Compare commits
11 Commits
Author | SHA1 | Date | |
---|---|---|---|
4e5c9f1e85 | |||
0f08725e8a | |||
229bc3cb44 | |||
7e7e6fa148 | |||
a5fadfb592 | |||
168d8dea2f | |||
c1436648df | |||
8fa8941cd2 | |||
e041330ed9 | |||
705bb7c066 | |||
faaf2166e9 |
7
Makefile
7
Makefile
@ -9,6 +9,7 @@ include $(DEVKITARM)/base_rules
|
||||
################################################################################
|
||||
|
||||
IPL_LOAD_ADDR := 0x40008000
|
||||
MAGIC = 0x4B434F4C #"LOCK"
|
||||
include ./Versions.inc
|
||||
|
||||
################################################################################
|
||||
@ -37,8 +38,8 @@ FFCFG_INC := '"../$(SOURCEDIR)/libs/fatfs/ffconf.h"'
|
||||
|
||||
################################################################################
|
||||
|
||||
CUSTOMDEFINES := -DIPL_LOAD_ADDR=$(IPL_LOAD_ADDR)
|
||||
CUSTOMDEFINES += -DLP_VER_MJ=$(LPVERSION_MAJOR) -DLP_VER_MN=$(LPVERSION_MINOR) -DLP_VER_BF=$(LPVERSION_BUGFX)
|
||||
CUSTOMDEFINES := -DIPL_LOAD_ADDR=$(IPL_LOAD_ADDR) -DLP_MAGIC=$(MAGIC)
|
||||
CUSTOMDEFINES += -DLP_VER_MJ=$(LPVERSION_MAJOR) -DLP_VER_MN=$(LPVERSION_MINOR) -DLP_VER_BF=$(LPVERSION_BUGFX) -DLP_RESERVED=$(LPVERSION_RSVD)
|
||||
CUSTOMDEFINES += -DGFX_INC=$(GFX_INC) -DFFCFG_INC=$(FFCFG_INC)
|
||||
|
||||
#CUSTOMDEFINES += -DDEBUG
|
||||
@ -51,7 +52,7 @@ CUSTOMDEFINES += -DGFX_INC=$(GFX_INC) -DFFCFG_INC=$(FFCFG_INC)
|
||||
WARNINGS := -Wall -Wno-array-bounds -Wno-stringop-overread -Wno-stringop-overflow
|
||||
|
||||
ARCH := -march=armv4t -mtune=arm7tdmi -mthumb -mthumb-interwork
|
||||
CFLAGS = $(ARCH) -O2 -nostdlib -ffunction-sections -fdata-sections -fomit-frame-pointer -fno-inline -std=gnu11 $(WARNINGS) $(CUSTOMDEFINES)
|
||||
CFLAGS = $(ARCH) -O2 -g -nostdlib -ffunction-sections -fdata-sections -fomit-frame-pointer -fno-inline -std=gnu11 $(WARNINGS) $(CUSTOMDEFINES)
|
||||
LDFLAGS = $(ARCH) -nostartfiles -lgcc -Wl,--nmagic,--gc-sections -Xlinker --defsym=IPL_LOAD_ADDR=$(IPL_LOAD_ADDR)
|
||||
|
||||
LDRDIR := $(wildcard loader)
|
||||
|
@ -1,4 +1,5 @@
|
||||
# LP Version.
|
||||
LPVERSION_MAJOR := 1
|
||||
LPVERSION_MINOR := 9
|
||||
LPVERSION_BUGFX := 4
|
||||
LPVERSION_BUGFX := 5
|
||||
LPVERSION_RSVD := 0
|
||||
|
@ -18,6 +18,8 @@
|
||||
#ifndef _TYPES_H_
|
||||
#define _TYPES_H_
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#define NULL ((void *)0)
|
||||
|
||||
#define ALWAYS_INLINE inline __attribute__((always_inline))
|
||||
@ -105,6 +107,16 @@ typedef struct __attribute__((__packed__)) _boot_cfg_t
|
||||
};
|
||||
} boot_cfg_t;
|
||||
|
||||
static_assert(sizeof(boot_cfg_t) == 0x84, "Boot CFG size is wrong!");
|
||||
|
||||
typedef struct __attribute__((__packed__)) _ipl_ver_meta_t
|
||||
{
|
||||
u32 magic;
|
||||
u32 version;
|
||||
u16 rsvd0;
|
||||
u16 rsvd1;
|
||||
} ipl_ver_meta_t;
|
||||
|
||||
typedef struct __attribute__((__packed__)) _reloc_meta_t
|
||||
{
|
||||
u32 start;
|
||||
|
@ -7,7 +7,7 @@ include $(DEVKITARM)/base_rules
|
||||
################################################################################
|
||||
|
||||
LDR_LOAD_ADDR := 0x40007000
|
||||
IPL_MAGIC := 0x43544349 #"ICTC"
|
||||
MAGIC := 0x4B434F4C #"LOCK"
|
||||
include ../Versions.inc
|
||||
|
||||
################################################################################
|
||||
@ -26,8 +26,8 @@ OBJS = $(addprefix $(BUILDDIR)/$(TARGET)/, \
|
||||
|
||||
################################################################################
|
||||
|
||||
CUSTOMDEFINES := -DBL_MAGIC=$(IPL_MAGIC)
|
||||
CUSTOMDEFINES += -DBL_VER_MJ=$(BLVERSION_MAJOR) -DBL_VER_MN=$(BLVERSION_MINOR) -DBL_VER_HF=$(BLVERSION_HOTFX) -DBL_RESERVED=$(BLVERSION_RSVD)
|
||||
CUSTOMDEFINES := -DLP_MAGIC=$(MAGIC)
|
||||
CUSTOMDEFINES += -DLP_VER_MJ=$(LPVERSION_MAJOR) -DLP_VER_MN=$(LPVERSION_MINOR) -DLP_VER_BF=$(LPVERSION_BUGFX) -DLP_RESERVED=$(LPVERSION_RSVD)
|
||||
|
||||
#TODO: Considering reinstating some of these when pointer warnings have been fixed.
|
||||
WARNINGS := -Wall -Wno-array-bounds -Wno-stringop-overflow
|
||||
|
@ -6,6 +6,7 @@ SECTIONS {
|
||||
.text : {
|
||||
*(.text._start);
|
||||
KEEP(*(._boot_cfg));
|
||||
KEEP(*(._ipl_version));
|
||||
*(.text*);
|
||||
}
|
||||
.data : {
|
||||
|
@ -30,6 +30,12 @@
|
||||
#define IPL_PATCHED_RELOC_SZ 0x94
|
||||
|
||||
boot_cfg_t __attribute__((section ("._boot_cfg"))) b_cfg;
|
||||
const volatile ipl_ver_meta_t __attribute__((section ("._ipl_version"))) ipl_ver = {
|
||||
.magic = LP_MAGIC,
|
||||
.version = (LP_VER_MJ + '0') | ((LP_VER_MN + '0') << 8) | ((LP_VER_BF + '0') << 16),
|
||||
.rsvd0 = 0,
|
||||
.rsvd1 = 0
|
||||
};
|
||||
|
||||
void loader_main()
|
||||
{
|
||||
|
99
source/frontend/gui.c
Normal file
99
source/frontend/gui.c
Normal file
@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2021 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 "../gfx/gfx.h"
|
||||
#include <mem/heap.h>
|
||||
#include <rtc/max77620-rtc.h>
|
||||
#include <storage/nx_sd.h>
|
||||
#include <utils/util.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
int save_fb_to_bmp()
|
||||
{
|
||||
// Disallow screenshots if less than 2s passed.
|
||||
static u32 timer = 0;
|
||||
if (get_tmr_ms() < timer)
|
||||
return 1;
|
||||
|
||||
const u32 file_size = 0x384000 + 0x36;
|
||||
u8 *bitmap = malloc(file_size);
|
||||
u32 *fb = malloc(0x384000);
|
||||
u32 *fb_ptr = gfx_ctxt.fb;
|
||||
|
||||
// Reconstruct FB for bottom-top, portrait bmp.
|
||||
for (int y = 1279; y > -1; y--)
|
||||
{
|
||||
for (u32 x = 0; x < 720; x++)
|
||||
fb[y * 720 + x] = *fb_ptr++;
|
||||
}
|
||||
|
||||
memcpy(bitmap + 0x36, fb, 0x384000);
|
||||
|
||||
typedef struct _bmp_t
|
||||
{
|
||||
u16 magic;
|
||||
u32 size;
|
||||
u32 rsvd;
|
||||
u32 data_off;
|
||||
u32 hdr_size;
|
||||
u32 width;
|
||||
u32 height;
|
||||
u16 planes;
|
||||
u16 pxl_bits;
|
||||
u32 comp;
|
||||
u32 img_size;
|
||||
u32 res_h;
|
||||
u32 res_v;
|
||||
u64 rsvd2;
|
||||
} __attribute__((packed)) bmp_t;
|
||||
|
||||
bmp_t *bmp = (bmp_t *)bitmap;
|
||||
|
||||
bmp->magic = 0x4D42;
|
||||
bmp->size = file_size;
|
||||
bmp->rsvd = 0;
|
||||
bmp->data_off = 0x36;
|
||||
bmp->hdr_size = 40;
|
||||
bmp->width = 720;
|
||||
bmp->height = 1280;
|
||||
bmp->planes = 1;
|
||||
bmp->pxl_bits = 32;
|
||||
bmp->comp = 0;
|
||||
bmp->img_size = 0x384000;
|
||||
bmp->res_h = 2834;
|
||||
bmp->res_v = 2834;
|
||||
bmp->rsvd2 = 0;
|
||||
|
||||
sd_mount();
|
||||
|
||||
f_mkdir("sd:/switch");
|
||||
|
||||
char path[0x80] = "sd:/switch/lockpick_rcm.bmp";
|
||||
|
||||
// Save screenshot and log.
|
||||
int res = sd_save_to_file(bitmap, file_size, path);
|
||||
|
||||
// sd_unmount();
|
||||
|
||||
free(bitmap);
|
||||
free(fb);
|
||||
|
||||
// Set timer to 2s.
|
||||
timer = get_tmr_ms() + 2000;
|
||||
|
||||
return res;
|
||||
}
|
17
source/frontend/gui.h
Normal file
17
source/frontend/gui.h
Normal file
@ -0,0 +1,17 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2021 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/>.
|
||||
*/
|
||||
|
||||
int save_fb_to_bmp();
|
@ -224,7 +224,7 @@ void gfx_putc(char c)
|
||||
cbuf++;
|
||||
}
|
||||
gfx_con.x += 16;
|
||||
if (gfx_con.x >= gfx_ctxt.width - 16)
|
||||
if (gfx_con.x > gfx_ctxt.width - 16)
|
||||
{
|
||||
gfx_con.x = 0;
|
||||
gfx_con.y += 16;
|
||||
@ -233,7 +233,7 @@ void gfx_putc(char c)
|
||||
else if (c == '\n')
|
||||
{
|
||||
gfx_con.x = 0;
|
||||
gfx_con.y +=16;
|
||||
gfx_con.y += 16;
|
||||
if (gfx_con.y > gfx_ctxt.height - 16)
|
||||
gfx_con.y = 0;
|
||||
}
|
||||
@ -259,7 +259,7 @@ void gfx_putc(char c)
|
||||
fb += gfx_ctxt.stride - 8;
|
||||
}
|
||||
gfx_con.x += 8;
|
||||
if (gfx_con.x >= gfx_ctxt.width - 8)
|
||||
if (gfx_con.x > gfx_ctxt.width - 8)
|
||||
{
|
||||
gfx_con.x = 0;
|
||||
gfx_con.y += 8;
|
||||
|
@ -32,6 +32,7 @@
|
||||
#define KB_FIRMWARE_VERSION_900 9
|
||||
#define KB_FIRMWARE_VERSION_910 10
|
||||
#define KB_FIRMWARE_VERSION_1210 11
|
||||
#define KB_FIRMWARE_VERSION_MAX KB_FIRMWARE_VERSION_1210 //!TODO: Update on mkey changes.
|
||||
#define KB_FIRMWARE_VERSION_1300 12
|
||||
#define KB_FIRMWARE_VERSION_MAX KB_FIRMWARE_VERSION_1300 //!TODO: Update on mkey changes.
|
||||
|
||||
#endif
|
||||
|
@ -36,6 +36,7 @@ static const u8 master_kek_sources[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_VERSION
|
||||
{0x1A, 0xEC, 0x11, 0x82, 0x2B, 0x32, 0x38, 0x7A, 0x2B, 0xED, 0xBA, 0x01, 0x47, 0x7E, 0x3B, 0x67}, //9.0.0
|
||||
{0x30, 0x3F, 0x02, 0x7E, 0xD8, 0x38, 0xEC, 0xD7, 0x93, 0x25, 0x34, 0xB5, 0x30, 0xEB, 0xCA, 0x7A}, //9.1.0
|
||||
{0x84, 0x67, 0xB6, 0x7F, 0x13, 0x11, 0xAE, 0xE6, 0x58, 0x9B, 0x19, 0xAF, 0x13, 0x6C, 0x80, 0x7A}, //12.1.0
|
||||
{0x68, 0x3B, 0xCA, 0x54, 0xB8, 0x6F, 0x92, 0x48, 0xC3, 0x05, 0x76, 0x87, 0x88, 0x70, 0x79, 0x23}, //13.0.0
|
||||
};
|
||||
|
||||
//!TODO: Update on mkey changes.
|
||||
@ -52,6 +53,7 @@ static const u8 master_key_vectors[KB_FIRMWARE_VERSION_MAX + 1][0x10] __attribut
|
||||
{0x4D, 0xD9, 0x98, 0x42, 0x45, 0x0D, 0xB1, 0x3C, 0x52, 0x0C, 0x9A, 0x44, 0xBB, 0xAD, 0xAF, 0x80}, /* Master key 08 encrypted with Master key 09. */
|
||||
{0xB8, 0x96, 0x9E, 0x4A, 0x00, 0x0D, 0xD6, 0x28, 0xB3, 0xD1, 0xDB, 0x68, 0x5F, 0xFB, 0xE1, 0x2A}, /* Master key 09 encrypted with Master key 0A. */
|
||||
{0xC1, 0x8D, 0x16, 0xBB, 0x2A, 0xE4, 0x1D, 0xD4, 0xC2, 0xC1, 0xB6, 0x40, 0x94, 0x35, 0x63, 0x98}, /* Master key 0A encrypted with Master key 0B. */
|
||||
{0xA3, 0x24, 0x65, 0x75, 0xEA, 0xCC, 0x6E, 0x8D, 0xFB, 0x5A, 0x16, 0x50, 0x74, 0xD2, 0x15, 0x06}, /* Master key 0B encrypted with Master key 0C. */
|
||||
};
|
||||
|
||||
//!TODO: Update on mkey changes.
|
||||
@ -68,6 +70,7 @@ static const u8 master_key_vectors_dev[KB_FIRMWARE_VERSION_MAX + 1][0x10] __attr
|
||||
{0x43, 0x3D, 0xC5, 0x3B, 0xEF, 0x91, 0x02, 0x21, 0x61, 0x54, 0x63, 0x8A, 0x35, 0xE7, 0xCA, 0xEE}, /* Master key 08 encrypted with Master key 09. */
|
||||
{0x6C, 0x2E, 0xCD, 0xB3, 0x34, 0x61, 0x77, 0xF5, 0xF9, 0xB1, 0xDD, 0x61, 0x98, 0x19, 0x3E, 0xD4}, /* Master key 09 encrypted with Master key 0A. */
|
||||
{0x21, 0x88, 0x6B, 0x10, 0x9E, 0x83, 0xD6, 0x52, 0xAB, 0x08, 0xDB, 0x6D, 0x39, 0xFF, 0x1C, 0x9C}, /* Master key 0A encrypted with Master key 0B. */
|
||||
{0x8A, 0xCE, 0xC4, 0x7F, 0xBE, 0x08, 0x61, 0x88, 0xD3, 0x73, 0x64, 0x51, 0xE2, 0xB6, 0x53, 0x15}, /* Master key 0B encrypted with Master key 0C. */
|
||||
};
|
||||
|
||||
static const u8 mariko_key_vectors[][0x10] __attribute__((aligned(4))) = {
|
||||
@ -127,6 +130,7 @@ static const u8 mariko_master_kek_sources[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_
|
||||
{0x86, 0x69, 0xF0, 0x09, 0x87, 0xC8, 0x05, 0xAE, 0xB5, 0x7B, 0x48, 0x74, 0xDE, 0x62, 0xA6, 0x13}, // 9.0.0.
|
||||
{0x0E, 0x44, 0x0C, 0xED, 0xB4, 0x36, 0xC0, 0x3F, 0xAA, 0x1D, 0xAE, 0xBF, 0x62, 0xB1, 0x09, 0x82}, // 9.1.0.
|
||||
{0xE5, 0x41, 0xAC, 0xEC, 0xD1, 0xA7, 0xD1, 0xAB, 0xED, 0x03, 0x77, 0xF1, 0x27, 0xCA, 0xF8, 0xF1}, // 12.1.0.
|
||||
{0x52, 0x71, 0x9B, 0xDF, 0xA7, 0x8B, 0x61, 0xD8, 0xD5, 0x85, 0x11, 0xE4, 0x8E, 0x4F, 0x74, 0xC6}, // 13.0.0.
|
||||
}; //!TODO: Update on mkey changes.
|
||||
static const u8 mariko_master_kek_sources_dev[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_VERSION_600 + 1][0x10] __attribute__((aligned(4))) = {
|
||||
{0x32, 0xC0, 0x97, 0x6B, 0x63, 0x6D, 0x44, 0x64, 0xF2, 0x3A, 0xA5, 0xC0, 0xDE, 0x46, 0xCC, 0xE9}, // 6.0.0.
|
||||
@ -136,6 +140,7 @@ static const u8 mariko_master_kek_sources_dev[KB_FIRMWARE_VERSION_MAX - KB_FIRMW
|
||||
{0x82, 0x72, 0x91, 0x65, 0x40, 0x3B, 0x9D, 0x66, 0x60, 0xD0, 0x1B, 0x3D, 0x4D, 0xA5, 0x70, 0xE1}, // 9.0.0.
|
||||
{0xF9, 0x37, 0xCF, 0x9A, 0xBD, 0x86, 0xBB, 0xA9, 0x9C, 0x9E, 0x03, 0xC4, 0xFC, 0xBC, 0x3B, 0xCE}, // 9.1.0.
|
||||
{0x75, 0x2D, 0x2E, 0xF3, 0x2F, 0x3F, 0xFE, 0x65, 0xF4, 0xA9, 0x83, 0xB4, 0xED, 0x42, 0x63, 0xBA}, // 12.1.0.
|
||||
{0x4D, 0x5A, 0xB2, 0xC9, 0xE9, 0xE4, 0x4E, 0xA4, 0xD3, 0xBF, 0x94, 0x12, 0x36, 0x30, 0xD0, 0x7F}, // 13.0.0.
|
||||
}; //!TODO: Update on mkey changes.
|
||||
|
||||
static const u8 device_master_key_source_sources[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_VERSION_400 + 1][0x10] __attribute__((aligned(4))) = {
|
||||
@ -148,6 +153,7 @@ static const u8 device_master_key_source_sources[KB_FIRMWARE_VERSION_MAX - KB_FI
|
||||
{0x4A, 0xC3, 0x4E, 0x14, 0x8B, 0x96, 0x4A, 0xD5, 0xD4, 0x99, 0x73, 0xC4, 0x45, 0xAB, 0x8B, 0x49}, /* 9.0.0 Device Master Key Source Source. */
|
||||
{0x14, 0xB8, 0x74, 0x12, 0xCB, 0xBD, 0x0B, 0x8F, 0x20, 0xFB, 0x30, 0xDA, 0x27, 0xE4, 0x58, 0x94}, /* 9.1.0 Device Master Key Source Source. */
|
||||
{0xAA, 0xFD, 0xBC, 0xBB, 0x25, 0xC3, 0xA4, 0xEF, 0xE3, 0xEE, 0x58, 0x53, 0xB7, 0xF8, 0xDD, 0xD6}, /* 12.1.0 Device Master Key Source Source. */
|
||||
{0xE4, 0xF3, 0x45, 0x6F, 0x18, 0xA1, 0x89, 0xF8, 0xDA, 0x4C, 0x64, 0x75, 0x68, 0xE6, 0xBD, 0x4F}, /* 13.0.0 Device Master Key Source Source. */
|
||||
}; //!TODO: Update on mkey changes.
|
||||
|
||||
// from ES
|
||||
@ -174,6 +180,7 @@ static const u8 device_master_kek_sources[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_
|
||||
{0x03, 0xE7, 0xEB, 0x43, 0x1B, 0xCF, 0x5F, 0xB5, 0xED, 0xDC, 0x97, 0xAE, 0x21, 0x8D, 0x19, 0xED}, /* 9.0.0 Device Master Kek Source. */
|
||||
{0xCE, 0xFE, 0x41, 0x0F, 0x46, 0x9A, 0x30, 0xD6, 0xF2, 0xE9, 0x0C, 0x6B, 0xB7, 0x15, 0x91, 0x36}, /* 9.1.0 Device Master Kek Source. */
|
||||
{0xC2, 0x65, 0x34, 0x6E, 0xC7, 0xC6, 0x5D, 0x97, 0x3E, 0x34, 0x5C, 0x6B, 0xB3, 0x7E, 0xC6, 0xE3}, /* 12.1.0 Device Master Kek Source. */
|
||||
{0x77, 0x52, 0x92, 0xF0, 0xAA, 0xE3, 0xFB, 0xE0, 0x60, 0x16, 0xB3, 0x78, 0x68, 0x53, 0xF7, 0xA8}, /* 13.0.0 Device Master Kek Source. */
|
||||
}; //!TODO: Update on mkey changes.
|
||||
|
||||
static const u8 device_master_kek_sources_dev[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_VERSION_400 + 1][0x10] __attribute__((aligned(4))) = {
|
||||
@ -186,6 +193,7 @@ static const u8 device_master_kek_sources_dev[KB_FIRMWARE_VERSION_MAX - KB_FIRMW
|
||||
{0x61, 0x6A, 0x88, 0x21, 0xA3, 0x52, 0xB0, 0x19, 0x16, 0x25, 0xA4, 0xE3, 0x4C, 0x54, 0x02, 0x0F}, /* 9.0.0 Device Master Kek Source. */
|
||||
{0x9D, 0xB1, 0xAE, 0xCB, 0xF6, 0xF6, 0xE3, 0xFE, 0xAB, 0x6F, 0xCB, 0xAF, 0x38, 0x03, 0xFC, 0x7B}, /* 9.1.0 Device Master Kek Source. */
|
||||
{0xC4, 0xBB, 0xF3, 0x9F, 0xA3, 0xAA, 0x00, 0x99, 0x7C, 0x97, 0xAD, 0x91, 0x8F, 0xE8, 0x45, 0xCB}, /* 12.1.0 Device Master Kek Source. */
|
||||
{0x20, 0x20, 0xAA, 0xFB, 0x89, 0xC2, 0xF0, 0x70, 0xB5, 0xE0, 0xA3, 0x11, 0x8A, 0x29, 0x8D, 0x0F}, /* 13.0.0 Device Master Kek Source. */
|
||||
}; //!TODO: Update on mkey changes.
|
||||
|
||||
// from SPL
|
||||
|
@ -20,6 +20,7 @@
|
||||
|
||||
#include "../config.h"
|
||||
#include <display/di.h>
|
||||
#include "../frontend/gui.h"
|
||||
#include <gfx_utils.h>
|
||||
#include "../gfx/tui.h"
|
||||
#include "../hos/hos.h"
|
||||
@ -81,9 +82,13 @@ static bool _test_key_pair(const void *E, const void *D, const void *N);
|
||||
static void _derive_master_key_mariko(key_derivation_ctx_t *keys, bool is_dev) {
|
||||
// Relies on the SBK being properly set in slot 14
|
||||
se_aes_crypt_block_ecb(14, DECRYPT, keys->device_key_4x, device_master_key_source_kek_source);
|
||||
// Relies on the Mariko KEK being properly set in slot 12
|
||||
se_aes_unwrap_key(8, 12, is_dev ? &mariko_master_kek_sources_dev[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_VERSION_600] : &mariko_master_kek_sources[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_VERSION_600]);
|
||||
se_aes_crypt_block_ecb(8, DECRYPT, keys->master_key[KB_FIRMWARE_VERSION_MAX], master_key_source);
|
||||
// Derive all master keys based on Mariko KEK
|
||||
for (u32 i = KB_FIRMWARE_VERSION_600; i < ARRAY_SIZE(mariko_master_kek_sources) + KB_FIRMWARE_VERSION_600; i++) {
|
||||
// Relies on the Mariko KEK being properly set in slot 12
|
||||
se_aes_crypt_block_ecb(12, DECRYPT, keys->master_kek[i], is_dev ? &mariko_master_kek_sources_dev[i - KB_FIRMWARE_VERSION_600] : &mariko_master_kek_sources[i - KB_FIRMWARE_VERSION_600]); // mkek = unwrap(mariko_kek, mariko_kek_source)
|
||||
se_aes_key_set(8, keys->master_kek[i], AES_128_KEY_SIZE); // mkey = unwrap(mkek, mkeys)
|
||||
se_aes_crypt_block_ecb(8, DECRYPT, keys->master_key[i], master_key_source);
|
||||
}
|
||||
}
|
||||
|
||||
static int _run_ams_keygen(key_derivation_ctx_t *keys) {
|
||||
@ -91,13 +96,17 @@ static int _run_ams_keygen(key_derivation_ctx_t *keys) {
|
||||
tsec_ctxt.fw = tsec_keygen;
|
||||
tsec_ctxt.size = sizeof(tsec_keygen);
|
||||
tsec_ctxt.type = TSEC_FW_TYPE_NEW;
|
||||
int res = tsec_query(keys->temp_key, &tsec_ctxt);
|
||||
|
||||
if (res) {
|
||||
EPRINTFARGS("ERROR %d running keygen.\n", res);
|
||||
u32 retries = 0;
|
||||
while (tsec_query(keys->temp_key, &tsec_ctxt) < 0) {
|
||||
retries++;
|
||||
if (retries > 15) {
|
||||
EPRINTF("Failed to run keygen.");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void _derive_master_keys_from_latest_key(key_derivation_ctx_t *keys, bool is_dev) {
|
||||
@ -127,8 +136,8 @@ static void _derive_master_keys_from_latest_key(key_derivation_ctx_t *keys, bool
|
||||
|
||||
static void _derive_keyblob_keys(key_derivation_ctx_t *keys) {
|
||||
u8 *keyblob_block = (u8 *)calloc(KB_FIRMWARE_VERSION_600 + 1, NX_EMMC_BLOCKSIZE);
|
||||
encrypted_keyblob_t *current_keyblob = (encrypted_keyblob_t *)keyblob_block;
|
||||
u32 keyblob_mac[AES_128_KEY_SIZE / 4] = {0};
|
||||
bool have_keyblobs = true;
|
||||
|
||||
if (FUSE(FUSE_PRIVATE_KEY0) == 0xFFFFFFFF) {
|
||||
u8 *aes_keys = (u8 *)calloc(0x1000, 1);
|
||||
@ -142,10 +151,16 @@ static void _derive_keyblob_keys(key_derivation_ctx_t *keys) {
|
||||
keys->sbk[3] = FUSE(FUSE_PRIVATE_KEY3);
|
||||
}
|
||||
|
||||
if (!emummc_storage_read(KEYBLOB_OFFSET / NX_EMMC_BLOCKSIZE, KB_FIRMWARE_VERSION_600 + 1, keyblob_block)) {
|
||||
if (!emmc_storage.initialized) {
|
||||
have_keyblobs = false;
|
||||
} else if (!emummc_storage_read(KEYBLOB_OFFSET / NX_EMMC_BLOCKSIZE, KB_FIRMWARE_VERSION_600 + 1, keyblob_block)) {
|
||||
EPRINTF("Unable to read keyblobs.");
|
||||
have_keyblobs = false;
|
||||
} else {
|
||||
have_keyblobs = true;
|
||||
}
|
||||
|
||||
encrypted_keyblob_t *current_keyblob = (encrypted_keyblob_t *)keyblob_block;
|
||||
for (u32 i = 0; i <= KB_FIRMWARE_VERSION_600; i++, current_keyblob++) {
|
||||
minerva_periodic_training();
|
||||
se_aes_crypt_block_ecb(12, DECRYPT, keys->keyblob_key[i], keyblob_key_sources[i]); // temp = unwrap(kbks, tsec)
|
||||
@ -157,6 +172,10 @@ static void _derive_keyblob_keys(key_derivation_ctx_t *keys) {
|
||||
se_aes_crypt_block_ecb(7, DECRYPT, keys->device_key_4x, device_master_key_source_kek_source);
|
||||
}
|
||||
|
||||
if (!have_keyblobs) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// verify keyblob is not corrupt
|
||||
se_aes_key_set(10, keys->keyblob_mac_key[i], sizeof(keys->keyblob_mac_key[i]));
|
||||
se_aes_cmac(10, keyblob_mac, sizeof(keyblob_mac), current_keyblob->iv, sizeof(current_keyblob->iv) + sizeof(keyblob_t));
|
||||
@ -226,7 +245,7 @@ static void _derive_misc_keys(key_derivation_ctx_t *keys, bool is_dev) {
|
||||
}
|
||||
}
|
||||
|
||||
static void _derive_master_key_per_generation_keys(key_derivation_ctx_t *keys) {
|
||||
static void _derive_per_generation_keys(key_derivation_ctx_t *keys) {
|
||||
for (u32 i = 0; i < KB_FIRMWARE_VERSION_MAX + 1; i++) {
|
||||
if (!_key_exists(keys->master_key[i]))
|
||||
continue;
|
||||
@ -543,7 +562,7 @@ static void _save_mariko_partial_keys(u32 start, u32 count, bool append) {
|
||||
}
|
||||
|
||||
u32 pos = 0;
|
||||
u32 zeros[4] = {0};
|
||||
u32 zeros[AES_128_KEY_SIZE / 4] = {0};
|
||||
u8 *data = malloc(4 * AES_128_KEY_SIZE);
|
||||
char *text_buffer = calloc(1, 0x100 * count);
|
||||
|
||||
@ -552,6 +571,7 @@ static void _save_mariko_partial_keys(u32 start, u32 count, bool append) {
|
||||
if (ks < ARRAY_SIZE(mariko_key_vectors)) {
|
||||
se_aes_crypt_block_ecb(ks, DECRYPT, &data[0], mariko_key_vectors[ks]);
|
||||
if (_key_exists(data)) {
|
||||
EPRINTFARGS("Failed to validate keyslot %d.", ks);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@ -569,6 +589,7 @@ static void _save_mariko_partial_keys(u32 start, u32 count, bool append) {
|
||||
|
||||
// Skip saving key if two results are the same indicating unsuccessful overwrite or empty slot
|
||||
if (memcmp(&data[0], &data[SE_KEY_128_SIZE], AES_128_KEY_SIZE) == 0) {
|
||||
EPRINTFARGS("Failed to overwrite keyslot %d.", ks);
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -583,7 +604,7 @@ static void _save_mariko_partial_keys(u32 start, u32 count, bool append) {
|
||||
free(data);
|
||||
|
||||
if (strlen(text_buffer) == 0) {
|
||||
EPRINTF("Failed to dump partial keys.");
|
||||
EPRINTFARGS("Failed to dump partial keys %d-%d.", start, start + count - 1);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -625,7 +646,7 @@ static void _save_keys_to_sd(key_derivation_ctx_t *keys, titlekey_buffer_t *titl
|
||||
SAVE_KEY(aes_key_generation_source);
|
||||
SAVE_KEY(bis_kek_source);
|
||||
SAVE_KEY_FAMILY_VAR(bis_key, keys->bis_key, 0);
|
||||
SAVE_KEY_FAMILY(bis_key_sources, 0);
|
||||
SAVE_KEY_FAMILY_VAR(bis_key_source, bis_key_sources, 0);
|
||||
SAVE_KEY_VAR(device_key, keys->device_key);
|
||||
SAVE_KEY_VAR(device_key_4x, keys->device_key_4x);
|
||||
SAVE_KEY_VAR(eticket_rsa_kek, keys->eticket_rsa_kek);
|
||||
@ -751,10 +772,14 @@ static void _derive_keys() {
|
||||
f_unlink("sd:/switch/partialaes.keys");
|
||||
}
|
||||
|
||||
minerva_periodic_training();
|
||||
|
||||
if (h_cfg.t210b01) {
|
||||
_save_mariko_partial_keys(0, 12, false);
|
||||
}
|
||||
|
||||
minerva_periodic_training();
|
||||
|
||||
if (!_check_keyslot_access()) {
|
||||
EPRINTF("Unable to set crypto keyslots!\nTry launching payload differently\n or flash Spacecraft-NX if using a modchip.");
|
||||
return;
|
||||
@ -764,13 +789,15 @@ static void _derive_keys() {
|
||||
|
||||
if (emummc_storage_init_mmc()) {
|
||||
EPRINTF("Unable to init MMC.");
|
||||
return;
|
||||
} else {
|
||||
TPRINTFARGS("%kMMC init... ", colors[(color_idx++) % 6]);
|
||||
}
|
||||
TPRINTFARGS("%kMMC init... ", colors[(color_idx++) % 6]);
|
||||
|
||||
if (!emummc_storage_set_mmc_partition(EMMC_BOOT0)) {
|
||||
minerva_periodic_training();
|
||||
|
||||
if (emmc_storage.initialized && !emummc_storage_set_mmc_partition(EMMC_BOOT0)) {
|
||||
EPRINTF("Unable to set partition.");
|
||||
return;
|
||||
emummc_storage_end();
|
||||
}
|
||||
|
||||
bool is_dev = fuse_read_hw_state() == FUSE_NX_HW_STATE_DEV;
|
||||
@ -781,11 +808,11 @@ static void _derive_keys() {
|
||||
// Master key derivation
|
||||
if (h_cfg.t210b01) {
|
||||
_derive_master_key_mariko(keys, is_dev);
|
||||
minerva_periodic_training();
|
||||
_derive_master_keys_from_latest_key(keys, is_dev);
|
||||
} else {
|
||||
int res = _run_ams_keygen(keys);
|
||||
if (res) {
|
||||
EPRINTF("Unable to run keygen.");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -797,7 +824,9 @@ static void _derive_keys() {
|
||||
free(aes_keys);
|
||||
|
||||
_derive_master_keys_from_latest_key(&prod_keys, false);
|
||||
minerva_periodic_training();
|
||||
_derive_master_keys_from_latest_key(&dev_keys, true);
|
||||
minerva_periodic_training();
|
||||
_derive_keyblob_keys(keys);
|
||||
}
|
||||
|
||||
@ -807,17 +836,24 @@ static void _derive_keys() {
|
||||
|
||||
TPRINTFARGS("%kBIS keys... ", colors[(color_idx++) % 6]);
|
||||
|
||||
minerva_periodic_training();
|
||||
_derive_misc_keys(keys, is_dev);
|
||||
|
||||
minerva_periodic_training();
|
||||
_derive_non_unique_keys(&prod_keys, is_dev);
|
||||
minerva_periodic_training();
|
||||
_derive_non_unique_keys(&dev_keys, is_dev);
|
||||
_derive_master_key_per_generation_keys(&prod_keys);
|
||||
_derive_master_key_per_generation_keys(&dev_keys);
|
||||
minerva_periodic_training();
|
||||
_derive_per_generation_keys(&prod_keys);
|
||||
minerva_periodic_training();
|
||||
_derive_per_generation_keys(&dev_keys);
|
||||
|
||||
titlekey_buffer_t *titlekey_buffer = (titlekey_buffer_t *)TITLEKEY_BUF_ADR;
|
||||
|
||||
// BIS key for SYSTEM partition
|
||||
if (_key_exists(keys->bis_key[2])) {
|
||||
// Requires BIS key for SYSTEM partition
|
||||
if (!emmc_storage.initialized) {
|
||||
EPRINTF("eMMC not initialized.\nSkipping SD seed and titlekeys.");
|
||||
} else if (_key_exists(keys->bis_key[2])) {
|
||||
_derive_emmc_keys(keys, titlekey_buffer);
|
||||
} else {
|
||||
EPRINTF("Missing needed BIS keys.\nSkipping SD seed and titlekeys.");
|
||||
@ -825,12 +861,21 @@ static void _derive_keys() {
|
||||
|
||||
end_time = get_tmr_us();
|
||||
gfx_printf("%kLockpick totally done in %d us\n", colors[(color_idx++) % 6], end_time - start_whole_operation_time);
|
||||
_save_keys_to_sd(&prod_keys, titlekey_buffer, false);
|
||||
_key_count = 0;
|
||||
_save_keys_to_sd(&dev_keys, NULL, true);
|
||||
|
||||
if (h_cfg.t210b01) {
|
||||
// On Mariko, save only relevant key set
|
||||
_save_keys_to_sd(keys, titlekey_buffer, is_dev);
|
||||
} else {
|
||||
// On Erista, save both prod and dev key sets
|
||||
_save_keys_to_sd(&prod_keys, titlekey_buffer, false);
|
||||
_key_count = 0;
|
||||
_save_keys_to_sd(&dev_keys, NULL, true);
|
||||
}
|
||||
}
|
||||
|
||||
void dump_keys() {
|
||||
minerva_change_freq(FREQ_1600);
|
||||
|
||||
display_backlight_brightness(h_cfg.backlight, 1000);
|
||||
gfx_clear_grey(0x1B);
|
||||
gfx_con_setpos(0, 0);
|
||||
@ -850,9 +895,23 @@ void dump_keys() {
|
||||
// Ignore whether emummc is enabled.
|
||||
h_cfg.emummc_force_disable = emu_cfg.sector == 0 && !emu_cfg.path;
|
||||
emu_cfg.enabled = !h_cfg.emummc_force_disable;
|
||||
emummc_storage_end(&emmc_storage);
|
||||
gfx_printf("\n%kPress a button to return to the menu.", colors[(color_idx) % 6], colors[(color_idx + 1) % 6], colors[(color_idx + 2) % 6]);
|
||||
btn_wait();
|
||||
if (emmc_storage.initialized) {
|
||||
emummc_storage_end();
|
||||
}
|
||||
|
||||
minerva_change_freq(FREQ_800);
|
||||
gfx_printf("\n%kPress VOL+ to save a screenshot\n or another button to return to the menu.\n\n", colors[(color_idx++) % 6]);
|
||||
u8 btn = btn_wait();
|
||||
if (btn == BTN_VOL_UP) {
|
||||
int res = save_fb_to_bmp();
|
||||
if (!res) {
|
||||
gfx_printf("%kScreenshot sd:/switch/lockpick_rcm.bmp saved.", colors[(color_idx++) % 6]);
|
||||
} else {
|
||||
EPRINTF("Screenshot failed.");
|
||||
}
|
||||
gfx_printf("\n%kPress a button to return to the menu.", colors[(color_idx++) % 6]);
|
||||
btn_wait();
|
||||
}
|
||||
gfx_clear_grey(0x1B);
|
||||
}
|
||||
|
||||
|
@ -6,6 +6,7 @@ SECTIONS {
|
||||
.text : {
|
||||
*(.text._start);
|
||||
KEEP(*(._boot_cfg));
|
||||
KEEP(*(._ipl_version));
|
||||
*(.text._irq_setup);
|
||||
*(.text*);
|
||||
}
|
||||
|
@ -46,6 +46,12 @@
|
||||
|
||||
hekate_config h_cfg;
|
||||
boot_cfg_t __attribute__((section ("._boot_cfg"))) b_cfg;
|
||||
const volatile ipl_ver_meta_t __attribute__((section ("._ipl_version"))) ipl_ver = {
|
||||
.magic = LP_MAGIC,
|
||||
.version = (LP_VER_MJ + '0') | ((LP_VER_MN + '0') << 8) | ((LP_VER_BF + '0') << 16),
|
||||
.rsvd0 = 0,
|
||||
.rsvd1 = 0
|
||||
};
|
||||
|
||||
volatile nyx_storage_t *nyx_str = (nyx_storage_t *)NYX_STORAGE_ADDR;
|
||||
|
||||
@ -276,6 +282,12 @@ out:
|
||||
btn_wait();
|
||||
}
|
||||
|
||||
void launch_hekate()
|
||||
{
|
||||
if (!f_stat("bootloader/update.bin", NULL))
|
||||
launch_payload("bootloader/update.bin", false);
|
||||
}
|
||||
|
||||
void dump_sysnand()
|
||||
{
|
||||
h_cfg.emummc_force_disable = true;
|
||||
@ -303,10 +315,11 @@ ment_t ment_top[] = {
|
||||
MDEF_HANDLER("Dump from EmuNAND", dump_emunand, COLOR_ORANGE),
|
||||
MDEF_CAPTION("---------------", COLOR_YELLOW),
|
||||
MDEF_HANDLER("Payloads...", launch_tools, COLOR_GREEN),
|
||||
MDEF_CAPTION("---------------", COLOR_BLUE),
|
||||
MDEF_HANDLER_EX("Reboot (OFW)", &STATE_REBOOT_BYPASS_FUSES, power_set_state_ex, COLOR_VIOLET),
|
||||
MDEF_HANDLER_EX("Reboot (RCM)", &STATE_REBOOT_RCM, power_set_state_ex, COLOR_RED),
|
||||
MDEF_HANDLER_EX("Power off", &STATE_POWER_OFF, power_set_state_ex, COLOR_ORANGE),
|
||||
MDEF_HANDLER("Reboot to Hekate", launch_hekate, COLOR_BLUE),
|
||||
MDEF_CAPTION("---------------", COLOR_VIOLET),
|
||||
MDEF_HANDLER_EX("Reboot (OFW)", &STATE_REBOOT_BYPASS_FUSES, power_set_state_ex, COLOR_RED),
|
||||
MDEF_HANDLER_EX("Reboot (RCM)", &STATE_REBOOT_RCM, power_set_state_ex, COLOR_ORANGE),
|
||||
MDEF_HANDLER_EX("Power off", &STATE_POWER_OFF, power_set_state_ex, COLOR_YELLOW),
|
||||
MDEF_END()
|
||||
};
|
||||
|
||||
@ -339,7 +352,6 @@ void ipl_main()
|
||||
// Train DRAM and switch to max frequency.
|
||||
if (minerva_init()) //!TODO: Add Tegra210B01 support to minerva.
|
||||
h_cfg.errors |= ERR_LIBSYS_MTC;
|
||||
minerva_change_freq(FREQ_1600);
|
||||
|
||||
display_init();
|
||||
|
||||
@ -370,16 +382,26 @@ void ipl_main()
|
||||
// Grey out reboot to RCM option if on Mariko or patched console.
|
||||
if (h_cfg.t210b01 || h_cfg.rcm_patched)
|
||||
{
|
||||
ment_top[6].type = MENT_CAPTION;
|
||||
ment_top[6].color = 0xFF555555;
|
||||
ment_top[6].handler = NULL;
|
||||
ment_top[7].type = MENT_CAPTION;
|
||||
ment_top[7].color = 0xFF555555;
|
||||
ment_top[7].handler = NULL;
|
||||
}
|
||||
|
||||
if (h_cfg.rcm_patched)
|
||||
{
|
||||
ment_top[6].data = &STATE_REBOOT_FULL;
|
||||
ment_top[7].data = &STATE_REBOOT_FULL;
|
||||
}
|
||||
|
||||
// Grey out reboot to Hekate option if no update.bin found.
|
||||
if (f_stat("bootloader/update.bin", NULL))
|
||||
{
|
||||
ment_top[4].type = MENT_CAPTION;
|
||||
ment_top[4].color = 0xFF555555;
|
||||
ment_top[4].handler = NULL;
|
||||
}
|
||||
|
||||
minerva_change_freq(FREQ_800);
|
||||
|
||||
while (true)
|
||||
tui_do_menu(&menu_top);
|
||||
|
||||
|
Reference in New Issue
Block a user