8 Commits

50 changed files with 4438 additions and 696 deletions

View File

@ -10,7 +10,7 @@ include $(DEVKITARM)/base_rules
IPL_LOAD_ADDR := 0x40003000 IPL_LOAD_ADDR := 0x40003000
LPVERSION_MAJOR := 1 LPVERSION_MAJOR := 1
LPVERSION_MINOR := 4 LPVERSION_MINOR := 6
LPVERSION_BUGFX := 0 LPVERSION_BUGFX := 0
################################################################################ ################################################################################

39
common/common_module.h Normal file
View File

@ -0,0 +1,39 @@
/*
* Common Module Header
* Copyright (C) 2018 M4xw
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* 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/>.
*/
#pragma once
#include <stddef.h>
//TODO: Move it to BDK
#include "common_gfx.h"
#include "common_heap.h"
// Module Callback
typedef void (*cbMainModule_t)(const char *s);
typedef void (*memcpy_t)(void *, void *, size_t);
typedef void (*memset_t)(void *, int, size_t);
typedef struct _bdkParams_t
{
gfx_con_t *gfxCon;
gfx_ctxt_t *gfxCtx;
heap_t *sharedHeap;
memcpy_t memcpy;
memset_t memset;
} *bdkParams_t;
// Module Entrypoint
typedef void (*moduleEntrypoint_t)(void *, bdkParams_t);

54
source/config/config.c Normal file
View File

@ -0,0 +1,54 @@
/*
* 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/>.
*/
#include <string.h>
#include <stdlib.h>
#include "config.h"
#include "ini.h"
#include "../gfx/gfx.h"
#include "../libs/fatfs/ff.h"
#include "../soc/t210.h"
#include "../storage/sdmmc.h"
#include "../utils/btn.h"
#include "../utils/list.h"
#include "../utils/util.h"
extern hekate_config h_cfg;
extern bool sd_mount();
extern void sd_unmount();
void set_default_configuration()
{
h_cfg.autoboot = 0;
h_cfg.autoboot_list = 0;
h_cfg.bootwait = 3;
h_cfg.verification = 1;
h_cfg.se_keygen_done = 0;
h_cfg.sbar_time_keeping = 0;
h_cfg.backlight = 100;
h_cfg.autohosoff = 0;
h_cfg.autonogc = 1;
h_cfg.brand = NULL;
h_cfg.tagline = NULL;
h_cfg.errors = 0;
h_cfg.sept_run = EMC(EMC_SCRATCH0) & EMC_SEPT_RUN;
h_cfg.rcm_patched = true;
h_cfg.emummc_force_disable = false;
sd_power_cycle_time_start = 0xFFFFFFF;
}

50
source/config/config.h Normal file
View File

@ -0,0 +1,50 @@
/*
* 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 _CONFIG_H_
#define _CONFIG_H_
#include "../utils/types.h"
typedef struct _hekate_config
{
// Non-volatile config.
u32 autoboot;
u32 autoboot_list;
u32 bootwait;
u32 verification;
u32 backlight;
u32 autohosoff;
u32 autonogc;
char *brand;
char *tagline;
// Global temporary config.
bool se_keygen_done;
bool sept_run;
bool emummc_force_disable;
bool rcm_patched;
u32 sbar_time_keeping;
u32 errors;
} hekate_config;
typedef enum
{
ERR_LIBSYS_LP0 = (1 << 0),
} hsysmodule_t;
void set_default_configuration();
#endif /* _CONFIG_H_ */

193
source/config/ini.c Normal file
View File

@ -0,0 +1,193 @@
/*
* Copyright (c) 2018 naehrwert
* 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/>.
*/
#include <string.h>
#include "ini.h"
#include "../libs/fatfs/ff.h"
#include "../mem/heap.h"
#include "../utils/dirlist.h"
static char *_strdup(char *str)
{
if (!str)
return NULL;
// Remove starting space.
if (str[0] == ' ' && strlen(str))
str++;
char *res = (char *)malloc(strlen(str) + 1);
strcpy(res, str);
// Remove trailing space.
if (strlen(res) && res[strlen(res) - 1] == ' ')
res[strlen(res) - 1] = 0;
return res;
}
u32 _find_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;
}
ini_sec_t *_ini_create_section(link_t *dst, ini_sec_t *csec, char *name, u8 type)
{
if (csec)
{
list_append(dst, &csec->link);
csec = NULL;
}
csec = (ini_sec_t *)malloc(sizeof(ini_sec_t));
csec->name = _strdup(name);
csec->type = type;
return csec;
}
int ini_parse(link_t *dst, char *ini_path, bool is_dir)
{
u32 lblen;
u32 pathlen = strlen(ini_path);
u32 k = 0;
char lbuf[512];
char *filelist = NULL;
FIL fp;
ini_sec_t *csec = NULL;
char *filename = (char *)malloc(256);
memcpy(filename, ini_path, pathlen + 1);
// Get all ini filenames.
if (is_dir)
{
filelist = dirlist(filename, "*.ini", false);
if (!filelist)
{
free(filename);
return 0;
}
memcpy(filename + pathlen, "/", 2);
pathlen++;
}
do
{
// Copy ini filename in path string.
if (is_dir)
{
if (filelist[k * 256])
{
memcpy(filename + pathlen, &filelist[k * 256], strlen(&filelist[k * 256]) + 1);
k++;
}
else
break;
}
// Open ini.
if (f_open(&fp, filename, FA_READ) != FR_OK)
{
free(filelist);
free(filename);
return 0;
}
do
{
// Fetch one line.
lbuf[0] = 0;
f_gets(lbuf, 512, &fp);
lblen = strlen(lbuf);
// Remove trailing newline.
if (lbuf[lblen - 1] == '\n' || lbuf[lblen - 1] == '\r')
lbuf[lblen - 1] = 0;
if (lblen > 2 && lbuf[0] == '[') // Create new section.
{
_find_section_name(lbuf, lblen, ']');
csec = _ini_create_section(dst, csec, &lbuf[1], INI_CHOICE);
list_init(&csec->kvs);
}
else if (lblen > 2 && lbuf[0] == '{') //Create new caption.
{
_find_section_name(lbuf, lblen, '}');
csec = _ini_create_section(dst, csec, &lbuf[1], INI_CAPTION);
csec->color = 0xFF0AB9E6;
}
else if (lblen > 2 && lbuf[0] == '#') //Create empty lines and comments.
{
_find_section_name(lbuf, lblen, '\0');
csec = _ini_create_section(dst, csec, &lbuf[1], INI_COMMENT);
}
else if (lblen < 2)
{
csec = _ini_create_section(dst, csec, NULL, INI_NEWLINE);
}
else if (csec && csec->type == INI_CHOICE) //Extract key/value.
{
u32 i = _find_section_name(lbuf, lblen, '=');
ini_kv_t *kv = (ini_kv_t *)malloc(sizeof(ini_kv_t));
kv->key = _strdup(&lbuf[0]);
kv->val = _strdup(&lbuf[i + 1]);
list_append(&csec->kvs, &kv->link);
}
} while (!f_eof(&fp));
f_close(&fp);
if (csec)
{
list_append(dst, &csec->link);
if (is_dir)
csec = NULL;
}
} while (is_dir);
free(filename);
free(filelist);
return 1;
}
char *ini_check_payload_section(ini_sec_t *cfg)
{
if (cfg == NULL)
return NULL;
LIST_FOREACH_ENTRY(ini_kv_t, kv, &cfg->kvs, link)
{
if (!strcmp("payload", kv->key))
return kv->val;
}
return NULL;
}

50
source/config/ini.h Normal file
View File

@ -0,0 +1,50 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (C) 2018 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 _INI_H_
#define _INI_H_
#include "../utils/types.h"
#include "../utils/list.h"
#define INI_CHOICE 3
#define INI_CAPTION 5
#define INI_CHGLINE 6
#define INI_NEWLINE 0xFE
#define INI_COMMENT 0xFF
typedef struct _ini_kv_t
{
char *key;
char *val;
link_t link;
} ini_kv_t;
typedef struct _ini_sec_t
{
char *name;
link_t kvs;
link_t link;
u32 type;
u32 color;
} ini_sec_t;
int ini_parse(link_t *dst, char *ini_path, bool is_dir);
char *ini_check_payload_section(ini_sec_t *cfg);
#endif

View File

@ -263,7 +263,6 @@ void gfx_putc(char c)
} }
break; break;
} }
} }
void gfx_puts(const char *s) void gfx_puts(const char *s)

225
source/gfx/tui.c Normal file
View File

@ -0,0 +1,225 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (c) 2018 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 "di.h"
#include "tui.h"
#include "../utils/btn.h"
#include "../config/config.h"
#include "../power/max17050.h"
#include "../utils/util.h"
#ifdef MENU_LOGO_ENABLE
extern u8 *Kc_MENU_LOGO;
#define X_MENU_LOGO 119
#define Y_MENU_LOGO 57
#define X_POS_MENU_LOGO 577
#define Y_POS_MENU_LOGO 1179
#endif //MENU_LOGO_ENABLE
extern hekate_config h_cfg;
void tui_sbar(bool force_update)
{
u32 cx, cy;
u32 timePassed = get_tmr_s() - h_cfg.sbar_time_keeping;
if (!force_update)
if (timePassed < 5)
return;
u8 prevFontSize = gfx_con.fntsz;
gfx_con.fntsz = 16;
h_cfg.sbar_time_keeping = get_tmr_s();
u32 battPercent = 0;
int battVoltCurr = 0;
gfx_con_getpos(&cx, &cy);
gfx_con_setpos(0, 1260);
max17050_get_property(MAX17050_RepSOC, (int *)&battPercent);
max17050_get_property(MAX17050_VCELL, &battVoltCurr);
gfx_clear_partial_grey(0x30, 1256, 24);
gfx_printf("%K%k Battery: %d.%d%% (%d mV) - Charge:", 0xFF303030, 0xFF888888,
(battPercent >> 8) & 0xFF, (battPercent & 0xFF) / 26, battVoltCurr);
max17050_get_property(MAX17050_Current, &battVoltCurr);
if (battVoltCurr >= 0)
gfx_printf(" %k+%d mA%k%K\n",
0xFF008800, battVoltCurr / 1000, 0xFFCCCCCC, 0xFF1B1B1B);
else
gfx_printf(" %k-%d mA%k%K\n",
0xFF880000, (~battVoltCurr) / 1000, 0xFFCCCCCC, 0xFF1B1B1B);
gfx_con.fntsz = prevFontSize;
gfx_con_setpos(cx, cy);
}
void tui_pbar(int x, int y, u32 val, u32 fgcol, u32 bgcol)
{
u32 cx, cy;
if (val > 200)
val = 200;
gfx_con_getpos(&cx, &cy);
gfx_con_setpos(x, y);
gfx_printf("%k[%3d%%]%k", fgcol, val, 0xFFCCCCCC);
x += 7 * gfx_con.fntsz;
for (int i = 0; i < (gfx_con.fntsz >> 3) * 6; i++)
{
gfx_line(x, y + i + 1, x + 3 * val, y + i + 1, fgcol);
gfx_line(x + 3 * val, y + i + 1, x + 3 * 100, y + i + 1, bgcol);
}
gfx_con_setpos(cx, cy);
// Update status bar.
tui_sbar(false);
}
void *tui_do_menu(menu_t *menu)
{
int idx = 0, prev_idx = 0, cnt = 0x7FFFFFFF;
gfx_clear_partial_grey(0x1B, 0, 1256);
tui_sbar(true);
#ifdef MENU_LOGO_ENABLE
gfx_set_rect_rgb(Kc_MENU_LOGO,
X_MENU_LOGO, Y_MENU_LOGO, X_POS_MENU_LOGO, Y_POS_MENU_LOGO);
#endif //MENU_LOGO_ENABLE
while (true)
{
gfx_con_setcol(0xFFCCCCCC, 1, 0xFF1B1B1B);
gfx_con_setpos(menu->x, menu->y);
gfx_printf("[%kLo%kck%kpi%kck%k_R%kCM%k v%d.%d.%d%k]\n\n",
colors[0], colors[1], colors[2], colors[3], colors[4], colors[5], 0xFFFF00FF, LP_VER_MJ, LP_VER_MN, LP_VER_BF, 0xFFCCCCCC);
// Skip caption or seperator lines selection.
while (menu->ents[idx].type == MENT_CAPTION ||
menu->ents[idx].type == MENT_CHGLINE)
{
if (prev_idx <= idx || (!idx && prev_idx == cnt - 1))
{
idx++;
if (idx > (cnt - 1))
{
idx = 0;
prev_idx = 0;
}
}
else
{
idx--;
if (idx < 0)
{
idx = cnt - 1;
prev_idx = cnt;
}
}
}
prev_idx = idx;
// Draw the menu.
for (cnt = 0; menu->ents[cnt].type != MENT_END; cnt++)
{
if (cnt == idx)
gfx_con_setcol(0xFF1B1B1B, 1, 0xFFCCCCCC);
else
gfx_con_setcol(0xFFCCCCCC, 1, 0xFF1B1B1B);
if (menu->ents[cnt].type != MENT_CHGLINE && menu->ents[cnt].type != MENT_MENU) {
if (cnt == idx)
gfx_printf(" %s", menu->ents[cnt].caption);
else
gfx_printf("%k %s", menu->ents[cnt].color, menu->ents[cnt].caption);
}
if(menu->ents[cnt].type == MENT_MENU)
gfx_printf("%k...", 0xFF0099EE);
gfx_printf(" \n");
}
gfx_con_setcol(0xFFCCCCCC, 1, 0xFF1B1B1B);
gfx_putc('\n');
// Print help and battery status.
gfx_con_setpos(0, 1127);
if (h_cfg.emummc_force_disable)
gfx_printf("%kNo emuMMC config found.\n", 0xFF800000);
gfx_con_setpos(0, 1191);
gfx_printf("%k VOL: Move up/down\n PWR: Select option%k", 0xFF555555, 0xFFCCCCCC);
display_backlight_brightness(h_cfg.backlight, 1000);
// Wait for user command.
u32 btn = btn_wait();
if (btn & BTN_VOL_DOWN && idx < (cnt - 1))
idx++;
else if (btn & BTN_VOL_DOWN && idx == (cnt - 1))
{
idx = 0;
prev_idx = -1;
}
if (btn & BTN_VOL_UP && idx > 0)
idx--;
else if (btn & BTN_VOL_UP && idx == 0)
{
idx = cnt - 1;
prev_idx = cnt;
}
if (btn & BTN_POWER)
{
ment_t *ent = &menu->ents[idx];
switch (ent->type)
{
case MENT_HANDLER:
ent->handler(ent->data);
break;
case MENT_MENU:
return tui_do_menu(ent->menu);
break;
case MENT_DATA:
return ent->data;
break;
case MENT_BACK:
return NULL;
break;
case MENT_HDLR_RE:
ent->handler(ent);
if (!ent->data)
return NULL;
break;
default:
break;
}
gfx_con.fntsz = 16;
gfx_clear_partial_grey(0x1B, 0, 1256);
#ifdef MENU_LOGO_ENABLE
gfx_set_rect_rgb(Kc_MENU_LOGO,
X_MENU_LOGO, Y_MENU_LOGO, X_POS_MENU_LOGO, Y_POS_MENU_LOGO);
#endif //MENU_LOGO_ENABLE
}
tui_sbar(false);
}
return NULL;
}

66
source/gfx/tui.h Normal file
View File

@ -0,0 +1,66 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (C) 2018 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 _TUI_H_
#define _TUI_H_
#include "../utils/types.h"
#include "gfx.h"
#define MENT_END 0
#define MENT_HANDLER 1
#define MENT_MENU 2
#define MENT_DATA 3
#define MENT_BACK 4
#define MENT_CAPTION 5
#define MENT_CHGLINE 6
#define MENT_HDLR_RE 7
typedef struct _ment_t
{
u32 type;
const char *caption;
u32 color;
void *data;
union
{
void(*handler)(void *);
struct _menu_t *menu;
};
} ment_t;
typedef struct _menu_t
{
ment_t *ents;
const char *caption;
u32 x;
u32 y;
} menu_t;
#define MDEF_END() {MENT_END}
#define MDEF_HANDLER(caption, _handler, color) { MENT_HANDLER, caption, color, NULL, { .handler = _handler } }
#define MDEF_HANDLER_EX(caption, data, _handler, color) { MENT_HANDLER, caption, color, data, { .handler = _handler } }
#define MDEF_MENU(caption, _menu) { MENT_MENU, caption, 0, NULL, { .menu = _menu } }
#define MDEF_BACK() { MENT_BACK, "Back" }
#define MDEF_CAPTION(caption, color) { MENT_CAPTION, caption, color }
#define MDEF_CHGLINE() {MENT_CHGLINE}
void tui_sbar(bool force_update);
void tui_pbar(int x, int y, u32 val, u32 fgcol, u32 bgcol);
void *tui_do_menu(menu_t *menu);
#endif

View File

@ -56,6 +56,7 @@ u8 warmboot_reboot[] = {
#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 void sd_unmount(); extern void sd_unmount();
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);
@ -115,7 +116,7 @@ int reboot_to_sept(const u8 *tsec_fw, const u32 tsec_size, const u32 kb)
f_close(&fp); f_close(&fp);
sd_unmount(); sd_unmount();
gfx_printf("\n%kPress Power or Vol +/-\n%k to Reboot to Sept...", COLOR_BLUE, COLOR_VIOLET); gfx_printf("\n%kPress Power or Vol +/-\n to Reboot to Sept...", colors[(color_idx++) % 6]);
btn_wait(); btn_wait();
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);

131
source/ianos/ianos.c Normal file
View File

@ -0,0 +1,131 @@
/*
* Copyright (c) 2018 M4xw
* 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/>.
*/
#include <string.h>
#include "ianos.h"
#include "../utils/types.h"
#include "../libs/elfload/elfload.h"
#include "../../common/common_module.h"
#include "../mem/heap.h"
#include "../gfx/gfx.h"
#define IRAM_LIB_ADDR 0x4002B000
#define DRAM_LIB_ADDR 0xE0000000
extern heap_t _heap;
extern void *sd_file_read(const char *path, u32 *fsize);
extern bool sd_mount();
extern void sd_unmount();
void *elfBuf = NULL;
void *fileBuf = NULL;
static void _ianos_call_ep(moduleEntrypoint_t entrypoint, void *moduleConfig)
{
bdkParams_t bdkParameters = (bdkParams_t)malloc(sizeof(struct _bdkParams_t));
bdkParameters->gfxCon = &gfx_con;
bdkParameters->gfxCtx = &gfx_ctxt;
bdkParameters->memcpy = (memcpy_t)&memcpy;
bdkParameters->memset = (memset_t)&memset;
bdkParameters->sharedHeap = &_heap;
entrypoint(moduleConfig, bdkParameters);
}
static void *_ianos_alloc_cb(el_ctx *ctx, Elf_Addr phys, Elf_Addr virt, Elf_Addr size)
{
(void)ctx;
(void)phys;
(void)size;
return (void *)virt;
}
static bool _ianos_read_cb(el_ctx *ctx, void *dest, size_t numberBytes, size_t offset)
{
(void)ctx;
memcpy(dest, fileBuf + offset, numberBytes);
return true;
}
//TODO: Support shared libraries.
uintptr_t ianos_loader(bool sdmount, char *path, elfType_t type, void *moduleConfig)
{
uintptr_t epaddr = 0;
if (sdmount)
{
if (!sd_mount())
goto elfLoadFinalOut;
}
fileBuf = sd_file_read(path, NULL);
if (sdmount)
sd_unmount();
if (!fileBuf)
goto elfLoadFinalOut;
el_ctx ctx;
ctx.pread = _ianos_read_cb;
if (el_init(&ctx))
goto elfLoadFinalOut;
// Set our relocated library's buffer.
switch (type & 0xFFFF)
{
case EXEC_ELF:
case AR64_ELF:
elfBuf = (void *)DRAM_LIB_ADDR;
sd_unmount();
break;
default:
elfBuf = malloc(ctx.memsz); // Aligned to 0x10 by default.
}
if (!elfBuf)
goto elfLoadFinalOut;
// Load and relocate library.
ctx.base_load_vaddr = ctx.base_load_paddr = (uintptr_t)elfBuf;
if (el_load(&ctx, _ianos_alloc_cb))
goto elfFreeOut;
if (el_relocate(&ctx))
goto elfFreeOut;
// Launch.
epaddr = ctx.ehdr.e_entry + (uintptr_t)elfBuf;
moduleEntrypoint_t ep = (moduleEntrypoint_t)epaddr;
_ianos_call_ep(ep, moduleConfig);
elfFreeOut:
free(fileBuf);
elfBuf = NULL;
fileBuf = NULL;
elfLoadFinalOut:
return epaddr;
}

34
source/ianos/ianos.h Normal file
View File

