32 Commits

Author SHA1 Message Date
e578e09ff9 v1.7.0: Titlekey save parsing, memory bugfixes 2019-10-28 09:56:38 -06:00
6ad7192199 Move key offsets to struct for cleaner code 2019-10-28 09:54:01 -06:00
1c82665901 Parse ES saves right, vastly improve titlekey time 2019-10-26 20:29:36 -06:00
1feb83f1dc heap: Fix calloc memset, end node max size on free 2019-10-25 22:01:23 -06:00
5d44ef0af6 se: Hardcode internal se vars, add HMAC-SHA256 2019-10-25 21:48:29 -06:00
5f100fef8a nx_emmc: Fix nested loop with same variable 2019-10-25 12:04:03 -06:00
a5bb071927 keys: Fix potential memory leak in _nca_process 2019-10-25 11:59:34 -06:00
dbc86a6699 keys: Ensure SD mount before writing key buffer 2019-10-25 11:57:59 -06:00
86f2a63fb7 keys: Fix failure to free decompressed kip1 2019-10-25 11:56:06 -06:00
535a2d97f2 keys: Validate storage init 2019-10-25 11:54:57 -06:00
d946ade94b kfuse: Fix missing include 2019-10-25 11:46:10 -06:00
472aa1665e sept: Prevent memory leak 2019-10-25 11:44:51 -06:00
2d4ffd2965 diskio: Alloc xts enc, don't realloc sector cache 2019-10-25 11:43:11 -06:00
b468026540 heap: Prevent node chain collapse on free 2019-10-25 11:41:30 -06:00
e5849e3ab2 Remove invalid free for this use case 2019-10-25 10:05:57 -06:00
28f4190076 Compile as Thumb to reduce binary size 2019-10-22 11:22:55 -06:00
76a13c85fa Remove "Os" pragmas, merge hekate changes 2019-10-22 11:22:26 -06:00
eee656bb34 Add missing file for KFuse fix 2019-10-22 11:18:05 -06:00
b5e932755a Remove wait for button press before reboot to Sept 2019-10-22 11:16:32 -06:00
3ea82573e0 Add wait for KFuse init to prevent wrong TSEC key 2019-10-22 11:15:59 -06:00
8c2aa76fd0 v1.6.4: Skip f_mkdir validation altogether 2019-10-21 11:06:39 -06:00
340a256518 Fix the f_mkdir fix 2019-10-15 11:14:14 -06:00
ee1a3e08ae Fix bad f_mkdir check skipping file save 2019-10-15 11:11:47 -06:00
d4fa066854 Bump version to v1.6.2 2019-10-15 10:26:42 -06:00
d890616c33 Fix function name typo 2019-10-15 10:25:20 -06:00
5d1386cc10 Validate more file I/O calls 2019-10-07 13:18:14 -06:00
0024f049b6 Add new FS keys for LibHac, ff.c -> thumb 2019-10-06 18:41:20 -06:00
3b6f356460 Update readme 2019-09-29 23:12:23 -06:00
21e8ca6204 Fixed key save buffer non-zero init error 2019-09-29 23:07:05 -06:00
9ceb56f743 Bump version to v1.6.0 2019-09-27 16:31:43 -06:00
d6105b95e1 Add key generation to menu and fix repeat dump bug 2019-09-27 16:30:44 -06:00
035134f36e Add titlekey dumping and Minerva 2019-09-25 12:18:08 -06:00
39 changed files with 4336 additions and 344 deletions

View File

