diff --git a/common/common_module.h b/common/common_module.h new file mode 100644 index 0000000..1d3fb89 --- /dev/null +++ b/common/common_module.h @@ -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 . +*/ + +#pragma once +#include +//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); diff --git a/source/gfx/tui.c b/source/gfx/tui.c index ed2357a..cd3cea6 100644 --- a/source/gfx/tui.c +++ b/source/gfx/tui.c @@ -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); diff --git a/source/hos/sept.c b/source/hos/sept.c index 3ec628e..f991cf9 100644 --- a/source/hos/sept.c +++ b/source/hos/sept.c @@ -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); @@ -115,7 +116,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); + gfx_printf("\n%kPress Power or Vol +/-\n to Reboot to Sept...", colors[(color_idx++) % 6]); btn_wait(); u32 pk1t_sept = SEPT_PK1T_ADDR - (ALIGN(PATCHED_RELOC_SZ, 0x10) + WB_RST_SIZE); diff --git a/source/ianos/ianos.c b/source/ianos/ianos.c new file mode 100644 index 0000000..18d4165 --- /dev/null +++ b/source/ianos/ianos.c @@ -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 . + */ + +#include + +#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; +} \ No newline at end of file diff --git a/source/ianos/ianos.h b/source/ianos/ianos.h new file mode 100644 index 0000000..74d02c1 --- /dev/null +++ b/source/ianos/ianos.h @@ -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 . + */ + +#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 \ No newline at end of file diff --git a/source/keys/keys.c b/source/keys/keys.c index ca4b9f9..2af24cd 100644 --- a/source/keys/keys.c +++ b/source/keys/keys.c @@ -26,6 +26,7 @@ #include "../libs/fatfs/ff.h" #include "../mem/heap.h" #include "../mem/mc.h" +#include "../mem/minerva.h" #include "../mem/sdram.h" #include "../sec/se.h" #include "../sec/se_t210.h" @@ -51,7 +52,8 @@ extern int sd_save_to_file(void *buf, u32 size, const char *filename); extern hekate_config h_cfg; -u32 _key_count = 0; +u32 _key_count = 0, _titlekey_count = 0; +u32 color_idx = 0; sdmmc_storage_t storage; emmc_part_t *system_part; u32 start_time, end_time; @@ -59,13 +61,17 @@ u32 start_time, end_time; #define TPRINTF(text) \ end_time = get_tmr_us(); \ gfx_printf(text" done in %d us\n", end_time - start_time); \ - start_time = get_tmr_us() + start_time = get_tmr_us(); \ + minerva_periodic_training() + #define TPRINTFARGS(text, args...) \ end_time = get_tmr_us(); \ gfx_printf(text" done in %d us\n", args, end_time - start_time); \ - start_time = get_tmr_us() + start_time = get_tmr_us(); \ + minerva_periodic_training() + #define SAVE_KEY(name, src, len) _save_key(name, src, len, text_buffer) -#define SAVE_KEY_FAMILY(name, src, count, len) _save_key_family(name, src, count, len, text_buffer) +#define SAVE_KEY_FAMILY(name, src, start, count, len) _save_key_family(name, src, start, count, len, text_buffer) static u8 temp_key[0x10], bis_key[4][0x20] = {0}, @@ -94,27 +100,31 @@ static u8 temp_key[0x10], titlekek[KB_FIRMWARE_VERSION_MAX+1][0x10] = {0}; // key functions -static bool _key_exists(const void *data) { return memcmp(data, zeros, 0x10); }; -static void _save_key(const char *name, const void *data, const u32 len, char *outbuf); -static void _save_key_family(const char *name, const void *data, const u32 num_keys, const u32 len, char *outbuf); -static void _generate_kek(u32 ks, const void *key_source, void *master_key, const void *kek_seed, const void *key_seed); +static bool _key_exists(const void *data) { return memcmp(data, zeros, 0x10); }; +static void _save_key(const char *name, const void *data, u32 len, char *outbuf); +static void _save_key_family(const char *name, const void *data, u32 start_key, u32 num_keys, u32 len, char *outbuf); +static void _generate_kek(u32 ks, const void *key_source, void *master_key, const void *kek_seed, const void *key_seed); // nca functions -static void *_nca_process(u32 hk_ks1, u32 hk_ks2, FIL *fp, u32 key_offset, u32 len); -static u32 _nca_fread_ctr(u32 ks, FIL *fp, void *buffer, u32 offset, u32 len, u8 *ctr); -static void _update_ctr(u8 *ctr, u32 ofs); +static void *_nca_process(u32 hk_ks1, u32 hk_ks2, FIL *fp, u32 key_offset, u32 len); +static u32 _nca_fread_ctr(u32 ks, FIL *fp, void *buffer, u32 offset, u32 len, u8 *ctr); +static void _update_ctr(u8 *ctr, u32 ofs); +// titlekey functions +static bool _test_key_pair(const void *E, const void *D, const void *N); +static void _mgf1_xor(void *masked, u32 masked_size, const void *seed, u32 seed_size); void dump_keys() { - display_backlight_brightness(100, 1000); + display_backlight_brightness(h_cfg.backlight, 1000); gfx_clear_partial_grey(0x1B, 0, 1256); gfx_con_setpos(0, 0); gfx_printf("[%kLo%kck%kpi%kck%k_R%kCM%k v%d.%d.%d%k]\n\n", colors[0], colors[1], colors[2], colors[3], colors[4], colors[5], 0xFFFF00FF, LP_VER_MJ, LP_VER_MN, LP_VER_BF, 0xFFCCCCCC); + tui_sbar(true); + start_time = get_tmr_us(); u32 begin_time = get_tmr_us(); u32 retries = 0; - u32 color_idx = 0; tsec_ctxt_t tsec_ctxt; sdmmc_t sdmmc; @@ -141,10 +151,12 @@ void dump_keys() { } } if (!found_tsec_fw) { - EPRINTF("Failed to locate TSEC firmware."); + EPRINTF("Unable to locate TSEC firmware."); goto out_wait; } + minerva_periodic_training(); + tsec_key_data_t *key_data = (tsec_key_data_t *)(tsec_ctxt.fw + TSEC_KEY_DATA_ADDR); tsec_ctxt.pkg1 = pkg1; tsec_ctxt.size = 0x100 + key_data->blob0_size + key_data->blob1_size + key_data->blob2_size + key_data->blob3_size + key_data->blob4_size; @@ -177,10 +189,10 @@ void dump_keys() { u32 payload_size = *(u32 *)(IPL_LOAD_ADDR + 0x84) - IPL_LOAD_ADDR; f_write(&fp, (u8 *)IPL_LOAD_ADDR, payload_size, NULL); f_close(&fp); - gfx_printf("%k\nFirmware 7.x or higher detected.\n%kRenamed /sept/payload.bin", colors[(color_idx) % 6], colors[(color_idx + 1) % 6]); - color_idx += 2; - gfx_printf("\n%k to /sept/payload.bak\n%kCopied self to /sept/payload.bin", colors[(color_idx) % 6], colors[(color_idx + 1) % 6]); - color_idx += 2; + gfx_printf("%k\nFirmware 7.x or higher detected.\n\n", colors[(color_idx++) % 6]); + gfx_printf("%kRenamed /sept/payload.bin", colors[(color_idx++) % 6]); + gfx_printf("\n to /sept/payload.bak\n\n", colors[(color_idx++) % 6]); + gfx_printf("%kCopied self to /sept/payload.bin\n", colors[(color_idx++) % 6]); sdmmc_storage_end(&storage); if (!reboot_to_sept((u8 *)tsec_ctxt.fw, tsec_ctxt.size, pkg1_id->kb)) goto out_wait; @@ -239,7 +251,8 @@ get_tsec: ; se_aes_key_set(8, master_key[0], 0x10); se_aes_crypt_block_ecb(8, 0, temp_key, mkey_vectors[0]); if (_key_exists(temp_key)) { - EPRINTFARGS("Failed to derive master key. kb = %d", pkg1_id->kb); + EPRINTFARGS("Unable to derive master key. kb = %d.\n Put current sept files on SD and retry.", pkg1_id->kb); + memset(master_key, 0, sizeof(master_key)); } } else if (_key_exists(master_key[KB_FIRMWARE_VERSION_MAX])) { // handle sept version differences @@ -257,7 +270,8 @@ get_tsec: ; memcpy(master_key[kb], zeros, 0x10); } if (_key_exists(temp_key)) { - EPRINTF("Failed to derive master key."); + EPRINTF("Unable to derive master key."); + memset(master_key, 0, sizeof(master_key)); } } } @@ -269,6 +283,7 @@ get_tsec: ; se_aes_key_set(8, tsec_keys, 0x10); se_aes_key_set(9, sbk, 0x10); for (u32 i = 0; i <= KB_FIRMWARE_VERSION_600; i++) { + minerva_periodic_training(); se_aes_crypt_block_ecb(8, 0, keyblob_key[i], keyblob_key_source[i]); // temp = unwrap(kbks, tsec) se_aes_crypt_block_ecb(9, 0, keyblob_key[i], keyblob_key[i]); // kbk = unwrap(temp, sbk) se_aes_key_set(7, keyblob_key[i], 0x10); @@ -305,7 +320,7 @@ get_tsec: ; /* key = unwrap(source, wrapped_key): key_set(ks, wrapped_key), block_ecb(ks, 0, key, source) -> final key in key */ - + minerva_periodic_training(); u32 key_generation = 0; if (pkg1_id->kb >= KB_FIRMWARE_VERSION_500) { if ((fuse_read_odm(4) & 0x800) && fuse_read_odm(0) == 0x8E61ECAE && fuse_read_odm(1) == 0xF2BA3BB2) { @@ -346,7 +361,7 @@ get_tsec: ; // Find package2 partition. emmc_part_t *pkg2_part = nx_emmc_part_find(&gpt, "BCPKG2-1-Normal-Main"); if (!pkg2_part) { - EPRINTF("Failed to locate Package2."); + EPRINTF("Unable to locate Package2."); goto pkg2_done; } @@ -367,6 +382,7 @@ get_tsec: ; nx_emmc_part_read(&storage, pkg2_part, 0x4000 / NX_EMMC_BLOCKSIZE, pkg2_size_aligned / NX_EMMC_BLOCKSIZE, pkg2); // Decrypt package2 and parse KIP1 blobs in INI1 section. Try all available key generations in case of pkg1/pkg2 mismatch. + minerva_periodic_training(); pkg2_hdr_t *pkg2_hdr; pkg2_hdr_t hdr; u32 pkg2_kb; @@ -379,14 +395,14 @@ get_tsec: ; break; } if (pkg2_kb == MAX_KEY) { - EPRINTF("Failed to derive Package2 key."); + EPRINTF("Unable to derive Package2 key."); goto pkg2_done; } else if (pkg2_kb != pkg1_id->kb) EPRINTFARGS("Warning! Package1-Package2 mismatch: %d, %d", pkg1_id->kb, pkg2_kb); pkg2_hdr = pkg2_decrypt(pkg2); if (!pkg2_hdr) { - EPRINTF("Failed to decrypt Package2."); + EPRINTF("Unable to decrypt Package2."); goto pkg2_done; } @@ -406,7 +422,7 @@ get_tsec: ; free(CONTAINER_OF(iter, pkg2_kip1_info_t, link)); if (!ki) { - EPRINTF("Failed to parse INI1."); + EPRINTF("Unable to parse INI1."); goto pkg2_done; } @@ -485,6 +501,7 @@ get_tsec: ; u8 temp_hash[0x20]; for (u32 i = ki->kip1->sections[0].size_comp + start_offset; i < ki->size - 0x20; ) { + minerva_periodic_training(); se_calc_sha256(temp_hash, ki->kip1->data + i, key_lengths[hash_order[hash_index]]); if (!memcmp(temp_hash, fs_hashes_sha256[hash_order[hash_index]], 0x20)) { memcpy(fs_keys[hash_order[hash_index]], ki->kip1->data + i, key_lengths[hash_order[hash_index]]); @@ -504,11 +521,12 @@ get_tsec: ; i += alignment; } } - pkg2_done: free(pkg2); free(ki); + u8 *rights_ids = NULL, *titlekeys = NULL; + TPRINTFARGS("%kFS keys... ", colors[(color_idx++) % 6]); if (_key_exists(fs_keys[0]) && _key_exists(fs_keys[1]) && _key_exists(master_key[0])) { @@ -539,7 +557,6 @@ pkg2_done: se_aes_crypt_block_ecb(8, 0, titlekek[i], titlekek_source); } - if (!_key_exists(header_key) || !_key_exists(bis_key[2])) { EPRINTF("Missing FS keys. Skipping ES/SSL keys."); @@ -553,12 +570,12 @@ pkg2_done: system_part = nx_emmc_part_find(&gpt, "SYSTEM"); if (!system_part) { - EPRINTF("Failed to locate System partition."); + EPRINTF("Unable to locate System partition."); goto key_output; } __attribute__ ((aligned (16))) FATFS emmc_fs; if (f_mount(&emmc_fs, "emmc:", 1)) { - EPRINTF("Mount failed."); + EPRINTF("Mount Unable."); goto key_output; } @@ -574,7 +591,7 @@ pkg2_done: u8 *temp_file = NULL; if (f_opendir(&dir, path)) { - EPRINTF("Failed to open System:/Contents/registered."); + EPRINTF("Unable to open System:/Contents/registered."); goto dismount; } @@ -583,14 +600,14 @@ pkg2_done: f_closedir(&dir); if (f_opendir(&dir, path)) { - EPRINTF("Failed to open System:/Contents/registered."); + EPRINTF("Unable to open System:/Contents/registered."); goto dismount; } path[25] = '/'; start_offset = 0; - while (!f_readdir(&dir, &fno) && fno.fname[0] && titles_found < title_limit) { + minerva_periodic_training(); memcpy(path + 26, fno.fname, 36); path[62] = 0; if (fno.fattrib & AM_DIR) @@ -711,6 +728,20 @@ pkg2_done: f_closedir(&dir); free(dec_header); + // derive eticket_rsa_kek and ssl_rsa_kek + if (_key_exists(es_keys[0]) && _key_exists(es_keys[1]) && _key_exists(master_key[0])) { + for (u32 i = 0; i < 0x10; i++) + temp_key[i] = aes_kek_generation_source[i] ^ aes_kek_seed_03[i]; + _generate_kek(7, es_keys[1], master_key[0], temp_key, NULL); + se_aes_crypt_block_ecb(7, 0, eticket_rsa_kek, es_keys[0]); + } + if (_key_exists(ssl_keys[1]) && _key_exists(es_keys[2]) && _key_exists(master_key[0])) { + for (u32 i = 0; i < 0x10; i++) + temp_key[i] = aes_kek_generation_source[i] ^ aes_kek_seed_01[i]; + _generate_kek(7, es_keys[2], master_key[0], temp_key, NULL); + se_aes_crypt_block_ecb(7, 0, ssl_rsa_kek, ssl_keys[1]); + } + if (memcmp(pkg1_id->id, "2016", 4)) { TPRINTFARGS("%kES & SSL keys...", colors[(color_idx++) % 6]); } else { @@ -718,23 +749,22 @@ pkg2_done: } if (f_open(&fp, "sd:/Nintendo/Contents/private", FA_READ | FA_OPEN_EXISTING)) { - EPRINTF("Unable to locate SD seed. Skipping."); - goto dismount; + EPRINTF("Unable to open SD seed vector. Skipping."); + goto get_titlekeys; } // get sd seed verification vector if (f_read(&fp, temp_key, 0x10, &read_bytes) || read_bytes != 0x10) { - EPRINTF("Unable to locate SD seed. Skipping."); + EPRINTF("Unable to read SD seed vector. Skipping."); f_close(&fp); - goto dismount; + goto get_titlekeys; } f_close(&fp); if (f_open(&fp, "emmc:/save/8000000000000043", FA_READ | FA_OPEN_EXISTING)) { - EPRINTF("Failed to open ns_appman save.\nSkipping SD seed."); - goto dismount; + EPRINTF("Unable to open ns_appman save.\nSkipping SD seed."); + goto get_titlekeys; } - // locate sd seed u8 read_buf[0x20] = {0}; for (u32 i = 0x8000; i < f_size(&fp); i += 0x4000) { if (f_lseek(&fp, i) || f_read(&fp, read_buf, 0x20, &read_bytes) || read_bytes != 0x20) @@ -748,33 +778,188 @@ pkg2_done: TPRINTFARGS("%kSD Seed... ", colors[(color_idx++) % 6]); +get_titlekeys: + if (!_key_exists(eticket_rsa_kek)) + goto dismount; + + if (!minerva_cfg) { + gfx_printf("%k Minerva not found!\n This may take up to a minute...\n", colors[(color_idx++) % 6]); + gfx_printf(" For better performance, download Hekate\n and put bootloader/sys/libsys_minerva.bso\n on SD.\n"); + } + gfx_printf("%kTitlekeys... ", colors[(color_idx++) % 6]); + u32 save_x = gfx_con.x, save_y = gfx_con.y; + gfx_printf("\n"); + + u8 null_hash[0x20] = { + 0xE3, 0xB0, 0xC4, 0x42, 0x98, 0xFC, 0x1C, 0x14, 0x9A, 0xFB, 0xF4, 0xC8, 0x99, 0x6F, 0xB9, 0x24, + 0x27, 0xAE, 0x41, 0xE4, 0x64, 0x9B, 0x93, 0x4C, 0xA4, 0x95, 0x99, 0x1B, 0x78, 0x52, 0xB8, 0x55}; + + se_aes_key_set(8, bis_key[0] + 0x00, 0x10); + se_aes_key_set(9, bis_key[0] + 0x10, 0x10); + + u32 buf_size = 0x80000; + u8 *buffer = (u8 *)malloc(buf_size); + + u8 keypair[0x230] = {0}; + + emummc_storage_read(&storage, 0x4400 / NX_EMMC_BLOCKSIZE, 0x4000 / NX_EMMC_BLOCKSIZE, buffer); + + se_aes_xts_crypt(9, 8, 0, 0, buffer, buffer, 0x4000, 1); + + se_aes_key_set(8, bis_key[2] + 0x00, 0x10); + se_aes_key_set(9, bis_key[2] + 0x10, 0x10); + + if (*(u32 *)buffer != 0x304C4143) { + EPRINTF("CAL0 magic not found. Check BIS key 0."); + free(buffer); + goto dismount; + } + + se_aes_key_set(2, eticket_rsa_kek, 0x10); + se_aes_crypt_ctr(2, keypair, 0x230, buffer + 0x38a0, 0x230, buffer + 0x3890); + + u8 *D = keypair, *N = keypair + 0x100, *E = keypair + 0x200; + + // Check public exponent is 0x10001 big endian + if (E[0] != 0 || E[1] != 1 || E[2] != 0 || E[3] != 1) { + EPRINTF("Invalid public exponent."); + free(buffer); + goto dismount; + } + + if (!_test_key_pair(E, D, N)) { + EPRINTF("Invalid keypair. Check eticket_rsa_kek."); + free(buffer); + goto dismount; + } + + se_rsa_key_set(0, N, 0x100, D, 0x100); + + if (f_stat("emmc:/save/80000000000000E1", &fno)) { + EPRINTF("Unable to stat ES save 1. Skipping."); + free(buffer); + goto dismount; + } + u64 total_size = fno.fsize; + if (f_stat("emmc:/save/80000000000000E2", &fno)) { + EPRINTF("Unable to stat ES save 2. Skipping."); + free(buffer); + goto dismount; + } + total_size += fno.fsize; + u32 br; + u64 total_br = 0; + rights_ids = (u8 *)malloc(0x400000); + titlekeys = (u8 *)malloc(0x400000); + u8 M[0x100]; + if (f_open(&fp, "emmc:/save/80000000000000E1", FA_READ | FA_OPEN_EXISTING)) { + EPRINTF("Unable to open ES save 1. Skipping."); + free(buffer); + goto dismount; + } + f_lseek(&fp, 0x8000); + u32 pct = 0, last_pct = 0; + tui_pbar(save_x, save_y, pct, COLOR_GREEN, 0xFF155500); + + while (!f_read(&fp, buffer, buf_size, &br)) { + total_br += br; + for (u32 i = 0; i < br; i += 0x4000) { + pct = (u32)((total_br + i) * 100 / total_size); + if (pct > last_pct && pct <= 100) { + last_pct = pct; + tui_pbar(save_x, save_y, pct, COLOR_GREEN, 0xFF155500); + } + for (u32 j = i; j < i + 0x4000; j += 0x400) { + minerva_periodic_training(); + if (buffer[j] == 4 && buffer[j+1] == 0 && buffer[j+2] == 1 && buffer[j+3] == 0) { + u32 k = 0; + bool titlekey_found = false; + for (; k < _titlekey_count; k++) { + if (!memcmp(rights_ids + 0x10 * k, buffer + j + 0x2a0, 0x10)) { + titlekey_found = true; + break; + } + } + if (titlekey_found) + continue; + memcpy(rights_ids + 0x10 * _titlekey_count, buffer + j + 0x2a0, 0x10); + memcpy(titlekeys + 0x10 * _titlekey_count, buffer + j + 0x180, 0x10); + _titlekey_count++; + } else { + break; + } + } + } + if (br < buf_size) break; + } + + u32 common_titlekey_count = _titlekey_count; + if (f_open(&fp, "emmc:/save/80000000000000E2", FA_READ | FA_OPEN_EXISTING)) { + EPRINTF("Unable to open ES save 2. Skipping."); + free(buffer); + goto dismount; + } + f_lseek(&fp, 0x8000); + while (!f_read(&fp, buffer, buf_size, &br)) { + total_br += br; + for (u32 i = 0; i < br; i += 0x4000) { + pct = (u32)((total_br + i) * 100 / total_size); + if (pct > last_pct && pct <= 100) { + last_pct = pct; + tui_pbar(save_x, save_y, pct, COLOR_GREEN, 0xFF155500); + } + for (u32 j = i; j < i + 0x4000; j += 0x400) { + minerva_periodic_training(); + if (buffer[j] == 4 && buffer[j+1] == 0 && buffer[j+2] == 1 && buffer[j+3] == 0) { + u32 k = common_titlekey_count; + bool titlekey_found = false; + for (; k < _titlekey_count; k++) { + if (!memcmp(rights_ids + 0x10 * k, buffer + j + 0x2a0, 0x10)) { + titlekey_found = true; + break; + } + } + if (titlekey_found) + continue; + memcpy(rights_ids + 0x10 * _titlekey_count, buffer + j + 0x2a0, 0x10); + + u8 *titlekey_block = buffer + j + 0x180; + se_rsa_exp_mod(0, M, 0x100, titlekey_block, 0x100); + u8 *salt = M + 1; + u8 *db = M + 0x21; + _mgf1_xor(salt, 0x20, db, 0xdf); + _mgf1_xor(db, 0xdf, salt, 0x20); + if (memcmp(db, null_hash, 0x20)) + continue; + memcpy(titlekeys + 0x10 * _titlekey_count, db + 0xcf, 0x10); + _titlekey_count++; + } else { + break; + } + } + } + if (br < buf_size) break; + } + free(buffer); + f_close(&fp); + + gfx_con_setpos(0, save_y); + TPRINTFARGS("\n%k ", colors[(color_idx++) % 6]); + gfx_printf("\n%k Found %d titlekeys.\n", colors[(color_idx++) % 6], _titlekey_count); + dismount: f_mount(NULL, "emmc:", 1); nx_emmc_gpt_free(&gpt); emummc_storage_end(&storage); - // derive eticket_rsa_kek and ssl_rsa_kek - if (_key_exists(es_keys[0]) && _key_exists(es_keys[1]) && _key_exists(master_key[0])) { - for (u32 i = 0; i < 0x10; i++) - temp_key[i] = aes_kek_generation_source[i] ^ aes_kek_seed_03[i]; - _generate_kek(8, es_keys[1], master_key[0], temp_key, NULL); - se_aes_crypt_block_ecb(8, 0, eticket_rsa_kek, es_keys[0]); - } - if (_key_exists(ssl_keys[1]) && _key_exists(es_keys[2]) && _key_exists(master_key[0])) { - for (u32 i = 0; i < 0x10; i++) - temp_key[i] = aes_kek_generation_source[i] ^ aes_kek_seed_01[i]; - _generate_kek(8, es_keys[2], master_key[0], temp_key, NULL); - se_aes_crypt_block_ecb(8, 0, ssl_rsa_kek, ssl_keys[1]); - } - key_output: ; - __attribute__ ((aligned (16))) char text_buffer[0x3000] = {0}; + char *text_buffer = (char *)malloc(_titlekey_count * 68 < 0x3000 ? 0x3000 : _titlekey_count * 68 + 1); SAVE_KEY("aes_kek_generation_source", aes_kek_generation_source, 0x10); SAVE_KEY("aes_key_generation_source", aes_key_generation_source, 0x10); SAVE_KEY("bis_kek_source", bis_kek_source, 0x10); - SAVE_KEY_FAMILY("bis_key", bis_key, 4, 0x20); - SAVE_KEY_FAMILY("bis_key_source", bis_key_source, 3, 0x20); + SAVE_KEY_FAMILY("bis_key", bis_key, 0, 4, 0x20); + SAVE_KEY_FAMILY("bis_key_source", bis_key_source, 0, 3, 0x20); SAVE_KEY("device_key", device_key, 0x10); SAVE_KEY("eticket_rsa_kek", eticket_rsa_kek, 0x10); SAVE_KEY("eticket_rsa_kek_source", es_keys[0], 0x10); @@ -782,26 +967,23 @@ key_output: ; SAVE_KEY("header_kek_source", fs_keys[0], 0x10); SAVE_KEY("header_key", header_key, 0x20); SAVE_KEY("header_key_source", fs_keys[1], 0x20); - SAVE_KEY_FAMILY("key_area_key_application", key_area_key[0], MAX_KEY, 0x10); + SAVE_KEY_FAMILY("key_area_key_application", key_area_key[0], 0, MAX_KEY, 0x10); SAVE_KEY("key_area_key_application_source", fs_keys[2], 0x10); - SAVE_KEY_FAMILY("key_area_key_ocean", key_area_key[1], MAX_KEY, 0x10); + SAVE_KEY_FAMILY("key_area_key_ocean", key_area_key[1], 0, MAX_KEY, 0x10); SAVE_KEY("key_area_key_ocean_source", fs_keys[3], 0x10); - SAVE_KEY_FAMILY("key_area_key_system", key_area_key[2], MAX_KEY, 0x10); + SAVE_KEY_FAMILY("key_area_key_system", key_area_key[2], 0, MAX_KEY, 0x10); SAVE_KEY("key_area_key_system_source", fs_keys[4], 0x10); - SAVE_KEY_FAMILY("keyblob", keyblob, 6, 0x90); - SAVE_KEY_FAMILY("keyblob_key", keyblob_key, 6, 0x10); - SAVE_KEY_FAMILY("keyblob_key_source", keyblob_key_source, 6, 0x10); - SAVE_KEY_FAMILY("keyblob_mac_key", keyblob_mac_key, 6, 0x10); + SAVE_KEY_FAMILY("keyblob", keyblob, 0, 6, 0x90); + SAVE_KEY_FAMILY("keyblob_key", keyblob_key, 0, 6, 0x10); + SAVE_KEY_FAMILY("keyblob_key_source", keyblob_key_source, 0, 6, 0x10); + SAVE_KEY_FAMILY("keyblob_mac_key", keyblob_mac_key, 0, 6, 0x10); SAVE_KEY("keyblob_mac_key_source", keyblob_mac_key_source, 0x10); - SAVE_KEY_FAMILY("master_kek", master_kek, MAX_KEY, 0x10); - SAVE_KEY("master_kek_source_06", master_kek_sources[0], 0x10); - SAVE_KEY("master_kek_source_07", master_kek_sources[1], 0x10); - SAVE_KEY("master_kek_source_08", master_kek_sources[2], 0x10); - SAVE_KEY("master_kek_source_09", master_kek_sources[3], 0x10); - SAVE_KEY_FAMILY("master_key", master_key, MAX_KEY, 0x10); + SAVE_KEY_FAMILY("master_kek", master_kek, 0, MAX_KEY, 0x10); + SAVE_KEY_FAMILY("master_kek_source", master_kek_sources, KB_FIRMWARE_VERSION_620, sizeof(master_kek_sources) / 0x10, 0x10); + SAVE_KEY_FAMILY("master_key", master_key, 0, MAX_KEY, 0x10); SAVE_KEY("master_key_source", master_key_source, 0x10); - SAVE_KEY_FAMILY("package1_key", package1_key, 6, 0x10); - SAVE_KEY_FAMILY("package2_key", package2_key, MAX_KEY, 0x10); + SAVE_KEY_FAMILY("package1_key", package1_key, 0, 6, 0x10); + SAVE_KEY_FAMILY("package2_key", package2_key, 0, MAX_KEY, 0x10); SAVE_KEY("package2_key_source", package2_key_source, 0x10); SAVE_KEY("per_console_key_source", per_console_key_source, 0x10); SAVE_KEY("retail_specific_aes_key_source", retail_specific_aes_key_source, 0x10); @@ -822,7 +1004,7 @@ key_output: ; SAVE_KEY("ssl_rsa_kek", ssl_rsa_kek, 0x10); SAVE_KEY("ssl_rsa_kek_source_x", es_keys[2], 0x10); SAVE_KEY("ssl_rsa_kek_source_y", ssl_keys[1], 0x10); - SAVE_KEY_FAMILY("titlekek", titlekek, MAX_KEY, 0x10); + SAVE_KEY_FAMILY("titlekek", titlekek, 0, MAX_KEY, 0x10); SAVE_KEY("titlekek_source", titlekek_source, 0x10); SAVE_KEY("tsec_key", tsec_keys, 0x10); if (pkg1_id->kb == KB_FIRMWARE_VERSION_620) @@ -831,10 +1013,10 @@ key_output: ; //gfx_con.fntsz = 8; gfx_puts(text_buffer); gfx_con.fntsz = 16; end_time = get_tmr_us(); - gfx_printf("\n%kFound %d keys.", colors[(color_idx++) % 6], _key_count); + gfx_printf("\n%k Found %d keys.\n\n", colors[(color_idx++) % 6], _key_count); _key_count = 0; - gfx_printf("\n%kLockpick totally done in %d us", colors[(color_idx++) % 6], end_time - begin_time); - gfx_printf("\n%kFound through master_key_%02x\n", colors[(color_idx++) % 6], MAX_KEY - 1); + gfx_printf("%kLockpick totally done in %d us\n\n", colors[(color_idx++) % 6], end_time - begin_time); + gfx_printf("%kFound through master_key_%02x.\n\n", colors[(color_idx++) % 6], MAX_KEY - 1); f_mkdir("sd:/switch"); char keyfile_path[30] = "sd:/switch/"; @@ -845,17 +1027,36 @@ key_output: ; if (sd_mount() && !sd_save_to_file(text_buffer, strlen(text_buffer), keyfile_path) && !f_stat(keyfile_path, &fno)) { gfx_printf("%kWrote %d bytes to %s\n", colors[(color_idx++) % 6], (u32)fno.fsize, keyfile_path); } else - EPRINTF("Failed to save keys to SD."); - h_cfg.emummc_force_disable = emummc_load_cfg(); + EPRINTF("Unable to save keys to SD."); + + if (_titlekey_count == 0) + goto out_wait; + memset(text_buffer, 0, _titlekey_count * 68 + 1); + for (u32 i = 0; i < _titlekey_count; i++) { + for (u32 j = 0; j < 0x10; j++) + sprintf(&text_buffer[i * 68 + j * 2], "%02x", rights_ids[i * 0x10 + j]); + sprintf(&text_buffer[i * 68 + 0x20], " = "); + for (u32 j = 0; j < 0x10; j++) + sprintf(&text_buffer[i * 68 + 0x23 + j * 2], "%02x", titlekeys[i * 0x10 + j]); + sprintf(&text_buffer[i * 68 + 0x43], "\n"); + } + sprintf(&keyfile_path[11], "title.keys"); + if (sd_mount() && !sd_save_to_file(text_buffer, strlen(text_buffer), keyfile_path) && !f_stat(keyfile_path, &fno)) { + gfx_printf("%kWrote %d bytes to %s\n", colors[(color_idx++) % 6], (u32)fno.fsize, keyfile_path); + } else + EPRINTF("Unable to save titlekeys to SD."); + free(rights_ids); + free(titlekeys); + free(text_buffer); out_wait: + h_cfg.emummc_force_disable = emummc_load_cfg(); sd_unmount(); gfx_printf("\n%kPress any key to return to the main menu.", colors[(color_idx) % 6], colors[(color_idx + 1) % 6], colors[(color_idx + 2) % 6]); - btn_wait(); } -static void _save_key(const char *name, const void *data, const u32 len, char *outbuf) { +static void _save_key(const char *name, const void *data, u32 len, char *outbuf) { if (!_key_exists(data)) return; u32 pos = strlen(outbuf); @@ -866,9 +1067,9 @@ static void _save_key(const char *name, const void *data, const u32 len, char *o _key_count++; } -static void _save_key_family(const char *name, const void *data, const u32 num_keys, const u32 len, char *outbuf) { +static void _save_key_family(const char *name, const void *data, u32 start_key, u32 num_keys, u32 len, char *outbuf) { char temp_name[0x40] = {0}; - for (u32 i = 0; i < num_keys; i++) { + for (u32 i = start_key; i < num_keys + start_key; i++) { sprintf(temp_name, "%s_%02x", name, i); _save_key(temp_name, data + i * len, len, outbuf); } @@ -950,3 +1151,45 @@ static void _update_ctr(u8 *ctr, u32 ofs) { for (u32 i = 0; i < 4; i++, ofs >>= 8) ctr[0x10-i-1] = (u8)(ofs & 0xff); } + +static bool _test_key_pair(const void *E, const void *D, const void *N) { + u8 X[0x100] = {0}, Y[0x100] = {0}, Z[0x100] = {0}; + + // 0xCAFEBABE + X[0xfc] = 0xca; X[0xfd] = 0xfe; X[0xfe] = 0xba; X[0xff] = 0xbe; + se_rsa_key_set(0, N, 0x100, D, 0x100); + se_rsa_exp_mod(0, Y, 0x100, X, 0x100); + se_rsa_key_set(0, N, 0x100, E, 4); + se_rsa_exp_mod(0, Z, 0x100, Y, 0x100); + + return !memcmp(X, Z, 0x100); +} + +// _mgf1_xor() was derived from Atmosphère's calculate_mgf1_and_xor +static void _mgf1_xor(void *masked, u32 masked_size, const void *seed, u32 seed_size) { + u8 cur_hash[0x20]; + u8 hash_buf[0xe4]; + + u32 hash_buf_size = seed_size + 4; + memcpy(hash_buf, seed, seed_size); + u32 round_num = 0; + + u8 *p_out = (u8 *)masked; + + while (masked_size) { + u32 cur_size = masked_size > 0x20 ? 0x20 : masked_size; + + for (u32 i = 0; i < 4; i++) + hash_buf[seed_size + 3 - i] = (round_num >> (8 * i)) & 0xff; + round_num++; + + se_calc_sha256(cur_hash, hash_buf, hash_buf_size); + + for (unsigned int i = 0; i < cur_size; i++) { + *p_out ^= cur_hash[i]; + p_out++; + } + + masked_size -= cur_size; + } +} diff --git a/source/libs/elfload/elf.h b/source/libs/elfload/elf.h new file mode 100644 index 0000000..196cf87 --- /dev/null +++ b/source/libs/elfload/elf.h @@ -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 + +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 diff --git a/source/libs/elfload/elfarch.h b/source/libs/elfload/elfarch.h new file mode 100644 index 0000000..f1cc388 --- /dev/null +++ b/source/libs/elfload/elfarch.h @@ -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 diff --git a/source/libs/elfload/elfload.c b/source/libs/elfload/elfload.c new file mode 100644 index 0000000..16f8200 --- /dev/null +++ b/source/libs/elfload/elfload.c @@ -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 + +#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; +} diff --git a/source/libs/elfload/elfload.h b/source/libs/elfload/elfload.h new file mode 100644 index 0000000..3a15dc2 --- /dev/null +++ b/source/libs/elfload/elfload.h @@ -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 + +#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 diff --git a/source/libs/elfload/elfreloc_aarch64.c b/source/libs/elfload/elfreloc_aarch64.c new file mode 100644 index 0000000..bbb0ce4 --- /dev/null +++ b/source/libs/elfload/elfreloc_aarch64.c @@ -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 diff --git a/source/libs/elfload/elfreloc_arm.c b/source/libs/elfload/elfreloc_arm.c new file mode 100644 index 0000000..8b905cb --- /dev/null +++ b/source/libs/elfload/elfreloc_arm.c @@ -0,0 +1,66 @@ +/* + * ---------------------------------------------------------------------------- + * "THE BEER-WARE LICENSE" (Revision 42): + * 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 diff --git a/source/libs/fatfs/diskio.c b/source/libs/fatfs/diskio.c index 97f8336..5f48faa 100644 --- a/source/libs/fatfs/diskio.c +++ b/source/libs/fatfs/diskio.c @@ -46,7 +46,7 @@ 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; static u32 secindex = 0; DSTATUS disk_status ( @@ -135,7 +135,15 @@ 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]; @@ -144,6 +152,10 @@ DRESULT disk_read ( u32 tweak_exp = 0; bool regen_tweak = true, cache_sector = false; + if (secindex == 0) { + sector_cache = (sector_cache_t *)malloc(sizeof(sector_cache_t) * MAX_SEC_CACHE_ENTRIES); + } + u32 s = 0; if (count == 1) { for ( ; s < secindex; s++) { @@ -199,7 +211,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 ( diff --git a/source/main.c b/source/main.c index 3fcdef5..26a84a4 100644 --- a/source/main.c +++ b/source/main.c @@ -24,6 +24,7 @@ #include "gfx/tui.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" @@ -165,18 +166,18 @@ void dump_emunand() } ment_t ment_top[] = { - MDEF_HANDLER("Dump keys from SysNAND", dump_sysnand, COLOR_RED), + 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_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 +#define IPL_STACK_TOP 0x90010000//0x4003F000 #define IPL_HEAP_START 0x90020000 extern void pivot_stack(u32 stack_top); @@ -189,6 +190,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); diff --git a/source/mem/minerva.c b/source/mem/minerva.c new file mode 100644 index 0000000..2ac8516 --- /dev/null +++ b/source/mem/minerva.c @@ -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 . + */ + +#include +#include + +#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); + } +} \ No newline at end of file diff --git a/source/mem/minerva.h b/source/mem/minerva.h new file mode 100644 index 0000000..dd71658 --- /dev/null +++ b/source/mem/minerva.h @@ -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 . + */ + +#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 diff --git a/source/mem/mtc_table.h b/source/mem/mtc_table.h new file mode 100644 index 0000000..38a3e2f --- /dev/null +++ b/source/mem/mtc_table.h @@ -0,0 +1,560 @@ +/* + * Minerva Training Cell + * DRAM Training for Tegra X1 SoC. Supports DDR2/3 and LPDDR3/4. + * + * 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 . + */ + +#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 \ No newline at end of file diff --git a/source/sec/se.c b/source/sec/se.c index 6070400..fbd0d4c 100644 --- a/source/sec/se.c +++ b/source/sec/se.c @@ -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; @@ -158,6 +161,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) diff --git a/source/sec/se.h b/source/sec/se.h index 263fe02..434a97a 100644 --- a/source/sec/se.h +++ b/source/sec/se.h @@ -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); diff --git a/source/soc/hw_init.c b/source/soc/hw_init.c index 7cdea95..e343fd0 100644 --- a/source/soc/hw_init.c +++ b/source/soc/hw_init.c @@ -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. diff --git a/source/storage/sdmmc_driver.c b/source/storage/sdmmc_driver.c index 9330eac..96910c8 100644 --- a/source/storage/sdmmc_driver.c +++ b/source/storage/sdmmc_driver.c @@ -32,6 +32,10 @@ //#define DPRINTF(...) gfx_printf(__VA_ARGS__) #define DPRINTF(...) +#pragma GCC push_options +#pragma GCC target ("thumb") +#pragma GCC optimize ("Os") + /*! SCMMC controller base addresses. */ static const u32 _sdmmc_bases[4] = { 0x700B0000, @@ -1146,3 +1150,5 @@ int sdmmc_enable_low_voltage(sdmmc_t *sdmmc) return 0; } + +#pragma GCC pop_options diff --git a/source/utils/util.h b/source/utils/util.h index 7186263..2eb0899 100644 --- a/source/utils/util.h +++ b/source/utils/util.h @@ -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();