@ -0,0 +1,34 @@
/*
* Copyright (c) 2018 M4xw
* Copyright (c) 2018 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 IANOS_H
#define IANOS_H
#include "../utils/types.h"
typedef enum
{
DRAM_LIB = 0, // DRAM library.
EXEC_ELF = 1, // Executable elf that does not return.
DR64_LIB = 2, // AARCH64 DRAM library.
AR64_ELF = 3, // Executable elf that does not return.
KEEP_IN_RAM = (1 << 31) // Shared library mask.
} elfType_t;
uintptr_t ianos_loader(bool sdmount, char *path, elfType_t type, void* config);
#endif

View File

@ -68,6 +68,28 @@ static const u8 master_key_source[0x10] = {
0xD8, 0xA2, 0x41, 0x0A, 0xC6, 0xC5, 0x90, 0x01, 0xC6, 0x1D, 0x6A, 0x26, 0x7C, 0x51, 0x3F, 0x3C}; 0xD8, 0xA2, 0x41, 0x0A, 0xC6, 0xC5, 0x90, 0x01, 0xC6, 0x1D, 0x6A, 0x26, 0x7C, 0x51, 0x3F, 0x3C};
static const u8 per_console_key_source[0x10] = { static const u8 per_console_key_source[0x10] = {
0x4F, 0x02, 0x5F, 0x0E, 0xB6, 0x6D, 0x11, 0x0E, 0xDC, 0x32, 0x7D, 0x41, 0x86, 0xC2, 0xF4, 0x78}; 0x4F, 0x02, 0x5F, 0x0E, 0xB6, 0x6D, 0x11, 0x0E, 0xDC, 0x32, 0x7D, 0x41, 0x86, 0xC2, 0xF4, 0x78};
static const u8 per_console_key_source_4x[0x10] = {
0x0C, 0x91, 0x09, 0xDB, 0x93, 0x93, 0x07, 0x81, 0x07, 0x3C, 0xC4, 0x16, 0x22, 0x7C, 0x6C, 0x28};
static const u8 new_device_key_sources[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_VERSION_400 + 1][0x10] = {
{0x8B, 0x4E, 0x1C, 0x22, 0x42, 0x07, 0xC8, 0x73, 0x56, 0x94, 0x08, 0x8B, 0xCC, 0x47, 0x0F, 0x5D}, /* 4.x New Device Key Source. */
{0x6C, 0xEF, 0xC6, 0x27, 0x8B, 0xEC, 0x8A, 0x91, 0x99, 0xAB, 0x24, 0xAC, 0x4F, 0x1C, 0x8F, 0x1C}, /* 5.x New Device Key Source. */
{0x70, 0x08, 0x1B, 0x97, 0x44, 0x64, 0xF8, 0x91, 0x54, 0x9D, 0xC6, 0x84, 0x8F, 0x1A, 0xB2, 0xE4}, /* 6.x New Device Key Source. */
{0x8E, 0x09, 0x1F, 0x7A, 0xBB, 0xCA, 0x6A, 0xFB, 0xB8, 0x9B, 0xD5, 0xC1, 0x25, 0x9C, 0xA9, 0x17}, /* 6.2.0 New Device Key Source. */
{0x8F, 0x77, 0x5A, 0x96, 0xB0, 0x94, 0xFD, 0x8D, 0x28, 0xE4, 0x19, 0xC8, 0x16, 0x1C, 0xDB, 0x3D}, /* 7.0.0 New Device Key Source. */
{0x67, 0x62, 0xD4, 0x8E, 0x55, 0xCF, 0xFF, 0x41, 0x31, 0x15, 0x3B, 0x24, 0x0C, 0x7C, 0x07, 0xAE}, /* 8.1.0 New Device Key Source. */
{0x4A, 0xC3, 0x4E, 0x14, 0x8B, 0x96, 0x4A, 0xD5, 0xD4, 0x99, 0x73, 0xC4, 0x45, 0xAB, 0x8B, 0x49}, /* 9.0.0 New Device Key Source. */
};
static const u8 new_device_keygen_sources[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_VERSION_400 + 1][0x10] = {
{0x88, 0x62, 0x34, 0x6E, 0xFA, 0xF7, 0xD8, 0x3F, 0xE1, 0x30, 0x39, 0x50, 0xF0, 0xB7, 0x5D, 0x5D}, /* 4.x New Device Keygen Source. */
{0x06, 0x1E, 0x7B, 0xE9, 0x6D, 0x47, 0x8C, 0x77, 0xC5, 0xC8, 0xE7, 0x94, 0x9A, 0xA8, 0x5F, 0x2E}, /* 5.x New Device Keygen Source. */
{0x99, 0xFA, 0x98, 0xBD, 0x15, 0x1C, 0x72, 0xFD, 0x7D, 0x9A, 0xD5, 0x41, 0x00, 0xFD, 0xB2, 0xEF}, /* 6.x New Device Keygen Source. */
{0x81, 0x3C, 0x6C, 0xBF, 0x5D, 0x21, 0xDE, 0x77, 0x20, 0xD9, 0x6C, 0xE3, 0x22, 0x06, 0xAE, 0xBB}, /* 6.2.0 New Device Keygen Source. */
{0x86, 0x61, 0xB0, 0x16, 0xFA, 0x7A, 0x9A, 0xEA, 0xF6, 0xF5, 0xBE, 0x1A, 0x13, 0x5B, 0x6D, 0x9E}, /* 7.0.0 New Device Keygen Source. */
{0xA6, 0x81, 0x71, 0xE7, 0xB5, 0x23, 0x74, 0xB0, 0x39, 0x8C, 0xB7, 0xFF, 0xA0, 0x62, 0x9F, 0x8D}, /* 8.1.0 New Device Keygen Source. */
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* TODO: 9.0.0 New Device Keygen Source to be added on next change-of-keys. */
};
// from SPL // from SPL
static const u8 aes_key_generation_source[0x10] = { static const u8 aes_key_generation_source[0x10] = {

View File

@ -15,14 +15,18 @@
*/ */
#include "keys.h" #include "keys.h"
#include "../config/config.h"
#include "../gfx/di.h" #include "../gfx/di.h"
#include "../gfx/gfx.h" #include "../gfx/gfx.h"
#include "../gfx/tui.h"
#include "../hos/pkg1.h" #include "../hos/pkg1.h"
#include "../hos/pkg2.h" #include "../hos/pkg2.h"
#include "../hos/sept.h" #include "../hos/sept.h"
#include "../libs/fatfs/ff.h" #include "../libs/fatfs/ff.h"
#include "../mem/heap.h" #include "../mem/heap.h"
#include "../mem/mc.h" #include "../mem/mc.h"
#include "../mem/minerva.h"
#include "../mem/sdram.h" #include "../mem/sdram.h"
#include "../sec/se.h" #include "../sec/se.h"
#include "../sec/se_t210.h" #include "../sec/se_t210.h"
@ -30,6 +34,7 @@
#include "../soc/fuse.h" #include "../soc/fuse.h"
#include "../soc/smmu.h" #include "../soc/smmu.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/sdmmc.h" #include "../storage/sdmmc.h"
#include "../utils/btn.h" #include "../utils/btn.h"
@ -45,77 +50,98 @@ extern bool sd_mount();
extern void sd_unmount(); extern void sd_unmount();
extern int sd_save_to_file(void *buf, u32 size, const char *filename); extern int sd_save_to_file(void *buf, u32 size, const char *filename);
u32 _key_count = 0; extern hekate_config h_cfg;
extern bool clear_sector_cache;
u32 _key_count = 0, _titlekey_count = 0;
u32 color_idx = 0;
sdmmc_storage_t storage; sdmmc_storage_t storage;
emmc_part_t *system_part; emmc_part_t *system_part;
u32 start_time, end_time;
#define TPRINTF(text) \ #define TPRINTF(text) \
end_time = get_tmr_ms(); \ end_time = get_tmr_us(); \
gfx_printf(text" done @ %d.%03ds\n", (end_time - start_time) / 1000, (end_time - start_time) % 1000) gfx_printf(text" done in %d us\n", end_time - start_time); \
start_time = get_tmr_us(); \
minerva_periodic_training()
#define TPRINTFARGS(text, args...) \ #define TPRINTFARGS(text, args...) \
end_time = get_tmr_ms(); \ end_time = get_tmr_us(); \
gfx_printf(text" done @ %d.%03ds\n", args, (end_time - start_time) / 1000, (end_time - start_time) % 1000) gfx_printf(text" done in %d us\n", args, end_time - start_time); \
start_time = get_tmr_us(); \
minerva_periodic_training()
#define SAVE_KEY(name, src, len) _save_key(name, src, len, text_buffer) #define SAVE_KEY(name, src, len) _save_key(name, src, len, text_buffer)
#define SAVE_KEY_FAMILY(name, src, count, len) _save_key_family(name, src, count, len, text_buffer) #define SAVE_KEY_FAMILY(name, src, start, count, len) _save_key_family(name, src, start, count, len, text_buffer)
static u8 temp_key[0x10],
bis_key[4][0x20] = {0},
device_key[0x10] = {0},
sd_seed[0x10] = {0},
// FS-related keys
fs_keys[10][0x20] = {0},
header_key[0x20] = {0},
save_mac_key[0x10] = {0},
// other sysmodule sources
es_keys[3][0x10] = {0},
eticket_rsa_kek[0x10] = {0},
ssl_keys[2][0x10] = {0},
ssl_rsa_kek[0x10] = {0},
// keyblob-derived families
keyblob[KB_FIRMWARE_VERSION_600+1][0x90] = {0},
keyblob_key[KB_FIRMWARE_VERSION_600+1][0x10] = {0},
keyblob_mac_key[KB_FIRMWARE_VERSION_600+1][0x10] = {0},
package1_key[KB_FIRMWARE_VERSION_600+1][0x10] = {0},
// master key-derived families
key_area_key[3][KB_FIRMWARE_VERSION_MAX+1][0x10] = {0},
master_kek[KB_FIRMWARE_VERSION_MAX+1][0x10] = {0},
master_key[KB_FIRMWARE_VERSION_MAX+1][0x10] = {0},
package2_key[KB_FIRMWARE_VERSION_MAX+1][0x10] = {0},
titlekek[KB_FIRMWARE_VERSION_MAX+1][0x10] = {0};
static const u32 colors[6] = {COLOR_RED, COLOR_ORANGE, COLOR_YELLOW, COLOR_GREEN, COLOR_BLUE, COLOR_VIOLET};
// key functions // key functions
static bool _key_exists(const void *data) { return memcmp(data, zeros, 0x10); }; static bool _key_exists(const void *data) { return memcmp(data, zeros, 0x10); };
static void _save_key(const char *name, const void *data, const u32 len, char *outbuf); static void _save_key(const char *name, const void *data, u32 len, char *outbuf);
static void _save_key_family(const char *name, const void *data, const u32 num_keys, const u32 len, char *outbuf); static void _save_key_family(const char *name, const void *data, u32 start_key, u32 num_keys, u32 len, char *outbuf);
static void _generate_kek(u32 ks, const void *key_source, void *master_key, const void *kek_seed, const void *key_seed); static void _generate_kek(u32 ks, const void *key_source, void *master_key, const void *kek_seed, const void *key_seed);
// nca functions // nca functions
static void *_nca_process(u32 hk_ks1, u32 hk_ks2, FIL *fp, u32 key_offset, u32 len); static void *_nca_process(u32 hk_ks1, u32 hk_ks2, FIL *fp, u32 key_offset, u32 len, const u8 key_area_key[3][KB_FIRMWARE_VERSION_MAX+1][0x10]);
static u32 _nca_fread_ctr(u32 ks, FIL *fp, void *buffer, u32 offset, u32 len, u8 *ctr); static u32 _nca_fread_ctr(u32 ks, FIL *fp, void *buffer, u32 offset, u32 len, u8 *ctr);
static void _update_ctr(u8 *ctr, u32 ofs); static void _update_ctr(u8 *ctr, u32 ofs);
// titlekey functions
static bool _test_key_pair(const void *E, const void *D, const void *N);
static void _mgf1_xor(void *masked, u32 masked_size, const void *seed, u32 seed_size);
void dump_keys() { void dump_keys() {
display_backlight_brightness(100, 1000); u8 temp_key[0x10],
gfx_clear_grey(0x1B); bis_key[4][0x20] = {0},
device_key[0x10] = {0},
new_device_key[0x10] = {0},
sd_seed[0x10] = {0},
// FS-related keys
fs_keys[10][0x20] = {0},
header_key[0x20] = {0},
save_mac_key[0x10] = {0},
// other sysmodule sources
es_keys[3][0x10] = {0},
eticket_rsa_kek[0x10] = {0},
ssl_keys[0x10] = {0},
ssl_rsa_kek[0x10] = {0},
// keyblob-derived families
keyblob[KB_FIRMWARE_VERSION_600+1][0x90] = {0},
keyblob_key[KB_FIRMWARE_VERSION_600+1][0x10] = {0},
keyblob_mac_key[KB_FIRMWARE_VERSION_600+1][0x10] = {0},
package1_key[KB_FIRMWARE_VERSION_600+1][0x10] = {0},
// master key-derived families
key_area_key[3][KB_FIRMWARE_VERSION_MAX+1][0x10] = {0},
master_kek[KB_FIRMWARE_VERSION_MAX+1][0x10] = {0},
master_key[KB_FIRMWARE_VERSION_MAX+1][0x10] = {0},
package2_key[KB_FIRMWARE_VERSION_MAX+1][0x10] = {0},
titlekek[KB_FIRMWARE_VERSION_MAX+1][0x10] = {0};
display_backlight_brightness(h_cfg.backlight, 1000);
gfx_clear_partial_grey(0x1B, 0, 1256);
gfx_con_setpos(0, 0); gfx_con_setpos(0, 0);
gfx_printf("[%kLo%kck%kpi%kck%k_R%kCM%k v%d.%d.%d%k]\n\n", gfx_printf("[%kLo%kck%kpi%kck%k_R%kCM%k v%d.%d.%d%k]\n\n",
colors[0], colors[1], colors[2], colors[3], colors[4], colors[5], 0xFFFF00FF, LP_VER_MJ, LP_VER_MN, LP_VER_BF, 0xFFCCCCCC); colors[0], colors[1], colors[2], colors[3], colors[4], colors[5], 0xFFFF00FF, LP_VER_MJ, LP_VER_MN, LP_VER_BF, 0xFFCCCCCC);
u32 start_time = get_tmr_ms(), tui_sbar(true);
end_time,
retries = 0; _key_count = 0;
_titlekey_count = 0;
color_idx = 0;
start_time = get_tmr_us();
u32 begin_time = get_tmr_us();
u32 retries = 0;
tsec_ctxt_t tsec_ctxt; tsec_ctxt_t tsec_ctxt;
sdmmc_t sdmmc; sdmmc_t sdmmc;
sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4); emummc_storage_init_mmc(&storage, &sdmmc);
TPRINTFARGS("%kMMC init... ", colors[(color_idx++) % 6]);
// Read package1. // Read package1.
u8 *pkg1 = (u8 *)malloc(0x40000); u8 *pkg1 = (u8 *)malloc(0x40000);
sdmmc_storage_set_mmc_partition(&storage, 1); emummc_storage_set_mmc_partition(&storage, 1);
sdmmc_storage_read(&storage, 0x100000 / NX_EMMC_BLOCKSIZE, 0x40000 / NX_EMMC_BLOCKSIZE, pkg1); emummc_storage_read(&storage, 0x100000 / NX_EMMC_BLOCKSIZE, 0x40000 / NX_EMMC_BLOCKSIZE, pkg1);
const pkg1_id_t *pkg1_id = pkg1_identify(pkg1); const pkg1_id_t *pkg1_id = pkg1_identify(pkg1);
if (!pkg1_id) { if (!pkg1_id) {
EPRINTF("Unknown pkg1 version."); EPRINTF("Unknown pkg1 version.");
@ -131,10 +157,12 @@ void dump_keys() {
} }
} }
if (!found_tsec_fw) { if (!found_tsec_fw) {
EPRINTF("Failed to locate TSEC firmware."); EPRINTF("Unable to locate TSEC firmware.");
goto out_wait; goto out_wait;
} }
minerva_periodic_training();
tsec_key_data_t *key_data = (tsec_key_data_t *)(tsec_ctxt.fw + TSEC_KEY_DATA_ADDR); tsec_key_data_t *key_data = (tsec_key_data_t *)(tsec_ctxt.fw + TSEC_KEY_DATA_ADDR);
tsec_ctxt.pkg1 = pkg1; tsec_ctxt.pkg1 = pkg1;
tsec_ctxt.size = 0x100 + key_data->blob0_size + key_data->blob1_size + key_data->blob2_size + key_data->blob3_size + key_data->blob4_size; tsec_ctxt.size = 0x100 + key_data->blob0_size + key_data->blob1_size + key_data->blob2_size + key_data->blob3_size + key_data->blob4_size;
@ -145,12 +173,13 @@ void dump_keys() {
} }
if (pkg1_id->kb >= KB_FIRMWARE_VERSION_700) { if (pkg1_id->kb >= KB_FIRMWARE_VERSION_700) {
sd_mount();
if (!f_stat("sd:/sept/payload.bak", NULL)) { if (!f_stat("sd:/sept/payload.bak", NULL)) {
f_unlink("sd:/sept/payload.bin"); f_unlink("sd:/sept/payload.bin");
f_rename("sd:/sept/payload.bak", "sd:/sept/payload.bin"); f_rename("sd:/sept/payload.bak", "sd:/sept/payload.bin");
} }
if (!(EMC(EMC_SCRATCH0) & EMC_SEPT_RUN)) { if (!h_cfg.sept_run) {
// bundle lp0 fw for sept instead of loading it from SD as hekate does // bundle lp0 fw for sept instead of loading it from SD as hekate does
sdram_lp0_save_params(sdram_get_params_patched()); sdram_lp0_save_params(sdram_get_params_patched());
FIL fp; FIL fp;
@ -166,8 +195,10 @@ void dump_keys() {
u32 payload_size = *(u32 *)(IPL_LOAD_ADDR + 0x84) - IPL_LOAD_ADDR; u32 payload_size = *(u32 *)(IPL_LOAD_ADDR + 0x84) - IPL_LOAD_ADDR;
f_write(&fp, (u8 *)IPL_LOAD_ADDR, payload_size, NULL); f_write(&fp, (u8 *)IPL_LOAD_ADDR, payload_size, NULL);
f_close(&fp); f_close(&fp);
gfx_printf("%kFirmware 7.x or higher detected.\n%kRenamed /sept/payload.bin", colors[0], colors[1]); gfx_printf("%k\nFirmware 7.x or higher detected.\n\n", colors[(color_idx++) % 6]);
gfx_printf("\n%k to /sept/payload.bak\n%kCopied self to /sept/payload.bin",colors[2], colors[3]); gfx_printf("%kRenamed /sept/payload.bin", colors[(color_idx++) % 6]);
gfx_printf("\n to /sept/payload.bak\n\n", colors[(color_idx++) % 6]);
gfx_printf("%kCopied self to /sept/payload.bin\n", colors[(color_idx++) % 6]);
sdmmc_storage_end(&storage); sdmmc_storage_end(&storage);
if (!reboot_to_sept((u8 *)tsec_ctxt.fw, tsec_ctxt.size, pkg1_id->kb)) if (!reboot_to_sept((u8 *)tsec_ctxt.fw, tsec_ctxt.size, pkg1_id->kb))
goto out_wait; goto out_wait;
@ -206,7 +237,7 @@ get_tsec: ;
goto out_wait; goto out_wait;
} }
TPRINTFARGS("%kTSEC key(s)... ", colors[0]); TPRINTFARGS("%kTSEC key(s)... ", colors[(color_idx++) % 6]);
// Master key derivation // Master key derivation
if (pkg1_id->kb == KB_FIRMWARE_VERSION_620 && _key_exists(tsec_keys + 0x10)) { if (pkg1_id->kb == KB_FIRMWARE_VERSION_620 && _key_exists(tsec_keys + 0x10)) {
@ -226,7 +257,8 @@ get_tsec: ;
se_aes_key_set(8, master_key[0], 0x10); se_aes_key_set(8, master_key[0], 0x10);
se_aes_crypt_block_ecb(8, 0, temp_key, mkey_vectors[0]); se_aes_crypt_block_ecb(8, 0, temp_key, mkey_vectors[0]);
if (_key_exists(temp_key)) { if (_key_exists(temp_key)) {
EPRINTFARGS("Failed to derive master key. kb = %d", pkg1_id->kb); EPRINTFARGS("Unable to derive master key. kb = %d.\n Put current sept files on SD and retry.", pkg1_id->kb);
memset(master_key, 0, sizeof(master_key));
} }
} else if (_key_exists(master_key[KB_FIRMWARE_VERSION_MAX])) { } else if (_key_exists(master_key[KB_FIRMWARE_VERSION_MAX])) {
// handle sept version differences // handle sept version differences
@ -244,7 +276,8 @@ get_tsec: ;
memcpy(master_key[kb], zeros, 0x10); memcpy(master_key[kb], zeros, 0x10);
} }
if (_key_exists(temp_key)) { if (_key_exists(temp_key)) {
EPRINTF("Failed to derive master key."); EPRINTF("Unable to derive master key.");
memset(master_key, 0, sizeof(master_key));
} }
} }
} }
@ -256,15 +289,18 @@ get_tsec: ;
se_aes_key_set(8, tsec_keys, 0x10); se_aes_key_set(8, tsec_keys, 0x10);
se_aes_key_set(9, sbk, 0x10); se_aes_key_set(9, sbk, 0x10);
for (u32 i = 0; i <= KB_FIRMWARE_VERSION_600; i++) { for (u32 i = 0; i <= KB_FIRMWARE_VERSION_600; i++) {
minerva_periodic_training();
se_aes_crypt_block_ecb(8, 0, keyblob_key[i], keyblob_key_source[i]); // temp = unwrap(kbks, tsec) se_aes_crypt_block_ecb(8, 0, keyblob_key[i], keyblob_key_source[i]); // temp = unwrap(kbks, tsec)
se_aes_crypt_block_ecb(9, 0, keyblob_key[i], keyblob_key[i]); // kbk = unwrap(temp, sbk) se_aes_crypt_block_ecb(9, 0, keyblob_key[i], keyblob_key[i]); // kbk = unwrap(temp, sbk)
se_aes_key_set(7, keyblob_key[i], 0x10); se_aes_key_set(7, keyblob_key[i], 0x10);
se_aes_crypt_block_ecb(7, 0, keyblob_mac_key[i], keyblob_mac_key_source); // kbm = unwrap(kbms, kbk) se_aes_crypt_block_ecb(7, 0, keyblob_mac_key[i], keyblob_mac_key_source); // kbm = unwrap(kbms, kbk)
if (i == 0) if (i == 0) {
se_aes_crypt_block_ecb(7, 0, device_key, per_console_key_source); // devkey = unwrap(pcks, kbk0) se_aes_crypt_block_ecb(7, 0, device_key, per_console_key_source); // devkey = unwrap(pcks, kbk0)
se_aes_crypt_block_ecb(7, 0, new_device_key, per_console_key_source_4x);
}
// verify keyblob is not corrupt // verify keyblob is not corrupt
sdmmc_storage_read(&storage, 0x180000 / NX_EMMC_BLOCKSIZE + i, 1, keyblob_block); emummc_storage_read(&storage, 0x180000 / NX_EMMC_BLOCKSIZE + i, 1, keyblob_block);
se_aes_key_set(3, keyblob_mac_key[i], 0x10); se_aes_key_set(3, keyblob_mac_key[i], 0x10);
se_aes_cmac(3, keyblob_mac, 0x10, keyblob_block + 0x10, 0xa0); se_aes_cmac(3, keyblob_mac, 0x10, keyblob_block + 0x10, 0xa0);
if (memcmp(keyblob_block, keyblob_mac, 0x10)) { if (memcmp(keyblob_block, keyblob_mac, 0x10)) {
@ -285,19 +321,33 @@ get_tsec: ;
} }
free(keyblob_block); free(keyblob_block);
TPRINTFARGS("%kMaster keys... ", colors[1]); TPRINTFARGS("%kMaster keys... ", colors[(color_idx++) % 6]);
/* key = unwrap(source, wrapped_key): /* key = unwrap(source, wrapped_key):
key_set(ks, wrapped_key), block_ecb(ks, 0, key, source) -> final key in key key_set(ks, wrapped_key), block_ecb(ks, 0, key, source) -> final key in key
*/ */
// TODO: fix bis key generation for newer unpatched consoles minerva_periodic_training();
u32 key_generation = 0;
if (pkg1_id->kb >= KB_FIRMWARE_VERSION_500) {
if ((fuse_read_odm(4) & 0x800) && fuse_read_odm(0) == 0x8E61ECAE && fuse_read_odm(1) == 0xF2BA3BB2) {
key_generation = fuse_read_odm(2) & 0x1F;
}
}
if (_key_exists(device_key)) { if (_key_exists(device_key)) {
se_aes_key_set(8, device_key, 0x10); if (key_generation) {
se_aes_key_set(8, new_device_key, 0x10);
se_aes_crypt_block_ecb(8, 0, temp_key, new_device_key_sources[pkg1_id->kb - KB_FIRMWARE_VERSION_400]);
se_aes_key_set(8, master_key[0], 0x10);
se_aes_unwrap_key(8, 8, new_device_keygen_sources[pkg1_id->kb - KB_FIRMWARE_VERSION_400]);
se_aes_crypt_block_ecb(8, 0, temp_key, temp_key);
} else
memcpy(temp_key, device_key, 0x10);
se_aes_key_set(8, temp_key, 0x10);
se_aes_unwrap_key(8, 8, retail_specific_aes_key_source); // kek = unwrap(rsaks, devkey) se_aes_unwrap_key(8, 8, retail_specific_aes_key_source); // kek = unwrap(rsaks, devkey)
se_aes_crypt_block_ecb(8, 0, bis_key[0] + 0x00, bis_key_source[0] + 0x00); // bkey = unwrap(bkeys, kek) se_aes_crypt_block_ecb(8, 0, bis_key[0] + 0x00, bis_key_source[0] + 0x00); // bkey = unwrap(bkeys, kek)
se_aes_crypt_block_ecb(8, 0, bis_key[0] + 0x10, bis_key_source[0] + 0x10); se_aes_crypt_block_ecb(8, 0, bis_key[0] + 0x10, bis_key_source[0] + 0x10);
// kek = generate_kek(bkeks, devkey, aeskek, aeskey) // kek = generate_kek(bkeks, devkey, aeskek, aeskey)
_generate_kek(8, bis_kek_source, device_key, aes_kek_generation_source, aes_key_generation_source); _generate_kek(8, bis_kek_source, temp_key, aes_kek_generation_source, aes_key_generation_source);
se_aes_crypt_block_ecb(8, 0, bis_key[1] + 0x00, bis_key_source[1] + 0x00); // bkey = unwrap(bkeys, kek) se_aes_crypt_block_ecb(8, 0, bis_key[1] + 0x00, bis_key_source[1] + 0x00); // bkey = unwrap(bkeys, kek)
se_aes_crypt_block_ecb(8, 0, bis_key[1] + 0x10, bis_key_source[1] + 0x10); se_aes_crypt_block_ecb(8, 0, bis_key[1] + 0x10, bis_key_source[1] + 0x10);
se_aes_crypt_block_ecb(8, 0, bis_key[2] + 0x00, bis_key_source[2] + 0x00); se_aes_crypt_block_ecb(8, 0, bis_key[2] + 0x00, bis_key_source[2] + 0x00);
@ -309,7 +359,7 @@ get_tsec: ;
u8 *pkg2 = NULL; u8 *pkg2 = NULL;
pkg2_kip1_info_t *ki = NULL; pkg2_kip1_info_t *ki = NULL;
sdmmc_storage_set_mmc_partition(&storage, 0); emummc_storage_set_mmc_partition(&storage, 0);
// Parse eMMC GPT. // Parse eMMC GPT.
LIST_INIT(gpt); LIST_INIT(gpt);
nx_emmc_gpt_parse(&gpt, &storage); nx_emmc_gpt_parse(&gpt, &storage);
@ -317,7 +367,7 @@ get_tsec: ;
// Find package2 partition. // Find package2 partition.
emmc_part_t *pkg2_part = nx_emmc_part_find(&gpt, "BCPKG2-1-Normal-Main"); emmc_part_t *pkg2_part = nx_emmc_part_find(&gpt, "BCPKG2-1-Normal-Main");
if (!pkg2_part) { if (!pkg2_part) {
EPRINTF("Failed to locate Package2."); EPRINTF("Unable to locate Package2.");
goto pkg2_done; goto pkg2_done;
} }
@ -338,6 +388,7 @@ get_tsec: ;
nx_emmc_part_read(&storage, pkg2_part, 0x4000 / NX_EMMC_BLOCKSIZE, pkg2_size_aligned / NX_EMMC_BLOCKSIZE, pkg2); nx_emmc_part_read(&storage, pkg2_part, 0x4000 / NX_EMMC_BLOCKSIZE, pkg2_size_aligned / NX_EMMC_BLOCKSIZE, pkg2);
// Decrypt package2 and parse KIP1 blobs in INI1 section. Try all available key generations in case of pkg1/pkg2 mismatch. // Decrypt package2 and parse KIP1 blobs in INI1 section. Try all available key generations in case of pkg1/pkg2 mismatch.
minerva_periodic_training();
pkg2_hdr_t *pkg2_hdr; pkg2_hdr_t *pkg2_hdr;
pkg2_hdr_t hdr; pkg2_hdr_t hdr;
u32 pkg2_kb; u32 pkg2_kb;
@ -350,18 +401,18 @@ get_tsec: ;
break; break;
} }
if (pkg2_kb == MAX_KEY) { if (pkg2_kb == MAX_KEY) {
EPRINTF("Failed to derive Package2 key."); EPRINTF("Unable to derive Package2 key.");
goto pkg2_done; goto pkg2_done;
} else if (pkg2_kb != pkg1_id->kb) } else if (pkg2_kb != pkg1_id->kb)
EPRINTF("Warning: Package1-Package2 mismatch."); EPRINTFARGS("Warning! Package1-Package2 mismatch: %d, %d", pkg1_id->kb, pkg2_kb);
pkg2_hdr = pkg2_decrypt(pkg2); pkg2_hdr = pkg2_decrypt(pkg2);
if (!pkg2_hdr) { if (!pkg2_hdr) {
EPRINTF("Failed to decrypt Package2."); EPRINTF("Unable to decrypt Package2.");
goto pkg2_done; goto pkg2_done;
} }
TPRINTFARGS("%kDecrypt pkg2... ", colors[2]); TPRINTFARGS("%kDecrypt pkg2... ", colors[(color_idx++) % 6]);
LIST_INIT(kip1_info); LIST_INIT(kip1_info);
bool new_pkg2; bool new_pkg2;
@ -377,12 +428,12 @@ get_tsec: ;
free(CONTAINER_OF(iter, pkg2_kip1_info_t, link)); free(CONTAINER_OF(iter, pkg2_kip1_info_t, link));
if (!ki) { if (!ki) {
EPRINTF("Failed to parse INI1."); EPRINTF("Unable to parse INI1.");
goto pkg2_done; goto pkg2_done;
} }
pkg2_decompress_kip(ki, 2 | 4); // we only need .rodata and .data pkg2_decompress_kip(ki, 2 | 4); // we only need .rodata and .data
TPRINTFARGS("%kDecompress FS...", colors[3]); TPRINTFARGS("%kDecompress FS...", colors[(color_idx++) % 6]);
u8 hash_index = 0, hash_max = 9, hash_order[10], u8 hash_index = 0, hash_max = 9, hash_order[10],
key_lengths[10] = {0x10, 0x20, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x20, 0x20}; key_lengths[10] = {0x10, 0x20, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x20, 0x20};
@ -456,6 +507,7 @@ get_tsec: ;
u8 temp_hash[0x20]; u8 temp_hash[0x20];
for (u32 i = ki->kip1->sections[0].size_comp + start_offset; i < ki->size - 0x20; ) { for (u32 i = ki->kip1->sections[0].size_comp + start_offset; i < ki->size - 0x20; ) {
minerva_periodic_training();
se_calc_sha256(temp_hash, ki->kip1->data + i, key_lengths[hash_order[hash_index]]); se_calc_sha256(temp_hash, ki->kip1->data + i, key_lengths[hash_order[hash_index]]);
if (!memcmp(temp_hash, fs_hashes_sha256[hash_order[hash_index]], 0x20)) { if (!memcmp(temp_hash, fs_hashes_sha256[hash_order[hash_index]], 0x20)) {
memcpy(fs_keys[hash_order[hash_index]], ki->kip1->data + i, key_lengths[hash_order[hash_index]]); memcpy(fs_keys[hash_order[hash_index]], ki->kip1->data + i, key_lengths[hash_order[hash_index]]);
@ -475,12 +527,13 @@ get_tsec: ;
i += alignment; i += alignment;
} }
} }
pkg2_done: pkg2_done:
free(pkg2); free(pkg2);
free(ki); free(ki);
TPRINTFARGS("%kFS keys... ", colors[4]); u8 *rights_ids = NULL, *titlekeys = NULL;
TPRINTFARGS("%kFS keys... ", colors[(color_idx++) % 6]);
if (_key_exists(fs_keys[0]) && _key_exists(fs_keys[1]) && _key_exists(master_key[0])) { if (_key_exists(fs_keys[0]) && _key_exists(fs_keys[1]) && _key_exists(master_key[0])) {
_generate_kek(8, fs_keys[0], master_key[0], aes_kek_generation_source, aes_key_generation_source); _generate_kek(8, fs_keys[0], master_key[0], aes_kek_generation_source, aes_key_generation_source);
@ -510,7 +563,6 @@ pkg2_done:
se_aes_crypt_block_ecb(8, 0, titlekek[i], titlekek_source); se_aes_crypt_block_ecb(8, 0, titlekek[i], titlekek_source);
} }
if (!_key_exists(header_key) || !_key_exists(bis_key[2])) if (!_key_exists(header_key) || !_key_exists(bis_key[2]))
{ {
EPRINTF("Missing FS keys. Skipping ES/SSL keys."); EPRINTF("Missing FS keys. Skipping ES/SSL keys.");
@ -524,12 +576,12 @@ pkg2_done:
system_part = nx_emmc_part_find(&gpt, "SYSTEM"); system_part = nx_emmc_part_find(&gpt, "SYSTEM");
if (!system_part) { if (!system_part) {
EPRINTF("Failed to locate System partition."); EPRINTF("Unable to locate System partition.");
goto key_output; goto key_output;
} }
__attribute__ ((aligned (16))) FATFS emmc_fs; __attribute__ ((aligned (16))) FATFS emmc_fs;
if (f_mount(&emmc_fs, "emmc:", 1)) { if (f_mount(&emmc_fs, "emmc:", 1)) {
EPRINTF("Mount failed."); EPRINTF("Unable to mount system partition.");
goto key_output; goto key_output;
} }
@ -545,7 +597,7 @@ pkg2_done:
u8 *temp_file = NULL; u8 *temp_file = NULL;
if (f_opendir(&dir, path)) { if (f_opendir(&dir, path)) {
EPRINTF("Failed to open System:/Contents/registered."); EPRINTF("Unable to open System:/Contents/registered.");
goto dismount; goto dismount;
} }
@ -554,14 +606,14 @@ pkg2_done:
f_closedir(&dir); f_closedir(&dir);
if (f_opendir(&dir, path)) { if (f_opendir(&dir, path)) {
EPRINTF("Failed to open System:/Contents/registered."); EPRINTF("Unable to open System:/Contents/registered.");
goto dismount; goto dismount;
} }
path[25] = '/'; path[25] = '/';
start_offset = 0; start_offset = 0;
while (!f_readdir(&dir, &fno) && fno.fname[0] && titles_found < title_limit) { while (!f_readdir(&dir, &fno) && fno.fname[0] && titles_found < title_limit) {
minerva_periodic_training();
memcpy(path + 26, fno.fname, 36); memcpy(path + 26, fno.fname, 36);
path[62] = 0; path[62] = 0;
if (fno.fattrib & AM_DIR) if (fno.fattrib & AM_DIR)
@ -611,7 +663,7 @@ pkg2_done:
} }
hash_index = 0; hash_index = 0;
// decrypt only what is needed to locate needed keys // decrypt only what is needed to locate needed keys
temp_file = (u8*)_nca_process(5, 4, &fp, start_offset, 0xc0); temp_file = (u8*)_nca_process(5, 4, &fp, start_offset, 0xc0, key_area_key);
for (u32 i = 0; i <= 0xb0; ) { for (u32 i = 0; i <= 0xb0; ) {
se_calc_sha256(temp_hash, temp_file + i, 0x10); se_calc_sha256(temp_hash, temp_file + i, 0x10);
if (!memcmp(temp_hash, es_hashes_sha256[hash_order[hash_index]], 0x10)) { if (!memcmp(temp_hash, es_hashes_sha256[hash_order[hash_index]], 0x10)) {
@ -657,11 +709,11 @@ pkg2_done:
} }
if (!memcmp(pkg1_id->id, "2016", 4)) if (!memcmp(pkg1_id->id, "2016", 4))
start_offset = 0x449dc; start_offset = 0x449dc;
temp_file = (u8*)_nca_process(5, 4, &fp, start_offset, 0x70); temp_file = (u8*)_nca_process(5, 4, &fp, start_offset, 0x70, key_area_key);
for (u32 i = 0; i <= 0x60; i++) { for (u32 i = 0; i <= 0x60; i++) {
se_calc_sha256(temp_hash, temp_file + i, 0x10); se_calc_sha256(temp_hash, temp_file + i, 0x10);
if (!memcmp(temp_hash, ssl_hashes_sha256[1], 0x10)) { if (!memcmp(temp_hash, ssl_hashes_sha256[1], 0x10)) {
memcpy(ssl_keys[1], temp_file + i, 0x10); memcpy(ssl_keys, temp_file + i, 0x10);
// only get ssl_rsa_kek_source_x from SSL on 1.0.0 // only get ssl_rsa_kek_source_x from SSL on 1.0.0
// we get it from ES on every other firmware // we get it from ES on every other firmware
// and it's located oddly distant from ssl_rsa_kek_source_y on >= 6.0.0 // and it's located oddly distant from ssl_rsa_kek_source_y on >= 6.0.0
@ -682,24 +734,43 @@ pkg2_done:
f_closedir(&dir); f_closedir(&dir);
free(dec_header); free(dec_header);
// derive eticket_rsa_kek and ssl_rsa_kek
if (_key_exists(es_keys[0]) && _key_exists(es_keys[1]) && _key_exists(master_key[0])) {
for (u32 i = 0; i < 0x10; i++)
temp_key[i] = aes_kek_generation_source[i] ^ aes_kek_seed_03[i];
_generate_kek(7, es_keys[1], master_key[0], temp_key, NULL);
se_aes_crypt_block_ecb(7, 0, eticket_rsa_kek, es_keys[0]);
}
if (_key_exists(ssl_keys) && _key_exists(es_keys[2]) && _key_exists(master_key[0])) {
for (u32 i = 0; i < 0x10; i++)
temp_key[i] = aes_kek_generation_source[i] ^ aes_kek_seed_01[i];
_generate_kek(7, es_keys[2], master_key[0], temp_key, NULL);
se_aes_crypt_block_ecb(7, 0, ssl_rsa_kek, ssl_keys);
}
if (memcmp(pkg1_id->id, "2016", 4)) {
TPRINTFARGS("%kES & SSL keys...", colors[(color_idx++) % 6]);
} else {
TPRINTFARGS("%kSSL keys... ", colors[(color_idx++) % 6]);
}
if (f_open(&fp, "sd:/Nintendo/Contents/private", FA_READ | FA_OPEN_EXISTING)) { if (f_open(&fp, "sd:/Nintendo/Contents/private", FA_READ | FA_OPEN_EXISTING)) {
EPRINTF("Unable to locate SD seed. Skipping."); EPRINTF("Unable to open SD seed vector. Skipping.");
goto dismount; goto get_titlekeys;
} }
// get sd seed verification vector // get sd seed verification vector
if (f_read(&fp, temp_key, 0x10, &read_bytes) || read_bytes != 0x10) { if (f_read(&fp, temp_key, 0x10, &read_bytes) || read_bytes != 0x10) {
EPRINTF("Unable to locate SD seed. Skipping."); EPRINTF("Unable to read SD seed vector. Skipping.");
f_close(&fp); f_close(&fp);
goto dismount; goto get_titlekeys;
} }
f_close(&fp); f_close(&fp);
if (f_open(&fp, "emmc:/save/8000000000000043", FA_READ | FA_OPEN_EXISTING)) { if (f_open(&fp, "emmc:/save/8000000000000043", FA_READ | FA_OPEN_EXISTING)) {
EPRINTF("Failed to open ns_appman save.\nSkipping SD seed."); EPRINTF("Unable to open ns_appman save.\nSkipping SD seed.");
goto dismount; goto get_titlekeys;
} }
// locate sd seed
u8 read_buf[0x20] = {0}; u8 read_buf[0x20] = {0};
for (u32 i = 0x8000; i < f_size(&fp); i += 0x4000) { for (u32 i = 0x8000; i < f_size(&fp); i += 0x4000) {
if (f_lseek(&fp, i) || f_read(&fp, read_buf, 0x20, &read_bytes) || read_bytes != 0x20) if (f_lseek(&fp, i) || f_read(&fp, read_buf, 0x20, &read_bytes) || read_bytes != 0x20)
@ -711,39 +782,190 @@ pkg2_done:
} }
f_close(&fp); f_close(&fp);
TPRINTFARGS("%kSD Seed... ", colors[(color_idx++) % 6]);
get_titlekeys:
if (!_key_exists(eticket_rsa_kek))
goto dismount;
if (!minerva_cfg) {
gfx_printf("%k Minerva not found!\n This may take up to a minute...\n", colors[(color_idx++) % 6]);
gfx_printf(" For better performance, download Hekate\n and put bootloader/sys/libsys_minerva.bso\n on SD.\n");
}
gfx_printf("%kTitlekeys... ", colors[color_idx % 6]);
u32 save_x = gfx_con.x, save_y = gfx_con.y;
gfx_printf("\n");
u8 null_hash[0x20] = {
0xE3, 0xB0, 0xC4, 0x42, 0x98, 0xFC, 0x1C, 0x14, 0x9A, 0xFB, 0xF4, 0xC8, 0x99, 0x6F, 0xB9, 0x24,
0x27, 0xAE, 0x41, 0xE4, 0x64, 0x9B, 0x93, 0x4C, 0xA4, 0x95, 0x99, 0x1B, 0x78, 0x52, 0xB8, 0x55};
se_aes_key_set(8, bis_key[0] + 0x00, 0x10);
se_aes_key_set(9, bis_key[0] + 0x10, 0x10);
u32 buf_size = 0x80000;
u8 *buffer = (u8 *)malloc(buf_size);
u8 keypair[0x230] = {0};
emummc_storage_read(&storage, 0x4400 / NX_EMMC_BLOCKSIZE, 0x4000 / NX_EMMC_BLOCKSIZE, buffer);
se_aes_xts_crypt(9, 8, 0, 0, buffer, buffer, 0x4000, 1);
se_aes_key_set(8, bis_key[2] + 0x00, 0x10);
se_aes_key_set(9, bis_key[2] + 0x10, 0x10);
if (*(u32 *)buffer != 0x304C4143) {
EPRINTF("CAL0 magic not found. Check BIS key 0.");
free(buffer);
goto dismount;
}
se_aes_key_set(2, eticket_rsa_kek, 0x10);
se_aes_crypt_ctr(2, keypair, 0x230, buffer + 0x38a0, 0x230, buffer + 0x3890);
u8 *D = keypair, *N = keypair + 0x100, *E = keypair + 0x200;
// Check public exponent is 0x10001 big endian
if (E[0] != 0 || E[1] != 1 || E[2] != 0 || E[3] != 1) {
EPRINTF("Invalid public exponent.");
free(buffer);
goto dismount;
}
if (!_test_key_pair(E, D, N)) {
EPRINTF("Invalid keypair. Check eticket_rsa_kek.");
free(buffer);
goto dismount;
}
se_rsa_key_set(0, N, 0x100, D, 0x100);
if (f_stat("emmc:/save/80000000000000E1", &fno)) {
EPRINTF("Unable to stat ES save 1. Skipping.");
free(buffer);
goto dismount;
}
u64 total_size = fno.fsize;
if (f_stat("emmc:/save/80000000000000E2", &fno)) {
EPRINTF("Unable to stat ES save 2. Skipping.");
free(buffer);
goto dismount;
}
total_size += fno.fsize;
u32 br;
u64 total_br = 0;
rights_ids = (u8 *)malloc(0x400000);
titlekeys = (u8 *)malloc(0x400000);
u8 M[0x100];
if (f_open(&fp, "emmc:/save/80000000000000E1", FA_READ | FA_OPEN_EXISTING)) {
EPRINTF("Unable to open ES save 1. Skipping.");
free(buffer);
goto dismount;
}
f_lseek(&fp, 0x8000);
u32 pct = 0, last_pct = 0;
tui_pbar(save_x, save_y, pct, COLOR_GREEN, 0xFF155500);
while (!f_read(&fp, buffer, buf_size, &br)) {
total_br += br;
for (u32 i = 0; i < br; i += 0x4000) {
pct = (u32)((total_br + i) * 100 / total_size);
if (pct > last_pct && pct <= 100) {
last_pct = pct;
tui_pbar(save_x, save_y, pct, COLOR_GREEN, 0xFF155500);
}
for (u32 j = i; j < i + 0x4000; j += 0x400) {
minerva_periodic_training();
if (buffer[j] == 4 && buffer[j+1] == 0 && buffer[j+2] == 1 && buffer[j+3] == 0) {
u32 k = 0;
bool titlekey_found = false;
for (; k < _titlekey_count; k++) {
if (!memcmp(rights_ids + 0x10 * k, buffer + j + 0x2a0, 0x10)) {
titlekey_found = true;
break;
}
}
if (titlekey_found)
continue;
memcpy(rights_ids + 0x10 * _titlekey_count, buffer + j + 0x2a0, 0x10);
memcpy(titlekeys + 0x10 * _titlekey_count, buffer + j + 0x180, 0x10);
_titlekey_count++;
} else {
break;
}
}
}
if (br < buf_size) break;
}
u32 common_titlekey_count = _titlekey_count;
if (f_open(&fp, "emmc:/save/80000000000000E2", FA_READ | FA_OPEN_EXISTING)) {
EPRINTF("Unable to open ES save 2. Skipping.");
free(buffer);
goto dismount;
}
f_lseek(&fp, 0x8000);
while (!f_read(&fp, buffer, buf_size, &br)) {
total_br += br;
for (u32 i = 0; i < br; i += 0x4000) {
pct = (u32)((total_br + i) * 100 / total_size);
if (pct > last_pct && pct <= 100) {
last_pct = pct;
tui_pbar(save_x, save_y, pct, COLOR_GREEN, 0xFF155500);
}
for (u32 j = i; j < i + 0x4000; j += 0x400) {
minerva_periodic_training();
if (buffer[j] == 4 && buffer[j+1] == 0 && buffer[j+2] == 1 && buffer[j+3] == 0) {
u32 k = common_titlekey_count;
bool titlekey_found = false;
for (; k < _titlekey_count; k++) {
if (!memcmp(rights_ids + 0x10 * k, buffer + j + 0x2a0, 0x10)) {
titlekey_found = true;
break;
}
}
if (titlekey_found)
continue;
memcpy(rights_ids + 0x10 * _titlekey_count, buffer + j + 0x2a0, 0x10);
u8 *titlekey_block = buffer + j + 0x180;
se_rsa_exp_mod(0, M, 0x100, titlekey_block, 0x100);
u8 *salt = M + 1;
u8 *db = M + 0x21;
_mgf1_xor(salt, 0x20, db, 0xdf);
_mgf1_xor(db, 0xdf, salt, 0x20);
if (memcmp(db, null_hash, 0x20))
continue;
memcpy(titlekeys + 0x10 * _titlekey_count, db + 0xcf, 0x10);
_titlekey_count++;
} else {
break;
}
}
}
if (br < buf_size) break;
}
free(buffer);
f_close(&fp);
gfx_con_setpos(0, save_y);
TPRINTFARGS("\n%k ", colors[(color_idx++) % 6]);
gfx_printf("\n%k Found %d titlekeys.\n", colors[(color_idx++) % 6], _titlekey_count);
dismount: dismount:
f_mount(NULL, "emmc:", 1); f_mount(NULL, "emmc:", 1);
clear_sector_cache = true;
nx_emmc_gpt_free(&gpt); nx_emmc_gpt_free(&gpt);
sdmmc_storage_end(&storage);
if (memcmp(pkg1_id->id, "2016", 4)) {
TPRINTFARGS("%kES & SSL keys...", colors[5]);
} else {
TPRINTFARGS("%kSSL keys... ", colors[5]);
}
// derive eticket_rsa_kek and ssl_rsa_kek
if (_key_exists(es_keys[0]) && _key_exists(es_keys[1]) && _key_exists(master_key[0])) {
for (u32 i = 0; i < 0x10; i++)
temp_key[i] = aes_kek_generation_source[i] ^ aes_kek_seed_03[i];
_generate_kek(8, es_keys[1], master_key[0], temp_key, NULL);
se_aes_crypt_block_ecb(8, 0, eticket_rsa_kek, es_keys[0]);
}
if (_key_exists(ssl_keys[1]) && _key_exists(es_keys[2]) && _key_exists(master_key[0])) {
for (u32 i = 0; i < 0x10; i++)
temp_key[i] = aes_kek_generation_source[i] ^ aes_kek_seed_01[i];
_generate_kek(8, es_keys[2], master_key[0], temp_key, NULL);
se_aes_crypt_block_ecb(8, 0, ssl_rsa_kek, ssl_keys[1]);
}
key_output: ; key_output: ;
__attribute__ ((aligned (16))) char text_buffer[0x3000] = {0}; char *text_buffer = (char *)malloc(_titlekey_count * 68 < 0x3000 ? 0x3000 : _titlekey_count * 68 + 1);
SAVE_KEY("aes_kek_generation_source", aes_kek_generation_source, 0x10); SAVE_KEY("aes_kek_generation_source", aes_kek_generation_source, 0x10);
SAVE_KEY("aes_key_generation_source", aes_key_generation_source, 0x10); SAVE_KEY("aes_key_generation_source", aes_key_generation_source, 0x10);
SAVE_KEY("bis_kek_source", bis_kek_source, 0x10); SAVE_KEY("bis_kek_source", bis_kek_source, 0x10);
SAVE_KEY_FAMILY("bis_key", bis_key, 4, 0x20); SAVE_KEY_FAMILY("bis_key", bis_key, 0, 4, 0x20);
SAVE_KEY_FAMILY("bis_key_source", bis_key_source, 3, 0x20); SAVE_KEY_FAMILY("bis_key_source", bis_key_source, 0, 3, 0x20);
SAVE_KEY("device_key", device_key, 0x10); SAVE_KEY("device_key", device_key, 0x10);
SAVE_KEY("eticket_rsa_kek", eticket_rsa_kek, 0x10); SAVE_KEY("eticket_rsa_kek", eticket_rsa_kek, 0x10);
SAVE_KEY("eticket_rsa_kek_source", es_keys[0], 0x10); SAVE_KEY("eticket_rsa_kek_source", es_keys[0], 0x10);
@ -751,26 +973,23 @@ key_output: ;
SAVE_KEY("header_kek_source", fs_keys[0], 0x10); SAVE_KEY("header_kek_source", fs_keys[0], 0x10);
SAVE_KEY("header_key", header_key, 0x20); SAVE_KEY("header_key", header_key, 0x20);
SAVE_KEY("header_key_source", fs_keys[1], 0x20); SAVE_KEY("header_key_source", fs_keys[1], 0x20);
SAVE_KEY_FAMILY("key_area_key_application", key_area_key[0], MAX_KEY, 0x10); SAVE_KEY_FAMILY("key_area_key_application", key_area_key[0], 0, MAX_KEY, 0x10);
SAVE_KEY("key_area_key_application_source", fs_keys[2], 0x10); SAVE_KEY("key_area_key_application_source", fs_keys[2], 0x10);
SAVE_KEY_FAMILY("key_area_key_ocean", key_area_key[1], MAX_KEY, 0x10); SAVE_KEY_FAMILY("key_area_key_ocean", key_area_key[1], 0, MAX_KEY, 0x10);
SAVE_KEY("key_area_key_ocean_source", fs_keys[3], 0x10); SAVE_KEY("key_area_key_ocean_source", fs_keys[3], 0x10);
SAVE_KEY_FAMILY("key_area_key_system", key_area_key[2], MAX_KEY, 0x10); SAVE_KEY_FAMILY("key_area_key_system", key_area_key[2], 0, MAX_KEY, 0x10);
SAVE_KEY("key_area_key_system_source", fs_keys[4], 0x10); SAVE_KEY("key_area_key_system_source", fs_keys[4], 0x10);
SAVE_KEY_FAMILY("keyblob", keyblob, 6, 0x90); SAVE_KEY_FAMILY("keyblob", keyblob, 0, 6, 0x90);
SAVE_KEY_FAMILY("keyblob_key", keyblob_key, 6, 0x10); SAVE_KEY_FAMILY("keyblob_key", keyblob_key, 0, 6, 0x10);
SAVE_KEY_FAMILY("keyblob_key_source", keyblob_key_source, 6, 0x10); SAVE_KEY_FAMILY("keyblob_key_source", keyblob_key_source, 0, 6, 0x10);
SAVE_KEY_FAMILY("keyblob_mac_key", keyblob_mac_key, 6, 0x10); SAVE_KEY_FAMILY("keyblob_mac_key", keyblob_mac_key, 0, 6, 0x10);
SAVE_KEY("keyblob_mac_key_source", keyblob_mac_key_source, 0x10); SAVE_KEY("keyblob_mac_key_source", keyblob_mac_key_source, 0x10);
SAVE_KEY_FAMILY("master_kek", master_kek, MAX_KEY, 0x10); SAVE_KEY_FAMILY("master_kek", master_kek, 0, MAX_KEY, 0x10);
SAVE_KEY("master_kek_source_06", master_kek_sources[0], 0x10); SAVE_KEY_FAMILY("master_kek_source", master_kek_sources, KB_FIRMWARE_VERSION_620, sizeof(master_kek_sources) / 0x10, 0x10);
SAVE_KEY("master_kek_source_07", master_kek_sources[1], 0x10); SAVE_KEY_FAMILY("master_key", master_key, 0, MAX_KEY, 0x10);
SAVE_KEY("master_kek_source_08", master_kek_sources[2], 0x10);
SAVE_KEY("master_kek_source_09", master_kek_sources[3], 0x10);
SAVE_KEY_FAMILY("master_key", master_key, MAX_KEY, 0x10);
SAVE_KEY("master_key_source", master_key_source, 0x10); SAVE_KEY("master_key_source", master_key_source, 0x10);
SAVE_KEY_FAMILY("package1_key", package1_key, 6, 0x10); SAVE_KEY_FAMILY("package1_key", package1_key, 0, 6, 0x10);
SAVE_KEY_FAMILY("package2_key", package2_key, MAX_KEY, 0x10); SAVE_KEY_FAMILY("package2_key", package2_key, 0, MAX_KEY, 0x10);
SAVE_KEY("package2_key_source", package2_key_source, 0x10); SAVE_KEY("package2_key_source", package2_key_source, 0x10);
SAVE_KEY("per_console_key_source", per_console_key_source, 0x10); SAVE_KEY("per_console_key_source", per_console_key_source, 0x10);
SAVE_KEY("retail_specific_aes_key_source", retail_specific_aes_key_source, 0x10); SAVE_KEY("retail_specific_aes_key_source", retail_specific_aes_key_source, 0x10);
@ -790,8 +1009,8 @@ key_output: ;
SAVE_KEY("secure_boot_key", sbk, 0x10); SAVE_KEY("secure_boot_key", sbk, 0x10);
SAVE_KEY("ssl_rsa_kek", ssl_rsa_kek, 0x10); SAVE_KEY("ssl_rsa_kek", ssl_rsa_kek, 0x10);
SAVE_KEY("ssl_rsa_kek_source_x", es_keys[2], 0x10); SAVE_KEY("ssl_rsa_kek_source_x", es_keys[2], 0x10);
SAVE_KEY("ssl_rsa_kek_source_y", ssl_keys[1], 0x10); SAVE_KEY("ssl_rsa_kek_source_y", ssl_keys, 0x10);
SAVE_KEY_FAMILY("titlekek", titlekek, MAX_KEY, 0x10); SAVE_KEY_FAMILY("titlekek", titlekek, 0, MAX_KEY, 0x10);
SAVE_KEY("titlekek_source", titlekek_source, 0x10); SAVE_KEY("titlekek_source", titlekek_source, 0x10);
SAVE_KEY("tsec_key", tsec_keys, 0x10); SAVE_KEY("tsec_key", tsec_keys, 0x10);
if (pkg1_id->kb == KB_FIRMWARE_VERSION_620) if (pkg1_id->kb == KB_FIRMWARE_VERSION_620)
@ -799,33 +1018,50 @@ key_output: ;
//gfx_con.fntsz = 8; gfx_puts(text_buffer); gfx_con.fntsz = 16; //gfx_con.fntsz = 8; gfx_puts(text_buffer); gfx_con.fntsz = 16;
TPRINTFARGS("\n%kFound %d keys.\n%kLockpick totally", colors[0], _key_count, colors[1]); end_time = get_tmr_us();
gfx_printf("\n%k Found %d keys.\n\n", colors[(color_idx++) % 6], _key_count);
gfx_printf("%kLockpick totally done in %d us\n\n", colors[(color_idx++) % 6], end_time - begin_time);
gfx_printf("%kFound through master_key_%02x.\n\n", colors[(color_idx++) % 6], MAX_KEY - 1);
f_mkdir("switch"); f_mkdir("sd:/switch");
char keyfile_path[30] = "sd:/switch/"; char keyfile_path[30] = "sd:/switch/";
if (!(fuse_read_odm(4) & 3)) if (!(fuse_read_odm(4) & 3))
sprintf(&keyfile_path[11], "prod.keys"); sprintf(&keyfile_path[11], "prod.keys");
else else
sprintf(&keyfile_path[11], "dev.keys"); sprintf(&keyfile_path[11], "dev.keys");
if (!sd_save_to_file(text_buffer, strlen(text_buffer), keyfile_path) && !f_stat(keyfile_path, &fno)) { if (sd_mount() && !sd_save_to_file(text_buffer, strlen(text_buffer), keyfile_path) && !f_stat(keyfile_path, &fno)) {
gfx_printf("%kWrote %d bytes to %s\n", colors[2], (u32)fno.fsize, keyfile_path); gfx_printf("%kWrote %d bytes to %s\n", colors[(color_idx++) % 6], (u32)fno.fsize, keyfile_path);
} else } else
EPRINTF("Failed to save keys to SD."); EPRINTF("Unable to save keys to SD.");
sd_unmount();
if (_titlekey_count == 0)
goto out_wait;
memset(text_buffer, 0, _titlekey_count * 68 + 1);
for (u32 i = 0; i < _titlekey_count; i++) {
for (u32 j = 0; j < 0x10; j++)
sprintf(&text_buffer[i * 68 + j * 2], "%02x", rights_ids[i * 0x10 + j]);
sprintf(&text_buffer[i * 68 + 0x20], " = ");
for (u32 j = 0; j < 0x10; j++)
sprintf(&text_buffer[i * 68 + 0x23 + j * 2], "%02x", titlekeys[i * 0x10 + j]);
sprintf(&text_buffer[i * 68 + 0x43], "\n");
}
sprintf(&keyfile_path[11], "title.keys");
if (sd_mount() && !sd_save_to_file(text_buffer, strlen(text_buffer), keyfile_path) && !f_stat(keyfile_path, &fno)) {
gfx_printf("%kWrote %d bytes to %s\n", colors[(color_idx++) % 6], (u32)fno.fsize, keyfile_path);
} else
EPRINTF("Unable to save titlekeys to SD.");
free(rights_ids);
free(titlekeys);
free(text_buffer);
out_wait: out_wait:
gfx_printf("\n%kVOL + -> Reboot to RCM\n%kVOL - -> Reboot normally\n%kPower -> Power off", colors[3], colors[4], colors[5]); h_cfg.emummc_force_disable = emummc_load_cfg();
emummc_storage_end(&storage);
u32 btn = btn_wait(); gfx_printf("\n%kPress any key to return to the main menu.", colors[(color_idx) % 6], colors[(color_idx + 1) % 6], colors[(color_idx + 2) % 6]);
if (btn & BTN_VOL_UP) btn_wait();
reboot_rcm();
else if (btn & BTN_VOL_DOWN)
reboot_normal();
else
power_off();
} }
static void _save_key(const char *name, const void *data, const u32 len, char *outbuf) { static void _save_key(const char *name, const void *data, u32 len, char *outbuf) {
if (!_key_exists(data)) if (!_key_exists(data))
return; return;
u32 pos = strlen(outbuf); u32 pos = strlen(outbuf);
@ -836,9 +1072,9 @@ static void _save_key(const char *name, const void *data, const u32 len, char *o
_key_count++; _key_count++;
} }
static void _save_key_family(const char *name, const void *data, const u32 num_keys, const u32 len, char *outbuf) { static void _save_key_family(const char *name, const void *data, u32 start_key, u32 num_keys, u32 len, char *outbuf) {
char temp_name[0x40] = {0}; char temp_name[0x40] = {0};
for (u32 i = 0; i < num_keys; i++) { for (u32 i = start_key; i < num_keys + start_key; i++) {
sprintf(temp_name, "%s_%02x", name, i); sprintf(temp_name, "%s_%02x", name, i);
_save_key(temp_name, data + i * len, len, outbuf); _save_key(temp_name, data + i * len, len, outbuf);
} }
@ -862,7 +1098,7 @@ static inline u32 _read_le_u32(const void *buffer, u32 offset) {
(*(u8*)(buffer + offset + 3) << 0x18); (*(u8*)(buffer + offset + 3) << 0x18);
} }
static void *_nca_process(u32 hk_ks1, u32 hk_ks2, FIL *fp, u32 key_offset, u32 len) { static void *_nca_process(u32 hk_ks1, u32 hk_ks2, FIL *fp, u32 key_offset, u32 len, const u8 key_area_key[3][KB_FIRMWARE_VERSION_MAX+1][0x10]) {
u32 read_bytes = 0, crypt_offset, read_size, num_files, string_table_size, rodata_offset; u32 read_bytes = 0, crypt_offset, read_size, num_files, string_table_size, rodata_offset;
u8 *temp_file = (u8*)malloc(0x400), u8 *temp_file = (u8*)malloc(0x400),
@ -920,3 +1156,45 @@ static void _update_ctr(u8 *ctr, u32 ofs) {
for (u32 i = 0; i < 4; i++, ofs >>= 8) for (u32 i = 0; i < 4; i++, ofs >>= 8)
ctr[0x10-i-1] = (u8)(ofs & 0xff); ctr[0x10-i-1] = (u8)(ofs & 0xff);
} }
static bool _test_key_pair(const void *E, const void *D, const void *N) {
u8 X[0x100] = {0}, Y[0x100] = {0}, Z[0x100] = {0};
// 0xCAFEBABE
X[0xfc] = 0xca; X[0xfd] = 0xfe; X[0xfe] = 0xba; X[0xff] = 0xbe;
se_rsa_key_set(0, N, 0x100, D, 0x100);
se_rsa_exp_mod(0, Y, 0x100, X, 0x100);
se_rsa_key_set(0, N, 0x100, E, 4);
se_rsa_exp_mod(0, Z, 0x100, Y, 0x100);
return !memcmp(X, Z, 0x100);
}
// _mgf1_xor() was derived from Atmosphère's calculate_mgf1_and_xor
static void _mgf1_xor(void *masked, u32 masked_size, const void *seed, u32 seed_size) {
u8 cur_hash[0x20];
u8 hash_buf[0xe4];
u32 hash_buf_size = seed_size + 4;
memcpy(hash_buf, seed, seed_size);
u32 round_num = 0;
u8 *p_out = (u8 *)masked;
while (masked_size) {
u32 cur_size = masked_size > 0x20 ? 0x20 : masked_size;
for (u32 i = 0; i < 4; i++)
hash_buf[seed_size + 3 - i] = (round_num >> (8 * i)) & 0xff;
round_num++;
se_calc_sha256(cur_hash, hash_buf, hash_buf_size);
for (unsigned int i = 0; i < cur_size; i++) {
*p_out ^= cur_hash[i];
p_out++;
}
masked_size -= cur_size;
}
}

589
source/libs/elfload/elf.h Normal file
View File

@ -0,0 +1,589 @@
/* $OpenBSD: exec_elf.h,v 1.53 2014/01/03 03:00:39 guenther Exp $ */
/*
* Copyright (c) 1995, 1996 Erik Theisen. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* imported sys/exec_elf.h from OpenBSD */
#ifndef ELF_H
#define ELF_H
#include <stdint.h>
typedef uint8_t Elf_Byte;
typedef uint32_t Elf32_Addr; /* Unsigned program address */
typedef uint32_t Elf32_Off; /* Unsigned file offset */
typedef int32_t Elf32_Sword; /* Signed large integer */
typedef uint32_t Elf32_Word; /* Unsigned large integer */
typedef uint16_t Elf32_Half; /* Unsigned medium integer */
typedef uint64_t Elf64_Addr;
typedef uint64_t Elf64_Off;
typedef int32_t Elf64_Shalf;
#ifdef __alpha__
typedef int64_t Elf64_Sword;
typedef uint64_t Elf64_Word;
#else
typedef int32_t Elf64_Sword;
typedef uint32_t Elf64_Word;
#endif
typedef int64_t Elf64_Sxword;
typedef uint64_t Elf64_Xword;
typedef uint32_t Elf64_Half;
typedef uint16_t Elf64_Quarter;
/*
* e_ident[] identification indexes
* See http://www.sco.com/developers/gabi/latest/ch4.eheader.html
*/
#define EI_MAG0 0 /* file ID */
#define EI_MAG1 1 /* file ID */
#define EI_MAG2 2 /* file ID */
#define EI_MAG3 3 /* file ID */
#define EI_CLASS 4 /* file class */
#define EI_DATA 5 /* data encoding */
#define EI_VERSION 6 /* ELF header version */
#define EI_OSABI 7 /* OS/ABI ID */
#define EI_ABIVERSION 8 /* ABI version */
#define EI_PAD 9 /* start of pad bytes */
#define EI_NIDENT 16 /* Size of e_ident[] */
/* e_ident[] magic number */
#define ELFMAG0 0x7f /* e_ident[EI_MAG0] */
#define ELFMAG1 'E' /* e_ident[EI_MAG1] */
#define ELFMAG2 'L' /* e_ident[EI_MAG2] */
#define ELFMAG3 'F' /* e_ident[EI_MAG3] */
#define ELFMAG "\177ELF" /* magic */
#define SELFMAG 4 /* size of magic */
/* e_ident[] file class */
#define ELFCLASSNONE 0 /* invalid */
#define ELFCLASS32 1 /* 32-bit objs */
#define ELFCLASS64 2 /* 64-bit objs */
#define ELFCLASSNUM 3 /* number of classes */
/* e_ident[] data encoding */
#define ELFDATANONE 0 /* invalid */
#define ELFDATA2LSB 1 /* Little-Endian */
#define ELFDATA2MSB 2 /* Big-Endian */
#define ELFDATANUM 3 /* number of data encode defines */
/* e_ident[] Operating System/ABI */
#define ELFOSABI_SYSV 0 /* UNIX System V ABI */
#define ELFOSABI_HPUX 1 /* HP-UX operating system */
#define ELFOSABI_NETBSD 2 /* NetBSD */
#define ELFOSABI_LINUX 3 /* GNU/Linux */
#define ELFOSABI_HURD 4 /* GNU/Hurd */
#define ELFOSABI_86OPEN 5 /* 86Open common IA32 ABI */
#define ELFOSABI_SOLARIS 6 /* Solaris */
#define ELFOSABI_MONTEREY 7 /* Monterey */
#define ELFOSABI_IRIX 8 /* IRIX */
#define ELFOSABI_FREEBSD 9 /* FreeBSD */
#define ELFOSABI_TRU64 10 /* TRU64 UNIX */
#define ELFOSABI_MODESTO 11 /* Novell Modesto */
#define ELFOSABI_OPENBSD 12 /* OpenBSD */
#define ELFOSABI_ARM 97 /* ARM */
#define ELFOSABI_STANDALONE 255 /* Standalone (embedded) application */
/* e_ident */
#define IS_ELF(ehdr) ((ehdr).e_ident[EI_MAG0] == ELFMAG0 && \
(ehdr).e_ident[EI_MAG1] == ELFMAG1 && \
(ehdr).e_ident[EI_MAG2] == ELFMAG2 && \
(ehdr).e_ident[EI_MAG3] == ELFMAG3)
/* ELF Header */
typedef struct
{
unsigned char e_ident[EI_NIDENT]; /* ELF Identification */
Elf32_Half e_type; /* object file type */
Elf32_Half e_machine; /* machine */
Elf32_Word e_version; /* object file version */
Elf32_Addr e_entry; /* virtual entry point */
Elf32_Off e_phoff; /* program header table offset */
Elf32_Off e_shoff; /* section header table offset */
Elf32_Word e_flags; /* processor-specific flags */
Elf32_Half e_ehsize; /* ELF header size */
Elf32_Half e_phentsize; /* program header entry size */
Elf32_Half e_phnum; /* number of program header entries */
Elf32_Half e_shentsize; /* section header entry size */
Elf32_Half e_shnum; /* number of section header entries */
Elf32_Half e_shstrndx; /* section header table's "section
header string table" entry offset */
} Elf32_Ehdr;
typedef struct
{
unsigned char e_ident[EI_NIDENT]; /* Id bytes */
Elf64_Quarter e_type; /* file type */
Elf64_Quarter e_machine; /* machine type */
Elf64_Half e_version; /* version number */
Elf64_Addr e_entry; /* entry point */
Elf64_Off e_phoff; /* Program hdr offset */
Elf64_Off e_shoff; /* Section hdr offset */
Elf64_Half e_flags; /* Processor flags */
Elf64_Quarter e_ehsize; /* sizeof ehdr */
Elf64_Quarter e_phentsize; /* Program header entry size */
Elf64_Quarter e_phnum; /* Number of program headers */
Elf64_Quarter e_shentsize; /* Section header entry size */
Elf64_Quarter e_shnum; /* Number of section headers */
Elf64_Quarter e_shstrndx; /* String table index */
} Elf64_Ehdr;
/* e_type */
#define ET_NONE 0 /* No file type */
#define ET_REL 1 /* relocatable file */
#define ET_EXEC 2 /* executable file */
#define ET_DYN 3 /* shared object file */
#define ET_CORE 4 /* core file */
#define ET_NUM 5 /* number of types */
#define ET_LOPROC 0xff00 /* reserved range for processor */
#define ET_HIPROC 0xffff /* specific e_type */
/* e_machine */
#define EM_NONE 0 /* No Machine */
#define EM_M32 1 /* AT&T WE 32100 */
#define EM_SPARC 2 /* SPARC */
#define EM_386 3 /* Intel 80386 */
#define EM_68K 4 /* Motorola 68000 */
#define EM_88K 5 /* Motorola 88000 */
#define EM_486 6 /* Intel 80486 - unused? */
#define EM_860 7 /* Intel 80860 */
#define EM_MIPS 8 /* MIPS R3000 Big-Endian only */
/*
* Don't know if EM_MIPS_RS4_BE,
* EM_SPARC64, EM_PARISC,
* or EM_PPC are ABI compliant
*/
#define EM_MIPS_RS4_BE 10 /* MIPS R4000 Big-Endian */
#define EM_SPARC64 11 /* SPARC v9 64-bit unofficial */
#define EM_PARISC 15 /* HPPA */
#define EM_SPARC32PLUS 18 /* Enhanced instruction set SPARC */
#define EM_PPC 20 /* PowerPC */
#define EM_ARM 40 /* ARM AArch32 */
#define EM_ALPHA 41 /* DEC ALPHA */
#define EM_SH 42 /* Hitachi/Renesas Super-H */
#define EM_SPARCV9 43 /* SPARC version 9 */
#define EM_IA_64 50 /* Intel IA-64 Processor */
#define EM_AMD64 62 /* AMD64 architecture */
#define EM_VAX 75 /* DEC VAX */
#define EM_AARCH64 183 /* ARM AArch64 */
/* Non-standard */
#define EM_ALPHA_EXP 0x9026 /* DEC ALPHA */
/* Version */
#define EV_NONE 0 /* Invalid */
#define EV_CURRENT 1 /* Current */
#define EV_NUM 2 /* number of versions */
/* Section Header */
typedef struct
{
Elf32_Word sh_name; /* name - index into section header
* string table section */
Elf32_Word sh_type; /* type */
Elf32_Word sh_flags; /* flags */
Elf32_Addr sh_addr; /* address */
Elf32_Off sh_offset; /* file offset */
Elf32_Word sh_size; /* section size */
Elf32_Word sh_link; /* section header table index link */
Elf32_Word sh_info; /* extra information */
Elf32_Word sh_addralign; /* address alignment */
Elf32_Word sh_entsize; /* section entry size */
} Elf32_Shdr;
typedef struct
{
Elf64_Half sh_name; /* section name */
Elf64_Half sh_type; /* section type */
Elf64_Xword sh_flags; /* section flags */
Elf64_Addr sh_addr; /* virtual address */
Elf64_Off sh_offset; /* file offset */
Elf64_Xword sh_size; /* section size */
Elf64_Half sh_link; /* link to another */
Elf64_Half sh_info; /* misc info */
Elf64_Xword sh_addralign; /* memory alignment */
Elf64_Xword sh_entsize; /* table entry size */
} Elf64_Shdr;
/* Special Section Indexes */
#define SHN_UNDEF 0 /* undefined */
#define SHN_LORESERVE 0xff00 /* lower bounds of reserved indexes */
#define SHN_LOPROC 0xff00 /* reserved range for processor */
#define SHN_HIPROC 0xff1f /* specific section indexes */
#define SHN_ABS 0xfff1 /* absolute value */
#define SHN_COMMON 0xfff2 /* common symbol */
#define SHN_HIRESERVE 0xffff /* upper bounds of reserved indexes */
/* sh_type */
#define SHT_NULL 0 /* inactive */
#define SHT_PROGBITS 1 /* program defined information */
#define SHT_SYMTAB 2 /* symbol table section */
#define SHT_STRTAB 3 /* string table section */
#define SHT_RELA 4 /* relocation section with addends*/
#define SHT_HASH 5 /* symbol hash table section */
#define SHT_DYNAMIC 6 /* dynamic section */
#define SHT_NOTE 7 /* note section */
#define SHT_NOBITS 8 /* no space section */
#define SHT_REL 9 /* relation section without addends */
#define SHT_SHLIB 10 /* reserved - purpose unknown */
#define SHT_DYNSYM 11 /* dynamic symbol table section */
#define SHT_NUM 12 /* number of section types */
#define SHT_LOPROC 0x70000000 /* reserved range for processor */
#define SHT_HIPROC 0x7fffffff /* specific section header types */
#define SHT_LOUSER 0x80000000 /* reserved range for application */
#define SHT_HIUSER 0xffffffff /* specific indexes */
/* Section names */
#define ELF_BSS ".bss" /* uninitialized data */
#define ELF_DATA ".data" /* initialized data */
#define ELF_DEBUG ".debug" /* debug */
#define ELF_DYNAMIC ".dynamic" /* dynamic linking information */
#define ELF_DYNSTR ".dynstr" /* dynamic string table */
#define ELF_DYNSYM ".dynsym" /* dynamic symbol table */
#define ELF_FINI ".fini" /* termination code */
#define ELF_GOT ".got" /* global offset table */
#define ELF_HASH ".hash" /* symbol hash table */
#define ELF_INIT ".init" /* initialization code */
#define ELF_REL_DATA ".rel.data" /* relocation data */
#define ELF_REL_FINI ".rel.fini" /* relocation termination code */
#define ELF_REL_INIT ".rel.init" /* relocation initialization code */
#define ELF_REL_DYN ".rel.dyn" /* relocation dynamic link info */
#define ELF_REL_RODATA ".rel.rodata" /* relocation read-only data */
#define ELF_REL_TEXT ".rel.text" /* relocation code */
#define ELF_RODATA ".rodata" /* read-only data */
#define ELF_SHSTRTAB ".shstrtab" /* section header string table */
#define ELF_STRTAB ".strtab" /* string table */
#define ELF_SYMTAB ".symtab" /* symbol table */
#define ELF_TEXT ".text" /* code */
/* Section Attribute Flags - sh_flags */
#define SHF_WRITE 0x1 /* Writable */
#define SHF_ALLOC 0x2 /* occupies memory */
#define SHF_EXECINSTR 0x4 /* executable */
#define SHF_TLS 0x400 /* thread local storage */
#define SHF_MASKPROC 0xf0000000 /* reserved bits for processor \
* specific section attributes */
/* Symbol Table Entry */
typedef struct elf32_sym
{
Elf32_Word st_name; /* name - index into string table */
Elf32_Addr st_value; /* symbol value */
Elf32_Word st_size; /* symbol size */
unsigned char st_info; /* type and binding */
unsigned char st_other; /* 0 - no defined meaning */
Elf32_Half st_shndx; /* section header index */
} Elf32_Sym;
typedef struct
{
Elf64_Half st_name; /* Symbol name index in str table */
Elf_Byte st_info; /* type / binding attrs */
Elf_Byte st_other; /* unused */
Elf64_Quarter st_shndx; /* section index of symbol */
Elf64_Xword st_value; /* value of symbol */
Elf64_Xword st_size; /* size of symbol */
} Elf64_Sym;
/* Symbol table index */
#define STN_UNDEF 0 /* undefined */
/* Extract symbol info - st_info */
#define ELF32_ST_BIND(x) ((x) >> 4)
#define ELF32_ST_TYPE(x) (((unsigned int)x) & 0xf)
#define ELF32_ST_INFO(b, t) (((b) << 4) + ((t)&0xf))
#define ELF64_ST_BIND(x) ((x) >> 4)
#define ELF64_ST_TYPE(x) (((unsigned int)x) & 0xf)
#define ELF64_ST_INFO(b, t) (((b) << 4) + ((t)&0xf))
/* Symbol Binding - ELF32_ST_BIND - st_info */
#define STB_LOCAL 0 /* Local symbol */
#define STB_GLOBAL 1 /* Global symbol */
#define STB_WEAK 2 /* like global - lower precedence */
#define STB_NUM 3 /* number of symbol bindings */
#define STB_LOPROC 13 /* reserved range for processor */
#define STB_HIPROC 15 /* specific symbol bindings */
/* Symbol type - ELF32_ST_TYPE - st_info */
#define STT_NOTYPE 0 /* not specified */
#define STT_OBJECT 1 /* data object */
#define STT_FUNC 2 /* function */
#define STT_SECTION 3 /* section */
#define STT_FILE 4 /* file */
#define STT_TLS 6 /* thread local storage */
#define STT_LOPROC 13 /* reserved range for processor */
#define STT_HIPROC 15 /* specific symbol types */
/* Relocation entry with implicit addend */
typedef struct
{
Elf32_Addr r_offset; /* offset of relocation */
Elf32_Word r_info; /* symbol table index and type */
} Elf32_Rel;
/* Relocation entry with explicit addend */
typedef struct
{
Elf32_Addr r_offset; /* offset of relocation */
Elf32_Word r_info; /* symbol table index and type */
Elf32_Sword r_addend;
} Elf32_Rela;
/* Extract relocation info - r_info */
#define ELF32_R_SYM(i) ((i) >> 8)
#define ELF32_R_TYPE(i) ((unsigned char)(i))
#define ELF32_R_INFO(s, t) (((s) << 8) + (unsigned char)(t))
typedef struct
{
Elf64_Xword r_offset; /* where to do it */
Elf64_Xword r_info; /* index & type of relocation */
} Elf64_Rel;
typedef struct
{
Elf64_Xword r_offset; /* where to do it */
Elf64_Xword r_info; /* index & type of relocation */
Elf64_Sxword r_addend; /* adjustment value */
} Elf64_Rela;
#define ELF64_R_SYM(info) ((info) >> 32)
#define ELF64_R_TYPE(info) ((info)&0xFFFFFFFF)
#define ELF64_R_INFO(s, t) (((s) << 32) + (__uint32_t)(t))
#if defined(__mips64__) && defined(__MIPSEL__)
/*
* The 64-bit MIPS ELF ABI uses a slightly different relocation format
* than the regular ELF ABI: the r_info field is split into several
* pieces (see gnu/usr.bin/binutils/include/elf/mips.h for details).
*/
#undef ELF64_R_SYM
#undef ELF64_R_TYPE
#undef ELF64_R_INFO
#define ELF64_R_TYPE(info) (swap32((info) >> 32))
#define ELF64_R_SYM(info) ((info)&0xFFFFFFFF)
#define ELF64_R_INFO(s, t) (((__uint64_t)swap32(t) << 32) + (__uint32_t)(s))
#endif /* __mips64__ && __MIPSEL__ */
/* Program Header */
typedef struct
{
Elf32_Word p_type; /* segment type */
Elf32_Off p_offset; /* segment offset */
Elf32_Addr p_vaddr; /* virtual address of segment */
Elf32_Addr p_paddr; /* physical address - ignored? */
Elf32_Word p_filesz; /* number of bytes in file for seg. */
Elf32_Word p_memsz; /* number of bytes in mem. for seg. */
Elf32_Word p_flags; /* flags */
Elf32_Word p_align; /* memory alignment */
} Elf32_Phdr;
typedef struct
{
Elf64_Half p_type; /* entry type */
Elf64_Half p_flags; /* flags */
Elf64_Off p_offset; /* offset */
Elf64_Addr p_vaddr; /* virtual address */
Elf64_Addr p_paddr; /* physical address */
Elf64_Xword p_filesz; /* file size */
Elf64_Xword p_memsz; /* memory size */
Elf64_Xword p_align; /* memory & file alignment */
} Elf64_Phdr;
/* Segment types - p_type */
#define PT_NULL 0 /* unused */
#define PT_LOAD 1 /* loadable segment */
#define PT_DYNAMIC 2 /* dynamic linking section */
#define PT_INTERP 3 /* the RTLD */
#define PT_NOTE 4 /* auxiliary information */
#define PT_SHLIB 5 /* reserved - purpose undefined */
#define PT_PHDR 6 /* program header */
#define PT_TLS 7 /* thread local storage */
#define PT_LOOS 0x60000000 /* reserved range for OS */
#define PT_HIOS 0x6fffffff /* specific segment types */
#define PT_LOPROC 0x70000000 /* reserved range for processor */
#define PT_HIPROC 0x7fffffff /* specific segment types */
#define PT_OPENBSD_RANDOMIZE 0x65a3dbe6 /* fill with random data */
#define PT_GANDR_KERNEL 0x67646b6c /* gdkl */
/* Segment flags - p_flags */
#define PF_X 0x1 /* Executable */
#define PF_W 0x2 /* Writable */
#define PF_R 0x4 /* Readable */
#define PF_MASKPROC 0xf0000000 /* reserved bits for processor */
/* specific segment flags */
/* Dynamic structure */
typedef struct
{
Elf32_Sword d_tag; /* controls meaning of d_val */
union {
Elf32_Word d_val; /* Multiple meanings - see d_tag */
Elf32_Addr d_ptr; /* program virtual address */
} d_un;
} Elf32_Dyn;
typedef struct
{
Elf64_Xword d_tag; /* controls meaning of d_val */
union {
Elf64_Addr d_ptr;
Elf64_Xword d_val;
} d_un;
} Elf64_Dyn;
/* Dynamic Array Tags - d_tag */
#define DT_NULL 0 /* marks end of _DYNAMIC array */
#define DT_NEEDED 1 /* string table offset of needed lib */
#define DT_PLTRELSZ 2 /* size of relocation entries in PLT */
#define DT_PLTGOT 3 /* address PLT/GOT */
#define DT_HASH 4 /* address of symbol hash table */
#define DT_STRTAB 5 /* address of string table */
#define DT_SYMTAB 6 /* address of symbol table */
#define DT_RELA 7 /* address of relocation table */
#define DT_RELASZ 8 /* size of relocation table */
#define DT_RELAENT 9 /* size of relocation entry */
#define DT_STRSZ 10 /* size of string table */
#define DT_SYMENT 11 /* size of symbol table entry */
#define DT_INIT 12 /* address of initialization func. */
#define DT_FINI 13 /* address of termination function */
#define DT_SONAME 14 /* string table offset of shared obj */
#define DT_RPATH 15 /* string table offset of library \
* search path */
#define DT_SYMBOLIC 16 /* start sym search in shared obj. */
#define DT_REL 17 /* address of rel. tbl. w addends */
#define DT_RELSZ 18 /* size of DT_REL relocation table */
#define DT_RELENT 19 /* size of DT_REL relocation entry */
#define DT_PLTREL 20 /* PLT referenced relocation entry */
#define DT_DEBUG 21 /* bugger */
#define DT_TEXTREL 22 /* Allow rel. mod. to unwritable seg */
#define DT_JMPREL 23 /* add. of PLT's relocation entries */
#define DT_BIND_NOW 24 /* Bind now regardless of env setting */
#define DT_LOOS 0x6000000d /* reserved range for OS */
#define DT_HIOS 0x6ffff000 /* specific dynamic array tags */
#define DT_LOPROC 0x70000000 /* reserved range for processor */
#define DT_HIPROC 0x7fffffff /* specific dynamic array tags */
/* some other useful tags */
#define DT_RELACOUNT 0x6ffffff9 /* if present, number of RELATIVE */
#define DT_RELCOUNT 0x6ffffffa /* relocs, which must come first */
#define DT_FLAGS_1 0x6ffffffb
/* Dynamic Flags - DT_FLAGS_1 .dynamic entry */
#define DF_1_NOW 0x00000001
#define DF_1_GLOBAL 0x00000002
#define DF_1_GROUP 0x00000004
#define DF_1_NODELETE 0x00000008
#define DF_1_LOADFLTR 0x00000010
#define DF_1_INITFIRST 0x00000020
#define DF_1_NOOPEN 0x00000040
#define DF_1_ORIGIN 0x00000080
#define DF_1_DIRECT 0x00000100
#define DF_1_TRANS 0x00000200
#define DF_1_INTERPOSE 0x00000400
#define DF_1_NODEFLIB 0x00000800
#define DF_1_NODUMP 0x00001000
#define DF_1_CONLFAT 0x00002000
/* ld.so: number of low tags that are used saved internally (0 .. DT_NUM-1) */
#define DT_NUM (DT_JMPREL + 1)
/*
* Note Definitions
*/
typedef struct
{
Elf32_Word namesz;
Elf32_Word descsz;
Elf32_Word type;
} Elf32_Note;
typedef struct
{
Elf64_Half namesz;
Elf64_Half descsz;
Elf64_Half type;
} Elf64_Note;
#if defined(ELFSIZE) && (ELFSIZE == 32)
#define Elf_Ehdr Elf32_Ehdr
#define Elf_Phdr Elf32_Phdr
#define Elf_Shdr Elf32_Shdr
#define Elf_Sym Elf32_Sym
#define Elf_Rel Elf32_Rel
#define Elf_RelA Elf32_Rela
#define Elf_Dyn Elf32_Dyn
#define Elf_Half Elf32_Half
#define Elf_Word Elf32_Word
#define Elf_Sword Elf32_Sword
#define Elf_Addr Elf32_Addr
#define Elf_Off Elf32_Off
#define Elf_Nhdr Elf32_Nhdr
#define Elf_Note Elf32_Note
#define ELF_R_SYM ELF32_R_SYM
#define ELF_R_TYPE ELF32_R_TYPE
#define ELF_R_INFO ELF32_R_INFO
#define ELFCLASS ELFCLASS32
#define ELF_ST_BIND ELF32_ST_BIND
#define ELF_ST_TYPE ELF32_ST_TYPE
#define ELF_ST_INFO ELF32_ST_INFO
#elif defined(ELFSIZE) && (ELFSIZE == 64)
#define Elf_Ehdr Elf64_Ehdr
#define Elf_Phdr Elf64_Phdr
#define Elf_Shdr Elf64_Shdr
#define Elf_Sym Elf64_Sym
#define Elf_Rel Elf64_Rel
#define Elf_RelA Elf64_Rela
#define Elf_Dyn Elf64_Dyn
#define Elf_Half Elf64_Half
#define Elf_Word Elf64_Word
#define Elf_Sword Elf64_Sword
#define Elf_Addr Elf64_Addr
#define Elf_Off Elf64_Off
#define Elf_Nhdr Elf64_Nhdr
#define Elf_Note Elf64_Note
#define ELF_R_SYM ELF64_R_SYM
#define ELF_R_TYPE ELF64_R_TYPE
#define ELF_R_INFO ELF64_R_INFO
#define ELFCLASS ELFCLASS64
#define ELF_ST_BIND ELF64_ST_BIND
#define ELF_ST_TYPE ELF64_ST_TYPE
#define ELF_ST_INFO ELF64_ST_INFO
#endif
#endif

View File

@ -0,0 +1,49 @@
/*
* Copyright © 2014, Owen Shepherd
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef ELFARCH_H
#define ELFARCH_H
#if defined(__i386__)
#define EM_THIS EM_386
#define EL_ARCH_USES_REL
#elif defined(__amd64__)
#define EM_THIS EM_AMD64
#define EL_ARCH_USES_RELA
#elif defined(__arm__)
#define EM_THIS EM_ARM
#define EL_ARCH_USES_REL
#elif defined(__aarch64__)
#define EM_THIS EM_AARCH64
#define EL_ARCH_USES_RELA
#define EL_ARCH_USES_REL
#else
#error specify your ELF architecture
#endif
#if defined(__LP64__) || defined(__LLP64__)
#define ELFSIZE 64
#else
#define ELFSIZE 32
#endif
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
#define ELFDATATHIS ELFDATA2LSB
#else
#define ELFDATATHIS ELFDATA2MSB
#endif
#endif

View File

@ -0,0 +1,324 @@
/*
* Copyright © 2018, M4xw
* Copyright © 2014, Owen Shepherd
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#include <string.h>
#include "elfload.h"
el_status el_pread(el_ctx *ctx, void *def, size_t nb, size_t offset)
{
return ctx->pread(ctx, def, nb, offset) ? EL_OK : EL_EIO;
}
#define EL_PHOFF(ctx, num) (((ctx)->ehdr.e_phoff + (num) *(ctx)->ehdr.e_phentsize))
el_status el_findphdr(el_ctx *ctx, Elf_Phdr *phdr, uint32_t type, unsigned *i)
{
el_status rv = EL_OK;
for (; *i < ctx->ehdr.e_phnum; (*i)++)
{
if ((rv = el_pread(ctx, phdr, sizeof *phdr, EL_PHOFF(ctx, *i))))
return rv;
if (phdr->p_type == type)
{
return rv;
}
}
*i = -1;
return rv;
}
#define EL_SHOFF(ctx, num) (((ctx)->ehdr.e_shoff + (num) *(ctx)->ehdr.e_shentsize))
el_status el_findshdr(el_ctx *ctx, Elf_Shdr *shdr, uint32_t type, unsigned *i)
{
el_status rv = EL_OK;
for (; *i < ctx->ehdr.e_shnum; (*i)++)
{
if ((rv = el_pread(ctx, shdr, sizeof *shdr, EL_SHOFF(ctx, *i))))
return rv;
if (shdr->sh_type == type)
{
return rv;
}
}
*i = -1;
return rv;
}
el_status el_init(el_ctx *ctx)
{
el_status rv = EL_OK;
if ((rv = el_pread(ctx, &ctx->ehdr, sizeof ctx->ehdr, 0)))
return rv;
/* validate header */
if (!IS_ELF(ctx->ehdr))
return EL_NOTELF;
if (ctx->ehdr.e_ident[EI_CLASS] != ELFCLASS)
return EL_WRONGBITS;
if (ctx->ehdr.e_ident[EI_DATA] != ELFDATATHIS)
return EL_WRONGENDIAN;
if (ctx->ehdr.e_ident[EI_VERSION] != EV_CURRENT)
return EL_NOTELF;
if (ctx->ehdr.e_type != ET_EXEC && ctx->ehdr.e_type != ET_DYN)
return EL_NOTEXEC;
if (ctx->ehdr.e_machine != EM_THIS)
return EL_WRONGARCH;
if (ctx->ehdr.e_version != EV_CURRENT)
return EL_NOTELF;
/* load phdrs */
Elf_Phdr ph;
/* iterate through, calculate extents */
ctx->base_load_paddr = ctx->base_load_vaddr = 0;
ctx->align = 1;
ctx->memsz = 0;
unsigned i = 0;
for (;;)
{
if ((rv = el_findphdr(ctx, &ph, PT_LOAD, &i)))
return rv;
if (i == (unsigned)-1)
break;
Elf_Addr phend = ph.p_vaddr + ph.p_memsz;
if (phend > ctx->memsz)
ctx->memsz = phend;
if (ph.p_align > ctx->align)
ctx->align = ph.p_align;
i++;
}
// Program Header
if (ctx->ehdr.e_type == ET_DYN)
{
i = 0;
if ((rv = el_findphdr(ctx, &ph, PT_DYNAMIC, &i)))
return rv;
if (i == (unsigned)-1)
return EL_NODYN;
ctx->dynoff = ph.p_offset;
ctx->dynsize = ph.p_filesz;
}
else
{
ctx->dynoff = 0;
ctx->dynsize = 0;
}
// Section String Table
if (ctx->ehdr.e_type == ET_DYN)
{
i = ctx->ehdr.e_shstrndx - 1;
if ((rv = el_findshdr(ctx, &ctx->shstr, SHT_STRTAB, &i)))
return rv;
// Reset
i = 0;
if ((rv = el_findshdr(ctx, &ctx->symtab, SHT_SYMTAB, &i)))
return rv;
if (i == (unsigned)-1)
return EL_NODYN;
}
return rv;
}
/*
typedef void* (*el_alloc_cb)(
el_ctx *ctx,
Elf_Addr phys,
Elf_Addr virt,
Elf_Addr size);
*/
el_status el_load(el_ctx *ctx, el_alloc_cb alloc)
{
el_status rv = EL_OK;
/* address deltas */
Elf_Addr pdelta = ctx->base_load_paddr;
Elf_Addr vdelta = ctx->base_load_vaddr;
/* iterate paddrs */
Elf_Phdr ph;
unsigned i = 0;
for (;;)
{
if ((rv = el_findphdr(ctx, &ph, PT_LOAD, &i)))
return rv;
if (i == (unsigned)-1)
break;
Elf_Addr pload = ph.p_paddr + pdelta;
Elf_Addr vload = ph.p_vaddr + vdelta;
/* allocate mem */
char *dest = alloc(ctx, pload, vload, ph.p_memsz);
if (!dest)
return EL_ENOMEM;
EL_DEBUG("Loading seg fileoff %x, vaddr %x to %p\n",
ph.p_offset, ph.p_vaddr, dest);
/* read loaded portion */
if ((rv = el_pread(ctx, dest, ph.p_filesz, ph.p_offset)))
return rv;
/* zero mem-only portion */
memset(dest + ph.p_filesz, 0, ph.p_memsz - ph.p_filesz);
i++;
}
return rv;
}
el_status el_finddyn(el_ctx *ctx, Elf_Dyn *dyn, uint32_t tag)
{
el_status rv = EL_OK;
size_t ndyn = ctx->dynsize / sizeof(Elf_Dyn);
for (unsigned i = 0; i < ndyn; i++)
{
if ((rv = el_pread(ctx, dyn, sizeof *dyn, ctx->dynoff + i * sizeof *dyn)))
return rv;
if (dyn->d_tag == tag)
return EL_OK;
}
dyn->d_tag = DT_NULL;
return EL_OK;
}
el_status el_findrelocs(el_ctx *ctx, el_relocinfo *ri, uint32_t type)
{
el_status rv = EL_OK;
Elf_Dyn rel, relsz, relent;
if ((rv = el_finddyn(ctx, &rel, type)))
return rv;
if ((rv = el_finddyn(ctx, &relsz, type + 1)))
return rv;
if ((rv = el_finddyn(ctx, &relent, type + 2)))
return rv;
if (rel.d_tag == DT_NULL || relsz.d_tag == DT_NULL || relent.d_tag == DT_NULL)
{
ri->entrysize = 0;
ri->tablesize = 0;
ri->tableoff = 0;
}
else
{
ri->tableoff = rel.d_un.d_ptr;
ri->tablesize = relsz.d_un.d_val;
ri->entrysize = relent.d_un.d_val;
}
return rv;
}
extern el_status el_applyrel(el_ctx *ctx, Elf_Rel *rel);
extern el_status el_applyrela(el_ctx *ctx, Elf_RelA *rela);
el_status el_relocate(el_ctx *ctx)
{
el_status rv = EL_OK;
// not dynamic
if (ctx->ehdr.e_type != ET_DYN)
return EL_OK;
char *base = (char *)ctx->base_load_paddr;
el_relocinfo ri;
#ifdef EL_ARCH_USES_REL
if ((rv = el_findrelocs(ctx, &ri, DT_REL)))
return rv;
if (ri.entrysize != sizeof(Elf_Rel) && ri.tablesize)
{
EL_DEBUG("Relocation size %u doesn't match expected %u\n",
ri.entrysize, sizeof(Elf_Rel));
return EL_BADREL;
}
size_t relcnt = ri.tablesize / sizeof(Elf_Rel);
Elf_Rel *reltab = (Elf_Rel *)(base + ri.tableoff);
for (size_t i = 0; i < relcnt; i++)
{
if ((rv = el_applyrel(ctx, &reltab[i])))
return rv;
}
#endif
#ifdef EL_ARCH_USES_RELA
if ((rv = el_findrelocs(ctx, &ri, DT_RELA)))
return rv;
if (ri.entrysize != sizeof(Elf_RelA) && ri.tablesize)
{
EL_DEBUG("Relocation size %u doesn't match expected %u\n",
ri.entrysize, sizeof(Elf_RelA));
return EL_BADREL;
}
size_t relacnt = ri.tablesize / sizeof(Elf_RelA);
Elf_RelA *relatab = (Elf_RelA *)(base + ri.tableoff);
for (size_t i = 0; i < relacnt; i++)
{
if ((rv = el_applyrela(ctx, &relatab[i])))
return rv;
}
#endif
#if !defined(EL_ARCH_USES_REL) && !defined(EL_ARCH_USES_RELA)
#error No relocation type defined!
#endif
return rv;
}

View File

@ -0,0 +1,127 @@
/*
* Copyright © 2018, M4xw
* Copyright © 2014, Owen Shepherd
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef ELFLOAD_H
#define ELFLOAD_H
#include <stddef.h>
#include "elfarch.h"
#include "elf.h"
#include "../../utils/types.h"
#ifdef DEBUG
#include "../../gfx/gfx.h"
#define EL_DEBUG(format, ...) \
gfx_printf(format __VA_OPT__(, ) __VA_ARGS__)
#else
#define EL_DEBUG(...) \
do \
{ \
} while (0)
#endif
typedef enum
{
EL_OK = 0,
EL_EIO,
EL_ENOMEM,
EL_NOTELF,
EL_WRONGBITS,
EL_WRONGENDIAN,
EL_WRONGARCH,
EL_WRONGOS,
EL_NOTEXEC,
EL_NODYN,
EL_BADREL,
} el_status;
typedef struct el_ctx
{
bool (*pread)(struct el_ctx *ctx, void *dest, size_t nb, size_t offset);
/* base_load_* -> address we are actually going to load at
*/
Elf_Addr
base_load_paddr,
base_load_vaddr;
/* size in memory of binary */
Elf_Addr memsz;
/* required alignment */
Elf_Addr align;
/* ELF header */
Elf_Ehdr ehdr;
// Section Header Str Table
Elf_Shdr shstr;
Elf_Shdr symtab;
/* Offset of dynamic table (0 if not ET_DYN) */
Elf_Off dynoff;
/* Size of dynamic table (0 if not ET_DYN) */
Elf_Addr dynsize;
} el_ctx;
el_status el_pread(el_ctx *ctx, void *def, size_t nb, size_t offset);
el_status el_init(el_ctx *ctx);
typedef void *(*el_alloc_cb)(
el_ctx *ctx,
Elf_Addr phys,
Elf_Addr virt,
Elf_Addr size);
el_status el_load(el_ctx *ctx, el_alloc_cb alloccb);
/* find the next phdr of type \p type, starting at \p *i.
* On success, returns EL_OK with *i set to the phdr number, and the phdr loaded
* in *phdr.
*
* If the end of the phdrs table was reached, *i is set to -1 and the contents
* of *phdr are undefined
*/
el_status el_findphdr(el_ctx *ctx, Elf_Phdr *phdr, uint32_t type, unsigned *i);
/* Relocate the loaded executable */
el_status el_relocate(el_ctx *ctx);
/* find a dynamic table entry
* returns the entry on success, dyn->d_tag = DT_NULL on failure
*/
el_status el_finddyn(el_ctx *ctx, Elf_Dyn *dyn, uint32_t type);
typedef struct
{
Elf_Off tableoff;
Elf_Addr tablesize;
Elf_Addr entrysize;
} el_relocinfo;
/* find all information regarding relocations of a specific type.
*
* pass DT_REL or DT_RELA for type
* sets ri->entrysize = 0 if not found
*/
el_status el_findrelocs(el_ctx *ctx, el_relocinfo *ri, uint32_t type);
#endif

View File

@ -0,0 +1,84 @@
/*
* Copyright © 2014, Owen Shepherd
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#include "elfload.h"
#if defined(__aarch64__)
#define R_AARCH64_NONE 0
#define R_AARCH64_RELATIVE 1027
el_status el_applyrela(el_ctx *ctx, Elf_RelA *rel)
{
uintptr_t *p = (uintptr_t *)(rel->r_offset + ctx->base_load_paddr);
uint32_t type = ELF_R_TYPE(rel->r_info);
uint32_t sym = ELF_R_SYM(rel->r_info);
switch (type)
{
case R_AARCH64_NONE:
EL_DEBUG("R_AARCH64_NONE\n");
break;
case R_AARCH64_RELATIVE:
if (sym)
{
EL_DEBUG("R_AARCH64_RELATIVE with symbol ref!\n");
return EL_BADREL;
}
EL_DEBUG("Applying R_AARCH64_RELATIVE reloc @%p\n", p);
*p = rel->r_addend + ctx->base_load_vaddr;
break;
default:
EL_DEBUG("Bad relocation %u\n", type);
return EL_BADREL;
}
return EL_OK;
}
el_status el_applyrel(el_ctx *ctx, Elf_Rel *rel)
{
uintptr_t *p = (uintptr_t *)(rel->r_offset + ctx->base_load_paddr);
uint32_t type = ELF_R_TYPE(rel->r_info);
uint32_t sym = ELF_R_SYM(rel->r_info);
switch (type)
{
case R_AARCH64_NONE:
EL_DEBUG("R_AARCH64_NONE\n");
break;
case R_AARCH64_RELATIVE:
if (sym)
{
EL_DEBUG("R_AARCH64_RELATIVE with symbol ref!\n");
return EL_BADREL;
}
EL_DEBUG("Applying R_AARCH64_RELATIVE reloc @%p\n", p);
*p += ctx->base_load_vaddr;
break;
default:
EL_DEBUG("Bad relocation %u\n", type);
return EL_BADREL;
}
return EL_OK;
}
#endif

View File

@ -0,0 +1,66 @@
/*
* ----------------------------------------------------------------------------
* "THE BEER-WARE LICENSE" (Revision 42):
* <m4x@m4xw.net> wrote this file. As long as you retain this notice you can do
* whatever you want with this stuff. If we meet some day, and you think this
* stuff is worth it, you can buy me a beer in return. M4xw
* ----------------------------------------------------------------------------
*/
#include "elfload.h"
#if defined(__arm__)
// Taken from http://infocenter.arm.com/help/topic/com.arm.doc.ihi0044f/IHI0044F_aaelf.pdf
#define R_ARM_NONE 0
#define R_ARM_ABS32 2
#define R_ARM_JUMP_SLOT 22
#define R_ARM_GLOB_DAT 21
#define R_ARM_RELATIVE 23
el_status el_applyrel(el_ctx *ctx, Elf_Rel *rel)
{
uint32_t sym = ELF_R_SYM(rel->r_info); // Symbol offset
uint32_t type = ELF_R_TYPE(rel->r_info); // Relocation Type
uintptr_t *p = (uintptr_t *)(rel->r_offset + ctx->base_load_paddr); // Target Addr
#if 0 // For later symbol usage
Elf32_Sym *elfSym;
const char *symbolName;
// We resolve relocs from the originating elf-image
elfSym = (Elf32_Sym *)(ctx->symtab.sh_offset + (char *)buffteg) + sym;
int strtab_offset = ctx->shstr.sh_offset;
char *strtab = (char *)buffteg + strtab_offset;
symbolName = strtab + elfSym->st_name;
//EL_DEBUG("Str: %s sz: %x val: %x\n", symbolName, elfSym->st_size, elfSym->st_value);
#endif
switch (type)
{
case R_ARM_NONE:
EL_DEBUG("R_ARM_NONE\n");
break;
case R_ARM_JUMP_SLOT:
case R_ARM_ABS32:
case R_ARM_GLOB_DAT:
// Stubbed for later purpose
//*p += elfSym->st_value; // + vaddr from sec
//*p |= 0; // 1 if Thumb && STT_FUNC, ignored for now
break;
case R_ARM_RELATIVE: // Needed for PIE
if (sym)
{
return EL_BADREL;
}
*p += ctx->base_load_vaddr;
break;
default:
return EL_BADREL;
}
return EL_OK;
}
#endif

View File

@ -42,11 +42,13 @@ typedef struct {
u32 visit_count; u32 visit_count;
u8 tweak[0x10]; u8 tweak[0x10];
u8 cached_sector[0x200]; u8 cached_sector[0x200];
u8 align[8];
} sector_cache_t; } sector_cache_t;
#define MAX_SEC_CACHE_ENTRIES 64 #define MAX_SEC_CACHE_ENTRIES 64
static sector_cache_t *sector_cache = (sector_cache_t*)0x40020000; static sector_cache_t *sector_cache = NULL;
static u32 secindex = 0; static u32 secindex = 0;
bool clear_sector_cache = false;
DSTATUS disk_status ( DSTATUS disk_status (
BYTE pdrv /* Physical drive number to identify the drive */ BYTE pdrv /* Physical drive number to identify the drive */
@ -134,7 +136,15 @@ DRESULT disk_read (
switch (pdrv) switch (pdrv)
{ {
case 0: case 0:
return sdmmc_storage_read(&sd_storage, sector, count, buff) ? RES_OK : RES_ERROR; if (((u32)buff >= DRAM_START) && !((u32)buff % 8))
return sdmmc_storage_read(&sd_storage, sector, count, buff) ? RES_OK : RES_ERROR;
u8 *buf = (u8 *)SDMMC_UPPER_BUFFER;
if (sdmmc_storage_read(&sd_storage, sector, count, buf))
{
memcpy(buff, buf, 512 * count);
return RES_OK;
}
return RES_ERROR;
case 1:; case 1:;
__attribute__ ((aligned (16))) static u8 tweak[0x10]; __attribute__ ((aligned (16))) static u8 tweak[0x10];
@ -143,6 +153,13 @@ DRESULT disk_read (
u32 tweak_exp = 0; u32 tweak_exp = 0;
bool regen_tweak = true, cache_sector = false; bool regen_tweak = true, cache_sector = false;
if (secindex == 0 || clear_sector_cache) {
free(sector_cache);
sector_cache = (sector_cache_t *)malloc(sizeof(sector_cache_t) * MAX_SEC_CACHE_ENTRIES);
clear_sector_cache = false;
secindex = 0;
}
u32 s = 0; u32 s = 0;
if (count == 1) { if (count == 1) {
for ( ; s < secindex; s++) { for ( ; s < secindex; s++) {
@ -198,7 +215,14 @@ DRESULT disk_write (
{ {
if (pdrv == 1) if (pdrv == 1)
return RES_WRPRT; return RES_WRPRT;
return sdmmc_storage_write(&sd_storage, sector, count, (void *)buff) ? RES_OK : RES_ERROR;
if (((u32)buff >= DRAM_START) && !((u32)buff % 8))
return sdmmc_storage_write(&sd_storage, sector, count, (void *)buff) ? RES_OK : RES_ERROR;
u8 *buf = (u8 *)SDMMC_UPPER_BUFFER; //TODO: define this somewhere.
memcpy(buf, buff, 512 * count);
if (sdmmc_storage_write(&sd_storage, sector, count, buf))
return RES_OK;
return RES_ERROR;
} }
DRESULT disk_ioctl ( DRESULT disk_ioctl (

View File

@ -25,7 +25,7 @@
/ 3: f_lseek() function is removed in addition to 2. */ / 3: f_lseek() function is removed in addition to 2. */
#define FF_USE_STRFUNC 0 #define FF_USE_STRFUNC 2
/* This option switches string functions, f_gets(), f_putc(), f_puts() and f_printf(). /* This option switches string functions, f_gets(), f_putc(), f_puts() and f_printf().
/ /
/ 0: Disable string functions. / 0: Disable string functions.
@ -33,7 +33,7 @@
/ 2: Enable with LF-CRLF conversion. */ / 2: Enable with LF-CRLF conversion. */
#define FF_USE_FIND 0 #define FF_USE_FIND 1
/* This option switches filtered directory read functions, f_findfirst() and /* This option switches filtered directory read functions, f_findfirst() and
/ f_findnext(). (0:Disable, 1:Enable 2:Enable with matching altname[] too) */ / f_findnext(). (0:Disable, 1:Enable 2:Enable with matching altname[] too) */
@ -50,7 +50,7 @@
/* This option switches f_expand function. (0:Disable or 1:Enable) */ /* This option switches f_expand function. (0:Disable or 1:Enable) */
#define FF_USE_CHMOD 0 #define FF_USE_CHMOD 1
/* This option switches attribute manipulation functions, f_chmod() and f_utime(). /* This option switches attribute manipulation functions, f_chmod() and f_utime().
/ (0:Disable or 1:Enable) Also FF_FS_READONLY needs to be 0 to enable this option. */ / (0:Disable or 1:Enable) Also FF_FS_READONLY needs to be 0 to enable this option. */

View File

@ -18,15 +18,22 @@
#include <string.h> #include <string.h>
#include "config/config.h"
#include "gfx/di.h" #include "gfx/di.h"
#include "gfx/gfx.h" #include "gfx/gfx.h"
#include "gfx/tui.h"
#include "hos/pkg1.h"
#include "libs/fatfs/ff.h" #include "libs/fatfs/ff.h"
#include "mem/heap.h" #include "mem/heap.h"
#include "mem/minerva.h"
#include "power/max77620.h" #include "power/max77620.h"
#include "rtc/max77620-rtc.h" #include "rtc/max77620-rtc.h"
#include "soc/bpmp.h" #include "soc/bpmp.h"
#include "soc/hw_init.h" #include "soc/hw_init.h"
#include "storage/emummc.h"
#include "storage/nx_emmc.h"
#include "storage/sdmmc.h" #include "storage/sdmmc.h"
#include "utils/sprintf.h"
#include "utils/util.h" #include "utils/util.h"
#include "keys/keys.h" #include "keys/keys.h"
@ -36,6 +43,7 @@ sdmmc_storage_t sd_storage;
__attribute__ ((aligned (16))) FATFS sd_fs; __attribute__ ((aligned (16))) FATFS sd_fs;
static bool sd_mounted; static bool sd_mounted;
hekate_config h_cfg;
boot_cfg_t __attribute__((section ("._boot_cfg"))) b_cfg; boot_cfg_t __attribute__((section ("._boot_cfg"))) b_cfg;
bool sd_mount() bool sd_mount()
@ -77,27 +85,27 @@ void sd_unmount()
void *sd_file_read(const char *path, u32 *fsize) void *sd_file_read(const char *path, u32 *fsize)
{ {
FIL fp; FIL fp;
if (f_open(&fp, path, FA_READ) != FR_OK) if (f_open(&fp, path, FA_READ) != FR_OK)
return NULL; return NULL;
u32 size = f_size(&fp); u32 size = f_size(&fp);
if (fsize) if (fsize)
*fsize = size; *fsize = size;
void *buf = malloc(size); void *buf = malloc(size);
if (f_read(&fp, buf, size, NULL) != FR_OK) if (f_read(&fp, buf, size, NULL) != FR_OK)
{ {
free(buf); free(buf);
f_close(&fp); f_close(&fp);
return NULL; return NULL;
} }
f_close(&fp); f_close(&fp);
return buf; return buf;
} }
int sd_save_to_file(void *buf, u32 size, const char *filename) int sd_save_to_file(void *buf, u32 size, const char *filename)
@ -143,7 +151,66 @@ void reloc_patcher(u32 payload_dst, u32 payload_src, u32 payload_size)
} }
} }
#define IPL_STACK_TOP 0x4003F000 void dump_sysnand()
{
h_cfg.emummc_force_disable = true;
b_cfg.extra_cfg &= ~EXTRA_CFG_DUMP_EMUMMC;
dump_keys();
}
void dump_emunand()
{
if (h_cfg.emummc_force_disable)
return;
emu_cfg.enabled = 1;
b_cfg.extra_cfg |= EXTRA_CFG_DUMP_EMUMMC;
dump_keys();
}
ment_t ment_top[] = {
MDEF_HANDLER("Dump from SysNAND | Key generation: unk", dump_sysnand, COLOR_RED),
MDEF_HANDLER("Dump from EmuNAND | Key generation: unk", dump_emunand, COLOR_ORANGE),
MDEF_CAPTION("---------------", COLOR_YELLOW),
MDEF_HANDLER("Reboot (Normal)", reboot_normal, COLOR_GREEN),
MDEF_HANDLER("Reboot (RCM)", reboot_rcm, COLOR_BLUE),
MDEF_HANDLER("Power off", power_off, COLOR_VIOLET),
MDEF_END()
};
menu_t menu_top = { ment_top, NULL, 0, 0 };
void _get_key_generations(char *sysnand_label, char *emunand_label) {
sdmmc_t sdmmc;
sdmmc_storage_t storage;
sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4);
u8 *pkg1 = (u8 *)malloc(NX_EMMC_BLOCKSIZE);
sdmmc_storage_set_mmc_partition(&storage, 1);
sdmmc_storage_read(&storage, 0x100000 / NX_EMMC_BLOCKSIZE, 1, pkg1);
const pkg1_id_t *pkg1_id = pkg1_identify(pkg1);
sdmmc_storage_end(&storage);
if (pkg1_id)
sprintf(sysnand_label + 36, "% 3d", pkg1_id->kb);
ment_top[0].caption = sysnand_label;
if (h_cfg.emummc_force_disable) {
free(pkg1);
return;
}
emummc_storage_init_mmc(&storage, &sdmmc);
memset(pkg1, 0, NX_EMMC_BLOCKSIZE);
emummc_storage_set_mmc_partition(&storage, 1);
emummc_storage_read(&storage, 0x100000 / NX_EMMC_BLOCKSIZE, 1, pkg1);
pkg1_id = pkg1_identify(pkg1);
emummc_storage_end(&storage);
if (pkg1_id)
sprintf(emunand_label + 36, "% 3d", pkg1_id->kb);
free(pkg1);
ment_top[1].caption = emunand_label;
}
#define IPL_STACK_TOP 0x90010000
#define IPL_HEAP_START 0x90020000 #define IPL_HEAP_START 0x90020000
extern void pivot_stack(u32 stack_top); extern void pivot_stack(u32 stack_top);
@ -154,6 +221,12 @@ void ipl_main()
pivot_stack(IPL_STACK_TOP); pivot_stack(IPL_STACK_TOP);
heap_init(IPL_HEAP_START); heap_init(IPL_HEAP_START);
set_default_configuration();
sd_mount();
minerva_init();
minerva_change_freq(FREQ_1600);
display_init(); display_init();
u32 *fb = display_init_framebuffer(); u32 *fb = display_init_framebuffer();
gfx_init_ctxt(fb, 720, 1280, 720); gfx_init_ctxt(fb, 720, 1280, 720);
@ -162,6 +235,27 @@ void ipl_main()
bpmp_clk_rate_set(BPMP_CLK_SUPER_BOOST); bpmp_clk_rate_set(BPMP_CLK_SUPER_BOOST);
sd_mount(); h_cfg.emummc_force_disable = emummc_load_cfg();
dump_keys();
if (b_cfg.boot_cfg & BOOT_CFG_SEPT_RUN)
{
if (!(b_cfg.extra_cfg & EXTRA_CFG_DUMP_EMUMMC))
h_cfg.emummc_force_disable = true;
dump_keys();
}
if (h_cfg.emummc_force_disable)
{
ment_top[1].type = MENT_CAPTION;
ment_top[1].color = 0xFF555555;
ment_top[1].handler = NULL;
}
_get_key_generations((char *)ment_top[0].caption, (char *)ment_top[1].caption);
while (true)
tui_do_menu(&menu_top);
while (true)
bpmp_halt();
} }

88
source/mem/minerva.c Normal file
View File

@ -0,0 +1,88 @@
/*
* 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/>.
*/
#include <string.h>
#include <stdlib.h>
#include "minerva.h"
#include "../soc/fuse.h"
#include "../utils/util.h"
#include "../soc/clock.h"
#include "../ianos/ianos.h"
#include "../soc/fuse.h"
#include "../soc/t210.h"
volatile nyx_storage_t *nyx_str = (nyx_storage_t *)0xED000000;
void minerva_init()
{
u32 curr_ram_idx = 0;
mtc_config_t *mtc_cfg = (mtc_config_t *)&nyx_str->mtc_cfg;
// Set table to ram.
mtc_cfg->mtc_table = NULL;
mtc_cfg->sdram_id = (fuse_read_odm(4) >> 3) & 0x1F;
u32 ep_addr = ianos_loader(false, "bootloader/sys/libsys_minerva.bso", DRAM_LIB, (void *)mtc_cfg);
minerva_cfg = (void *)ep_addr;
if (!minerva_cfg)
return;
// Get current frequency
for (curr_ram_idx = 0; curr_ram_idx < 10; curr_ram_idx++)
{
if (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC) == mtc_cfg->mtc_table[curr_ram_idx].clk_src_emc)
break;
}
mtc_cfg->rate_from = mtc_cfg->mtc_table[curr_ram_idx].rate_khz;
mtc_cfg->rate_to = 204000;
mtc_cfg->train_mode = OP_TRAIN;
minerva_cfg(mtc_cfg, NULL);
mtc_cfg->rate_to = 800000;
minerva_cfg(mtc_cfg, NULL);
mtc_cfg->rate_to = 1600000;
minerva_cfg(mtc_cfg, NULL);
}
void minerva_change_freq(minerva_freq_t freq)
{
if (!minerva_cfg)
return;
mtc_config_t *mtc_cfg = (mtc_config_t *)&nyx_str->mtc_cfg;
if (minerva_cfg && (mtc_cfg->rate_from != freq))
{
mtc_cfg->rate_to = freq;
mtc_cfg->train_mode = OP_SWITCH;
minerva_cfg(mtc_cfg, NULL);
}
}
void minerva_periodic_training()
{
if (!minerva_cfg)
return;
mtc_config_t *mtc_cfg = (mtc_config_t *)&nyx_str->mtc_cfg;
if (minerva_cfg && mtc_cfg->rate_from == FREQ_1600)
{
mtc_cfg->train_mode = OP_PERIODIC_TRAIN;
minerva_cfg(mtc_cfg, NULL);
}
}

61
source/mem/minerva.h Normal file
View File

@ -0,0 +1,61 @@
/*
* 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 _FE_MINERVA_H_
#define _FE_MINERVA_H_
#include "mtc_table.h"
#include "../utils/types.h"
#define EMC_PERIODIC_TRAIN_MS 100
typedef struct
{
s32 rate_to;
s32 rate_from;
emc_table_t *mtc_table;
u32 table_entries;
emc_table_t *current_emc_table;
u32 train_mode;
u32 sdram_id;
u32 prev_temp;
bool emc_2X_clk_src_is_pllmb;
bool fsp_for_src_freq;
bool train_ram_patterns;
} mtc_config_t;
enum train_mode_t
{
OP_SWITCH = 0,
OP_TRAIN = 1,
OP_TRAIN_SWITCH = 2,
OP_PERIODIC_TRAIN = 3,
OP_TEMP_COMP = 4
};
typedef enum
{
FREQ_204 = 204000,
FREQ_800 = 800000,
FREQ_1600 = 1600000
} minerva_freq_t;
void (*minerva_cfg)(mtc_config_t *mtc_cfg, void *);
void minerva_init();
void minerva_change_freq(minerva_freq_t freq);
void minerva_periodic_training();
#endif

560
source/mem/mtc_table.h Normal file
View File

@ -0,0 +1,560 @@
/*
* Minerva Training Cell
* DRAM Training for Tegra X1 SoC. Supports DDR2/3 and LPDDR3/4.
*
* Copyright (c) 2018 CTCaer <ctcaer@gmail.com>
*
* 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 _MTC_TABLE_H_
#define _MTC_TABLE_H_
#include "../utils/types.h"
typedef struct
{
s32 pll_osc_in;
s32 pll_out;
u32 pll_feedback_div;
u32 pll_input_div;
u32 pll_post_div;
} pllm_clk_config_t;
typedef struct
{
u32 emc_rc_idx;
u32 emc_rfc_idx;
u32 emc_rfcpb_idx;
u32 emc_refctrl2_idx;
u32 emc_rfc_slr_idx;
u32 emc_ras_idx;
u32 emc_rp_idx;
u32 emc_r2w_idx;
u32 emc_w2r_idx;
u32 emc_r2p_idx;
u32 emc_w2p_idx;
u32 emc_r2r_idx;
u32 emc_tppd_idx;
u32 emc_ccdmw_idx;
u32 emc_rd_rcd_idx;
u32 emc_wr_rcd_idx;
u32 emc_rrd_idx;
u32 emc_rext_idx;
u32 emc_wext_idx;
u32 emc_wdv_chk_idx;
u32 emc_wdv_idx;
u32 emc_wsv_idx;
u32 emc_wev_idx;
u32 emc_wdv_mask_idx;
u32 emc_ws_duration_idx;
u32 emc_we_duration_idx;
u32 emc_quse_idx;
u32 emc_quse_width_idx;
u32 emc_ibdly_idx;
u32 emc_obdly_idx;
u32 emc_einput_idx;
u32 emc_mrw6_idx;
u32 emc_einput_duration_idx;
u32 emc_puterm_extra_idx;
u32 emc_puterm_width_idx;
u32 emc_qrst_idx;
u32 emc_qsafe_idx;
u32 emc_rdv_idx;
u32 emc_rdv_mask_idx;
u32 emc_rdv_early_idx;
u32 emc_rdv_early_mask_idx;
u32 emc_refresh_idx;
u32 emc_burst_refresh_num_idx;
u32 emc_pre_refresh_req_cnt_idx;
u32 emc_pdex2wr_idx;
u32 emc_pdex2rd_idx;
u32 emc_pchg2pden_idx;
u32 emc_act2pden_idx;
u32 emc_ar2pden_idx;
u32 emc_rw2pden_idx;
u32 emc_cke2pden_idx;
u32 emc_pdex2cke_idx;
u32 emc_pdex2mrr_idx;
u32 emc_txsr_idx;
u32 emc_txsrdll_idx;
u32 emc_tcke_idx;
u32 emc_tckesr_idx;
u32 emc_tpd_idx;
u32 emc_tfaw_idx;
u32 emc_trpab_idx;
u32 emc_tclkstable_idx;
u32 emc_tclkstop_idx;
u32 emc_mrw7_idx;
u32 emc_trefbw_idx;
u32 emc_odt_write_idx;
u32 emc_fbio_cfg5_idx;
u32 emc_fbio_cfg7_idx;
u32 emc_cfg_dig_dll_idx;
u32 emc_cfg_dig_dll_period_idx;
u32 emc_pmacro_ib_rxrt_idx;
u32 emc_cfg_pipe_1_idx;
u32 emc_cfg_pipe_2_idx;
u32 emc_pmacro_quse_ddll_rank0_4_idx;
u32 emc_pmacro_quse_ddll_rank0_5_idx;
u32 emc_pmacro_quse_ddll_rank1_4_idx;
u32 emc_pmacro_quse_ddll_rank1_5_idx;
u32 emc_mrw8_idx;
u32 emc_pmacro_ob_ddll_long_dq_rank1_4_idx;
u32 emc_pmacro_ob_ddll_long_dq_rank1_5_idx;
u32 emc_pmacro_ob_ddll_long_dqs_rank0_0_idx;
u32 emc_pmacro_ob_ddll_long_dqs_rank0_1_idx;
u32 emc_pmacro_ob_ddll_long_dqs_rank0_2_idx;
u32 emc_pmacro_ob_ddll_long_dqs_rank0_3_idx;
u32 emc_pmacro_ob_ddll_long_dqs_rank0_4_idx;
u32 emc_pmacro_ob_ddll_long_dqs_rank0_5_idx;
u32 emc_pmacro_ob_ddll_long_dqs_rank1_0_idx;
u32 emc_pmacro_ob_ddll_long_dqs_rank1_1_idx;
u32 emc_pmacro_ob_ddll_long_dqs_rank1_2_idx;
u32 emc_pmacro_ob_ddll_long_dqs_rank1_3_idx;
u32 emc_pmacro_ob_ddll_long_dqs_rank1_4_idx;
u32 emc_pmacro_ob_ddll_long_dqs_rank1_5_idx;
u32 emc_pmacro_ddll_long_cmd_0_idx;
u32 emc_pmacro_ddll_long_cmd_1_idx;
u32 emc_pmacro_ddll_long_cmd_2_idx;
u32 emc_pmacro_ddll_long_cmd_3_idx;
u32 emc_pmacro_ddll_long_cmd_4_idx;
u32 emc_pmacro_ddll_short_cmd_0_idx;
u32 emc_pmacro_ddll_short_cmd_1_idx;
u32 emc_pmacro_ddll_short_cmd_2_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte0_3_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte1_3_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte2_3_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte3_3_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte4_3_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte5_3_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte6_3_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte7_3_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd0_3_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd1_3_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd2_3_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd3_3_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte0_3_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte1_3_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte2_3_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte3_3_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte4_3_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte5_3_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte6_3_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte7_3_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd0_0_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd0_1_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd0_2_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd0_3_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd1_0_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd1_1_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd1_2_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd1_3_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd2_0_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd2_1_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd2_2_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd2_3_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd3_0_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd3_1_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd3_2_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd3_3_idx;
u32 emc_txdsrvttgen_idx;
u32 emc_fdpd_ctrl_dq_idx;
u32 emc_fdpd_ctrl_cmd_idx;
u32 emc_fbio_spare_idx;
u32 emc_zcal_interval_idx;
u32 emc_zcal_wait_cnt_idx;
u32 emc_mrs_wait_cnt_idx;
u32 emc_mrs_wait_cnt2_idx;
u32 emc_auto_cal_channel_idx;
u32 emc_dll_cfg_0_idx;
u32 emc_dll_cfg_1_idx;
u32 emc_pmacro_autocal_cfg_common_idx;
u32 emc_pmacro_zctrl_idx;
u32 emc_cfg_idx;
u32 emc_cfg_pipe_idx;
u32 emc_dyn_self_ref_control_idx;
u32 emc_qpop_idx;
u32 emc_dqs_brlshft_0_idx;
u32 emc_dqs_brlshft_1_idx;
u32 emc_cmd_brlshft_2_idx;
u32 emc_cmd_brlshft_3_idx;
u32 emc_pmacro_pad_cfg_ctrl_idx;
u32 emc_pmacro_data_pad_rx_ctrl_idx;
u32 emc_pmacro_cmd_pad_rx_ctrl_idx;
u32 emc_pmacro_data_rx_term_mode_idx;
u32 emc_pmacro_cmd_rx_term_mode_idx;
u32 emc_pmacro_cmd_pad_tx_ctrl_idx;
u32 emc_pmacro_data_pad_tx_ctrl_idx;
u32 emc_pmacro_common_pad_tx_ctrl_idx;
u32 emc_pmacro_vttgen_ctrl_0_idx;
u32 emc_pmacro_vttgen_ctrl_1_idx;
u32 emc_pmacro_vttgen_ctrl_2_idx;
u32 emc_pmacro_brick_ctrl_rfu1_idx;
u32 emc_pmacro_cmd_brick_ctrl_fdpd_idx;
u32 emc_pmacro_brick_ctrl_rfu2_idx;
u32 emc_pmacro_data_brick_ctrl_fdpd_idx;
u32 emc_pmacro_bg_bias_ctrl_0_idx;
u32 emc_cfg_3_idx;
u32 emc_pmacro_tx_pwrd_0_idx;
u32 emc_pmacro_tx_pwrd_1_idx;
u32 emc_pmacro_tx_pwrd_2_idx;
u32 emc_pmacro_tx_pwrd_3_idx;
u32 emc_pmacro_tx_pwrd_4_idx;
u32 emc_pmacro_tx_pwrd_5_idx;
u32 emc_config_sample_delay_idx;
u32 emc_pmacro_tx_sel_clk_src_0_idx;
u32 emc_pmacro_tx_sel_clk_src_1_idx;
u32 emc_pmacro_tx_sel_clk_src_2_idx;
u32 emc_pmacro_tx_sel_clk_src_3_idx;
u32 emc_pmacro_tx_sel_clk_src_4_idx;
u32 emc_pmacro_tx_sel_clk_src_5_idx;
u32 emc_pmacro_ddll_bypass_idx;
u32 emc_pmacro_ddll_pwrd_0_idx;
u32 emc_pmacro_ddll_pwrd_1_idx;
u32 emc_pmacro_ddll_pwrd_2_idx;
u32 emc_pmacro_cmd_ctrl_0_idx;
u32 emc_pmacro_cmd_ctrl_1_idx;
u32 emc_pmacro_cmd_ctrl_2_idx;
u32 emc_tr_timing_0_idx;
u32 emc_tr_dvfs_idx;
u32 emc_tr_ctrl_1_idx;
u32 emc_tr_rdv_idx;
u32 emc_tr_qpop_idx;
u32 emc_tr_rdv_mask_idx;
u32 emc_mrw14_idx;
u32 emc_tr_qsafe_idx;
u32 emc_tr_qrst_idx;
u32 emc_training_ctrl_idx;
u32 emc_training_settle_idx;
u32 emc_training_vref_settle_idx;
u32 emc_training_ca_fine_ctrl_idx;
u32 emc_training_ca_ctrl_misc_idx;
u32 emc_training_ca_ctrl_misc1_idx;
u32 emc_training_ca_vref_ctrl_idx;
u32 emc_training_quse_cors_ctrl_idx;
u32 emc_training_quse_fine_ctrl_idx;
u32 emc_training_quse_ctrl_misc_idx;
u32 emc_training_quse_vref_ctrl_idx;
u32 emc_training_read_fine_ctrl_idx;
u32 emc_training_read_ctrl_misc_idx;
u32 emc_training_read_vref_ctrl_idx;
u32 emc_training_write_fine_ctrl_idx;
u32 emc_training_write_ctrl_misc_idx;
u32 emc_training_write_vref_ctrl_idx;
u32 emc_training_mpc_idx;
u32 emc_mrw15_idx;
} burst_regs_t;
typedef struct
{
u32 burst_regs[221];
u32 burst_reg_per_ch[8];
u32 shadow_regs_ca_train[221];
u32 shadow_regs_quse_train[221];
u32 shadow_regs_rdwr_train[221];
} burst_regs_table_t;
typedef struct
{
u32 ptfv_dqsosc_movavg_c0d0u0_idx;
u32 ptfv_dqsosc_movavg_c0d0u1_idx;
u32 ptfv_dqsosc_movavg_c0d1u0_idx;
u32 ptfv_dqsosc_movavg_c0d1u1_idx;
u32 ptfv_dqsosc_movavg_c1d0u0_idx;
u32 ptfv_dqsosc_movavg_c1d0u1_idx;
u32 ptfv_dqsosc_movavg_c1d1u0_idx;
u32 ptfv_dqsosc_movavg_c1d1u1_idx;
u32 ptfv_write_samples_idx;
u32 ptfv_dvfs_samples_idx;
u32 ptfv_movavg_weight_idx;
u32 ptfv_config_ctrl_idx;
} ptfv_list_table_t;
typedef struct
{
u32 emc0_mrw10_idx;
u32 emc1_mrw10_idx;
u32 emc0_mrw11_idx;
u32 emc1_mrw11_idx;
u32 emc0_mrw12_idx;
u32 emc1_mrw12_idx;
u32 emc0_mrw13_idx;
u32 emc1_mrw13_idx;
} burst_reg_per_ch_t;
typedef struct
{
u32 emc_pmacro_ib_ddll_long_dqs_rank0_0_idx;
u32 emc_pmacro_ib_ddll_long_dqs_rank0_1_idx;
u32 emc_pmacro_ib_ddll_long_dqs_rank0_2_idx;
u32 emc_pmacro_ib_ddll_long_dqs_rank0_3_idx;
u32 emc_pmacro_ib_ddll_long_dqs_rank1_0_idx;
u32 emc_pmacro_ib_ddll_long_dqs_rank1_1_idx;
u32 emc_pmacro_ib_ddll_long_dqs_rank1_2_idx;
u32 emc_pmacro_ib_ddll_long_dqs_rank1_3_idx;
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte0_0_idx;
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte0_1_idx;
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte0_2_idx;
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte1_0_idx;
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte1_1_idx;
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte1_2_idx;
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte2_0_idx;
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte2_1_idx;
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte2_2_idx;
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte3_0_idx;
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte3_1_idx;
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte3_2_idx;
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte4_0_idx;
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte4_1_idx;
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte4_2_idx;
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte5_0_idx;
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte5_1_idx;
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte5_2_idx;
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte6_0_idx;
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte6_1_idx;
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte6_2_idx;
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte7_0_idx;
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte7_1_idx;
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte7_2_idx;
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte0_0_idx;
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte0_1_idx;
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte0_2_idx;
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte1_0_idx;
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte1_1_idx;
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte1_2_idx;
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte2_0_idx;
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte2_1_idx;
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte2_2_idx;
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte3_0_idx;
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte3_1_idx;
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte3_2_idx;
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte4_0_idx;
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte4_1_idx;
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte4_2_idx;
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte5_0_idx;
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte5_1_idx;
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte5_2_idx;
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte6_0_idx;
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte6_1_idx;
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte6_2_idx;
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte7_0_idx;
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte7_1_idx;
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte7_2_idx;
u32 emc_pmacro_ib_vref_dqs_0_idx;
u32 emc_pmacro_ib_vref_dqs_1_idx;
u32 emc_pmacro_ib_vref_dq_0_idx;
u32 emc_pmacro_ib_vref_dq_1_idx;
u32 emc_pmacro_ob_ddll_long_dq_rank0_0_idx;
u32 emc_pmacro_ob_ddll_long_dq_rank0_1_idx;
u32 emc_pmacro_ob_ddll_long_dq_rank0_2_idx;
u32 emc_pmacro_ob_ddll_long_dq_rank0_3_idx;
u32 emc_pmacro_ob_ddll_long_dq_rank0_4_idx;
u32 emc_pmacro_ob_ddll_long_dq_rank0_5_idx;
u32 emc_pmacro_ob_ddll_long_dq_rank1_0_idx;
u32 emc_pmacro_ob_ddll_long_dq_rank1_1_idx;
u32 emc_pmacro_ob_ddll_long_dq_rank1_2_idx;
u32 emc_pmacro_ob_ddll_long_dq_rank1_3_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte0_0_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte0_1_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte0_2_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte1_0_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte1_1_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte1_2_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte2_0_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte2_1_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte2_2_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte3_0_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte3_1_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte3_2_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte4_0_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte4_1_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte4_2_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte5_0_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte5_1_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte5_2_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte6_0_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte6_1_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte6_2_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte7_0_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte7_1_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte7_2_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd0_0_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd0_1_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd0_2_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd1_0_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd1_1_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd1_2_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd2_0_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd2_1_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd2_2_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd3_0_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd3_1_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd3_2_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte0_0_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte0_1_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte0_2_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte1_0_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte1_1_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte1_2_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte2_0_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte2_1_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte2_2_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte3_0_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte3_1_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte3_2_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte4_0_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte4_1_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte4_2_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte5_0_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte5_1_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte5_2_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte6_0_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte6_1_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte6_2_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte7_0_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte7_1_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte7_2_idx;
u32 emc_pmacro_quse_ddll_rank0_0_idx;
u32 emc_pmacro_quse_ddll_rank0_1_idx;
u32 emc_pmacro_quse_ddll_rank0_2_idx;
u32 emc_pmacro_quse_ddll_rank0_3_idx;
u32 emc_pmacro_quse_ddll_rank1_0_idx;
u32 emc_pmacro_quse_ddll_rank1_1_idx;
u32 emc_pmacro_quse_ddll_rank1_2_idx;
u32 emc_pmacro_quse_ddll_rank1_3_idx;
} trim_regs_t;
typedef struct
{
u32 emc_cmd_brlshft_0_idx;
u32 emc_cmd_brlshft_1_idx;
u32 emc0_data_brlshft_0_idx;
u32 emc1_data_brlshft_0_idx;
u32 emc0_data_brlshft_1_idx;
u32 emc1_data_brlshft_1_idx;
u32 emc_quse_brlshft_0_idx;
u32 emc_quse_brlshft_1_idx;
u32 emc_quse_brlshft_2_idx;
u32 emc_quse_brlshft_3_idx;
} trim_perch_regs_t;
typedef struct
{
u32 t_rp;
u32 t_fc_lpddr4;
u32 t_rfc;
u32 t_pdex;
u32 rl;
} dram_timings_t;
typedef struct
{
u32 emc0_training_opt_dqs_ib_vref_rank0_idx;
u32 emc1_training_opt_dqs_ib_vref_rank0_idx;
u32 emc0_training_opt_dqs_ib_vref_rank1_idx;
u32 emc1_training_opt_dqs_ib_vref_rank1_idx;
} vref_perch_regs_t;
typedef struct
{
u32 trim_regs[138];
u32 trim_perch_regs[10];
u32 vref_perch_regs[4];
} trim_regs_table_t;
typedef struct
{
u32 rev;
char dvfs_ver[60];
u32 rate_khz;
u32 min_volt;
u32 gpu_min_volt;
char clock_src[32];
u32 clk_src_emc;
u32 needs_training;
u32 training_pattern;
u32 trained;
u32 periodic_training;
u32 trained_dram_clktree_c0d0u0;
u32 trained_dram_clktree_c0d0u1;
u32 trained_dram_clktree_c0d1u0;
u32 trained_dram_clktree_c0d1u1;
u32 trained_dram_clktree_c1d0u0;
u32 trained_dram_clktree_c1d0u1;
u32 trained_dram_clktree_c1d1u0;
u32 trained_dram_clktree_c1d1u1;
u32 current_dram_clktree_c0d0u0;
u32 current_dram_clktree_c0d0u1;
u32 current_dram_clktree_c0d1u0;
u32 current_dram_clktree_c0d1u1;
u32 current_dram_clktree_c1d0u0;
u32 current_dram_clktree_c1d0u1;
u32 current_dram_clktree_c1d1u0;
u32 current_dram_clktree_c1d1u1;
u32 run_clocks;
u32 tree_margin;
u32 num_burst;
u32 num_burst_per_ch;
u32 num_trim;
u32 num_trim_per_ch;
u32 num_mc_regs;
u32 num_up_down;
u32 vref_num;
u32 training_mod_num;
u32 dram_timing_num;
ptfv_list_table_t ptfv_list;
burst_regs_t burst_regs;
burst_reg_per_ch_t burst_reg_per_ch;
burst_regs_t shadow_regs_ca_train;
burst_regs_t shadow_regs_quse_train;
burst_regs_t shadow_regs_rdwr_train;
trim_regs_t trim_regs;
trim_perch_regs_t trim_perch_regs;
vref_perch_regs_t vref_perch_regs;
dram_timings_t dram_timings;
u32 training_mod_regs[20];
u32 save_restore_mod_regs[12];
u32 burst_mc_regs[33];
u32 la_scale_regs[24];
u32 min_mrs_wait;
u32 emc_mrw;
u32 emc_mrw2;
u32 emc_mrw3;
u32 emc_mrw4;
u32 emc_mrw9;
u32 emc_mrs;
u32 emc_emrs;
u32 emc_emrs2;
u32 emc_auto_cal_config;
u32 emc_auto_cal_config2;
u32 emc_auto_cal_config3;
u32 emc_auto_cal_config4;
u32 emc_auto_cal_config5;
u32 emc_auto_cal_config6;
u32 emc_auto_cal_config7;
u32 emc_auto_cal_config8;
u32 emc_cfg_2;
u32 emc_sel_dpd_ctrl;
u32 emc_fdpd_ctrl_cmd_no_ramp;
u32 dll_clk_src;
u32 clk_out_enb_x_0_clk_enb_emc_dll;
u32 latency;
} emc_table_t;
#endif

View File

@ -43,6 +43,9 @@
#define MAX17050_VMAX_TOLERANCE 50 /* 50 mV */ #define MAX17050_VMAX_TOLERANCE 50 /* 50 mV */
#pragma GCC push_options
#pragma GCC optimize ("Os")
int max17050_get_property(enum MAX17050_reg reg, int *value) int max17050_get_property(enum MAX17050_reg reg, int *value)
{ {
u16 data; u16 data;
@ -264,3 +267,5 @@ int max17050_fix_configuration()
return 0; return 0;
} }
#pragma GCC pop_options

View File

@ -33,6 +33,9 @@ typedef struct _se_ll_t
vu32 size; vu32 size;
} se_ll_t; } se_ll_t;
static u32 _se_rsa_mod_sizes[TEGRA_SE_RSA_KEYSLOT_COUNT];
static u32 _se_rsa_exp_sizes[TEGRA_SE_RSA_KEYSLOT_COUNT];
static void _gf256_mul_x(void *block) static void _gf256_mul_x(void *block)
{ {
u8 *pdata = (u8 *)block; u8 *pdata = (u8 *)block;
@ -158,6 +161,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 & 0x7F) if (flags & 0x7F)

View File

@ -20,6 +20,9 @@
#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_aes_key_set(u32 ks, const void *key, u32 size); void se_aes_key_set(u32 ks, const void *key, u32 size);
void se_aes_key_read(u32 ks, void *key, u32 size); void se_aes_key_read(u32 ks, void *key, u32 size);

View File

@ -28,6 +28,7 @@
#include "t210.h" #include "t210.h"
#include "../gfx/di.h" #include "../gfx/di.h"
#include "../mem/mc.h" #include "../mem/mc.h"
#include "../mem/minerva.h"
#include "../mem/sdram.h" #include "../mem/sdram.h"
#include "../power/max77620.h" #include "../power/max77620.h"
#include "../power/max7762x.h" #include "../power/max7762x.h"
@ -309,6 +310,7 @@ void reconfig_hw_workaround(bool extra_reconfig, u32 magic)
// Flush and disable MMU. // Flush and disable MMU.
bpmp_mmu_disable(); bpmp_mmu_disable();
bpmp_clk_rate_set(BPMP_CLK_NORMAL); bpmp_clk_rate_set(BPMP_CLK_NORMAL);
minerva_change_freq(FREQ_204);
// 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.

266
source/storage/emummc.c Normal file
View File

@ -0,0 +1,266 @@
/*
* 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/>.
*/
#include <string.h>
#include <stdlib.h>
#include "emummc.h"
#include "sdmmc.h"
#include "../config/config.h"
#include "../config/ini.h"
#include "../gfx/gfx.h"
#include "../libs/fatfs/ff.h"
#include "../mem/heap.h"
#include "../utils/list.h"
#include "../utils/types.h"
extern sdmmc_t sd_sdmmc;
extern sdmmc_storage_t sd_storage;
extern FATFS sd_fs;
extern hekate_config h_cfg;
extern bool sd_mount();
extern void sd_unmount();
bool emummc_load_cfg()
{
sd_mount();
emu_cfg.enabled = 0;
emu_cfg.path = NULL;
emu_cfg.nintendo_path = NULL;
emu_cfg.sector = 0;
emu_cfg.id = 0;
emu_cfg.file_based_part_size = 0;
emu_cfg.active_part = 0;
emu_cfg.fs_ver = 0;
emu_cfg.emummc_file_based_path = (char *)malloc(0x80);
LIST_INIT(ini_sections);
if (ini_parse(&ini_sections, "emuMMC/emummc.ini", false))
{
LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_sections, link)
{
if (ini_sec->type == INI_CHOICE)
{
if (strcmp(ini_sec->name, "emummc"))
continue;
LIST_FOREACH_ENTRY(ini_kv_t, kv, &ini_sec->kvs, link)
{
if (!strcmp("enabled", kv->key))
emu_cfg.enabled = atoi(kv->val);
else if (!strcmp("sector", kv->key))
emu_cfg.sector = strtol(kv->val, NULL, 16);
else if (!strcmp("id", kv->key))
emu_cfg.id = strtol(kv->val, NULL, 16);
else if (!strcmp("path", kv->key))
emu_cfg.path = kv->val;
else if (!strcmp("nintendo_path", kv->key))
emu_cfg.nintendo_path = kv->val;
}
break;
}
}
return 0;
}
return 1;
}
static int emummc_raw_get_part_off(int part_idx)
{
switch (part_idx)
{
case 0:
return 2;
case 1:
return 0;
case 2:
return 1;
}
return 2;
}
int emummc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc)
{
FILINFO fno;
if (!sdmmc_storage_init_mmc(storage, sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4))
{
EPRINTF("Failed to init eMMC.");
goto out;
}
if (h_cfg.emummc_force_disable)
return 1;
emu_cfg.active_part = 0;
if (!sd_mount())
goto out;
if (emu_cfg.enabled && !emu_cfg.sector)
{
strcpy(emu_cfg.emummc_file_based_path, emu_cfg.path);
strcat(emu_cfg.emummc_file_based_path, "/eMMC");
if (f_stat(emu_cfg.emummc_file_based_path, &fno))
{
EPRINTF("Failed to open eMMC folder.");
goto out;
}
f_chmod(emu_cfg.emummc_file_based_path, AM_ARC, AM_ARC);
strcat(emu_cfg.emummc_file_based_path, "/00");
if (f_stat(emu_cfg.emummc_file_based_path, &fno))
{
EPRINTF("Failed to open emuMMC rawnand.");
goto out;
}
emu_cfg.file_based_part_size = fno.fsize >> 9;
}
return 1;
out:
return 0;
}
int emummc_storage_end(sdmmc_storage_t *storage)
{
sd_unmount();
sdmmc_storage_end(storage);
return 1;
}
int emummc_storage_read(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, void *buf)
{
FIL fp;
if (!emu_cfg.enabled || h_cfg.emummc_force_disable)
return sdmmc_storage_read(storage, sector, num_sectors, buf);
else if (emu_cfg.sector)
{
sector += emu_cfg.sector;
sector += emummc_raw_get_part_off(emu_cfg.active_part) * 0x2000;
return sdmmc_storage_read(&sd_storage, sector, num_sectors, buf);
}
else
{
if (!emu_cfg.active_part)
{
u32 file_part = sector / emu_cfg.file_based_part_size;
sector = sector % emu_cfg.file_based_part_size;
if (file_part >= 10)
itoa(file_part, emu_cfg.emummc_file_based_path + strlen(emu_cfg.emummc_file_based_path) - 2, 10);
else
{
emu_cfg.emummc_file_based_path[strlen(emu_cfg.emummc_file_based_path) - 2] = '0';
itoa(file_part, emu_cfg.emummc_file_based_path + strlen(emu_cfg.emummc_file_based_path) - 1, 10);
}
}
if (f_open(&fp, emu_cfg.emummc_file_based_path, FA_READ))
{
EPRINTF("Failed to open emuMMC image.");
return 0;
}
f_lseek(&fp, (u64)sector << 9);
if (f_read(&fp, buf, (u64)num_sectors << 9, NULL))
{
EPRINTF("Failed to read emuMMC image.");
f_close(&fp);
return 0;
}
f_close(&fp);
return 1;
}
return 1;
}
int emummc_storage_write(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, void *buf)
{
FIL fp;
if (!emu_cfg.enabled || h_cfg.emummc_force_disable)
return sdmmc_storage_write(storage, sector, num_sectors, buf);
else if (emu_cfg.sector)
{
sector += emu_cfg.sector;
sector += emummc_raw_get_part_off(emu_cfg.active_part) * 0x2000;
return sdmmc_storage_write(&sd_storage, sector, num_sectors, buf);
}
else
{
if (!emu_cfg.active_part)
{
u32 file_part = sector / emu_cfg.file_based_part_size;
sector = sector % emu_cfg.file_based_part_size;
if (file_part >= 10)
itoa(file_part, emu_cfg.emummc_file_based_path + strlen(emu_cfg.emummc_file_based_path) - 2, 10);
else
{
emu_cfg.emummc_file_based_path[strlen(emu_cfg.emummc_file_based_path) - 2] = '0';
itoa(file_part, emu_cfg.emummc_file_based_path + strlen(emu_cfg.emummc_file_based_path) - 1, 10);
}
}
if (f_open(&fp, emu_cfg.emummc_file_based_path, FA_WRITE))
{
gfx_printf("e5\n");
return 0;
}
f_lseek(&fp, (u64)sector << 9);
if (f_write(&fp, buf, (u64)num_sectors << 9, NULL))
{
gfx_printf("e6\n");
f_close(&fp);
return 0;
}
f_close(&fp);
return 1;
}
}
int emummc_storage_set_mmc_partition(sdmmc_storage_t *storage, u32 partition)
{
emu_cfg.active_part = partition;
if (!emu_cfg.enabled || h_cfg.emummc_force_disable)
sdmmc_storage_set_mmc_partition(storage, partition);
else if (emu_cfg.sector)
return 1;
else
{
strcpy(emu_cfg.emummc_file_based_path, emu_cfg.path);
strcat(emu_cfg.emummc_file_based_path, "/eMMC");
switch (partition)
{
case 0:
strcat(emu_cfg.emummc_file_based_path, "/00");
break;
case 1:
strcat(emu_cfg.emummc_file_based_path, "/BOOT0");
break;
case 2:
strcat(emu_cfg.emummc_file_based_path, "/BOOT1");
break;
}
return 1;
}
return 1;
}

59
source/storage/emummc.h Normal file
View File

@ -0,0 +1,59 @@
/*
* 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 EMUMMC_H
#define EMUMMC_H
#include "sdmmc.h"
#include "../utils/types.h"
typedef enum
{
EMUMMC_TYPE_NONE = 0,
EMUMMC_TYPE_PARTITION = 1,
EMUMMC_TYPE_FILES = 2,
} emummc_type_t;
typedef enum {
EMUMMC_MMC_NAND = 0,
EMUMMC_MMC_SD = 1,
EMUMMC_MMC_GC = 2,
} emummc_mmc_t;
typedef struct _emummc_cfg_t
{
int enabled;
u64 sector;
u16 id;
char *path;
char *nintendo_path;
// Internal.
char *emummc_file_based_path;
u32 file_based_part_size;
u32 active_part;
int fs_ver;
} emummc_cfg_t;
emummc_cfg_t emu_cfg;
bool emummc_load_cfg();
int emummc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc);
int emummc_storage_end(sdmmc_storage_t *storage);
int emummc_storage_read(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, void *buf);
int emummc_storage_write(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, void *buf);
int emummc_storage_set_mmc_partition(sdmmc_storage_t *storage, u32 partition);
#endif

View File

@ -17,6 +17,7 @@
#include <string.h> #include <string.h>
#include "nx_emmc.h" #include "nx_emmc.h"
#include "emummc.h"
#include "../mem/heap.h" #include "../mem/heap.h"
#include "../utils/list.h" #include "../utils/list.h"
@ -24,7 +25,7 @@ void nx_emmc_gpt_parse(link_t *gpt, sdmmc_storage_t *storage)
{ {
u8 *buf = (u8 *)malloc(NX_GPT_NUM_BLOCKS * NX_EMMC_BLOCKSIZE); u8 *buf = (u8 *)malloc(NX_GPT_NUM_BLOCKS * NX_EMMC_BLOCKSIZE);
sdmmc_storage_read(storage, NX_GPT_FIRST_LBA, NX_GPT_NUM_BLOCKS, buf); emummc_storage_read(storage, NX_GPT_FIRST_LBA, NX_GPT_NUM_BLOCKS, buf);
gpt_header_t *hdr = (gpt_header_t *)buf; gpt_header_t *hdr = (gpt_header_t *)buf;
for (u32 i = 0; i < hdr->num_part_ents; i++) for (u32 i = 0; i < hdr->num_part_ents; i++)
@ -65,7 +66,7 @@ int nx_emmc_part_read(sdmmc_storage_t *storage, emmc_part_t *part, u32 sector_of
// The last LBA is inclusive. // The last LBA is inclusive.
if (part->lba_start + sector_off > part->lba_end) if (part->lba_start + sector_off > part->lba_end)
return 0; return 0;
return sdmmc_storage_read(storage, part->lba_start + sector_off, num_sectors, buf); return emummc_storage_read(storage, part->lba_start + sector_off, num_sectors, buf);
} }
int nx_emmc_part_write(sdmmc_storage_t *storage, emmc_part_t *part, u32 sector_off, u32 num_sectors, void *buf) int nx_emmc_part_write(sdmmc_storage_t *storage, emmc_part_t *part, u32 sector_off, u32 num_sectors, void *buf)

View File

@ -32,6 +32,10 @@
//#define DPRINTF(...) gfx_printf(__VA_ARGS__) //#define DPRINTF(...) gfx_printf(__VA_ARGS__)
#define DPRINTF(...) #define DPRINTF(...)
#pragma GCC push_options
#pragma GCC target ("thumb")
#pragma GCC optimize ("Os")
/*! SCMMC controller base addresses. */ /*! SCMMC controller base addresses. */
static const u32 _sdmmc_bases[4] = { static const u32 _sdmmc_bases[4] = {
0x700B0000, 0x700B0000,
@ -1146,3 +1150,5 @@ int sdmmc_enable_low_voltage(sdmmc_t *sdmmc)
return 0; return 0;
} }
#pragma GCC pop_options

94
source/utils/dirlist.c Normal file
View File

@ -0,0 +1,94 @@
/*
* Copyright (c) 2018 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 <stdlib.h>
#include "../libs/fatfs/ff.h"
#include "../mem/heap.h"
#include "../utils/types.h"
char *dirlist(const char *directory, const char *pattern, bool includeHiddenFiles)
{
u8 max_entries = 61;
int res = 0;
u32 i = 0, j = 0, k = 0;
DIR dir;
FILINFO fno;
char *dir_entries = (char *)calloc(max_entries, 256);
char *temp = (char *)calloc(1, 256);
if (!pattern && !f_opendir(&dir, directory))
{
for (;;)
{
res = f_readdir(&dir, &fno);
if (res || !fno.fname[0])
break;
if (!(fno.fattrib & AM_DIR) && (fno.fname[0] != '.') && (includeHiddenFiles || !(fno.fattrib & AM_HID)))
{
memcpy(dir_entries + (k * 256), fno.fname, strlen(fno.fname) + 1);
k++;
if (k > (max_entries - 1))
break;
}
}
f_closedir(&dir);
}
else if (pattern && !f_findfirst(&dir, &fno, directory, pattern) && fno.fname[0])
{
do
{
if (!(fno.fattrib & AM_DIR) && (fno.fname[0] != '.') && (includeHiddenFiles || !(fno.fattrib & AM_HID)))
{
memcpy(dir_entries + (k * 256), fno.fname, strlen(fno.fname) + 1);
k++;
if (k > (max_entries - 1))
break;
}
res = f_findnext(&dir, &fno);
} while (fno.fname[0] && !res);
f_closedir(&dir);
}
if (!k)
{
free(temp);
free(dir_entries);
return NULL;
}
// Reorder ini files by ASCII ordering.
for (i = 0; i < k - 1 ; i++)
{
for (j = i + 1; j < k; j++)
{
if (strcmp(&dir_entries[i * 256], &dir_entries[j * 256]) > 0)
{
memcpy(temp, &dir_entries[i * 256], strlen(&dir_entries[i * 256]) + 1);
memcpy(&dir_entries[i * 256], &dir_entries[j * 256], strlen(&dir_entries[j * 256]) + 1);
memcpy(&dir_entries[j * 256], temp, strlen(temp) + 1);
}
}
}
free(temp);
return dir_entries;
}

19
source/utils/dirlist.h Normal file
View File

@ -0,0 +1,19 @@
/*
* Copyright (c) 2018 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 "../utils/types.h"
char *dirlist(const char *directory, const char *pattern, bool includeHiddenFiles);

View File

@ -68,6 +68,8 @@ typedef volatile unsigned char vu8;
typedef volatile unsigned short vu16; typedef volatile unsigned short vu16;
typedef volatile unsigned int vu32; typedef volatile unsigned int vu32;
static const u32 colors[6] = {COLOR_RED, COLOR_ORANGE, COLOR_YELLOW, COLOR_GREEN, COLOR_BLUE, COLOR_VIOLET};
typedef int bool; typedef int bool;
#define true 1 #define true 1
#define false 0 #define false 0
@ -76,6 +78,8 @@ typedef int bool;
#define BOOT_CFG_FROM_LAUNCH (1 << 1) #define BOOT_CFG_FROM_LAUNCH (1 << 1)
#define BOOT_CFG_SEPT_RUN (1 << 7) #define BOOT_CFG_SEPT_RUN (1 << 7)
#define EXTRA_CFG_DUMP_EMUMMC (1 << 0)
typedef struct __attribute__((__packed__)) _boot_cfg_t typedef struct __attribute__((__packed__)) _boot_cfg_t
{ {
u8 boot_cfg; u8 boot_cfg;

View File

@ -19,6 +19,7 @@
#define _UTIL_H_ #define _UTIL_H_
#include "types.h" #include "types.h"
#include "../mem/minerva.h"
#define byte_swap_32(num) (((num >> 24) & 0xff) | ((num << 8) & 0xff0000) | \ #define byte_swap_32(num) (((num >> 24) & 0xff) | ((num << 8) & 0xff0000) | \
((num >> 8 )& 0xff00) | ((num << 24) & 0xff000000)) ((num >> 8 )& 0xff00) | ((num << 24) & 0xff000000))
@ -29,6 +30,17 @@ typedef struct _cfg_op_t
u32 val; u32 val;
} cfg_op_t; } cfg_op_t;
typedef struct _nyx_storage_t
{
u32 version;
u32 cfg;
u8 irama[0x8000];
u8 hekate[0x30000];
u8 rsvd[0x800000];
mtc_config_t mtc_cfg;
emc_table_t mtc_table;
} nyx_storage_t;
u32 get_tmr_us(); u32 get_tmr_us();
u32 get_tmr_ms(); u32 get_tmr_ms();
u32 get_tmr_s(); u32 get_tmr_s();