@ -10,7 +10,7 @@ include $(DEVKITARM)/base_rules
IPL_LOAD_ADDR := 0x40003000
LPVERSION_MAJOR := 1
LPVERSION_MINOR := 5
LPVERSION_MINOR := 7
LPVERSION_BUGFX := 0
################################################################################
@ -29,7 +29,7 @@ OBJS = $(patsubst $(SOURCEDIR)/%.S, $(BUILDDIR)/$(TARGET)/%.o, \
CUSTOMDEFINES := -DIPL_LOAD_ADDR=$(IPL_LOAD_ADDR)
CUSTOMDEFINES += -DLP_VER_MJ=$(LPVERSION_MAJOR) -DLP_VER_MN=$(LPVERSION_MINOR) -DLP_VER_BF=$(LPVERSION_BUGFX)
ARCH := -march=armv4t -mtune=arm7tdmi -mthumb-interwork
ARCH := -march=armv4t -mtune=arm7tdmi -mthumb -mthumb-interwork
CFLAGS = $(ARCH) -O2 -nostdlib -ffunction-sections -fdata-sections -fomit-frame-pointer -std=gnu11 -Wall $(CUSTOMDEFINES)
LDFLAGS = $(ARCH) -nostartfiles -lgcc -Wl,--nmagic,--gc-sections -Xlinker --defsym=IPL_LOAD_ADDR=$(IPL_LOAD_ADDR)

View File

@ -6,8 +6,9 @@ Due to changes imposed by firmware 7.0.0, Lockpick homebrew can no longer derive
Usage
=
* Launch Lockpick_RCM.bin using your favorite payload injector
* Upon completion, keys will be saved to `/switch/prod.keys` on SD
* It is highly recommended, but not required, to place Minerva on SD from the latest [Hekate](https://github.com/CTCaer/hekate/releases) for best performance, especially while dumping titlekeys - the file and path is `/bootloader/sys/libsys_minerva.bso`
* Launch Lockpick_RCM.bin using your favorite payload injector or chainloader
* Upon completion, keys will be saved to `/switch/prod.keys` and titlekeys to `/switch/title.keys` on SD
* If the console has Firmware 7.x or higher, the `/sept/` folder from [Atmosphère](https://github.com/Atmosphere-NX/Atmosphere/releases) or [Kosmos](https://github.com/AtlasNX/Kosmos/releases) release zip must be present on SD or else only keyblob master key derivation is possible (ie. up to `master_key_05` only)
Building
@ -16,8 +17,4 @@ Install [devkitARM](https://devkitpro.org/) and run `make`.
Massive Thanks to CTCaer!
=
This software is heavily based on [Hekate](https://github.com/CTCaer/hekate). Beyond that, CTCaer was exceptionally helpful in the development of this project, lending loads of advice, expertise, and humor.
Known Issues
=
* Chainloading from SX will hang immediately due to quirks in their hwinit code, please launch payload directly
This software is heavily based on [Hekate](https://github.com/CTCaer/hekate). Beyond that, CTCaer was exceptionally helpful in the development of this project, lending loads of advice, expertise, and humor.

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);

View File

@ -147,13 +147,11 @@ void *tui_do_menu(menu_t *menu)
gfx_con_setcol(0xFF1B1B1B, 1, 0xFFCCCCCC);
else
gfx_con_setcol(0xFFCCCCCC, 1, 0xFF1B1B1B);
// if (menu->ents[cnt].type == MENT_CAPTION)
// gfx_printf("%k %s", menu->ents[cnt].color, menu->ents[cnt].caption);
if (menu->ents[cnt].type != MENT_CHGLINE) {
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);//gfx_printf(" %s", menu->ents[cnt].caption);
gfx_printf("%k %s", menu->ents[cnt].color, menu->ents[cnt].caption);
}
if(menu->ents[cnt].type == MENT_MENU)
gfx_printf("%k...", 0xFF0099EE);

View File

@ -22,20 +22,25 @@
#include "pkg1.h"
#include "../sec/se.h"
#define HASH_ORDER_100_100 {2, 3, 4, 0, 5, 6, 1}
#define HASH_ORDER_200_510 {2, 3, 4, 0, 5, 7, 10, 12, 11, 6, 8, 1}
#define HASH_ORDER_600_620 {6, 5, 10, 7, 8, 2, 3, 4, 0, 12, 11, 1}
#define HASH_ORDER_700_9xx {6, 5, 10, 7, 8, 2, 3, 4, 0, 12, 11, 9, 1}
static const pkg1_id_t _pkg1_ids[] = {
{ "20161121183008", 0 }, //1.0.0
{ "20170210155124", 0 }, //2.0.0 - 2.3.0
{ "20170519101410", 1 }, //3.0.0
{ "20170710161758", 2 }, //3.0.1 - 3.0.2
{ "20170921172629", 3 }, //4.0.0 - 4.1.0
{ "20180220163747", 4 }, //5.0.0 - 5.1.0
{ "20180802162753", 5 }, //6.0.0 - 6.1.0
{ "20181107105733", 6 }, //6.2.0
{ "20181218175730", 7 }, //7.0.0
{ "20190208150037", 7 }, //7.0.1
{ "20190314172056", 7 }, //8.0.0
{ "20190531152432", 8 }, //8.1.0
{ "20190809135709", 9 }, //9.0.0
{ "20161121183008", 0, {0x1b517, 0x125bc2, 1, 16, 6, HASH_ORDER_100_100, 0, 0x449dc} }, //1.0.0
{ "20170210155124", 0, {0x1d226, 0x26fe, 0, 16, 11, HASH_ORDER_200_510, 0x557b, 0x3d41a} }, //2.0.0 - 2.3.0
{ "20170519101410", 1, {0x1ffa6, 0x298b, 0, 16, 11, HASH_ORDER_200_510, 0x552d, 0x3cb81} }, //3.0.0
{ "20170710161758", 2, {0x20026, 0x29ab, 0, 16, 11, HASH_ORDER_200_510, 0x552d, 0x3cb81} }, //3.0.1 - 3.0.2
{ "20170921172629", 3, {0x1c64c, 0x37eb, 0, 16, 11, HASH_ORDER_200_510, 0x5382, 0x3711c} }, //4.0.0 - 4.1.0
{ "20180220163747", 4, {0x1f3b4, 0x465b, 0, 16, 11, HASH_ORDER_200_510, 0x5a63, 0x37901} }, //5.0.0 - 5.1.0
{ "20180802162753", 5, {0x27350, 0x17ff5, 1, 8, 11, HASH_ORDER_600_620, 0x5674, 0x1d5be} }, //6.0.0 - 6.1.0
{ "20181107105733", 6, {0x27350, 0x17ff5, 1, 8, 11, HASH_ORDER_600_620, 0x5674, 0x1d5be} }, //6.2.0
{ "20181218175730", 7, {0x29c50, 0x6a73, 0, 8, 12, HASH_ORDER_700_9xx, 0x5563, 0x1d437} }, //7.0.0
{ "20190208150037", 7, {0x29c50, 0x6a73, 0, 8, 12, HASH_ORDER_700_9xx, 0x5563, 0x1d437} }, //7.0.1
{ "20190314172056", 7, {0x29c50, 0x6a73, 0, 8, 12, HASH_ORDER_700_9xx, 0x5563, 0x1d437} }, //8.0.0 - 8.0.1
{ "20190531152432", 8, {0x29c50, 0x6a73, 0, 8, 12, HASH_ORDER_700_9xx, 0x5563, 0x1d437} }, //8.1.0
{ "20190809135709", 9, {0x2ec10, 0x5573, 0, 1, 12, HASH_ORDER_700_9xx, 0x6495, 0x1d807} }, //9.0.0 - 9.0.1
{ NULL } //End.
};

View File

@ -19,10 +19,23 @@
#include "../utils/types.h"
typedef struct _key_info_t
{
u32 start_offset;
u32 hks_offset;
bool hks_offset_is_from_end;
u32 alignment;
u32 hash_max;
u8 hash_order[13];
u32 es_offset;
u32 ssl_offset;
} key_info_t;
typedef struct _pkg1_id_t
{
const char *id;
u32 kb;
key_info_t key_info;
} pkg1_id_t;
const pkg1_id_t *pkg1_identify(u8 *pkg1);

View File

@ -139,7 +139,6 @@ int pkg2_decompress_kip(pkg2_kip1_info_t* ki, u32 sectsToDecomp)
memcpy(newKip, &hdr, sizeof(hdr));
newKipSize = dstDataPtr-(unsigned char*)(newKip);
free(ki->kip1);
ki->kip1 = newKip;
ki->size = newKipSize;

View File

@ -56,6 +56,7 @@ u8 warmboot_reboot[] = {
#define SEPT_STG2_ADDR (SEPT_PK1T_ADDR + 0x60E0)
#define SEPT_PKG_SZ (0x2F100 + WB_RST_SIZE)
extern u32 color_idx;
extern boot_cfg_t b_cfg;
extern void sd_unmount();
extern void reloc_patcher(u32 payload_dst, u32 payload_src, u32 payload_size);
@ -106,8 +107,10 @@ int reboot_to_sept(const u8 *tsec_fw, const u32 tsec_size, const u32 kb)
tmp_cfg->boot_cfg |= BOOT_CFG_SEPT_RUN;
if (f_open(&fp, "sd:/sept/payload.bin", FA_READ | FA_WRITE))
if (f_open(&fp, "sd:/sept/payload.bin", FA_READ | FA_WRITE)) {
free(tmp_cfg);
goto error;
}
f_lseek(&fp, PATCHED_RELOC_SZ);
f_write(&fp, tmp_cfg, sizeof(boot_cfg_t), NULL);
@ -115,8 +118,7 @@ int reboot_to_sept(const u8 *tsec_fw, const u32 tsec_size, const u32 kb)
f_close(&fp);
sd_unmount();
gfx_printf("\n%kPress Power or Vol +/-\n%k to Reboot to Sept...", COLOR_BLUE, COLOR_VIOLET);
btn_wait();
gfx_printf("\n%kPress Power or Vol +/-\n to Reboot to Sept...", colors[(color_idx++) % 6]);
u32 pk1t_sept = SEPT_PK1T_ADDR - (ALIGN(PATCHED_RELOC_SZ, 0x10) + WB_RST_SIZE);

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

@ -110,7 +110,7 @@ static const u8 bis_key_source[3][0x20] = {
0x4D, 0x12, 0xE1, 0x4B, 0x2A, 0x47, 0x4C, 0x1C, 0x09, 0xCB, 0x03, 0x59, 0xF0, 0x15, 0xF4, 0xE4}
};
static const u8 fs_hashes_sha256[10][0x20] = {
static const u8 fs_hashes_sha256[13][0x20] = {
{ // header_kek_source
0x18, 0x88, 0xca, 0xed, 0x55, 0x51, 0xb3, 0xed, 0xe0, 0x14, 0x99, 0xe8, 0x7c, 0xe0, 0xd8, 0x68,
0x27, 0xf8, 0x08, 0x20, 0xef, 0xb2, 0x75, 0x92, 0x10, 0x55, 0xaa, 0x4e, 0x2a, 0xbd, 0xff, 0xc2},
@ -132,6 +132,15 @@ static const u8 fs_hashes_sha256[10][0x20] = {
{ // save_mac_key_source
0xB4, 0x7B, 0x60, 0x0B, 0x1A, 0xD3, 0x14, 0xF9, 0x41, 0x14, 0x7D, 0x8B, 0x39, 0x1D, 0x4B, 0x19,
0x87, 0xCC, 0x8C, 0x88, 0x4A, 0xC8, 0x9F, 0xFC, 0x91, 0xCA, 0xE2, 0x21, 0xC5, 0x24, 0x51, 0xF7},
{ // save_mac_sd_card_kek_source
0x60, 0x1a, 0x60, 0xbe, 0x13, 0xf6, 0x3e, 0xda, 0xec, 0xcc, 0x96, 0x7f, 0x27, 0xa3, 0xa3, 0x64,
0x65, 0xcb, 0xe8, 0xf0, 0x29, 0xf0, 0xc4, 0x14, 0xb2, 0x36, 0x6a, 0x8b, 0x8a, 0x0f, 0x13, 0x00},
{ // save_mac_sd_card_key_source
0xc2, 0x22, 0x0a, 0x38, 0xb6, 0x87, 0x2b, 0x63, 0xee, 0x77, 0xac, 0x8c, 0x28, 0x24, 0x7a, 0x44,
0x02, 0xe6, 0xdd, 0x85, 0x24, 0x8b, 0x41, 0x9a, 0x6f, 0x9b, 0x17, 0x93, 0xc0, 0x50, 0x3f, 0x21},
{ // sd_card_custom_storage_key_source
0x6b, 0x8f, 0xd2, 0x6c, 0x76, 0x5b, 0x7c, 0x67, 0x70, 0x0c, 0x68, 0x54, 0x90, 0x8e, 0xbe, 0x88,
0x45, 0xb0, 0x55, 0xa6, 0xbb, 0xbb, 0xea, 0x0c, 0x06, 0x3a, 0x85, 0x04, 0x12, 0xd4, 0xca, 0x53},
{ // sd_card_kek_source
0x6B, 0x2E, 0xD8, 0x77, 0xC2, 0xC5, 0x23, 0x34, 0xAC, 0x51, 0xE5, 0x9A, 0xBF, 0xA7, 0xEC, 0x45,
0x7F, 0x4A, 0x7D, 0x01, 0xE4, 0x62, 0x91, 0xE9, 0xF2, 0xEA, 0xA4, 0x5F, 0x01, 0x1D, 0x24, 0xB7},

File diff suppressed because it is too large Load Diff

821
source/keys/save.c Normal file
View File

@ -0,0 +1,821 @@
#include <string.h>
#include "save.h"
#include "../gfx/gfx.h"
#include "../mem/heap.h"
#include "../sec/se.h"
#include "../utils/types.h"
#include "../utils/util.h"
#define REMAP_ENTRY_LENGTH 0x20
static inline void save_bitmap_set_bit(void *buffer, size_t bit_offset) {
*((uint8_t *)buffer + (bit_offset >> 3)) |= 1 << (bit_offset & 7);
}
static inline void save_bitmap_clear_bit(void *buffer, size_t bit_offset) {
*((uint8_t *)buffer + (bit_offset >> 3)) &= ~(uint8_t)(1 << (bit_offset & 7));
}
static inline uint8_t save_bitmap_check_bit(const void *buffer, size_t bit_offset) {
return *((uint8_t *)buffer + (bit_offset >> 3)) & (1 << (bit_offset & 7));
}
void save_duplex_storage_init(duplex_storage_ctx_t *ctx, duplex_fs_layer_info_t *layer, void *bitmap, uint64_t bitmap_size) {
ctx->data_a = layer->data_a;
ctx->data_b = layer->data_b;
ctx->bitmap_storage = (uint8_t *)bitmap;
ctx->block_size = 1 << layer->info.block_size_power;
ctx->bitmap.data = ctx->bitmap_storage;
ctx->bitmap.bitmap = malloc(bitmap_size >> 3);
uint32_t bits_remaining = bitmap_size;
uint32_t bitmap_pos = 0;
uint32_t *buffer_pos = (uint32_t *)bitmap;
while (bits_remaining) {
uint32_t bits_to_read = bits_remaining < 32 ? bits_remaining : 32;
uint32_t val = *buffer_pos;
for (uint32_t i = 0; i < bits_to_read; i++) {
if (val & 0x80000000)
save_bitmap_set_bit(ctx->bitmap.bitmap, bitmap_pos);
else
save_bitmap_clear_bit(ctx->bitmap.bitmap, bitmap_pos);
bitmap_pos++;
bits_remaining--;
val <<= 1;
}
buffer_pos++;
}
}
uint32_t save_duplex_storage_read(duplex_storage_ctx_t *ctx, void *buffer, uint64_t offset, size_t count) {
uint64_t in_pos = offset;
uint32_t out_pos = 0;
uint32_t remaining = count;
while (remaining) {
uint32_t block_num = (uint32_t)(in_pos / ctx->block_size);
uint32_t block_pos = (uint32_t)(in_pos % ctx->block_size);
uint32_t bytes_to_read = ctx->block_size - block_pos < remaining ? ctx->block_size - block_pos : remaining;
uint8_t *data = save_bitmap_check_bit(ctx->bitmap.bitmap, block_num) ? ctx->data_b : ctx->data_a;
memcpy((uint8_t *)buffer + out_pos, data + in_pos, bytes_to_read);
out_pos += bytes_to_read;
in_pos += bytes_to_read;
remaining -= bytes_to_read;
}
return out_pos;
}
remap_segment_ctx_t *save_remap_init_segments(remap_header_t *header, remap_entry_ctx_t *map_entries, uint32_t num_map_entries) {
remap_segment_ctx_t *segments = malloc(sizeof(remap_segment_ctx_t) * header->map_segment_count);
unsigned int entry_idx = 0;
for (unsigned int i = 0; i < header->map_segment_count; i++) {
remap_segment_ctx_t *seg = &segments[i];
seg->entries = malloc(sizeof(remap_entry_ctx_t));
memcpy(seg->entries, &map_entries[entry_idx], sizeof(remap_entry_ctx_t));
seg->offset = map_entries[entry_idx].virtual_offset;
map_entries[entry_idx].segment = seg;
seg->entry_count = 1;
entry_idx++;
while (entry_idx < num_map_entries && map_entries[entry_idx - 1].virtual_offset_end == map_entries[entry_idx].virtual_offset) {
map_entries[entry_idx].segment = seg;
map_entries[entry_idx - 1].next = &map_entries[entry_idx];
seg->entries = malloc(sizeof(remap_entry_ctx_t));
memcpy(seg->entries, &map_entries[entry_idx], sizeof(remap_entry_ctx_t));
seg->entry_count++;
entry_idx++;
}
seg->length = seg->entries[seg->entry_count - 1].virtual_offset_end - seg->entries[0].virtual_offset;
}
return segments;
}
remap_entry_ctx_t *save_remap_get_map_entry(remap_storage_ctx_t *ctx, uint64_t offset) {
uint32_t segment_idx = (uint32_t)(offset >> (64 - ctx->header->segment_bits));
if (segment_idx < ctx->header->map_segment_count) {
for (unsigned int i = 0; i < ctx->segments[segment_idx].entry_count; i++)
if (ctx->segments[segment_idx].entries[i].virtual_offset_end > offset)
return &ctx->segments[segment_idx].entries[i];
}
return NULL;
}
uint32_t save_remap_read(remap_storage_ctx_t *ctx, void *buffer, uint64_t offset, size_t count) {
remap_entry_ctx_t *entry = save_remap_get_map_entry(ctx, offset);
uint64_t in_pos = offset;
uint32_t out_pos = 0;
uint32_t remaining = count;
while (remaining) {
uint64_t entry_pos = in_pos - entry->virtual_offset;
uint32_t bytes_to_read = entry->virtual_offset_end - in_pos < remaining ? (uint32_t)(entry->virtual_offset_end - in_pos) : remaining;
switch (ctx->type) {
case STORAGE_BYTES:
f_lseek(ctx->file, ctx->base_storage_offset + entry->physical_offset + entry_pos);
f_read(ctx->file, (uint8_t *)buffer + out_pos, bytes_to_read, NULL);
break;
case STORAGE_DUPLEX:
save_duplex_storage_read(ctx->duplex, (uint8_t *)buffer + out_pos, ctx->base_storage_offset + entry->physical_offset + entry_pos, bytes_to_read);
break;
default:
break;
}
out_pos += bytes_to_read;
in_pos += bytes_to_read;
remaining -= bytes_to_read;
if (in_pos >= entry->virtual_offset_end)
entry = entry->next;
}
return out_pos;
}
uint32_t save_journal_storage_read(journal_storage_ctx_t *ctx, remap_storage_ctx_t *remap, void *buffer, uint64_t offset, size_t count) {
uint64_t in_pos = offset;
uint32_t out_pos = 0;
uint32_t remaining = count;
while (remaining) {
uint32_t block_num = (uint32_t)(in_pos / ctx->block_size);
uint32_t block_pos = (uint32_t)(in_pos % ctx->block_size);
uint64_t physical_offset = ctx->map.entries[block_num].physical_index * ctx->block_size + block_pos;
uint32_t bytes_to_read = ctx->block_size - block_pos < remaining ? ctx->block_size - block_pos : remaining;
save_remap_read(remap, (uint8_t *)buffer + out_pos, ctx->journal_data_offset + physical_offset, bytes_to_read);
out_pos += bytes_to_read;
in_pos += bytes_to_read;
remaining -= bytes_to_read;
}
return out_pos;
}
void save_ivfc_storage_init(hierarchical_integrity_verification_storage_ctx_t *ctx, uint64_t master_hash_offset, ivfc_save_hdr_t *ivfc) {
ivfc_level_save_ctx_t *levels = ctx->levels;
levels[0].type = STORAGE_BYTES;
levels[0].hash_offset = master_hash_offset;
for (unsigned int i = 1; i < 4; i++) {
ivfc_level_hdr_t *level = &ivfc->level_headers[i - 1];
levels[i].type = STORAGE_REMAP;
levels[i].data_offset = level->logical_offset;
levels[i].data_size = level->hash_data_size;
}
if (ivfc->num_levels == 5) {
ivfc_level_hdr_t *data_level = &ivfc->level_headers[ivfc->num_levels - 2];
levels[ivfc->num_levels - 1].type = STORAGE_JOURNAL;
levels[ivfc->num_levels - 1].data_offset = data_level->logical_offset;
levels[ivfc->num_levels - 1].data_size = data_level->hash_data_size;
}
struct salt_source_t {
char string[50];
uint32_t length;
};
static struct salt_source_t salt_sources[6] = {
{"HierarchicalIntegrityVerificationStorage::Master", 48},
{"HierarchicalIntegrityVerificationStorage::L1", 44},
{"HierarchicalIntegrityVerificationStorage::L2", 44},
{"HierarchicalIntegrityVerificationStorage::L3", 44},
{"HierarchicalIntegrityVerificationStorage::L4", 44},
{"HierarchicalIntegrityVerificationStorage::L5", 44}
};
integrity_verification_info_ctx_t init_info[ivfc->num_levels];
init_info[0].data = &levels[0];
init_info[0].block_size = 0;
for (unsigned int i = 1; i < ivfc->num_levels; i++) {
init_info[i].data = &levels[i];
init_info[i].block_size = 1 << ivfc->level_headers[i - 1].block_size;
se_calc_hmac_sha256(init_info[i].salt, ivfc->salt_source, 0x20, salt_sources[i - 1].string, salt_sources[i - 1].length);
}
ctx->integrity_storages[0].next_level = NULL;
ctx->level_validities = malloc(sizeof(validity_t *) * (ivfc->num_levels - 1));
for (unsigned int i = 1; i < ivfc->num_levels; i++) {
integrity_verification_storage_ctx_t *level_data = &ctx->integrity_storages[i - 1];
level_data->hash_storage = &levels[i - 1];
level_data->base_storage = &levels[i];
level_data->sector_size = init_info[i].block_size;
level_data->_length = init_info[i].data->data_size;
level_data->sector_count = (level_data->_length + level_data->sector_size - 1) / level_data->sector_size;
memcpy(level_data->salt, init_info[i].salt, 0x20);
level_data->block_validities = calloc(1, sizeof(validity_t) * level_data->sector_count);
ctx->level_validities[i - 1] = level_data->block_validities;
if (i > 1) {
level_data->next_level = &ctx->integrity_storages[i - 2];
}
}
ctx->data_level = &levels[ivfc->num_levels - 1];
ctx->_length = ctx->integrity_storages[ivfc->num_levels - 2]._length;
}
size_t save_ivfc_level_fread(ivfc_level_save_ctx_t *ctx, void *buffer, uint64_t offset, size_t count) {
switch (ctx->type) {
case STORAGE_BYTES:
f_lseek(ctx->save_ctx->file, ctx->hash_offset + offset);
UINT br = 0;
f_read(ctx->save_ctx->file, buffer, count, &br);
return br;
case STORAGE_REMAP:
save_remap_read(&ctx->save_ctx->meta_remap_storage, buffer, ctx->data_offset + offset, count);
return count;
case STORAGE_JOURNAL:
save_journal_storage_read(&ctx->save_ctx->journal_storage, &ctx->save_ctx->data_remap_storage, buffer, ctx->data_offset + offset, count);
return count;
default:
return 0;
}
}
void save_ivfc_storage_read(integrity_verification_storage_ctx_t *ctx, void *buffer, uint64_t offset, size_t count, uint32_t verify) {
if (count > ctx->sector_size) {
EPRINTF("IVFC read exceeds sector size!\n");
}
uint64_t block_index = offset / ctx->sector_size;
if (ctx->block_validities[block_index] == VALIDITY_INVALID && verify) {
EPRINTFARGS("Hash error from previous check\n found at offset %x count %x!\n", (u32)offset, count);
}
uint8_t hash_buffer[0x20] = {0};
uint8_t zeroes[0x20] = {0};
uint64_t hash_pos = block_index * 0x20;
if (ctx->next_level) {
save_ivfc_storage_read(ctx->next_level, hash_buffer, hash_pos, 0x20, verify);
} else {
save_ivfc_level_fread(ctx->hash_storage, hash_buffer, hash_pos, 0x20);
}
if (!memcmp(hash_buffer, zeroes, 0x20)) {
memset(buffer, 0, count);
ctx->block_validities[block_index] = VALIDITY_VALID;
return;
}
save_ivfc_level_fread(ctx->base_storage, buffer, offset, count);
if (!(verify && ctx->block_validities[block_index] == VALIDITY_UNCHECKED)) {
return;
}
uint8_t hash[0x20] = {0};
uint8_t *data_buffer = calloc(1, ctx->sector_size + 0x20);
memcpy(data_buffer, ctx->salt, 0x20);
memcpy(data_buffer + 0x20, buffer, count);
se_calc_sha256(hash, data_buffer, ctx->sector_size + 0x20);
hash[0x1F] |= 0x80;
free(data_buffer);
if (memcmp(hash_buffer, hash, 0x20)) {
ctx->block_validities[block_index] = VALIDITY_INVALID;
} else {
ctx->block_validities[block_index] = VALIDITY_VALID;
}
if (ctx->block_validities[block_index] == VALIDITY_INVALID && verify) {
EPRINTFARGS("Hash error from current check\n found at offset %x count %x!\n", (u32)offset, count);
}
}
uint32_t save_allocation_table_read_entry_with_length(allocation_table_ctx_t *ctx, allocation_table_entry_t *entry) {
uint32_t length = 1;
uint32_t entry_index = allocation_table_block_to_entry_index(entry->next);
allocation_table_entry_t *entries = (allocation_table_entry_t *)((uint8_t *)(ctx->base_storage) + entry_index * SAVE_FAT_ENTRY_SIZE);
if ((entries[0].next & 0x80000000) == 0) {
if (entries[0].prev & 0x80000000 && entries[0].prev != 0x80000000) {
EPRINTF("Invalid range entry in allocation table!\n");
}
} else {
length = entries[1].next - entry_index + 1;
}
if (allocation_table_is_list_end(&entries[0])) {
entry->next = 0xFFFFFFFF;
} else {
entry->next = allocation_table_entry_index_to_block(allocation_table_get_next(&entries[0]));
}
if (allocation_table_is_list_start(&entries[0])) {
entry->prev = 0xFFFFFFFF;
} else {
entry->prev = allocation_table_entry_index_to_block(allocation_table_get_prev(&entries[0]));
}
return length;
}
uint32_t save_allocation_table_get_list_length(allocation_table_ctx_t *ctx, uint32_t block_index) {
allocation_table_entry_t entry;
entry.next = block_index;
uint32_t total_length = 0;
uint32_t table_size = ctx->header->allocation_table_block_count;
uint32_t nodes_iterated = 0;
while (entry.next != 0xFFFFFFFF) {
total_length += save_allocation_table_read_entry_with_length(ctx, &entry);
nodes_iterated++;
if (nodes_iterated > table_size) {
EPRINTF("Cycle detected in allocation table!\n");
return 0;
}
}
return total_length;
}
uint64_t save_allocation_table_get_free_space_size(save_filesystem_ctx_t *ctx) {
uint32_t free_list_start = save_allocation_table_get_free_list_block_index(&ctx->allocation_table);
if (free_list_start == 0xFFFFFFFF) return 0;
return ctx->header->block_size * save_allocation_table_get_list_length(&ctx->allocation_table, free_list_start);
}
void save_allocation_table_iterator_begin(allocation_table_iterator_ctx_t *ctx, allocation_table_ctx_t *table, uint32_t initial_block) {
ctx->fat = table;
ctx->physical_block = initial_block;
ctx->virtual_block = 0;
allocation_table_entry_t entry;
entry.next = initial_block;
ctx->current_segment_size = save_allocation_table_read_entry_with_length(ctx->fat, &entry);
ctx->next_block = entry.next;
ctx->prev_block = entry.prev;
if (ctx->prev_block != 0xFFFFFFFF) {
EPRINTFARGS("Attempted to start FAT iteration from\n invalid block %x!\n", initial_block);
}
}
int save_allocation_table_iterator_move_next(allocation_table_iterator_ctx_t *ctx) {
if (ctx->next_block == 0xFFFFFFFF) return 0;
ctx->virtual_block += ctx->current_segment_size;
ctx->physical_block = ctx->next_block;
allocation_table_entry_t entry;
entry.next = ctx->next_block;
ctx->current_segment_size = save_allocation_table_read_entry_with_length(ctx->fat, &entry);
ctx->next_block = entry.next;
ctx->prev_block = entry.prev;
return 1;
}
int save_allocation_table_iterator_move_prev(allocation_table_iterator_ctx_t *ctx) {
if (ctx->prev_block == 0xFFFFFFFF) return 0;
ctx->physical_block = ctx->prev_block;
allocation_table_entry_t entry;
entry.next = ctx->prev_block;
ctx->current_segment_size = save_allocation_table_read_entry_with_length(ctx->fat, &entry);
ctx->next_block = entry.next;
ctx->prev_block = entry.prev;
ctx->virtual_block -= ctx->current_segment_size;
return 1;
}
int save_allocation_table_iterator_seek(allocation_table_iterator_ctx_t *ctx, uint32_t block) {
while (1) {
if (block < ctx->virtual_block) {
if (!save_allocation_table_iterator_move_prev(ctx)) return 0;
} else if (block >= ctx->virtual_block + ctx->current_segment_size) {
if (!save_allocation_table_iterator_move_next(ctx)) return 0;
} else {
return 1;
}
}
}
uint32_t save_allocation_table_storage_read(allocation_table_storage_ctx_t *ctx, void *buffer, uint64_t offset, size_t count) {
allocation_table_iterator_ctx_t iterator;
save_allocation_table_iterator_begin(&iterator, ctx->fat, ctx->initial_block);
uint64_t in_pos = offset;
uint32_t out_pos = 0;
uint32_t remaining = count;
while (remaining) {
uint32_t block_num = (uint32_t)(in_pos / ctx->block_size);
save_allocation_table_iterator_seek(&iterator, block_num);
uint32_t segment_pos = (uint32_t)(in_pos - (uint64_t)iterator.virtual_block * ctx->block_size);
uint64_t physical_offset = iterator.physical_block * ctx->block_size + segment_pos;
uint32_t remaining_in_segment = iterator.current_segment_size * ctx->block_size - segment_pos;
uint32_t bytes_to_read = remaining < remaining_in_segment ? remaining : remaining_in_segment;
uint32_t sector_size = ctx->base_storage->integrity_storages[3].sector_size;
uint32_t chunk_remaining = bytes_to_read;
for (unsigned int i = 0; i < bytes_to_read; i += sector_size) {
uint32_t bytes_to_request = chunk_remaining < sector_size ? chunk_remaining : sector_size;
save_ivfc_storage_read(&ctx->base_storage->integrity_storages[3], (uint8_t *)buffer + out_pos + i, physical_offset + i, bytes_to_request, ctx->base_storage->data_level->save_ctx->tool_ctx.action & ACTION_VERIFY);
chunk_remaining -= bytes_to_request;
}
out_pos += bytes_to_read;
in_pos += bytes_to_read;
remaining -= bytes_to_read;
}
return out_pos;
}
uint32_t save_fs_list_get_capacity(save_filesystem_list_ctx_t *ctx) {
if (!ctx->capacity)
save_allocation_table_storage_read(&ctx->storage, &ctx->capacity, 4, 4);
return ctx->capacity;
}
uint32_t save_fs_list_read_entry(save_filesystem_list_ctx_t *ctx, uint32_t index, save_fs_list_entry_t *entry) {
return save_allocation_table_storage_read(&ctx->storage, entry, index * SAVE_FS_LIST_ENTRY_SIZE, SAVE_FS_LIST_ENTRY_SIZE);
}
int save_fs_list_get_value(save_filesystem_list_ctx_t *ctx, uint32_t index, save_fs_list_entry_t *value) {
if (index >= save_fs_list_get_capacity(ctx)) {
return 0;
}
save_fs_list_read_entry(ctx, index, value);
return 1;
}
uint32_t save_fs_get_index_from_key(save_filesystem_list_ctx_t *ctx, save_entry_key_t *key, uint32_t *prev_index) {
save_fs_list_entry_t entry;
uint32_t capacity = save_fs_list_get_capacity(ctx);
save_fs_list_read_entry(ctx, ctx->used_list_head_index, &entry);
uint32_t prev;
if (!prev_index) {
prev_index = &prev;
}
*prev_index = ctx->used_list_head_index;
uint32_t index = entry.next;
while (index) {
if (index > capacity) {
EPRINTFARGS("Save entry index %d out of range!", index);
}
save_fs_list_read_entry(ctx, index, &entry);
if (entry.parent == key->parent && !strcmp(entry.name, key->name)) {
return index;
}
*prev_index = index;
index = entry.next;
}
*prev_index = 0xFFFFFFFF;
return 0xFFFFFFFF;
}
int save_hierarchical_file_table_find_path_recursive(hierarchical_save_file_table_ctx_t *ctx, save_entry_key_t *key, char *path) {
key->parent = 0;
char *pos = strchr(path, '/');
while (pos) {
memset(key->name, 0, SAVE_FS_LIST_MAX_NAME_LENGTH);
char *tmp = strchr(pos, '/');
if (!tmp) {
memcpy(key->name, pos, strlen(pos));
break;
}
memcpy(key->name, pos, tmp - pos);
key->parent = save_fs_get_index_from_key(&ctx->directory_table, key, NULL);
if (key->parent == 0xFFFFFFFF)
return 0;
pos = tmp + 1;
}
return 1;
}
int save_hierarchical_file_table_find_next_file(hierarchical_save_file_table_ctx_t *ctx, save_find_position_t *position, save_file_info_t *info, char *name) {
if (position->next_file == 0) {
return 0;
}
save_fs_list_entry_t entry;
if(!save_fs_list_get_value(&ctx->file_table, position->next_file, &entry)) {
return 0;
}
position->next_file = entry.value.next_sibling;
memcpy(name, &entry.name, SAVE_FS_LIST_MAX_NAME_LENGTH);
memcpy(info, &entry.value.save_file_info, sizeof(save_file_info_t));
return 1;
}
int save_hierarchical_file_table_find_next_directory(hierarchical_save_file_table_ctx_t *ctx, save_find_position_t *position, char *name) {
if (position->next_directory == 0) {
return 0;
}
save_fs_list_entry_t entry;
if(!save_fs_list_get_value(&ctx->directory_table, position->next_directory, &entry)) {
return 0;
}
position->next_directory = entry.value.next_sibling;
memcpy(name, &entry.name, SAVE_FS_LIST_MAX_NAME_LENGTH);
return 1;
}
int save_hierarchical_file_table_get_file_entry_by_path(hierarchical_save_file_table_ctx_t *ctx, char *path, save_fs_list_entry_t *entry) {
save_entry_key_t key;
if (!save_hierarchical_file_table_find_path_recursive(ctx, &key, path)) {
EPRINTF("Unable to locate file.");
return 0;
}
u32 index = save_fs_get_index_from_key(&ctx->file_table, &key, NULL);
if (index == 0xFFFFFFFF) {
EPRINTF("Unable to get table index for file.");
return 0;
}
if (!save_fs_list_get_value(&ctx->file_table, index, entry)) {
EPRINTF("Unable to get file entry from index.");
return 0;
}
return 1;
}
void save_open_fat_storage(save_filesystem_ctx_t *ctx, allocation_table_storage_ctx_t *storage_ctx, uint32_t block_index) {
storage_ctx->base_storage = ctx->base_storage;
storage_ctx->fat = &ctx->allocation_table;
storage_ctx->block_size = (uint32_t)ctx->header->block_size;
storage_ctx->initial_block = block_index;
storage_ctx->_length = block_index == 0xFFFFFFFF ? 0 : save_allocation_table_get_list_length(storage_ctx->fat, block_index) * storage_ctx->block_size;
}
void save_filesystem_init(save_filesystem_ctx_t *ctx, void *fat, save_fs_header_t *save_fs_header, fat_header_t *fat_header) {
ctx->allocation_table.base_storage = fat;
ctx->allocation_table.header = fat_header;
ctx->allocation_table.free_list_entry_index = 0;
ctx->header = save_fs_header;
save_open_fat_storage(ctx, &ctx->file_table.directory_table.storage, fat_header->directory_table_block);
save_open_fat_storage(ctx, &ctx->file_table.file_table.storage, fat_header->file_table_block);
ctx->file_table.file_table.free_list_head_index = 0;
ctx->file_table.file_table.used_list_head_index = 1;
ctx->file_table.directory_table.free_list_head_index = 0;
ctx->file_table.directory_table.used_list_head_index = 1;
}
validity_t save_ivfc_validate(hierarchical_integrity_verification_storage_ctx_t *ctx, ivfc_save_hdr_t *ivfc) {
validity_t result = VALIDITY_VALID;
for (unsigned int i = 0; i < ivfc->num_levels - 1 && result != VALIDITY_INVALID; i++) {
integrity_verification_storage_ctx_t *storage = &ctx->integrity_storages[i];
uint64_t block_size = storage->sector_size;
uint32_t block_count = (uint32_t)((storage->_length + block_size - 1) / block_size);
uint8_t *buffer = malloc(block_size);
for (unsigned int j = 0; j < block_count; j++) {
if (ctx->level_validities[ivfc->num_levels - 2][j] == VALIDITY_UNCHECKED) {
uint32_t to_read = storage->_length - block_size * j < block_size ? storage->_length - block_size * j : block_size;
save_ivfc_storage_read(storage, buffer, block_size * j, to_read, 1);
}
if (ctx->level_validities[ivfc->num_levels - 2][j] == VALIDITY_INVALID) {
result = VALIDITY_INVALID;
break;
}
}
free(buffer);
}
return result;
}
void save_ivfc_set_level_validities(hierarchical_integrity_verification_storage_ctx_t *ctx, ivfc_save_hdr_t *ivfc) {
for (unsigned int i = 0; i < ivfc->num_levels - 1; i++) {
validity_t level_validity = VALIDITY_VALID;
for (unsigned int j = 0; j < ctx->integrity_storages[i].sector_count; j++) {
if (ctx->level_validities[i][j] == VALIDITY_INVALID) {
level_validity = VALIDITY_INVALID;
break;
}
if (ctx->level_validities[i][j] == VALIDITY_UNCHECKED && level_validity != VALIDITY_INVALID) {
level_validity = VALIDITY_UNCHECKED;
}
}
ctx->levels[i].hash_validity = level_validity;
}
}
validity_t save_filesystem_verify(save_ctx_t *ctx) {
validity_t journal_validity = save_ivfc_validate(&ctx->core_data_ivfc_storage, &ctx->header.data_ivfc_header);
save_ivfc_set_level_validities(&ctx->core_data_ivfc_storage, &ctx->header.data_ivfc_header);
if (!ctx->fat_ivfc_storage.levels[0].save_ctx) return journal_validity;
validity_t fat_validity = save_ivfc_validate(&ctx->fat_ivfc_storage, &ctx->header.fat_ivfc_header);
save_ivfc_set_level_validities(&ctx->fat_ivfc_storage, &ctx->header.fat_ivfc_header);
if (journal_validity != VALIDITY_VALID) return journal_validity;
if (fat_validity != VALIDITY_VALID) return fat_validity;
return journal_validity;
}
void save_process(save_ctx_t *ctx) {
/* Try to parse Header A. */
f_lseek(ctx->file, 0);
if (f_read(ctx->file, &ctx->header, sizeof(ctx->header), NULL)) {
EPRINTF("Failed to read save header!\n");
}
save_process_header(ctx);
if (ctx->header_hash_validity == VALIDITY_INVALID) {
/* Try to parse Header B. */
f_lseek(ctx->file, 0x4000);
if (f_read(ctx->file, &ctx->header, sizeof(ctx->header), NULL)) {
EPRINTF("Failed to read save header!\n");
}
save_process_header(ctx);
if (ctx->header_hash_validity == VALIDITY_INVALID) {
EPRINTF("Error: Save header is invalid!\n");
}
}
unsigned char cmac[0x10];
memset(cmac, 0, 0x10);
se_aes_key_set(3, ctx->save_mac_key, 0x10);
se_aes_cmac(3, cmac, 0x10, &ctx->header.layout, sizeof(ctx->header.layout));
if (memcmp(cmac, &ctx->header.cmac, 0x10) == 0) {
ctx->header_cmac_validity = VALIDITY_VALID;
} else {
ctx->header_cmac_validity = VALIDITY_INVALID;
}
/* Initialize remap storages. */
ctx->data_remap_storage.type = STORAGE_BYTES;
ctx->data_remap_storage.base_storage_offset = ctx->header.layout.file_map_data_offset;
ctx->data_remap_storage.header = &ctx->header.main_remap_header;
ctx->data_remap_storage.map_entries = malloc(sizeof(remap_entry_ctx_t) * ctx->data_remap_storage.header->map_entry_count);
ctx->data_remap_storage.file = ctx->file;
f_lseek(ctx->file, ctx->header.layout.file_map_entry_offset);
for (unsigned int i = 0; i < ctx->data_remap_storage.header->map_entry_count; i++) {
f_read(ctx->file, &ctx->data_remap_storage.map_entries[i], 0x20, NULL);
ctx->data_remap_storage.map_entries[i].physical_offset_end = ctx->data_remap_storage.map_entries[i].physical_offset + ctx->data_remap_storage.map_entries[i].size;
ctx->data_remap_storage.map_entries[i].virtual_offset_end = ctx->data_remap_storage.map_entries[i].virtual_offset + ctx->data_remap_storage.map_entries[i].size;
}
/* Initialize data remap storage. */
ctx->data_remap_storage.segments = save_remap_init_segments(ctx->data_remap_storage.header, ctx->data_remap_storage.map_entries, ctx->data_remap_storage.header->map_entry_count);
/* Initialize duplex storage. */
ctx->duplex_layers[0].data_a = (uint8_t *)&ctx->header + ctx->header.layout.duplex_master_offset_a;
ctx->duplex_layers[0].data_b = (uint8_t *)&ctx->header + ctx->header.layout.duplex_master_offset_b;
memcpy(&ctx->duplex_layers[0].info, &ctx->header.duplex_header.layers[0], sizeof(duplex_info_t));
ctx->duplex_layers[1].data_a = malloc(ctx->header.layout.duplex_l1_size);
save_remap_read(&ctx->data_remap_storage, ctx->duplex_layers[1].data_a, ctx->header.layout.duplex_l1_offset_a, ctx->header.layout.duplex_l1_size);
ctx->duplex_layers[1].data_b = malloc(ctx->header.layout.duplex_l1_size);
save_remap_read(&ctx->data_remap_storage, ctx->duplex_layers[1].data_b, ctx->header.layout.duplex_l1_offset_b, ctx->header.layout.duplex_l1_size);
memcpy(&ctx->duplex_layers[1].info, &ctx->header.duplex_header.layers[1], sizeof(duplex_info_t));
ctx->duplex_layers[2].data_a = malloc(ctx->header.layout.duplex_data_size);
save_remap_read(&ctx->data_remap_storage, ctx->duplex_layers[2].data_a, ctx->header.layout.duplex_data_offset_a, ctx->header.layout.duplex_data_size);
ctx->duplex_layers[2].data_b = malloc(ctx->header.layout.duplex_data_size);
save_remap_read(&ctx->data_remap_storage, ctx->duplex_layers[2].data_b, ctx->header.layout.duplex_data_offset_b, ctx->header.layout.duplex_data_size);
memcpy(&ctx->duplex_layers[2].info, &ctx->header.duplex_header.layers[2], sizeof(duplex_info_t));
/* Initialize hierarchical duplex storage. */
uint8_t *bitmap = ctx->header.layout.duplex_index == 1 ? ctx->duplex_layers[0].data_b : ctx->duplex_layers[0].data_a;
save_duplex_storage_init(&ctx->duplex_storage.layers[0], &ctx->duplex_layers[1], bitmap, ctx->header.layout.duplex_master_size);
ctx->duplex_storage.layers[0]._length = ctx->header.layout.duplex_l1_size;
bitmap = malloc(ctx->duplex_storage.layers[0]._length);
save_duplex_storage_read(&ctx->duplex_storage.layers[0], bitmap, 0, ctx->duplex_storage.layers[0]._length);
save_duplex_storage_init(&ctx->duplex_storage.layers[1], &ctx->duplex_layers[2], bitmap, ctx->duplex_storage.layers[0]._length);
ctx->duplex_storage.layers[1]._length = ctx->header.layout.duplex_data_size;
ctx->duplex_storage.data_layer = ctx->duplex_storage.layers[1];
/* Initialize meta remap storage. */
ctx->meta_remap_storage.type = STORAGE_DUPLEX;
ctx->meta_remap_storage.duplex = &ctx->duplex_storage.data_layer;
ctx->meta_remap_storage.header = &ctx->header.meta_remap_header;
ctx->meta_remap_storage.map_entries = malloc(sizeof(remap_entry_ctx_t) * ctx->meta_remap_storage.header->map_entry_count);
ctx->meta_remap_storage.file = ctx->file;
f_lseek(ctx->file, ctx->header.layout.meta_map_entry_offset);
for (unsigned int i = 0; i < ctx->meta_remap_storage.header->map_entry_count; i++) {
f_read(ctx->file, &ctx->meta_remap_storage.map_entries[i], 0x20, NULL);
ctx->meta_remap_storage.map_entries[i].physical_offset_end = ctx->meta_remap_storage.map_entries[i].physical_offset + ctx->meta_remap_storage.map_entries[i].size;
ctx->meta_remap_storage.map_entries[i].virtual_offset_end = ctx->meta_remap_storage.map_entries[i].virtual_offset + ctx->meta_remap_storage.map_entries[i].size;
}
ctx->meta_remap_storage.segments = save_remap_init_segments(ctx->meta_remap_storage.header, ctx->meta_remap_storage.map_entries, ctx->meta_remap_storage.header->map_entry_count);
/* Initialize journal map. */
ctx->journal_map_info.map_storage = malloc(ctx->header.layout.journal_map_table_size);
save_remap_read(&ctx->meta_remap_storage, ctx->journal_map_info.map_storage, ctx->header.layout.journal_map_table_offset, ctx->header.layout.journal_map_table_size);
/* Initialize journal storage. */
ctx->journal_storage.header = &ctx->header.journal_header;
ctx->journal_storage.journal_data_offset = ctx->header.layout.journal_data_offset;
ctx->journal_storage._length = ctx->journal_storage.header->total_size - ctx->journal_storage.header->journal_size;
ctx->journal_storage.file = ctx->file;
ctx->journal_storage.map.header = &ctx->header.map_header;
ctx->journal_storage.map.map_storage = ctx->journal_map_info.map_storage;
ctx->journal_storage.map.entries = malloc(sizeof(journal_map_entry_t) * ctx->journal_storage.map.header->main_data_block_count);
uint32_t *pos = (uint32_t *)ctx->journal_storage.map.map_storage;
for (unsigned int i = 0; i < ctx->journal_storage.map.header->main_data_block_count; i++) {
ctx->journal_storage.map.entries[i].virtual_index = i;
ctx->journal_storage.map.entries[i].physical_index = *pos & 0x7FFFFFFF;
pos += 2;
}
ctx->journal_storage.block_size = ctx->journal_storage.header->block_size;
ctx->journal_storage._length = ctx->journal_storage.header->total_size - ctx->journal_storage.header->journal_size;
/* Initialize core IVFC storage. */
for (unsigned int i = 0; i < 5; i++) {
ctx->core_data_ivfc_storage.levels[i].save_ctx = ctx;
}
save_ivfc_storage_init(&ctx->core_data_ivfc_storage, ctx->header.layout.ivfc_master_hash_offset_a, &ctx->header.data_ivfc_header);
/* Initialize FAT storage. */
if (ctx->header.layout.version < 0x50000) {
ctx->fat_storage = malloc(ctx->header.layout.fat_size);
save_remap_read(&ctx->meta_remap_storage, ctx->fat_storage, ctx->header.layout.fat_offset, ctx->header.layout.fat_size);
} else {
for (unsigned int i = 0; i < 5; i++) {
ctx->fat_ivfc_storage.levels[i].save_ctx = ctx;
}
save_ivfc_storage_init(&ctx->fat_ivfc_storage, ctx->header.layout.fat_ivfc_master_hash_a, &ctx->header.fat_ivfc_header);
ctx->fat_storage = malloc(ctx->fat_ivfc_storage._length);
save_remap_read(&ctx->meta_remap_storage, ctx->fat_storage, ctx->header.fat_ivfc_header.level_headers[ctx->header.fat_ivfc_header.num_levels - 2].logical_offset, ctx->fat_ivfc_storage._length);
}
if (ctx->tool_ctx.action & ACTION_VERIFY) {
save_filesystem_verify(ctx);
}
/* Initialize core save filesystem. */
ctx->save_filesystem_core.base_storage = &ctx->core_data_ivfc_storage;
save_filesystem_init(&ctx->save_filesystem_core, ctx->fat_storage, &ctx->header.save_header, &ctx->header.fat_header);
}
void save_process_header(save_ctx_t *ctx) {
if (ctx->header.layout.magic != MAGIC_DISF || ctx->header.duplex_header.magic != MAGIC_DPFS ||
ctx->header.data_ivfc_header.magic != MAGIC_IVFC || ctx->header.journal_header.magic != MAGIC_JNGL ||
ctx->header.save_header.magic != MAGIC_SAVE || ctx->header.main_remap_header.magic != MAGIC_RMAP ||
ctx->header.meta_remap_header.magic != MAGIC_RMAP) {
EPRINTF("Error: Save header is corrupt!\n");
}
ctx->data_ivfc_master = (uint8_t *)&ctx->header + ctx->header.layout.ivfc_master_hash_offset_a;
ctx->fat_ivfc_master = (uint8_t *)&ctx->header + ctx->header.layout.fat_ivfc_master_hash_a;
uint8_t hash[0x20];
se_calc_sha256(hash, &ctx->header.duplex_header, 0x3D00);
ctx->header_hash_validity = memcmp(hash, ctx->header.layout.hash, 0x20) == 0 ? VALIDITY_VALID : VALIDITY_INVALID;
ctx->header.data_ivfc_header.num_levels = 5;
if (ctx->header.layout.version >= 0x50000) {
ctx->header.fat_ivfc_header.num_levels = 4;
}
}
void save_free_contexts(save_ctx_t *ctx) {
for (unsigned int i = 0; i < ctx->data_remap_storage.header->map_segment_count; i++) {
for (unsigned int j = 0; j < ctx->data_remap_storage.segments[i].entry_count; j++) {
free(&ctx->data_remap_storage.segments[i].entries[j]);
}
}
free(ctx->data_remap_storage.segments);
for (unsigned int i = 0; i < ctx->meta_remap_storage.header->map_segment_count; i++) {
for (unsigned int j = 0; j < ctx->meta_remap_storage.segments[i].entry_count; j++) {
free(&ctx->meta_remap_storage.segments[i].entries[j]);
}
}
free(ctx->meta_remap_storage.segments);
free(ctx->data_remap_storage.map_entries);
free(ctx->meta_remap_storage.map_entries);
free(ctx->duplex_storage.layers[0].bitmap.bitmap);
free(ctx->duplex_storage.layers[1].bitmap.bitmap);
free(ctx->duplex_storage.layers[1].bitmap_storage);
for (unsigned int i = 1; i < 3; i++) {
free(ctx->duplex_layers[i].data_a);
free(ctx->duplex_layers[i].data_b);
}
free(ctx->journal_map_info.map_storage);
free(ctx->journal_storage.map.entries);
for (unsigned int i = 0; i < ctx->header.data_ivfc_header.num_levels - 1; i++) {
free(ctx->core_data_ivfc_storage.integrity_storages[i].block_validities);
}
free(ctx->core_data_ivfc_storage.level_validities);
if (ctx->header.layout.version >= 0x50000) {
for (unsigned int i = 0; i < ctx->header.fat_ivfc_header.num_levels - 1; i++) {
free(ctx->fat_ivfc_storage.integrity_storages[i].block_validities);
}
}
free(ctx->fat_ivfc_storage.level_validities);
free(ctx->fat_storage);
}

489
source/keys/save.h Normal file
View File

@ -0,0 +1,489 @@
#ifndef _SAVE_H
#define _SAVE_H
#include <stddef.h>
#include <stdint.h>
#include "../libs/fatfs/ff.h"
#define SAVE_HEADER_SIZE 0x4000
#define SAVE_FAT_ENTRY_SIZE 8
#define SAVE_FS_LIST_MAX_NAME_LENGTH 0x40
#define SAVE_FS_LIST_ENTRY_SIZE 0x60
#define IVFC_MAX_LEVEL 6
#define MAGIC_DISF 0x46534944
#define MAGIC_DPFS 0x53465044
#define MAGIC_JNGL 0x4C474E4A
#define MAGIC_SAVE 0x45564153
#define MAGIC_RMAP 0x50414D52
#define MAGIC_IVFC 0x43465649
typedef enum {
VALIDITY_UNCHECKED = 0,
VALIDITY_INVALID,
VALIDITY_VALID
} validity_t;
typedef struct save_ctx_t save_ctx_t;
typedef struct {
uint32_t magic; /* DISF */
uint32_t version;
uint8_t hash[0x20];
uint64_t file_map_entry_offset;
uint64_t file_map_entry_size;
uint64_t meta_map_entry_offset;
uint64_t meta_map_entry_size;
uint64_t file_map_data_offset;
uint64_t file_map_data_size;
uint64_t duplex_l1_offset_a;
uint64_t duplex_l1_offset_b;
uint64_t duplex_l1_size;
uint64_t duplex_data_offset_a;
uint64_t duplex_data_offset_b;
uint64_t duplex_data_size;
uint64_t journal_data_offset;
uint64_t journal_data_size_a;
uint64_t journal_data_size_b;
uint64_t journal_size;
uint64_t duplex_master_offset_a;
uint64_t duplex_master_offset_b;
uint64_t duplex_master_size;
uint64_t ivfc_master_hash_offset_a;
uint64_t ivfc_master_hash_offset_b;
uint64_t ivfc_master_hash_size;
uint64_t journal_map_table_offset;
uint64_t journal_map_table_size;
uint64_t journal_physical_bitmap_offset;
uint64_t journal_physical_bitmap_size;
uint64_t journal_virtual_bitmap_offset;
uint64_t journal_virtual_bitmap_size;
uint64_t journal_free_bitmap_offset;
uint64_t journal_free_bitmap_size;
uint64_t ivfc_l1_offset;
uint64_t ivfc_l1_size;
uint64_t ivfc_l2_offset;
uint64_t ivfc_l2_size;
uint64_t ivfc_l3_offset;
uint64_t ivfc_l3_size;
uint64_t fat_offset;
uint64_t fat_size;
uint64_t duplex_index;
uint64_t fat_ivfc_master_hash_a;
uint64_t fat_ivfc_master_hash_b;
uint64_t fat_ivfc_l1_offset;
uint64_t fat_ivfc_l1_size;
uint64_t fat_ivfc_l2_offset;
uint64_t fat_ivfc_l2_size;
uint8_t _0x190[0x70];
} fs_layout_t;
#pragma pack(push, 1)
typedef struct {
uint64_t offset;
uint64_t length;
uint32_t block_size_power;
} duplex_info_t;
#pragma pack(pop)
typedef struct {
uint32_t magic; /* DPFS */
uint32_t version;
duplex_info_t layers[3];
} duplex_header_t;
typedef struct {
uint32_t version;
uint32_t main_data_block_count;
uint32_t journal_block_count;
uint32_t _0x0C;
} journal_map_header_t;
typedef struct {
uint32_t magic; /* JNGL */
uint32_t version;
uint64_t total_size;
uint64_t journal_size;
uint64_t block_size;
} journal_header_t;
typedef struct {
uint32_t magic; /* SAVE */
uint32_t version;
uint64_t block_count;
uint64_t block_size;
} save_fs_header_t;
typedef struct {
uint64_t block_size;
uint64_t allocation_table_offset;
uint32_t allocation_table_block_count;
uint32_t _0x14;
uint64_t data_offset;
uint32_t data_block_count;
uint32_t _0x24;
uint32_t directory_table_block;
uint32_t file_table_block;
} fat_header_t;
typedef struct {
uint32_t magic; /* RMAP */
uint32_t version;
uint32_t map_entry_count;
uint32_t map_segment_count;
uint32_t segment_bits;
uint8_t _0x14[0x2C];
} remap_header_t;
typedef struct remap_segment_ctx_t remap_segment_ctx_t;
typedef struct remap_entry_ctx_t remap_entry_ctx_t;
#pragma pack(push, 1)
struct remap_entry_ctx_t {
uint64_t virtual_offset;
uint64_t physical_offset;
uint64_t size;
uint32_t alignment;
uint32_t _0x1C;
uint64_t virtual_offset_end;
uint64_t physical_offset_end;
remap_segment_ctx_t *segment;
remap_entry_ctx_t *next;
};
#pragma pack(pop)
struct remap_segment_ctx_t{
uint64_t offset;
uint64_t length;
remap_entry_ctx_t *entries;
uint64_t entry_count;
};
typedef struct {
uint8_t *data;
uint8_t *bitmap;
} duplex_bitmap_t;
typedef struct {
uint32_t block_size;
uint8_t *bitmap_storage;
uint8_t *data_a;
uint8_t *data_b;
duplex_bitmap_t bitmap;
uint64_t _length;
} duplex_storage_ctx_t;
enum base_storage_type {
STORAGE_BYTES = 0,
STORAGE_DUPLEX = 1,
STORAGE_REMAP = 2,
STORAGE_JOURNAL = 3
};
typedef struct {
remap_header_t *header;
remap_entry_ctx_t *map_entries;
remap_segment_ctx_t *segments;
enum base_storage_type type;
uint64_t base_storage_offset;
duplex_storage_ctx_t *duplex;
FIL *file;
} remap_storage_ctx_t;
typedef struct {
uint64_t title_id;
uint8_t user_id[0x10];
uint64_t save_id;
uint8_t save_data_type;
uint8_t _0x21[0x1F];
uint64_t save_owner_id;
uint64_t timestamp;
uint64_t _0x50;
uint64_t data_size;
uint64_t journal_size;
uint64_t commit_id;
} extra_data_t;
typedef struct {
uint64_t logical_offset;
uint64_t hash_data_size;
uint32_t block_size;
uint32_t reserved;
} ivfc_level_hdr_t;
typedef struct {
uint32_t magic;
uint32_t id;
uint32_t master_hash_size;
uint32_t num_levels;
ivfc_level_hdr_t level_headers[IVFC_MAX_LEVEL];
uint8_t salt_source[0x20];
} ivfc_save_hdr_t;
#pragma pack(push, 1)
typedef struct {
uint8_t cmac[0x10];
uint8_t _0x10[0xF0];
fs_layout_t layout;
duplex_header_t duplex_header;
ivfc_save_hdr_t data_ivfc_header;
uint32_t _0x404;
journal_header_t journal_header;
journal_map_header_t map_header;
uint8_t _0x438[0x1D0];
save_fs_header_t save_header;
fat_header_t fat_header;
remap_header_t main_remap_header, meta_remap_header;
uint64_t _0x6D0;
extra_data_t extra_data;
uint8_t _0x748[0x390];
ivfc_save_hdr_t fat_ivfc_header;
uint8_t _0xB98[0x3468];
} save_header_t;
#pragma pack(pop)
typedef struct {
duplex_storage_ctx_t layers[2];
duplex_storage_ctx_t data_layer;
uint64_t _length;
} hierarchical_duplex_storage_ctx_t;
typedef struct {
uint8_t *data_a;
uint8_t *data_b;
duplex_info_t info;
} duplex_fs_layer_info_t;
typedef struct {
uint8_t *map_storage;
uint8_t *physical_block_bitmap;
uint8_t *virtual_block_bitmap;
uint8_t *free_block_bitmap;
} journal_map_params_t;
typedef struct {
uint32_t physical_index;
uint32_t virtual_index;
} journal_map_entry_t;
typedef struct {
journal_map_header_t *header;
journal_map_entry_t *entries;
uint8_t *map_storage;
} journal_map_ctx_t;
typedef struct {
journal_map_ctx_t map;
journal_header_t *header;
uint32_t block_size;
uint64_t journal_data_offset;
uint64_t _length;
FIL *file;
} journal_storage_ctx_t;
typedef struct {
uint64_t data_offset;
uint64_t data_size;
uint64_t hash_offset;
uint32_t hash_block_size;
validity_t hash_validity;
enum base_storage_type type;
save_ctx_t *save_ctx;
} ivfc_level_save_ctx_t;
typedef struct {
ivfc_level_save_ctx_t *data;
uint32_t block_size;
uint8_t salt[0x20];
} integrity_verification_info_ctx_t;
typedef struct integrity_verification_storage_ctx_t integrity_verification_storage_ctx_t;
struct integrity_verification_storage_ctx_t {
ivfc_level_save_ctx_t *hash_storage;
ivfc_level_save_ctx_t *base_storage;
validity_t *block_validities;
uint8_t salt[0x20];
uint32_t sector_size;
uint32_t sector_count;
uint64_t _length;
integrity_verification_storage_ctx_t *next_level;
};
typedef struct {
ivfc_level_save_ctx_t levels[5];
ivfc_level_save_ctx_t *data_level;
validity_t **level_validities;
uint64_t _length;
integrity_verification_storage_ctx_t integrity_storages[4];
} hierarchical_integrity_verification_storage_ctx_t;
typedef struct {
uint32_t prev;
uint32_t next;
} allocation_table_entry_t;
typedef struct {
uint32_t free_list_entry_index;
void *base_storage;
fat_header_t *header;
} allocation_table_ctx_t;
typedef struct {
hierarchical_integrity_verification_storage_ctx_t *base_storage;
uint32_t block_size;
uint32_t initial_block;
allocation_table_ctx_t *fat;
uint64_t _length;
} allocation_table_storage_ctx_t;
typedef struct {
allocation_table_ctx_t *fat;
uint32_t virtual_block;
uint32_t physical_block;
uint32_t current_segment_size;
uint32_t next_block;
uint32_t prev_block;
} allocation_table_iterator_ctx_t;
typedef struct {
char name[SAVE_FS_LIST_MAX_NAME_LENGTH];
uint32_t parent;
} save_entry_key_t;
#pragma pack(push, 1)
typedef struct {
uint32_t start_block;
uint64_t length;
uint32_t _0xC[2];
} save_file_info_t;
#pragma pack(pop)
#pragma pack(push, 1)
typedef struct {
uint32_t next_directory;
uint32_t next_file;
uint32_t _0x8[3];
} save_find_position_t;
#pragma pack(pop)
#pragma pack(push, 1)
typedef struct {
uint32_t next_sibling;
union { /* Save table entry type. Size = 0x14. */
save_file_info_t save_file_info;
save_find_position_t save_find_position;
};
} save_table_entry_t;
#pragma pack(pop)
#pragma pack(push, 1)
typedef struct {
uint32_t parent;
char name[SAVE_FS_LIST_MAX_NAME_LENGTH];
save_table_entry_t value;
uint32_t next;
} save_fs_list_entry_t;
#pragma pack(pop)
typedef struct {
uint32_t free_list_head_index;
uint32_t used_list_head_index;
allocation_table_storage_ctx_t storage;
uint32_t capacity;
} save_filesystem_list_ctx_t;
typedef struct {
save_filesystem_list_ctx_t file_table;
save_filesystem_list_ctx_t directory_table;
} hierarchical_save_file_table_ctx_t;
typedef struct {
hierarchical_integrity_verification_storage_ctx_t *base_storage;
allocation_table_ctx_t allocation_table;
save_fs_header_t *header;
hierarchical_save_file_table_ctx_t file_table;
} save_filesystem_ctx_t;
#define ACTION_VERIFY (1<<2)
struct save_ctx_t {
save_header_t header;
FIL *file;
struct {
FIL *file;
uint32_t action;
} tool_ctx;
validity_t header_cmac_validity;
validity_t header_hash_validity;
uint8_t *data_ivfc_master;
uint8_t *fat_ivfc_master;
remap_storage_ctx_t data_remap_storage;
remap_storage_ctx_t meta_remap_storage;
duplex_fs_layer_info_t duplex_layers[3];
hierarchical_duplex_storage_ctx_t duplex_storage;
journal_storage_ctx_t journal_storage;
journal_map_params_t journal_map_info;
hierarchical_integrity_verification_storage_ctx_t core_data_ivfc_storage;
hierarchical_integrity_verification_storage_ctx_t fat_ivfc_storage;
uint8_t *fat_storage;
save_filesystem_ctx_t save_filesystem_core;
uint8_t save_mac_key[0x10];
};
static inline uint32_t allocation_table_entry_index_to_block(uint32_t entry_index) {
return entry_index - 1;
}
static inline uint32_t allocation_table_block_to_entry_index(uint32_t block_index) {
return block_index + 1;
}
static inline int allocation_table_is_list_end(allocation_table_entry_t *entry) {
return (entry->next & 0x7FFFFFFF) == 0;
}
static inline int allocation_table_is_list_start(allocation_table_entry_t *entry) {
return entry->prev == 0x80000000;
}
static inline int allocation_table_get_next(allocation_table_entry_t *entry) {
return entry->next & 0x7FFFFFFF;
}
static inline int allocation_table_get_prev(allocation_table_entry_t *entry) {
return entry->prev & 0x7FFFFFFF;
}
static inline allocation_table_entry_t *save_allocation_table_read_entry(allocation_table_ctx_t *ctx, uint32_t entry_index) {
return (allocation_table_entry_t *)((uint8_t *)ctx->base_storage + entry_index * SAVE_FAT_ENTRY_SIZE);
}
static inline uint32_t save_allocation_table_get_free_list_entry_index(allocation_table_ctx_t *ctx) {
return allocation_table_get_next(save_allocation_table_read_entry(ctx, ctx->free_list_entry_index));
}
static inline uint32_t save_allocation_table_get_free_list_block_index(allocation_table_ctx_t *ctx) {
return allocation_table_entry_index_to_block(save_allocation_table_get_free_list_entry_index(ctx));
}
void save_process(save_ctx_t *ctx);
void save_process_header(save_ctx_t *ctx);
void save_save(save_ctx_t *ctx);
void save_print(save_ctx_t *ctx);
void save_free_contexts(save_ctx_t *ctx);
void save_open_fat_storage(save_filesystem_ctx_t *ctx, allocation_table_storage_ctx_t *storage_ctx, uint32_t block_index);
uint32_t save_allocation_table_storage_read(allocation_table_storage_ctx_t *ctx, void *buffer, uint64_t offset, size_t count);
int save_fs_list_get_value(save_filesystem_list_ctx_t *ctx, uint32_t index, save_fs_list_entry_t *value);
uint32_t save_fs_get_index_from_key(save_filesystem_list_ctx_t *ctx, save_entry_key_t *key, uint32_t *prev_index);
int save_hierarchical_file_table_find_path_recursive(hierarchical_save_file_table_ctx_t *ctx, save_entry_key_t *key, char *path);
int save_hierarchical_file_table_get_file_entry_by_path(hierarchical_save_file_table_ctx_t *ctx, char *path, save_fs_list_entry_t *entry);
#endif

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

@ -46,8 +46,9 @@ typedef struct {
} sector_cache_t;
#define MAX_SEC_CACHE_ENTRIES 64
static sector_cache_t *sector_cache = (sector_cache_t*)0x40022000;
static sector_cache_t *sector_cache = NULL;
static u32 secindex = 0;
bool clear_sector_cache = false;
DSTATUS disk_status (
BYTE pdrv /* Physical drive number to identify the drive */
@ -106,7 +107,7 @@ static inline int _emmc_xts(u32 ks1, u32 ks2, u32 enc, u8 *tweak, bool regen_twe
pdst += 0x10;
}
se_aes_crypt_ecb(ks2, 0, dst, secsize, src, secsize);
se_aes_crypt_ecb(ks2, enc, dst, secsize, src, secsize);
pdst = (u8 *)dst;
@ -135,14 +136,28 @@ DRESULT disk_read (
switch (pdrv)
{
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:;
__attribute__ ((aligned (16))) static u8 tweak[0x10];
__attribute__ ((aligned (16))) static u64 prev_cluster = -1;
__attribute__ ((aligned (16))) static u32 prev_sector = 0;
u32 tweak_exp = 0;
bool regen_tweak = true, cache_sector = false;
bool needs_cache_sector = false;
if (secindex == 0 || clear_sector_cache) {
if (!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;
if (count == 1) {
@ -160,12 +175,14 @@ DRESULT disk_read (
if (s == secindex && s < MAX_SEC_CACHE_ENTRIES) {
sector_cache[s].sector = sector;
sector_cache[s].visit_count++;
cache_sector = true;
needs_cache_sector = true;
secindex++;
}
}
if (nx_emmc_part_read(&storage, system_part, sector, count, buff)) {
u32 tweak_exp = 0;
bool regen_tweak = true;
if (prev_cluster != sector / 0x20) { // sector in different cluster than last read
prev_cluster = sector / 0x20;
tweak_exp = sector % 0x20;
@ -178,7 +195,7 @@ DRESULT disk_read (
// fatfs will never pull more than a cluster
_emmc_xts(9, 8, 0, tweak, regen_tweak, tweak_exp, prev_cluster, buff, buff, count * 0x200);
if (cache_sector) {
if (needs_cache_sector) {
memcpy(sector_cache[s].cached_sector, buff, 0x200);
memcpy(sector_cache[s].tweak, tweak, 0x10);
}
@ -199,7 +216,14 @@ DRESULT disk_write (
{
if (pdrv == 1)
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 (

View File

@ -97,7 +97,7 @@
*/
#define FF_USE_LFN 1
#define FF_USE_LFN 3
#define FF_MAX_LFN 255
/* The FF_USE_LFN switches the support for LFN (long file name).
/

View File

@ -22,13 +22,16 @@
#include "gfx/di.h"
#include "gfx/gfx.h"
#include "gfx/tui.h"
#include "hos/pkg1.h"
#include "libs/fatfs/ff.h"
#include "mem/heap.h"
#include "mem/minerva.h"
#include "power/max77620.h"
#include "rtc/max77620-rtc.h"
#include "soc/bpmp.h"
#include "soc/hw_init.h"
#include "storage/emummc.h"
#include "storage/nx_emmc.h"
#include "storage/sdmmc.h"
#include "utils/sprintf.h"
#include "utils/util.h"
@ -165,18 +168,49 @@ void dump_emunand()
}
ment_t ment_top[] = {
MDEF_HANDLER("Dump keys from SysNAND", dump_sysnand, COLOR_RED),
MDEF_HANDLER("Dump keys from emuMMC", 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()
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 };
#define IPL_STACK_TOP 0x4003F000
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
extern void pivot_stack(u32 stack_top);
@ -189,6 +223,10 @@ void ipl_main()
set_default_configuration();
sd_mount();
minerva_init();
minerva_change_freq(FREQ_1600);
display_init();
u32 *fb = display_init_framebuffer();
gfx_init_ctxt(fb, 720, 1280, 720);
@ -213,6 +251,8 @@ void ipl_main()
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);

View File

@ -56,6 +56,7 @@ static u32 _heap_alloc(heap_t *heap, u32 size, u32 alignment)
node->used = 1;
new->used = 0;
new->next = node->next;
new->next->prev = new;
new->prev = node;
node->next = new;
@ -82,7 +83,7 @@ static void _heap_free(heap_t *heap, u32 addr)
hnode_t *node = (hnode_t *)(addr - sizeof(hnode_t));
node->used = 0;
node = heap->first;
while (node)
while (1)
{
if (!node->used)
{
@ -94,7 +95,14 @@ static void _heap_free(heap_t *heap, u32 addr)
node->next->prev = node->prev;
}
}
node = node->next;
if (node->next)
node = node->next;
else
{
node->size = -1;
break;
}
}
}
@ -113,7 +121,7 @@ void *malloc(u32 size)
void *calloc(u32 num, u32 size)
{
void *res = (void *)_heap_alloc(&_heap, num * size, sizeof(hnode_t));
memset(res, 0, num * size);
memset(res, 0, ALIGN(num * size, sizeof(hnode_t)));
return res;
}

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,9 +43,6 @@
#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)
{
u16 data;
@ -267,5 +264,3 @@ int max17050_fix_configuration()
return 0;
}
#pragma GCC pop_options

View File

@ -33,6 +33,9 @@ typedef struct _se_ll_t
vu32 size;
} se_ll_t;
static u32 _se_rsa_mod_sizes[TEGRA_SE_RSA_KEYSLOT_COUNT];
static u32 _se_rsa_exp_sizes[TEGRA_SE_RSA_KEYSLOT_COUNT];
static void _gf256_mul_x(void *block)
{
u8 *pdata = (u8 *)block;
@ -91,17 +94,15 @@ static int _se_wait()
static int _se_execute(u32 op, void *dst, u32 dst_size, const void *src, u32 src_size)
{
se_ll_t *ll_dst = NULL, *ll_src = NULL;
se_ll_t *ll_dst = (se_ll_t *)0xECFFFFE0, *ll_src = (se_ll_t *)0xECFFFFF0;
if (dst)
{
ll_dst = (se_ll_t *)malloc(sizeof(se_ll_t));
_se_ll_init(ll_dst, (u32)dst, dst_size);
}
if (src)
{
ll_src = (se_ll_t *)malloc(sizeof(se_ll_t));
_se_ll_init(ll_src, (u32)src, src_size);
}
@ -117,11 +118,6 @@ static int _se_execute(u32 op, void *dst, u32 dst_size, const void *src, u32 src
bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY);
if (src)
free(ll_src);
if (dst)
free(ll_dst);
return res;
}
@ -158,6 +154,66 @@ void se_rsa_acc_ctrl(u32 rs, u32 flags)
SE(SE_RSA_KEYTABLE_ACCESS_LOCK_OFFSET) &= ~(1 << rs);
}
// se_rsa_key_set() was derived from Atmosphère's set_rsa_keyslot
void se_rsa_key_set(u32 ks, const void *mod, u32 mod_size, const void *exp, u32 exp_size)
{
u32 *data = (u32 *)mod;
for (u32 i = 0; i < mod_size / 4; i++)
{
SE(SE_RSA_KEYTABLE_ADDR) = RSA_KEY_NUM(ks) | RSA_KEY_TYPE(RSA_KEY_TYPE_MOD) | i;
SE(SE_RSA_KEYTABLE_DATA) = byte_swap_32(data[mod_size / 4 - i - 1]);
}
data = (u32 *)exp;
for (u32 i = 0; i < exp_size / 4; i++)
{
SE(SE_RSA_KEYTABLE_ADDR) = RSA_KEY_NUM(ks) | RSA_KEY_TYPE(RSA_KEY_TYPE_EXP) | i;
SE(SE_RSA_KEYTABLE_DATA) = byte_swap_32(data[exp_size / 4 - i - 1]);
}
_se_rsa_mod_sizes[ks] = mod_size;
_se_rsa_exp_sizes[ks] = exp_size;
}
// se_rsa_key_clear() was derived from Atmosphère's clear_rsa_keyslot
void se_rsa_key_clear(u32 ks)
{
for (u32 i = 0; i < TEGRA_SE_RSA2048_DIGEST_SIZE / 4; i++)
{
SE(SE_RSA_KEYTABLE_ADDR) = RSA_KEY_NUM(ks) | RSA_KEY_TYPE(RSA_KEY_TYPE_MOD) | i;
SE(SE_RSA_KEYTABLE_DATA) = 0;
}
for (u32 i = 0; i < TEGRA_SE_RSA2048_DIGEST_SIZE / 4; i++)
{
SE(SE_RSA_KEYTABLE_ADDR) = RSA_KEY_NUM(ks) | RSA_KEY_TYPE(RSA_KEY_TYPE_EXP) | i;
SE(SE_RSA_KEYTABLE_DATA) = 0;
}
}
// se_rsa_exp_mod() was derived from Atmosphère's se_synchronous_exp_mod and se_get_exp_mod_output
int se_rsa_exp_mod(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_size)
{
int res;
u8 stack_buf[TEGRA_SE_RSA2048_DIGEST_SIZE];
for (u32 i = 0; i < src_size; i++)
stack_buf[i] = *((u8 *)src + src_size - i - 1);
SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_ENC_ALG(ALG_RSA) | SE_CONFIG_DST(DST_RSAREG);
SE(SE_RSA_CONFIG) = RSA_KEY_SLOT(ks);
SE(SE_RSA_KEY_SIZE_REG_OFFSET) = (_se_rsa_mod_sizes[ks] >> 6) - 1;
SE(SE_RSA_EXP_SIZE_REG_OFFSET) = _se_rsa_exp_sizes[ks] >> 2;
res = _se_execute(OP_START, NULL, 0, stack_buf, src_size);
// Copy output hash.
u32 *dst32 = (u32 *)dst;
for (u32 i = 0; i < dst_size / 4; i++)
dst32[dst_size / 4 - i - 1] = byte_swap_32(SE(SE_RSA_OUTPUT + (i << 2)));
return res;
}
void se_key_acc_ctrl(u32 ks, u32 flags)
{
if (flags & 0x7F)
@ -365,7 +421,7 @@ int se_calc_sha256(void *dst, const void *src, u32 src_size)
int res;
// Setup config for SHA256, size = BITS(src_size).
SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_ENC_MODE(MODE_SHA256) | SE_CONFIG_ENC_ALG(ALG_SHA) | SE_CONFIG_DST(DST_HASHREG);
SE(SE_SHA_CONFIG_REG_OFFSET) = SHA_ENABLE;
SE(SE_SHA_CONFIG_REG_OFFSET) = SHA_INIT_ENABLE;
SE(SE_SHA_MSG_LENGTH_REG_OFFSET) = (u32)(src_size << 3);
SE(SE_SHA_MSG_LENGTH_REG_OFFSET + 4 * 1) = 0;
SE(SE_SHA_MSG_LENGTH_REG_OFFSET + 4 * 2) = 0;
@ -385,3 +441,46 @@ int se_calc_sha256(void *dst, const void *src, u32 src_size)
return res;
}
int se_calc_hmac_sha256(void *dst, const void *src, u32 src_size, const void *key, u32 key_size) {
int res = 0;
u8 *secret = (u8 *)malloc(0x40);
u8 *ipad = (u8 *)malloc(0x40 + src_size);
u8 *opad = (u8 *)malloc(0x60);
if (key_size > 0x40)
{
if (!se_calc_sha256(secret, key, key_size))
goto out;
memset(secret + 0x20, 0, 0x20);
}
else
{
memcpy(secret, key, key_size);
memset(secret + key_size, 0, 0x40 - key_size);
}
u32 *secret32 = (u32 *)secret;
u32 *ipad32 = (u32 *)ipad;
u32 *opad32 = (u32 *)opad;
for (u32 i = 0; i < 0x10; i++)
{
ipad32[i] = secret32[i] ^ 0x36363636;
opad32[i] = secret32[i] ^ 0x5C5C5C5C;
}
memcpy(ipad + 0x40, src, src_size);
if (!se_calc_sha256(dst, ipad, 0x40 + src_size))
goto out;
memcpy(opad + 0x40, dst, 0x20);
if (!se_calc_sha256(dst, opad, 0x60))
goto out;
res = 1;
out:;
free(secret);
free(ipad);
free(opad);
return res;
}

View File

@ -20,6 +20,9 @@
#include "../utils/types.h"
void se_rsa_acc_ctrl(u32 rs, u32 flags);
void se_rsa_key_set(u32 ks, const void *mod, u32 mod_size, const void *exp, u32 exp_size);
void se_rsa_key_clear(u32 ks);
int se_rsa_exp_mod(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_size);
void se_key_acc_ctrl(u32 ks, u32 flags);
void se_aes_key_set(u32 ks, const void *key, u32 size);
void se_aes_key_read(u32 ks, void *key, u32 size);
@ -32,5 +35,6 @@ int se_aes_xts_crypt_sec(u32 ks1, u32 ks2, u32 enc, u64 sec, void *dst, const vo
int se_aes_xts_crypt(u32 ks1, u32 ks2, u32 enc, u64 sec, void *dst, const void *src, u32 secsize, u32 num_secs);
int se_aes_cmac(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_size);
int se_calc_sha256(void *dst, const void *src, u32 src_size);
int se_calc_hmac_sha256(void *dst, const void *src, u32 src_size, const void *key, u32 key_size);
#endif

View File

@ -231,8 +231,8 @@
#define SE_SPARE_0_REG_OFFSET 0x80c
#define SE_SHA_CONFIG_REG_OFFSET 0x200
#define SHA_DISABLE 0
#define SHA_ENABLE 1
#define SHA_INIT_DISABLE 0
#define SHA_INIT_ENABLE 1
#define SE_SHA_MSG_LENGTH_REG_OFFSET 0x204
#define SE_SHA_MSG_LEFT_REG_OFFSET 0x214

View File

@ -15,6 +15,7 @@
*/
#include "../soc/clock.h"
#include "../soc/kfuse.h"
#include "../soc/t210.h"
#include "../utils/util.h"
#include "../storage/sdmmc.h"
@ -188,6 +189,7 @@ void clock_enable_kfuse()
usleep(10);
CLOCK(CLK_RST_CONTROLLER_RST_DEVICES_H) &= 0xFFFFFEFF;
usleep(20);
kfuse_wait_ready();
}
void clock_disable_kfuse()

View File

@ -37,12 +37,31 @@
#define FUSE_WRITE_ACCESS_SW 0x30
#define FUSE_PWR_GOOD_SW 0x34
#define FUSE_SKU_INFO 0x110
#define FUSE_CPU_SPEEDO_0_CALIB 0x114
#define FUSE_CPU_IDDQ_CALIB 0x118
#define FUSE_OPT_FT_REV 0x128
#define FUSE_CPU_SPEEDO_1_CALIB 0x12C
#define FUSE_CPU_SPEEDO_2_CALIB 0x130
#define FUSE_SOC_SPEEDO_0_CALIB 0x134
#define FUSE_SOC_SPEEDO_1_CALIB 0x138
#define FUSE_SOC_SPEEDO_2_CALIB 0x13C
#define FUSE_SOC_IDDQ_CALIB 0x140
#define FUSE_OPT_CP_REV 0x190
#define FUSE_FIRST_BOOTROM_PATCH_SIZE 0x19c
#define FUSE_PRIVATE_KEY0 0x1A4
#define FUSE_PRIVATE_KEY1 0x1A8
#define FUSE_PRIVATE_KEY2 0x1AC
#define FUSE_PRIVATE_KEY3 0x1B0
#define FUSE_PRIVATE_KEY4 0x1B4
#define FUSE_RESERVED_SW 0x1C0
#define FUSE_OPT_VENDOR_CODE 0x200
#define FUSE_OPT_FAB_CODE 0x204
#define FUSE_OPT_LOT_CODE_0 0x208
#define FUSE_OPT_LOT_CODE_1 0x20C
#define FUSE_OPT_WAFER_ID 0x210
#define FUSE_OPT_X_COORDINATE 0x214
#define FUSE_OPT_Y_COORDINATE 0x218
#define FUSE_GPU_IDDQ_CALIB 0x228
/*! Fuse commands. */
#define FUSE_READ 0x1

View File

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

57
source/soc/kfuse.c Normal file
View File

@ -0,0 +1,57 @@
/*
* Copyright (c) 2018 naehrwert
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "../soc/kfuse.h"
#include "../soc/clock.h"
#include "../soc/t210.h"
#include "../utils/util.h"
int kfuse_read(u32 *buf)
{
int res = 0;
clock_enable_kfuse();
while (!(KFUSE(KFUSE_STATE) & KFUSE_STATE_DONE))
;
if (!(KFUSE(KFUSE_STATE) & KFUSE_STATE_CRCPASS))
goto out;
KFUSE(KFUSE_KEYADDR) = KFUSE_KEYADDR_AUTOINC;
for (int i = 0; i < KFUSE_NUM_WORDS; i++)
buf[i] = KFUSE(KFUSE_KEYS);
res = 1;
out:;
clock_disable_kfuse();
return res;
}
int kfuse_wait_ready()
{
// Wait for KFUSE to finish init and verification of data.
while (!(KFUSE(KFUSE_STATE) & KFUSE_STATE_DONE))
{
usleep(500);
}
if (!(KFUSE(KFUSE_STATE) & KFUSE_STATE_CRCPASS))
return 0;
return 1;
}

42
source/soc/kfuse.h Normal file
View File

@ -0,0 +1,42 @@
/*
* Copyright (c) 2018 naehrwert
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _KFUSE_H_
#define _KFUSE_H_
#include "../utils/types.h"
#define KFUSE_STATE_SOFTRESET (1 << 31)
#define KFUSE_STATE_STOP (1 << 25)
#define KFUSE_STATE_RESTART (1 << 24)
#define KFUSE_STATE_CRCPASS (1 << 17)
#define KFUSE_STATE_DONE (1 << 16)
#define KFUSE_STATE_ERRBLOCK_MASK 0x3F00
#define KFUSE_STATE_ERRBLOCK_SHIFT 8
#define KFUSE_STATE_CURBLOCK_MASK 0x3F
#define KFUSE_KEYADDR_AUTOINC (1<<16)
#define KFUSE_STATE 0x80
#define KFUSE_KEYADDR 0x88
#define KFUSE_KEYS 0x8C
#define KFUSE_NUM_WORDS 144
int kfuse_read(u32 *buf);
int kfuse_wait_ready();
#endif

View File

@ -37,8 +37,8 @@ void nx_emmc_gpt_parse(link_t *gpt, sdmmc_storage_t *storage)
part->attrs = ent->attrs;
//HACK
for (u32 i = 0; i < 36; i++)
part->name[i] = ent->name[i];
for (u32 j = 0; j < 36; j++)
part->name[j] = ent->name[j];
part->name[36] = 0;
list_append(gpt, &part->link);

View File

@ -77,7 +77,7 @@ static int _sdmmc_set_voltage(sdmmc_t *sdmmc, u32 power)
{
pwr |= TEGRA_MMC_PWRCTL_SD_BUS_POWER;
sdmmc->regs->pwrcon = pwr;
}
}
return 1;
}
@ -385,7 +385,7 @@ int sdmmc_get_rsp(sdmmc_t *sdmmc, u32 *rsp, u32 size, u32 type)
static void _sdmmc_reset(sdmmc_t *sdmmc)
{
sdmmc->regs->swrst |=
sdmmc->regs->swrst |=
TEGRA_MMC_SWRST_SW_RESET_FOR_CMD_LINE | TEGRA_MMC_SWRST_SW_RESET_FOR_DAT_LINE;
_sdmmc_get_clkcon(sdmmc);
u32 timeout = get_tmr_ms() + 2000;
@ -456,7 +456,7 @@ static int _sdmmc_setup_read_small_block(sdmmc_t *sdmmc)
static int _sdmmc_parse_cmdbuf(sdmmc_t *sdmmc, sdmmc_cmd_t *cmd, bool is_data_present)
{
u16 cmdflags = 0;
switch (cmd->rsp_type)
{
case SDMMC_RSP_TYPE_0:
@ -722,7 +722,7 @@ static int _sdmmc_check_mask_interrupt(sdmmc_t *sdmmc, u16 *pout, u16 mask)
sdmmc->regs->norintsts = norintsts & mask;
return SDMMC_MASKINT_MASKED;
}
return SDMMC_MASKINT_NOERROR;
}
@ -767,7 +767,7 @@ static int _sdmmc_stop_transmission_inner(sdmmc_t *sdmmc, u32 *rsp)
if (!res)
return 0;
_sdmmc_cache_rsp(sdmmc, rsp, 4, SDMMC_RSP_TYPE_1);
return _sdmmc_wait_prnsts_type1(sdmmc);
@ -901,7 +901,7 @@ static int _sdmmc_execute_cmd_inner(sdmmc_t *sdmmc, sdmmc_cmd_t *cmd, sdmmc_req_
_sdmmc_parse_cmdbuf(sdmmc, cmd, is_data_present);
int res = _sdmmc_wait_request(sdmmc);
DPRINTF("rsp(%d): %08X, %08X, %08X, %08X\n", res,
DPRINTF("rsp(%d): %08X, %08X, %08X, %08X\n", res,
sdmmc->regs->rspreg0, sdmmc->regs->rspreg1, sdmmc->regs->rspreg2, sdmmc->regs->rspreg3);
if (res)
{
@ -943,7 +943,7 @@ static int _sdmmc_config_sdmmc1()
gpio_output_enable(GPIO_PORT_Z, GPIO_PIN_1, GPIO_OUTPUT_DISABLE);
usleep(100);
// Check if SD card is inserted.
// Check if SD card is inserted.
if(!!gpio_read(GPIO_PORT_Z, GPIO_PIN_1))
return 0;
@ -1055,7 +1055,7 @@ void sdmmc_end(sdmmc_t *sdmmc)
if (!sdmmc->clock_stopped)
{
_sdmmc_sd_clock_disable(sdmmc);
// Disable SDMMC power.
// Disable SDMMC power.
_sdmmc_set_voltage(sdmmc, SDMMC_POWER_OFF);
// Disable SD card power.
@ -1134,7 +1134,7 @@ int sdmmc_enable_low_voltage(sdmmc_t *sdmmc)
_sdmmc_set_voltage(sdmmc, SDMMC_POWER_1_8);
_sdmmc_get_clkcon(sdmmc);
msleep(5);
if (sdmmc->regs->hostctl2 & SDHCI_CTRL_VDD_180)
{
sdmmc->regs->clkcon |= TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE;

View File

@ -19,6 +19,7 @@
#define _UTIL_H_
#include "types.h"
#include "../mem/minerva.h"
#define byte_swap_32(num) (((num >> 24) & 0xff) | ((num << 8) & 0xff0000) | \
((num >> 8 )& 0xff00) | ((num << 24) & 0xff000000))
@ -29,6 +30,17 @@ typedef struct _cfg_op_t
u32 val;
} 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_ms();
u32 get_tmr_s();