diff --git a/Makefile b/Makefile index aae3050..3d70332 100644 --- a/Makefile +++ b/Makefile @@ -9,7 +9,7 @@ include $(DEVKITARM)/base_rules ################################################################################ IPL_LOAD_ADDR := 0x40003000 -LPVERSION_MAJOR := 1 +LPVERSION_MAJOR := 2 LPVERSION_MINOR := 0 LPVERSION_BUGFX := 0 @@ -29,7 +29,7 @@ OBJS = $(patsubst $(SOURCEDIR)/%.S, $(BUILDDIR)/$(TARGET)/%.o, \ CUSTOMDEFINES := -DIPL_LOAD_ADDR=$(IPL_LOAD_ADDR) CUSTOMDEFINES += -DLP_VER_MJ=$(LPVERSION_MAJOR) -DLP_VER_MN=$(LPVERSION_MINOR) -DLP_VER_BF=$(LPVERSION_BUGFX) -ARCH := -march=armv4t -mtune=arm7tdmi -mthumb-interwork +ARCH := -march=armv4t -mtune=arm7tdmi -mthumb -mthumb-interwork CFLAGS = $(ARCH) -O2 -nostdlib -ffunction-sections -fdata-sections -fomit-frame-pointer -std=gnu11 -Wall $(CUSTOMDEFINES) LDFLAGS = $(ARCH) -nostartfiles -lgcc -Wl,--nmagic,--gc-sections -Xlinker --defsym=IPL_LOAD_ADDR=$(IPL_LOAD_ADDR) diff --git a/README.md b/README.md index 5bcfa1d..1e0667f 100644 --- a/README.md +++ b/README.md @@ -10,16 +10,16 @@ Navigate around the menu's using the vol+, vol- and power buttons ## Functions - Navigate the SD card - Navigate the System partition of your sysnand -- Deleting, copying or moving files -- Launching payloads +- Interact with files + - Deleting, copying or moving files + - Launching payloads files + - Viewing the hex data of a file - Dumping your current firmware to sd - -## Screenshot -![screenshot](example.png) +- Formatting the sd card # Credits Based on [Lockpick_RCM](https://github.com/shchmue/Lockpick_RCM), and thus based on [Hekate](https://github.com/CTCaer/hekate) Lots of help from: -shchmue -Denn \ No newline at end of file +- shchmue +- Denn diff --git a/common/common_heap.h b/common/common_heap.h index 41a1973..f609add 100644 --- a/common/common_heap.h +++ b/common/common_heap.h @@ -25,6 +25,7 @@ typedef struct _hnode u32 size; struct _hnode *prev; struct _hnode *next; + u32 align[4]; // Align to arch cache line size. } hnode_t; typedef struct _heap @@ -32,3 +33,9 @@ typedef struct _heap u32 start; hnode_t *first; } heap_t; + +typedef struct +{ + u32 total; + u32 used; +} heap_monitor_t; 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/common/memory_map.h b/common/memory_map.h new file mode 100644 index 0000000..271d9f7 --- /dev/null +++ b/common/memory_map.h @@ -0,0 +1,87 @@ +/* + * 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 _MEMORY_MAP_H_ +#define _MEMORY_MAP_H_ + +//#define IPL_STACK_TOP 0x4003FF00 +/* --- BIT/BCT: 0x40000000 - 0x40003000 --- */ +/* --- IPL: 0x40003000 - 0x40028000 --- */ +#define IPL_LOAD_ADDR 0x40003000 +#define IPL_SZ_MAX 0x20000 // 128KB. +//#define IRAM_LIB_ADDR 0x4002B000 +#define SDRAM_PARAMS_ADDR 0x40030000 // SDRAM extraction buffer during sdram init. +#define CBFS_DRAM_EN_ADDR 0x4003e000 // u32. + +/* --- DRAM START --- */ +#define DRAM_START 0x80000000 +/* Do not write anything in this area */ +#define NYX_LOAD_ADDR 0x81000000 +#define NYX_SZ_MAX 0x1000000 +/* Stack theoretical max: 220MB */ +#define IPL_STACK_TOP 0x90010000 +#define IPL_HEAP_START 0x90020000 +#define IPL_HEAP_SZ 0x24FE0000 // 592MB. +/* --- Gap: 0xB5000000 - 0xB5FFFFFF --- */ + +// SDMMC DMA buffers +#define SDXC_BUF_ALIGNED 0xB6000000 +#define MIXD_BUF_ALIGNED 0xB7000000 +#define EMMC_BUF_ALIGNED MIXD_BUF_ALIGNED +#define SDMMC_DMA_BUF_SZ 0x1000000 // 16MB (4MB currently used). +#define SDMMC_UPPER_BUFFER 0xB8000000 +#define SDMMC_UP_BUF_SZ 0x8000000 // 128MB. + +// Virtual disk / Chainloader buffers. +#define RAM_DISK_ADDR 0xC1000000 +#define RAM_DISK_SZ 0x20000000 +//#define DRAM_LIB_ADDR 0xE0000000 +/* --- Chnldr: 252MB 0xC03C0000 - 0xCFFFFFFF --- */ //! Only used when chainloading. +/* --- Gap: 464MB 0xD0000000 - 0xECFFFFFF --- */ + +// Nyx buffers. +#define NYX_STORAGE_ADDR 0xED000000 +#define NYX_RES_ADDR 0xEE000000 + +// Framebuffer addresses. +#define IPL_FB_ADDRESS 0xF0000000 +#define IPL_FB_SZ 0x384000 // 720 x 1280 x 4. +#define LOG_FB_ADDRESS 0xF0400000 +#define LOG_FB_SZ 0x334000 // 1280 x 656 x 4. +#define NYX_FB_ADDRESS 0xF0800000 +#define NYX_FB_SZ 0x384000 // 1280 x 720 x 4. + +// Nyx LvGL buffers. +#define NYX_LV_VDB_ADR 0xF0C00000 +#define NYX_FB_SZ 0x384000 // 1280 x 720 x 4. +#define NYX_LV_MEM_ADR 0xF1000000 +#define NYX_LV_MEM_SZ 0x8000000 + +// NX BIS driver sector cache. +#define NX_BIS_CACHE_ADDR 0xF9000000 +#define NX_BIS_CACHE_SZ 0x8800 +/* --- Gap: 111MB 0xF9008800 - 0xFFFFFFFF --- */ + +// #define EXT_PAYLOAD_ADDR 0xC03C0000 +// #define RCM_PAYLOAD_ADDR (EXT_PAYLOAD_ADDR + ALIGN(PATCHED_RELOC_SZ, 0x10)) +// #define COREBOOT_ADDR (0xD0000000 - 0x100000) + +// NYX +// #define EXT_PAYLOAD_ADDR 0xC0000000 +// #define RCM_PAYLOAD_ADDR (EXT_PAYLOAD_ADDR + ALIGN(PATCHED_RELOC_SZ, 0x10)) +// #define COREBOOT_ADDR (0xD0000000 - 0x100000) + +#endif diff --git a/example.png b/example.png deleted file mode 100644 index f31f200..0000000 Binary files a/example.png and /dev/null differ diff --git a/source/config/config.c b/source/config/config.c new file mode 100644 index 0000000..38e5bcf --- /dev/null +++ b/source/config/config.c @@ -0,0 +1,666 @@ +/* + * 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 + +#include "config.h" +#include "ini.h" +#include "../gfx/gfx.h" +#include "../gfx/tui.h" +#include "../libs/fatfs/ff.h" +#include "../soc/t210.h" +#include "../storage/sdmmc.h" +#include "../utils/btn.h" +#include "../utils/list.h" +#include "../utils/util.h" + +extern hekate_config h_cfg; +extern bool sd_mount(); +extern void sd_unmount(); + +void set_default_configuration() +{ + h_cfg.autoboot = 0; + h_cfg.autoboot_list = 0; + h_cfg.bootwait = 3; + h_cfg.verification = 1; + h_cfg.se_keygen_done = 0; + h_cfg.sbar_time_keeping = 0; + h_cfg.backlight = 100; + h_cfg.autohosoff = 0; + h_cfg.autonogc = 1; + h_cfg.brand = NULL; + h_cfg.tagline = NULL; + h_cfg.errors = 0; + h_cfg.sept_run = EMC(EMC_SCRATCH0) & EMC_SEPT_RUN; + h_cfg.rcm_patched = true; + h_cfg.emummc_force_disable = false; + + sd_power_cycle_time_start = 0xFFFFFFF; +} + +int create_config_entry() +{ + if (!sd_mount()) + return 1; + + char lbuf[32]; + FIL fp; + bool mainIniFound = false; + + LIST_INIT(ini_sections); + + if (ini_parse(&ini_sections, "bootloader/hekate_ipl.ini", false)) + mainIniFound = true; + else + { + u8 res = f_open(&fp, "bootloader/hekate_ipl.ini", FA_READ); + if (res == FR_NO_FILE || res == FR_NO_PATH) + { + f_mkdir("bootloader"); + f_mkdir("bootloader/ini"); + f_mkdir("bootloader/payloads"); + f_mkdir("bootloader/sys"); + } + else + { + if (!res) + f_close(&fp); + return 1; + } + } + + if (f_open(&fp, "bootloader/hekate_ipl.ini", FA_WRITE | FA_CREATE_ALWAYS) != FR_OK) + return 1; + // Add config entry. + f_puts("[config]\nautoboot=", &fp); + itoa(h_cfg.autoboot, lbuf, 10); + f_puts(lbuf, &fp); + f_puts("\nautoboot_list=", &fp); + itoa(h_cfg.autoboot_list, lbuf, 10); + f_puts(lbuf, &fp); + f_puts("\nbootwait=", &fp); + itoa(h_cfg.bootwait, lbuf, 10); + f_puts(lbuf, &fp); + f_puts("\nverification=", &fp); + itoa(h_cfg.verification, lbuf, 10); + f_puts(lbuf, &fp); + f_puts("\nbacklight=", &fp); + itoa(h_cfg.backlight, lbuf, 10); + f_puts(lbuf, &fp); + f_puts("\nautohosoff=", &fp); + itoa(h_cfg.autohosoff, lbuf, 10); + f_puts(lbuf, &fp); + f_puts("\nautonogc=", &fp); + itoa(h_cfg.autonogc, lbuf, 10); + f_puts(lbuf, &fp); + if (h_cfg.brand) + { + f_puts("\nbrand=", &fp); + f_puts(h_cfg.brand, &fp); + } + if (h_cfg.tagline) + { + f_puts("\ntagline=", &fp); + f_puts(h_cfg.tagline, &fp); + } + f_puts("\n", &fp); + + if (mainIniFound) + { + // Re-construct existing entries. + LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_sections, link) + { + if (!strcmp(ini_sec->name, "config")) + continue; + + switch (ini_sec->type) + { + case INI_CHOICE: // Re-construct Boot entry [ ]. + f_puts("[", &fp); + f_puts(ini_sec->name, &fp); + f_puts("]\n", &fp); + // Re-construct boot entry's config. + LIST_FOREACH_ENTRY(ini_kv_t, kv, &ini_sec->kvs, link) + { + f_puts(kv->key, &fp); + f_puts("=", &fp); + f_puts(kv->val, &fp); + f_puts("\n", &fp); + } + break; + case INI_CAPTION: // Re-construct caption entry { }. + f_puts("{", &fp); + f_puts(ini_sec->name, &fp); + f_puts("}\n", &fp); + break; + case INI_NEWLINE: // Re-construct cosmetic newline \n. + f_puts("\n", &fp); + break; + case INI_COMMENT: // Re-construct comment entry #. + f_puts("#", &fp); + f_puts(ini_sec->name, &fp); + f_puts("\n", &fp); + break; + } + } + } + + f_close(&fp); + sd_unmount(); + + return 0; +} + +#pragma GCC push_options +#pragma GCC optimize ("Os") + +static void _save_config() +{ + gfx_clear_grey(0x1B); + gfx_con_setpos(0, 0); + + if (!create_config_entry()) + gfx_puts("\nConfiguration was saved!\n"); + else + EPRINTF("\nConfiguration saving failed!"); + gfx_puts("\nPress any key..."); +} + +static void _config_autoboot_list(void *ent) +{ + gfx_clear_grey(0x1B); + gfx_con_setpos(0, 0); + + u32 *temp_autoboot = NULL; + + LIST_INIT(ini_sections); + + u8 max_entries = 30; + + ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * (max_entries + 3)); + u32 *boot_values = (u32 *)malloc(sizeof(u32) * max_entries); + char *boot_text = (char *)malloc(512 * max_entries); + + for (u32 j = 0; j < max_entries; j++) + boot_values[j] = j; + + if (sd_mount()) + { + if (ini_parse(&ini_sections, "bootloader/ini", true)) + { + // Build configuration menu. + ments[0].type = MENT_BACK; + ments[0].caption = "Back"; + + ments[1].type = MENT_CHGLINE; + + u32 i = 2; + LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_sections, link) + { + // Skip other ini entries for autoboot. + if (ini_sec->type == INI_CHOICE) + { + if (!strcmp(ini_sec->name, "config")) + continue; + + if (strlen(ini_sec->name) > 510) + ments[i].caption = ini_sec->name; + else + { + if (h_cfg.autoboot != (i - 1) || !h_cfg.autoboot_list) + boot_text[(i - 1) * 512] = ' '; + + else + boot_text[(i - 1) * 512] = '*'; + strcpy(boot_text + (i - 1) * 512 + 1, ini_sec->name); + ments[i].caption = &boot_text[(i - 1) * 512]; + } + ments[i].type = ini_sec->type; + ments[i].data = &boot_values[i - 1]; + i++; + + if ((i - 1) > max_entries) + break; + } + } + + memset(&ments[i], 0, sizeof(ment_t)); + menu_t menu = {ments, "Select an entry to auto boot", 0, 0}; + temp_autoboot = (u32 *)tui_do_menu(&menu); + if (temp_autoboot != NULL) + { + h_cfg.autoboot = *(u32 *)temp_autoboot; + h_cfg.autoboot_list = 1; + _save_config(); + + ment_t *tmp = (ment_t *)ent; + tmp->data = NULL; + } + else + goto out2; + } + else + { + EPRINTF("Could not open 'bootloader/hekate_ipl.ini'.\nMake sure it exists!."); + goto out; + } + } + +out:; + btn_wait(); +out2:; + free(ments); + free(boot_values); + free(boot_text); + + sd_unmount(); +} + +void config_autoboot() +{ + gfx_clear_grey(0x1B); + gfx_con_setpos(0, 0); + + u32 *temp_autoboot = NULL; + + LIST_INIT(ini_sections); + + u8 max_entries = 30; + + ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * (max_entries + 5)); + u32 *boot_values = (u32 *)malloc(sizeof(u32) * max_entries); + char *boot_text = (char *)malloc(512 * max_entries); + + for (u32 j = 0; j < max_entries; j++) + boot_values[j] = j; + + if (sd_mount()) + { + if (ini_parse(&ini_sections, "bootloader/hekate_ipl.ini", false)) + { + // Build configuration menu. + ments[0].type = MENT_BACK; + ments[0].caption = "Back"; + + ments[1].type = MENT_CHGLINE; + + ments[2].type = MENT_DATA; + if (!h_cfg.autoboot) + ments[2].caption = "*Disable"; + else + ments[2].caption = " Disable"; + ments[2].data = &boot_values[0]; + + ments[3].type = MENT_HDLR_RE; + if (h_cfg.autoboot_list) + ments[3].caption = "*More configs..."; + else + ments[3].caption = " More configs..."; + ments[3].handler = _config_autoboot_list; + ments[3].data = (void *)0xCAFE; + + ments[4].type = MENT_CHGLINE; + + u32 i = 5; + LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_sections, link) + { + // Skip other ini entries for autoboot. + if (ini_sec->type == INI_CHOICE) + { + if (!strcmp(ini_sec->name, "config")) + continue; + + if (strlen(ini_sec->name) > 510) + ments[i].caption = ini_sec->name; + else + { + if (h_cfg.autoboot != (i - 4) || h_cfg.autoboot_list) + boot_text[(i - 4) * 512] = ' '; + + else + boot_text[(i - 4) * 512] = '*'; + strcpy(boot_text + (i - 4) * 512 + 1, ini_sec->name); + ments[i].caption = &boot_text[(i - 4) * 512]; + } + ments[i].type = ini_sec->type; + ments[i].data = &boot_values[i - 4]; + i++; + + if ((i - 4) > max_entries) + break; + } + } + if (i < 6 && !h_cfg.autoboot_list) + { + ments[i].type = MENT_CAPTION; + ments[i].caption = "No main configurations found..."; + ments[i].color = 0xFFFFDD00; + i++; + } + + memset(&ments[i], 0, sizeof(ment_t)); + menu_t menu = {ments, "Disable or select entry to auto boot", 0, 0}; + temp_autoboot = (u32 *)tui_do_menu(&menu); + if (temp_autoboot != NULL) + { + h_cfg.autoboot = *(u32 *)temp_autoboot; + h_cfg.autoboot_list = 0; + _save_config(); + } + else + goto out2; + } + else + { + EPRINTF("Could not open 'bootloader/hekate_ipl.ini'.\nMake sure it exists!."); + goto out; + } + } + +out:; + btn_wait(); +out2:; + free(ments); + free(boot_values); + free(boot_text); + + sd_unmount(); + + if (temp_autoboot == NULL) + return; +} + +void config_bootdelay() +{ + gfx_clear_grey(0x1B); + gfx_con_setpos(0, 0); + + u32 delay_entries = 6; + + ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * (delay_entries + 3)); + u32 *delay_values = (u32 *)malloc(sizeof(u32) * delay_entries); + char *delay_text = (char *)malloc(32 * delay_entries); + + for (u32 j = 0; j < delay_entries; j++) + delay_values[j] = j; + + ments[0].type = MENT_BACK; + ments[0].caption = "Back"; + + ments[1].type = MENT_CHGLINE; + + ments[2].type = MENT_DATA; + if (h_cfg.bootwait) + ments[2].caption = " 0 seconds (Bootlogo disabled)"; + else + ments[2].caption = "*0 seconds (Bootlogo disabled)"; + ments[2].data = &delay_values[0]; + + u32 i = 0; + for (i = 1; i < delay_entries; i++) + { + if (h_cfg.bootwait != i) + delay_text[i * 32] = ' '; + else + delay_text[i * 32] = '*'; + delay_text[i * 32 + 1] = i + '0'; + strcpy(delay_text + i * 32 + 2, " seconds"); + + ments[i + 2].type = MENT_DATA; + ments[i + 2].caption = delay_text + i * 32; + ments[i + 2].data = &delay_values[i]; + } + + memset(&ments[i + 2], 0, sizeof(ment_t)); + menu_t menu = {ments, "Time delay for entering bootloader menu", 0, 0}; + + u32 *temp_bootwait = (u32 *)tui_do_menu(&menu); + if (temp_bootwait != NULL) + { + h_cfg.bootwait = *(u32 *)temp_bootwait; + _save_config(); + } + + free(ments); + free(delay_values); + free(delay_text); + + if (temp_bootwait == NULL) + return; + btn_wait(); +} + +void config_verification() +{ + gfx_clear_grey(0x1B); + gfx_con_setpos(0, 0); + + ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * 6); + u32 *vr_values = (u32 *)malloc(sizeof(u32) * 3); + char *vr_text = (char *)malloc(64 * 3); + + for (u32 j = 0; j < 3; j++) + { + vr_values[j] = j; + ments[j + 2].type = MENT_DATA; + ments[j + 2].data = &vr_values[j]; + } + + ments[0].type = MENT_BACK; + ments[0].caption = "Back"; + + ments[1].type = MENT_CHGLINE; + + strcpy(vr_text, " Disable (Fastest - Unsafe)"); + strcpy(vr_text + 64, " Sparse (Fast - Safe)"); + strcpy(vr_text + 128, " Full (Slow - Safe)"); + + for (u32 i = 0; i < 3; i++) + { + if (h_cfg.verification != i) + vr_text[64 * i] = ' '; + else + vr_text[64 * i] = '*'; + ments[2 + i].caption = vr_text + (i * 64); + } + + memset(&ments[5], 0, sizeof(ment_t)); + menu_t menu = {ments, "Backup & Restore verification", 0, 0}; + + u32 *temp_verification = (u32 *)tui_do_menu(&menu); + if (temp_verification != NULL) + { + h_cfg.verification = *(u32 *)temp_verification; + _save_config(); + } + + free(ments); + free(vr_values); + free(vr_text); + + if (temp_verification == NULL) + return; + btn_wait(); +} + +void config_backlight() +{ + gfx_clear_grey(0x1B); + gfx_con_setpos(0, 0); + + u32 bri_entries = 11; + + ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * (bri_entries + 3)); + u32 *bri_values = (u32 *)malloc(sizeof(u32) * bri_entries); + char *bri_text = (char *)malloc(8 * bri_entries); + + for (u32 j = 1; j < bri_entries; j++) + bri_values[j] = j * 10; + + ments[0].type = MENT_BACK; + ments[0].caption = "Back"; + + ments[1].type = MENT_CHGLINE; + + u32 i = 0; + for (i = 1; i < bri_entries; i++) + { + if ((h_cfg.backlight / 20) != i) + bri_text[i * 32] = ' '; + else + bri_text[i * 32] = '*'; + + if (i < 10) + { + bri_text[i * 32 + 1] = i + '0'; + strcpy(bri_text + i * 32 + 2, "0%"); + } + else + strcpy(bri_text + i * 32 + 1, "100%"); + + ments[i + 1].type = MENT_DATA; + ments[i + 1].caption = bri_text + i * 32; + ments[i + 1].data = &bri_values[i]; + } + + memset(&ments[i + 1], 0, sizeof(ment_t)); + menu_t menu = {ments, "Backlight brightness", 0, 0}; + + u32 *temp_backlight = (u32 *)tui_do_menu(&menu); + if (temp_backlight != NULL) + { + h_cfg.backlight = (*(u32 *)temp_backlight) * 2; + _save_config(); + } + + free(ments); + free(bri_values); + free(bri_text); + + if (temp_backlight == NULL) + return; + btn_wait(); +} + +void config_auto_hos_poweroff() +{ + gfx_clear_grey(0x1B); + gfx_con_setpos(0, 0); + + ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * 6); + u32 *hp_values = (u32 *)malloc(sizeof(u32) * 3); + + for (u32 j = 0; j < 3; j++) + { + hp_values[j] = j; + ments[j + 2].type = MENT_DATA; + ments[j + 2].data = &hp_values[j]; + } + + ments[0].type = MENT_BACK; + ments[0].caption = "Back"; + + ments[1].type = MENT_CHGLINE; + + if (h_cfg.autohosoff == 1) + { + ments[2].caption = " Disable"; + ments[3].caption = "*Enable"; + ments[4].caption = " Enable (No logo)"; + } + else if (h_cfg.autohosoff >= 2) + { + ments[2].caption = " Disable"; + ments[3].caption = " Enable"; + ments[4].caption = "*Enable (No logo)"; + } + else + { + ments[2].caption = "*Disable"; + ments[3].caption = " Enable"; + ments[4].caption = " Enable (No logo)"; + } + + memset(&ments[5], 0, sizeof(ment_t)); + menu_t menu = {ments, "Power off if woke up from HOS", 0, 0}; + + u32 *temp_autohosoff = (u32 *)tui_do_menu(&menu); + if (temp_autohosoff != NULL) + { + h_cfg.autohosoff = *(u32 *)temp_autohosoff; + _save_config(); + } + + free(ments); + free(hp_values); + + if (temp_autohosoff == NULL) + return; + btn_wait(); +} + +void config_nogc() +{ + gfx_clear_grey(0x1B); + gfx_con_setpos(0, 0); + + ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * 5); + u32 *cb_values = (u32 *)malloc(sizeof(u32) * 2); + + for (u32 j = 0; j < 2; j++) + { + cb_values[j] = j; + ments[j + 2].type = MENT_DATA; + ments[j + 2].data = &cb_values[j]; + } + + ments[0].type = MENT_BACK; + ments[0].caption = "Back"; + + ments[1].type = MENT_CHGLINE; + + if (h_cfg.autonogc) + { + ments[2].caption = " Disable"; + ments[3].caption = "*Auto"; + } + else + { + ments[2].caption = "*Disable"; + ments[3].caption = " Auto"; + } + + memset(&ments[4], 0, sizeof(ment_t)); + menu_t menu = {ments, "No Gamecard", 0, 0}; + + u32 *temp_nogc = (u32 *)tui_do_menu(&menu); + if (temp_nogc != NULL) + { + h_cfg.autonogc = *(u32 *)temp_nogc; + _save_config(); + } + + free(ments); + free(cb_values); + + if (temp_nogc == NULL) + return; + btn_wait(); +} + +#pragma GCC pop_options diff --git a/source/config/config.h b/source/config/config.h new file mode 100644 index 0000000..8cd34e1 --- /dev/null +++ b/source/config/config.h @@ -0,0 +1,57 @@ +/* + * 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 . + */ + +#ifndef _CONFIG_H_ +#define _CONFIG_H_ + +#include "../utils/types.h" + +typedef struct _hekate_config +{ + // Non-volatile config. + u32 autoboot; + u32 autoboot_list; + u32 bootwait; + u32 verification; + u32 backlight; + u32 autohosoff; + u32 autonogc; + char *brand; + char *tagline; + // Global temporary config. + bool se_keygen_done; + bool sept_run; + bool emummc_force_disable; + bool rcm_patched; + u32 sbar_time_keeping; + u32 errors; +} hekate_config; + +typedef enum +{ + ERR_LIBSYS_LP0 = (1 << 0), +} hsysmodule_t; + +void set_default_configuration(); +int create_config_entry(); +void config_autoboot(); +void config_bootdelay(); +void config_verification(); +void config_backlight(); +void config_auto_hos_poweroff(); +void config_nogc(); + +#endif /* _CONFIG_H_ */ diff --git a/source/config/ini.c b/source/config/ini.c new file mode 100644 index 0000000..e807aec --- /dev/null +++ b/source/config/ini.c @@ -0,0 +1,193 @@ +/* + * Copyright (c) 2018 naehrwert + * Copyright (c) 2018-2019 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include + +#include "ini.h" +#include "../libs/fatfs/ff.h" +#include "../mem/heap.h" +#include "../utils/dirlist.h" + +static char *_strdup(char *str) +{ + if (!str) + return NULL; + + // Remove starting space. + if (str[0] == ' ' && strlen(str)) + str++; + + char *res = (char *)malloc(strlen(str) + 1); + strcpy(res, str); + + // Remove trailing space. + if (strlen(res) && res[strlen(res) - 1] == ' ') + res[strlen(res) - 1] = 0; + + return res; +} + +u32 _find_section_name(char *lbuf, u32 lblen, char schar) +{ + u32 i; + for (i = 0; i < lblen && lbuf[i] != schar && lbuf[i] != '\n' && lbuf[i] != '\r'; i++) + ; + lbuf[i] = 0; + + return i; +} + +ini_sec_t *_ini_create_section(link_t *dst, ini_sec_t *csec, char *name, u8 type) +{ + if (csec) + { + list_append(dst, &csec->link); + csec = NULL; + } + + csec = (ini_sec_t *)malloc(sizeof(ini_sec_t)); + csec->name = _strdup(name); + csec->type = type; + + return csec; +} + +int ini_parse(link_t *dst, char *ini_path, bool is_dir) +{ + u32 lblen; + u32 pathlen = strlen(ini_path); + u32 k = 0; + char lbuf[512]; + char *filelist = NULL; + FIL fp; + ini_sec_t *csec = NULL; + + char *filename = (char *)malloc(256); + + strcpy(filename, ini_path); + + // Get all ini filenames. + if (is_dir) + { + filelist = dirlist(filename, "*.ini", false); + if (!filelist) + { + free(filename); + return 0; + } + strcpy(filename + pathlen, "/"); + pathlen++; + } + + do + { + // Copy ini filename in path string. + if (is_dir) + { + if (filelist[k * 256]) + { + strcpy(filename + pathlen, &filelist[k * 256]); + k++; + } + else + break; + } + + // Open ini. + if (f_open(&fp, filename, FA_READ) != FR_OK) + { + free(filelist); + free(filename); + + return 0; + } + + do + { + // Fetch one line. + lbuf[0] = 0; + f_gets(lbuf, 512, &fp); + lblen = strlen(lbuf); + + // Remove trailing newline. + if (lbuf[lblen - 1] == '\n' || lbuf[lblen - 1] == '\r') + lbuf[lblen - 1] = 0; + + if (lblen > 2 && lbuf[0] == '[') // Create new section. + { + _find_section_name(lbuf, lblen, ']'); + + csec = _ini_create_section(dst, csec, &lbuf[1], INI_CHOICE); + list_init(&csec->kvs); + } + else if (lblen > 2 && lbuf[0] == '{') //Create new caption. + { + _find_section_name(lbuf, lblen, '}'); + + csec = _ini_create_section(dst, csec, &lbuf[1], INI_CAPTION); + csec->color = 0xFF0AB9E6; + } + else if (lblen > 2 && lbuf[0] == '#') //Create empty lines and comments. + { + _find_section_name(lbuf, lblen, '\0'); + + csec = _ini_create_section(dst, csec, &lbuf[1], INI_COMMENT); + } + else if (lblen < 2) + { + csec = _ini_create_section(dst, csec, NULL, INI_NEWLINE); + } + else if (csec && csec->type == INI_CHOICE) //Extract key/value. + { + u32 i = _find_section_name(lbuf, lblen, '='); + + ini_kv_t *kv = (ini_kv_t *)malloc(sizeof(ini_kv_t)); + kv->key = _strdup(&lbuf[0]); + kv->val = _strdup(&lbuf[i + 1]); + list_append(&csec->kvs, &kv->link); + } + } while (!f_eof(&fp)); + + f_close(&fp); + + if (csec) + { + list_append(dst, &csec->link); + if (is_dir) + csec = NULL; + } + } while (is_dir); + + free(filename); + free(filelist); + + return 1; +} + +char *ini_check_payload_section(ini_sec_t *cfg) +{ + if (cfg == NULL) + return NULL; + + LIST_FOREACH_ENTRY(ini_kv_t, kv, &cfg->kvs, link) + { + if (!strcmp("payload", kv->key)) + return kv->val; + } + + return NULL; +} diff --git a/source/config/ini.h b/source/config/ini.h new file mode 100644 index 0000000..dffbe86 --- /dev/null +++ b/source/config/ini.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2018 naehrwert + * Copyright (c) 2018 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef _INI_H_ +#define _INI_H_ + +#include "../utils/types.h" +#include "../utils/list.h" + +#define INI_CHOICE 3 +#define INI_CAPTION 5 +#define INI_CHGLINE 6 +#define INI_NEWLINE 0xFE +#define INI_COMMENT 0xFF + +typedef struct _ini_kv_t +{ + char *key; + char *val; + link_t link; +} ini_kv_t; + +typedef struct _ini_sec_t +{ + char *name; + link_t kvs; + link_t link; + u32 type; + u32 color; +} ini_sec_t; + +int ini_parse(link_t *dst, char *ini_path, bool is_dir); +char *ini_check_payload_section(ini_sec_t *cfg); + +#endif + diff --git a/source/gfx/di.c b/source/gfx/di.c index 5710ef1..200d412 100644 --- a/source/gfx/di.c +++ b/source/gfx/di.c @@ -18,15 +18,16 @@ #include #include "di.h" -#include "../soc/t210.h" -#include "../utils/util.h" -#include "../soc/i2c.h" -#include "../soc/pmc.h" +#include "../gfx/gfx.h" #include "../power/max77620.h" #include "../power/max7762x.h" -#include "../soc/gpio.h" -#include "../soc/pinmux.h" #include "../soc/clock.h" +#include "../soc/gpio.h" +#include "../soc/i2c.h" +#include "../soc/pinmux.h" +#include "../soc/pmc.h" +#include "../soc/t210.h" +#include "../utils/util.h" #include "di.inl" @@ -46,54 +47,61 @@ void display_init() max77620_regulator_set_volt_and_flags(REGULATOR_LDO0, 1200000, MAX77620_POWER_MODE_NORMAL); // Configure to 1.2V. i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_GPIO7, MAX77620_CNFG_GPIO_OUTPUT_VAL_HIGH | MAX77620_CNFG_GPIO_DRV_PUSHPULL); - // Enable MIPI CAL, DSI, DISP1, HOST1X, UART_FST_MIPI_CAL, DSIA LP clocks. - CLOCK(CLK_RST_CONTROLLER_RST_DEV_H_CLR) = 0x1010000; - CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) = 0x1010000; - CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_CLR) = 0x18000000; - CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_SET) = 0x18000000; - CLOCK(CLK_RST_CONTROLLER_CLK_ENB_X_SET) = 0x20000; - CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_UART_FST_MIP_CAL) = 0xA; - CLOCK(CLK_RST_CONTROLLER_CLK_ENB_W_SET) = 0x80000; - CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_DSIA_LP) = 0xA; + // Enable Display Interface specific clocks. + CLOCK(CLK_RST_CONTROLLER_RST_DEV_H_CLR) = 0x1010000; // Clear reset DSI, MIPI_CAL. + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) = 0x1010000; // Set enable clock DSI, MIPI_CAL. - // DPD idle. + CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_CLR) = 0x18000000; // Clear reset DISP1, HOST1X. + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_SET) = 0x18000000; // Set enable clock DISP1, HOST1X. + + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_X_SET) = 0x20000; // Set enable clock UART_FST_MIPI_CAL. + CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_UART_FST_MIPI_CAL) = 10; // Set PLLP_OUT3 and div 6 (17MHz). + + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_W_SET) = 0x80000; // Set enable clock DSIA_LP. + CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_DSIA_LP) = 10; // Set PLLP_OUT and div 6 (68MHz). + + // Disable deap power down. PMC(APBDEV_PMC_IO_DPD_REQ) = 0x40000000; PMC(APBDEV_PMC_IO_DPD2_REQ) = 0x40000000; - // Config pins. + // Config LCD and Backlight pins. PINMUX_AUX(PINMUX_AUX_NFC_EN) &= ~PINMUX_TRISTATE; PINMUX_AUX(PINMUX_AUX_NFC_INT) &= ~PINMUX_TRISTATE; PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) &= ~PINMUX_TRISTATE; PINMUX_AUX(PINMUX_AUX_LCD_BL_EN) &= ~PINMUX_TRISTATE; PINMUX_AUX(PINMUX_AUX_LCD_RST) &= ~PINMUX_TRISTATE; - gpio_config(GPIO_PORT_I, GPIO_PIN_0 | GPIO_PIN_1, GPIO_MODE_GPIO); // Backlight +-5V. - gpio_output_enable(GPIO_PORT_I, GPIO_PIN_0 | GPIO_PIN_1, GPIO_OUTPUT_ENABLE); // Backlight +-5V. + // Set Backlight +-5V pins mode and direction + gpio_config(GPIO_PORT_I, GPIO_PIN_0 | GPIO_PIN_1, GPIO_MODE_GPIO); + gpio_output_enable(GPIO_PORT_I, GPIO_PIN_0 | GPIO_PIN_1, GPIO_OUTPUT_ENABLE); + + // Enable Backlight power. gpio_write(GPIO_PORT_I, GPIO_PIN_0, GPIO_HIGH); // Backlight +5V enable. - usleep(10000); - gpio_write(GPIO_PORT_I, GPIO_PIN_1, GPIO_HIGH); // Backlight -5V enable. - usleep(10000); - gpio_config(GPIO_PORT_V, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2, GPIO_MODE_GPIO); // Backlight PWM, Enable, Reset. + // Configure Backlight pins (PWM, EN, RST). + gpio_config(GPIO_PORT_V, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2, GPIO_MODE_GPIO); gpio_output_enable(GPIO_PORT_V, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2, GPIO_OUTPUT_ENABLE); - gpio_write(GPIO_PORT_V, GPIO_PIN_1, GPIO_HIGH); // Backlight Enable enable. + gpio_write(GPIO_PORT_V, GPIO_PIN_1, GPIO_HIGH); // Enable Backlight EN. - // Config display interface and display. + // Power up supply regulator for display interface. MIPI_CAL(MIPI_CAL_MIPI_BIAS_PAD_CFG2) = 0; + // Set DISP1 clock source and parrent clock. exec_cfg((u32 *)CLOCK_BASE, _display_config_1, 4); + + // Setup display communication interfaces. exec_cfg((u32 *)DISPLAY_A_BASE, _display_config_2, 94); exec_cfg((u32 *)DSI_BASE, _display_config_3, 61); - usleep(10000); - gpio_write(GPIO_PORT_V, GPIO_PIN_2, GPIO_HIGH); // Backlight Reset enable. - + // Enable Backlight Reset. + gpio_write(GPIO_PORT_V, GPIO_PIN_2, GPIO_HIGH); usleep(60000); + // Setups DSI packet configuration and request display id. DSI(_DSIREG(DSI_BTA_TIMING)) = 0x50204; DSI(_DSIREG(DSI_WR_DATA)) = 0x337; // MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE DSI(_DSIREG(DSI_TRIGGER)) = DSI_TRIGGER_HOST; @@ -122,19 +130,22 @@ void display_init() usleep(20000); + // Configure PLLD for DISP1. exec_cfg((u32 *)CLOCK_BASE, _display_config_6, 3); + + // Finalize DSI configuration. exec_cfg((u32 *)DSI_BASE, _display_config_5, 21); DISPLAY_A(_DIREG(DC_DISP_DISP_CLOCK_CONTROL)) = 4; exec_cfg((u32 *)DSI_BASE, _display_config_7, 10); - usleep(10000); + // Calibrate display communication pads. exec_cfg((u32 *)MIPI_CAL_BASE, _display_config_8, 6); exec_cfg((u32 *)DSI_BASE, _display_config_9, 4); exec_cfg((u32 *)MIPI_CAL_BASE, _display_config_10, 16); - usleep(10000); + // Enable video display controller. exec_cfg((u32 *)DISPLAY_A_BASE, _display_config_11, 113); } @@ -142,11 +153,10 @@ void display_backlight_pwm_init() { clock_enable_pwm(); - PWM(PWM_CONTROLLER_PWM_CSR_0) = (1 << 31); // Enable PWM + PWM(PWM_CONTROLLER_PWM_CSR_0) = PWM_CSR_EN; // Enable PWM and set it to 25KHz PFM. - PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) = (PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) >> 2) << 2 | 1; // PWM clock source. + PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) = (PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) & 0xFFFFFFFC) | 1; // PWM clock source. gpio_config(GPIO_PORT_V, GPIO_PIN_0, GPIO_MODE_SPIO); // Backlight power mode. - } void display_backlight(bool enable) @@ -167,7 +177,7 @@ void display_backlight_brightness(u32 brightness, u32 step_delay) { for (u32 i = old_value; i < brightness + 1; i++) { - PWM(PWM_CONTROLLER_PWM_CSR_0) = (1 << 31) | (i << 16); // Enable PWM + PWM(PWM_CONTROLLER_PWM_CSR_0) = PWM_CSR_EN | (i << 16); // Enable PWM and set it to 25KHz PFM. usleep(step_delay); } } @@ -175,7 +185,7 @@ void display_backlight_brightness(u32 brightness, u32 step_delay) { for (u32 i = old_value; i > brightness; i--) { - PWM(PWM_CONTROLLER_PWM_CSR_0) = (1 << 31) | (i << 16); // Enable PWM + PWM(PWM_CONTROLLER_PWM_CSR_0) = PWM_CSR_EN | (i << 16); // Enable PWM and set it to 25KHz PFM. usleep(step_delay); } } @@ -191,13 +201,14 @@ void display_end() DSI(_DSIREG(DSI_WR_DATA)) = 0x2805; // MIPI_DCS_SET_DISPLAY_OFF DISPLAY_A(_DIREG(DC_CMD_STATE_ACCESS)) = READ_MUX | WRITE_MUX; - DSI(_DSIREG(DSI_VIDEO_MODE_CONTROL)) = 0; + DSI(_DSIREG(DSI_VIDEO_MODE_CONTROL)) = 0; // Disable host cmd packet. + // De-initialize video controller. exec_cfg((u32 *)DISPLAY_A_BASE, _display_config_12, 17); exec_cfg((u32 *)DSI_BASE, _display_config_13, 16); - usleep(10000); + // De-initialize display panel. if (_display_ver == 0x10) exec_cfg((u32 *)DSI_BASE, _display_config_14, 22); @@ -206,31 +217,31 @@ void display_end() usleep(50000); + // Disable display and backlight pins. gpio_write(GPIO_PORT_V, GPIO_PIN_2, GPIO_LOW); //Backlight Reset disable. - usleep(10000); gpio_write(GPIO_PORT_I, GPIO_PIN_1, GPIO_LOW); //Backlight -5V disable. - usleep(10000); gpio_write(GPIO_PORT_I, GPIO_PIN_0, GPIO_LOW); //Backlight +5V disable. - usleep(10000); - // Disable clocks. - CLOCK(CLK_RST_CONTROLLER_RST_DEV_H_SET) = 0x1010000; - CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_CLR) = 0x1010000; - CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = 0x18000000; - CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_CLR) = 0x18000000; + // Disable Display Interface specific clocks. + CLOCK(CLK_RST_CONTROLLER_RST_DEV_H_SET) = 0x1010000; // Set reset clock DSI, MIPI_CAL. + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_CLR) = 0x1010000; // Clear enable clock DSI, MIPI_CAL. + CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = 0x18000000; // Set reset DISP1, HOST1X. + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_CLR) = 0x18000000; // Clear enable DISP1, HOST1X. + // Power down pads. DSI(_DSIREG(DSI_PAD_CONTROL_0)) = DSI_PAD_CONTROL_VS1_PULLDN_CLK | DSI_PAD_CONTROL_VS1_PULLDN(0xF) | DSI_PAD_CONTROL_VS1_PDIO_CLK | DSI_PAD_CONTROL_VS1_PDIO(0xF); DSI(_DSIREG(DSI_POWER_CONTROL)) = 0; + // Switch to automatic function mode. gpio_config(GPIO_PORT_V, GPIO_PIN_0, GPIO_MODE_SPIO); // Backlight PWM. PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) = (PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) & ~PINMUX_TRISTATE) | PINMUX_TRISTATE; - PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) = (PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) >> 2) << 2 | 1; + PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) = (PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) & 0xFFFFFFFC)| 1; } void display_color_screen(u32 color) @@ -243,7 +254,6 @@ void display_color_screen(u32 color) DISPLAY_A(_DIREG(DC_WIN_CD_WIN_OPTIONS)) = 0; DISPLAY_A(_DIREG(DC_DISP_BLEND_BACKGROUND_COLOR)) = color; DISPLAY_A(_DIREG(DC_CMD_STATE_CONTROL)) = (DISPLAY_A(_DIREG(DC_CMD_STATE_CONTROL)) & 0xFFFFFFFE) | GENERAL_ACT_REQ; - usleep(35000); display_backlight(true); @@ -252,11 +262,12 @@ void display_color_screen(u32 color) u32 *display_init_framebuffer() { // Sanitize framebuffer area. - memset((u32 *)0xC0000000, 0, 0x3C0000); - // This configures the framebuffer @ 0xC0000000 with a resolution of 1280x720 (line stride 768). - exec_cfg((u32 *)DISPLAY_A_BASE, cfg_display_framebuffer, 32); + memset((u32 *)IPL_FB_ADDRESS, 0, 0x3C0000); + // This configures the framebuffer @ IPL_FB_ADDRESS with a resolution of 1280x720 (line stride 720). + exec_cfg((u32 *)DISPLAY_A_BASE, cfg_display_framebuffer, 32); usleep(35000); - return (u32 *)0xC0000000; + return (u32 *)IPL_FB_ADDRESS; } + diff --git a/source/gfx/di.h b/source/gfx/di.h index 898029d..ee796a7 100644 --- a/source/gfx/di.h +++ b/source/gfx/di.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2018 naehrwert - * Copyright (C) 2018 CTCaer + * 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, @@ -18,6 +18,7 @@ #ifndef _DI_H_ #define _DI_H_ +#include "../../common/memory_map.h" #include "../utils/types.h" /*! Display registers. */ @@ -233,7 +234,7 @@ #define UV_LINE_STRIDE(x) (((x) & 0xffff) << 16) #define DC_WIN_DV_CONTROL 0x70E -// The following registers are A/B/C shadows of the 0xBC0/0xDC0/0xFC0 registers (see DISPLAY_WINDOW_HEADER). +/*! The following registers are A/B/C shadows of the 0xBC0/0xDC0/0xFC0 registers (see DISPLAY_WINDOW_HEADER). */ #define DC_WINBUF_START_ADDR 0x800 #define DC_WINBUF_ADDR_H_OFFSET 0x806 #define DC_WINBUF_ADDR_V_OFFSET 0x808 @@ -333,7 +334,7 @@ #define DSI_PAD_CONTROL_VS1_PDIO_CLK (1 << 8) #define DSI_PAD_CONTROL_VS1_PDIO(x) (((x) & 0xf) << 0) -#define DSI_PAD_CONTROL_CD 0x4c +#define DSI_PAD_CONTROL_CD 0x4C #define DSI_VIDEO_MODE_CONTROL 0x4E #define DSI_PAD_CONTROL_1 0x4F diff --git a/source/gfx/di.inl b/source/gfx/di.inl index 3d2471b..dd82899 100644 --- a/source/gfx/di.inl +++ b/source/gfx/di.inl @@ -1,6 +1,6 @@ /* * Copyright (c) 2018 naehrwert -* Copyright (C) 2018 CTCaer +* 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, @@ -122,7 +122,7 @@ static const cfg_op_t _display_config_2[94] = { {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT}, {DC_WIN_WIN_OPTIONS, 0}, {DC_DISP_DISP_WIN_OPTIONS, 0}, - {DC_CMD_DISPLAY_COMMAND, 0}, + {DC_CMD_DISPLAY_COMMAND, DISP_CTRL_MODE_STOP}, {DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE | WIN_B_UPDATE | WIN_C_UPDATE}, {DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ | WIN_B_ACT_REQ | WIN_C_ACT_REQ} }; @@ -405,7 +405,7 @@ static const cfg_op_t _display_config_11[113] = { {DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT}, {DC_WIN_WIN_OPTIONS, 0}, {DC_DISP_DISP_WIN_OPTIONS, 0}, - {DC_CMD_DISPLAY_COMMAND, 0}, + {DC_CMD_DISPLAY_COMMAND, DISP_CTRL_MODE_STOP}, {DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE | WIN_B_UPDATE | WIN_C_UPDATE}, {DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ | WIN_B_ACT_REQ | WIN_C_ACT_REQ}, {DC_CMD_STATE_ACCESS, 0}, @@ -415,7 +415,7 @@ static const cfg_op_t _display_config_11[113] = { {DC_DISP_SYNC_WIDTH, 0x10048}, {DC_DISP_BACK_PORCH, 0x90048}, {DC_DISP_ACTIVE, 0x50002D0}, - {DC_DISP_FRONT_PORCH, 0xA0088}, // Sources say that this should be above the DC_DISP_ACTIVE cmd. + {DC_DISP_FRONT_PORCH, 0xA0088}, // Sources say that this should be above the DC_DISP_ACTIVE cmd. /* End of Display timings */ {DC_DISP_SHIFT_CLOCK_OPTIONS, SC1_H_QUALIFIER_NONE | SC0_H_QUALIFIER_NONE}, {DC_COM_PIN_OUTPUT_ENABLE(1), 0}, @@ -455,7 +455,7 @@ static const cfg_op_t _display_config_12[17] = { {DC_CMD_STATE_ACCESS, 0}, {DC_CMD_INT_ENABLE, 0}, {DC_CMD_CONT_SYNCPT_VSYNC, 0}, - {DC_CMD_DISPLAY_COMMAND, 0}, + {DC_CMD_DISPLAY_COMMAND, DISP_CTRL_MODE_STOP}, {DC_CMD_STATE_CONTROL, GENERAL_UPDATE}, {DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ}, {DC_CMD_STATE_CONTROL, GENERAL_UPDATE}, @@ -548,7 +548,7 @@ static const cfg_op_t cfg_display_framebuffer[32] = { {DC_WIN_LINE_STRIDE, UV_LINE_STRIDE(720 * 2) | LINE_STRIDE(720 * 4)}, //768*2x768*4 (= 0x600 x 0xC00) bytes, see TRM for alignment requirements. {DC_WIN_BUFFER_CONTROL, 0}, {DC_WINBUF_SURFACE_KIND, 0}, //Regular surface. - {DC_WINBUF_START_ADDR, 0xC0000000}, //Framebuffer address. + {DC_WINBUF_START_ADDR, IPL_FB_ADDRESS}, // Framebuffer address. {DC_WINBUF_ADDR_H_OFFSET, 0}, {DC_WINBUF_ADDR_V_OFFSET, 0}, {DC_WIN_WIN_OPTIONS, 0}, diff --git a/source/gfx/gfx.c b/source/gfx/gfx.c index f6f8a0e..5371f4d 100644 --- a/source/gfx/gfx.c +++ b/source/gfx/gfx.c @@ -19,7 +19,6 @@ #include #include #include "gfx.h" -//#include "../utils/types.h" static const u8 _gfx_font[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Char 032 ( ) @@ -129,12 +128,12 @@ void gfx_init_ctxt(u32 *fb, u32 width, u32 height, u32 stride) void gfx_clear_grey(u8 color) { - memset(gfx_ctxt.fb, color, 0x3C0000); + memset(gfx_ctxt.fb, color, gfx_ctxt.width * gfx_ctxt.height * 4); } void gfx_clear_color(u32 color) { - for (u32 i = 0; i < gfx_ctxt.height * gfx_ctxt.stride; i++) + for (u32 i = 0; i < gfx_ctxt.width * gfx_ctxt.height; i++) gfx_ctxt.fb[i] = color; } @@ -153,8 +152,7 @@ void gfx_con_init() gfx_con.savedy = 0; gfx_con.fgcol = 0xFFCCCCCC; gfx_con.fillbg = 1; - //gfx_con.bgcol = 0xFF1B1B1B; - gfx_con.bgcol = 0xFF009600; + gfx_con.bgcol = 0xFF1B1B1B; gfx_con.mute = 0; } @@ -217,7 +215,7 @@ void gfx_putc(char c) } } gfx_con.x += 16; - if (gfx_con.x >= gfx_ctxt.width - 8) { + if (gfx_con.x >= gfx_ctxt.width - 16) { gfx_con.x = 0; gfx_con.y += 16; } @@ -229,9 +227,13 @@ void gfx_putc(char c) if (gfx_con.y > gfx_ctxt.height - 16) gfx_con.y = 0; } - else if (c == '\r'){ + else if (c == '\e') + gfx_con.x = 672; + else if (c == '\a') + gfx_con.x = 608; + else if (c == '\r') gfx_con.x = 0; - } + break; case 8: default: @@ -266,9 +268,9 @@ void gfx_putc(char c) if (gfx_con.y > gfx_ctxt.height - 8) gfx_con.y = 0; } + break; } - } void gfx_puts(const char *s) @@ -371,8 +373,6 @@ void gfx_printf(const char *fmt, ...) _gfx_putn(va_arg(ap, u32), 10, fill, fcnt); break; case 'p': - gfx_con.bgcol = va_arg(ap, u32); - break; case 'P': case 'x': case 'X': @@ -495,14 +495,6 @@ void gfx_line(int x0, int y0, int x1, int y1, u32 color) } } -void gfx_box(int x0, int y0, int x1, int y1, u32 color){ - int i = y0; - while(y1 >= i){ - gfx_line(x0, i, x1, i, color); - i++; - } -} - void gfx_set_rect_grey(const u8 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y) { u32 pos = 0; @@ -516,6 +508,13 @@ void gfx_set_rect_grey(const u8 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos } } +void gfx_box(int x0, int y0, int x1, int y1, u32 color){ + int i = y0; + while(y1 >= i){ + gfx_line(x0, i, x1, i, color); + i++; + } +} void gfx_set_rect_rgb(const u8 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y) { diff --git a/source/gfx/gfx.h b/source/gfx/gfx.h index a0c80d8..a5c9fd6 100644 --- a/source/gfx/gfx.h +++ b/source/gfx/gfx.h @@ -41,13 +41,13 @@ void gfx_hexdump(u32 base, const u8 *buf, u32 len); void gfx_set_pixel(u32 x, u32 y, u32 color); void gfx_line(int x0, int y0, int x1, int y1, u32 color); -void gfx_box(int x0, int y0, int x1, int y1, u32 color); void gfx_put_small_sep(); void gfx_put_big_sep(); void gfx_set_rect_grey(const u8 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y); void gfx_set_rect_rgb(const u8 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y); void gfx_set_rect_argb(const u32 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y); void gfx_render_bmp_argb(const u32 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y); +void gfx_box(int x0, int y0, int x1, int y1, u32 color); // Global gfx console and context. gfx_ctxt_t gfx_ctxt; diff --git a/source/gfx/tui.c b/source/gfx/tui.c new file mode 100644 index 0000000..cd3cea6 --- /dev/null +++ b/source/gfx/tui.c @@ -0,0 +1,225 @@ +/* + * Copyright (c) 2018 naehrwert + * Copyright (c) 2018 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "di.h" +#include "tui.h" +#include "../utils/btn.h" +#include "../config/config.h" +#include "../power/max17050.h" +#include "../utils/util.h" + +#ifdef MENU_LOGO_ENABLE +extern u8 *Kc_MENU_LOGO; +#define X_MENU_LOGO 119 +#define Y_MENU_LOGO 57 +#define X_POS_MENU_LOGO 577 +#define Y_POS_MENU_LOGO 1179 +#endif //MENU_LOGO_ENABLE + +extern hekate_config h_cfg; + +void tui_sbar(bool force_update) +{ + u32 cx, cy; + + u32 timePassed = get_tmr_s() - h_cfg.sbar_time_keeping; + if (!force_update) + if (timePassed < 5) + return; + + u8 prevFontSize = gfx_con.fntsz; + gfx_con.fntsz = 16; + h_cfg.sbar_time_keeping = get_tmr_s(); + + u32 battPercent = 0; + int battVoltCurr = 0; + + gfx_con_getpos(&cx, &cy); + gfx_con_setpos(0, 1260); + + max17050_get_property(MAX17050_RepSOC, (int *)&battPercent); + max17050_get_property(MAX17050_VCELL, &battVoltCurr); + + gfx_clear_partial_grey(0x30, 1256, 24); + gfx_printf("%K%k Battery: %d.%d%% (%d mV) - Charge:", 0xFF303030, 0xFF888888, + (battPercent >> 8) & 0xFF, (battPercent & 0xFF) / 26, battVoltCurr); + + max17050_get_property(MAX17050_Current, &battVoltCurr); + + if (battVoltCurr >= 0) + gfx_printf(" %k+%d mA%k%K\n", + 0xFF008800, battVoltCurr / 1000, 0xFFCCCCCC, 0xFF1B1B1B); + else + gfx_printf(" %k-%d mA%k%K\n", + 0xFF880000, (~battVoltCurr) / 1000, 0xFFCCCCCC, 0xFF1B1B1B); + gfx_con.fntsz = prevFontSize; + gfx_con_setpos(cx, cy); +} + +void tui_pbar(int x, int y, u32 val, u32 fgcol, u32 bgcol) +{ + u32 cx, cy; + if (val > 200) + val = 200; + + gfx_con_getpos(&cx, &cy); + + gfx_con_setpos(x, y); + + gfx_printf("%k[%3d%%]%k", fgcol, val, 0xFFCCCCCC); + + x += 7 * gfx_con.fntsz; + + for (int i = 0; i < (gfx_con.fntsz >> 3) * 6; i++) + { + gfx_line(x, y + i + 1, x + 3 * val, y + i + 1, fgcol); + gfx_line(x + 3 * val, y + i + 1, x + 3 * 100, y + i + 1, bgcol); + } + + gfx_con_setpos(cx, cy); + + // Update status bar. + tui_sbar(false); +} + +void *tui_do_menu(menu_t *menu) +{ + int idx = 0, prev_idx = 0, cnt = 0x7FFFFFFF; + + gfx_clear_partial_grey(0x1B, 0, 1256); + tui_sbar(true); + +#ifdef MENU_LOGO_ENABLE + gfx_set_rect_rgb(Kc_MENU_LOGO, + X_MENU_LOGO, Y_MENU_LOGO, X_POS_MENU_LOGO, Y_POS_MENU_LOGO); +#endif //MENU_LOGO_ENABLE + + while (true) + { + gfx_con_setcol(0xFFCCCCCC, 1, 0xFF1B1B1B); + gfx_con_setpos(menu->x, menu->y); + gfx_printf("[%kLo%kck%kpi%kck%k_R%kCM%k v%d.%d.%d%k]\n\n", + colors[0], colors[1], colors[2], colors[3], colors[4], colors[5], 0xFFFF00FF, LP_VER_MJ, LP_VER_MN, LP_VER_BF, 0xFFCCCCCC); + + // Skip caption or seperator lines selection. + while (menu->ents[idx].type == MENT_CAPTION || + menu->ents[idx].type == MENT_CHGLINE) + { + if (prev_idx <= idx || (!idx && prev_idx == cnt - 1)) + { + idx++; + if (idx > (cnt - 1)) + { + idx = 0; + prev_idx = 0; + } + } + else + { + idx--; + if (idx < 0) + { + idx = cnt - 1; + prev_idx = cnt; + } + } + } + prev_idx = idx; + + // Draw the menu. + for (cnt = 0; menu->ents[cnt].type != MENT_END; cnt++) + { + if (cnt == idx) + gfx_con_setcol(0xFF1B1B1B, 1, 0xFFCCCCCC); + else + gfx_con_setcol(0xFFCCCCCC, 1, 0xFF1B1B1B); + if (menu->ents[cnt].type != MENT_CHGLINE && menu->ents[cnt].type != MENT_MENU) { + if (cnt == idx) + gfx_printf(" %s", menu->ents[cnt].caption); + else + gfx_printf("%k %s", menu->ents[cnt].color, menu->ents[cnt].caption); + } + if(menu->ents[cnt].type == MENT_MENU) + gfx_printf("%k...", 0xFF0099EE); + gfx_printf(" \n"); + } + gfx_con_setcol(0xFFCCCCCC, 1, 0xFF1B1B1B); + gfx_putc('\n'); + + // Print help and battery status. + gfx_con_setpos(0, 1127); + if (h_cfg.emummc_force_disable) + gfx_printf("%kNo emuMMC config found.\n", 0xFF800000); + gfx_con_setpos(0, 1191); + gfx_printf("%k VOL: Move up/down\n PWR: Select option%k", 0xFF555555, 0xFFCCCCCC); + + display_backlight_brightness(h_cfg.backlight, 1000); + + // Wait for user command. + u32 btn = btn_wait(); + + if (btn & BTN_VOL_DOWN && idx < (cnt - 1)) + idx++; + else if (btn & BTN_VOL_DOWN && idx == (cnt - 1)) + { + idx = 0; + prev_idx = -1; + } + if (btn & BTN_VOL_UP && idx > 0) + idx--; + else if (btn & BTN_VOL_UP && idx == 0) + { + idx = cnt - 1; + prev_idx = cnt; + } + if (btn & BTN_POWER) + { + ment_t *ent = &menu->ents[idx]; + switch (ent->type) + { + case MENT_HANDLER: + ent->handler(ent->data); + break; + case MENT_MENU: + return tui_do_menu(ent->menu); + break; + case MENT_DATA: + return ent->data; + break; + case MENT_BACK: + return NULL; + break; + case MENT_HDLR_RE: + ent->handler(ent); + if (!ent->data) + return NULL; + break; + default: + break; + } + gfx_con.fntsz = 16; + gfx_clear_partial_grey(0x1B, 0, 1256); +#ifdef MENU_LOGO_ENABLE + gfx_set_rect_rgb(Kc_MENU_LOGO, + X_MENU_LOGO, Y_MENU_LOGO, X_POS_MENU_LOGO, Y_POS_MENU_LOGO); +#endif //MENU_LOGO_ENABLE + } + tui_sbar(false); + } + + return NULL; +} diff --git a/source/gfx/tui.h b/source/gfx/tui.h new file mode 100644 index 0000000..2b7d3f7 --- /dev/null +++ b/source/gfx/tui.h @@ -0,0 +1,66 @@ +/* +* Copyright (c) 2018 naehrwert +* Copyright (C) 2018 CTCaer +* +* This program is free software; you can redistribute it and/or modify it +* under the terms and conditions of the GNU General Public License, +* version 2, as published by the Free Software Foundation. +* +* This program is distributed in the hope it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +* more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +*/ + +#ifndef _TUI_H_ +#define _TUI_H_ + +#include "../utils/types.h" +#include "gfx.h" + +#define MENT_END 0 +#define MENT_HANDLER 1 +#define MENT_MENU 2 +#define MENT_DATA 3 +#define MENT_BACK 4 +#define MENT_CAPTION 5 +#define MENT_CHGLINE 6 +#define MENT_HDLR_RE 7 + +typedef struct _ment_t +{ + u32 type; + const char *caption; + u32 color; + void *data; + union + { + void(*handler)(void *); + struct _menu_t *menu; + }; +} ment_t; + +typedef struct _menu_t +{ + ment_t *ents; + const char *caption; + u32 x; + u32 y; +} menu_t; + +#define MDEF_END() {MENT_END} +#define MDEF_HANDLER(caption, _handler, color) { MENT_HANDLER, caption, color, NULL, { .handler = _handler } } +#define MDEF_HANDLER_EX(caption, data, _handler, color) { MENT_HANDLER, caption, color, data, { .handler = _handler } } +#define MDEF_MENU(caption, _menu) { MENT_MENU, caption, 0, NULL, { .menu = _menu } } +#define MDEF_BACK() { MENT_BACK, "Back" } +#define MDEF_CAPTION(caption, color) { MENT_CAPTION, caption, color } +#define MDEF_CHGLINE() {MENT_CHGLINE} + +void tui_sbar(bool force_update); +void tui_pbar(int x, int y, u32 val, u32 fgcol, u32 bgcol); +void *tui_do_menu(menu_t *menu); + +#endif diff --git a/source/hos/pkg1.c b/source/hos/pkg1.c index 5e36e05..e93ac0d 100644 --- a/source/hos/pkg1.c +++ b/source/hos/pkg1.c @@ -22,20 +22,26 @@ #include "pkg1.h" #include "../sec/se.h" +#define HASH_ORDER_100_100 {2, 3, 4, 0, 5, 6, 1} +#define HASH_ORDER_200_510 {2, 3, 4, 0, 5, 7, 10, 12, 11, 6, 8, 1} +#define HASH_ORDER_600_620 {6, 5, 10, 7, 8, 2, 3, 4, 0, 12, 11, 1} +#define HASH_ORDER_700_9xx {6, 5, 10, 7, 8, 2, 3, 4, 0, 12, 11, 9, 1} + static const pkg1_id_t _pkg1_ids[] = { - { "20161121183008", 0 }, //1.0.0 - { "20170210155124", 0 }, //2.0.0 - 2.3.0 - { "20170519101410", 1 }, //3.0.0 - { "20170710161758", 2 }, //3.0.1 - 3.0.2 - { "20170921172629", 3 }, //4.0.0 - 4.1.0 - { "20180220163747", 4 }, //5.0.0 - 5.1.0 - { "20180802162753", 5 }, //6.0.0 - 6.1.0 - { "20181107105733", 6 }, //6.2.0 - { "20181218175730", 7 }, //7.0.0 - { "20190208150037", 7 }, //7.0.1 - { "20190314172056", 7 }, //8.0.0 - { "20190531152432", 8 }, //8.1.0 - { "20190809135709", 9 }, //9.0.0 + { "20161121183008", 0, {0x1b517, 0x125bc2, 1, 16, 6, HASH_ORDER_100_100, 0, 0x449dc} }, //1.0.0 + { "20170210155124", 0, {0x1d226, 0x26fe, 0, 16, 11, HASH_ORDER_200_510, 0x557b, 0x3d41a} }, //2.0.0 - 2.3.0 + { "20170519101410", 1, {0x1ffa6, 0x298b, 0, 16, 11, HASH_ORDER_200_510, 0x552d, 0x3cb81} }, //3.0.0 + { "20170710161758", 2, {0x20026, 0x29ab, 0, 16, 11, HASH_ORDER_200_510, 0x552d, 0x3cb81} }, //3.0.1 - 3.0.2 + { "20170921172629", 3, {0x1c64c, 0x37eb, 0, 16, 11, HASH_ORDER_200_510, 0x5382, 0x3711c} }, //4.0.0 - 4.1.0 + { "20180220163747", 4, {0x1f3b4, 0x465b, 0, 16, 11, HASH_ORDER_200_510, 0x5a63, 0x37901} }, //5.0.0 - 5.1.0 + { "20180802162753", 5, {0x27350, 0x17ff5, 1, 8, 11, HASH_ORDER_600_620, 0x5674, 0x1d5be} }, //6.0.0 - 6.1.0 + { "20181107105733", 6, {0x27350, 0x17ff5, 1, 8, 11, HASH_ORDER_600_620, 0x5674, 0x1d5be} }, //6.2.0 + { "20181218175730", 7, {0x29c50, 0x6a73, 0, 8, 12, HASH_ORDER_700_9xx, 0x5563, 0x1d437} }, //7.0.0 + { "20190208150037", 7, {0x29c50, 0x6a73, 0, 8, 12, HASH_ORDER_700_9xx, 0x5563, 0x1d437} }, //7.0.1 + { "20190314172056", 7, {0x29c50, 0x6a73, 0, 8, 12, HASH_ORDER_700_9xx, 0x5563, 0x1d437} }, //8.0.0 - 8.0.1 + { "20190531152432", 8, {0x29c50, 0x6a73, 0, 8, 12, HASH_ORDER_700_9xx, 0x5563, 0x1d437} }, //8.1.0 + { "20190809135709", 9, {0x2ec10, 0x5573, 0, 1, 12, HASH_ORDER_700_9xx, 0x6495, 0x1d807} }, //9.0.0 - 9.0.1 + { "20191021113848", 10,{0x2ec10, 0x5573, 0, 1, 12, HASH_ORDER_700_9xx, 0x6495, 0x1d807} }, //9.1.0 { NULL } //End. }; diff --git a/source/hos/pkg1.h b/source/hos/pkg1.h index c0be0ac..1d1e4ad 100644 --- a/source/hos/pkg1.h +++ b/source/hos/pkg1.h @@ -19,10 +19,23 @@ #include "../utils/types.h" +typedef struct _key_info_t +{ + u32 start_offset; + u32 hks_offset; + bool hks_offset_is_from_end; + u32 alignment; + u32 hash_max; + u8 hash_order[13]; + u32 es_offset; + u32 ssl_offset; +} key_info_t; + typedef struct _pkg1_id_t { const char *id; u32 kb; + key_info_t key_info; } pkg1_id_t; const pkg1_id_t *pkg1_identify(u8 *pkg1); diff --git a/source/hos/pkg2.c b/source/hos/pkg2.c index 4cece1c..e745cbc 100644 --- a/source/hos/pkg2.c +++ b/source/hos/pkg2.c @@ -39,14 +39,25 @@ static u32 _pkg2_calc_kip1_size(pkg2_kip1_t *kip1) return size; } -void pkg2_parse_kips(link_t *info, pkg2_hdr_t *pkg2) +void pkg2_get_newkern_info(u8 *kern_data) +{ + u32 info_op = *(u32 *)(kern_data + PKG2_NEWKERN_GET_INI1); + pkg2_newkern_ini1_val = ((info_op & 0xFFFF) >> 3) + PKG2_NEWKERN_GET_INI1; // Parse ADR and PC. + + pkg2_newkern_ini1_start = *(u32 *)(kern_data + pkg2_newkern_ini1_val); + pkg2_newkern_ini1_end = *(u32 *)(kern_data + pkg2_newkern_ini1_val + 0x8); +} + +void pkg2_parse_kips(link_t *info, pkg2_hdr_t *pkg2, bool *new_pkg2) { u8 *ptr; // Check for new pkg2 type. if (!pkg2->sec_size[PKG2_SEC_INI1]) { - u32 kernel_ini1_off = *(u32 *)(pkg2->data + PKG2_NEWKERN_INI1_START); - ptr = pkg2->data + kernel_ini1_off; + pkg2_get_newkern_info(pkg2->data); + + ptr = pkg2->data + pkg2_newkern_ini1_start; + *new_pkg2 = true; } else ptr = pkg2->data + pkg2->sec_size[PKG2_SEC_KERNEL]; @@ -74,19 +85,19 @@ int pkg2_decompress_kip(pkg2_kip1_info_t* ki, u32 sectsToDecomp) pkg2_kip1_t hdr; memcpy(&hdr, ki->kip1, sizeof(hdr)); - + unsigned int newKipSize = sizeof(hdr); for (u32 sectIdx = 0; sectIdx < KIP1_NUM_SECTIONS; sectIdx++) { u32 sectCompBit = 1u << sectIdx; // For compressed, cant get actual decompressed size without doing it, so use safe "output size". - if (sectIdx < 3 && (sectsToDecomp & sectCompBit) && (hdr.flags & sectCompBit)) + if (sectIdx < 3 && (sectsToDecomp & sectCompBit) && (hdr.flags & sectCompBit)) newKipSize += hdr.sections[sectIdx].size_decomp; else newKipSize += hdr.sections[sectIdx].size_comp; } - pkg2_kip1_t* newKip = malloc(newKipSize); + pkg2_kip1_t* newKip = malloc(newKipSize); unsigned char* dstDataPtr = newKip->data; const unsigned char* srcDataPtr = ki->kip1->data; for (u32 sectIdx = 0; sectIdx < KIP1_NUM_SECTIONS; sectIdx++) @@ -110,7 +121,7 @@ int pkg2_decompress_kip(pkg2_kip1_info_t* ki, u32 sectsToDecomp) //gfx_printf("Decomping %s KIP1 sect %d of size %d...\n", (const char*)hdr.name, sectIdx, compSize); if (blz_uncompress_srcdest(srcDataPtr, compSize, dstDataPtr, outputSize) == 0) { - gfx_printf("%kERROR decomping sect %d of %s KIP!%k\n", 0xFFFF0000, sectIdx, (char*)hdr.name, 0xFFCCCCCC); + gfx_printf("%kERROR decomping sect %d of %s KIP!%k\n", 0xFFFF0000, sectIdx, (char*)hdr.name, 0xFFCCCCCC); free(newKip); return 1; @@ -138,7 +149,7 @@ int pkg2_decompress_kip(pkg2_kip1_info_t* ki, u32 sectsToDecomp) pkg2_hdr_t *pkg2_decrypt(void *data) { u8 *pdata = (u8 *)data; - + // Skip signature. pdata += 0x100; diff --git a/source/hos/pkg2.h b/source/hos/pkg2.h index fe067ec..0cb9962 100644 --- a/source/hos/pkg2.h +++ b/source/hos/pkg2.h @@ -26,7 +26,11 @@ #define PKG2_SEC_KERNEL 0 #define PKG2_SEC_INI1 1 -#define PKG2_NEWKERN_INI1_START 0x168 +#define PKG2_NEWKERN_GET_INI1 0x44 + +u32 pkg2_newkern_ini1_val; +u32 pkg2_newkern_ini1_start; +u32 pkg2_newkern_ini1_end; typedef struct _pkg2_hdr_t { @@ -83,7 +87,7 @@ typedef struct _pkg2_kip1_info_t link_t link; } pkg2_kip1_info_t; -void pkg2_parse_kips(link_t *info, pkg2_hdr_t *pkg2); +void pkg2_parse_kips(link_t *info, pkg2_hdr_t *pkg2, bool *new_pkg2); int pkg2_decompress_kip(pkg2_kip1_info_t* ki, u32 sectsToDecomp); pkg2_hdr_t *pkg2_decrypt(void *data); diff --git a/source/hos/sept.c b/source/hos/sept.c index d31f83a..1858533 100644 --- a/source/hos/sept.c +++ b/source/hos/sept.c @@ -20,6 +20,7 @@ #include "../gfx/di.h" #include "../libs/fatfs/ff.h" #include "../mem/heap.h" +#include "../soc/hw_init.h" #include "../soc/pmc.h" #include "../soc/t210.h" #include "../storage/nx_emmc.h" @@ -38,7 +39,7 @@ u8 warmboot_reboot[] = { 0x14, 0x00, 0x9F, 0xE5, // LDR R0, =0x7000E450 0x01, 0x10, 0xB0, 0xE3, // MOVS R1, #1 0x00, 0x10, 0x80, 0xE5, // STR R1, [R0] - 0x0C, 0x00, 0x9F, 0xE5, // LDR R0, =0x7000E400 + 0x0C, 0x00, 0x9F, 0xE5, // LDR R0, =0x7000E400 0x10, 0x10, 0xB0, 0xE3, // MOVS R1, #0x10 0x00, 0x10, 0x80, 0xE5, // STR R1, [R0] 0xFE, 0xFF, 0xFF, 0xEA, // LOOP @@ -55,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); @@ -80,10 +82,17 @@ int reboot_to_sept(const u8 *tsec_fw, const u32 tsec_size, const u32 kb) f_close(&fp); // Copy sept-secondary. - if ((kb == 7) && f_open(&fp, "sd:/sept/sept-secondary.enc", FA_READ) && f_open(&fp, "sd:/sept/sept-secondary_00.enc", FA_READ)) - goto error; - else if ((kb == 8) && f_open(&fp, "sd:/sept/sept-secondary_01.enc", FA_READ)) - goto error; + if (kb < KB_FIRMWARE_VERSION_810) + { + if (f_open(&fp, "sd:/sept/sept-secondary_00.enc", FA_READ)) + if (f_open(&fp, "sd:/sept/sept-secondary.enc", FA_READ)) // Try the deprecated version. + goto error; + } + else + { + if (f_open(&fp, "sd:/sept/sept-secondary_01.enc", FA_READ)) + goto error; + } if (f_read(&fp, (u8 *)SEPT_STG2_ADDR, f_size(&fp), NULL)) { @@ -98,8 +107,10 @@ int reboot_to_sept(const u8 *tsec_fw, const u32 tsec_size, const u32 kb) tmp_cfg->boot_cfg |= BOOT_CFG_SEPT_RUN; - if (f_open(&fp, "sd:/sept/payload.bin", FA_READ | FA_WRITE)) + if (f_open(&fp, "sd:/sept/payload.bin", FA_READ | FA_WRITE)) { + free(tmp_cfg); goto error; + } f_lseek(&fp, PATCHED_RELOC_SZ); f_write(&fp, tmp_cfg, sizeof(boot_cfg_t), NULL); @@ -107,8 +118,7 @@ int reboot_to_sept(const u8 *tsec_fw, const u32 tsec_size, const u32 kb) f_close(&fp); sd_unmount(); - gfx_printf("\n%kPress Power or Vol +/-\n%k to Reboot to Sept...", COLOR_BLUE, COLOR_VIOLET); - btn_wait(); + gfx_printf("\n%kPress Power or Vol +/-\n to Reboot to Sept...", colors[(color_idx++) % 6]); u32 pk1t_sept = SEPT_PK1T_ADDR - (ALIGN(PATCHED_RELOC_SZ, 0x10) + WB_RST_SIZE); @@ -123,12 +133,12 @@ int reboot_to_sept(const u8 *tsec_fw, const u32 tsec_size, const u32 kb) PMC(APBDEV_PMC_SCRATCH33) = SEPT_PRI_ADDR; PMC(APBDEV_PMC_SCRATCH40) = 0x6000F208; - display_end(); + reconfig_hw_workaround(false, 0); (*sept)(); error: - EPRINTF("Sept files not found in sd:/sept!\nPlace appropriate files and try again."); + EPRINTF("\nSept files not found in sd:/sept!\nPlace appropriate files and try again."); display_backlight_brightness(100, 1000); btn_wait(); 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/key_sources.inl b/source/keys/key_sources.inl deleted file mode 100644 index 536c41b..0000000 --- a/source/keys/key_sources.inl +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Copyright (c) 2019 shchmue - * - * 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 . - */ - -static const u8 zeros[0x10] = {0}; - -static const u8 keyblob_key_source[][0x10] = { - {0xDF, 0x20, 0x6F, 0x59, 0x44, 0x54, 0xEF, 0xDC, 0x70, 0x74, 0x48, 0x3B, 0x0D, 0xED, 0x9F, 0xD3}, //1.0.0 - {0x0C, 0x25, 0x61, 0x5D, 0x68, 0x4C, 0xEB, 0x42, 0x1C, 0x23, 0x79, 0xEA, 0x82, 0x25, 0x12, 0xAC}, //3.0.0 - {0x33, 0x76, 0x85, 0xEE, 0x88, 0x4A, 0xAE, 0x0A, 0xC2, 0x8A, 0xFD, 0x7D, 0x63, 0xC0, 0x43, 0x3B}, //3.0.1 - {0x2D, 0x1F, 0x48, 0x80, 0xED, 0xEC, 0xED, 0x3E, 0x3C, 0xF2, 0x48, 0xB5, 0x65, 0x7D, 0xF7, 0xBE}, //4.0.0 - {0xBB, 0x5A, 0x01, 0xF9, 0x88, 0xAF, 0xF5, 0xFC, 0x6C, 0xFF, 0x07, 0x9E, 0x13, 0x3C, 0x39, 0x80}, //5.0.0 - {0xD8, 0xCC, 0xE1, 0x26, 0x6A, 0x35, 0x3F, 0xCC, 0x20, 0xF3, 0x2D, 0x3B, 0x51, 0x7D, 0xE9, 0xC0} //6.0.0 -}; - -static const u8 master_kek_sources[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_VERSION_600][0x10] = { - {0x37, 0x4B, 0x77, 0x29, 0x59, 0xB4, 0x04, 0x30, 0x81, 0xF6, 0xE5, 0x8C, 0x6D, 0x36, 0x17, 0x9A}, //6.2.0 - {0x9A, 0x3E, 0xA9, 0xAB, 0xFD, 0x56, 0x46, 0x1C, 0x9B, 0xF6, 0x48, 0x7F, 0x5C, 0xFA, 0x09, 0x5C}, //7.0.0 - {0xDE, 0xDC, 0xE3, 0x39, 0x30, 0x88, 0x16, 0xF8, 0xAE, 0x97, 0xAD, 0xEC, 0x64, 0x2D, 0x41, 0x41}, //8.1.0 -}; - -static const u8 mkey_vectors[KB_FIRMWARE_VERSION_MAX+1][0x10] = -{ - {0x0C, 0xF0, 0x59, 0xAC, 0x85, 0xF6, 0x26, 0x65, 0xE1, 0xE9, 0x19, 0x55, 0xE6, 0xF2, 0x67, 0x3D}, /* Zeroes encrypted with Master Key 00. */ - {0x29, 0x4C, 0x04, 0xC8, 0xEB, 0x10, 0xED, 0x9D, 0x51, 0x64, 0x97, 0xFB, 0xF3, 0x4D, 0x50, 0xDD}, /* Master key 00 encrypted with Master key 01. */ - {0xDE, 0xCF, 0xEB, 0xEB, 0x10, 0xAE, 0x74, 0xD8, 0xAD, 0x7C, 0xF4, 0x9E, 0x62, 0xE0, 0xE8, 0x72}, /* Master key 01 encrypted with Master key 02. */ - {0x0A, 0x0D, 0xDF, 0x34, 0x22, 0x06, 0x6C, 0xA4, 0xE6, 0xB1, 0xEC, 0x71, 0x85, 0xCA, 0x4E, 0x07}, /* Master key 02 encrypted with Master key 03. */ - {0x6E, 0x7D, 0x2D, 0xC3, 0x0F, 0x59, 0xC8, 0xFA, 0x87, 0xA8, 0x2E, 0xD5, 0x89, 0x5E, 0xF3, 0xE9}, /* Master key 03 encrypted with Master key 04. */ - {0xEB, 0xF5, 0x6F, 0x83, 0x61, 0x9E, 0xF8, 0xFA, 0xE0, 0x87, 0xD7, 0xA1, 0x4E, 0x25, 0x36, 0xEE}, /* Master key 04 encrypted with Master key 05. */ - {0x1E, 0x1E, 0x22, 0xC0, 0x5A, 0x33, 0x3C, 0xB9, 0x0B, 0xA9, 0x03, 0x04, 0xBA, 0xDB, 0x07, 0x57}, /* Master key 05 encrypted with Master key 06. */ - {0xA4, 0xD4, 0x52, 0x6F, 0xD1, 0xE4, 0x36, 0xAA, 0x9F, 0xCB, 0x61, 0x27, 0x1C, 0x67, 0x65, 0x1F}, /* Master key 06 encrypted with Master key 07. */ - {0xEA, 0x60, 0xB3, 0xEA, 0xCE, 0x8F, 0x24, 0x46, 0x7D, 0x33, 0x9C, 0xD1, 0xBC, 0x24, 0x98, 0x29}, /* Master key 07 encrypted with Master key 08. */ -}; - -//======================================Keys======================================// -// from Package1 -> Secure_Monitor -static const u8 aes_kek_generation_source[0x10] = { - 0x4D, 0x87, 0x09, 0x86, 0xC4, 0x5D, 0x20, 0x72, 0x2F, 0xBA, 0x10, 0x53, 0xDA, 0x92, 0xE8, 0xA9}; -static const u8 aes_kek_seed_01[0x10] = { - 0xA2, 0xAB, 0xBF, 0x9C, 0x92, 0x2F, 0xBB, 0xE3, 0x78, 0x79, 0x9B, 0xC0, 0xCC, 0xEA, 0xA5, 0x74}; -static const u8 aes_kek_seed_03[0x10] = { - 0xE5, 0x4D, 0x9A, 0x02, 0xF0, 0x4F, 0x5F, 0xA8, 0xAD, 0x76, 0x0A, 0xF6, 0x32, 0x95, 0x59, 0xBB}; -static const u8 package2_key_source[0x10] = { - 0xFB, 0x8B, 0x6A, 0x9C, 0x79, 0x00, 0xC8, 0x49, 0xEF, 0xD2, 0x4D, 0x85, 0x4D, 0x30, 0xA0, 0xC7}; -static const u8 titlekek_source[0x10] = { - 0x1E, 0xDC, 0x7B, 0x3B, 0x60, 0xE6, 0xB4, 0xD8, 0x78, 0xB8, 0x17, 0x15, 0x98, 0x5E, 0x62, 0x9B}; -static const u8 retail_specific_aes_key_source[0x10] = { - 0xE2, 0xD6, 0xB8, 0x7A, 0x11, 0x9C, 0xB8, 0x80, 0xE8, 0x22, 0x88, 0x8A, 0x46, 0xFB, 0xA1, 0x95}; - -// from Package1ldr (or Secure_Monitor on 6.2.0) -static const u8 keyblob_mac_key_source[0x10] = { - 0x59, 0xC7, 0xFB, 0x6F, 0xBE, 0x9B, 0xBE, 0x87, 0x65, 0x6B, 0x15, 0xC0, 0x53, 0x73, 0x36, 0xA5}; -static const u8 master_key_source[0x10] = { - 0xD8, 0xA2, 0x41, 0x0A, 0xC6, 0xC5, 0x90, 0x01, 0xC6, 0x1D, 0x6A, 0x26, 0x7C, 0x51, 0x3F, 0x3C}; -static const u8 per_console_key_source[0x10] = { - 0x4F, 0x02, 0x5F, 0x0E, 0xB6, 0x6D, 0x11, 0x0E, 0xDC, 0x32, 0x7D, 0x41, 0x86, 0xC2, 0xF4, 0x78}; - -// from SPL -static const u8 aes_key_generation_source[0x10] = { - 0x89, 0x61, 0x5E, 0xE0, 0x5C, 0x31, 0xB6, 0x80, 0x5F, 0xE5, 0x8F, 0x3D, 0xA2, 0x4F, 0x7A, 0xA8}; - -// from FS -static const u8 bis_kek_source[0x10] = { - 0x34, 0xC1, 0xA0, 0xC4, 0x82, 0x58, 0xF8, 0xB4, 0xFA, 0x9E, 0x5E, 0x6A, 0xDA, 0xFC, 0x7E, 0x4F}; -static const u8 bis_key_source[3][0x20] = { - { - 0xF8, 0x3F, 0x38, 0x6E, 0x2C, 0xD2, 0xCA, 0x32, 0xA8, 0x9A, 0xB9, 0xAA, 0x29, 0xBF, 0xC7, 0x48, - 0x7D, 0x92, 0xB0, 0x3A, 0xA8, 0xBF, 0xDE, 0xE1, 0xA7, 0x4C, 0x3B, 0x6E, 0x35, 0xCB, 0x71, 0x06}, - { - 0x41, 0x00, 0x30, 0x49, 0xDD, 0xCC, 0xC0, 0x65, 0x64, 0x7A, 0x7E, 0xB4, 0x1E, 0xED, 0x9C, 0x5F, - 0x44, 0x42, 0x4E, 0xDA, 0xB4, 0x9D, 0xFC, 0xD9, 0x87, 0x77, 0x24, 0x9A, 0xDC, 0x9F, 0x7C, 0xA4}, - { - 0x52, 0xC2, 0xE9, 0xEB, 0x09, 0xE3, 0xEE, 0x29, 0x32, 0xA1, 0x0C, 0x1F, 0xB6, 0xA0, 0x92, 0x6C, - 0x4D, 0x12, 0xE1, 0x4B, 0x2A, 0x47, 0x4C, 0x1C, 0x09, 0xCB, 0x03, 0x59, 0xF0, 0x15, 0xF4, 0xE4} -}; - -static const u8 fs_hashes_sha256[10][0x20] = { - { // header_kek_source - 0x18, 0x88, 0xca, 0xed, 0x55, 0x51, 0xb3, 0xed, 0xe0, 0x14, 0x99, 0xe8, 0x7c, 0xe0, 0xd8, 0x68, - 0x27, 0xf8, 0x08, 0x20, 0xef, 0xb2, 0x75, 0x92, 0x10, 0x55, 0xaa, 0x4e, 0x2a, 0xbd, 0xff, 0xc2}, - { // header_key_source - 0x8f, 0x78, 0x3e, 0x46, 0x85, 0x2d, 0xf6, 0xbe, 0x0b, 0xa4, 0xe1, 0x92, 0x73, 0xc4, 0xad, 0xba, - 0xee, 0x16, 0x38, 0x00, 0x43, 0xe1, 0xb8, 0xc4, 0x18, 0xc4, 0x08, 0x9a, 0x8b, 0xd6, 0x4a, 0xa6}, - { // key_area_key_application_source - 0x04, 0xad, 0x66, 0x14, 0x3c, 0x72, 0x6b, 0x2a, 0x13, 0x9f, 0xb6, 0xb2, 0x11, 0x28, 0xb4, 0x6f, - 0x56, 0xc5, 0x53, 0xb2, 0xb3, 0x88, 0x71, 0x10, 0x30, 0x42, 0x98, 0xd8, 0xd0, 0x09, 0x2d, 0x9e}, - { // key_area_key_ocean_source - 0xfd, 0x43, 0x40, 0x00, 0xc8, 0xff, 0x2b, 0x26, 0xf8, 0xe9, 0xa9, 0xd2, 0xd2, 0xc1, 0x2f, 0x6b, - 0xe5, 0x77, 0x3c, 0xbb, 0x9d, 0xc8, 0x63, 0x00, 0xe1, 0xbd, 0x99, 0xf8, 0xea, 0x33, 0xa4, 0x17}, - { // key_area_key_system_source - 0x1f, 0x17, 0xb1, 0xfd, 0x51, 0xad, 0x1c, 0x23, 0x79, 0xb5, 0x8f, 0x15, 0x2c, 0xa4, 0x91, 0x2e, - 0xc2, 0x10, 0x64, 0x41, 0xe5, 0x17, 0x22, 0xf3, 0x87, 0x00, 0xd5, 0x93, 0x7a, 0x11, 0x62, 0xf7}, - { // save_mac_kek_source - 0x3D, 0xCB, 0xA1, 0x00, 0xAD, 0x4D, 0xF1, 0x54, 0x7F, 0xE3, 0xC4, 0x79, 0x5C, 0x4B, 0x22, 0x8A, - 0xA9, 0x80, 0x38, 0xF0, 0x7A, 0x36, 0xF1, 0xBC, 0x14, 0x8E, 0xEA, 0xF3, 0xDC, 0xD7, 0x50, 0xF4}, - { // save_mac_key_source - 0xB4, 0x7B, 0x60, 0x0B, 0x1A, 0xD3, 0x14, 0xF9, 0x41, 0x14, 0x7D, 0x8B, 0x39, 0x1D, 0x4B, 0x19, - 0x87, 0xCC, 0x8C, 0x88, 0x4A, 0xC8, 0x9F, 0xFC, 0x91, 0xCA, 0xE2, 0x21, 0xC5, 0x24, 0x51, 0xF7}, - { // sd_card_kek_source - 0x6B, 0x2E, 0xD8, 0x77, 0xC2, 0xC5, 0x23, 0x34, 0xAC, 0x51, 0xE5, 0x9A, 0xBF, 0xA7, 0xEC, 0x45, - 0x7F, 0x4A, 0x7D, 0x01, 0xE4, 0x62, 0x91, 0xE9, 0xF2, 0xEA, 0xA4, 0x5F, 0x01, 0x1D, 0x24, 0xB7}, - { // sd_card_nca_key_source - 0x2E, 0x75, 0x1C, 0xEC, 0xF7, 0xD9, 0x3A, 0x2B, 0x95, 0x7B, 0xD5, 0xFF, 0xCB, 0x08, 0x2F, 0xD0, - 0x38, 0xCC, 0x28, 0x53, 0x21, 0x9D, 0xD3, 0x09, 0x2C, 0x6D, 0xAB, 0x98, 0x38, 0xF5, 0xA7, 0xCC}, - { // sd_card_save_key_source - 0xD4, 0x82, 0x74, 0x35, 0x63, 0xD3, 0xEA, 0x5D, 0xCD, 0xC3, 0xB7, 0x4E, 0x97, 0xC9, 0xAC, 0x8A, - 0x34, 0x21, 0x64, 0xFA, 0x04, 0x1A, 0x1D, 0xC8, 0x0F, 0x17, 0xF6, 0xD3, 0x1E, 0x4B, 0xC0, 0x1C} -}; - -static const u8 es_hashes_sha256[3][0x20] = { - { // eticket_rsa_kek - 0xB7, 0x1D, 0xB2, 0x71, 0xDC, 0x33, 0x8D, 0xF3, 0x80, 0xAA, 0x2C, 0x43, 0x35, 0xEF, 0x88, 0x73, - 0xB1, 0xAF, 0xD4, 0x08, 0xE8, 0x0B, 0x35, 0x82, 0xD8, 0x71, 0x9F, 0xC8, 0x1C, 0x5E, 0x51, 0x1C}, - { // eticket_rsa_kekek - 0xE8, 0x96, 0x5A, 0x18, 0x7D, 0x30, 0xE5, 0x78, 0x69, 0xF5, 0x62, 0xD0, 0x43, 0x83, 0xC9, 0x96, - 0xDE, 0x48, 0x7B, 0xBA, 0x57, 0x61, 0x36, 0x3D, 0x2D, 0x4D, 0x32, 0x39, 0x18, 0x66, 0xA8, 0x5C}, - { // ssl_rsa_kek_source_x - 0x69, 0xA0, 0x8E, 0x62, 0xE0, 0xAE, 0x50, 0x7B, 0xB5, 0xDA, 0x0E, 0x65, 0x17, 0x9A, 0xE3, 0xBE, - 0x05, 0x1F, 0xED, 0x3C, 0x49, 0x94, 0x1D, 0xF4, 0xEF, 0x29, 0x56, 0xD3, 0x6D, 0x30, 0x11, 0x0C} -}; - -static const u8 ssl_hashes_sha256[2][0x20] = { - { // ssl_rsa_kek_source_x - 0x69, 0xA0, 0x8E, 0x62, 0xE0, 0xAE, 0x50, 0x7B, 0xB5, 0xDA, 0x0E, 0x65, 0x17, 0x9A, 0xE3, 0xBE, - 0x05, 0x1F, 0xED, 0x3C, 0x49, 0x94, 0x1D, 0xF4, 0xEF, 0x29, 0x56, 0xD3, 0x6D, 0x30, 0x11, 0x0C}, - { // ssl_rsa_kek_source_y - 0x1C, 0x86, 0xF3, 0x63, 0x26, 0x54, 0x17, 0xD4, 0x99, 0x22, 0x9E, 0xB1, 0xC4, 0xAD, 0xC7, 0x47, - 0x9B, 0x2A, 0x15, 0xF9, 0x31, 0x26, 0x1F, 0x31, 0xEE, 0x67, 0x76, 0xAE, 0xB4, 0xC7, 0x65, 0x42} -}; \ No newline at end of file diff --git a/source/keys/keys.c b/source/keys/keys.c deleted file mode 100644 index 2ef6a13..0000000 --- a/source/keys/keys.c +++ /dev/null @@ -1,871 +0,0 @@ -/* - * Copyright (c) 2019 shchmue - * - * 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 "keys.h" -#include "../gfx/di.h" -#include "../gfx/gfx.h" -#include "../hos/pkg1.h" -#include "../hos/pkg2.h" -#include "../hos/sept.h" -#include "../libs/fatfs/ff.h" -#include "../mem/heap.h" -#include "../mem/mc.h" -#include "../mem/sdram.h" -#include "../sec/se.h" -#include "../sec/se_t210.h" -#include "../sec/tsec.h" -#include "../soc/fuse.h" -#include "../soc/smmu.h" -#include "../soc/t210.h" -#include "../storage/nx_emmc.h" -#include "../storage/sdmmc.h" -#include "../utils/btn.h" -#include "../utils/list.h" -#include "../utils/sprintf.h" -#include "../utils/util.h" - -#include "key_sources.inl" - -#include - -extern bool sd_mount(); -extern void sd_unmount(); -extern int sd_save_to_file(void *buf, u32 size, const char *filename); - -u32 _key_count = 0; -sdmmc_storage_t storage; -emmc_part_t *system_part; - -#define TPRINTF(text) \ - end_time = get_tmr_ms(); \ - gfx_printf(text" done @ %d.%03ds\n", (end_time - start_time) / 1000, (end_time - start_time) % 1000) -#define TPRINTFARGS(text, args...) \ - end_time = get_tmr_ms(); \ - gfx_printf(text" done @ %d.%03ds\n", args, (end_time - start_time) / 1000, (end_time - start_time) % 1000) -#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) - -static u8 temp_key[0x10], - bis_key[4][0x20] = {0}, - device_key[0x10] = {0}, - sd_seed[0x10] = {0}, - // FS-related keys - fs_keys[10][0x20] = {0}, - header_key[0x20] = {0}, - save_mac_key[0x10] = {0}, - // other sysmodule sources - es_keys[3][0x10] = {0}, - eticket_rsa_kek[0x10] = {0}, - ssl_keys[2][0x10] = {0}, - ssl_rsa_kek[0x10] = {0}, - // keyblob-derived families - keyblob[KB_FIRMWARE_VERSION_600+1][0x90] = {0}, - keyblob_key[KB_FIRMWARE_VERSION_600+1][0x10] = {0}, - keyblob_mac_key[KB_FIRMWARE_VERSION_600+1][0x10] = {0}, - package1_key[KB_FIRMWARE_VERSION_600+1][0x10] = {0}, - // master key-derived families - key_area_key[3][KB_FIRMWARE_VERSION_MAX+1][0x10] = {0}, - master_kek[KB_FIRMWARE_VERSION_MAX+1][0x10] = {0}, - master_key[KB_FIRMWARE_VERSION_MAX+1][0x10] = {0}, - package2_key[KB_FIRMWARE_VERSION_MAX+1][0x10] = {0}, - titlekek[KB_FIRMWARE_VERSION_MAX+1][0x10] = {0}; - -static const u32 colors[6] = {COLOR_RED, COLOR_ORANGE, COLOR_YELLOW, COLOR_GREEN, COLOR_BLUE, COLOR_VIOLET}; - -// key functions -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); -// 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); - -void dump_keys() { - display_backlight_brightness(100, 1000); - gfx_clear_grey(0x1B); - 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); - - u32 start_time = get_tmr_ms(), - end_time, - retries = 0; - - tsec_ctxt_t tsec_ctxt; - sdmmc_t sdmmc; - - sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4); - - // Read package1. - u8 *pkg1 = (u8 *)malloc(0x40000); - sdmmc_storage_set_mmc_partition(&storage, 1); - sdmmc_storage_read(&storage, 0x100000 / NX_EMMC_BLOCKSIZE, 0x40000 / NX_EMMC_BLOCKSIZE, pkg1); - const pkg1_id_t *pkg1_id = pkg1_identify(pkg1); - if (!pkg1_id) { - EPRINTF("Unknown pkg1 version."); - goto out_wait; - } - - bool found_tsec_fw = false; - for (const u32 *pos = (const u32 *)pkg1; (u8 *)pos < pkg1 + 0x40000; pos += 0x100 / sizeof(u32)) { - if (*pos == 0xCF42004D) { - tsec_ctxt.fw = (u8 *)pos; - found_tsec_fw = true; - break; - } - } - if (!found_tsec_fw) { - EPRINTF("Failed to locate TSEC firmware."); - goto out_wait; - } - - 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; - - u32 MAX_KEY = 6; - if (pkg1_id->kb >= KB_FIRMWARE_VERSION_620) - MAX_KEY = pkg1_id->kb + 1; - - if (pkg1_id->kb >= KB_FIRMWARE_VERSION_700) { - if (!f_stat("sd:/sept/payload.bak", NULL)) { - f_unlink("sd:/sept/payload.bin"); - f_rename("sd:/sept/payload.bak", "sd:/sept/payload.bin"); - } - - if (!(EMC(EMC_SCRATCH0) & EMC_SEPT_RUN)) { - // bundle lp0 fw for sept instead of loading it from SD as hekate does - sdram_lp0_save_params(sdram_get_params_patched()); - FIL fp; - if (f_stat("sd:/sept", NULL)) { - EPRINTF("On firmware 7.x+ but Sept missing.\nSkipping new key derivation..."); - goto get_tsec; - } - // backup post-reboot payload - if (!f_stat("sd:/sept/payload.bin", NULL)) - f_rename("sd:/sept/payload.bin", "sd:/sept/payload.bak"); - // write self to payload.bin to run again when sept finishes - f_open(&fp, "sd:/sept/payload.bin", FA_CREATE_NEW | FA_WRITE); - 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("%kFirmware 7.x or higher detected.\n%kRenamed /sept/payload.bin", colors[0], colors[1]); - gfx_printf("\n%k to /sept/payload.bak\n%kCopied self to /sept/payload.bin",colors[2], colors[3]); - sdmmc_storage_end(&storage); - if (!reboot_to_sept((u8 *)tsec_ctxt.fw, tsec_ctxt.size, pkg1_id->kb)) - goto out_wait; - } else { - se_aes_key_read(12, master_key[pkg1_id->kb], 0x10); - } - } - -get_tsec: ; - u8 tsec_keys[0x10 * 2] = {0}; - - if (pkg1_id->kb == KB_FIRMWARE_VERSION_620) { - u8 *tsec_paged = (u8 *)page_alloc(3); - memcpy(tsec_paged, (void *)tsec_ctxt.fw, tsec_ctxt.size); - tsec_ctxt.fw = tsec_paged; - } - - int res = 0; - - mc_disable_ahb_redirect(); - - while (tsec_query(tsec_keys, pkg1_id->kb, &tsec_ctxt) < 0) { - memset(tsec_keys, 0x00, 0x20); - retries++; - if (retries > 15) { - res = -1; - break; - } - } - free(pkg1); - - mc_enable_ahb_redirect(); - - if (res < 0) { - EPRINTFARGS("ERROR %x dumping TSEC.\n", res); - goto out_wait; - } - - TPRINTFARGS("%kTSEC key(s)... ", colors[0]); - - // Master key derivation - if (pkg1_id->kb == KB_FIRMWARE_VERSION_620 && _key_exists(tsec_keys + 0x10)) { - se_aes_key_set(8, tsec_keys + 0x10, 0x10); // mkek6 = unwrap(mkeks6, tsecroot) - se_aes_crypt_block_ecb(8, 0, master_kek[6], master_kek_sources[0]); - se_aes_key_set(8, master_kek[6], 0x10); // mkey = unwrap(mkek, mks) - se_aes_crypt_block_ecb(8, 0, master_key[6], master_key_source); - } - - if (pkg1_id->kb >= KB_FIRMWARE_VERSION_620 && _key_exists(master_key[pkg1_id->kb])) { - // derive all lower master keys in the event keyblobs are bad - for (u32 i = pkg1_id->kb; i > 0; i--) { - se_aes_key_set(8, master_key[i], 0x10); - se_aes_crypt_block_ecb(8, 0, master_key[i-1], mkey_vectors[i]); - } - } - - u8 *keyblob_block = (u8 *)calloc(NX_EMMC_BLOCKSIZE, 1); - u8 keyblob_mac[0x10] = {0}; - u32 sbk[4] = {FUSE(FUSE_PRIVATE_KEY0), FUSE(FUSE_PRIVATE_KEY1), - FUSE(FUSE_PRIVATE_KEY2), FUSE(FUSE_PRIVATE_KEY3)}; - 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++) { - 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); - se_aes_crypt_block_ecb(7, 0, keyblob_mac_key[i], keyblob_mac_key_source); // kbm = unwrap(kbms, kbk) - if (i == 0) - se_aes_crypt_block_ecb(7, 0, device_key, per_console_key_source); // devkey = unwrap(pcks, kbk0) - - // verify keyblob is not corrupt - sdmmc_storage_read(&storage, 0x180000 / NX_EMMC_BLOCKSIZE + i, 1, keyblob_block); - se_aes_key_set(3, keyblob_mac_key[i], 0x10); - se_aes_cmac(3, keyblob_mac, 0x10, keyblob_block + 0x10, 0xa0); - if (memcmp(keyblob_block, keyblob_mac, 0x10)) { - EPRINTFARGS("Keyblob %x corrupt.", i); - gfx_hexdump(i, keyblob_block, 0x10); - gfx_hexdump(i, keyblob_mac, 0x10); - continue; - } - - // decrypt keyblobs - se_aes_key_set(2, keyblob_key[i], 0x10); - se_aes_crypt_ctr(2, keyblob[i], 0x90, keyblob_block + 0x20, 0x90, keyblob_block + 0x10); - - memcpy(package1_key[i], keyblob[i] + 0x80, 0x10); - memcpy(master_kek[i], keyblob[i], 0x10); - se_aes_key_set(7, master_kek[i], 0x10); - se_aes_crypt_block_ecb(7, 0, master_key[i], master_key_source); - } - free(keyblob_block); - - TPRINTFARGS("%kMaster keys... ", colors[1]); - - /* key = unwrap(source, wrapped_key): - key_set(ks, wrapped_key), block_ecb(ks, 0, key, source) -> final key in key - */ - if (_key_exists(device_key)) { - se_aes_key_set(8, device_key, 0x10); - se_aes_unwrap_key(8, 8, retail_specific_aes_key_source); // kek = unwrap(rsaks, devkey) - se_aes_crypt_block_ecb(8, 0, bis_key[0] + 0x00, bis_key_source[0] + 0x00); // bkey = unwrap(bkeys, kek) - se_aes_crypt_block_ecb(8, 0, bis_key[0] + 0x10, bis_key_source[0] + 0x10); - // kek = generate_kek(bkeks, devkey, aeskek, aeskey) - _generate_kek(8, bis_kek_source, device_key, aes_kek_generation_source, aes_key_generation_source); - se_aes_crypt_block_ecb(8, 0, bis_key[1] + 0x00, bis_key_source[1] + 0x00); // bkey = unwrap(bkeys, kek) - se_aes_crypt_block_ecb(8, 0, bis_key[1] + 0x10, bis_key_source[1] + 0x10); - se_aes_crypt_block_ecb(8, 0, bis_key[2] + 0x00, bis_key_source[2] + 0x00); - se_aes_crypt_block_ecb(8, 0, bis_key[2] + 0x10, bis_key_source[2] + 0x10); - memcpy(bis_key[3], bis_key[2], 0x20); - } - - // Dump package2. - u8 *pkg2 = NULL; - pkg2_kip1_info_t *ki = NULL; - - sdmmc_storage_set_mmc_partition(&storage, 0); - // Parse eMMC GPT. - LIST_INIT(gpt); - nx_emmc_gpt_parse(&gpt, &storage); - - // 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."); - goto pkg2_done; - } - - // Read in package2 header and get package2 real size. - u8 *tmp = (u8 *)malloc(NX_EMMC_BLOCKSIZE); - nx_emmc_part_read(&storage, pkg2_part, 0x4000 / NX_EMMC_BLOCKSIZE, 1, tmp); - u32 *hdr_pkg2_raw = (u32 *)(tmp + 0x100); - u32 pkg2_size = hdr_pkg2_raw[0] ^ hdr_pkg2_raw[2] ^ hdr_pkg2_raw[3]; - free(tmp); - - if (pkg2_size > 0x7FC000) { - EPRINTF("Invalid Package2 header."); - goto pkg2_done; - } - // Read in package2. - u32 pkg2_size_aligned = ALIGN(pkg2_size, NX_EMMC_BLOCKSIZE); - pkg2 = malloc(pkg2_size_aligned); - 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. - pkg2_hdr_t *pkg2_hdr; - pkg2_hdr_t hdr; - u32 pkg2_kb; - for (pkg2_kb = 0; pkg2_kb < MAX_KEY; pkg2_kb++) { - se_aes_key_set(8, master_key[pkg2_kb], 0x10); - se_aes_unwrap_key(8, 8, package2_key_source); - memcpy(&hdr, pkg2 + 0x100, sizeof(pkg2_hdr_t)); - se_aes_crypt_ctr(8, &hdr, sizeof(pkg2_hdr_t), &hdr, sizeof(pkg2_hdr_t), &hdr); - if (hdr.magic == PKG2_MAGIC) - break; - } - if (pkg2_kb == MAX_KEY) { - EPRINTF("Failed to decrypt Package2."); - goto pkg2_done; - } else if (pkg2_kb != pkg1_id->kb) - EPRINTF("Warning: Package1-Package2 mismatch."); - pkg2_hdr = pkg2_decrypt(pkg2); - - TPRINTFARGS("%kDecrypt pkg2... ", colors[2]); - - LIST_INIT(kip1_info); - pkg2_parse_kips(&kip1_info, pkg2_hdr); - LIST_FOREACH_ENTRY(pkg2_kip1_info_t, ki_tmp, &kip1_info, link) { - if(ki_tmp->kip1->tid == 0x0100000000000000ULL) { - ki = malloc(sizeof(pkg2_kip1_info_t)); - memcpy(ki, ki_tmp, sizeof(pkg2_kip1_info_t)); - break; - } - } - LIST_FOREACH_SAFE(iter, &kip1_info) - free(CONTAINER_OF(iter, pkg2_kip1_info_t, link)); - - if (!ki) { - EPRINTF("Failed to parse INI1."); - goto pkg2_done; - } - - pkg2_decompress_kip(ki, 2 | 4); // we only need .rodata and .data - TPRINTFARGS("%kDecompress FS...", colors[3]); - - u8 hash_index = 0, hash_max = 9, hash_order[10], - key_lengths[10] = {0x10, 0x20, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x20, 0x20}; - u32 start_offset = 0, hks_offset_from_end = ki->kip1->sections[2].size_decomp, alignment = 1; - - // the FS keys appear in different orders - if (!memcmp(pkg1_id->id, "2016", 4)) { - // 1.0.0 doesn't have SD keys at all - hash_max = 6; - // the first key isn't aligned with the rest - memcpy(fs_keys[2], ki->kip1->data + ki->kip1->sections[0].size_comp + 0x1ae0e, 0x10); - hash_index = 1; - start_offset = 0x1b517; - hks_offset_from_end = 0x125bc2; - alignment = 0x10; - u8 temp[7] = {2, 3, 4, 0, 5, 6, 1}; - memcpy(hash_order, temp, 7); - } else { - // 2.0.0 - 8.0.0 - alignment = 0x40; - switch (pkg1_id->kb) { - case KB_FIRMWARE_VERSION_100_200: - start_offset = 0x1d226; - alignment = 0x10; - hks_offset_from_end -= 0x26fe; - break; - case KB_FIRMWARE_VERSION_300: - start_offset = 0x1ffa6; - hks_offset_from_end -= 0x298b; - break; - case KB_FIRMWARE_VERSION_301: - start_offset = 0x20026; - hks_offset_from_end -= 0x29ab; - break; - case KB_FIRMWARE_VERSION_400: - start_offset = 0x1c64c; - hks_offset_from_end -= 0x37eb; - break; - case KB_FIRMWARE_VERSION_500: - start_offset = 0x1f3b4; - hks_offset_from_end -= 0x465b; - alignment = 0x20; - break; - case KB_FIRMWARE_VERSION_600: - case KB_FIRMWARE_VERSION_620: - start_offset = 0x27350; - hks_offset_from_end = 0x17ff5; - alignment = 8; - break; - case KB_FIRMWARE_VERSION_700: - case KB_FIRMWARE_VERSION_810: - start_offset = 0x29c50; - hks_offset_from_end -= 0x6a73; - alignment = 8; - break; - } - - if (pkg1_id->kb <= KB_FIRMWARE_VERSION_500) { - u8 temp[10] = {2, 3, 4, 0, 5, 7, 9, 8, 6, 1}; - memcpy(hash_order, temp, 10); - } else { - u8 temp[10] = {6, 5, 7, 2, 3, 4, 0, 9, 8, 1}; - memcpy(hash_order, temp, 10); - } - } - - u8 temp_hash[0x20]; - for (u32 i = ki->kip1->sections[0].size_comp + start_offset; i < ki->size - 0x20; ) { - 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]]); - /*if (hash_index == hash_max) { - TPRINTFARGS("%d: %x end -%x", hash_index, (*(ki->kip1->data + i)), ki->size - i); - } else { - TPRINTFARGS("%d: %x rodata +%x", hash_index, (*(ki->kip1->data + i)), i - ki->kip1->sections[0].size_comp); - }*/ - i += key_lengths[hash_order[hash_index]]; - if (hash_index == hash_max - 1) { - i = ki->size - hks_offset_from_end; - } else if (hash_index == hash_max) { - break; - } - hash_index++; - } else { - i += alignment; - } - } - -pkg2_done: - free(pkg2); - free(ki); - - TPRINTFARGS("%kFS keys... ", colors[4]); - - if (_key_exists(fs_keys[0]) && _key_exists(fs_keys[1]) && _key_exists(master_key[0])) { - _generate_kek(8, fs_keys[0], master_key[0], aes_kek_generation_source, aes_key_generation_source); - se_aes_crypt_block_ecb(8, 0, header_key + 0x00, fs_keys[1] + 0x00); - se_aes_crypt_block_ecb(8, 0, header_key + 0x10, fs_keys[1] + 0x10); - } - - if (_key_exists(fs_keys[5]) && _key_exists(fs_keys[6]) && _key_exists(device_key)) { - _generate_kek(8, fs_keys[5], device_key, aes_kek_generation_source, NULL); - se_aes_crypt_block_ecb(8, 0, save_mac_key, fs_keys[6]); - } - - for (u32 i = 0; i < MAX_KEY; i++) { - if (!_key_exists(master_key[i])) - continue; - if (_key_exists(fs_keys[2]) && _key_exists(fs_keys[3]) && _key_exists(fs_keys[4])) { - for (u32 j = 0; j < 3; j++) { - _generate_kek(8, fs_keys[2 + j], master_key[i], aes_kek_generation_source, NULL); - se_aes_crypt_block_ecb(8, 0, key_area_key[j][i], aes_key_generation_source); - } - } - se_aes_key_set(8, master_key[i], 0x10); - se_aes_crypt_block_ecb(8, 0, package2_key[i], package2_key_source); - se_aes_crypt_block_ecb(8, 0, titlekek[i], titlekek_source); - } - - - if (!_key_exists(header_key) || !_key_exists(bis_key[2])) - goto key_output; - - se_aes_key_set(4, header_key + 0x00, 0x10); - se_aes_key_set(5, header_key + 0x10, 0x10); - se_aes_key_set(8, bis_key[2] + 0x00, 0x10); - se_aes_key_set(9, bis_key[2] + 0x10, 0x10); - - system_part = nx_emmc_part_find(&gpt, "SYSTEM"); - if (!system_part) { - EPRINTF("Failed to locate System partition."); - goto key_output; - } - __attribute__ ((aligned (16))) FATFS emmc_fs; - if (f_mount(&emmc_fs, "emmc:", 1)) { - EPRINTF("Mount failed."); - goto key_output; - } - - DIR dir; - FILINFO fno; - FIL fp; - // sysmodule NCAs only ever have one section (exefs) so 0x600 is sufficient - u8 *dec_header = (u8*)malloc(0x600); - char path[100] = "emmc:/Contents/registered"; - u32 titles_found = 0, title_limit = 2, read_bytes = 0; - if (!memcmp(pkg1_id->id, "2016", 4)) - title_limit = 1; - u8 *temp_file = NULL; - - if (f_opendir(&dir, path)) { - EPRINTF("Failed to open System:/Contents/registered."); - goto dismount; - } - - // prepopulate /Contents/registered in decrypted sector cache - while (!f_readdir(&dir, &fno) && fno.fname[0]) {} - f_closedir(&dir); - - if (f_opendir(&dir, path)) { - EPRINTF("Failed to open System:/Contents/registered."); - goto dismount; - } - - path[25] = '/'; - start_offset = 0; - - while (!f_readdir(&dir, &fno) && fno.fname[0] && titles_found < title_limit) { - memcpy(path + 26, fno.fname, 36); - path[62] = 0; - if (fno.fattrib & AM_DIR) - memcpy(path + 62, "/00", 4); - if (f_open(&fp, path, FA_READ | FA_OPEN_EXISTING)) continue; - if (f_lseek(&fp, 0x200) || f_read(&fp, dec_header, 32, &read_bytes) || read_bytes != 32) { - f_close(&fp); - continue; - } - se_aes_xts_crypt(5, 4, 0, 1, dec_header + 0x200, dec_header, 32, 1); - // es doesn't contain es key sources on 1.0.0 - if (memcmp(pkg1_id->id, "2016", 4) && *(u32*)(dec_header + 0x210) == 0x33 && dec_header[0x205] == 0) { - // es (offset 0x210 is lower half of titleid, 0x205 == 0 means it's program nca, not meta) - switch (pkg1_id->kb) { - case KB_FIRMWARE_VERSION_100_200: - start_offset = 0x557b; - break; - case KB_FIRMWARE_VERSION_300: - case KB_FIRMWARE_VERSION_301: - start_offset = 0x552d; - break; - case KB_FIRMWARE_VERSION_400: - start_offset = 0x5382; - break; - case KB_FIRMWARE_VERSION_500: - start_offset = 0x5a63; - break; - case KB_FIRMWARE_VERSION_600: - case KB_FIRMWARE_VERSION_620: - start_offset = 0x5674; - break; - case KB_FIRMWARE_VERSION_700: - case KB_FIRMWARE_VERSION_810: - start_offset = 0x5563; - break; - } - hash_order[2] = 2; - if (pkg1_id->kb < KB_FIRMWARE_VERSION_500) { - hash_order[0] = 0; - hash_order[1] = 1; - } else { - hash_order[0] = 1; - hash_order[1] = 0; - } - hash_index = 0; - // decrypt only what is needed to locate needed keys - temp_file = (u8*)_nca_process(5, 4, &fp, start_offset, 0xc0); - for (u32 i = 0; i <= 0xb0; ) { - se_calc_sha256(temp_hash, temp_file + i, 0x10); - if (!memcmp(temp_hash, es_hashes_sha256[hash_order[hash_index]], 0x10)) { - memcpy(es_keys[hash_order[hash_index]], temp_file + i, 0x10); - hash_index++; - if (hash_index == 3) - break; - i += 0x10; - } else { - i++; - } - } - free(temp_file); - temp_file = NULL; - titles_found++; - } else if (*(u32*)(dec_header + 0x210) == 0x24 && dec_header[0x205] == 0) { - // ssl - switch (pkg1_id->kb) { - case KB_FIRMWARE_VERSION_100_200: - start_offset = 0x3d41a; - break; - case KB_FIRMWARE_VERSION_300: - case KB_FIRMWARE_VERSION_301: - start_offset = 0x3cb81; - break; - case KB_FIRMWARE_VERSION_400: - start_offset = 0x3711c; - break; - case KB_FIRMWARE_VERSION_500: - start_offset = 0x37901; - break; - case KB_FIRMWARE_VERSION_600: - case KB_FIRMWARE_VERSION_620: - start_offset = 0x1d5be; - break; - case KB_FIRMWARE_VERSION_700: - case KB_FIRMWARE_VERSION_810: - start_offset = 0x1d437; - break; - } - if (!memcmp(pkg1_id->id, "2016", 4)) - start_offset = 0x449dc; - temp_file = (u8*)_nca_process(5, 4, &fp, start_offset, 0x70); - for (u32 i = 0; i <= 0x60; i++) { - se_calc_sha256(temp_hash, temp_file + i, 0x10); - if (!memcmp(temp_hash, ssl_hashes_sha256[1], 0x10)) { - memcpy(ssl_keys[1], temp_file + i, 0x10); - // only get ssl_rsa_kek_source_x from SSL on 1.0.0 - // we get it from ES on every other firmware - // and it's located oddly distant from ssl_rsa_kek_source_y on >= 6.0.0 - if (!memcmp(pkg1_id->id, "2016", 4)) { - se_calc_sha256(temp_hash, temp_file + i + 0x10, 0x10); - if (!memcmp(temp_hash, ssl_hashes_sha256[0], 0x10)) - memcpy(es_keys[2], temp_file + i + 0x10, 0x10); - } - break; - } - } - free(temp_file); - temp_file = NULL; - titles_found++; - } - f_close(&fp); - } - f_closedir(&dir); - free(dec_header); - - if (f_open(&fp, "sd:/Nintendo/Contents/private", FA_READ | FA_OPEN_EXISTING)) { - EPRINTF("Unable to locate SD seed. Skipping."); - goto dismount; - } - // get sd seed verification vector - if (f_read(&fp, temp_key, 0x10, &read_bytes) || read_bytes != 0x10) { - EPRINTF("Unable to locate SD seed. Skipping."); - f_close(&fp); - goto dismount; - } - 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; - } - - // locate sd seed - u8 read_buf[0x20] = {0}; - for (u32 i = 0; i < f_size(&fp); i += 0x4000) { - if (f_lseek(&fp, i) || f_read(&fp, read_buf, 0x20, &read_bytes) || read_bytes != 0x20) - break; - if (!memcmp(temp_key, read_buf, 0x10)) { - memcpy(sd_seed, read_buf + 0x10, 0x10); - break; - } - } - f_close(&fp); - -dismount: - f_mount(NULL, "emmc:", 1); - nx_emmc_gpt_free(&gpt); - sdmmc_storage_end(&storage); - - if (memcmp(pkg1_id->id, "2016", 4)) { - TPRINTFARGS("%kES & SSL keys...", colors[5]); - } else { - TPRINTFARGS("%kSSL keys... ", colors[5]); - } - - // derive eticket_rsa_kek and ssl_rsa_kek - if (_key_exists(es_keys[0]) && _key_exists(es_keys[1]) && _key_exists(master_key[0])) { - for (u32 i = 0; i < 0x10; i++) - temp_key[i] = aes_kek_generation_source[i] ^ aes_kek_seed_03[i]; - _generate_kek(8, es_keys[1], master_key[0], temp_key, NULL); - se_aes_crypt_block_ecb(8, 0, eticket_rsa_kek, es_keys[0]); - } - if (_key_exists(ssl_keys[1]) && _key_exists(es_keys[2]) && _key_exists(master_key[0])) { - for (u32 i = 0; i < 0x10; i++) - temp_key[i] = aes_kek_generation_source[i] ^ aes_kek_seed_01[i]; - _generate_kek(8, es_keys[2], master_key[0], temp_key, NULL); - se_aes_crypt_block_ecb(8, 0, ssl_rsa_kek, ssl_keys[1]); - } - -key_output: ; - __attribute__ ((aligned (16))) char text_buffer[0x3000] = {0}; - - 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("device_key", device_key, 0x10); - SAVE_KEY("eticket_rsa_kek", eticket_rsa_kek, 0x10); - SAVE_KEY("eticket_rsa_kek_source", es_keys[0], 0x10); - SAVE_KEY("eticket_rsa_kekek_source", es_keys[1], 0x10); - 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("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("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("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("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_FAMILY("master_key", master_key, 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("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); - for (u32 i = 0; i < 0x10; i++) - temp_key[i] = aes_kek_generation_source[i] ^ aes_kek_seed_03[i]; - SAVE_KEY("rsa_oaep_kek_generation_source", temp_key, 0x10); - for (u32 i = 0; i < 0x10; i++) - temp_key[i] = aes_kek_generation_source[i] ^ aes_kek_seed_01[i]; - SAVE_KEY("rsa_private_kek_generation_source", temp_key, 0x10); - SAVE_KEY("save_mac_kek_source", fs_keys[5], 0x10); - SAVE_KEY("save_mac_key", save_mac_key, 0x10); - SAVE_KEY("save_mac_key_source", fs_keys[6], 0x10); - SAVE_KEY("sd_card_kek_source", fs_keys[7], 0x10); - SAVE_KEY("sd_card_nca_key_source", fs_keys[8], 0x20); - SAVE_KEY("sd_card_save_key_source", fs_keys[9], 0x20); - SAVE_KEY("sd_seed", sd_seed, 0x10); - SAVE_KEY("secure_boot_key", sbk, 0x10); - SAVE_KEY("ssl_rsa_kek", ssl_rsa_kek, 0x10); - SAVE_KEY("ssl_rsa_kek_source_x", es_keys[2], 0x10); - SAVE_KEY("ssl_rsa_kek_source_y", ssl_keys[1], 0x10); - SAVE_KEY_FAMILY("titlekek", titlekek, 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) - SAVE_KEY("tsec_root_key", tsec_keys + 0x10, 0x10); - - //gfx_con.fntsz = 8; gfx_puts(text_buffer); gfx_con.fntsz = 16; - - TPRINTFARGS("\n%kFound %d keys.\n%kLockpick totally", colors[0], _key_count, colors[1]); - - f_mkdir("switch"); - char keyfile_path[30] = "sd:/switch/"; - if (!(fuse_read_odm(4) & 3)) - sprintf(&keyfile_path[11], "prod.keys"); - else - sprintf(&keyfile_path[11], "dev.keys"); - if (!sd_save_to_file(text_buffer, strlen(text_buffer), keyfile_path) && !f_stat(keyfile_path, &fno)) { - gfx_printf("%kWrote %d bytes to %s\n", colors[2], (u32)fno.fsize, keyfile_path); - } else - EPRINTF("Failed to save keys to SD."); - sd_unmount(); - -out_wait: - gfx_printf("\n%kVOL + -> Reboot to RCM\n%kVOL - -> Reboot normally\n%kPower -> Power off", colors[3], colors[4], colors[5]); - - u32 btn = btn_wait(); - if (btn & BTN_VOL_UP) - reboot_rcm(); - else if (btn & BTN_VOL_DOWN) - reboot_normal(); - else - power_off(); -} - -static void _save_key(const char *name, const void *data, const u32 len, char *outbuf) { - if (!_key_exists(data)) - return; - u32 pos = strlen(outbuf); - pos += sprintf(&outbuf[pos], "%s = ", name); - for (u32 i = 0; i < len; i++) - pos += sprintf(&outbuf[pos], "%02x", *(u8*)(data + i)); - sprintf(&outbuf[pos], "\n"); - _key_count++; -} - -static void _save_key_family(const char *name, const void *data, const u32 num_keys, const u32 len, char *outbuf) { - char temp_name[0x40] = {0}; - for (u32 i = 0; i < num_keys; i++) { - sprintf(temp_name, "%s_%02x", name, i); - _save_key(temp_name, data + i * len, len, outbuf); - } -} - -static void _generate_kek(u32 ks, const void *key_source, void *master_key, const void *kek_seed, const void *key_seed) { - if (!_key_exists(key_source) || !_key_exists(master_key) || !_key_exists(kek_seed)) - return; - - se_aes_key_set(ks, master_key, 0x10); - se_aes_unwrap_key(ks, ks, kek_seed); - se_aes_unwrap_key(ks, ks, key_source); - if (key_seed && _key_exists(key_seed)) - se_aes_unwrap_key(ks, ks, key_seed); -} - -static inline u32 _read_le_u32(const void *buffer, u32 offset) { - return (*(u8*)(buffer + offset + 0) ) | - (*(u8*)(buffer + offset + 1) << 0x08) | - (*(u8*)(buffer + offset + 2) << 0x10) | - (*(u8*)(buffer + offset + 3) << 0x18); -} - -static void *_nca_process(u32 hk_ks1, u32 hk_ks2, FIL *fp, u32 key_offset, u32 len) { - u32 read_bytes = 0, crypt_offset, read_size, num_files, string_table_size, rodata_offset; - - u8 *temp_file = (u8*)malloc(0x400), - ctr[0x10] = {0}; - if (f_lseek(fp, 0x200) || f_read(fp, temp_file, 0x400, &read_bytes) || read_bytes != 0x400) - return NULL; - se_aes_xts_crypt(hk_ks1, hk_ks2, 0, 1, temp_file, temp_file, 0x200, 2); - // both 1.x and 2.x use master_key_00 - temp_file[0x20] -= temp_file[0x20] ? 1 : 0; - // decrypt key area and load decrypted key area key - se_aes_key_set(7, key_area_key[temp_file[7]][temp_file[0x20]], 0x10); - se_aes_crypt_block_ecb(7, 0, temp_file + 0x120, temp_file + 0x120); - se_aes_key_set(2, temp_file + 0x120, 0x10); - for (u32 i = 0; i < 8; i++) - ctr[i] = temp_file[0x347 - i]; - crypt_offset = _read_le_u32(temp_file, 0x40) * 0x200 + _read_le_u32(temp_file, 0x240); - read_size = 0x10; - _nca_fread_ctr(2, fp, temp_file, crypt_offset, read_size, ctr); - num_files = _read_le_u32(temp_file, 4); - string_table_size = _read_le_u32(temp_file, 8); - if (!memcmp(temp_file + 0x10 + num_files * 0x18, "main.npdm", 9)) - crypt_offset += _read_le_u32(temp_file, 0x18); - crypt_offset += 0x10 + num_files * 0x18 + string_table_size; - read_size = 0x40; - _nca_fread_ctr(2, fp, temp_file, crypt_offset, read_size, ctr); - rodata_offset = _read_le_u32(temp_file, 0x20); - - void *buf = malloc(len); - _nca_fread_ctr(2, fp, buf, crypt_offset + rodata_offset + key_offset, len, ctr); - free(temp_file); - - return buf; -} - -static u32 _nca_fread_ctr(u32 ks, FIL *fp, void *buffer, u32 offset, u32 len, u8 *ctr) { - u32 br; - if (f_lseek(fp, offset) || f_read(fp, buffer, len, &br) || br != len) - return 0; - _update_ctr(ctr, offset); - - if (offset % 0x10) { - u8 *temp = (u8*)malloc(ALIGN(br + offset % 0x10, 0x10)); - memcpy(temp + offset % 0x10, buffer, br); - se_aes_crypt_ctr(ks, temp, ALIGN(br + offset % 0x10, 0x10), temp, ALIGN(br + offset % 0x10, 0x10), ctr); - memcpy(buffer, temp + offset % 0x10, br); - free(temp); - return br; - } - se_aes_crypt_ctr(ks, buffer, br, buffer, br, ctr); - return br; -} - -static void _update_ctr(u8 *ctr, u32 ofs) { - ofs >>= 4; - for (u32 i = 0; i < 4; i++, ofs >>= 8) - ctr[0x10-i-1] = (u8)(ofs & 0xff); -} diff --git a/source/libs/compr/blz.c b/source/libs/compr/blz.c index ffe78f0..226d011 100644 --- a/source/libs/compr/blz.c +++ b/source/libs/compr/blz.c @@ -32,24 +32,24 @@ const blz_footer *blz_get_footer(const unsigned char *compData, unsigned int com } // From https://github.com/SciresM/hactool/blob/master/kip.c which is exactly how kernel does it, thanks SciresM! -int blz_uncompress_inplace(unsigned char *dataBuf, unsigned int compSize, const blz_footer *footer) +int blz_uncompress_inplace(unsigned char *dataBuf, unsigned int compSize, const blz_footer *footer) { u32 addl_size = footer->addl_size; u32 header_size = footer->header_size; u32 cmp_and_hdr_size = footer->cmp_and_hdr_size; - + unsigned char* cmp_start = &dataBuf[compSize] - cmp_and_hdr_size; u32 cmp_ofs = cmp_and_hdr_size - header_size; u32 out_ofs = cmp_and_hdr_size + addl_size; - - while (out_ofs) + + while (out_ofs) { unsigned char control = cmp_start[--cmp_ofs]; - for (unsigned int i=0; i<8; i++) + for (unsigned int i=0; i<8; i++) { - if (control & 0x80) + if (control & 0x80) { - if (cmp_ofs < 2) + if (cmp_ofs < 2) return 0; // Out of bounds. cmp_ofs -= 2; @@ -64,17 +64,17 @@ int blz_uncompress_inplace(unsigned char *dataBuf, unsigned int compSize, const for (unsigned int j = 0; j < seg_size; j++) cmp_start[out_ofs + j] = cmp_start[out_ofs + j + seg_ofs]; } - else + else { // Copy directly. - if (cmp_ofs < 1) + if (cmp_ofs < 1) return 0; //out of bounds cmp_start[--out_ofs] = cmp_start[--cmp_ofs]; } control <<= 1; if (out_ofs == 0) // Blz works backwards, so if it reaches byte 0, it's done. - return 1; + return 1; } } 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 f33f011..46c7c09 100644 --- a/source/libs/fatfs/diskio.c +++ b/source/libs/fatfs/diskio.c @@ -24,15 +24,15 @@ /*-----------------------------------------------------------------------*/ #include + +#include "../../../common/memory_map.h" + #include "diskio.h" /* FatFs lower layer API */ #include "../../mem/heap.h" #include "../../sec/se.h" #include "../../storage/nx_emmc.h" #include "../../storage/sdmmc.h" -#define SDMMC_UPPER_BUFFER 0xB8000000 -#define DRAM_START 0x80000000 - extern sdmmc_storage_t sd_storage; extern sdmmc_storage_t storage; extern emmc_part_t *system_part; @@ -42,11 +42,13 @@ typedef struct { u32 visit_count; u8 tweak[0x10]; u8 cached_sector[0x200]; + u8 align[8]; } sector_cache_t; - + #define MAX_SEC_CACHE_ENTRIES 64 -static sector_cache_t *sector_cache = (sector_cache_t*)0x40020000; +static sector_cache_t *sector_cache = NULL; static u32 secindex = 0; +bool clear_sector_cache = false; DSTATUS disk_status ( BYTE pdrv /* Physical drive number to identify the drive */ @@ -105,7 +107,7 @@ static inline int _emmc_xts(u32 ks1, u32 ks2, u32 enc, u8 *tweak, bool regen_twe pdst += 0x10; } - se_aes_crypt_ecb(ks2, 0, dst, secsize, src, secsize); + se_aes_crypt_ecb(ks2, enc, dst, secsize, src, secsize); pdst = (u8 *)dst; @@ -134,14 +136,28 @@ DRESULT disk_read ( switch (pdrv) { case 0: - return sdmmc_storage_read(&sd_storage, sector, count, buff) ? RES_OK : RES_ERROR; + if (((u32)buff >= DRAM_START) && !((u32)buff % 8)) + return sdmmc_storage_read(&sd_storage, sector, count, buff) ? RES_OK : RES_ERROR; + u8 *buf = (u8 *)SDMMC_UPPER_BUFFER; + if (sdmmc_storage_read(&sd_storage, sector, count, buf)) + { + memcpy(buff, buf, 512 * count); + return RES_OK; + } + return RES_ERROR; case 1:; __attribute__ ((aligned (16))) static u8 tweak[0x10]; __attribute__ ((aligned (16))) static u64 prev_cluster = -1; __attribute__ ((aligned (16))) static u32 prev_sector = 0; - u32 tweak_exp = 0; - bool regen_tweak = true, cache_sector = false; + bool needs_cache_sector = false; + + if (secindex == 0 || clear_sector_cache) { + if (!sector_cache) + sector_cache = (sector_cache_t *)malloc(sizeof(sector_cache_t) * MAX_SEC_CACHE_ENTRIES); + clear_sector_cache = false; + secindex = 0; + } u32 s = 0; if (count == 1) { @@ -159,12 +175,14 @@ DRESULT disk_read ( if (s == secindex && s < MAX_SEC_CACHE_ENTRIES) { sector_cache[s].sector = sector; sector_cache[s].visit_count++; - cache_sector = true; + needs_cache_sector = true; secindex++; } } - + //system_part (pdrv == 1) ? system_part_sys : system_part_usr if (nx_emmc_part_read(&storage, system_part, sector, count, buff)) { + u32 tweak_exp = 0; + bool regen_tweak = true; if (prev_cluster != sector / 0x20) { // sector in different cluster than last read prev_cluster = sector / 0x20; tweak_exp = sector % 0x20; @@ -177,7 +195,7 @@ DRESULT disk_read ( // fatfs will never pull more than a cluster _emmc_xts(9, 8, 0, tweak, regen_tweak, tweak_exp, prev_cluster, buff, buff, count * 0x200); - if (cache_sector) { + if (needs_cache_sector) { memcpy(sector_cache[s].cached_sector, buff, 0x200); memcpy(sector_cache[s].tweak, tweak, 0x10); } @@ -198,7 +216,14 @@ DRESULT disk_write ( { if (pdrv == 1) return RES_WRPRT; - return sdmmc_storage_write(&sd_storage, sector, count, (void *)buff) ? RES_OK : RES_ERROR; + + if (((u32)buff >= DRAM_START) && !((u32)buff % 8)) + return sdmmc_storage_write(&sd_storage, sector, count, (void *)buff) ? RES_OK : RES_ERROR; + u8 *buf = (u8 *)SDMMC_UPPER_BUFFER; //TODO: define this somewhere. + memcpy(buf, buff, 512 * count); + if (sdmmc_storage_write(&sd_storage, sector, count, buf)) + return RES_OK; + return RES_ERROR; } DRESULT disk_ioctl ( diff --git a/source/libs/fatfs/ff.c b/source/libs/fatfs/ff.c index 38d6422..e171ccb 100644 --- a/source/libs/fatfs/ff.c +++ b/source/libs/fatfs/ff.c @@ -1,10 +1,25 @@ +/* + * Copyright (c) 2018 naehrwert + * Copyright (c) 2018-2019 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + /*----------------------------------------------------------------------------/ -/ FatFs - Generic FAT Filesystem Module R0.13c (p3) / +/ FatFs - Generic FAT Filesystem Module R0.13c (p4) / /-----------------------------------------------------------------------------/ / / Copyright (C) 2018, ChaN, all right reserved. -/ Copyright (c) 2018 naehrwert -/ Copyright (C) 2018-2019 CTCaer / / FatFs module is an open source software. Redistribution and use of FatFs in / source and binary forms, with or without modification, are permitted provided @@ -33,6 +48,18 @@ Module Private Definitions ---------------------------------------------------------------------------*/ +/* +PARTITION VolToPart[] = { + {0, 1}, + {1, 8}, + {1, 9} +}; +*/ + +PARTITION VolToPart[] = { + {0, 1}, + {1, 0} +}; #if FF_DEFINED != 86604 /* Revision ID */ #error Wrong include file (ff.h). @@ -3472,7 +3499,7 @@ static FRESULT find_volume ( /* FR_OK(0): successful, !=0: an error occurred */ #if FF_USE_LFN == 1 fs->lfnbuf = LfnBuf; /* Static LFN working buffer */ #if FF_FS_EXFAT - fs->dirbuf = DirBuf; /* Static directory block scratchpad buuffer */ + fs->dirbuf = DirBuf; /* Static directory block scratchpad buffer */ #endif #endif #if FF_FS_RPATH != 0 @@ -4243,9 +4270,9 @@ FRESULT f_getcwd ( TCHAR *tp = buff; #if FF_VOLUMES >= 2 UINT vl; -#endif #if FF_STR_VOLUME_ID const char *vp; +#endif #endif FILINFO fno; DEF_NAMBUF @@ -4726,7 +4753,7 @@ FRESULT f_getfree ( /* Get logical drive */ res = find_volume(&path, &fs, 0); if (res == FR_OK) { - *fatfs = fs; /* Return ptr to the fs object */ + if (fatfs) *fatfs = fs; /* Return ptr to the fs object */ /* If free_clst is valid, return it without full FAT scan */ if (fs->free_clst <= fs->n_fatent - 2) { *nclst = fs->free_clst; @@ -6024,7 +6051,7 @@ FRESULT f_mkfs ( sys = 0x07; /* HPFS/NTFS/exFAT */ } else { if (fmt == FS_FAT32) { - sys = 0x0C; /* FAT32X */ + sys = 0x0B; /* FAT32X */ } else { if (sz_vol >= 0x10000) { sys = 0x06; /* FAT12/16 (large) */ @@ -6107,19 +6134,20 @@ FRESULT f_fdisk ( mem_set(buf, 0, FF_MAX_SS); p = buf + MBR_Table; b_cyl = 0; for (i = 0; i < 4; i++, p += SZ_PTE) { - p_cyl = (szt[i] <= 100U) ? (DWORD)tot_cyl * szt[i] / 100 : szt[i] / sz_cyl; /* Number of cylinders */ + p_cyl = (szt[i] <= 100U) ? (DWORD)tot_cyl * (szt[i] / 100) : szt[i] / sz_cyl; /* Number of cylinders */ if (p_cyl == 0) continue; s_part = (DWORD)sz_cyl * b_cyl; sz_part = (DWORD)sz_cyl * p_cyl; if (i == 0) { /* Exclude first track of cylinder 0 */ s_hd = 1; - s_part += 63; sz_part -= 63; + s_part += 32768; sz_part -= 32768; } else { s_hd = 0; } e_cyl = b_cyl + p_cyl - 1; /* End cylinder */ if (e_cyl >= tot_cyl) LEAVE_MKFS(FR_INVALID_PARAMETER); + /* Set partition table */ p[1] = s_hd; /* Start head */ p[2] = (BYTE)(((b_cyl >> 2) & 0xC0) | 1); /* Start sector */ @@ -6130,7 +6158,6 @@ FRESULT f_fdisk ( p[7] = (BYTE)e_cyl; /* End cylinder */ st_dword(p + 8, s_part); /* Start sector in LBA */ st_dword(p + 12, sz_part); /* Number of sectors */ - /* Next partition */ b_cyl += p_cyl; } @@ -6632,4 +6659,3 @@ FRESULT f_setcp ( return FR_OK; } #endif /* FF_CODE_PAGE == 0 */ - diff --git a/source/libs/fatfs/ff.h b/source/libs/fatfs/ff.h index 41a6571..f867131 100644 --- a/source/libs/fatfs/ff.h +++ b/source/libs/fatfs/ff.h @@ -95,6 +95,7 @@ typedef DWORD FSIZE_t; /* Filesystem object structure (FATFS) */ typedef struct { + BYTE win[FF_MAX_SS]; /* Disk access window for Directory, FAT (and file data at tiny cfg) */ BYTE fs_type; /* Filesystem type (0:not mounted) */ BYTE pdrv; /* Associated physical drive */ BYTE n_fats; /* Number of FATs (1 or 2) */ @@ -137,8 +138,6 @@ typedef struct { DWORD bitbase; /* Allocation bitmap base sector */ #endif DWORD winsect; /* Current sector appearing in the win[] */ - DWORD padding; /* Ensure window is 16-aligned */ - BYTE win[FF_MAX_SS]; /* Disk access window for Directory, FAT (and file data at tiny cfg) */ } FATFS; @@ -169,6 +168,9 @@ typedef struct { /* File object structure (FIL) */ typedef struct { +#if !FF_FS_TINY + BYTE buf[FF_MAX_SS]; /* File private data read/write window */ +#endif FFOBJID obj; /* Object identifier (must be the 1st member to detect invalid object pointer) */ BYTE flag; /* File status flags */ BYTE err; /* Abort flag (error code) */ @@ -179,9 +181,6 @@ typedef struct { DWORD dir_sect; /* Sector number containing the directory entry (not used at exFAT) */ BYTE* dir_ptr; /* Pointer to the directory entry in the win[] (not used at exFAT) */ #endif -#if !FF_FS_TINY - BYTE buf[FF_MAX_SS]; /* File private data read/write window */ -#endif #if FF_USE_FASTSEEK DWORD* cltbl; /* Pointer to the cluster link map table (nulled on open, set by application) */ #endif @@ -280,7 +279,7 @@ FRESULT f_getfree (const TCHAR* path, DWORD* nclst, FATFS** fatfs); /* Get numbe FRESULT f_getlabel (const TCHAR* path, TCHAR* label, DWORD* vsn); /* Get volume label */ FRESULT f_setlabel (const TCHAR* label); /* Set volume label */ FRESULT f_forward (FIL* fp, UINT(*func)(const BYTE*,UINT), UINT btf, UINT* bf); /* Forward data to the stream */ -FRESULT f_expand (FIL* fp, FSIZE_t szf, BYTE opt); /* Allocate a contiguous block to the file */ +FRESULT f_expand (FIL* fp, FSIZE_t fsz, BYTE opt); /* Allocate a contiguous block to the file */ FRESULT f_mount (FATFS* fs, const TCHAR* path, BYTE opt); /* Mount/Unmount a logical drive */ FRESULT f_mkfs (const TCHAR* path, BYTE opt, DWORD au, void* work, UINT len); /* Create a FAT volume */ FRESULT f_fdisk (BYTE pdrv, const DWORD* szt, void* work); /* Divide a physical drive into some partitions */ diff --git a/source/libs/fatfs/ffconf.h b/source/libs/fatfs/ffconf.h index ca13b33..cbe319a 100644 --- a/source/libs/fatfs/ffconf.h +++ b/source/libs/fatfs/ffconf.h @@ -25,7 +25,7 @@ / 3: f_lseek() function is removed in addition to 2. */ -#define FF_USE_STRFUNC 0 +#define FF_USE_STRFUNC 2 /* This option switches string functions, f_gets(), f_putc(), f_puts() and f_printf(). / / 0: Disable string functions. @@ -33,12 +33,12 @@ / 2: Enable with LF-CRLF conversion. */ -#define FF_USE_FIND 0 +#define FF_USE_FIND 1 /* This option switches filtered directory read functions, f_findfirst() and / f_findnext(). (0:Disable, 1:Enable 2:Enable with matching altname[] too) */ -#define FF_USE_MKFS 0 +#define FF_USE_MKFS 1 /* This option switches f_mkfs() function. (0:Disable or 1:Enable) */ @@ -50,7 +50,7 @@ /* This option switches f_expand function. (0:Disable or 1:Enable) */ -#define FF_USE_CHMOD 0 +#define FF_USE_CHMOD 1 /* This option switches attribute manipulation functions, f_chmod() and f_utime(). / (0:Disable or 1:Enable) Also FF_FS_READONLY needs to be 0 to enable this option. */ @@ -97,7 +97,7 @@ */ -#define FF_USE_LFN 1 +#define FF_USE_LFN 3 #define FF_MAX_LFN 255 /* The FF_USE_LFN switches the support for LFN (long file name). / @@ -169,6 +169,7 @@ #define FF_STR_VOLUME_ID 1 #define FF_VOLUME_STRS "sd", "emmc" + /* FF_STR_VOLUME_ID switches support for volume ID in arbitrary strings. / When FF_STR_VOLUME_ID is set to 1 or 2, arbitrary strings can be used as drive / number in the path name. FF_VOLUME_STRS defines the volume ID strings for each @@ -181,7 +182,7 @@ */ -#define FF_MULTI_PARTITION 0 +#define FF_MULTI_PARTITION 1 /* This option switches support for multiple volumes on the physical drive. / By default (0), each logical drive number is bound to the same physical drive / number and only an FAT volume found on the physical drive will be mounted. diff --git a/source/libs/fatfs/ffunicode.c b/source/libs/fatfs/ffunicode.c index bc23f80..9f03963 100644 --- a/source/libs/fatfs/ffunicode.c +++ b/source/libs/fatfs/ffunicode.c @@ -34,7 +34,6 @@ #define MERGE2(a, b) a ## b #define CVTBL(tbl, cp) MERGE2(tbl, cp) - /*------------------------------------------------------------------------*/ /* Code Conversion Tables */ /*------------------------------------------------------------------------*/ @@ -623,5 +622,4 @@ DWORD ff_wtoupper ( /* Returns up-converted code point */ return uni; } - #endif /* #if FF_USE_LFN */ diff --git a/source/main.c b/source/main.c index 4c0cd0c..601c2ca 100644 --- a/source/main.c +++ b/source/main.c @@ -18,61 +18,73 @@ #include +#include "config/config.h" +#include "config/ini.h" #include "gfx/di.h" #include "gfx/gfx.h" +#include "gfx/tui.h" +#include "hos/pkg1.h" #include "libs/fatfs/ff.h" #include "mem/heap.h" +#include "mem/minerva.h" #include "power/max77620.h" #include "rtc/max77620-rtc.h" +#include "soc/bpmp.h" #include "soc/hw_init.h" +#include "storage/emummc.h" +#include "storage/nx_emmc.h" #include "storage/sdmmc.h" -#include "utils/util.h" #include "utils/btn.h" -#include "meme/main.h" -#include "meme/utils.h" +#include "utils/dirlist.h" +#include "utils/sprintf.h" +#include "utils/util.h" +#include "tegraexplorer/te.h" + +//#include "keys/keys.h" sdmmc_t sd_sdmmc; sdmmc_storage_t sd_storage; __attribute__ ((aligned (16))) FATFS sd_fs; static bool sd_mounted; - +volatile nyx_storage_t *nyx_str = (nyx_storage_t *)NYX_STORAGE_ADDR; +hekate_config h_cfg; boot_cfg_t __attribute__((section ("._boot_cfg"))) b_cfg; bool sd_mount() { - if (sd_mounted) - return true; + if (sd_mounted) + return true; - if (!sdmmc_storage_init_sd(&sd_storage, &sd_sdmmc, SDMMC_1, SDMMC_BUS_WIDTH_4, 11)) - { - EPRINTF("Failed to init SD card.\nMake sure that it is inserted.\nOr that SD reader is properly seated!"); - } - else - { - int res = 0; - res = f_mount(&sd_fs, "sd:", 1); - if (res == FR_OK) - { - sd_mounted = 1; - return true; - } - else - { - EPRINTFARGS("Failed to mount SD card (FatFS Error %d).\nMake sure that a FAT partition exists..", res); - } - } + if (!sdmmc_storage_init_sd(&sd_storage, &sd_sdmmc, SDMMC_1, SDMMC_BUS_WIDTH_4, 11)) + { + EPRINTF("Failed to init SD card.\nMake sure that it is inserted.\nOr that SD reader is properly seated!"); + } + else + { + int res = 0; + res = f_mount(&sd_fs, "sd:", 1); + if (res == FR_OK) + { + sd_mounted = 1; + return true; + } + else + { + EPRINTFARGS("Failed to mount SD card (FatFS Error %d).\nMake sure that a FAT partition exists..", res); + } + } - return false; + return false; } void sd_unmount() { - if (sd_mounted) - { - f_mount(NULL, "sd:", 1); - sdmmc_storage_end(&sd_storage); - sd_mounted = false; - } + if (sd_mounted) + { + f_mount(NULL, "sd:", 1); + sdmmc_storage_end(&sd_storage); + sd_mounted = false; + } } void *sd_file_read(const char *path, u32 *fsize) @@ -102,65 +114,341 @@ void *sd_file_read(const char *path, u32 *fsize) int sd_save_to_file(void *buf, u32 size, const char *filename) { - FIL fp; - u32 res = 0; - res = f_open(&fp, filename, FA_CREATE_ALWAYS | FA_WRITE); - if (res) - { - EPRINTFARGS("Error (%d) creating file\n%s.\n", res, filename); - return 1; - } + FIL fp; + u32 res = 0; + res = f_open(&fp, filename, FA_CREATE_ALWAYS | FA_WRITE); + if (res) + { + EPRINTFARGS("Error (%d) creating file\n%s.\n", res, filename); + return res; + } - f_write(&fp, buf, size, NULL); - f_close(&fp); + f_write(&fp, buf, size, NULL); + f_close(&fp); - return 0; + return 0; } // This is a safe and unused DRAM region for our payloads. #define RELOC_META_OFF 0x7C #define PATCHED_RELOC_SZ 0x94 #define PATCHED_RELOC_STACK 0x40007000 +#define PATCHED_RELOC_ENTRY 0x40010000 +#define EXT_PAYLOAD_ADDR 0xC03C0000 +#define RCM_PAYLOAD_ADDR (EXT_PAYLOAD_ADDR + ALIGN(PATCHED_RELOC_SZ, 0x10)) #define COREBOOT_ADDR (0xD0000000 - 0x100000) #define CBFS_DRAM_EN_ADDR 0x4003e000 #define CBFS_DRAM_MAGIC 0x4452414D // "DRAM" - void reloc_patcher(u32 payload_dst, u32 payload_src, u32 payload_size) { - memcpy((u8 *)payload_src, (u8 *)IPL_LOAD_ADDR, PATCHED_RELOC_SZ); + memcpy((u8 *)payload_src, (u8 *)IPL_LOAD_ADDR, PATCHED_RELOC_SZ); - volatile reloc_meta_t *relocator = (reloc_meta_t *)(payload_src + RELOC_META_OFF); + volatile reloc_meta_t *relocator = (reloc_meta_t *)(payload_src + RELOC_META_OFF); - relocator->start = payload_dst - ALIGN(PATCHED_RELOC_SZ, 0x10); - relocator->stack = PATCHED_RELOC_STACK; - relocator->end = payload_dst + payload_size; - relocator->ep = payload_dst; + relocator->start = payload_dst - ALIGN(PATCHED_RELOC_SZ, 0x10); + relocator->stack = PATCHED_RELOC_STACK; + relocator->end = payload_dst + payload_size; + relocator->ep = payload_dst; - if (payload_size == 0x7000) - { - memcpy((u8 *)(payload_src + ALIGN(PATCHED_RELOC_SZ, 0x10)), (u8 *)COREBOOT_ADDR, 0x7000); //Bootblock - *(vu32 *)CBFS_DRAM_EN_ADDR = CBFS_DRAM_MAGIC; - } + if (payload_size == 0x7000) + { + memcpy((u8 *)(payload_src + ALIGN(PATCHED_RELOC_SZ, 0x10)), (u8 *)COREBOOT_ADDR, 0x7000); //Bootblock + *(vu32 *)CBFS_DRAM_EN_ADDR = CBFS_DRAM_MAGIC; + } } -#define IPL_STACK_TOP 0x4003F000 +int launch_payload(char *path) +{ + gfx_clear_grey(0x1B); + gfx_con_setpos(0, 0); + if (!path) + return 1; + + if (sd_mount()) + { + FIL fp; + if (f_open(&fp, path, FA_READ)) + { + EPRINTFARGS("Payload file is missing!\n(%s)", path); + sd_unmount(); + + return 1; + } + + // Read and copy the payload to our chosen address + void *buf; + u32 size = f_size(&fp); + + if (size < 0x30000) + buf = (void *)RCM_PAYLOAD_ADDR; + else + buf = (void *)COREBOOT_ADDR; + + if (f_read(&fp, buf, size, NULL)) + { + f_close(&fp); + sd_unmount(); + + return 1; + } + + f_close(&fp); + + sd_unmount(); + + if (size < 0x30000) + { + reloc_patcher(PATCHED_RELOC_ENTRY, EXT_PAYLOAD_ADDR, ALIGN(size, 0x10)); + + reconfig_hw_workaround(false, byte_swap_32(*(u32 *)(buf + size - sizeof(u32)))); + } + else + { + reloc_patcher(PATCHED_RELOC_ENTRY, EXT_PAYLOAD_ADDR, 0x7000); + reconfig_hw_workaround(true, 0); + } + + // Some cards (Sandisk U1), do not like a fast power cycle. Wait min 100ms. + sdmmc_storage_init_wait_sd(); + + void (*ext_payload_ptr)() = (void *)EXT_PAYLOAD_ADDR; + + // Launch our payload. + (*ext_payload_ptr)(); + } + + return 1; +} + +void launch_tools() +{ + u8 max_entries = 61; + char *filelist = NULL; + char *file_sec = NULL; + char *dir = NULL; + + ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * (max_entries + 3)); + + gfx_clear_grey(0x1B); + gfx_con_setpos(0, 0); + + if (sd_mount()) + { + dir = (char *)malloc(256); + + memcpy(dir, "sd:/bootloader/payloads", 24); + + filelist = dirlist(dir, NULL, false); + + u32 i = 0; + u32 i_off = 2; + + if (filelist) + { + // Build configuration menu. + u32 color_idx = 0; + + ments[0].type = MENT_BACK; + ments[0].caption = "Back"; + ments[0].color = colors[(color_idx++) % 6]; + ments[1].type = MENT_CHGLINE; + ments[1].color = colors[(color_idx++) % 6]; + if (!f_stat("sd:/atmosphere/reboot_payload.bin", NULL)) + { + ments[i_off].type = INI_CHOICE; + ments[i_off].caption = "reboot_payload.bin"; + ments[i_off].color = colors[(color_idx++) % 6]; + ments[i_off].data = "sd:/atmosphere/reboot_payload.bin"; + i_off++; + } + if (!f_stat("sd:/ReiNX.bin", NULL)) + { + ments[i_off].type = INI_CHOICE; + ments[i_off].caption = "ReiNX.bin"; + ments[i_off].color = colors[(color_idx++) % 6]; + ments[i_off].data = "sd:/ReiNX.bin"; + i_off++; + } + + while (true) + { + if (i > max_entries || !filelist[i * 256]) + break; + ments[i + i_off].type = INI_CHOICE; + ments[i + i_off].caption = &filelist[i * 256]; + ments[i + i_off].color = colors[(color_idx++) % 6]; + ments[i + i_off].data = &filelist[i * 256]; + + i++; + } + } + + if (i > 0) + { + memset(&ments[i + i_off], 0, sizeof(ment_t)); + menu_t menu = { ments, "Choose a file to launch", 0, 0 }; + + file_sec = (char *)tui_do_menu(&menu); + + if (!file_sec) + { + free(ments); + free(dir); + free(filelist); + sd_unmount(); + return; + } + } + else + EPRINTF("No payloads or modules found."); + + free(ments); + free(filelist); + } + else + { + free(ments); + goto out; + } + + if (file_sec) + { + if (memcmp("sd:/", file_sec, 4)) { + memcpy(dir + strlen(dir), "/", 2); + memcpy(dir + strlen(dir), file_sec, strlen(file_sec) + 1); + } + else + memcpy(dir, file_sec, strlen(file_sec) + 1); + + if (launch_payload(dir)) + { + EPRINTF("Failed to launch payload."); + free(dir); + } + } + +out: + sd_unmount(); + free(dir); + + btn_wait(); +} + +void dump_sysnand() +{ + h_cfg.emummc_force_disable = true; + b_cfg.extra_cfg &= ~EXTRA_CFG_DUMP_EMUMMC; + dump_keys(); +} + +void dump_emunand() +{ + if (h_cfg.emummc_force_disable) + return; + emu_cfg.enabled = 1; + b_cfg.extra_cfg |= EXTRA_CFG_DUMP_EMUMMC; + dump_keys(); +} + +ment_t ment_top[] = { + MDEF_HANDLER("Dump from SysNAND | Key generation: unk", dump_sysnand, COLOR_RED), + MDEF_HANDLER("Dump from EmuNAND | Key generation: unk", dump_emunand, COLOR_ORANGE), + MDEF_CAPTION("---------------", COLOR_YELLOW), + MDEF_HANDLER("Payloads...", launch_tools, COLOR_GREEN), + MDEF_CAPTION("---------------", COLOR_BLUE), + MDEF_HANDLER("Reboot (Normal)", reboot_normal, COLOR_VIOLET), + MDEF_HANDLER("Reboot (RCM)", reboot_rcm, COLOR_RED), + MDEF_HANDLER("Power off", power_off, COLOR_ORANGE), + MDEF_END() +}; + +menu_t menu_top = { ment_top, NULL, 0, 0 }; + +void _get_key_generations(char *sysnand_label, char *emunand_label) { + sdmmc_t sdmmc; + sdmmc_storage_t storage; + sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4); + u8 *pkg1 = (u8 *)malloc(NX_EMMC_BLOCKSIZE); + sdmmc_storage_set_mmc_partition(&storage, 1); + sdmmc_storage_read(&storage, 0x100000 / NX_EMMC_BLOCKSIZE, 1, pkg1); + const pkg1_id_t *pkg1_id = pkg1_identify(pkg1); + sdmmc_storage_end(&storage); + + if (pkg1_id) + sprintf(sysnand_label + 36, "% 3d", pkg1_id->kb); + ment_top[0].caption = sysnand_label; + if (h_cfg.emummc_force_disable) { + free(pkg1); + return; + } + + emummc_storage_init_mmc(&storage, &sdmmc); + memset(pkg1, 0, NX_EMMC_BLOCKSIZE); + emummc_storage_set_mmc_partition(&storage, 1); + emummc_storage_read(&storage, 0x100000 / NX_EMMC_BLOCKSIZE, 1, pkg1); + pkg1_id = pkg1_identify(pkg1); + emummc_storage_end(&storage); + + if (pkg1_id) + sprintf(emunand_label + 36, "% 3d", pkg1_id->kb); + free(pkg1); + ment_top[1].caption = emunand_label; +} + +#define IPL_STACK_TOP 0x90010000 #define IPL_HEAP_START 0x90020000 extern void pivot_stack(u32 stack_top); +// todo: chainload to reboot payload or payloads folder option? + void ipl_main() { - config_hw(); - pivot_stack(IPL_STACK_TOP); - heap_init(IPL_HEAP_START); + config_hw(); + pivot_stack(IPL_STACK_TOP); + heap_init(IPL_HEAP_START); - display_init(); - u32 *fb = display_init_framebuffer(); - gfx_init_ctxt(fb, 720, 1280, 720); - gfx_con_init(); - display_backlight_pwm_init(); + set_default_configuration(); - meme_main(); - sd_unmount(); + sd_mount(); + minerva_init(); + minerva_change_freq(FREQ_1600); + + display_init(); + u32 *fb = display_init_framebuffer(); + gfx_init_ctxt(fb, 720, 1280, 720); + gfx_con_init(); + display_backlight_pwm_init(); + display_backlight_brightness(100, 1000); + + bpmp_clk_rate_set(BPMP_CLK_DEFAULT_BOOST); + + /* + h_cfg.emummc_force_disable = emummc_load_cfg(); + + if (b_cfg.boot_cfg & BOOT_CFG_SEPT_RUN) + { + if (!(b_cfg.extra_cfg & EXTRA_CFG_DUMP_EMUMMC)) + h_cfg.emummc_force_disable = true; + dump_keys(); + } + + if (h_cfg.emummc_force_disable) + { + ment_top[1].type = MENT_CAPTION; + ment_top[1].color = 0xFF555555; + ment_top[1].handler = NULL; + } + + _get_key_generations((char *)ment_top[0].caption, (char *)ment_top[1].caption); + + while (true) + tui_do_menu(&menu_top); + */ + + te_main(); + + while (true) + bpmp_halt(); } diff --git a/source/mem/heap.c b/source/mem/heap.c index e637dd2..1e3493a 100644 --- a/source/mem/heap.c +++ b/source/mem/heap.c @@ -17,6 +17,7 @@ #include #include "heap.h" +#include "../gfx/gfx.h" #include "../../common/common_heap.h" static void _heap_create(heap_t *heap, u32 start) @@ -25,12 +26,13 @@ static void _heap_create(heap_t *heap, u32 start) heap->first = NULL; } -static u32 _heap_alloc(heap_t *heap, u32 size, u32 alignment) +// Node info is before node address. +static u32 _heap_alloc(heap_t *heap, u32 size) { hnode_t *node, *new; - int search = 1; - size = ALIGN(size, alignment); + // Align to cache line size. + size = ALIGN(size, sizeof(hnode_t)); if (!heap->first) { @@ -45,26 +47,35 @@ static u32 _heap_alloc(heap_t *heap, u32 size, u32 alignment) } node = heap->first; - while (search) + while (true) { - if (!node->used && size + sizeof(hnode_t) < node->size) + if (!node->used && (size <= node->size)) { + u32 new_size = node->size - size; new = (hnode_t *)((u32)node + sizeof(hnode_t) + size); - new->size = node->size - sizeof(hnode_t) - size; + // If there's aligned leftover space, create a new node. + if (new_size >= (sizeof(hnode_t) << 2)) + { + new->size = new_size - sizeof(hnode_t); + new->used = 0; + new->next = node->next; + new->next->prev = new; + new->prev = node; + node->next = new; + } + else + size += new_size; + node->size = size; node->used = 1; - new->used = 0; - new->next = node->next; - new->prev = node; - node->next = new; return (u32)node + sizeof(hnode_t); } if (node->next) node = node->next; else - search = 0; + break; } new = (hnode_t *)((u32)node + sizeof(hnode_t) + node->size); @@ -107,17 +118,12 @@ void heap_init(u32 base) void *malloc(u32 size) { - return (void *)_heap_alloc(&_heap, size, 0x10); -} - -void *memalign(u32 align, u32 size) -{ - return (void *)_heap_alloc(&_heap, size, align); + return (void *)_heap_alloc(&_heap, size); } void *calloc(u32 num, u32 size) { - void *res = (void *)_heap_alloc(&_heap, num * size, 0x10); + void *res = (void *)_heap_alloc(&_heap, num * size); memset(res, 0, num * size); return res; } @@ -127,3 +133,30 @@ void free(void *buf) if ((u32)buf >= _heap.start) _heap_free(&_heap, (u32)buf); } + +void heap_monitor(heap_monitor_t *mon, bool print_node_stats) +{ + u32 count = 0; + memset(mon, 0, sizeof(heap_monitor_t)); + + hnode_t *node = _heap.first; + while (true) + { + if (node->used) + mon->used += node->size + sizeof(hnode_t); + else + mon->total += node->size + sizeof(hnode_t); + + if (print_node_stats) + gfx_printf("%3d - %d, addr: 0x%08X, size: 0x%X\n", + count, node->used, (u32)node + sizeof(hnode_t), node->size); + + count++; + + if (node->next) + node = node->next; + else + break; + } + mon->total += mon->used; +} diff --git a/source/mem/heap.h b/source/mem/heap.h index ad0783c..4ec3fb0 100644 --- a/source/mem/heap.h +++ b/source/mem/heap.h @@ -18,11 +18,12 @@ #define _HEAP_H_ #include "../utils/types.h" +#include "../../common/common_heap.h" void heap_init(u32 base); void *malloc(u32 size); void *calloc(u32 num, u32 size); void free(void *buf); -void *memalign(u32 align, u32 size); +void heap_monitor(heap_monitor_t *mon, bool print_node_stats); #endif diff --git a/source/mem/mc.c b/source/mem/mc.c index c799573..dd508e2 100644 --- a/source/mem/mc.c +++ b/source/mem/mc.c @@ -127,7 +127,7 @@ void mc_disable_ahb_redirect() void mc_enable() { CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC) & 0x1FFFFFFF) | 0x40000000; - // Enable MIPI CAL clock. + // Enable EMC clock. CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) = (CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) & 0xFDFFFFFF) | 0x2000000; // Enable MC clock. CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) = (CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) & 0xFFFFFFFE) | 1; diff --git a/source/mem/minerva.c b/source/mem/minerva.c new file mode 100644 index 0000000..68aa66d --- /dev/null +++ b/source/mem/minerva.c @@ -0,0 +1,105 @@ +/* + * 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" + +extern volatile nyx_storage_t *nyx_str; + +u32 minerva_init() +{ + u32 curr_ram_idx = 0; + + mtc_config_t *mtc_cfg = (mtc_config_t *)&nyx_str->mtc_cfg; + + // Set table to nyx storage. + mtc_cfg->mtc_table = (emc_table_t *)&nyx_str->mtc_table; + + mtc_cfg->sdram_id = (fuse_read_odm(4) >> 3) & 0x1F; + mtc_cfg->init_done = MTC_NEW_MAGIC; // Initialize mtc table. + + u32 ep_addr = ianos_loader(false, "bootloader/sys/libsys_minerva.bso", DRAM_LIB, (void *)mtc_cfg); + + // Ensure that Minerva is new. + if (mtc_cfg->init_done == MTC_INIT_MAGIC) + minerva_cfg = (void *)ep_addr; + + if (!minerva_cfg) + return 1; + + // 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); + + // FSP WAR. + mtc_cfg->train_mode = OP_SWITCH; + mtc_cfg->rate_to = 800000; + minerva_cfg(mtc_cfg, NULL); + + // Switch to max. + mtc_cfg->rate_to = 1600000; + minerva_cfg(mtc_cfg, NULL); + + return 0; +} + +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 (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 (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..00228f4 --- /dev/null +++ b/source/mem/minerva.h @@ -0,0 +1,65 @@ +/* + * 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 MTC_INIT_MAGIC 0x3043544D +#define MTC_NEW_MAGIC 0x5243544D + +#define EMC_PERIODIC_TRAIN_MS 250 + +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; + bool init_done; +} 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 *); +u32 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/mem/sdram.c b/source/mem/sdram.c index 96e1792..a9a26d3 100644 --- a/source/mem/sdram.c +++ b/source/mem/sdram.c @@ -16,17 +16,18 @@ * along with this program. If not, see . */ -#include "../soc/i2c.h" -#include "../soc/t210.h" #include "mc.h" #include "emc.h" #include "sdram_param_t210.h" -#include "../soc/pmc.h" -#include "../utils/util.h" -#include "../soc/fuse.h" +#include "../../common/memory_map.h" #include "../power/max77620.h" #include "../power/max7762x.h" #include "../soc/clock.h" +#include "../soc/fuse.h" +#include "../soc/i2c.h" +#include "../soc/pmc.h" +#include "../soc/t210.h" +#include "../utils/util.h" #define CONFIG_SDRAM_COMPRESS_CFG @@ -39,24 +40,42 @@ static u32 _get_sdram_id() { - return (fuse_read_odm(4) & 0x38) >> 3; + u32 sdram_id = (fuse_read_odm(4) & 0x38) >> 3; + + // Check if id is proper. + if (sdram_id > 7) + sdram_id = 0; + + return sdram_id; } static void _sdram_config(const sdram_params_t *params) { - PMC(APBDEV_PMC_IO_DPD3_REQ) = (((4 * params->emc_pmc_scratch1 >> 2) + 0x80000000) ^ 0xFFFF) & 0xC000FFFF; + // Program DPD3/DPD4 regs (coldboot path). + // Enable sel_dpd on unused pins. + u32 dpd_req = (params->emc_pmc_scratch1 & 0x3FFFFFFF) | 0x80000000; + PMC(APBDEV_PMC_IO_DPD3_REQ) = (dpd_req ^ 0xFFFF) & 0xC000FFFF; usleep(params->pmc_io_dpd3_req_wait); - u32 req = (4 * params->emc_pmc_scratch2 >> 2) + 0x80000000; - PMC(APBDEV_PMC_IO_DPD4_REQ) = (req >> 16 << 16) ^ 0x3FFF0000; + // Disable e_dpd_vttgen. + dpd_req = (params->emc_pmc_scratch2 & 0x3FFFFFFF) | 0x80000000; + PMC(APBDEV_PMC_IO_DPD4_REQ) = (dpd_req & 0xFFFF0000) ^ 0x3FFF0000; usleep(params->pmc_io_dpd4_req_wait); - PMC(APBDEV_PMC_IO_DPD4_REQ) = (req ^ 0xFFFF) & 0xC000FFFF; + + // Disable e_dpd_bg. + PMC(APBDEV_PMC_IO_DPD4_REQ) = (dpd_req ^ 0xFFFF) & 0xC000FFFF; usleep(params->pmc_io_dpd4_req_wait); + PMC(APBDEV_PMC_WEAK_BIAS) = 0; usleep(1); + // Start clocks. CLOCK(CLK_RST_CONTROLLER_PLLM_MISC1) = params->pllm_setup_control; CLOCK(CLK_RST_CONTROLLER_PLLM_MISC2) = 0; + + // u32 tmp = (params->pllm_feedback_divider << 8) | params->pllm_input_divider | ((params->pllm_post_divider & 0xFFFF) << 20); + // CLOCK(CLK_RST_CONTROLLER_PLLM_BASE) = tmp; + // CLOCK(CLK_RST_CONTROLLER_PLLM_BASE) = tmp | 0x40000000; CLOCK(CLK_RST_CONTROLLER_PLLM_BASE) = (params->pllm_feedback_divider << 8) | params->pllm_input_divider | 0x40000000 | ((params->pllm_post_divider & 0xFFFF) << 20); u32 wait_end = get_tmr_us() + 300; @@ -66,24 +85,35 @@ static void _sdram_config(const sdram_params_t *params) goto break_nosleep; } usleep(10); -break_nosleep: +break_nosleep: CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC) = ((params->mc_emem_arb_misc0 >> 11) & 0x10000) | (params->emc_clock_source & 0xFFFEFFFF); if (params->emc_clock_source_dll) CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC_DLL) = params->emc_clock_source_dll; if (params->clear_clock2_mc1) CLOCK(CLK_RST_CONTROLLER_CLK_ENB_W_CLR) = 0x40000000; - CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) = 0x2000001; - CLOCK(CLK_RST_CONTROLLER_CLK_ENB_X_SET) = 0x4000; - CLOCK(CLK_RST_CONTROLLER_RST_DEV_H_CLR) = 0x2000001; + + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) = 0x2000001; // Enable EMC and MEM clocks. + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_X_SET) = 0x4000; // Enable EMC_DLL clock. + CLOCK(CLK_RST_CONTROLLER_RST_DEV_H_CLR) = 0x2000001; // Clear EMC and MEM resets. + + // Set pad macros. EMC(EMC_PMACRO_VTTGEN_CTRL_0) = params->emc_pmacro_vttgen_ctrl0; EMC(EMC_PMACRO_VTTGEN_CTRL_1) = params->emc_pmacro_vttgen_ctrl1; EMC(EMC_PMACRO_VTTGEN_CTRL_2) = params->emc_pmacro_vttgen_ctrl2; - EMC(EMC_TIMING_CONTROL) = 1; - usleep(1); + + EMC(EMC_TIMING_CONTROL) = 1; // Trigger timing update so above writes take place. + usleep(10); // Ensure the regulators settle. + + // Select EMC write mux. EMC(EMC_DBG) = (params->emc_dbg_write_mux << 1) | params->emc_dbg; + + // Patch 2 using BCT spare variables. if (params->emc_bct_spare2) *(vu32 *)params->emc_bct_spare2 = params->emc_bct_spare3; + + // Program CMD mapping. Required before brick mapping, else + // we can't guarantee CK will be differential at all times. EMC(EMC_FBIO_CFG7) = params->emc_fbio_cfg7; EMC(EMC_CMD_MAPPING_CMD0_0) = params->emc_cmd_mapping_cmd0_0; EMC(EMC_CMD_MAPPING_CMD0_1) = params->emc_cmd_mapping_cmd0_1; @@ -98,25 +128,40 @@ break_nosleep: EMC(EMC_CMD_MAPPING_CMD3_1) = params->emc_cmd_mapping_cmd3_1; EMC(EMC_CMD_MAPPING_CMD3_2) = params->emc_cmd_mapping_cmd3_2; EMC(EMC_CMD_MAPPING_BYTE) = params->emc_cmd_mapping_byte; + + // Program brick mapping. EMC(EMC_PMACRO_BRICK_MAPPING_0) = params->emc_pmacro_brick_mapping0; EMC(EMC_PMACRO_BRICK_MAPPING_1) = params->emc_pmacro_brick_mapping1; EMC(EMC_PMACRO_BRICK_MAPPING_2) = params->emc_pmacro_brick_mapping2; + EMC(EMC_PMACRO_BRICK_CTRL_RFU1) = (params->emc_pmacro_brick_ctrl_rfu1 & 0x1120112) | 0x1EED1EED; + + // This is required to do any reads from the pad macros. EMC(EMC_CONFIG_SAMPLE_DELAY) = params->emc_config_sample_delay; + EMC(EMC_FBIO_CFG8) = params->emc_fbio_cfg8; + + // Set swizzle for Rank 0. EMC(EMC_SWIZZLE_RANK0_BYTE0) = params->emc_swizzle_rank0_byte0; EMC(EMC_SWIZZLE_RANK0_BYTE1) = params->emc_swizzle_rank0_byte1; EMC(EMC_SWIZZLE_RANK0_BYTE2) = params->emc_swizzle_rank0_byte2; EMC(EMC_SWIZZLE_RANK0_BYTE3) = params->emc_swizzle_rank0_byte3; + // Set swizzle for Rank 1. EMC(EMC_SWIZZLE_RANK1_BYTE0) = params->emc_swizzle_rank1_byte0; EMC(EMC_SWIZZLE_RANK1_BYTE1) = params->emc_swizzle_rank1_byte1; EMC(EMC_SWIZZLE_RANK1_BYTE2) = params->emc_swizzle_rank1_byte2; EMC(EMC_SWIZZLE_RANK1_BYTE3) = params->emc_swizzle_rank1_byte3; + + // Patch 4 using BCT spare variables. if (params->emc_bct_spare6) *(vu32 *)params->emc_bct_spare6 = params->emc_bct_spare7; + + // Set pad controls. EMC(EMC_XM2COMPPADCTRL) = params->emc_xm2_comp_pad_ctrl; EMC(EMC_XM2COMPPADCTRL2) = params->emc_xm2_comp_pad_ctrl2; EMC(EMC_XM2COMPPADCTRL3) = params->emc_xm2_comp_pad_ctrl3; + + // Program Autocal controls with shadowed register fields. EMC(EMC_AUTO_CAL_CONFIG2) = params->emc_auto_cal_config2; EMC(EMC_AUTO_CAL_CONFIG3) = params->emc_auto_cal_config3; EMC(EMC_AUTO_CAL_CONFIG4) = params->emc_auto_cal_config4; @@ -124,6 +169,7 @@ break_nosleep: EMC(EMC_AUTO_CAL_CONFIG6) = params->emc_auto_cal_config6; EMC(EMC_AUTO_CAL_CONFIG7) = params->emc_auto_cal_config7; EMC(EMC_AUTO_CAL_CONFIG8) = params->emc_auto_cal_config8; + EMC(EMC_PMACRO_RX_TERM) = params->emc_pmacro_rx_term; EMC(EMC_PMACRO_DQ_TX_DRV) = params->emc_pmacro_dq_tx_drive; EMC(EMC_PMACRO_CA_TX_DRV) = params->emc_pmacro_ca_tx_drive; @@ -131,9 +177,11 @@ break_nosleep: EMC(EMC_PMACRO_AUTOCAL_CFG_COMMON) = params->emc_pmacro_auto_cal_common; EMC(EMC_AUTO_CAL_CHANNEL) = params->emc_auto_cal_channel; EMC(EMC_PMACRO_ZCTRL) = params->emc_pmacro_zcrtl; + EMC(EMC_DLL_CFG_0) = params->emc_dll_cfg0; EMC(EMC_DLL_CFG_1) = params->emc_dll_cfg1; EMC(EMC_CFG_DIG_DLL_1) = params->emc_cfg_dig_dll_1; + EMC(EMC_DATA_BRLSHFT_0) = params->emc_data_brlshft0; EMC(EMC_DATA_BRLSHFT_1) = params->emc_data_brlshft1; EMC(EMC_DQS_BRLSHFT_0) = params->emc_dqs_brlshft0; @@ -146,8 +194,10 @@ break_nosleep: EMC(EMC_QUSE_BRLSHFT_1) = params->emc_quse_brlshft1; EMC(EMC_QUSE_BRLSHFT_2) = params->emc_quse_brlshft2; EMC(EMC_QUSE_BRLSHFT_3) = params->emc_quse_brlshft3; + EMC(EMC_PMACRO_BRICK_CTRL_RFU1) = (params->emc_pmacro_brick_ctrl_rfu1 & 0x1BF01BF) | 0x1E401E40; EMC(EMC_PMACRO_PAD_CFG_CTRL) = params->emc_pmacro_pad_cfg_ctrl; + EMC(EMC_PMACRO_CMD_BRICK_CTRL_FDPD) = params->emc_pmacro_cmd_brick_ctrl_fdpd; EMC(EMC_PMACRO_BRICK_CTRL_RFU2) = params->emc_pmacro_brick_ctrl_rfu2 & 0xFF7FFF7F; EMC(EMC_PMACRO_DATA_BRICK_CTRL_FDPD) = params->emc_pmacro_data_brick_ctrl_fdpd; @@ -158,6 +208,7 @@ break_nosleep: EMC(EMC_PMACRO_DATA_RX_TERM_MODE) = params->emc_pmacro_data_rx_term_mode; EMC(EMC_PMACRO_CMD_RX_TERM_MODE) = params->emc_pmacro_cmd_rx_term_mode; EMC(EMC_PMACRO_CMD_PAD_TX_CTRL) = params->emc_pmacro_cmd_pad_tx_ctrl; + EMC(EMC_CFG_3) = params->emc_cfg3; EMC(EMC_PMACRO_TX_PWRD_0) = params->emc_pmacro_tx_pwrd0; EMC(EMC_PMACRO_TX_PWRD_1) = params->emc_pmacro_tx_pwrd1; @@ -183,6 +234,7 @@ break_nosleep: EMC(EMC_PMACRO_IB_VREF_DQS_0) = params->emc_pmacro_ib_vref_dqs_0; EMC(EMC_PMACRO_IB_VREF_DQS_1) = params->emc_pmacro_ib_vref_dqs_1; EMC(EMC_PMACRO_IB_RXRT) = params->emc_pmacro_ib_rxrt; + EMC(EMC_PMACRO_QUSE_DDLL_RANK0_0) = params->emc_pmacro_quse_ddll_rank0_0; EMC(EMC_PMACRO_QUSE_DDLL_RANK0_1) = params->emc_pmacro_quse_ddll_rank0_1; EMC(EMC_PMACRO_QUSE_DDLL_RANK0_2) = params->emc_pmacro_quse_ddll_rank0_2; @@ -196,6 +248,7 @@ break_nosleep: EMC(EMC_PMACRO_QUSE_DDLL_RANK1_4) = params->emc_pmacro_quse_ddll_rank1_4; EMC(EMC_PMACRO_QUSE_DDLL_RANK1_5) = params->emc_pmacro_quse_ddll_rank1_5; EMC(EMC_PMACRO_BRICK_CTRL_RFU1) = params->emc_pmacro_brick_ctrl_rfu1; + EMC(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_0) = params->emc_pmacro_ob_ddll_long_dq_rank0_0; EMC(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_1) = params->emc_pmacro_ob_ddll_long_dq_rank0_1; EMC(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_2) = params->emc_pmacro_ob_ddll_long_dq_rank0_2; @@ -208,6 +261,7 @@ break_nosleep: EMC(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_3) = params->emc_pmacro_ob_ddll_long_dq_rank1_3; EMC(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_4) = params->emc_pmacro_ob_ddll_long_dq_rank1_4; EMC(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_5) = params->emc_pmacro_ob_ddll_long_dq_rank1_5; + EMC(EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_0) = params->emc_pmacro_ob_ddll_long_dqs_rank0_0; EMC(EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_1) = params->emc_pmacro_ob_ddll_long_dqs_rank0_1; EMC(EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_2) = params->emc_pmacro_ob_ddll_long_dqs_rank0_2; @@ -228,6 +282,7 @@ break_nosleep: EMC(EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_1) = params->emc_pmacro_ib_ddll_long_dqs_rank1_1; EMC(EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_2) = params->emc_pmacro_ib_ddll_long_dqs_rank1_2; EMC(EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_3) = params->emc_pmacro_ib_ddll_long_dqs_rank1_3; + EMC(EMC_PMACRO_DDLL_LONG_CMD_0) = params->emc_pmacro_ddll_long_cmd_0; EMC(EMC_PMACRO_DDLL_LONG_CMD_1) = params->emc_pmacro_ddll_long_cmd_1; EMC(EMC_PMACRO_DDLL_LONG_CMD_2) = params->emc_pmacro_ddll_long_cmd_2; @@ -236,10 +291,17 @@ break_nosleep: EMC(EMC_PMACRO_DDLL_SHORT_CMD_0) = params->emc_pmacro_ddll_short_cmd_0; EMC(EMC_PMACRO_DDLL_SHORT_CMD_1) = params->emc_pmacro_ddll_short_cmd_1; EMC(EMC_PMACRO_DDLL_SHORT_CMD_2) = params->emc_pmacro_ddll_short_cmd_2; + + // Common pad macro (cpm). EMC(EMC_PMACRO_COMMON_PAD_TX_CTRL) = (params->emc_pmacro_common_pad_tx_ctrl & 1) | 0xE; + + // Patch 3 using BCT spare variables. if (params->emc_bct_spare4) *(vu32 *)params->emc_bct_spare4 = params->emc_bct_spare5; - EMC(EMC_TIMING_CONTROL) = 1; + + EMC(EMC_TIMING_CONTROL) = 1; // Trigger timing update so above writes take place. + + // Initialize MC VPR settings. MC(MC_VIDEO_PROTECT_BOM) = params->mc_video_protect_bom; MC(MC_VIDEO_PROTECT_BOM_ADR_HI) = params->mc_video_protect_bom_adr_hi; MC(MC_VIDEO_PROTECT_SIZE_MB) = params->mc_video_protect_size_mb; @@ -247,20 +309,32 @@ break_nosleep: MC(MC_VIDEO_PROTECT_VPR_OVERRIDE1) = params->mc_video_protect_vpr_override1; MC(MC_VIDEO_PROTECT_GPU_OVERRIDE_0) = params->mc_video_protect_gpu_override0; MC(MC_VIDEO_PROTECT_GPU_OVERRIDE_1) = params->mc_video_protect_gpu_override1; + + // Program SDRAM geometry parameters. MC(MC_EMEM_ADR_CFG) = params->mc_emem_adr_cfg; MC(MC_EMEM_ADR_CFG_DEV0) = params->mc_emem_adr_cfg_dev0; MC(MC_EMEM_ADR_CFG_DEV1) = params->mc_emem_adr_cfg_dev1; MC(MC_EMEM_ADR_CFG_CHANNEL_MASK) = params->mc_emem_adr_cfg_channel_mask; + + // Program bank swizzling. MC(MC_EMEM_ADR_CFG_BANK_MASK_0) = params->mc_emem_adr_cfg_bank_mask0; MC(MC_EMEM_ADR_CFG_BANK_MASK_1) = params->mc_emem_adr_cfg_bank_mask1; MC(MC_EMEM_ADR_CFG_BANK_MASK_2) = params->mc_emem_adr_cfg_bank_mask2; + + // Program external memory aperture (base and size). MC(MC_EMEM_CFG) = params->mc_emem_cfg; + + // Program SEC carveout (base and size). MC(MC_SEC_CARVEOUT_BOM) = params->mc_sec_carveout_bom; MC(MC_SEC_CARVEOUT_ADR_HI) = params->mc_sec_carveout_adr_hi; MC(MC_SEC_CARVEOUT_SIZE_MB) = params->mc_sec_carveout_size_mb; + + // Program MTS carveout (base and size). MC(MC_MTS_CARVEOUT_BOM) = params->mc_mts_carveout_bom; MC(MC_MTS_CARVEOUT_ADR_HI) = params->mc_mts_carveout_adr_hi; MC(MC_MTS_CARVEOUT_SIZE_MB) = params->mc_mts_carveout_size_mb; + + // Program the memory arbiter. MC(MC_EMEM_ARB_CFG) = params->mc_emem_arb_cfg; MC(MC_EMEM_ARB_OUTSTANDING_REQ) = params->mc_emem_arb_outstanding_req; MC(MC_EMEM_ARB_REFPB_HP_CTRL) = params->emc_emem_arb_refpb_hp_ctrl; @@ -289,21 +363,38 @@ break_nosleep: MC(MC_EMEM_ARB_OVERRIDE_1) = params->mc_emem_arb_override1; MC(MC_EMEM_ARB_RSV) = params->mc_emem_arb_rsv; MC(MC_DA_CONFIG0) = params->mc_da_cfg0; - MC(MC_TIMING_CONTROL) = 1; + + MC(MC_TIMING_CONTROL) = 1; // Trigger MC timing update. + + // Program second-level clock enable overrides. MC(MC_CLKEN_OVERRIDE) = params->mc_clken_override; + + // Program statistics gathering. MC(MC_STAT_CONTROL) = params->mc_stat_control; + + // Program SDRAM geometry parameters. EMC(EMC_ADR_CFG) = params->emc_adr_cfg; + + // Program second-level clock enable overrides. EMC(EMC_CLKEN_OVERRIDE) = params->emc_clken_override; + + // Program EMC pad auto calibration. EMC(EMC_PMACRO_AUTOCAL_CFG_0) = params->emc_pmacro_auto_cal_cfg0; EMC(EMC_PMACRO_AUTOCAL_CFG_1) = params->emc_pmacro_auto_cal_cfg1; EMC(EMC_PMACRO_AUTOCAL_CFG_2) = params->emc_pmacro_auto_cal_cfg2; + EMC(EMC_AUTO_CAL_VREF_SEL_0) = params->emc_auto_cal_vref_sel0; EMC(EMC_AUTO_CAL_VREF_SEL_1) = params->emc_auto_cal_vref_sel1; + EMC(EMC_AUTO_CAL_INTERVAL) = params->emc_auto_cal_interval; EMC(EMC_AUTO_CAL_CONFIG) = params->emc_auto_cal_config; usleep(params->emc_auto_cal_wait); + + // Patch 5 using BCT spare variables. if (params->emc_bct_spare8) *(vu32 *)params->emc_bct_spare8 = params->emc_bct_spare9; + + // Program EMC timing configuration. EMC(EMC_CFG_2) = params->emc_cfg2; EMC(EMC_CFG_PIPE) = params->emc_cfg_pipe; EMC(EMC_CFG_PIPE_1) = params->emc_cfg_pipe1; @@ -348,9 +439,11 @@ break_nosleep: EMC(EMC_EINPUT_DURATION) = params->emc_einput_duration; EMC(EMC_PUTERM_EXTRA) = params->emc_puterm_extra; EMC(EMC_PUTERM_WIDTH) = params->emc_puterm_width; + EMC(EMC_PMACRO_COMMON_PAD_TX_CTRL) = params->emc_pmacro_common_pad_tx_ctrl; EMC(EMC_DBG) = params->emc_dbg; EMC(EMC_QRST) = params->emc_qrst; + EMC(EMC_ISSUE_QRST) = 1; EMC(EMC_ISSUE_QRST) = 0; EMC(EMC_QSAFE) = params->emc_qsafe; EMC(EMC_RDV) = params->emc_rdv; @@ -383,6 +476,8 @@ break_nosleep: EMC(EMC_ODT_WRITE) = params->emc_odt_write; EMC(EMC_CFG_DIG_DLL) = params->emc_cfg_dig_dll; EMC(EMC_CFG_DIG_DLL_PERIOD) = params->emc_cfg_dig_dll_period; + + // Don't write CFG_ADR_EN (bit 1) here - lock bit written later. EMC(EMC_FBIO_SPARE) = params->emc_fbio_spare & 0xFFFFFFFD; EMC(EMC_CFG_RSV) = params->emc_cfg_rsv; EMC(EMC_PMC_SCRATCH1) = params->emc_pmc_scratch1; @@ -390,70 +485,104 @@ break_nosleep: EMC(EMC_PMC_SCRATCH3) = params->emc_pmc_scratch3; EMC(EMC_ACPD_CONTROL) = params->emc_acpd_control; EMC(EMC_TXDSRVTTGEN) = params->emc_txdsrvttgen; + + // Set pipe bypass enable bits before sending any DRAM commands. EMC(EMC_CFG) = (params->emc_cfg & 0xE) | 0x3C00000; + + // Patch BootROM. if (params->boot_rom_patch_control & (1 << 31)) { *(vu32 *)(APB_MISC_BASE + params->boot_rom_patch_control * 4) = params->boot_rom_patch_data; - MC(MC_TIMING_CONTROL) = 1; + MC(MC_TIMING_CONTROL) = 1; // Trigger MC timing update. } - PMC(APBDEV_PMC_IO_DPD3_REQ) = ((4 * params->emc_pmc_scratch1 >> 2) + 0x40000000) & 0xCFFF0000; + + // Release SEL_DPD_CMD. + PMC(APBDEV_PMC_IO_DPD3_REQ) = ((params->emc_pmc_scratch1 & 0x3FFFFFFF) | 0x40000000) & 0xCFFF0000; usleep(params->pmc_io_dpd3_req_wait); + + // Set autocal interval if not configured. if (!params->emc_auto_cal_interval) EMC(EMC_AUTO_CAL_CONFIG) = params->emc_auto_cal_config | 0x200; + EMC(EMC_PMACRO_BRICK_CTRL_RFU2) = params->emc_pmacro_brick_ctrl_rfu2; + + // ZQ CAL setup (not actually issuing ZQ CAL now). if (params->emc_zcal_warm_cold_boot_enables & 1) { if (params->memory_type == 2) - EMC(EMC_ZCAL_WAIT_CNT) = 8 * params->emc_zcal_wait_cnt; + EMC(EMC_ZCAL_WAIT_CNT) = params->emc_zcal_wait_cnt << 3; if (params->memory_type == 3) { EMC(EMC_ZCAL_WAIT_CNT) = params->emc_zcal_wait_cnt; EMC(EMC_ZCAL_MRW_CMD) = params->emc_zcal_mrw_cmd; } } - EMC(EMC_TIMING_CONTROL) = 1; + + EMC(EMC_TIMING_CONTROL) = 1; // Trigger timing update so above writes take place. usleep(params->emc_timing_control_wait); + + // Deassert HOLD_CKE_LOW. PMC(APBDEV_PMC_DDR_CNTRL) &= 0xFFF8007F; usleep(params->pmc_ddr_ctrl_wait); - if (params->memory_type == 2) + + // Set clock enable signal. + u32 pin_gpio_cfg = (params->emc_pin_gpio_enable << 16) | (params->emc_pin_gpio << 12); + if (params->memory_type == 2 || params->memory_type == 3) { - EMC(EMC_PIN) = (params->emc_pin_gpio_enable << 16) | (params->emc_pin_gpio << 12); + EMC(EMC_PIN) = pin_gpio_cfg; + (void)EMC(EMC_PIN); usleep(params->emc_pin_extra_wait + 200); - EMC(EMC_PIN) = ((params->emc_pin_gpio_enable << 16) | (params->emc_pin_gpio << 12)) + 256; - usleep(params->emc_pin_extra_wait + 500); + EMC(EMC_PIN) = pin_gpio_cfg | 0x100; + (void)EMC(EMC_PIN); } + if (params->memory_type == 3) - { - EMC(EMC_PIN) = (params->emc_pin_gpio_enable << 16) | (params->emc_pin_gpio << 12); - usleep(params->emc_pin_extra_wait + 200); - EMC(EMC_PIN) = ((params->emc_pin_gpio_enable << 16) | (params->emc_pin_gpio << 12)) + 256; usleep(params->emc_pin_extra_wait + 2000); - } - EMC(EMC_PIN) = ((params->emc_pin_gpio_enable << 16) | (params->emc_pin_gpio << 12)) + 0x101; + else if (params->memory_type == 2) + usleep(params->emc_pin_extra_wait + 500); + + // Enable clock enable signal. + EMC(EMC_PIN) = pin_gpio_cfg | 0x101; + (void)EMC(EMC_PIN); usleep(params->emc_pin_program_wait); + + // Send NOP (trigger just needs to be non-zero). if (params->memory_type != 3) EMC(EMC_NOP) = (params->emc_dev_select << 30) + 1; + + // On coldboot w/LPDDR2/3, wait 200 uSec after asserting CKE high. if (params->memory_type == 1) usleep(params->emc_pin_extra_wait + 200); + + // Init zq calibration, if (params->memory_type == 3) { + // Patch 6 using BCT spare variables. if (params->emc_bct_spare10) *(vu32 *)params->emc_bct_spare10 = params->emc_bct_spare11; + + // Write mode registers. EMC(EMC_MRW2) = params->emc_mrw2; EMC(EMC_MRW) = params->emc_mrw1; EMC(EMC_MRW3) = params->emc_mrw3; EMC(EMC_MRW4) = params->emc_mrw4; EMC(EMC_MRW6) = params->emc_mrw6; EMC(EMC_MRW14) = params->emc_mrw14; + EMC(EMC_MRW8) = params->emc_mrw8; EMC(EMC_MRW12) = params->emc_mrw12; EMC(EMC_MRW9) = params->emc_mrw9; EMC(EMC_MRW13) = params->emc_mrw13; + if (params->emc_zcal_warm_cold_boot_enables & 1) { + // Issue ZQCAL start, device 0. EMC(EMC_ZQ_CAL) = params->emc_zcal_init_dev0; usleep(params->emc_zcal_init_wait); + + // Issue ZQCAL latch. EMC(EMC_ZQ_CAL) = params->emc_zcal_init_dev0 ^ 3; + // Same for device 1. if (!(params->emc_dev_select & 2)) { EMC(EMC_ZQ_CAL) = params->emc_zcal_init_dev1; @@ -462,42 +591,64 @@ break_nosleep: } } } + + // Set package and DPD pad control. PMC(APBDEV_PMC_DDR_CFG) = params->pmc_ddr_cfg; + + // Start periodic ZQ calibration (LPDDRx only). if (params->memory_type - 1 <= 2) { EMC(EMC_ZCAL_INTERVAL) = params->emc_zcal_interval; EMC(EMC_ZCAL_WAIT_CNT) = params->emc_zcal_wait_cnt; EMC(EMC_ZCAL_MRW_CMD) = params->emc_zcal_mrw_cmd; } + + // Patch 7 using BCT spare variables. if (params->emc_bct_spare12) *(vu32 *)params->emc_bct_spare12 = params->emc_bct_spare13; - EMC(EMC_TIMING_CONTROL) = 1; + + EMC(EMC_TIMING_CONTROL) = 1; // Trigger timing update so above writes take place. + if (params->emc_extra_refresh_num) - EMC(EMC_REF) = ((1 << params->emc_extra_refresh_num << 8) - 0xFD) | (params->emc_pin_gpio << 30); + EMC(EMC_REF) = (((1 << params->emc_extra_refresh_num) - 1) << 8) | (params->emc_dev_select << 30) | 3; + + // Enable refresh. EMC(EMC_REFCTRL) = params->emc_dev_select | 0x80000000; + EMC(EMC_DYN_SELF_REF_CONTROL) = params->emc_dyn_self_ref_control; EMC(EMC_CFG_UPDATE) = params->emc_cfg_update; EMC(EMC_CFG) = params->emc_cfg; EMC(EMC_FDPD_CTRL_DQ) = params->emc_fdpd_ctrl_dq; EMC(EMC_FDPD_CTRL_CMD) = params->emc_fdpd_ctrl_cmd; EMC(EMC_SEL_DPD_CTRL) = params->emc_sel_dpd_ctrl; + + // Write addr swizzle lock bit. EMC(EMC_FBIO_SPARE) = params->emc_fbio_spare | 2; - EMC(EMC_TIMING_CONTROL) = 1; + + EMC(EMC_TIMING_CONTROL) = 1; // Re-trigger timing to latch power saving functions. + + // Enable EMC pipe clock gating. EMC(EMC_CFG_PIPE_CLK) = params->emc_cfg_pipe_clk; + + // Depending on freqency, enable CMD/CLK fdpd. EMC(EMC_FDPD_CTRL_CMD_NO_RAMP) = params->emc_fdpd_ctrl_cmd_no_ramp; - SYSREG(AHB_ARBITRATION_XBAR_CTRL) = (SYSREG(AHB_ARBITRATION_XBAR_CTRL) & 0xFFFEFFFF) | ((params->ahb_arbitration_xbar_ctrl_meminit_done & 0xFFFF) << 16); + + // Enable arbiter. + SYSREG(AHB_ARBITRATION_XBAR_CTRL) = (SYSREG(AHB_ARBITRATION_XBAR_CTRL) & 0xFFFEFFFF) | (params->ahb_arbitration_xbar_ctrl_meminit_done << 16); + + // Lock carveouts per BCT cfg. MC(MC_VIDEO_PROTECT_REG_CTRL) = params->mc_video_protect_write_access; MC(MC_SEC_CARVEOUT_REG_CTRL) = params->mc_sec_carveout_protect_write_access; MC(MC_MTS_CARVEOUT_REG_CTRL) = params->mc_mts_carveout_reg_ctrl; - MC(MC_EMEM_CFG_ACCESS_CTRL) = 1; //Disable write access to a bunch of EMC registers. + + //Disable write access to a bunch of EMC registers. + MC(MC_EMEM_CFG_ACCESS_CTRL) = 1; } sdram_params_t *sdram_get_params() { - //TODO: sdram_id should be in [0, 7]. - #ifdef CONFIG_SDRAM_COMPRESS_CFG - u8 *buf = (u8 *)0x40030000; + u8 *buf = (u8 *)SDRAM_PARAMS_ADDR; LZ_Uncompress(_dram_cfg_lz, buf, sizeof(_dram_cfg_lz)); return (sdram_params_t *)&buf[sizeof(sdram_params_t) * _get_sdram_id()]; #else @@ -529,7 +680,17 @@ sdram_params_t *sdram_get_params_patched() // Disable Warmboot signature check. sdram_params->boot_rom_patch_control = (1 << 31) | (((IPATCH_BASE + 4) - APB_MISC_BASE) / 4); sdram_params->boot_rom_patch_data = IPATCH_CONFIG(0x10459E, 0x2000); +/* + // Disable SBK lock. + sdram_params->emc_bct_spare8 = (IPATCH_BASE + 7 * 4); + sdram_params->emc_bct_spare9 = IPATCH_CONFIG(0x10210E, 0x2000); + // Disable bootrom read lock. + sdram_params->emc_bct_spare10 = (IPATCH_BASE + 10 * 4); + sdram_params->emc_bct_spare11 = IPATCH_CONFIG(0x100FDC, 0xF000); + sdram_params->emc_bct_spare12 = (IPATCH_BASE + 11 * 4); + sdram_params->emc_bct_spare13 = IPATCH_CONFIG(0x100FDE, 0xE320); +*/ return sdram_params; } @@ -538,16 +699,24 @@ void sdram_init() //TODO: sdram_id should be in [0,4]. const sdram_params_t *params = (const sdram_params_t *)sdram_get_params(); + // Set DRAM voltage. i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_SD_CFG2, 0x05); max77620_regulator_set_voltage(REGULATOR_SD1, 1100000); + // VDDP Select. PMC(APBDEV_PMC_VDDP_SEL) = params->pmc_vddp_sel; usleep(params->pmc_vddp_sel_wait); + + // Set DDR pad voltage. PMC(APBDEV_PMC_DDR_PWR) = PMC(APBDEV_PMC_DDR_PWR); + + // Turn on MEM IO Power. PMC(APBDEV_PMC_NO_IOPOWER) = params->pmc_no_io_power; PMC(APBDEV_PMC_REG_SHORT) = params->pmc_reg_short; + PMC(APBDEV_PMC_DDR_CNTRL) = params->pmc_ddr_ctrl; + // Patch 1 using BCT spare variables if (params->emc_bct_spare0) *(vu32 *)params->emc_bct_spare0 = params->emc_bct_spare1; diff --git a/source/mem/sdram_lp0_param_t210.h b/source/mem/sdram_lp0_param_t210.h index 7f44f1d..9028990 100644 --- a/source/mem/sdram_lp0_param_t210.h +++ b/source/mem/sdram_lp0_param_t210.h @@ -1,7 +1,7 @@ /* * Copyright (c) 2013-2015, NVIDIA CORPORATION. All rights reserved. * Copyright 2014 Google Inc. - * Copyright (C) 2018 CTCaer + * 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, diff --git a/source/meme/graphics.c b/source/meme/graphics.c deleted file mode 100644 index 423c3b8..0000000 --- a/source/meme/graphics.c +++ /dev/null @@ -1,144 +0,0 @@ -#include -#include -#include -#include "../gfx/di.h" -#include "../gfx/gfx.h" -#include "../utils/btn.h" -#include "../utils/util.h" -#include "graphics.h" -#include "utils.h" - -int _copystring(char *out, const char *in, int copynumb){ - strncpy(out, in, copynumb - 1); - int strlength = strlen(in); - if (strlength > copynumb + 1) strlength = copynumb; - memset(out + strlength, '\0', 1); - int ret = copynumb - strlength; - return ret + 4; -} - -int messagebox(char *message){ - int ret = -1; - meme_clearscreen(); - gfx_printf("%s", message); - msleep(100); - u8 res = btn_wait(); - if (res & BTN_POWER) ret = 0; - else ret = 1; - meme_clearscreen(); - return ret; -} - -int gfx_menulist(int ypos, char *list[], int length){ - int i = 0; - int highlight = 1; - while(1){ - gfx_con_setpos(0, ypos); - while(i < length){ - if (i == highlight - 1) gfx_printf("%k%p%s%k%p\n", COLOR_DEFAULT, COLOR_WHITE, list[i], COLOR_WHITE, COLOR_DEFAULT); - else gfx_printf("%s\n", list[i]); - i++; - } - i = 0; - u8 res = btn_wait(); - if (res & BTN_VOL_UP) highlight--; - else if (res & BTN_VOL_DOWN) highlight++; - else if (res & BTN_POWER) break; - if (highlight < 1) highlight = 1; - if (highlight > length) highlight = length; - } - return highlight; -} - -void meme_clearscreen(){ - gfx_clear_grey(0x1B); - gfx_con_setpos(0, 0); - gfx_box(0, 0, 719, 15, COLOR_WHITE); - gfx_printf("%k%pTegraExplorer\n%k%p", COLOR_DEFAULT, COLOR_WHITE, COLOR_WHITE, COLOR_DEFAULT); -} - -void _printwithhighlight(int offset, int folderamount, char *items[], int highlight, unsigned int *muhbits, int *filesizes){ - char temp[39]; - int i = 0; - int ret = 0; - gfx_con_setpos(0, 32); - while(i < folderamount && i < 76){ - ret = _copystring(temp, items[i + offset], 39); - if(i == highlight - 1) gfx_printf("\n%k%p%s%k%p", COLOR_DEFAULT, COLOR_WHITE, temp, COLOR_WHITE, COLOR_DEFAULT); - else if ((i == 0 || i == 1) && offset == 0) gfx_printf("%k\n%s%k", COLOR_ORANGE, temp, COLOR_WHITE); - else if (muhbits[i+offset] & OPTION1) gfx_printf("\n%s", temp); - else gfx_printf("%k\n%s%k", COLOR_VIOLET, temp, COLOR_WHITE); - - while(ret >= 0){ - gfx_printf(" "); - ret = ret - 1; - } - - gfx_con.x = 720 - (16 * 6); - if (!(muhbits[i + offset] & OPTION1)) { //should change later - char temp[6]; - return_readable_byte_amounts(filesizes[i + offset], temp); - gfx_printf("%s", temp); - } - i++; - } -} - -int fileexplorergui(char *items[], unsigned int *muhbits, const char path[], int folderamount){ - bool change = true; - int select = 1; - int sleepvalue = 300; - int offset = 0; - char temp[43]; - int *filesizes; - int i = 0; - filesizes = (int*) calloc(500, sizeof(int)); - gfx_con_setpos(0, 48); - for (i = 0; i < folderamount; i++){ - if(!(muhbits[i] & OPTION1)){ - char temppath[PATHSIZE]; - strcpy(temppath, path); - strcat(temppath, "/"); - strcat(temppath, items[i]); - filesizes[i] = getfilesize(temppath); - gfx_printf("Calcing filesizes: %d / %d\r", i, folderamount - 2); - } - } - _copystring(temp, path, 43); - gfx_con_setpos(0, 16); - gfx_printf("%k%s\n%k", COLOR_GREEN, temp, COLOR_WHITE); - while(1){ - if (change){ - _printwithhighlight(offset, folderamount, items, select, muhbits, filesizes); - change = false; - msleep(sleepvalue); - } - - u8 res = btn_read(); - if (res & BTN_VOL_UP){ - select = select - 1, change = true; - sleepvalue = sleepvalue - 75; - } - else if (res & BTN_VOL_DOWN){ - select++, change = true; - sleepvalue = sleepvalue - 75; - } - else { - sleepvalue = 300; - } - if (res & BTN_POWER) break; - if (select < 1){ - select = 1; - if (offset > 0) offset = offset - 1; - } - if (select > folderamount) select = folderamount; - if (select > 76){ - select = 76; - if (76 + offset < folderamount) offset++; - } - if (sleepvalue < 30) sleepvalue = 30; - } - int ret = select + offset; - free(filesizes); - return ret; -} \ No newline at end of file diff --git a/source/meme/graphics.h b/source/meme/graphics.h deleted file mode 100644 index 6e86aa2..0000000 --- a/source/meme/graphics.h +++ /dev/null @@ -1,6 +0,0 @@ -#pragma once - -int fileexplorergui(char *items[], unsigned int *muhbits, const char path[], int folderamount); -void meme_clearscreen(); -int gfx_menulist(int ypos, char *list[], int length); -int messagebox(char *message); \ No newline at end of file diff --git a/source/meme/main.c b/source/meme/main.c deleted file mode 100644 index a395fa5..0000000 --- a/source/meme/main.c +++ /dev/null @@ -1,131 +0,0 @@ -#include -#include -#include "../gfx/di.h" -#include "../gfx/gfx.h" -#include "../utils/btn.h" -#include "utils.h" -#include "main.h" -#include "mainfunctions.h" -#include "../libs/fatfs/ff.h" -#include "../utils/util.h" -#include "graphics.h" -#include "external_utils.h" - -extern bool sd_mount(); -extern void sd_unmount(); - -static u32 bis_keys[4][8]; - -void meme_main(){ - utils_gfx_init(); - //dump_keys(); - - /* - sdmmc_storage_t storage; - sdmmc_t sdmmc; - - sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4); - sdmmc_storage_set_mmc_partition(&storage, 1); */ - - int firmver = -1; - firmver = dump_biskeys(bis_keys); // add succeed check - - char *options[6]; - char *itemsinfolder[1000]; - unsigned int muhbits[1000]; - bool sd_mounted = false; - sd_mounted = sd_mount(); - if (!sd_mounted) messagebox("\nSD INIT FAILED"); - - while (1){ - int i = 0, ret = 0; - if (sd_mounted){ - addchartoarray("[SD:/] SD card", options, i); - i++; - } - addchartoarray("[emmc:/] SYSTEM", options, i); - if (!sd_mounted) addchartoarray("\nMount SD", options, i+1); - else addchartoarray("\nUnmount SD", options, i+1); - addchartoarray("\nTools", options, i+2); - addchartoarray("About", options, i+3); - addchartoarray("Exit", options, i+4); - meme_clearscreen(); - ret = gfx_menulist(32, options, (i + 5)); - - if (strcmp(options[ret - 1], "[SD:/] SD card") == 0){ - sdexplorer(itemsinfolder, muhbits, "sd:/"); - } - else if (strcmp(options[ret - 1], "About") == 0){ - messagebox(ABOUT_MESSAGE); - } - else if (strcmp(options[ret - 1], "\nMount SD") == 0 || strcmp(options[ret - 1], "\nUnmount SD") == 0){ - if (sd_mounted){ - sd_unmount(); - sd_mounted = false; - } - else { - sd_mounted = sd_mount(); - if (!sd_mounted) messagebox("\nSD INIT FAILED"); - } - } - else if (strcmp(options[ret - 1], "[emmc:/] SYSTEM") == 0){ - ret = messagebox(SYSTEM_WARNING_MESSAGE); // note: maybe add some sort of color system for messageboxes - if (ret == 0) sdexplorer(itemsinfolder, muhbits, "emmc:/"); - } - else if (strcmp(options[ret - 1], "\nTools") == 0){ - meme_clearscreen(); - addchartoarray("Back", options, 0); - addchartoarray("\nPrint BISKEYS", options, 1); - addchartoarray("Dump firmware", options, 2); - ret = gfx_menulist(32, options, 3); - switch(ret){ - case 2: - meme_clearscreen(); - gfx_printf("\nBisKey 0:\n"); - gfx_hexdump(0, bis_keys[0], 0x20 * sizeof(u8)); - gfx_printf("\n\nBisKey 1:\n"); - gfx_hexdump(0, bis_keys[1], 0x20 * sizeof(u8)); - gfx_printf("\n\nBisKey 2 + 3:\n"); - gfx_hexdump(0, bis_keys[2], 0x20 * sizeof(u8)); - btn_wait(); - break; - case 3: - ret = messagebox("\nThis will dump your firmware to your sd!\nThis might take a while\n\nVol-/+ to cancel\nPower to continue..."); - if (ret == 0 && sd_mounted) sdexplorer(itemsinfolder, muhbits, "DumpFirmware"); - break; - } - } - else { - meme_clearscreen(); - addchartoarray("Back", options, 0); - addchartoarray("\nReboot to RCM", options, 1); - addchartoarray("Reboot normally", options, 2); - addchartoarray("Power off", options, 3); - ret = gfx_menulist(32, options, 4); - if (ret != 1) sd_unmount(); - switch(ret){ - case 2: - reboot_rcm(); - case 3: - reboot_normal(); - case 4: - power_off(); - default: - break; - } - } - } - - //if (sd_mounted){ - - - //write file and folder menu - //make clipboard and shit like that - //figure out time from keys.c - //figure out how to reboot to payloads https://github.com/CTCaer/hekate/blob/101c8bc1d0813da10016be771a9919c9e8112277/bootloader/main.c#L266 - //gfx_printf("%k\n\nExited main loop, vol+ to reboot to rcm\nvol- to reboot normally\npower to power off\n", COLOR_GREEN); - //} - //else gfx_printf("%k%pSD INIT FAILED\n\nvol+ to reboot to rcm\nvol- to reboot normally\npower to power off", COLOR_RED, COLOR_DEFAULT); - - //utils_waitforpower(); -} \ No newline at end of file diff --git a/source/meme/main.h b/source/meme/main.h deleted file mode 100644 index 2da9438..0000000 --- a/source/meme/main.h +++ /dev/null @@ -1,6 +0,0 @@ -#pragma once - -#define ABOUT_MESSAGE "\nCreator: Such Meme, Many Skill#2921\nCool people: Denn, shchmue\nTesters: PhazonicRidley, huhen\n\n\nProject based on Lockpick_RCM\n With additional code from Hekate" -#define SYSTEM_WARNING_MESSAGE "\nNOTICE!\n\nAbout to enter SYSTEM:/\nThis is a SYSTEM partition!\nMessing something up here \n will brick your switch!\n\nVol+/- to cancel\nPower to continue..." - -void meme_main(); \ No newline at end of file diff --git a/source/meme/mainfunctions.c b/source/meme/mainfunctions.c deleted file mode 100644 index ed114d1..0000000 --- a/source/meme/mainfunctions.c +++ /dev/null @@ -1,179 +0,0 @@ -#include -#include -#include "../gfx/di.h" -#include "../gfx/gfx.h" -#include "../utils/btn.h" -#include "utils.h" -#include "mainfunctions.h" -#include "../libs/fatfs/ff.h" -#include "../storage/sdmmc.h" -#include "graphics.h" -#include "external_utils.h" - -int _openfilemenu(char *path, char *clipboardpath){ - meme_clearscreen(); - FILINFO fno; - f_stat(path, &fno); - char *options[6]; - int res = 0; - int mres = -1; - int ret = -1; - int i = 4; - - addchartoarray("Back\n", options, 0); - addchartoarray("Copy to clipboard", options, 1); - addchartoarray("Move to clipboard", options, 2); - addchartoarray("Delete file\n", options, 3); - if (strstr(path, ".bin") != NULL){ - addchartoarray("Launch payload", options, i); - i++; - } - if (strcmp(strstr(path, "emmc:/"), path) == 0){ - addchartoarray("Dump to SD", options, i); - i++; - } - - gfx_printf("%kPath: %s%k\n\n", COLOR_GREEN, path, COLOR_WHITE); - - char size[6]; - return_readable_byte_amounts(fno.fsize, size); - - gfx_printf("Size: %s", size); - - res = gfx_menulist(160, options, i); - switch(res){ - case 1: - break; - case 2: - ret = 0; - strcpy(clipboardpath, path); - break; - case 3: - ret = 1; - strcpy(clipboardpath, path); - break; - case 4: - mres = messagebox("Are you sure you want to delete this file?\nPower to confirm\nVOL to cancel"); - if (mres == 0) f_unlink(path); - break; - default: - if (strcmp(options[res - 1], "Launch payload") == 0) launch_payload(path, 0); - else if (strcmp(options[res - 1], "Dump to SD") == 0) { - int res = 0; - res = dumptosd(path); - if (res == 1) messagebox("Copy Failed\nInput or Output is invalid"); - } - } - - meme_clearscreen(); - return ret; -} - -int dumpfirmware(char *items[], unsigned int *muhbits){ - DIR dir; - FILINFO fno; - char path[28] = "emmc:/Contents/registered"; - char sdpath[28] = "sd:/tegraexplorer/firmware"; - char tempnand[100] = ""; - char tempsd[100] = ""; - int ret = 0, i = 0, foldersize = 0; - - meme_clearscreen(); - gfx_printf("\nStarting copy of firmware\n\n"); - - f_mkdir("sd:/tegraexplorer"); - f_mkdir("sd:/tegraexplorer/firmware"); - - if (f_opendir(&dir, path)) { - messagebox("Failed to open directory!"); - return -1; - } - - while (!f_readdir(&dir, &fno) && fno.fname[0]){ - addchartoarray(fno.fname, items, foldersize); - mallocandaddfolderbit(muhbits, foldersize, fno.fattrib & AM_DIR); - foldersize++; - } - - f_closedir(&dir); - - for (i = 0; i < foldersize; i++){ - if (muhbits[i] & AM_DIR){ - sprintf(tempnand, "%s/%s/00", path, items[i]); - sprintf(tempsd, "%s/%s", sdpath, items[i]); - ret = copy(tempnand, tempsd, 0); - if (ret != 0) { - messagebox("Copy failed! (infolder)"); - return 1; - } - f_closedir(&dir); - } - else { - sprintf(tempnand, "%s/%s", path, items[i]); - sprintf(tempsd, "%s/%s", sdpath, items[i]); - ret = copy(tempnand, tempsd, 0); - if (ret != 0) { - messagebox("Copy failed! (infile)"); - return 1; - } - } - gfx_printf("Copied %d / %d nca files\r", i + 1, foldersize); - } - messagebox("\nDump completed!\n\nThe firmware dump is located \n in sd:/tegraexplorer/firmware"); - return 0; -} - -void sdexplorer(char *items[], unsigned int *muhbits, char *rootpath){ - if (strcmp(rootpath, "DumpFirmware") == 0){ - dumpfirmware(items, muhbits); - return; - } - int value = 1; - int copymode = -1; - int folderamount = 0; - char path[PATHSIZE] = ""; - char clipboard[PATHSIZE + 1] = ""; - strcpy(path, rootpath); - char app[20], rpp[20]; - int temp = -1; - strcpy(app, rootpath); - strcpy(rpp, app); - removepartpath(rpp, "rpp"); - //static const u32 colors[8] = {COLOR_RED, COLOR_ORANGE, COLOR_YELLOW, COLOR_GREEN, COLOR_BLUE, COLOR_VIOLET, COLOR_DEFAULT, COLOR_WHITE}; - - while(1){ - gfx_clear_grey(0x1B); - gfx_con_setpos(0, 0); - gfx_box(0, 0, 719, 15, COLOR_WHITE); - folderamount = readfolder(items, muhbits, path); - if (folderamount == -1){ - messagebox("\nInvalid path\n\nReturning to main menu"); - break; - } - gfx_printf("%k%pTegraExplorer - %s", COLOR_DEFAULT, COLOR_WHITE, app); - gfx_con_setpos(39 * 16, 0); - gfx_printf("%d\n%k%p", folderamount - 2, COLOR_WHITE, COLOR_DEFAULT); - value = fileexplorergui(items, muhbits, path, folderamount); - - if (value == 1) { - if (strcmp(app, path) == 0) break; - else removepartpath(path, rpp); - } - else if (value == 2) { - if (copymode != -1){ - copywithpath(clipboard, path, copymode, app); - copymode = -1; - } - else messagebox("\nThe Clipboard is empty!"); - } - else { - if(muhbits[value - 1] & OPTION1) addpartpath(path, items[value - 1], app); - else { - addpartpath(path, items[value - 1], app); - temp = _openfilemenu(path, clipboard); - if (temp != -1) copymode = temp; - removepartpath(path, rpp); - } - } - } -} \ No newline at end of file diff --git a/source/meme/mainfunctions.h b/source/meme/mainfunctions.h deleted file mode 100644 index 453a366..0000000 --- a/source/meme/mainfunctions.h +++ /dev/null @@ -1,5 +0,0 @@ -#pragma once - -void sdexplorer(char *items[], unsigned int *muhbits, char *rootpath); -int dumpfirmware(char *items[], unsigned int *muhbits); -void wtf(char *items[], unsigned int *muhbits); \ No newline at end of file diff --git a/source/meme/utils.c b/source/meme/utils.c deleted file mode 100644 index 0bbab7f..0000000 --- a/source/meme/utils.c +++ /dev/null @@ -1,201 +0,0 @@ -#include -#include -#include -#include "../gfx/di.h" -#include "../gfx/gfx.h" -#include "../utils/btn.h" -#include "../utils/util.h" -#include "utils.h" -#include "../libs/fatfs/ff.h" -#include "../storage/sdmmc.h" -#include "graphics.h" -#include "external_utils.h" - -void utils_gfx_init(){ - display_backlight_brightness(100, 1000); - gfx_clear_grey(0x1B); - gfx_con_setpos(0, 0); -} - -void removepartpath(char *path, char *root){ - char *ret; - char temproot[20]; - ret = strrchr(path, '/'); - memset(ret, '\0', 1); - sprintf(temproot, "%s%s", root, "/"); - if (strcmp(path, root) == 0) strcpy(path, temproot); -} - -int dumptosd(const char *path){ - f_mkdir("sd:/tegraexplorer"); - f_mkdir("sd:/tegraexplorer/nanddump"); - FILINFO fno; - int res = 0; - f_stat(path, &fno); - char pathname[PATHSIZE]; - char foldername[75]; - strcpy(pathname, path); - removepartpath(pathname, "emmc:"); - strcpy(foldername, strrchr(pathname, '/')); - if (strcmp(foldername, "/") == 0) strcpy(foldername, "/root"); - sprintf(pathname, "%s%s", "sd:/tegraexplorer/nanddump", foldername); - f_mkdir(pathname); - sprintf(pathname, "%s%s%s%s", "sd:/tegraexplorer/nanddump", foldername, "/", fno.fname); - res = copy(path, pathname, 1); - return res; -} - -void addpartpath(char *path, char *add, char *root){ - if (strcmp(path, root) != 0) strcat(path, "/"); - strcat(path, add); -} - -void return_readable_byte_amounts(unsigned long int size, char *in){ - char type[3]; - unsigned long int sizetemp = size; - int muhbytes = 0; - while(sizetemp > 1024){ - muhbytes++; - sizetemp = sizetemp / 1024; - } - - switch(muhbytes){ - case 0: - strcpy(type, "B"); - break; - case 1: - strcpy(type, "KB"); - break; - case 2: - strcpy(type, "MB"); - break; - case 3: - strcpy(type, "GB"); - break; - default: - strcpy(type, "GB"); - break; - } - sprintf(in, "%d%s", sizetemp, type); -} - -int getfilesize(const char *path){ - FILINFO fno; - f_stat(path, &fno); - return fno.fsize; -} - -void addchartoarray(char *add, char *items[], int spot){ - size_t size = strlen(add) + 1; - items[spot] = (char*) malloc (size); - strlcpy(items[spot], add, size); -} - -void mallocandaddfolderbit(unsigned int *muhbits, int spot, bool value){ - muhbits[spot] = (unsigned int) malloc (sizeof(int)); - if (value) muhbits[spot] |= (OPTION1); - //ff.h line 368 -} - -int readfolder(char *items[], unsigned int *muhbits, const char *path){ - DIR dir; - FILINFO fno; - int i = 2; - addchartoarray("Current folder -> One folder up", items, 0); - addchartoarray("Clipboard -> Current folder", items, 1); - mallocandaddfolderbit(muhbits, 0, true); - mallocandaddfolderbit(muhbits, 1, true); - - - if (f_opendir(&dir, path)) { - gfx_printf("\nFailed to open %s", path); - return -1; - } - else { - while (!f_readdir(&dir, &fno) && fno.fname[0]){ - addchartoarray(fno.fname, items, i); - mallocandaddfolderbit(muhbits, i, fno.fattrib & AM_DIR); - i++; - } - } - f_closedir(&dir); - return i; -} - -int copy(const char *src, const char *dst, int print){ - FIL in; - FIL out; - unsigned int res = 0; - char temp[100]; - if (strcmp(src, dst) == 0){ - //in and out are the same, aborting! - return 2; - } - res = f_open(&in, src, FA_READ | FA_OPEN_EXISTING); - if (res != FR_OK){ - //something has gone wrong - //sprintf(temp, "%s %d", src, res); - //messagebox(temp); - - return 1; - } - if (f_open(&out, dst, FA_CREATE_ALWAYS | FA_WRITE) != FR_OK){ - //something has gone wrong - return 1; - } - - int BUFFSIZ = 32768; - u64 size = f_size(&in); - unsigned long totalsize = size, kbwritten = 0; - void *buff = malloc(BUFFSIZ); - int mbwritten = 0, percentage = 0; - bool abort = false; - if (print == 1) { - meme_clearscreen(); - gfx_printf("press VOL- to abort the file transfer!\n\n"); - } - while(size > BUFFSIZ){ - int res1, res2; - res1 = f_read(&in, buff, BUFFSIZ, NULL); - res2 = f_write(&out, buff, BUFFSIZ, NULL); - - kbwritten = kbwritten + (BUFFSIZ / 1024); - mbwritten = kbwritten / 1024; - percentage = (mbwritten * 100) / ((totalsize / 1024) / 1024); - - size = size - BUFFSIZ; - if (print == 1){ - gfx_printf("Written %dMB [%k%d%k%%]\r", mbwritten, COLOR_GREEN, percentage, COLOR_WHITE); - if (btn_read() & BTN_VOL_DOWN) size = 0, abort = true; - } - } - - if(size != 0){ - f_read(&in, buff, size, NULL); - f_write(&out, buff, size, NULL); - } - - f_close(&in); - f_close(&out); - - if(abort){ - f_unlink(dst); - } - - free(buff); - - return 0; -} - -int copywithpath(const char *src, const char *dstpath, int mode, char *app){ - FILINFO fno; - f_stat(src, &fno); - char dst[PATHSIZE]; - strcpy(dst, dstpath); - if (strcmp(dstpath, app) != 0) strcat(dst, "/"); - strcat(dst, fno.fname); - int ret = -1; - if (mode == 0) ret = copy(src, dst, 1); - if (mode == 1) f_rename(src, dst); - return ret; -} \ No newline at end of file diff --git a/source/meme/utils.h b/source/meme/utils.h deleted file mode 100644 index d311ae3..0000000 --- a/source/meme/utils.h +++ /dev/null @@ -1,20 +0,0 @@ -#pragma once - -#define OPTION1 (1 << 0) -#define OPTION2 (1 << 1) -#define OPTION3 (1 << 2) -#define OPTION4 (1 << 3) - -#define PATHSIZE 512 - -void utils_gfx_init(); -void removepartpath(char *path, char *root); -void addpartpath(char *path, char *add, char *root); -int readfolder(char *items[], unsigned int *muhbits, const char *path); -int copy(const char *src, const char *dst, int print); -void addchartoarray(char *add, char *items[], int spot); -int copywithpath(const char *src, const char *dstpath, int mode, char *app); -void return_readable_byte_amounts(unsigned long int size, char *in); -int getfilesize(const char *path); -int dumptosd(const char *path); -void mallocandaddfolderbit(unsigned int *muhbits, int spot, bool value); \ No newline at end of file diff --git a/source/power/max17050.c b/source/power/max17050.c index 2a2c8f6..635a437 100644 --- a/source/power/max17050.c +++ b/source/power/max17050.c @@ -1,9 +1,9 @@ /* * Fuel gauge driver for Nintendo Switch's Maxim 17050 * - * Copyright (C) 2011 Samsung Electronics + * Copyright (c) 2011 Samsung Electronics * MyungJoo Ham - * Copyright (C) 2018 CTCaer + * Copyright (c) 2018 CTCaer * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -43,6 +43,9 @@ #define MAX17050_VMAX_TOLERANCE 50 /* 50 mV */ +#pragma GCC push_options +#pragma GCC optimize ("Os") + int max17050_get_property(enum MAX17050_reg reg, int *value) { u16 data; @@ -259,8 +262,10 @@ int max17050_fix_configuration() /* Init complete, Clear the POR bit */ //_max17050_set_por_bit(0); // Should we? Or let the switch to reconfigure POR? - // Sets POR, BI, BR. + // Sets POR, BI, BR. _max17050_set_por_bit(0x8801); return 0; } + +#pragma GCC pop_options \ No newline at end of file diff --git a/source/power/max17050.h b/source/power/max17050.h index 2196b80..e4c8acf 100644 --- a/source/power/max17050.h +++ b/source/power/max17050.h @@ -2,9 +2,9 @@ * Fuel gauge driver for Nintendo Switch's Maxim 17050 * Note that Maxim 8966 and 8997 are mfd and this is its subdevice. * - * Copyright (C) 2011 Samsung Electronics + * Copyright (c) 2011 Samsung Electronics * MyungJoo Ham - * Copyright (C) 2018 CTCaer + * Copyright (c) 2018 CTCaer * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/source/power/max77620.h b/source/power/max77620.h index fcce309..26ea855 100644 --- a/source/power/max77620.h +++ b/source/power/max77620.h @@ -1,7 +1,7 @@ /* * Defining registers address and its bit definitions of MAX77620 and MAX20024 * - * Copyright (C) 2016 NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2016 NVIDIA CORPORATION. All rights reserved. * Copyright (c) 2019 CTCaer * * This program is free software; you can redistribute it and/or modify it @@ -19,9 +19,19 @@ #define MAX77620_CNFGGLBL1_LBDAC_EN (1 << 7) #define MAX77620_CNFGGLBL1_MPPLD (1 << 6) #define MAX77620_CNFGGLBL1_LBHYST ((1 << 5) | (1 << 4)) -#define MAX77620_CNFGGLBL1_LBHYST_N (1 << 4) -#define MAX77620_CNFGGLBL1_LBDAC 0x0E -#define MAX77620_CNFGGLBL1_LBDAC_N (1 << 1) +#define MAX77620_CNFGGLBL1_LBHYST_100 (0 << 4) +#define MAX77620_CNFGGLBL1_LBHYST_200 (1 << 4) +#define MAX77620_CNFGGLBL1_LBHYST_300 (2 << 4) +#define MAX77620_CNFGGLBL1_LBHYST_400 (3 << 4) +#define MAX77620_CNFGGLBL1_LBDAC_MASK 0x0E +#define MAX77620_CNFGGLBL1_LBDAC_2700 (0 << 1) +#define MAX77620_CNFGGLBL1_LBDAC_2800 (1 << 1) +#define MAX77620_CNFGGLBL1_LBDAC_2900 (2 << 1) +#define MAX77620_CNFGGLBL1_LBDAC_3000 (3 << 1) +#define MAX77620_CNFGGLBL1_LBDAC_3100 (4 << 1) +#define MAX77620_CNFGGLBL1_LBDAC_3200 (5 << 1) +#define MAX77620_CNFGGLBL1_LBDAC_3300 (6 << 1) +#define MAX77620_CNFGGLBL1_LBDAC_3400 (7 << 1) #define MAX77620_CNFGGLBL1_LBRSTEN (1 << 0) #define MAX77620_REG_CNFGGLBL2 0x01 @@ -130,7 +140,7 @@ #define MAX77620_POWER_MODE_DISABLE 0 #define MAX20024_LDO_CFG2_MPOK_MASK (1 << 2) #define MAX77620_LDO_CFG2_ADE_MASK (1 << 1) -#define MAX77620_LDO_CFG2_ADE_DISABLE 0 +#define MAX77620_LDO_CFG2_ADE_DISABLE (0 << 1) #define MAX77620_LDO_CFG2_ADE_ENABLE (1 << 1) #define MAX77620_LDO_CFG2_SS_MASK (1 << 0) #define MAX77620_LDO_CFG2_SS_FAST (1 << 0) @@ -153,6 +163,24 @@ #define MAX77620_REG_PUE_GPIO 0x3E #define MAX77620_REG_PDE_GPIO 0x3F #define MAX77620_REG_AME_GPIO 0x40 +#define MAX77620_CNFG_GPIO_DRV_MASK (1 << 0) +#define MAX77620_CNFG_GPIO_DRV_PUSHPULL (1 << 0) +#define MAX77620_CNFG_GPIO_DRV_OPENDRAIN (0 << 0) +#define MAX77620_CNFG_GPIO_DIR_MASK (1 << 1) +#define MAX77620_CNFG_GPIO_DIR_INPUT (1 << 1) +#define MAX77620_CNFG_GPIO_DIR_OUTPUT (0 << 1) +#define MAX77620_CNFG_GPIO_INPUT_VAL_MASK (1 << 2) +#define MAX77620_CNFG_GPIO_OUTPUT_VAL_MASK (1 << 3) +#define MAX77620_CNFG_GPIO_OUTPUT_VAL_HIGH (1 << 3) +#define MAX77620_CNFG_GPIO_OUTPUT_VAL_LOW (0 << 3) +#define MAX77620_CNFG_GPIO_INT_MASK (0x3 << 4) +#define MAX77620_CNFG_GPIO_INT_FALLING (1 << 4) +#define MAX77620_CNFG_GPIO_INT_RISING (1 << 5) +#define MAX77620_CNFG_GPIO_DBNC_MASK (0x3 << 6) +#define MAX77620_CNFG_GPIO_DBNC_None (0x0 << 6) +#define MAX77620_CNFG_GPIO_DBNC_8ms (0x1 << 6) +#define MAX77620_CNFG_GPIO_DBNC_16ms (0x2 << 6) +#define MAX77620_CNFG_GPIO_DBNC_32ms (0x3 << 6) #define MAX77620_REG_ONOFFCNFG1 0x41 #define MAX77620_ONOFFCNFG1_SFT_RST (1 << 7) @@ -259,25 +287,6 @@ #define MAX77620_SD_CFG1_FSRADE_SD_DISABLE 0 #define MAX77620_SD_CFG1_FSRADE_SD_ENABLE (1 << 0) -#define MAX77620_CNFG_GPIO_DRV_MASK (1 << 0) -#define MAX77620_CNFG_GPIO_DRV_PUSHPULL (1 << 0) -#define MAX77620_CNFG_GPIO_DRV_OPENDRAIN 0 -#define MAX77620_CNFG_GPIO_DIR_MASK (1 << 1) -#define MAX77620_CNFG_GPIO_DIR_INPUT (1 << 1) -#define MAX77620_CNFG_GPIO_DIR_OUTPUT 0 -#define MAX77620_CNFG_GPIO_INPUT_VAL_MASK (1 << 2) -#define MAX77620_CNFG_GPIO_OUTPUT_VAL_MASK (1 << 3) -#define MAX77620_CNFG_GPIO_OUTPUT_VAL_HIGH (1 << 3) -#define MAX77620_CNFG_GPIO_OUTPUT_VAL_LOW 0 -#define MAX77620_CNFG_GPIO_INT_MASK (0x3 << 4) -#define MAX77620_CNFG_GPIO_INT_FALLING (1 << 4) -#define MAX77620_CNFG_GPIO_INT_RISING (1 << 5) -#define MAX77620_CNFG_GPIO_DBNC_MASK (0x3 << 6) -#define MAX77620_CNFG_GPIO_DBNC_None (0x0 << 6) -#define MAX77620_CNFG_GPIO_DBNC_8ms (0x1 << 6) -#define MAX77620_CNFG_GPIO_DBNC_16ms (0x2 << 6) -#define MAX77620_CNFG_GPIO_DBNC_32ms (0x3 << 6) - #define MAX77620_IRQ_LVL2_GPIO_EDGE0 (1 << 0) #define MAX77620_IRQ_LVL2_GPIO_EDGE1 (1 << 1) #define MAX77620_IRQ_LVL2_GPIO_EDGE2 (1 << 2) diff --git a/source/power/max7762x.c b/source/power/max7762x.c index 2c8cff4..0e7a6b5 100644 --- a/source/power/max7762x.c +++ b/source/power/max7762x.c @@ -64,6 +64,16 @@ static const max77620_regulator_t _pmic_regulators[] = { { REGULATOR_LDO, "ldo8", 0x00, 50000, 800000, 1050000, 1050000, MAX77620_REG_LDO8_CFG, MAX77620_REG_LDO8_CFG2, MAX77620_LDO_VOLT_MASK, MAX77620_LDO_POWER_MODE_MASK, MAX77620_LDO_POWER_MODE_SHIFT, 0x00, MAX77620_REG_FPS_LDO8, 3, 7, 0 } }; +static void _max77620_try_set_reg(u8 reg, u8 val) +{ + u8 tmp; + do + { + i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, reg, val); + tmp = i2c_recv_byte(I2C_5, MAX77620_I2C_ADDR, reg); + } while (val != tmp); +} + int max77620_regulator_get_status(u32 id) { if (id > REGULATOR_MAX) @@ -83,7 +93,7 @@ int max77620_regulator_config_fps(u32 id) const max77620_regulator_t *reg = &_pmic_regulators[id]; - i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, reg->fps_addr, + _max77620_try_set_reg(reg->fps_addr, (reg->fps_src << MAX77620_FPS_SRC_SHIFT) | (reg->pu_period << MAX77620_FPS_PU_PERIOD_SHIFT) | (reg->pd_period)); return 1; @@ -102,7 +112,7 @@ int max77620_regulator_set_voltage(u32 id, u32 mv) u32 mult = (mv + reg->mv_step - 1 - reg->mv_min) / reg->mv_step; u8 val = i2c_recv_byte(I2C_5, MAX77620_I2C_ADDR, reg->volt_addr); val = (val & ~reg->volt_mask) | (mult & reg->volt_mask); - i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, reg->volt_addr, val); + _max77620_try_set_reg(reg->volt_addr, val); usleep(1000); return 1; @@ -121,7 +131,7 @@ int max77620_regulator_enable(u32 id, int enable) val = (val & ~reg->enable_mask) | ((MAX77620_POWER_MODE_NORMAL << reg->enable_shift) & reg->enable_mask); else val &= ~reg->enable_mask; - i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, addr, val); + _max77620_try_set_reg(addr, val); usleep(1000); return 1; @@ -139,7 +149,7 @@ int max77620_regulator_set_volt_and_flags(u32 id, u32 mv, u8 flags) u32 mult = (mv + reg->mv_step - 1 - reg->mv_min) / reg->mv_step; u8 val = ((flags << reg->enable_shift) & ~reg->volt_mask) | (mult & reg->volt_mask); - i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, reg->volt_addr, val); + _max77620_try_set_reg(reg->volt_addr, val); usleep(1000); return 1; @@ -155,11 +165,12 @@ void max77620_config_default() if (_pmic_regulators[i].fps_src != MAX77620_FPS_SRC_NONE) max77620_regulator_enable(i, 1); } - i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_SD_CFG2, 4); + _max77620_try_set_reg(MAX77620_REG_SD_CFG2, 4); } void max77620_low_battery_monitor_config() { - i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_CNFGGLBL1, - MAX77620_CNFGGLBL1_LBDAC_EN | MAX77620_CNFGGLBL1_LBHYST_N | MAX77620_CNFGGLBL1_LBDAC_N); + _max77620_try_set_reg(MAX77620_REG_CNFGGLBL1, + MAX77620_CNFGGLBL1_LBDAC_EN | MAX77620_CNFGGLBL1_MPPLD | + MAX77620_CNFGGLBL1_LBHYST_200 | MAX77620_CNFGGLBL1_LBDAC_2800); } diff --git a/source/power/max7762x.h b/source/power/max7762x.h index eefa112..3a0afe3 100644 --- a/source/power/max7762x.h +++ b/source/power/max7762x.h @@ -24,16 +24,16 @@ * Switch Power domains (max77620): * Name | Usage | uV step | uV min | uV default | uV max | Init *-------+---------------+---------+--------+------------+---------+------------------ -* sd0 | core | 12500 | 600000 | 625000 | 1400000 | 1.125V (pkg1.1) +* sd0 | SoC | 12500 | 600000 | 625000 | 1400000 | 1.125V (pkg1.1) * sd1 | SDRAM | 12500 | 600000 | 1125000 | 1125000 | 1.1V (pkg1.1) * sd2 | ldo{0-1, 7-8} | 12500 | 600000 | 1325000 | 1350000 | 1.325V (pcv) * sd3 | 1.8V general | 12500 | 600000 | 1800000 | 1800000 | * ldo0 | Display Panel | 25000 | 800000 | 1200000 | 1200000 | 1.2V (pkg1.1) * ldo1 | XUSB, PCIE | 25000 | 800000 | 1050000 | 1050000 | 1.05V (pcv) * ldo2 | SDMMC1 | 50000 | 800000 | 1800000 | 3300000 | -* ldo3 | GC ASIC | 50000 | 800000 | 3100000 | 3100000 | 3.1V (pcv) +* ldo3 | GC ASIC | 50000 | 800000 | 3100000 | 3100000 | 3.1V (pcv) * ldo4 | RTC | 12500 | 800000 | 850000 | 850000 | -* ldo5 | GC ASIC | 50000 | 800000 | 1800000 | 1800000 | 1.8V (pcv) +* ldo5 | GC ASIC | 50000 | 800000 | 1800000 | 1800000 | 1.8V (pcv) * ldo6 | Touch, ALS | 50000 | 800000 | 2900000 | 2900000 | 2.9V * ldo7 | XUSB | 50000 | 800000 | 1050000 | 1050000 | * ldo8 | XUSB, DC | 50000 | 800000 | 1050000 | 1050000 | @@ -71,6 +71,8 @@ /* MAX77621_VOUT */ #define MAX77621_VOUT_ENABLE (1 << 7) #define MAX77621_VOUT_MASK 0x7F +#define MAX77621_VOUT_0_95V 0x37 +#define MAX77621_VOUT_1_09V 0x4F /* MAX77621_VOUT_DVC_DVS */ #define MAX77621_DVS_VOUT_MASK 0x7F diff --git a/source/rtc/max77620-rtc.c b/source/rtc/max77620-rtc.c index 85895af..e214363 100644 --- a/source/rtc/max77620-rtc.c +++ b/source/rtc/max77620-rtc.c @@ -36,7 +36,7 @@ void max77620_rtc_get_time(rtc_time_t *time) time->min = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_MIN_REG) & 0x7F; time->hour = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_HOUR_REG) & 0x1F; - + if (!(val & MAX77620_RTC_24H) && time->hour & MAX77620_RTC_HOUR_PM_MASK) time->hour = (time->hour & 0xF) + 12; @@ -52,7 +52,7 @@ void max77620_rtc_get_time(rtc_time_t *time) } // Get date. - time->date = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_DATE_REG) & 0x1f; + time->day = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_DATE_REG) & 0x1f; time->month = (i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_MONTH_REG) & 0xF) - 1; time->year = (i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_YEAR_REG) & 0x7F) + 2000; } diff --git a/source/rtc/max77620-rtc.h b/source/rtc/max77620-rtc.h index 756e67c..981ccfe 100644 --- a/source/rtc/max77620-rtc.h +++ b/source/rtc/max77620-rtc.h @@ -64,7 +64,7 @@ typedef struct _rtc_time_t { u8 sec; u8 min; u8 hour; - u8 date; + u8 day; u8 month; u16 year; } rtc_time_t; diff --git a/source/sec/se.c b/source/sec/se.c index c9402c0..7416d38 100644 --- a/source/sec/se.c +++ b/source/sec/se.c @@ -21,6 +21,7 @@ #include "../sec/se.h" #include "../mem/heap.h" +#include "../soc/bpmp.h" #include "../soc/t210.h" #include "../sec/se_t210.h" #include "../utils/util.h" @@ -32,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; @@ -82,25 +86,23 @@ static int _se_wait() while (!(SE(SE_INT_STATUS_REG_OFFSET) & SE_INT_OP_DONE(INT_SET))) ; if (SE(SE_INT_STATUS_REG_OFFSET) & SE_INT_ERROR(INT_SET) || - SE(SE_STATUS_0) & 3 || - SE(SE_ERR_STATUS_0) != 0) + SE(SE_STATUS_0) & SE_STATUS_0_STATE_WAIT_IN || + SE(SE_ERR_STATUS_0) != SE_ERR_STATUS_0_SE_NS_ACCESS_CLEAR) return 0; return 1; } static int _se_execute(u32 op, void *dst, u32 dst_size, const void *src, u32 src_size) { - se_ll_t *ll_dst = NULL, *ll_src = NULL; + se_ll_t *ll_dst = (se_ll_t *)0xECFFFFE0, *ll_src = (se_ll_t *)0xECFFFFF0; if (dst) { - ll_dst = (se_ll_t *)malloc(sizeof(se_ll_t)); _se_ll_init(ll_dst, (u32)dst, dst_size); } if (src) { - ll_src = (se_ll_t *)malloc(sizeof(se_ll_t)); _se_ll_init(ll_src, (u32)src, src_size); } @@ -108,14 +110,13 @@ static int _se_execute(u32 op, void *dst, u32 dst_size, const void *src, u32 src SE(SE_ERR_STATUS_0) = SE(SE_ERR_STATUS_0); SE(SE_INT_STATUS_REG_OFFSET) = SE(SE_INT_STATUS_REG_OFFSET); - SE(SE_OPERATION_REG_OFFSET) = SE_OPERATION(op); + bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY, false); + + SE(SE_OPERATION_REG_OFFSET) = SE_OPERATION(op); int res = _se_wait(); - if (src) - free(ll_src); - if (dst) - free(ll_dst); + bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY, false); return res; } @@ -133,7 +134,7 @@ static int _se_execute_one_block(u32 op, void *dst, u32 dst_size, const void *sr memcpy(block, src, src_size); int res = _se_execute(op, block, 0x10, block, 0x10); memcpy(dst, block, dst_size); - + free(block); return res; } @@ -147,17 +148,79 @@ static void _se_aes_ctr_set(void *ctr) void se_rsa_acc_ctrl(u32 rs, u32 flags) { - if (flags & 0x7F) - SE(SE_RSA_KEYTABLE_ACCESS_REG_OFFSET + 4 * rs) = (((flags >> 4) & 4) | (flags & 3)) ^ 7; - if (flags & 0x80) + if (flags & SE_RSA_KEY_TBL_DIS_KEY_ALL_FLAG) + SE(SE_RSA_KEYTABLE_ACCESS_REG_OFFSET + 4 * rs) = + ((flags >> SE_RSA_KEY_TBL_DIS_KEYUSE_FLAG_SHIFT) & SE_RSA_KEY_TBL_DIS_KEYUSE_FLAG) | + ((flags & SE_RSA_KEY_TBL_DIS_KEY_READ_UPDATE_FLAG) ^ SE_RSA_KEY_TBL_DIS_KEY_ALL_COMMON_FLAG); + if (flags & SE_RSA_KEY_TBL_DIS_KEY_LOCK_FLAG) 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) + if (flags & SE_KEY_TBL_DIS_KEY_ACCESS_FLAG) SE(SE_KEY_TABLE_ACCESS_REG_OFFSET + 4 * ks) = ~flags; - if (flags & 0x80) + if (flags & SE_KEY_TBL_DIS_KEY_LOCK_FLAG) SE(SE_KEY_TABLE_ACCESS_LOCK_OFFSET) &= ~(1 << ks); } @@ -227,18 +290,7 @@ int se_aes_crypt_ecb(u32 ks, u32 enc, void *dst, u32 dst_size, const void *src, int se_aes_crypt_block_ecb(u32 ks, u32 enc, void *dst, const void *src) { - if (enc) - { - SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_ENC_ALG(ALG_AES_ENC) | SE_CONFIG_DST(DST_MEMORY); - SE(SE_CRYPTO_REG_OFFSET) = SE_CRYPTO_KEY_INDEX(ks) | SE_CRYPTO_CORE_SEL(CORE_ENCRYPT); - } - else - { - SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_DEC_ALG(ALG_AES_DEC) | SE_CONFIG_DST(DST_MEMORY); - SE(SE_CRYPTO_REG_OFFSET) = SE_CRYPTO_KEY_INDEX(ks) | SE_CRYPTO_CORE_SEL(CORE_DECRYPT); - } - SE(SE_BLOCK_COUNT_REG_OFFSET) = 0; - return _se_execute(OP_START, dst, 0x10, src, 0x10); + return se_aes_crypt_ecb(ks, enc, dst, 0x10, src, 0x10); } int se_aes_crypt_ctr(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_size, void *ctr) @@ -246,7 +298,8 @@ int se_aes_crypt_ctr(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_s SE(SE_SPARE_0_REG_OFFSET) = 1; SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_ENC_ALG(ALG_AES_ENC) | SE_CONFIG_DST(DST_MEMORY); SE(SE_CRYPTO_REG_OFFSET) = SE_CRYPTO_KEY_INDEX(ks) | SE_CRYPTO_CORE_SEL(CORE_ENCRYPT) | - SE_CRYPTO_XOR_POS(XOR_BOTTOM) | SE_CRYPTO_INPUT_SEL(INPUT_LNR_CTR) | SE_CRYPTO_CTR_VAL(1); + SE_CRYPTO_XOR_POS(XOR_BOTTOM) | SE_CRYPTO_INPUT_SEL(INPUT_LNR_CTR) | SE_CRYPTO_CTR_VAL(1) | + SE_CRYPTO_VCTRAM_SEL(VCTRAM_AHB); _se_aes_ctr_set(ctr); u32 src_size_aligned = src_size & 0xFFFFFFF0; @@ -331,7 +384,9 @@ int se_aes_cmac(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_size) _gf256_mul_x(key); SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_ENC_ALG(ALG_AES_ENC) | SE_CONFIG_DST(DST_HASHREG); - SE(SE_CRYPTO_REG_OFFSET) = SE_CRYPTO_KEY_INDEX(ks) | 0x145; + SE(SE_CRYPTO_REG_OFFSET) = SE_CRYPTO_KEY_INDEX(ks) | SE_CRYPTO_INPUT_SEL(INPUT_AHB) | + SE_CRYPTO_XOR_POS(XOR_TOP) | SE_CRYPTO_VCTRAM_SEL(VCTRAM_AESOUT) | SE_CRYPTO_HASH(HASH_ENABLE) | + SE_CRYPTO_CORE_SEL(CORE_ENCRYPT); se_aes_key_iv_clear(ks); u32 num_blocks = (src_size + 0xf) >> 4; @@ -371,15 +426,15 @@ int se_calc_sha256(void *dst, const void *src, u32 src_size) int res; // Setup config for SHA256, size = BITS(src_size). SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_ENC_MODE(MODE_SHA256) | SE_CONFIG_ENC_ALG(ALG_SHA) | SE_CONFIG_DST(DST_HASHREG); - SE(SE_SHA_CONFIG_REG_OFFSET) = SHA_ENABLE; - SE(SE_SHA_MSG_LENGTH_REG_OFFSET) = (u32)(src_size << 3); - SE(SE_SHA_MSG_LENGTH_REG_OFFSET + 4 * 1) = 0; - SE(SE_SHA_MSG_LENGTH_REG_OFFSET + 4 * 2) = 0; - SE(SE_SHA_MSG_LENGTH_REG_OFFSET + 4 * 3) = 0; - SE(SE_SHA_MSG_LEFT_REG_OFFSET) = (u32)(src_size << 3); - SE(SE_SHA_MSG_LEFT_REG_OFFSET + 4 * 1) = 0; - SE(SE_SHA_MSG_LEFT_REG_OFFSET + 4 * 2) = 0; - SE(SE_SHA_MSG_LEFT_REG_OFFSET + 4 * 3) = 0; + SE(SE_SHA_CONFIG_REG_OFFSET) = SHA_INIT_HASH; + SE(SE_SHA_MSG_LENGTH_0_REG_OFFSET) = (u32)(src_size << 3); + SE(SE_SHA_MSG_LENGTH_1_REG_OFFSET) = 0; + SE(SE_SHA_MSG_LENGTH_2_REG_OFFSET) = 0; + SE(SE_SHA_MSG_LENGTH_3_REG_OFFSET) = 0; + SE(SE_SHA_MSG_LEFT_0_REG_OFFSET) = (u32)(src_size << 3); + SE(SE_SHA_MSG_LEFT_1_REG_OFFSET) = 0; + SE(SE_SHA_MSG_LEFT_2_REG_OFFSET) = 0; + SE(SE_SHA_MSG_LEFT_3_REG_OFFSET) = 0; // Trigger the operation. res = _se_execute(OP_START, NULL, 0, src, src_size); @@ -391,3 +446,46 @@ int se_calc_sha256(void *dst, const void *src, u32 src_size) return res; } + +int se_calc_hmac_sha256(void *dst, const void *src, u32 src_size, const void *key, u32 key_size) { + int res = 0; + u8 *secret = (u8 *)malloc(0x40); + u8 *ipad = (u8 *)malloc(0x40 + src_size); + u8 *opad = (u8 *)malloc(0x60); + + if (key_size > 0x40) + { + if (!se_calc_sha256(secret, key, key_size)) + goto out; + memset(secret + 0x20, 0, 0x20); + } + else + { + memcpy(secret, key, key_size); + memset(secret + key_size, 0, 0x40 - key_size); + } + + u32 *secret32 = (u32 *)secret; + u32 *ipad32 = (u32 *)ipad; + u32 *opad32 = (u32 *)opad; + for (u32 i = 0; i < 0x10; i++) + { + ipad32[i] = secret32[i] ^ 0x36363636; + opad32[i] = secret32[i] ^ 0x5C5C5C5C; + } + + memcpy(ipad + 0x40, src, src_size); + if (!se_calc_sha256(dst, ipad, 0x40 + src_size)) + goto out; + memcpy(opad + 0x40, dst, 0x20); + if (!se_calc_sha256(dst, opad, 0x60)) + goto out; + + res = 1; + +out:; + free(secret); + free(ipad); + free(opad); + return res; +} diff --git a/source/sec/se.h b/source/sec/se.h index 263fe02..0d517c7 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); @@ -32,5 +35,6 @@ int se_aes_xts_crypt_sec(u32 ks1, u32 ks2, u32 enc, u64 sec, void *dst, const vo int se_aes_xts_crypt(u32 ks1, u32 ks2, u32 enc, u64 sec, void *dst, const void *src, u32 secsize, u32 num_secs); int se_aes_cmac(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_size); int se_calc_sha256(void *dst, const void *src, u32 src_size); +int se_calc_hmac_sha256(void *dst, const void *src, u32 src_size, const void *key, u32 key_size); #endif diff --git a/source/sec/se_t210.h b/source/sec/se_t210.h index 760527d..3b610bc 100644 --- a/source/sec/se_t210.h +++ b/source/sec/se_t210.h @@ -36,6 +36,8 @@ #define SE_SECURITY_0 0x000 #define SE_KEY_SCHED_READ_SHIFT 3 +#define SE_TZRAM_SECURITY_0 0x004 + #define SE_CONFIG_REG_OFFSET 0x014 #define SE_CONFIG_ENC_ALG_SHIFT 12 #define SE_CONFIG_DEC_ALG_SHIFT 8 @@ -209,8 +211,12 @@ #define SE_INT_OP_DONE(x) (x << SE_INT_OP_DONE_SHIFT) #define SE_INT_ERROR_SHIFT 16 #define SE_INT_ERROR(x) (x << SE_INT_ERROR_SHIFT) + #define SE_STATUS_0 0x800 +#define SE_STATUS_0_STATE_WAIT_IN 3 + #define SE_ERR_STATUS_0 0x804 +#define SE_ERR_STATUS_0_SE_NS_ACCESS_CLEAR 0 #define SE_CRYPTO_KEYTABLE_DST_REG_OFFSET 0X330 #define SE_CRYPTO_KEYTABLE_DST_WORD_QUAD_SHIFT 0 @@ -231,11 +237,17 @@ #define SE_SPARE_0_REG_OFFSET 0x80c #define SE_SHA_CONFIG_REG_OFFSET 0x200 -#define SHA_DISABLE 0 -#define SHA_ENABLE 1 +#define SHA_CONTINUE 0 +#define SHA_INIT_HASH 1 -#define SE_SHA_MSG_LENGTH_REG_OFFSET 0x204 -#define SE_SHA_MSG_LEFT_REG_OFFSET 0x214 +#define SE_SHA_MSG_LENGTH_0_REG_OFFSET 0x204 +#define SE_SHA_MSG_LENGTH_1_REG_OFFSET 0x208 +#define SE_SHA_MSG_LENGTH_2_REG_OFFSET 0x20C +#define SE_SHA_MSG_LENGTH_3_REG_OFFSET 0x210 +#define SE_SHA_MSG_LEFT_0_REG_OFFSET 0x214 +#define SE_SHA_MSG_LEFT_1_REG_OFFSET 0x218 +#define SE_SHA_MSG_LEFT_2_REG_OFFSET 0x21C +#define SE_SHA_MSG_LEFT_3_REG_OFFSET 0x220 #define SE_HASH_RESULT_REG_COUNT 16 #define SE_HASH_RESULT_REG_OFFSET 0x030 @@ -254,13 +266,24 @@ TEGRA_SE_RNG_DT_SIZE) #define TEGRA_SE_AES_CMAC_DIGEST_SIZE 16 -#define TEGRA_SE_RSA512_DIGEST_SIZE 64 +#define TEGRA_SE_RSA512_DIGEST_SIZE 64 #define TEGRA_SE_RSA1024_DIGEST_SIZE 128 #define TEGRA_SE_RSA1536_DIGEST_SIZE 192 #define TEGRA_SE_RSA2048_DIGEST_SIZE 256 #define SE_KEY_TABLE_ACCESS_LOCK_OFFSET 0x280 +#define SE_KEY_TBL_DIS_KEY_LOCK_FLAG 0x80 + #define SE_KEY_TABLE_ACCESS_REG_OFFSET 0x284 +#define SE_KEY_TBL_DIS_KEYREAD_FLAG (1 << 0) +#define SE_KEY_TBL_DIS_KEYUPDATE_FLAG (1 << 1) +#define SE_KEY_TBL_DIS_OIVREAD_FLAG (1 << 2) +#define SE_KEY_TBL_DIS_OIVUPDATE_FLAG (1 << 3) +#define SE_KEY_TBL_DIS_UIVREAD_FLAG (1 << 4) +#define SE_KEY_TBL_DIS_UIVUPDATE_FLAG (1 << 5) +#define SE_KEY_TBL_DIS_KEYUSE_FLAG (1 << 6) +#define SE_KEY_TBL_DIS_KEY_ACCESS_FLAG 0x7F + #define SE_KEY_READ_DISABLE_SHIFT 0 #define SE_KEY_UPDATE_DISABLE_SHIFT 1 @@ -312,7 +335,16 @@ #define TEGRA_SE_RSA_KEYSLOT_COUNT 2 #define SE_RSA_KEYTABLE_ACCESS_LOCK_OFFSET 0x40C +#define SE_RSA_KEY_TBL_DIS_KEY_LOCK_FLAG 0x80 + #define SE_RSA_KEYTABLE_ACCESS_REG_OFFSET 0x410 +#define SE_RSA_KEY_TBL_DIS_KEYREAD_FLAG (1 << 0) +#define SE_RSA_KEY_TBL_DIS_KEYUPDATE_FLAG (1 << 1) +#define SE_RSA_KEY_TBL_DIS_KEY_READ_UPDATE_FLAG (SE_RSA_KEY_TBL_DIS_KEYREAD_FLAG | SE_RSA_KEY_TBL_DIS_KEYUPDATE_FLAG) +#define SE_RSA_KEY_TBL_DIS_KEYUSE_FLAG (1 << 2) +#define SE_RSA_KEY_TBL_DIS_KEYUSE_FLAG_SHIFT (1 << 2) +#define SE_RSA_KEY_TBL_DIS_KEY_ALL_COMMON_FLAG 7 +#define SE_RSA_KEY_TBL_DIS_KEY_ALL_FLAG 0x7F #define SE_RSA_KEYTABLE_ADDR 0x420 #define SE_RSA_KEYTABLE_DATA 0x424 diff --git a/source/sec/tsec.c b/source/sec/tsec.c index 9916882..17cd623 100644 --- a/source/sec/tsec.c +++ b/source/sec/tsec.c @@ -21,7 +21,9 @@ #include "../sec/tsec.h" #include "../sec/tsec_t210.h" #include "../sec/se_t210.h" +#include "../soc/bpmp.h" #include "../soc/clock.h" +#include "../soc/kfuse.h" #include "../soc/smmu.h" #include "../soc/t210.h" #include "../mem/heap.h" @@ -64,14 +66,20 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt) u32 *pdir, *car, *fuse, *pmc, *flowctrl, *se, *mc, *iram, *evec; u32 *pkg11_magic_off; - //Enable clocks. + bpmp_mmu_disable(); + bpmp_clk_rate_set(BPMP_CLK_NORMAL); + + // Enable clocks. clock_enable_host1x(); + usleep(2); clock_enable_tsec(); clock_enable_sor_safe(); clock_enable_sor0(); clock_enable_sor1(); clock_enable_kfuse(); + kfuse_wait_ready(); + //Configure Falcon. TSEC(TSEC_DMACTL) = 0; TSEC(TSEC_IRQMSET) = @@ -149,7 +157,7 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt) se = page_alloc(1); memcpy(se, (void *)SE_BASE, 0x1000); smmu_map(pdir, SE_BASE, (u32)se, 1, _READABLE | _WRITABLE | _NONSECURE); - + // Memory controller. mc = page_alloc(1); memcpy(mc, (void *)MC_BASE, 0x1000); @@ -170,7 +178,7 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt) } //Execute firmware. - HOST1X(0x3300) = 0x34C2E1DA; + HOST1X(HOST1X_CH0_SYNC_SYNCPT_160) = 0x34C2E1DA; TSEC(TSEC_STATUS) = 0; TSEC(TSEC_BOOTKEYVER) = 1; // HOS uses key version 1. TSEC(TSEC_BOOTVEC) = 0; @@ -203,7 +211,7 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt) res = -6; smmu_deinit_for_tsec(); - goto out; + goto out_free; } // Give some extra time to make sure PKG1.1 is decrypted. @@ -211,7 +219,7 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt) memcpy(tsec_keys, &key, 0x20); memcpy(tsec_ctxt->pkg1, iram, 0x30000); - + smmu_deinit_for_tsec(); // for (int i = 0; i < kidx; i++) @@ -247,7 +255,7 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt) } //Fetch result. - HOST1X(0x3300) = 0; + HOST1X(HOST1X_CH0_SYNC_SYNCPT_160) = 0; u32 buf[4]; buf[0] = SOR1(SOR_NV_PDISP_SOR_DP_HDCP_BKSV_LSB); buf[1] = SOR1(SOR_NV_PDISP_SOR_TMDS_HDCP_BKSV_LSB); @@ -272,7 +280,8 @@ out:; clock_disable_sor0(); clock_disable_sor_safe(); clock_disable_tsec(); - clock_disable_host1x(); + bpmp_mmu_enable(); + bpmp_clk_rate_set(BPMP_CLK_DEFAULT_BOOST); return res; } diff --git a/source/soc/bpmp.c b/source/soc/bpmp.c new file mode 100644 index 0000000..94ce6d5 --- /dev/null +++ b/source/soc/bpmp.c @@ -0,0 +1,248 @@ +/* + * BPMP-Lite Cache/MMU and Frequency driver for Tegra X1 + * + * 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 "bpmp.h" +#include "clock.h" +#include "t210.h" +#include "../../common/memory_map.h" +#include "../utils/util.h" + +#define BPMP_CACHE_CONFIG 0x0 +#define CFG_ENABLE (1 << 0) +#define CFG_FORCE_WRITE_THROUGH (1 << 3) +#define CFG_DISABLE_WRITE_BUFFER (1 << 10) +#define CFG_DISABLE_READ_BUFFER (1 << 11) +#define CFG_FULL_LINE_DIRTY (1 << 13) +#define CFG_TAG_CHK_ABRT_ON_ERR (1 << 14) +#define BPMP_CACHE_LOCK 0x4 +#define BPMP_CACHE_SIZE 0xC +#define BPMP_CACHE_LFSR 0x10 +#define BPMP_CACHE_TAG_STATUS 0x14 +#define BPMP_CACHE_CLKEN_OVERRIDE 0x18 +#define BPMP_CACHE_MAINT_ADDR 0x20 +#define BPMP_CACHE_MAINT_DATA 0x24 +#define BPMP_CACHE_MAINT_REQ 0x28 +#define MAINT_REQ_WAY_BITMAP(x) ((x) << 8) + +#define BPMP_CACHE_INT_MASK 0x40 +#define BPMP_CACHE_INT_CLEAR 0x44 +#define INT_CLR_MAINT_DONE (1 << 0) + +#define BPMP_CACHE_INT_RAW_EVENT 0x48 +#define INT_RAW_EVENT_MAINT_DONE (1 << 0) +#define BPMP_CACHE_INT_STATUS 0x4C + +#define BPMP_CACHE_RB_CFG 0x80 +#define BPMP_CACHE_WB_CFG 0x84 + +#define BPMP_CACHE_MMU_FALLBACK_ENTRY 0xA0 +#define BPMP_CACHE_MMU_SHADOW_COPY_MASK 0xA4 +#define BPMP_CACHE_MMU_CFG 0xAC +#define MMU_CFG_SEQ_EN (1 << 1) +#define MMU_CFG_TLB_EN (1 << 2) +#define MMU_CFG_ABORT_STORE_LAST (1 << 4) +#define BPMP_CACHE_MMU_CMD 0xB0 +#define MMU_CMD_NOP 0 +#define MMU_CMD_INIT 1 +#define MMU_CMD_COPY_SHADOW 2 +#define BPMP_CACHE_MMU_ABORT_STAT 0xB4 +#define BPMP_CACHE_MMU_ABORT_ADDR 0xB8 +#define BPMP_CACHE_MMU_ACTIVE_ENTRIES 0xBC + +#define BPMP_MMU_SHADOW_ENTRY_BASE (BPMP_CACHE_BASE + 0x400) +#define BPMP_MMU_MAIN_ENTRY_BASE (BPMP_CACHE_BASE + 0x800) +#define MMU_ENTRY_ADDR_MASK 0xFFFFFFE0 + +#define MMU_EN_CACHED (1 << 0) +#define MMU_EN_EXEC (1 << 1) +#define MMU_EN_READ (1 << 2) +#define MMU_EN_WRITE (1 << 3) + +bpmp_mmu_entry_t mmu_entries[] = +{ + { DRAM_START, 0xFFFFFFFF, MMU_EN_READ | MMU_EN_WRITE | MMU_EN_EXEC | MMU_EN_CACHED, true }, + { IRAM_BASE, 0x4003FFFF, MMU_EN_READ | MMU_EN_WRITE | MMU_EN_EXEC | MMU_EN_CACHED, true } +}; + +void bpmp_mmu_maintenance(u32 op, bool force) +{ + if (!force && !(BPMP_CACHE_CTRL(BPMP_CACHE_CONFIG) & CFG_ENABLE)) + return; + + BPMP_CACHE_CTRL(BPMP_CACHE_INT_CLEAR) = INT_CLR_MAINT_DONE; + + // This is a blocking operation. + BPMP_CACHE_CTRL(BPMP_CACHE_MAINT_REQ) = MAINT_REQ_WAY_BITMAP(0xF) | op; + + while(!(BPMP_CACHE_CTRL(BPMP_CACHE_INT_RAW_EVENT) & INT_RAW_EVENT_MAINT_DONE)) + ; + + BPMP_CACHE_CTRL(BPMP_CACHE_INT_CLEAR) = BPMP_CACHE_CTRL(BPMP_CACHE_INT_RAW_EVENT); +} + +void bpmp_mmu_set_entry(int idx, bpmp_mmu_entry_t *entry, bool apply) +{ + if (idx > 31) + return; + + volatile bpmp_mmu_entry_t *mmu_entry = (bpmp_mmu_entry_t *)(BPMP_MMU_SHADOW_ENTRY_BASE + sizeof(bpmp_mmu_entry_t) * idx); + + if (entry->enable) + { + mmu_entry->min_addr = entry->min_addr & MMU_ENTRY_ADDR_MASK; + mmu_entry->max_addr = entry->max_addr & MMU_ENTRY_ADDR_MASK; + mmu_entry->attr = entry->attr; + + BPMP_CACHE_CTRL(BPMP_CACHE_MMU_SHADOW_COPY_MASK) |= (1 << idx); + + if (apply) + BPMP_CACHE_CTRL(BPMP_CACHE_MMU_CMD) = MMU_CMD_COPY_SHADOW; + } +} + +void bpmp_mmu_enable() +{ + if (BPMP_CACHE_CTRL(BPMP_CACHE_CONFIG) & CFG_ENABLE) + return; + + // Init BPMP MMU. + BPMP_CACHE_CTRL(BPMP_CACHE_MMU_CMD) = MMU_CMD_INIT; + BPMP_CACHE_CTRL(BPMP_CACHE_MMU_FALLBACK_ENTRY) = MMU_EN_READ | MMU_EN_WRITE | MMU_EN_EXEC; // RWX for non-defined regions. + BPMP_CACHE_CTRL(BPMP_CACHE_MMU_CFG) = MMU_CFG_SEQ_EN | MMU_CFG_TLB_EN | MMU_CFG_ABORT_STORE_LAST; + + // Init BPMP MMU entries. + BPMP_CACHE_CTRL(BPMP_CACHE_MMU_SHADOW_COPY_MASK) = 0; + for (u32 idx = 0; idx < (sizeof(mmu_entries) / sizeof(bpmp_mmu_entry_t)); idx++) + bpmp_mmu_set_entry(idx, &mmu_entries[idx], false); + + BPMP_CACHE_CTRL(BPMP_CACHE_MMU_CMD) = MMU_CMD_COPY_SHADOW; + + // Invalidate cache. + bpmp_mmu_maintenance(BPMP_MMU_MAINT_INVALID_WAY, true); + + // Enable cache. + BPMP_CACHE_CTRL(BPMP_CACHE_CONFIG) = CFG_ENABLE | CFG_FORCE_WRITE_THROUGH | CFG_TAG_CHK_ABRT_ON_ERR; + + // HW bug. Invalidate cache again. + bpmp_mmu_maintenance(BPMP_MMU_MAINT_INVALID_WAY, false); +} + +void bpmp_mmu_disable() +{ + if (!(BPMP_CACHE_CTRL(BPMP_CACHE_CONFIG) & CFG_ENABLE)) + return; + + // Clean and invalidate cache. + bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY, false); + + // Disable cache. + BPMP_CACHE_CTRL(BPMP_CACHE_CONFIG) = 0; +} + +const u8 pllc4_divn[] = { + 0, // BPMP_CLK_NORMAL: 408MHz 0% - 136MHz APB. + 85, // BPMP_CLK_HIGH_BOOST: 544MHz 33% - 136MHz APB. + 90, // BPMP_CLK_SUPER_BOOST: 576MHz 41% - 144MHz APB. + 92 // BPMP_CLK_HYPER_BOOST: 589MHz 44% - 147MHz APB. + // Do not use for public releases! + //95 // BPMP_CLK_DEV_BOOST: 608MHz 49% - 152MHz APB. +}; + +bpmp_freq_t bpmp_clock_set = BPMP_CLK_NORMAL; + +void bpmp_clk_rate_set(bpmp_freq_t fid) +{ + if (fid > (BPMP_CLK_MAX - 1)) + fid = BPMP_CLK_MAX - 1; + + if (bpmp_clock_set == fid) + return; + + if (fid) + { + if (bpmp_clock_set) + { + // Restore to PLLP source during PLLC4 configuration. + CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = 0x20003333; // PLLP_OUT. + // Wait a bit for clock source change. + msleep(10); + } + + CLOCK(CLK_RST_CONTROLLER_PLLC4_MISC) = PLLC4_MISC_EN_LCKDET; + CLOCK(CLK_RST_CONTROLLER_PLLC4_BASE) = 4 | (pllc4_divn[fid] << 8) | PLL_BASE_ENABLE; // DIVM: 4, DIVP: 1. + + while (!(CLOCK(CLK_RST_CONTROLLER_PLLC4_BASE) & PLLC4_BASE_LOCK)) + ; + + CLOCK(CLK_RST_CONTROLLER_PLLC4_OUT) = (1 << 8) | PLLC4_OUT3_CLKEN; // 1.5 div. + CLOCK(CLK_RST_CONTROLLER_PLLC4_OUT) |= PLLC4_OUT3_RSTN_CLR; // Get divider out of reset. + + // Wait a bit for PLLC4 to stabilize. + msleep(10); + CLOCK(CLK_RST_CONTROLLER_CLK_SYSTEM_RATE) = 3; // PCLK = HCLK / 4. + CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = 0x20003323; // PLLC4_OUT3. + + bpmp_clock_set = fid; + } + else + { + CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = 0x20003333; // PLLP_OUT. + + // Wait a bit for clock source change. + msleep(10); + + CLOCK(CLK_RST_CONTROLLER_CLK_SYSTEM_RATE) = 2; // PCLK = HCLK / 3. + CLOCK(CLK_RST_CONTROLLER_PLLC4_BASE) &= ~PLL_BASE_ENABLE; + bpmp_clock_set = BPMP_CLK_NORMAL; + } +} + +// The following functions halt BPMP to reduce power while sleeping. +// They are not as accurate as RTC at big values but they guarantee time+ delay. +void bpmp_usleep(u32 us) +{ + u32 delay; + + // Each iteration takes 1us. + while (us) + { + delay = (us > HALT_COP_MAX_CNT) ? HALT_COP_MAX_CNT : us; + us -= delay; + + FLOW_CTLR(FLOW_CTLR_HALT_COP_EVENTS) = HALT_COP_WAIT_EVENT | HALT_COP_USEC | delay; + } +} + +void bpmp_msleep(u32 ms) +{ + u32 delay; + + // Iteration time is variable. ~200 - 1000us. + while (ms) + { + delay = (ms > HALT_COP_MAX_CNT) ? HALT_COP_MAX_CNT : ms; + ms -= delay; + + FLOW_CTLR(FLOW_CTLR_HALT_COP_EVENTS) = HALT_COP_WAIT_EVENT | HALT_COP_MSEC | delay; + } +} + +void bpmp_halt() +{ + FLOW_CTLR(FLOW_CTLR_HALT_COP_EVENTS) = HALT_COP_WAIT_EVENT | HALT_COP_JTAG; +} diff --git a/source/soc/bpmp.h b/source/soc/bpmp.h new file mode 100644 index 0000000..4c1155e --- /dev/null +++ b/source/soc/bpmp.h @@ -0,0 +1,57 @@ +/* + * BPMP-Lite Cache/MMU and Frequency driver for Tegra X1 + * + * 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 _BPMP_H_ +#define _BPMP_H_ + +#include "../utils/types.h" + +#define BPMP_MMU_MAINT_CLEAN_WAY 17 +#define BPMP_MMU_MAINT_INVALID_WAY 18 +#define BPMP_MMU_MAINT_CLN_INV_WAY 19 + +typedef struct _bpmp_mmu_entry_t +{ + u32 min_addr; + u32 max_addr; + u32 attr; + u32 enable; +} bpmp_mmu_entry_t; + +typedef enum +{ + BPMP_CLK_NORMAL, // 408MHz 0% - 136MHz APB. + BPMP_CLK_HIGH_BOOST, // 544MHz 33% - 136MHz APB. + BPMP_CLK_SUPER_BOOST, // 576MHz 41% - 144MHz APB. + BPMP_CLK_HYPER_BOOST, // 589MHz 44% - 147MHz APB. + //BPMP_CLK_DEV_BOOST, // 608MHz 49% - 152MHz APB. + BPMP_CLK_MAX +} bpmp_freq_t; + +#define BPMP_CLK_DEFAULT_BOOST BPMP_CLK_HYPER_BOOST + +void bpmp_mmu_maintenance(u32 op, bool force); +void bpmp_mmu_set_entry(int idx, bpmp_mmu_entry_t *entry, bool apply); +void bpmp_mmu_enable(); +void bpmp_mmu_disable(); +void bpmp_clk_rate_set(bpmp_freq_t fid); +void bpmp_usleep(u32 us); +void bpmp_msleep(u32 ms); +void bpmp_halt(); + +#endif diff --git a/source/soc/clock.c b/source/soc/clock.c index f712935..dda6d4b 100644 --- a/source/soc/clock.c +++ b/source/soc/clock.c @@ -22,57 +22,59 @@ /* clock_t: reset, enable, source, index, clk_src, clk_div */ static const clock_t _clock_uart[] = { -/* UART A */ { CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_UARTA, 6, 0, 0 }, -/* UART B */ { CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_UARTB, 7, 0, 0 }, -/* UART C */ { CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_RST_CONTROLLER_CLK_SOURCE_UARTC, 0x17, 0, 0 }, -/* UART D */ { 0 }, -/* UART E */ { 0 } +/* UART A */ { CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_UARTA, 6, 0, 2 }, +/* UART B */ { CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_UARTB, 7, 0, 2 }, +/* UART C */ { CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_RST_CONTROLLER_CLK_SOURCE_UARTC, 23, 0, 2 }, +/* UART D */ { CLK_RST_CONTROLLER_RST_DEVICES_U, CLK_RST_CONTROLLER_CLK_OUT_ENB_U, CLK_RST_CONTROLLER_CLK_SOURCE_UARTD, 1, 0, 2 }, +/* UART E */ { CLK_RST_CONTROLLER_RST_DEVICES_Y, CLK_RST_CONTROLLER_CLK_OUT_ENB_Y, CLK_RST_CONTROLLER_CLK_SOURCE_UARTAPE, 20, 0, 2 } }; +//I2C default parameters - TLOW: 4, THIGH: 2, DEBOUNCE: 0 FM_DIV: 26. static const clock_t _clock_i2c[] = { -/* I2C1 */ { CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_I2C1, 0xC, 6, 0 }, -/* I2C2 */ { 0 }, -/* I2C3 */ { 0 }, -/* I2C4 */ { 0 }, -/* I2C5 */ { CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_RST_CONTROLLER_CLK_SOURCE_I2C5, 0xF, 6, 0 }, -/* I2C6 */ { 0 } +/* I2C1 */ { CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_I2C1, 12, 0, 19 }, //20.4MHz -> 100KHz +/* I2C2 */ { CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_RST_CONTROLLER_CLK_SOURCE_I2C2, 22, 0, 4 }, //81.6MHz -> 400KHz +/* I2C3 */ { CLK_RST_CONTROLLER_RST_DEVICES_U, CLK_RST_CONTROLLER_CLK_OUT_ENB_U, CLK_RST_CONTROLLER_CLK_SOURCE_I2C3, 3, 0, 4 }, //81.6MHz -> 400KHz +/* I2C4 */ { CLK_RST_CONTROLLER_RST_DEVICES_V, CLK_RST_CONTROLLER_CLK_OUT_ENB_V, CLK_RST_CONTROLLER_CLK_SOURCE_I2C4, 7, 0, 19 }, //20.4MHz -> 100KHz +/* I2C5 */ { CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_RST_CONTROLLER_CLK_SOURCE_I2C5, 15, 0, 4 }, //81.6MHz -> 400KHz +/* I2C6 */ { CLK_RST_CONTROLLER_RST_DEVICES_X, CLK_RST_CONTROLLER_CLK_OUT_ENB_X, CLK_RST_CONTROLLER_CLK_SOURCE_I2C6, 6, 0, 19 } //20.4MHz -> 100KHz }; static clock_t _clock_se = { - CLK_RST_CONTROLLER_RST_DEVICES_V, CLK_RST_CONTROLLER_CLK_OUT_ENB_V, CLK_RST_CONTROLLER_CLK_SOURCE_SE, 0x1F, 0, 0 + CLK_RST_CONTROLLER_RST_DEVICES_V, CLK_RST_CONTROLLER_CLK_OUT_ENB_V, CLK_RST_CONTROLLER_CLK_SOURCE_SE, 31, 0, 0 }; -static clock_t _clock_unk2 = { - CLK_RST_CONTROLLER_RST_DEVICES_V, CLK_RST_CONTROLLER_CLK_OUT_ENB_V, CLK_NO_SOURCE, 0x1E, 0, 0 + +static clock_t _clock_tzram = { + CLK_RST_CONTROLLER_RST_DEVICES_V, CLK_RST_CONTROLLER_CLK_OUT_ENB_V, CLK_NO_SOURCE, 30, 0, 0 }; static clock_t _clock_host1x = { - CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_HOST1X, 0x1C, 4, 3 + CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_HOST1X, 28, 4, 3 }; static clock_t _clock_tsec = { - CLK_RST_CONTROLLER_RST_DEVICES_U, CLK_RST_CONTROLLER_CLK_OUT_ENB_U, CLK_RST_CONTROLLER_CLK_SOURCE_TSEC, 0x13, 0, 2 + CLK_RST_CONTROLLER_RST_DEVICES_U, CLK_RST_CONTROLLER_CLK_OUT_ENB_U, CLK_RST_CONTROLLER_CLK_SOURCE_TSEC, 19, 0, 2 }; static clock_t _clock_sor_safe = { - CLK_RST_CONTROLLER_RST_DEVICES_Y, CLK_RST_CONTROLLER_CLK_OUT_ENB_Y, CLK_NO_SOURCE, 0x1E, 0, 0 + CLK_RST_CONTROLLER_RST_DEVICES_Y, CLK_RST_CONTROLLER_CLK_OUT_ENB_Y, CLK_NO_SOURCE, 30, 0, 0 }; static clock_t _clock_sor0 = { - CLK_RST_CONTROLLER_RST_DEVICES_X, CLK_RST_CONTROLLER_CLK_OUT_ENB_X, CLK_NO_SOURCE, 0x16, 0, 0 + CLK_RST_CONTROLLER_RST_DEVICES_X, CLK_RST_CONTROLLER_CLK_OUT_ENB_X, CLK_NO_SOURCE, 22, 0, 0 }; static clock_t _clock_sor1 = { - CLK_RST_CONTROLLER_RST_DEVICES_X, CLK_RST_CONTROLLER_CLK_OUT_ENB_X, CLK_RST_CONTROLLER_CLK_SOURCE_SOR1, 0x17, 0, 2 + CLK_RST_CONTROLLER_RST_DEVICES_X, CLK_RST_CONTROLLER_CLK_OUT_ENB_X, CLK_RST_CONTROLLER_CLK_SOURCE_SOR1, 23, 0, 2 }; static clock_t _clock_kfuse = { - CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_NO_SOURCE, 8, 0, 0 + CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_NO_SOURCE, 8, 0, 0 }; static clock_t _clock_cl_dvfs = { - CLK_RST_CONTROLLER_RST_DEVICES_W, CLK_RST_CONTROLLER_CLK_OUT_ENB_W, CLK_NO_SOURCE, 0x1B, 0, 0 + CLK_RST_CONTROLLER_RST_DEVICES_W, CLK_RST_CONTROLLER_CLK_OUT_ENB_W, CLK_NO_SOURCE, 27, 0, 0 }; static clock_t _clock_coresight = { - CLK_RST_CONTROLLER_RST_DEVICES_U, CLK_RST_CONTROLLER_CLK_OUT_ENB_U, CLK_RST_CONTROLLER_CLK_SOURCE_CSITE, 9, 0, 4 + CLK_RST_CONTROLLER_RST_DEVICES_U, CLK_RST_CONTROLLER_CLK_OUT_ENB_U, CLK_RST_CONTROLLER_CLK_SOURCE_CSITE, 9, 0, 4 }; static clock_t _clock_pwm = { - CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_PWM, 0x11, 6, 4 + CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_PWM, 17, 6, 4 // Fref: 6.2MHz. }; void clock_enable(const clock_t *clk) @@ -86,6 +88,8 @@ void clock_enable(const clock_t *clk) CLOCK(clk->source) = clk->clk_div | (clk->clk_src << 29); // Enable. CLOCK(clk->enable) = (CLOCK(clk->enable) & ~(1 << clk->index)) | (1 << clk->index); + usleep(2); + // Take clock off reset. CLOCK(clk->reset) &= ~(1 << clk->index); } @@ -123,9 +127,9 @@ void clock_enable_se() clock_enable(&_clock_se); } -void clock_enable_unk2() +void clock_enable_tzram() { - clock_enable(&_clock_unk2); + clock_enable(&_clock_tzram); } void clock_enable_host1x() @@ -365,54 +369,55 @@ static void _clock_sdmmc_clear_enable(u32 id) static u32 _clock_sdmmc_table[8] = { 0 }; #define PLLP_OUT0 0x0 - -static int _clock_sdmmc_config_clock_source_inner(u32 *pout, u32 id, u32 val) +static int _clock_sdmmc_config_clock_host(u32 *pout, u32 id, u32 val) { u32 divisor = 0; u32 source = PLLP_OUT0; + // Get IO clock divisor. switch (val) { case 25000: *pout = 24728; - divisor = 31; + divisor = 31; // 16.5 div. break; case 26000: *pout = 25500; - divisor = 30; + divisor = 30; // 16 div. break; case 40800: *pout = 40800; - divisor = 18; + divisor = 18; // 10 div. break; case 50000: *pout = 48000; - divisor = 15; + divisor = 15; // 8.5 div. break; case 52000: *pout = 51000; - divisor = 14; + divisor = 14; // 8 div. break; case 100000: *pout = 90667; - divisor = 7; + divisor = 7; // 4.5 div. break; case 200000: *pout = 163200; - divisor = 3; + divisor = 3; // 2.5 div. break; case 208000: *pout = 204000; - divisor = 2; + divisor = 2; // 2 div. break; default: *pout = 24728; - divisor = 31; + divisor = 31; // 16.5 div. } _clock_sdmmc_table[2 * id] = val; _clock_sdmmc_table[2 * id + 1] = *pout; + // Set SDMMC clock. switch (id) { case SDMMC_1: @@ -443,15 +448,16 @@ void clock_sdmmc_config_clock_source(u32 *pout, u32 id, u32 val) int is_enabled = _clock_sdmmc_is_enabled(id); if (is_enabled) _clock_sdmmc_clear_enable(id); - _clock_sdmmc_config_clock_source_inner(pout, id, val); + _clock_sdmmc_config_clock_host(pout, id, val); if (is_enabled) _clock_sdmmc_set_enable(id); _clock_sdmmc_is_reset(id); } } -void clock_sdmmc_get_params(u32 *pout, u16 *pdivisor, u32 type) +void clock_sdmmc_get_card_clock_div(u32 *pout, u16 *pdivisor, u32 type) { + // Get Card clock divisor. switch (type) { case 0: @@ -512,7 +518,7 @@ void clock_sdmmc_enable(u32 id, u32 val) if (_clock_sdmmc_is_enabled(id)) _clock_sdmmc_clear_enable(id); _clock_sdmmc_set_reset(id); - _clock_sdmmc_config_clock_source_inner(&div, id, val); + _clock_sdmmc_config_clock_host(&div, id, val); _clock_sdmmc_set_enable(id); _clock_sdmmc_is_reset(id); usleep((100000 + div - 1) / div); diff --git a/source/soc/clock.h b/source/soc/clock.h index 8e36069..ce6a81d 100644 --- a/source/soc/clock.h +++ b/source/soc/clock.h @@ -41,6 +41,8 @@ #define CLK_RST_CONTROLLER_PLLM_MISC2 0x9C #define CLK_RST_CONTROLLER_PLLP_BASE 0xA0 #define CLK_RST_CONTROLLER_PLLD_BASE 0xD0 +#define CLK_RST_CONTROLLER_PLLD_MISC1 0xD8 +#define CLK_RST_CONTROLLER_PLLD_MISC 0xDC #define CLK_RST_CONTROLLER_PLLX_BASE 0xE0 #define CLK_RST_CONTROLLER_PLLX_MISC 0xE4 #define CLK_RST_CONTROLLER_PLLE_BASE 0xE8 @@ -50,6 +52,7 @@ #define CLK_RST_CONTROLLER_CLK_SOURCE_PWM 0x110 #define CLK_RST_CONTROLLER_CLK_SOURCE_I2C1 0x124 #define CLK_RST_CONTROLLER_CLK_SOURCE_I2C5 0x128 +#define CLK_RST_CONTROLLER_CLK_SOURCE_DISP1 0x138 #define CLK_RST_CONTROLLER_CLK_SOURCE_VI 0x148 #define CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC1 0x150 #define CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC2 0x154 @@ -57,11 +60,13 @@ #define CLK_RST_CONTROLLER_CLK_SOURCE_UARTA 0x178 #define CLK_RST_CONTROLLER_CLK_SOURCE_UARTB 0x17C #define CLK_RST_CONTROLLER_CLK_SOURCE_HOST1X 0x180 +#define CLK_RST_CONTROLLER_CLK_SOURCE_I2C2 0x198 +#define CLK_RST_CONTROLLER_CLK_SOURCE_EMC 0x19C #define CLK_RST_CONTROLLER_CLK_SOURCE_UARTC 0x1A0 #define CLK_RST_CONTROLLER_CLK_SOURCE_I2C3 0x1B8 #define CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC3 0x1BC +#define CLK_RST_CONTROLLER_CLK_SOURCE_UARTD 0x1C0 #define CLK_RST_CONTROLLER_CLK_SOURCE_CSITE 0x1D4 -#define CLK_RST_CONTROLLER_CLK_SOURCE_EMC 0x19C #define CLK_RST_CONTROLLER_CLK_SOURCE_TSEC 0x1F4 #define CLK_RST_CONTROLLER_CLK_OUT_ENB_X 0x280 #define CLK_RST_CONTROLLER_CLK_ENB_X_SET 0x284 @@ -95,9 +100,13 @@ #define CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRC 0x3A0 #define CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRD 0x3A4 #define CLK_RST_CONTROLLER_CLK_SOURCE_MSELECT 0x3B4 +#define CLK_RST_CONTROLLER_CLK_SOURCE_I2C4 0x3C4 +#define CLK_RST_CONTROLLER_CLK_SOURCE_SYS 0x400 #define CLK_RST_CONTROLLER_CLK_SOURCE_SOR1 0x410 #define CLK_RST_CONTROLLER_CLK_SOURCE_SE 0x42C +#define CLK_RST_CONTROLLER_RST_DEV_V_CLR 0x434 #define CLK_RST_CONTROLLER_CLK_ENB_V_SET 0x440 +#define CLK_RST_CONTROLLER_CLK_ENB_V_CLR 0x444 #define CLK_RST_CONTROLLER_CLK_ENB_W_SET 0x448 #define CLK_RST_CONTROLLER_CLK_ENB_W_CLR 0x44C #define CLK_RST_CONTROLLER_RST_CPUG_CMPLX_SET 0x450 @@ -108,16 +117,30 @@ #define CLK_RST_CONTROLLER_PLLX_MISC_3 0x518 #define CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRE 0x554 #define CLK_RST_CONTROLLER_SPARE_REG0 0x55C +#define CLK_RST_CONTROLLER_PLLC4_BASE 0x5A4 +#define CLK_RST_CONTROLLER_PLLC4_MISC 0x5A8 +#define CLK_RST_CONTROLLER_PLLC4_OUT 0x5E4 #define CLK_RST_CONTROLLER_PLLMB_BASE 0x5E8 #define CLK_RST_CONTROLLER_CLK_SOURCE_DSIA_LP 0x620 +#define CLK_RST_CONTROLLER_CLK_SOURCE_I2C6 0x65C #define CLK_RST_CONTROLLER_CLK_SOURCE_EMC_DLL 0x664 -#define CLK_RST_CONTROLLER_CLK_SOURCE_UART_FST_MIP_CAL 0x66C +#define CLK_RST_CONTROLLER_CLK_SOURCE_UART_FST_MIPI_CAL 0x66C #define CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC_LEGACY_TM 0x694 #define CLK_RST_CONTROLLER_CLK_SOURCE_NVENC 0x6A0 #define CLK_RST_CONTROLLER_SE_SUPER_CLK_DIVIDER 0x704 +#define CLK_RST_CONTROLLER_CLK_SOURCE_UARTAPE 0x710 #define CLK_NO_SOURCE 0x0 +/*! PLL control and status bits */ +#define PLL_BASE_ENABLE (1 << 30) + +#define PLLC4_MISC_EN_LCKDET (1 << 30) +#define PLLC4_BASE_LOCK (1 << 27) +#define PLLC4_BASE_IDDQ (1 << 18) +#define PLLC4_OUT3_CLKEN (1 << 1) +#define PLLC4_OUT3_RSTN_CLR (1 << 0) + /*! Generic clock descriptor. */ typedef struct _clock_t { @@ -139,7 +162,7 @@ void clock_enable_uart(u32 idx); void clock_enable_i2c(u32 idx); void clock_disable_i2c(u32 idx); void clock_enable_se(); -void clock_enable_unk2(); +void clock_enable_tzram(); void clock_enable_host1x(); void clock_disable_host1x(); void clock_enable_tsec(); @@ -159,7 +182,7 @@ void clock_disable_coresight(); void clock_enable_pwm(); void clock_disable_pwm(); void clock_sdmmc_config_clock_source(u32 *pout, u32 id, u32 val); -void clock_sdmmc_get_params(u32 *pout, u16 *pdivisor, u32 type); +void clock_sdmmc_get_card_clock_div(u32 *pout, u16 *pdivisor, u32 type); int clock_sdmmc_is_not_reset_and_enabled(u32 id); void clock_sdmmc_enable(u32 id, u32 val); void clock_sdmmc_disable(u32 id); diff --git a/source/soc/cluster.c b/source/soc/cluster.c index 1976e11..79538ed 100644 --- a/source/soc/cluster.c +++ b/source/soc/cluster.c @@ -32,18 +32,21 @@ void _cluster_enable_power() // Enable cores power. // 1-3.x: MAX77621_NFSR_ENABLE. i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_CONTROL1_REG, - MAX77621_AD_ENABLE | MAX77621_NFSR_ENABLE | MAX77621_SNS_ENABLE); + MAX77621_AD_ENABLE | MAX77621_NFSR_ENABLE | MAX77621_SNS_ENABLE | MAX77621_RAMP_12mV_PER_US); // 1.0.0-3.x: MAX77621_T_JUNCTION_120 | MAX77621_CKKADV_TRIP_DISABLE | MAX77621_INDUCTOR_NOMINAL. i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_CONTROL2_REG, MAX77621_T_JUNCTION_120 | MAX77621_WDTMR_ENABLE | MAX77621_CKKADV_TRIP_75mV_PER_US| MAX77621_INDUCTOR_NOMINAL); - i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_VOUT_REG, MAX77621_VOUT_ENABLE | 0x37); - i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_VOUT_DVC_REG, MAX77621_VOUT_ENABLE | 0x37); + i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_VOUT_REG, MAX77621_VOUT_ENABLE | MAX77621_VOUT_0_95V); + i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_VOUT_DVC_REG, MAX77621_VOUT_ENABLE | MAX77621_VOUT_0_95V); } -int _cluster_pmc_enable_partition(u32 part, u32 toggle, bool enable) +int _cluster_pmc_enable_partition(u32 part, int enable) { - // Check if the partition has already been turned on. - if (enable && PMC(APBDEV_PMC_PWRGATE_STATUS) & part) + u32 part_mask = 1 << part; + u32 desired_state = enable << part; + + // Check if the partition has the state we want. + if ((PMC(APBDEV_PMC_PWRGATE_STATUS) & part_mask) == desired_state) return 1; u32 i = 5001; @@ -55,12 +58,13 @@ int _cluster_pmc_enable_partition(u32 part, u32 toggle, bool enable) return 0; } - PMC(APBDEV_PMC_PWRGATE_TOGGLE) = toggle | (enable ? 0x100 : 0); + // Toggle power gating. + PMC(APBDEV_PMC_PWRGATE_TOGGLE) = part | 0x100; i = 5001; while (i > 0) { - if (PMC(APBDEV_PMC_PWRGATE_STATUS) & part) + if ((PMC(APBDEV_PMC_PWRGATE_STATUS) & part_mask) == desired_state) break; usleep(1); i--; @@ -76,9 +80,9 @@ void cluster_boot_cpu0(u32 entry) _cluster_enable_power(); - if (!(CLOCK(CLK_RST_CONTROLLER_PLLX_BASE) & 0x40000000)) + if (!(CLOCK(CLK_RST_CONTROLLER_PLLX_BASE) & 0x40000000)) // PLLX_ENABLE. { - CLOCK(CLK_RST_CONTROLLER_PLLX_MISC_3) &= 0xFFFFFFF7; + CLOCK(CLK_RST_CONTROLLER_PLLX_MISC_3) &= 0xFFFFFFF7; // Disable IDDQ. usleep(2); CLOCK(CLK_RST_CONTROLLER_PLLX_BASE) = 0x80404E02; CLOCK(CLK_RST_CONTROLLER_PLLX_BASE) = 0x404E02; @@ -103,11 +107,11 @@ void cluster_boot_cpu0(u32 entry) CLOCK(CLK_RST_CONTROLLER_CPU_SOFTRST_CTRL2) &= 0xFFFFF000; // Enable CPU rail. - _cluster_pmc_enable_partition(1, 0, true); + _cluster_pmc_enable_partition(0, 1); // Enable cluster 0 non-CPU. - _cluster_pmc_enable_partition(0x8000, 15, true); + _cluster_pmc_enable_partition(15, 1); // Enable CE0. - _cluster_pmc_enable_partition(0x4000, 14, true); + _cluster_pmc_enable_partition(14, 1); // Request and wait for RAM repair. FLOW_CTLR(FLOW_CTLR_RAM_REPAIR) = 1; @@ -117,12 +121,15 @@ void cluster_boot_cpu0(u32 entry) EXCP_VEC(EVP_CPU_RESET_VECTOR) = 0; // Set reset vector. - SB(SB_AA64_RESET_LOW) = entry | 1; + SB(SB_AA64_RESET_LOW) = entry | SB_AA64_RST_AARCH64_MODE_EN; SB(SB_AA64_RESET_HIGH) = 0; // Non-secure reset vector write disable. - SB(SB_CSR) = 2; + SB(SB_CSR) = SB_CSR_NS_RST_VEC_WR_DIS; (void)SB(SB_CSR); + // Tighten up the security aperture. + // MC(MC_TZ_SECURITY_CTRL) = 1; + // Clear MSELECT reset. CLOCK(CLK_RST_CONTROLLER_RST_DEVICES_V) &= 0xFFFFFFF7; // Clear NONCPU reset. diff --git a/source/soc/cluster.h b/source/soc/cluster.h index 5cecd19..428c046 100644 --- a/source/soc/cluster.h +++ b/source/soc/cluster.h @@ -19,19 +19,6 @@ #include "../utils/types.h" -/*! Flow controller registers. */ -#define FLOW_CTLR_HALT_CPU0_EVENTS 0x0 -#define FLOW_CTLR_HALT_CPU1_EVENTS 0x14 -#define FLOW_CTLR_HALT_CPU2_EVENTS 0x1C -#define FLOW_CTLR_HALT_CPU3_EVENTS 0x24 -#define FLOW_CTLR_HALT_COP_EVENTS 0x4 -#define FLOW_CTLR_CPU0_CSR 0x8 -#define FLOW_CTLR_CPU1_CSR 0x18 -#define FLOW_CTLR_CPU2_CSR 0x20 -#define FLOW_CTLR_CPU3_CSR 0x28 -#define FLOW_CTLR_RAM_REPAIR 0x40 -#define FLOW_CTLR_BPMP_CLUSTER_CONTROL 0x98 - void cluster_boot_cpu0(u32 entry); #endif diff --git a/source/soc/fuse.c b/source/soc/fuse.c index c53389e..04d3612 100644 --- a/source/soc/fuse.c +++ b/source/soc/fuse.c @@ -22,6 +22,34 @@ #include "../soc/fuse.h" #include "../soc/t210.h" +#define ARRAYSIZE(x) (sizeof(x) / sizeof(*x)) + +static const u32 evp_thunk_template[] = { + 0xe92d0007, // STMFD SP!, {R0-R2} + 0xe1a0200e, // MOV R2, LR + 0xe2422002, // SUB R2, R2, #2 + 0xe5922000, // LDR R2, [R2] + 0xe20220ff, // AND R2, R2, #0xFF + 0xe1a02082, // MOV R2, R2,LSL#1 + 0xe59f001c, // LDR R0, =evp_thunk_template + 0xe59f101c, // LDR R1, =thunk_end + 0xe0411000, // SUB R1, R1, R0 + 0xe59f0018, // LDR R0, =iram_evp_thunks + 0xe0800001, // ADD R0, R0, R1 + 0xe0822000, // ADD R2, R2, R0 + 0xe3822001, // ORR R2, R2, #1 + 0xe8bd0003, // LDMFD SP!, {R0,R1} + 0xe12fff12, // BX R2 + 0x001007b0, // off_1007EC DCD evp_thunk_template + 0x001007f8, // off_1007F0 DCD thunk_end + 0x40004c30, // off_1007F4 DCD iram_evp_thunks + // thunk_end is here +}; +static const u32 evp_thunk_template_len = sizeof(evp_thunk_template); + +// treated as 12bit values +static const u32 hash_vals[] = {1, 2, 4, 8, 0, 3, 5, 6, 7, 9, 10, 11}; + void fuse_disable_program() { FUSE(FUSE_DISABLEREGPROGRAM) = 1; @@ -31,3 +59,291 @@ u32 fuse_read_odm(u32 idx) { return FUSE(FUSE_RESERVED_ODMX(idx)); } + +void fuse_wait_idle() +{ + u32 ctrl; + do + { + ctrl = FUSE(FUSE_CTRL); + } while (((ctrl >> 16) & 0x1f) != 4); +} + +u32 fuse_read(u32 addr) +{ + FUSE(FUSE_ADDR) = addr; + FUSE(FUSE_CTRL) = (FUSE(FUSE_ADDR) & ~FUSE_CMD_MASK) | FUSE_READ; + fuse_wait_idle(); + return FUSE(FUSE_RDATA); +} + +void fuse_read_array(u32 *words) +{ + for (u32 i = 0; i < 192; i++) + words[i] = fuse_read(i); +} + +static u32 _parity32_even(u32 *words, u32 count) +{ + u32 acc = words[0]; + for (u32 i = 1; i < count; i++) + { + acc ^= words[i]; + } + u32 lo = ((acc & 0xffff) ^ (acc >> 16)) & 0xff; + u32 hi = ((acc & 0xffff) ^ (acc >> 16)) >> 8; + u32 x = hi ^ lo; + lo = ((x & 0xf) ^ (x >> 4)) & 3; + hi = ((x & 0xf) ^ (x >> 4)) >> 2; + x = hi ^ lo; + + return (x & 1) ^ (x >> 1); +} + +static int _patch_hash_one(u32 *word) +{ + u32 bits20_31 = *word & 0xfff00000; + u32 parity_bit = _parity32_even(&bits20_31, 1); + u32 hash = 0; + for (u32 i = 0; i < 12; i++) + { + if (*word & (1 << (20 + i))) + { + hash ^= hash_vals[i]; + } + } + if (hash == 0) + { + if (parity_bit == 0) + { + return 0; + } + *word ^= 1 << 24; + return 1; + } + if (parity_bit == 0) + { + return 3; + } + for (u32 i = 0; i < ARRAYSIZE(hash_vals); i++) + { + if (hash_vals[i] == hash) + { + *word ^= 1 << (20 + i); + return 1; + } + } + return 2; +} + +static int _patch_hash_multi(u32 *words, u32 count) +{ + u32 parity_bit = _parity32_even(words, count); + u32 bits0_14 = words[0] & 0x7fff; + u32 bit15 = words[0] & 0x8000; + u32 bits16_19 = words[0] & 0xf0000; + + u32 hash = 0; + words[0] = bits16_19; + for (u32 i = 0; i < count; i++) + { + u32 w = words[i]; + if (w) + { + for (u32 bitpos = 0; bitpos < 32; bitpos++) + { + if ((w >> bitpos) & 1) + { + hash ^= 0x4000 + i * 32 + bitpos; + } + } + } + } + hash ^= bits0_14; + // stupid but this is what original code does. + // equivalent to original words[0] &= 0xfff00000 + words[0] = bits16_19 ^ bit15 ^ bits0_14; + + if (hash == 0) + { + if (parity_bit == 0) + { + return 0; + } + words[0] ^= 0x8000; + return 1; + } + if (parity_bit == 0) + { + return 3; + } + u32 bitcount = hash - 0x4000; + if (bitcount < 16 || bitcount >= count * 32) + { + u32 num_set = 0; + for (u32 bitpos = 0; bitpos < 15; bitpos++) + { + if ((hash >> bitpos) & 1) + { + num_set++; + } + } + if (num_set != 1) + { + return 2; + } + words[0] ^= hash; + return 1; + } + words[bitcount / 32] ^= 1 << (hash & 0x1f); + return 1; +} + +int fuse_read_ipatch(void (*ipatch)(u32 offset, u32 value)) +{ + u32 words[80]; + u32 word_count; + u32 word_addr; + u32 word0 = 0; + u32 total_read = 0; + + word_count = FUSE(FUSE_FIRST_BOOTROM_PATCH_SIZE); + word_count &= 0x7F; + word_addr = 191; + + while (word_count) + { + total_read += word_count; + if (total_read >= ARRAYSIZE(words)) + { + break; + } + + for (u32 i = 0; i < word_count; i++) + words[i] = fuse_read(word_addr--); + + word0 = words[0]; + if (_patch_hash_multi(words, word_count) >= 2) + { + return 1; + } + u32 ipatch_count = (words[0] >> 16) & 0xF; + if (ipatch_count) + { + for (u32 i = 0; i < ipatch_count; i++) + { + u32 word = words[i + 1]; + u32 addr = (word >> 16) * 2; + u32 data = word & 0xFFFF; + + ipatch(addr, data); + } + } + words[0] = word0; + if ((word0 >> 25) == 0) + break; + if (_patch_hash_one(&word0) >= 2) + { + return 3; + } + word_count = word0 >> 25; + } + + return 0; +} + +int fuse_read_evp_thunk(u32 *iram_evp_thunks, u32 *iram_evp_thunks_len) +{ + u32 words[80]; + u32 word_count; + u32 word_addr; + u32 word0 = 0; + u32 total_read = 0; + int evp_thunk_written = 0; + void *evp_thunk_dst_addr = 0; + + memset(iram_evp_thunks, 0, *iram_evp_thunks_len); + + word_count = FUSE(FUSE_FIRST_BOOTROM_PATCH_SIZE); + word_count &= 0x7F; + word_addr = 191; + + while (word_count) + { + total_read += word_count; + if (total_read >= ARRAYSIZE(words)) + { + break; + } + + for (u32 i = 0; i < word_count; i++) + words[i] = fuse_read(word_addr--); + + word0 = words[0]; + if (_patch_hash_multi(words, word_count) >= 2) + { + return 1; + } + u32 ipatch_count = (words[0] >> 16) & 0xF; + u32 insn_count = word_count - ipatch_count - 1; + if (insn_count) + { + if (!evp_thunk_written) + { + evp_thunk_dst_addr = (void *)iram_evp_thunks; + + memcpy(evp_thunk_dst_addr, (void *)evp_thunk_template, evp_thunk_template_len); + evp_thunk_dst_addr += evp_thunk_template_len; + evp_thunk_written = 1; + *iram_evp_thunks_len = evp_thunk_template_len; + + //write32(TEGRA_EXCEPTION_VECTORS_BASE + 0x208, iram_evp_thunks); + } + + u32 thunk_patch_len = insn_count * sizeof(u32); + memcpy(evp_thunk_dst_addr, &words[ipatch_count + 1], thunk_patch_len); + evp_thunk_dst_addr += thunk_patch_len; + *iram_evp_thunks_len += thunk_patch_len; + } + words[0] = word0; + if ((word0 >> 25) == 0) + break; + if (_patch_hash_one(&word0) >= 2) + { + return 3; + } + word_count = word0 >> 25; + } + + return 0; +} + +bool fuse_check_patched_rcm() +{ + // Check if XUSB in use. + if (FUSE(FUSE_RESERVED_SW) & (1<<7)) + return true; + + // Check if RCM is ipatched. + u32 word_count = FUSE(FUSE_FIRST_BOOTROM_PATCH_SIZE) & 0x7F; + u32 word_addr = 191; + + while (word_count) + { + u32 word0 = fuse_read(word_addr); + u32 ipatch_count = (word0 >> 16) & 0xF; + + for (u32 i = 0; i < ipatch_count; i++) + { + u32 word = fuse_read(word_addr - (i + 1)); + u32 addr = (word >> 16) * 2; + if (addr == 0x769A) + return true; + } + + word_addr -= word_count; + word_count = word0 >> 25; + } + + return false; +} diff --git a/source/soc/fuse.h b/source/soc/fuse.h index 191f18a..9240b04 100644 --- a/source/soc/fuse.h +++ b/source/soc/fuse.h @@ -37,12 +37,32 @@ #define FUSE_WRITE_ACCESS_SW 0x30 #define FUSE_PWR_GOOD_SW 0x34 #define FUSE_SKU_INFO 0x110 +#define FUSE_CPU_SPEEDO_0_CALIB 0x114 +#define FUSE_CPU_IDDQ_CALIB 0x118 +#define FUSE_OPT_FT_REV 0x128 +#define FUSE_CPU_SPEEDO_1_CALIB 0x12C +#define FUSE_CPU_SPEEDO_2_CALIB 0x130 +#define FUSE_SOC_SPEEDO_0_CALIB 0x134 +#define FUSE_SOC_SPEEDO_1_CALIB 0x138 +#define FUSE_SOC_SPEEDO_2_CALIB 0x13C +#define FUSE_SOC_IDDQ_CALIB 0x140 +#define FUSE_OPT_CP_REV 0x190 #define FUSE_FIRST_BOOTROM_PATCH_SIZE 0x19c #define FUSE_PRIVATE_KEY0 0x1A4 #define FUSE_PRIVATE_KEY1 0x1A8 #define FUSE_PRIVATE_KEY2 0x1AC #define FUSE_PRIVATE_KEY3 0x1B0 +#define FUSE_PRIVATE_KEY4 0x1B4 #define FUSE_RESERVED_SW 0x1C0 +#define FUSE_SKU_DIRECT_CONFIG 0x1F4 +#define FUSE_OPT_VENDOR_CODE 0x200 +#define FUSE_OPT_FAB_CODE 0x204 +#define FUSE_OPT_LOT_CODE_0 0x208 +#define FUSE_OPT_LOT_CODE_1 0x20C +#define FUSE_OPT_WAFER_ID 0x210 +#define FUSE_OPT_X_COORDINATE 0x214 +#define FUSE_OPT_Y_COORDINATE 0x218 +#define FUSE_GPU_IDDQ_CALIB 0x228 /*! Fuse commands. */ #define FUSE_READ 0x1 @@ -55,5 +75,10 @@ void fuse_disable_program(); u32 fuse_read_odm(u32 idx); +void fuse_wait_idle(); +int fuse_read_ipatch(void (*ipatch)(u32 offset, u32 value)); +int fuse_read_evp_thunk(u32 *iram_evp_thunks, u32 *iram_evp_thunks_len); +void fuse_read_array(u32 *words); +bool fuse_check_patched_rcm(); #endif diff --git a/source/soc/hw_init.c b/source/soc/hw_init.c index 294505f..9f0e900 100644 --- a/source/soc/hw_init.c +++ b/source/soc/hw_init.c @@ -18,6 +18,7 @@ #include #include "hw_init.h" +#include "bpmp.h" #include "clock.h" #include "fuse.h" #include "gpio.h" @@ -27,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" @@ -38,22 +40,36 @@ extern sdmmc_t sd_sdmmc; extern boot_cfg_t b_cfg; +/* + * CLK_OSC - 38.4 MHz crystal. + * CLK_M - 19.2 MHz (osc/2). + * CLK_S - 32.768 KHz (from PMIC). + * SCLK - 204MHz init (-> 408MHz -> OC). + * HCLK - 204MHz init (-> 408MHz -> OC). + * PCLK - 68MHz init (-> 136MHz -> OC/4). + */ + void _config_oscillators() { - CLOCK(CLK_RST_CONTROLLER_SPARE_REG0) = (CLOCK(CLK_RST_CONTROLLER_SPARE_REG0) & 0xFFFFFFF3) | 4; - SYSCTR0(SYSCTR0_CNTFID0) = 19200000; - TMR(TIMERUS_USEC_CFG) = 0x45F; // For 19.2MHz clk_m. - CLOCK(CLK_RST_CONTROLLER_OSC_CTRL) = 0x50000071; - PMC(APBDEV_PMC_OSC_EDPD_OVER) = (PMC(APBDEV_PMC_OSC_EDPD_OVER) & 0xFFFFFF81) | 0xE; - PMC(APBDEV_PMC_OSC_EDPD_OVER) = (PMC(APBDEV_PMC_OSC_EDPD_OVER) & 0xFFBFFFFF) | 0x400000; - PMC(APBDEV_PMC_CNTRL2) = (PMC(APBDEV_PMC_CNTRL2) & 0xFFFFEFFF) | 0x1000; - PMC(APBDEV_PMC_SCRATCH188) = (PMC(APBDEV_PMC_SCRATCH188) & 0xFCFFFFFF) | 0x2000000; - CLOCK(CLK_RST_CONTROLLER_CLK_SYSTEM_RATE) = 0x10; - CLOCK(CLK_RST_CONTROLLER_PLLMB_BASE) &= 0xBFFFFFFF; + CLOCK(CLK_RST_CONTROLLER_SPARE_REG0) = (CLOCK(CLK_RST_CONTROLLER_SPARE_REG0) & 0xFFFFFFF3) | 4; // Set CLK_M_DIVISOR to 2. + SYSCTR0(SYSCTR0_CNTFID0) = 19200000; // Set counter frequency. + TMR(TIMERUS_USEC_CFG) = 0x45F; // For 19.2MHz clk_m. + CLOCK(CLK_RST_CONTROLLER_OSC_CTRL) = 0x50000071; // Set OSC to 38.4MHz and drive strength. + + PMC(APBDEV_PMC_OSC_EDPD_OVER) = (PMC(APBDEV_PMC_OSC_EDPD_OVER) & 0xFFFFFF81) | 0xE; // Set LP0 OSC drive strength. + PMC(APBDEV_PMC_OSC_EDPD_OVER) = (PMC(APBDEV_PMC_OSC_EDPD_OVER) & 0xFFBFFFFF) | PMC_OSC_EDPD_OVER_OSC_CTRL_OVER; + PMC(APBDEV_PMC_CNTRL2) = (PMC(APBDEV_PMC_CNTRL2) & 0xFFFFEFFF) | PMC_CNTRL2_HOLD_CKE_LOW_EN; + PMC(APBDEV_PMC_SCRATCH188) = (PMC(APBDEV_PMC_SCRATCH188) & 0xFCFFFFFF) | (4 << 23); // LP0 EMC2TMC_CFG_XM2COMP_PU_VREF_SEL_RANGE. + + CLOCK(CLK_RST_CONTROLLER_CLK_SYSTEM_RATE) = 0x10; // Set HCLK div to 2 and PCLK div to 1. + CLOCK(CLK_RST_CONTROLLER_PLLMB_BASE) &= 0xBFFFFFFF; // PLLMB disable. + PMC(APBDEV_PMC_TSC_MULT) = (PMC(APBDEV_PMC_TSC_MULT) & 0xFFFF0000) | 0x249F; //0x249F = 19200000 * (16 / 32.768 kHz) - CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = 0x20004444; - CLOCK(CLK_RST_CONTROLLER_SUPER_SCLK_DIVIDER) = 0x80000000; - CLOCK(CLK_RST_CONTROLLER_CLK_SYSTEM_RATE) = 2; + + CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SYS) = 0; // Set SCLK div to 1. + CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = 0x20004444; // Set clk source to Run and PLLP_OUT2 (204MHz). + CLOCK(CLK_RST_CONTROLLER_SUPER_SCLK_DIVIDER) = 0x80000000; // Enable SUPER_SDIV to 1. + CLOCK(CLK_RST_CONTROLLER_CLK_SYSTEM_RATE) = 2; // Set HCLK div to 1 and PCLK div to 3. } void _config_gpios() @@ -61,11 +77,22 @@ void _config_gpios() PINMUX_AUX(PINMUX_AUX_UART2_TX) = 0; PINMUX_AUX(PINMUX_AUX_UART3_TX) = 0; + // Set Joy-Con IsAttached direction. PINMUX_AUX(PINMUX_AUX_GPIO_PE6) = PINMUX_INPUT_ENABLE; PINMUX_AUX(PINMUX_AUX_GPIO_PH6) = PINMUX_INPUT_ENABLE; + // Set pin mode for Joy-Con IsAttached and UARTB/C TX pins. +#if !defined (DEBUG_UART_PORT) || DEBUG_UART_PORT != UART_B + gpio_config(GPIO_PORT_G, GPIO_PIN_0, GPIO_MODE_GPIO); +#endif +#if !defined (DEBUG_UART_PORT) || DEBUG_UART_PORT != UART_C + gpio_config(GPIO_PORT_D, GPIO_PIN_1, GPIO_MODE_GPIO); +#endif + // Set Joy-Con IsAttached mode. gpio_config(GPIO_PORT_E, GPIO_PIN_6, GPIO_MODE_GPIO); gpio_config(GPIO_PORT_H, GPIO_PIN_6, GPIO_MODE_GPIO); + + // Enable input logic for Joy-Con IsAttached and UARTB/C TX pins. gpio_output_enable(GPIO_PORT_G, GPIO_PIN_0, GPIO_OUTPUT_DISABLE); gpio_output_enable(GPIO_PORT_D, GPIO_PIN_1, GPIO_OUTPUT_DISABLE); gpio_output_enable(GPIO_PORT_E, GPIO_PIN_6, GPIO_OUTPUT_DISABLE); @@ -80,27 +107,36 @@ void _config_gpios() gpio_config(GPIO_PORT_X, GPIO_PIN_7, GPIO_MODE_GPIO); gpio_output_enable(GPIO_PORT_X, GPIO_PIN_6, GPIO_OUTPUT_DISABLE); gpio_output_enable(GPIO_PORT_X, GPIO_PIN_7, GPIO_OUTPUT_DISABLE); + + // Configure HOME as inputs. + // PINMUX_AUX(PINMUX_AUX_BUTTON_HOME) = PINMUX_PULL_UP | PINMUX_INPUT_ENABLE; + // gpio_config(GPIO_PORT_Y, GPIO_PIN_1, GPIO_MODE_GPIO); } void _config_pmc_scratch() { - PMC(APBDEV_PMC_SCRATCH20) &= 0xFFF3FFFF; - PMC(APBDEV_PMC_SCRATCH190) &= 0xFFFFFFFE; - PMC(APBDEV_PMC_SECURE_SCRATCH21) |= 0x10; + PMC(APBDEV_PMC_SCRATCH20) &= 0xFFF3FFFF; // Unset Debug console from Customer Option. + PMC(APBDEV_PMC_SCRATCH190) &= 0xFFFFFFFE; // Unset DATA_DQ_E_IVREF EMC_PMACRO_DATA_PAD_TX_CTRL + PMC(APBDEV_PMC_SECURE_SCRATCH21) |= PMC_FUSE_PRIVATEKEYDISABLE_TZ_STICKY_BIT; } void _mbist_workaround() { CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_V) |= (1 << 10); // Enable AHUB clock. - CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_Y) |= (1 << 6); // Enable APE clock. + CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_Y) |= (1 << 6); // Enable APE clock. + // Set mux output to SOR1 clock switch. CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SOR1) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SOR1) | 0x8000) & 0xFFFFBFFF; - CLOCK(CLK_RST_CONTROLLER_PLLD_BASE) |= 0x40800000u; - CLOCK(CLK_RST_CONTROLLER_RST_DEV_Y_CLR) = 0x40; - CLOCK(CLK_RST_CONTROLLER_RST_DEV_X_CLR) = 0x40000; - CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_CLR) = 0x18000000; + // Enabled PLLD and set csi to PLLD for test pattern generation. + CLOCK(CLK_RST_CONTROLLER_PLLD_BASE) |= 0x40800000; + + // Clear per-clock resets. + CLOCK(CLK_RST_CONTROLLER_RST_DEV_Y_CLR) = 0x40; // Clear reset APE. + CLOCK(CLK_RST_CONTROLLER_RST_DEV_X_CLR) = 0x40000; // Clear reset VIC. + CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_CLR) = 0x18000000; // Clear reset DISP1, HOST1X. usleep(2); + // I2S channels to master and disable SLCG. I2S(I2S1_CTRL) |= I2S_CTRL_MASTER_EN; I2S(I2S1_CG) &= ~I2S_CG_SLCG_ENABLE; I2S(I2S2_CTRL) |= I2S_CTRL_MASTER_EN; @@ -111,30 +147,39 @@ void _mbist_workaround() I2S(I2S4_CG) &= ~I2S_CG_SLCG_ENABLE; I2S(I2S5_CTRL) |= I2S_CTRL_MASTER_EN; I2S(I2S5_CG) &= ~I2S_CG_SLCG_ENABLE; - DISPLAY_A(_DIREG(DC_COM_DSC_TOP_CTL)) |= 4; + + DISPLAY_A(_DIREG(DC_COM_DSC_TOP_CTL)) |= 4; // DSC_SLCG_OVERRIDE. VIC(0x8C) = 0xFFFFFFFF; usleep(2); - CLOCK(CLK_RST_CONTROLLER_RST_DEV_Y_SET) = 0x40; - CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = 0x18000000; - CLOCK(CLK_RST_CONTROLLER_RST_DEV_X_SET) = 0x40000; - CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_H) = 0xC0; - CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_L) = 0x80000130; - CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_U) = 0x1F00200; - CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_V) = 0x80400808; - CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_W) = 0x402000FC; - CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_X) = 0x23000780; - CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_Y) = 0x300; + // Set per-clock reset. + CLOCK(CLK_RST_CONTROLLER_RST_DEV_Y_SET) = 0x40; // Set reset APE. + CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = 0x18000000; // Set reset DISP1, HOST1x. + CLOCK(CLK_RST_CONTROLLER_RST_DEV_X_SET) = 0x40000; // Set reset VIC. + + // Enable specific clocks and disable all others. + CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_H) = 0xC0; // Enable clock PMC, FUSE. + CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_L) = 0x80000130; // Enable clock RTC, TMR, GPIO, BPMP_CACHE. + //CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_L) = 0x80400130; // Keep USB data ON. + CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_U) = 0x1F00200; // Enable clock CSITE, IRAMA, IRAMB, IRAMC, IRAMD, BPMP_CACHE_RAM. + CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_V) = 0x80400808; // Enable clock MSELECT, APB2APE, SPDIF_DOUBLER, SE. + CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_W) = 0x402000FC; // Enable clock PCIERX0, PCIERX1, PCIERX2, PCIERX3, PCIERX4, PCIERX5, ENTROPY, MC1. + CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_X) = 0x23000780; // Enable clock MC_CAPA, MC_CAPB, MC_CPU, MC_BBC, DBGAPB, HPLL_ADSP, PLLG_REF. + CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_Y) = 0x300; // Enable clock MC_CDPA, MC_CCPA. + + // Disable clock gate overrides. CLOCK(CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRA) = 0; CLOCK(CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRB) = 0; CLOCK(CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRC) = 0; CLOCK(CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRD) = 0; CLOCK(CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRE) = 0; - CLOCK(CLK_RST_CONTROLLER_PLLD_BASE) &= 0x1F7FFFFF; - CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SOR1) &= 0xFFFF3FFF; - CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_VI) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_VI) & 0x1FFFFFFF) | 0x80000000; - CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_HOST1X) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_HOST1X) & 0x1FFFFFFF) | 0x80000000; - CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_NVENC) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_NVENC) & 0x1FFFFFFF) | 0x80000000; + + // Set child clock sources. + CLOCK(CLK_RST_CONTROLLER_PLLD_BASE) &= 0x1F7FFFFF; // Disable PLLD and set reference clock and csi clock. + CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SOR1) &= 0xFFFF3FFF; // Set SOR1 to automatic muxing of safe clock (24MHz) or SOR1 clk switch. + CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_VI) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_VI) & 0x1FFFFFFF) | 0x80000000; // Set clock source to PLLP_OUT. + CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_HOST1X) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_HOST1X) & 0x1FFFFFFF) | 0x80000000; // Set clock source to PLLP_OUT. + CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_NVENC) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_NVENC) & 0x1FFFFFFF) | 0x80000000; // Set clock source to PLLP_OUT. } void _config_se_brom() @@ -143,7 +188,7 @@ void _config_se_brom() if (!(b_cfg.boot_cfg & BOOT_CFG_SEPT_RUN)) { // Bootrom part we skipped. - u32 sbk[4] = { + u32 sbk[4] = { FUSE(FUSE_PRIVATE_KEY0), FUSE(FUSE_PRIVATE_KEY1), FUSE(FUSE_PRIVATE_KEY2), @@ -170,38 +215,8 @@ void _config_se_brom() APB_MISC(APB_MISC_PP_STRAPPING_OPT_A) = (APB_MISC(APB_MISC_PP_STRAPPING_OPT_A) & 0xF0) | (7 << 10); } -void config_hw() +void _config_regulators() { - // Bootrom stuff we skipped by going through rcm. - _config_se_brom(); - //FUSE(FUSE_PRIVATEKEYDISABLE) = 0x11; - SYSREG(AHB_AHB_SPARE_REG) &= 0xFFFFFF9F; - PMC(APBDEV_PMC_SCRATCH49) = ((PMC(APBDEV_PMC_SCRATCH49) >> 1) << 1) & 0xFFFFFFFD; - - _mbist_workaround(); - clock_enable_se(); - - // Enable fuse clock. - clock_enable_fuse(true); - // Disable fuse programming. - fuse_disable_program(); - - mc_enable(); - - _config_oscillators(); - APB_MISC(APB_MISC_PP_PINMUX_GLOBAL) = 0; - _config_gpios(); - - clock_enable_cl_dvfs(); - - clock_enable_i2c(I2C_1); - clock_enable_i2c(I2C_5); - - clock_enable_unk2(); - - i2c_init(I2C_1); - i2c_init(I2C_5); - i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_CNFGBBC, MAX77620_CNFGBBC_RESISTOR_1K); i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_ONOFFCNFG1, (1 << 6) | (3 << MAX77620_ONOFFCNFG1_MRT_SHIFT)); // PWR delay for forced shutdown off. @@ -221,25 +236,83 @@ void config_hw() i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_GPIO3, (4 << MAX77620_FPS_TIME_PERIOD_SHIFT) | (2 << MAX77620_FPS_PD_PERIOD_SHIFT)); // 3.x+ + // Set vdd_core voltage to 1.125V max77620_regulator_set_voltage(REGULATOR_SD0, 1125000); - // Fix GPU after warmboot for Linux. + // Fix CPU/GPU after a Linux warmboot. i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_GPIO5, 2); i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_GPIO6, 2); - // Disable low battery shutdown monitor. + i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_VOUT_REG, MAX77621_VOUT_0_95V); // Disable power. + i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_VOUT_DVC_REG, MAX77621_VOUT_ENABLE | MAX77621_VOUT_1_09V); // Enable DVS power. + i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_CONTROL1_REG, MAX77621_RAMP_50mV_PER_US); + i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_CONTROL2_REG, + MAX77621_T_JUNCTION_120 | MAX77621_FT_ENABLE | MAX77621_CKKADV_TRIP_75mV_PER_US_HIST_DIS | + MAX77621_CKKADV_TRIP_150mV_PER_US | MAX77621_INDUCTOR_NOMINAL); + + i2c_send_byte(I2C_5, MAX77621_GPU_I2C_ADDR, MAX77621_VOUT_REG, MAX77621_VOUT_0_95V); // Disable power. + i2c_send_byte(I2C_5, MAX77621_GPU_I2C_ADDR, MAX77621_VOUT_DVC_REG, MAX77621_VOUT_ENABLE | MAX77621_VOUT_1_09V); // Enable DVS power. + i2c_send_byte(I2C_5, MAX77621_GPU_I2C_ADDR, MAX77621_CONTROL1_REG, MAX77621_RAMP_50mV_PER_US); + i2c_send_byte(I2C_5, MAX77621_GPU_I2C_ADDR, MAX77621_CONTROL2_REG, + MAX77621_T_JUNCTION_120 | MAX77621_FT_ENABLE | MAX77621_CKKADV_TRIP_75mV_PER_US_HIST_DIS | + MAX77621_CKKADV_TRIP_150mV_PER_US | MAX77621_INDUCTOR_NOMINAL); + + // Enable low battery shutdown monitor for < 2800mV. max77620_low_battery_monitor_config(); +} + +void config_hw() +{ + // Bootrom stuff we skipped by going through rcm. + _config_se_brom(); + //FUSE(FUSE_PRIVATEKEYDISABLE) = 0x11; + SYSREG(AHB_AHB_SPARE_REG) &= 0xFFFFFF9F; // Unset APB2JTAG_OVERRIDE_EN and OBS_OVERRIDE_EN. + PMC(APBDEV_PMC_SCRATCH49) = PMC(APBDEV_PMC_SCRATCH49) & 0xFFFFFFFC; + + _mbist_workaround(); + clock_enable_se(); + + // Enable fuse clock. + clock_enable_fuse(true); + + // Disable fuse programming. + fuse_disable_program(); + + mc_enable(); + + _config_oscillators(); + APB_MISC(APB_MISC_PP_PINMUX_GLOBAL) = 0; + _config_gpios(); + + clock_enable_cl_dvfs(); + + clock_enable_i2c(I2C_1); + clock_enable_i2c(I2C_5); + + clock_enable_tzram(); + + i2c_init(I2C_1); + i2c_init(I2C_5); + + _config_regulators(); _config_pmc_scratch(); // Missing from 4.x+ - CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = (CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) & 0xFFFF8888) | 0x3333; + CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = 0x20003333; // Set SCLK to PLLP_OUT (408MHz). sdram_init(); + + bpmp_mmu_enable(); mc_enable_ahb_redirect(); } 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. CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_Y) |= (1 << 6); // Enable APE clock. diff --git a/source/soc/i2c.c b/source/soc/i2c.c index e845693..d06d64a 100644 --- a/source/soc/i2c.c +++ b/source/soc/i2c.c @@ -44,10 +44,10 @@ static int _i2c_send_pkt(u32 idx, u32 x, u8 *buf, u32 size) memcpy(&tmp, buf, size); vu32 *base = (vu32 *)i2c_addrs[idx]; - base[I2C_CMD_ADDR0] = x << 1; //Set x (send mode). - base[I2C_CMD_DATA1] = tmp; //Set value. - base[I2C_CNFG] = (2 * size - 2) | 0x2800; //Set size and send mode. - _i2c_wait(base); //Kick transaction. + base[I2C_CMD_ADDR0] = x << 1; //Set x (send mode). + base[I2C_CMD_DATA1] = tmp; //Set value. + base[I2C_CNFG] = ((size - 1) << 1) | 0x2800; //Set size and send mode. + _i2c_wait(base); //Kick transaction. base[I2C_CNFG] = (base[I2C_CNFG] & 0xFFFFFDFF) | 0x200; while (base[I2C_STATUS] & 0x100) @@ -65,9 +65,9 @@ static int _i2c_recv_pkt(u32 idx, u8 *buf, u32 size, u32 x) return 0; vu32 *base = (vu32 *)i2c_addrs[idx]; - base[I2C_CMD_ADDR0] = (x << 1) | 1; // Set x (recv mode). - base[I2C_CNFG] = (size - 1) << 1 | 0x2840; // Set size and recv mode. - _i2c_wait(base); // Kick transaction. + base[I2C_CMD_ADDR0] = (x << 1) | 1; // Set x (recv mode). + base[I2C_CNFG] = ((size - 1) << 1) | 0x2840; // Set size and recv mode. + _i2c_wait(base); // Kick transaction. base[I2C_CNFG] = (base[I2C_CNFG] & 0xFFFFFDFF) | 0x200; while (base[I2C_STATUS] & 0x100) diff --git a/source/soc/kfuse.c b/source/soc/kfuse.c new file mode 100644 index 0000000..f2fde5a --- /dev/null +++ b/source/soc/kfuse.c @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2018 naehrwert + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "../soc/kfuse.h" +#include "../soc/clock.h" +#include "../soc/t210.h" + +#pragma GCC push_options +#pragma GCC optimize ("Os") + +int kfuse_wait_ready() +{ + // Wait for KFUSE to finish init and verification of data. + while (!(KFUSE(KFUSE_STATE) & KFUSE_STATE_DONE)) + ; + + if (!(KFUSE(KFUSE_STATE) & KFUSE_STATE_CRCPASS)) + return 0; + + return 1; +} + +int kfuse_read(u32 *buf) +{ + int res = 0; + + clock_enable_kfuse(); + + if (!kfuse_wait_ready()) + goto out; + + KFUSE(KFUSE_KEYADDR) = KFUSE_KEYADDR_AUTOINC; + for (int i = 0; i < KFUSE_NUM_WORDS; i++) + buf[i] = KFUSE(KFUSE_KEYS); + + res = 1; + +out:; + clock_disable_kfuse(); + return res; +} + +#pragma GCC pop_options diff --git a/source/soc/kfuse.h b/source/soc/kfuse.h new file mode 100644 index 0000000..a535803 --- /dev/null +++ b/source/soc/kfuse.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2018 naehrwert + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef _KFUSE_H_ +#define _KFUSE_H_ + +#include "../utils/types.h" + +#define KFUSE_STATE_SOFTRESET (1 << 31) +#define KFUSE_STATE_STOP (1 << 25) +#define KFUSE_STATE_RESTART (1 << 24) +#define KFUSE_STATE_CRCPASS (1 << 17) +#define KFUSE_STATE_DONE (1 << 16) +#define KFUSE_STATE_ERRBLOCK_MASK 0x3F00 +#define KFUSE_STATE_ERRBLOCK_SHIFT 8 +#define KFUSE_STATE_CURBLOCK_MASK 0x3F + +#define KFUSE_KEYADDR_AUTOINC (1<<16) + +#define KFUSE_STATE 0x80 +#define KFUSE_KEYADDR 0x88 +#define KFUSE_KEYS 0x8C + +#define KFUSE_NUM_WORDS 144 + +int kfuse_wait_ready(); +int kfuse_read(u32 *buf); + +#endif diff --git a/source/soc/pinmux.h b/source/soc/pinmux.h index 26bab31..bb4ecb1 100644 --- a/source/soc/pinmux.h +++ b/source/soc/pinmux.h @@ -26,31 +26,50 @@ #define APB_MISC_GP_VGPIO_GPIO_MUX_SEL 0xB74 /*! Pinmux registers. */ -#define PINMUX_AUX_SDMMC1_CLK 0x00 -#define PINMUX_AUX_SDMMC1_CMD 0x04 -#define PINMUX_AUX_SDMMC1_DAT3 0x08 -#define PINMUX_AUX_SDMMC1_DAT2 0x0C -#define PINMUX_AUX_SDMMC1_DAT1 0x10 -#define PINMUX_AUX_SDMMC1_DAT0 0x14 -#define PINMUX_AUX_SDMMC3_CLK 0x1C -#define PINMUX_AUX_SDMMC3_CMD 0x20 -#define PINMUX_AUX_SDMMC3_DAT0 0x24 -#define PINMUX_AUX_SDMMC3_DAT1 0x28 -#define PINMUX_AUX_SDMMC3_DAT2 0x2C -#define PINMUX_AUX_SDMMC3_DAT3 0x30 -#define PINMUX_AUX_DMIC3_CLK 0xB4 -#define PINMUX_AUX_UART2_TX 0xF4 -#define PINMUX_AUX_UART3_TX 0x104 -#define PINMUX_AUX_WIFI_EN 0x1B4 -#define PINMUX_AUX_WIFI_RST 0x1B8 -#define PINMUX_AUX_NFC_EN 0x1D0 -#define PINMUX_AUX_NFC_INT 0x1D4 -#define PINMUX_AUX_LCD_BL_PWM 0x1FC -#define PINMUX_AUX_LCD_BL_EN 0x200 -#define PINMUX_AUX_LCD_RST 0x204 -#define PINMUX_AUX_GPIO_PE6 0x248 -#define PINMUX_AUX_GPIO_PH6 0x250 -#define PINMUX_AUX_GPIO_PZ1 0x280 +#define PINMUX_AUX_SDMMC1_CLK 0x00 +#define PINMUX_AUX_SDMMC1_CMD 0x04 +#define PINMUX_AUX_SDMMC1_DAT3 0x08 +#define PINMUX_AUX_SDMMC1_DAT2 0x0C +#define PINMUX_AUX_SDMMC1_DAT1 0x10 +#define PINMUX_AUX_SDMMC1_DAT0 0x14 +#define PINMUX_AUX_SDMMC3_CLK 0x1C +#define PINMUX_AUX_SDMMC3_CMD 0x20 +#define PINMUX_AUX_SDMMC3_DAT0 0x24 +#define PINMUX_AUX_SDMMC3_DAT1 0x28 +#define PINMUX_AUX_SDMMC3_DAT2 0x2C +#define PINMUX_AUX_SDMMC3_DAT3 0x30 +#define PINMUX_AUX_SATA_LED_ACTIVE 0x4C +#define PINMUX_AUX_DMIC3_CLK 0xB4 +#define PINMUX_AUX_DMIC3_DAT 0xB8 +#define PINMUX_AUX_CAM_I2C_SCL 0xD4 +#define PINMUX_AUX_CAM_I2C_SDA 0xD8 +#define PINMUX_AUX_UART2_TX 0xF4 +#define PINMUX_AUX_UART3_TX 0x104 +#define PINMUX_AUX_DAP4_DIN 0x148 +#define PINMUX_AUX_DAP4_SCLK 0x150 +#define PINMUX_AUX_GPIO_X1_AUD 0x18C +#define PINMUX_AUX_GPIO_X3_AUD 0x190 +#define PINMUX_AUX_SPDIF_IN 0x1A4 +#define PINMUX_AUX_USB_VBUS_EN0 0x1A8 +#define PINMUX_AUX_USB_VBUS_EN1 0x1AC +#define PINMUX_AUX_WIFI_EN 0x1B4 +#define PINMUX_AUX_WIFI_RST 0x1B8 +#define PINMUX_AUX_AP_WAKE_NFC 0x1CC +#define PINMUX_AUX_NFC_EN 0x1D0 +#define PINMUX_AUX_NFC_INT 0x1D4 +#define PINMUX_AUX_CAM1_PWDN 0x1EC +#define PINMUX_AUX_CAM2_PWDN 0x1F0 +#define PINMUX_AUX_LCD_BL_PWM 0x1FC +#define PINMUX_AUX_LCD_BL_EN 0x200 +#define PINMUX_AUX_LCD_RST 0x204 +#define PINMUX_AUX_LCD_GPIO2 0x20C +#define PINMUX_AUX_TOUCH_INT 0x220 +#define PINMUX_AUX_MOTION_INT 0x224 +#define PINMUX_AUX_BUTTON_HOME 0x240 +#define PINMUX_AUX_GPIO_PE6 0x248 +#define PINMUX_AUX_GPIO_PH6 0x250 +#define PINMUX_AUX_GPIO_PK3 0x260 +#define PINMUX_AUX_GPIO_PZ1 0x280 /*! 0:UART-A, 1:UART-B, 3:UART-C, 3:UART-D */ #define PINMUX_AUX_UARTX_TX(x) (0xE4 + 0x10 * (x)) #define PINMUX_AUX_UARTX_RX(x) (0xE8 + 0x10 * (x)) @@ -78,7 +97,7 @@ #define PINMUX_OPEN_DRAIN (1 << 11) #define PINMUX_SCHMT (1 << 12) -#define PINMUX_DRIVE_1X (0 << 13) +#define PINMUX_DRIVE_1X (0 << 13) #define PINMUX_DRIVE_2X (1 << 13) #define PINMUX_DRIVE_3X (2 << 13) #define PINMUX_DRIVE_4X (3 << 13) diff --git a/source/soc/pmc.h b/source/soc/pmc.h index ec8eb99..8cd9161 100644 --- a/source/soc/pmc.h +++ b/source/soc/pmc.h @@ -25,6 +25,7 @@ #define APBDEV_PMC_PWRGATE_TOGGLE 0x30 #define APBDEV_PMC_PWRGATE_STATUS 0x38 #define APBDEV_PMC_NO_IOPOWER 0x44 +#define PMC_NO_IOPOWER_SDMMC1_IO_EN (1 << 12) #define APBDEV_PMC_SCRATCH0 0x50 #define APBDEV_PMC_SCRATCH1 0x54 #define APBDEV_PMC_SCRATCH20 0xA0 @@ -37,6 +38,7 @@ #define APBDEV_PMC_SCRATCH33 0x120 #define APBDEV_PMC_SCRATCH40 0x13C #define APBDEV_PMC_OSC_EDPD_OVER 0x1A4 +#define PMC_OSC_EDPD_OVER_OSC_CTRL_OVER 0x400000 #define APBDEV_PMC_RST_STATUS 0x1B4 #define APBDEV_PMC_IO_DPD_REQ 0x1B8 #define APBDEV_PMC_IO_DPD2_REQ 0x1C0 @@ -51,9 +53,11 @@ #define APBDEV_PMC_REG_SHORT 0x2CC #define APBDEV_PMC_SEC_DISABLE3 0x2D8 #define APBDEV_PMC_SECURE_SCRATCH21 0x334 +#define PMC_FUSE_PRIVATEKEYDISABLE_TZ_STICKY_BIT 0x10 #define APBDEV_PMC_SECURE_SCRATCH32 0x360 #define APBDEV_PMC_SECURE_SCRATCH49 0x3A4 #define APBDEV_PMC_CNTRL2 0x440 +#define PMC_CNTRL2_HOLD_CKE_LOW_EN 0x1000 #define APBDEV_PMC_IO_DPD3_REQ 0x45C #define APBDEV_PMC_IO_DPD4_REQ 0x464 #define APBDEV_PMC_UTMIP_PAD_CFG1 0x4C4 diff --git a/source/soc/smmu.c b/source/soc/smmu.c index 5aceaa4..fb096d4 100644 --- a/source/soc/smmu.c +++ b/source/soc/smmu.c @@ -106,7 +106,7 @@ bool smmu_is_used() void smmu_exit() { - *(uint32_t *)(smmu_payload + 0x14) = _NOP(); + *(u32 *)(smmu_payload + 0x14) = _NOP(); } u32 *smmu_init_domain4(u32 dev_base, u32 asid) diff --git a/source/soc/t210.h b/source/soc/t210.h index 1b11d72..85e42f4 100644 --- a/source/soc/t210.h +++ b/source/soc/t210.h @@ -20,6 +20,7 @@ #include "../utils/types.h" #define BOOTROM_BASE 0x100000 +#define IRAM_BASE 0x40000000 #define HOST1X_BASE 0x50000000 #define BPMP_CACHE_BASE 0x50040000 #define DISPLAY_A_BASE 0x54200000 @@ -100,15 +101,30 @@ #define CL_DVFS(off) _REG(CL_DVFS_BASE, off) #define TEST_REG(off) _REG(0x0, off) +/* HOST1X registers. */ +#define HOST1X_CH0_SYNC_BASE 0x2100 +#define HOST1X_CH0_SYNC_SYNCPT_9 (HOST1X_CH0_SYNC_BASE + 0xFA4) +#define HOST1X_CH0_SYNC_SYNCPT_160 (HOST1X_CH0_SYNC_BASE + 0x1200) + /*! EVP registers. */ #define EVP_CPU_RESET_VECTOR 0x100 +#define EVP_COP_RESET_VECTOR 0x200 +#define EVP_COP_UNDEF_VECTOR 0x204 +#define EVP_COP_SWI_VECTOR 0x208 +#define EVP_COP_PREFETCH_ABORT_VECTOR 0x20C +#define EVP_COP_DATA_ABORT_VECTOR 0x210 +#define EVP_COP_RSVD_VECTOR 0x214 +#define EVP_COP_IRQ_VECTOR 0x218 +#define EVP_COP_FIQ_VECTOR 0x21C /*! Misc registers. */ #define APB_MISC_PP_STRAPPING_OPT_A 0x08 #define APB_MISC_PP_PINMUX_GLOBAL 0x40 +#define APB_MISC_GP_HIDREV 0x804 #define APB_MISC_GP_LCD_BL_PWM_CFGPADCTRL 0xA34 #define APB_MISC_GP_SDMMC1_PAD_CFGPADCTRL 0xA98 #define APB_MISC_GP_EMMC4_PAD_CFGPADCTRL 0xAB4 +#define APB_MISC_GP_EMMC4_PAD_PUPD_CFGPADCTRL 0xABC #define APB_MISC_GP_WIFI_EN_CFGPADCTRL 0xB64 #define APB_MISC_GP_WIFI_RST_CFGPADCTRL 0xB68 @@ -118,7 +134,10 @@ /*! Secure boot registers. */ #define SB_CSR 0x0 +#define SB_CSR_NS_RST_VEC_WR_DIS (1 << 1) +#define SB_CSR_PIROM_DISABLE (1 << 4) #define SB_AA64_RESET_LOW 0x30 +#define SB_AA64_RST_AARCH64_MODE_EN (1 << 0) #define SB_AA64_RESET_HIGH 0x34 /*! SOR registers. */ @@ -145,7 +164,7 @@ #define SYSCTR0_COUNTERID7 0xFDC #define SYSCTR0_COUNTERID8 0xFF0 #define SYSCTR0_COUNTERID9 0xFF4 -#define SYSCTR0_COUNTERID10 0xFF8 +#define SYSCTR0_COUNTERID10 0xFF8 #define SYSCTR0_COUNTERID11 0xFFC /*! TMR registers. */ @@ -182,10 +201,31 @@ /*! PWM registers. */ #define PWM_CONTROLLER_PWM_CSR_0 0x00 #define PWM_CONTROLLER_PWM_CSR_1 0x10 +#define PWM_CSR_EN (1 << 31) /*! Special registers. */ #define EMC_SCRATCH0 0x324 #define EMC_HEKA_UPD (1 << 30) #define EMC_SEPT_RUN (1 << 31) +/*! Flow controller registers. */ +#define FLOW_CTLR_HALT_COP_EVENTS 0x4 +#define HALT_COP_SEC (1 << 23) +#define HALT_COP_MSEC (1 << 24) +#define HALT_COP_USEC (1 << 25) +#define HALT_COP_JTAG (1 << 28) +#define HALT_COP_WAIT_EVENT (1 << 30) +#define HALT_COP_WAIT_IRQ (1 << 31) +#define HALT_COP_MAX_CNT 0xFF +#define FLOW_CTLR_HALT_CPU0_EVENTS 0x0 +#define FLOW_CTLR_HALT_CPU1_EVENTS 0x14 +#define FLOW_CTLR_HALT_CPU2_EVENTS 0x1C +#define FLOW_CTLR_HALT_CPU3_EVENTS 0x24 +#define FLOW_CTLR_CPU0_CSR 0x8 +#define FLOW_CTLR_CPU1_CSR 0x18 +#define FLOW_CTLR_CPU2_CSR 0x20 +#define FLOW_CTLR_CPU3_CSR 0x28 +#define FLOW_CTLR_RAM_REPAIR 0x40 +#define FLOW_CTLR_BPMP_CLUSTER_CONTROL 0x98 + #endif diff --git a/source/storage/emummc.c b/source/storage/emummc.c new file mode 100644 index 0000000..a07d9ed --- /dev/null +++ b/source/storage/emummc.c @@ -0,0 +1,266 @@ +/* + * Copyright (C) 2019 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include + +#include "emummc.h" +#include "sdmmc.h" +#include "../config/config.h" +#include "../config/ini.h" +#include "../gfx/gfx.h" +#include "../libs/fatfs/ff.h" +#include "../mem/heap.h" +#include "../utils/list.h" +#include "../utils/types.h" + +extern sdmmc_t sd_sdmmc; +extern sdmmc_storage_t sd_storage; +extern FATFS sd_fs; + +extern hekate_config h_cfg; + +extern bool sd_mount(); +extern void sd_unmount(); + +bool emummc_load_cfg() +{ + sd_mount(); + emu_cfg.enabled = 0; + emu_cfg.path = NULL; + emu_cfg.nintendo_path = NULL; + emu_cfg.sector = 0; + emu_cfg.id = 0; + emu_cfg.file_based_part_size = 0; + emu_cfg.active_part = 0; + emu_cfg.fs_ver = 0; + emu_cfg.emummc_file_based_path = (char *)malloc(0x80); + + LIST_INIT(ini_sections); + if (ini_parse(&ini_sections, "emuMMC/emummc.ini", false)) + { + LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_sections, link) + { + if (ini_sec->type == INI_CHOICE) + { + if (strcmp(ini_sec->name, "emummc")) + continue; + + LIST_FOREACH_ENTRY(ini_kv_t, kv, &ini_sec->kvs, link) + { + if (!strcmp("enabled", kv->key)) + emu_cfg.enabled = atoi(kv->val); + else if (!strcmp("sector", kv->key)) + emu_cfg.sector = strtol(kv->val, NULL, 16); + else if (!strcmp("id", kv->key)) + emu_cfg.id = strtol(kv->val, NULL, 16); + else if (!strcmp("path", kv->key)) + emu_cfg.path = kv->val; + else if (!strcmp("nintendo_path", kv->key)) + emu_cfg.nintendo_path = kv->val; + } + break; + } + } + return 0; + } + return 1; +} + +static int emummc_raw_get_part_off(int part_idx) +{ + switch (part_idx) + { + case 0: + return 2; + case 1: + return 0; + case 2: + return 1; + } + return 2; +} + + +int emummc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc) +{ + FILINFO fno; + if (!sdmmc_storage_init_mmc(storage, sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4)) + { + EPRINTF("Failed to init eMMC."); + + goto out; + } + if (h_cfg.emummc_force_disable) + return 1; + + emu_cfg.active_part = 0; + if (!sd_mount()) + goto out; + + if (emu_cfg.enabled && !emu_cfg.sector) + { + strcpy(emu_cfg.emummc_file_based_path, emu_cfg.path); + strcat(emu_cfg.emummc_file_based_path, "/eMMC"); + + if (f_stat(emu_cfg.emummc_file_based_path, &fno)) + { + EPRINTF("Failed to open eMMC folder."); + goto out; + } + f_chmod(emu_cfg.emummc_file_based_path, AM_ARC, AM_ARC); + + strcat(emu_cfg.emummc_file_based_path, "/00"); + if (f_stat(emu_cfg.emummc_file_based_path, &fno)) + { + EPRINTF("Failed to open emuMMC rawnand."); + goto out; + } + emu_cfg.file_based_part_size = fno.fsize >> 9; + } + return 1; + +out: + return 0; +} + +int emummc_storage_end(sdmmc_storage_t *storage) +{ + sd_unmount(); + sdmmc_storage_end(storage); + + return 1; +} + +int emummc_storage_read(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, void *buf) +{ + FIL fp; + if (!emu_cfg.enabled || h_cfg.emummc_force_disable) + return sdmmc_storage_read(storage, sector, num_sectors, buf); + else if (emu_cfg.sector) + { + sector += emu_cfg.sector; + sector += emummc_raw_get_part_off(emu_cfg.active_part) * 0x2000; + return sdmmc_storage_read(&sd_storage, sector, num_sectors, buf); + } + else + { + if (!emu_cfg.active_part) + { + u32 file_part = sector / emu_cfg.file_based_part_size; + sector = sector % emu_cfg.file_based_part_size; + if (file_part >= 10) + itoa(file_part, emu_cfg.emummc_file_based_path + strlen(emu_cfg.emummc_file_based_path) - 2, 10); + else + { + emu_cfg.emummc_file_based_path[strlen(emu_cfg.emummc_file_based_path) - 2] = '0'; + itoa(file_part, emu_cfg.emummc_file_based_path + strlen(emu_cfg.emummc_file_based_path) - 1, 10); + } + } + if (f_open(&fp, emu_cfg.emummc_file_based_path, FA_READ)) + { + EPRINTF("Failed to open emuMMC image."); + return 0; + } + f_lseek(&fp, (u64)sector << 9); + if (f_read(&fp, buf, (u64)num_sectors << 9, NULL)) + { + EPRINTF("Failed to read emuMMC image."); + f_close(&fp); + return 0; + } + + f_close(&fp); + return 1; + } + + return 1; +} + +int emummc_storage_write(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, void *buf) +{ + FIL fp; + if (!emu_cfg.enabled || h_cfg.emummc_force_disable) + return sdmmc_storage_write(storage, sector, num_sectors, buf); + else if (emu_cfg.sector) + { + sector += emu_cfg.sector; + sector += emummc_raw_get_part_off(emu_cfg.active_part) * 0x2000; + return sdmmc_storage_write(&sd_storage, sector, num_sectors, buf); + } + else + { + if (!emu_cfg.active_part) + { + u32 file_part = sector / emu_cfg.file_based_part_size; + sector = sector % emu_cfg.file_based_part_size; + if (file_part >= 10) + itoa(file_part, emu_cfg.emummc_file_based_path + strlen(emu_cfg.emummc_file_based_path) - 2, 10); + else + { + emu_cfg.emummc_file_based_path[strlen(emu_cfg.emummc_file_based_path) - 2] = '0'; + itoa(file_part, emu_cfg.emummc_file_based_path + strlen(emu_cfg.emummc_file_based_path) - 1, 10); + } + } + if (f_open(&fp, emu_cfg.emummc_file_based_path, FA_WRITE)) + { + gfx_printf("e5\n"); + return 0; + } + f_lseek(&fp, (u64)sector << 9); + if (f_write(&fp, buf, (u64)num_sectors << 9, NULL)) + { + gfx_printf("e6\n"); + f_close(&fp); + return 0; + } + + f_close(&fp); + return 1; + } +} + +int emummc_storage_set_mmc_partition(sdmmc_storage_t *storage, u32 partition) +{ + emu_cfg.active_part = partition; + + if (!emu_cfg.enabled || h_cfg.emummc_force_disable) + sdmmc_storage_set_mmc_partition(storage, partition); + else if (emu_cfg.sector) + return 1; + else + { + strcpy(emu_cfg.emummc_file_based_path, emu_cfg.path); + strcat(emu_cfg.emummc_file_based_path, "/eMMC"); + + switch (partition) + { + case 0: + strcat(emu_cfg.emummc_file_based_path, "/00"); + break; + case 1: + strcat(emu_cfg.emummc_file_based_path, "/BOOT0"); + break; + case 2: + strcat(emu_cfg.emummc_file_based_path, "/BOOT1"); + break; + } + + return 1; + } + + return 1; +} diff --git a/source/storage/emummc.h b/source/storage/emummc.h new file mode 100644 index 0000000..635332f --- /dev/null +++ b/source/storage/emummc.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2019 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef EMUMMC_H +#define EMUMMC_H + +#include "sdmmc.h" +#include "../utils/types.h" + +typedef enum +{ + EMUMMC_TYPE_NONE = 0, + EMUMMC_TYPE_PARTITION = 1, + EMUMMC_TYPE_FILES = 2, +} emummc_type_t; + +typedef enum { + EMUMMC_MMC_NAND = 0, + EMUMMC_MMC_SD = 1, + EMUMMC_MMC_GC = 2, +} emummc_mmc_t; + +typedef struct _emummc_cfg_t +{ + int enabled; + u64 sector; + u16 id; + char *path; + char *nintendo_path; + // Internal. + char *emummc_file_based_path; + u32 file_based_part_size; + u32 active_part; + int fs_ver; +} emummc_cfg_t; + +emummc_cfg_t emu_cfg; + +bool emummc_load_cfg(); +int emummc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc); +int emummc_storage_end(sdmmc_storage_t *storage); +int emummc_storage_read(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, void *buf); +int emummc_storage_write(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, void *buf); +int emummc_storage_set_mmc_partition(sdmmc_storage_t *storage, u32 partition); + +#endif \ No newline at end of file diff --git a/source/storage/nx_emmc.c b/source/storage/nx_emmc.c index a65dced..c35177e 100644 --- a/source/storage/nx_emmc.c +++ b/source/storage/nx_emmc.c @@ -17,6 +17,7 @@ #include #include "nx_emmc.h" +#include "emummc.h" #include "../mem/heap.h" #include "../utils/list.h" @@ -24,7 +25,7 @@ void nx_emmc_gpt_parse(link_t *gpt, sdmmc_storage_t *storage) { u8 *buf = (u8 *)malloc(NX_GPT_NUM_BLOCKS * NX_EMMC_BLOCKSIZE); - sdmmc_storage_read(storage, NX_GPT_FIRST_LBA, NX_GPT_NUM_BLOCKS, buf); + emummc_storage_read(storage, NX_GPT_FIRST_LBA, NX_GPT_NUM_BLOCKS, buf); gpt_header_t *hdr = (gpt_header_t *)buf; for (u32 i = 0; i < hdr->num_part_ents; i++) @@ -35,7 +36,7 @@ void nx_emmc_gpt_parse(link_t *gpt, sdmmc_storage_t *storage) part->lba_end = ent->lba_end; part->attrs = ent->attrs; - //HACK + // ASCII conversion. Copy only the LSByte of the UTF-16LE name. for (u32 i = 0; i < 36; i++) part->name[i] = ent->name[i]; part->name[36] = 0; @@ -65,7 +66,7 @@ int nx_emmc_part_read(sdmmc_storage_t *storage, emmc_part_t *part, u32 sector_of // The last LBA is inclusive. if (part->lba_start + sector_off > part->lba_end) return 0; - return sdmmc_storage_read(storage, part->lba_start + sector_off, num_sectors, buf); + return emummc_storage_read(storage, part->lba_start + sector_off, num_sectors, buf); } int nx_emmc_part_write(sdmmc_storage_t *storage, emmc_part_t *part, u32 sector_off, u32 num_sectors, void *buf) diff --git a/source/storage/sd.h b/source/storage/sd.h index c3bf82b..fafd322 100644 --- a/source/storage/sd.h +++ b/source/storage/sd.h @@ -1,8 +1,8 @@ /* * include/linux/mmc/sd.h * - * Copyright (C) 2005-2007 Pierre Ossman, All Rights Reserved. - * Copyright (C) 2018 CTCaer + * Copyright (c) 2005-2007 Pierre Ossman, All Rights Reserved. + * Copyright (c) 2018 CTCaer * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -40,7 +40,9 @@ #define SD_ROCR_S18A SD_OCR_S18R /* 1.8V switching accepted by card */ #define SD_OCR_XPC (1 << 28) /* SDXC power control */ #define SD_OCR_CCS (1 << 30) /* Card Capacity Status */ +#define SD_OCR_VDD_27_34 (0x7F << 15) /* VDD voltage 2.7 ~ 3.4 */ #define SD_OCR_VDD_32_33 (1 << 20) /* VDD voltage 3.2 ~ 3.3 */ +#define SD_OCR_VDD_18 (1 << 7) /* VDD voltage 1.8 */ /* * SD_SWITCH argument format: diff --git a/source/storage/sdmmc.c b/source/storage/sdmmc.c index 585268b..d75e609 100644 --- a/source/storage/sdmmc.c +++ b/source/storage/sdmmc.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2018 naehrwert - * Copyright (C) 2018 CTCaer + * 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, @@ -19,6 +19,7 @@ #include "sdmmc.h" #include "mmc.h" #include "sd.h" +#include "../../common/memory_map.h" #include "../gfx/gfx.h" #include "../mem/heap.h" #include "../utils/util.h" @@ -26,8 +27,6 @@ //#define DPRINTF(...) gfx_printf(__VA_ARGS__) #define DPRINTF(...) -extern boot_cfg_t b_cfg; - static inline u32 unstuff_bits(u32 *resp, u32 start, u32 size) { const u32 mask = (size < 32 ? 1 << size : 0) - 1; @@ -71,6 +70,7 @@ static int _sdmmc_storage_execute_cmd_type1_ex(sdmmc_storage_t *storage, u32 *re if (_sdmmc_storage_check_result(*resp)) if (expected_state == 0x10 || R1_CURRENT_STATE(*resp) == expected_state) return 1; + return 0; } @@ -84,6 +84,7 @@ static int _sdmmc_storage_go_idle_state(sdmmc_storage_t *storage) { sdmmc_cmd_t cmd; sdmmc_init_cmd(&cmd, MMC_GO_IDLE_STATE, 0, SDMMC_RSP_TYPE_0, 0); + return sdmmc_execute_cmd(storage->sdmmc, &cmd, 0, 0); } @@ -93,7 +94,9 @@ static int _sdmmc_storage_get_cid(sdmmc_storage_t *storage, void *buf) sdmmc_init_cmd(&cmd, MMC_ALL_SEND_CID, 0, SDMMC_RSP_TYPE_2, 0); if (!sdmmc_execute_cmd(storage->sdmmc, &cmd, 0, 0)) return 0; + sdmmc_get_rsp(storage->sdmmc, buf, 0x10, SDMMC_RSP_TYPE_2); + return 1; } @@ -108,7 +111,9 @@ static int _sdmmc_storage_get_csd(sdmmc_storage_t *storage, void *buf) sdmmc_init_cmd(&cmdbuf, MMC_SEND_CSD, storage->rca << 16, SDMMC_RSP_TYPE_2, 0); if (!sdmmc_execute_cmd(storage->sdmmc, &cmdbuf, 0, 0)) return 0; + sdmmc_get_rsp(storage->sdmmc, buf, 0x10, SDMMC_RSP_TYPE_2); + return 1; } @@ -146,8 +151,10 @@ static int _sdmmc_storage_readwrite_ex(sdmmc_storage_t *storage, u32 *blkcnt_out u32 tmp = 0; sdmmc_stop_transmission(storage->sdmmc, &tmp); _sdmmc_storage_get_status(storage, &tmp, 0); + return 0; } + return 1; } @@ -155,7 +162,9 @@ int sdmmc_storage_end(sdmmc_storage_t *storage) { if (!_sdmmc_storage_go_idle_state(storage)) return 0; + sdmmc_end(storage->sdmmc); + return 1; } @@ -177,14 +186,16 @@ static int _sdmmc_storage_readwrite(sdmmc_storage_t *storage, u32 sector, u32 nu msleep(100); } while (retries); + return 0; out:; - DPRINTF("readwrite: %08X\n", blkcnt); +DPRINTF("readwrite: %08X\n", blkcnt); sector += blkcnt; num_sectors -= blkcnt; bbuf += 512 * blkcnt; } + return 1; } @@ -210,10 +221,10 @@ static int _mmc_storage_get_op_cond_inner(sdmmc_storage_t *storage, u32 *pout, u switch (power) { case SDMMC_POWER_1_8: - arg = 0x40000080; //Sector access, voltage. + arg = SD_OCR_CCS | SD_OCR_VDD_18; break; case SDMMC_POWER_3_3: - arg = 0x403F8000; //Sector access, voltage. + arg = SD_OCR_CCS | SD_OCR_VDD_27_34; break; default: return 0; @@ -235,14 +246,17 @@ static int _mmc_storage_get_op_cond(sdmmc_storage_t *storage, u32 power) u32 cond = 0; if (!_mmc_storage_get_op_cond_inner(storage, &cond, power)) break; + if (cond & MMC_CARD_BUSY) { - if (cond & 0x40000000) + if (cond & SD_OCR_CCS) storage->has_sector_access = 1; + return 1; } if (get_tmr_ms() > timeout) break; + usleep(1000); } @@ -372,6 +386,7 @@ static int _mmc_storage_switch_buswidth(sdmmc_storage_t *storage, u32 bus_width) if (_sdmmc_storage_check_status(storage)) { sdmmc_set_bus_width(storage->sdmmc, bus_width); + return 1; } @@ -382,14 +397,19 @@ static int _mmc_storage_enable_HS(sdmmc_storage_t *storage, int check) { if (!_mmc_storage_switch(storage, SDMMC_SWITCH(MMC_SWITCH_MODE_WRITE_BYTE, EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS))) return 0; + if (check && !_sdmmc_storage_check_status(storage)) return 0; + if (!sdmmc_setup_clock(storage->sdmmc, 2)) return 0; - DPRINTF("[MMC] switched to HS\n"); + +DPRINTF("[MMC] switched to HS\n"); storage->csd.busspeed = 52; + if (check || _sdmmc_storage_check_status(storage)) return 1; + return 0; } @@ -397,12 +417,16 @@ static int _mmc_storage_enable_HS200(sdmmc_storage_t *storage) { if (!_mmc_storage_switch(storage, SDMMC_SWITCH(MMC_SWITCH_MODE_WRITE_BYTE, EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS200))) return 0; + if (!sdmmc_setup_clock(storage->sdmmc, 3)) return 0; + if (!sdmmc_config_tuning(storage->sdmmc, 3, MMC_SEND_TUNING_BLOCK_HS200)) return 0; - DPRINTF("[MMC] switched to HS200\n"); + +DPRINTF("[MMC] switched to HS200\n"); storage->csd.busspeed = 200; + return _sdmmc_storage_check_status(storage); } @@ -410,17 +434,24 @@ static int _mmc_storage_enable_HS400(sdmmc_storage_t *storage) { if (!_mmc_storage_enable_HS200(storage)) return 0; + sdmmc_get_venclkctl(storage->sdmmc); + if (!_mmc_storage_enable_HS(storage, 0)) return 0; + if (!_mmc_storage_switch(storage, SDMMC_SWITCH(MMC_SWITCH_MODE_WRITE_BYTE, EXT_CSD_BUS_WIDTH, EXT_CSD_DDR_BUS_WIDTH_8))) return 0; + if (!_mmc_storage_switch(storage, SDMMC_SWITCH(MMC_SWITCH_MODE_WRITE_BYTE, EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS400))) return 0; + if (!sdmmc_setup_clock(storage->sdmmc, 4)) return 0; - DPRINTF("[MMC] switched to HS400\n"); + +DPRINTF("[MMC] switched to HS400\n"); storage->csd.busspeed = 400; + return _sdmmc_storage_check_status(storage); } @@ -432,8 +463,7 @@ static int _mmc_storage_enable_highspeed(sdmmc_storage_t *storage, u32 card_type goto out; if (sdmmc_get_bus_width(storage->sdmmc) == SDMMC_BUS_WIDTH_8 && - card_type & EXT_CSD_CARD_TYPE_HS400_1_8V && - type == 4) + card_type & EXT_CSD_CARD_TYPE_HS400_1_8V && type == 4) return _mmc_storage_enable_HS400(storage); if (sdmmc_get_bus_width(storage->sdmmc) == SDMMC_BUS_WIDTH_8 || @@ -445,6 +475,7 @@ static int _mmc_storage_enable_highspeed(sdmmc_storage_t *storage, u32 card_type out:; if (card_type & EXT_CSD_CARD_TYPE_HS_52) return _mmc_storage_enable_HS(storage, 1); + return 1; } @@ -452,6 +483,7 @@ static int _mmc_storage_enable_bkops(sdmmc_storage_t *storage) { if (!_mmc_storage_switch(storage, SDMMC_SWITCH(MMC_SWITCH_MODE_SET_BITS, EXT_CSD_BKOPS_EN, EXT_CSD_BKOPS_LEVEL_2))) return 0; + return _sdmmc_storage_check_status(storage); } @@ -463,42 +495,42 @@ int sdmmc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32 if (!sdmmc_init(sdmmc, id, SDMMC_POWER_1_8, SDMMC_BUS_WIDTH_1, 0, 0)) return 0; - DPRINTF("[MMC] after init\n"); +DPRINTF("[MMC] after init\n"); usleep(1000 + (74000 + sdmmc->divisor - 1) / sdmmc->divisor); if (!_sdmmc_storage_go_idle_state(storage)) return 0; - DPRINTF("[MMC] went to idle state\n"); +DPRINTF("[MMC] went to idle state\n"); if (!_mmc_storage_get_op_cond(storage, SDMMC_POWER_1_8)) return 0; - DPRINTF("[MMC] got op cond\n"); +DPRINTF("[MMC] got op cond\n"); if (!_sdmmc_storage_get_cid(storage, storage->raw_cid)) return 0; - DPRINTF("[MMC] got cid\n"); +DPRINTF("[MMC] got cid\n"); if (!_mmc_storage_set_relative_addr(storage)) return 0; - DPRINTF("[MMC] set relative addr\n"); +DPRINTF("[MMC] set relative addr\n"); if (!_sdmmc_storage_get_csd(storage, storage->raw_csd)) return 0; - DPRINTF("[MMC] got csd\n"); +DPRINTF("[MMC] got csd\n"); _mmc_storage_parse_csd(storage); if (!sdmmc_setup_clock(storage->sdmmc, 1)) return 0; - DPRINTF("[MMC] after setup clock\n"); +DPRINTF("[MMC] after setup clock\n"); if (!_sdmmc_storage_select_card(storage)) return 0; - DPRINTF("[MMC] card selected\n"); +DPRINTF("[MMC] card selected\n"); if (!_sdmmc_storage_set_blocklen(storage, 512)) return 0; - DPRINTF("[MMC] set blocklen to 512\n"); +DPRINTF("[MMC] set blocklen to 512\n"); u32 *csd = (u32 *)storage->raw_csd; //Check system specification version, only version 4.0 and later support below features. @@ -510,7 +542,7 @@ int sdmmc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32 if (!_mmc_storage_switch_buswidth(storage, bus_width)) return 0; - DPRINTF("[MMC] switched buswidth\n"); +DPRINTF("[MMC] switched buswidth\n"); u8 *ext_csd = (u8 *)malloc(512); if (!_mmc_storage_get_ext_csd(storage, ext_csd)) @@ -519,7 +551,7 @@ int sdmmc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32 return 0; } free(ext_csd); - DPRINTF("[MMC] got ext_csd\n"); +DPRINTF("[MMC] got ext_csd\n"); _mmc_storage_parse_cid(storage); //This needs to be after csd and ext_csd //gfx_hexdump(0, ext_csd, 512); @@ -529,16 +561,16 @@ int sdmmc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32 if (storage->ext_csd.bkops & 0x1 && !(storage->ext_csd.bkops_en & EXT_CSD_BKOPS_LEVEL_2) && 0) { _mmc_storage_enable_bkops(storage); - DPRINTF("[MMC] BKOPS enabled\n"); +DPRINTF("[MMC] BKOPS enabled\n"); } else { - DPRINTF("[MMC] BKOPS disabled\n"); +DPRINTF("[MMC] BKOPS disabled\n"); } if (!_mmc_storage_enable_highspeed(storage, storage->ext_csd.card_type, type)) return 0; - DPRINTF("[MMC] succesfully switched to highspeed mode\n"); +DPRINTF("[MMC] succesfully switched to HS mode\n"); sdmmc_sd_clock_ctrl(storage->sdmmc, 1); @@ -549,8 +581,10 @@ int sdmmc_storage_set_mmc_partition(sdmmc_storage_t *storage, u32 partition) { if (!_mmc_storage_switch(storage, SDMMC_SWITCH(MMC_SWITCH_MODE_WRITE_BYTE, EXT_CSD_PART_CONFIG, partition))) return 0; + if (!_sdmmc_storage_check_status(storage)) return 0; + storage->partition = partition; return 1; } @@ -564,6 +598,7 @@ static int _sd_storage_execute_app_cmd(sdmmc_storage_t *storage, u32 expected_st u32 tmp; if (!_sdmmc_storage_execute_cmd_type1_ex(storage, &tmp, MMC_APP_CMD, storage->rca << 16, 0, expected_state, mask)) return 0; + return sdmmc_execute_cmd(storage->sdmmc, cmd, req, blkcnt_out); } @@ -571,6 +606,7 @@ static int _sd_storage_execute_app_cmd_type1(sdmmc_storage_t *storage, u32 *resp { if (!_sdmmc_storage_execute_cmd_type1(storage, MMC_APP_CMD, storage->rca << 16, 0, R1_STATE_TRAN)) return 0; + return _sdmmc_storage_execute_cmd_type1_ex(storage, resp, cmd, arg, check_busy, expected_state, 0); } @@ -602,6 +638,7 @@ static int _sd_storage_get_op_cond_once(sdmmc_storage_t *storage, u32 *cond, int sdmmc_init_cmd(&cmdbuf, SD_APP_OP_COND, arg, SDMMC_RSP_TYPE_3, 0); if (!_sd_storage_execute_app_cmd(storage, 0x10, is_version_1 ? 0x400000 : 0, &cmdbuf, 0, 0)) return 0; + return sdmmc_get_rsp(storage->sdmmc, cond, 4, SDMMC_RSP_TYPE_3); } @@ -629,7 +666,7 @@ static int _sd_storage_get_op_cond(sdmmc_storage_t *storage, int is_version_1, i return 0; storage->is_low_voltage = 1; - DPRINTF("-> switched to low voltage\n"); +DPRINTF("-> switched to low voltage\n"); } } @@ -783,17 +820,17 @@ void _sd_storage_set_current_limit(sdmmc_storage_t *storage, u8 *buf) switch (pwr) { case SD_SET_CURRENT_LIMIT_800: - DPRINTF("[SD] Power limit raised to 800mA\n"); +DPRINTF("[SD] power limit raised to 800mA\n"); break; case SD_SET_CURRENT_LIMIT_600: - DPRINTF("[SD] Power limit raised to 600mA\n"); +DPRINTF("[SD] power limit raised to 600mA\n"); break; case SD_SET_CURRENT_LIMIT_400: - DPRINTF("[SD] Power limit raised to 800mA\n"); +DPRINTF("[SD] power limit raised to 800mA\n"); break; default: case SD_SET_CURRENT_LIMIT_200: - DPRINTF("[SD] Power limit defaulted to 200mA\n"); +DPRINTF("[SD] power limit defaulted to 200mA\n"); break; } } @@ -802,10 +839,12 @@ int _sd_storage_enable_highspeed(sdmmc_storage_t *storage, u32 hs_type, u8 *buf) { if (!_sd_storage_switch(storage, buf, SD_SWITCH_CHECK, 0, hs_type)) return 0; +DPRINTF("[SD] SD supports switch to (U)HS check\n"); u32 type_out = buf[16] & 0xF; if (type_out != hs_type) return 0; +DPRINTF("[SD] SD supports selected (U)HS mode\n"); if ((((u16)buf[0] << 8) | buf[1]) < 0x320) { @@ -819,7 +858,7 @@ int _sd_storage_enable_highspeed(sdmmc_storage_t *storage, u32 hs_type, u8 *buf) return 1; } -int _sd_storage_enable_highspeed_low_volt(sdmmc_storage_t *storage, u32 type, u8 *buf) +int _sd_storage_enable_uhs_low_volt(sdmmc_storage_t *storage, u32 type, u8 *buf) { // Try to raise the current limit to let the card perform better. _sd_storage_set_current_limit(storage, buf); @@ -834,31 +873,31 @@ int _sd_storage_enable_highspeed_low_volt(sdmmc_storage_t *storage, u32 type, u8 u32 hs_type = 0; switch (type) { - case 11: + case 11: // SDR104. // Fall through if not supported. if (buf[13] & SD_MODE_UHS_SDR104) { type = 11; hs_type = UHS_SDR104_BUS_SPEED; - DPRINTF("[SD] Bus speed set to SDR104\n"); +DPRINTF("[SD] bus speed set to SDR104\n"); storage->csd.busspeed = 104; break; } - case 10: + case 10: // SDR50. if (buf[13] & SD_MODE_UHS_SDR50) { type = 10; hs_type = UHS_SDR50_BUS_SPEED; - DPRINTF("[SD] Bus speed set to SDR50\n"); +DPRINTF("[SD] bus speed set to SDR50\n"); storage->csd.busspeed = 50; break; } - case 8: + case 8: // SDR12. if (!(buf[13] & SD_MODE_UHS_SDR12)) return 0; type = 8; hs_type = UHS_SDR12_BUS_SPEED; - DPRINTF("[SD] Bus speed set to SDR12\n"); +DPRINTF("[SD] bus speed set to SDR12\n"); storage->csd.busspeed = 12; break; default: @@ -868,14 +907,17 @@ int _sd_storage_enable_highspeed_low_volt(sdmmc_storage_t *storage, u32 type, u8 if (!_sd_storage_enable_highspeed(storage, hs_type, buf)) return 0; +DPRINTF("[SD] SD card accepted UHS\n"); if (!sdmmc_setup_clock(storage->sdmmc, type)) return 0; +DPRINTF("[SD] setup clock\n"); if (!sdmmc_config_tuning(storage->sdmmc, type, MMC_SEND_TUNING_BLOCK)) return 0; +DPRINTF("[SD] config tuning\n"); return _sdmmc_storage_check_status(storage); } -int _sd_storage_enable_highspeed_high_volt(sdmmc_storage_t *storage, u8 *buf) +int _sd_storage_enable_hs_high_volt(sdmmc_storage_t *storage, u8 *buf) { if (!_sd_storage_switch_get(storage, buf)) return 0; @@ -885,8 +927,10 @@ int _sd_storage_enable_highspeed_high_volt(sdmmc_storage_t *storage, u8 *buf) if (!_sd_storage_enable_highspeed(storage, 1, buf)) return 0; + if (!_sdmmc_storage_check_status(storage)) return 0; + return sdmmc_setup_clock(storage->sdmmc, 7); } @@ -949,7 +993,7 @@ static int _sd_storage_get_ssr(sdmmc_storage_t *storage, u8 *buf) if (!(storage->csd.cmdclass & CCC_APP_SPEC)) { - DPRINTF("[SD] ssr: Card lacks mandatory SD Status function\n"); +DPRINTF("[SD] ssr: Card lacks mandatory SD Status function\n"); return 0; } @@ -1011,49 +1055,55 @@ static void _sd_storage_parse_csd(sdmmc_storage_t *storage) } } +void sdmmc_storage_init_wait_sd() +{ + u32 sd_poweroff_time = (u32)get_tmr_ms() - sd_power_cycle_time_start; + if (sd_poweroff_time < 100) + msleep(100 - sd_poweroff_time); +} + int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32 bus_width, u32 type) { int is_version_1 = 0; + u8 *buf = (u8 *)SDMMC_UPPER_BUFFER; - // Some cards (Sandisk U1), do not like a fast power cycle. Wait min 100ms. - u32 sd_poweroff_time = (u32)get_tmr_ms() - b_cfg.sd_timeoff; - if (id == SDMMC_1 && (sd_poweroff_time < 100)) - msleep(100 - sd_poweroff_time); + // Some cards (SanDisk U1), do not like a fast power cycle. Wait min 100ms. + sdmmc_storage_init_wait_sd(); memset(storage, 0, sizeof(sdmmc_storage_t)); storage->sdmmc = sdmmc; if (!sdmmc_init(sdmmc, id, SDMMC_POWER_3_3, SDMMC_BUS_WIDTH_1, 5, 0)) return 0; - DPRINTF("[SD] after init\n"); +DPRINTF("[SD] after init\n"); usleep(1000 + (74000 + sdmmc->divisor - 1) / sdmmc->divisor); if (!_sdmmc_storage_go_idle_state(storage)) return 0; - DPRINTF("[SD] went to idle state\n"); +DPRINTF("[SD] went to idle state\n"); is_version_1 = _sd_storage_send_if_cond(storage); if (is_version_1 == 2) return 0; - DPRINTF("[SD] after send if cond\n"); +DPRINTF("[SD] after send if cond\n"); if (!_sd_storage_get_op_cond(storage, is_version_1, bus_width == SDMMC_BUS_WIDTH_4 && type == 11)) return 0; - DPRINTF("[SD] got op cond\n"); +DPRINTF("[SD] got op cond\n"); if (!_sdmmc_storage_get_cid(storage, storage->raw_cid)) return 0; - DPRINTF("[SD] got cid\n"); +DPRINTF("[SD] got cid\n"); _sd_storage_parse_cid(storage); if (!_sd_storage_get_rca(storage)) return 0; - DPRINTF("[SD] got rca (= %04X)\n", storage->rca); +DPRINTF("[SD] got rca (= %04X)\n", storage->rca); if (!_sdmmc_storage_get_csd(storage, storage->raw_csd)) return 0; - DPRINTF("[SD] got csd\n"); +DPRINTF("[SD] got csd\n"); //Parse CSD. _sd_storage_parse_csd(storage); @@ -1066,7 +1116,7 @@ int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32 storage->sec_cnt = storage->csd.c_size << 10; break; default: - DPRINTF("[SD] Unknown CSD structure %d\n", storage->csd.structure); +DPRINTF("[SD] unknown CSD structure %d\n", storage->csd.structure); break; } @@ -1074,65 +1124,54 @@ int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32 { if (!sdmmc_setup_clock(storage->sdmmc, 6)) return 0; - DPRINTF("[SD] after setup clock\n"); +DPRINTF("[SD] after setup clock\n"); } if (!_sdmmc_storage_select_card(storage)) return 0; - DPRINTF("[SD] card selected\n"); +DPRINTF("[SD] card selected\n"); if (!_sdmmc_storage_set_blocklen(storage, 512)) return 0; - DPRINTF("[SD] set blocklen to 512\n"); +DPRINTF("[SD] set blocklen to 512\n"); u32 tmp = 0; if (!_sd_storage_execute_app_cmd_type1(storage, &tmp, SD_APP_SET_CLR_CARD_DETECT, 0, 0, R1_STATE_TRAN)) return 0; - DPRINTF("[SD] cleared card detect\n"); +DPRINTF("[SD] cleared card detect\n"); - u8 *buf = (u8 *)malloc(512); if (!_sd_storage_get_scr(storage, buf)) - { - free(buf); return 0; - } - + //gfx_hexdump(0, storage->raw_scr, 8); - DPRINTF("[SD] got scr\n"); +DPRINTF("[SD] got scr\n"); // Check if card supports a wider bus and if it's not SD Version 1.X if (bus_width == SDMMC_BUS_WIDTH_4 && (storage->scr.bus_widths & 4) && (storage->scr.sda_vsn & 0xF)) { if (!_sd_storage_execute_app_cmd_type1(storage, &tmp, SD_APP_SET_BUS_WIDTH, SD_BUS_WIDTH_4, 0, R1_STATE_TRAN)) - { - free(buf); return 0; - } + sdmmc_set_bus_width(storage->sdmmc, SDMMC_BUS_WIDTH_4); - DPRINTF("[SD] switched to wide bus width\n"); +DPRINTF("[SD] switched to wide bus width\n"); } else { - DPRINTF("[SD] SD does not support wide bus width\n"); +DPRINTF("[SD] SD does not support wide bus width\n"); } if (storage->is_low_voltage) { - if (!_sd_storage_enable_highspeed_low_volt(storage, type, buf)) - { - free(buf); + if (!_sd_storage_enable_uhs_low_volt(storage, type, buf)) return 0; - } - DPRINTF("[SD] enabled highspeed (low voltage)\n"); +DPRINTF("[SD] enabled UHS\n"); } else if (type != 6 && (storage->scr.sda_vsn & 0xF) != 0) { - if (!_sd_storage_enable_highspeed_high_volt(storage, buf)) - { - free(buf); + if (!_sd_storage_enable_hs_high_volt(storage, buf)) return 0; - } - DPRINTF("[SD] enabled highspeed (high voltage)\n"); + +DPRINTF("[SD] enabled HS\n"); storage->csd.busspeed = 25; } @@ -1141,10 +1180,9 @@ int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32 // Parse additional card info from sd status. if (_sd_storage_get_ssr(storage, buf)) { - DPRINTF("[SD] got sd status\n"); +DPRINTF("[SD] got sd status\n"); } - free(buf); return 1; } @@ -1186,13 +1224,13 @@ int sdmmc_storage_init_gc(sdmmc_storage_t *storage, sdmmc_t *sdmmc) if (!sdmmc_init(sdmmc, SDMMC_2, SDMMC_POWER_1_8, SDMMC_BUS_WIDTH_8, 14, 0)) return 0; - DPRINTF("[gc] after init\n"); +DPRINTF("[gc] after init\n"); usleep(1000 + (10000 + sdmmc->divisor - 1) / sdmmc->divisor); if (!sdmmc_config_tuning(storage->sdmmc, 14, MMC_SEND_TUNING_BLOCK_HS200)) return 0; - DPRINTF("[gc] after tuning\n"); +DPRINTF("[gc] after tuning\n"); sdmmc_sd_clock_ctrl(sdmmc, 1); diff --git a/source/storage/sdmmc.h b/source/storage/sdmmc.h index a144c12..c8b8f96 100644 --- a/source/storage/sdmmc.h +++ b/source/storage/sdmmc.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2018 naehrwert - * Copyright (C) 2018 CTCaer + * 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, @@ -21,6 +21,8 @@ #include "../utils/types.h" #include "sdmmc_driver.h" +u32 sd_power_cycle_time_start; + typedef struct _mmc_cid { u32 manfid; @@ -47,7 +49,7 @@ typedef struct _mmc_csd u32 read_blkbits; u32 write_blkbits; u32 capacity; - u8 write_protect; + u8 write_protect; u16 busspeed; } mmc_csd_t; @@ -107,6 +109,7 @@ int sdmmc_storage_read(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, vo int sdmmc_storage_write(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, void *buf); int sdmmc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32 bus_width, u32 type); int sdmmc_storage_set_mmc_partition(sdmmc_storage_t *storage, u32 partition); +void sdmmc_storage_init_wait_sd(); int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32 bus_width, u32 type); int sdmmc_storage_init_gc(sdmmc_storage_t *storage, sdmmc_t *sdmmc); diff --git a/source/storage/sdmmc_driver.c b/source/storage/sdmmc_driver.c index 23f6c0d..57d20f9 100644 --- a/source/storage/sdmmc_driver.c +++ b/source/storage/sdmmc_driver.c @@ -21,6 +21,7 @@ #include "sdmmc.h" #include "../gfx/gfx.h" #include "../power/max7762x.h" +#include "../soc/bpmp.h" #include "../soc/clock.h" #include "../soc/gpio.h" #include "../soc/pinmux.h" @@ -31,8 +32,6 @@ //#define DPRINTF(...) gfx_printf(__VA_ARGS__) #define DPRINTF(...) -extern boot_cfg_t b_cfg; - /*! SCMMC controller base addresses. */ static const u32 _sdmmc_bases[4] = { 0x700B0000, @@ -123,6 +122,7 @@ static int _sdmmc_config_ven_ceata_clk(sdmmc_t *sdmmc, u32 id) { if (!sdmmc->venclkctl_set) return 0; + tap_val = sdmmc->venclkctl_tap; } else @@ -201,7 +201,7 @@ out:; int sdmmc_setup_clock(sdmmc_t *sdmmc, u32 type) { - //Disable the SD clock if it was enabled, and reenable it later. + // Disable the SD clock if it was enabled, and reenable it later. bool should_enable_sd_clock = false; if (sdmmc->regs->clkcon & TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE) { @@ -217,7 +217,7 @@ int sdmmc_setup_clock(sdmmc_t *sdmmc, u32 type) case 1: case 5: case 6: - sdmmc->regs->hostctl &= 0xFB; //Should this be 0xFFFB (~4) ? + sdmmc->regs->hostctl &= 0xFB; // Should this be 0xFFFB (~4) ? sdmmc->regs->hostctl2 &= SDHCI_CTRL_VDD_330; break; case 2: @@ -233,7 +233,7 @@ int sdmmc_setup_clock(sdmmc_t *sdmmc, u32 type) sdmmc->regs->hostctl2 |= SDHCI_CTRL_VDD_180; break; case 4: - //Non standard + // Non standard. sdmmc->regs->hostctl2 = (sdmmc->regs->hostctl2 & SDHCI_CTRL_UHS_MASK) | HS400_BUS_SPEED; sdmmc->regs->hostctl2 |= SDHCI_CTRL_VDD_180; break; @@ -242,7 +242,7 @@ int sdmmc_setup_clock(sdmmc_t *sdmmc, u32 type) sdmmc->regs->hostctl2 |= SDHCI_CTRL_VDD_180; break; case 10: - //T210 Errata for SDR50, the host must be set to SDR104. + // T210 Errata for SDR50, the host must be set to SDR104. sdmmc->regs->hostctl2 = (sdmmc->regs->hostctl2 & SDHCI_CTRL_UHS_MASK) | UHS_SDR104_BUS_SPEED; sdmmc->regs->hostctl2 |= SDHCI_CTRL_VDD_180; break; @@ -252,7 +252,7 @@ int sdmmc_setup_clock(sdmmc_t *sdmmc, u32 type) u32 tmp; u16 divisor; - clock_sdmmc_get_params(&tmp, &divisor, type); + clock_sdmmc_get_card_clock_div(&tmp, &divisor, type); clock_sdmmc_config_clock_source(&tmp, sdmmc->id, tmp); sdmmc->divisor = (tmp + divisor - 1) / divisor; @@ -264,7 +264,7 @@ int sdmmc_setup_clock(sdmmc_t *sdmmc, u32 type) divisor = div >> 8; sdmmc->regs->clkcon = (sdmmc->regs->clkcon & 0x3F) | (div << 8) | (divisor << 6); - //Enable the SD clock again. + // Enable the SD clock again. if (should_enable_sd_clock) sdmmc->regs->clkcon |= TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE; @@ -398,7 +398,7 @@ static int _sdmmc_wait_prnsts_type0(sdmmc_t *sdmmc, u32 wait_dat) _sdmmc_get_clkcon(sdmmc); u32 timeout = get_tmr_ms() + 2000; - while(sdmmc->regs->prnsts & 1) //CMD inhibit. + while(sdmmc->regs->prnsts & 1) // CMD inhibit. if (get_tmr_ms() > timeout) { _sdmmc_reset(sdmmc); @@ -408,7 +408,7 @@ static int _sdmmc_wait_prnsts_type0(sdmmc_t *sdmmc, u32 wait_dat) if (wait_dat) { timeout = get_tmr_ms() + 2000; - while (sdmmc->regs->prnsts & 2) //DAT inhibit. + while (sdmmc->regs->prnsts & 2) // DAT inhibit. if (get_tmr_ms() > timeout) { _sdmmc_reset(sdmmc); @@ -424,7 +424,7 @@ static int _sdmmc_wait_prnsts_type1(sdmmc_t *sdmmc) _sdmmc_get_clkcon(sdmmc); u32 timeout = get_tmr_ms() + 2000; - while (!(sdmmc->regs->prnsts & 0x100000)) //DAT0 line level. + while (!(sdmmc->regs->prnsts & 0x100000)) // DAT0 line level. if (get_tmr_ms() > timeout) { _sdmmc_reset(sdmmc); @@ -511,13 +511,17 @@ static int _sdmmc_config_tuning_once(sdmmc_t *sdmmc, u32 cmd) return 0; _sdmmc_setup_read_small_block(sdmmc); + sdmmc->regs->norintstsen |= TEGRA_MMC_NORINTSTSEN_BUFFER_READ_READY; sdmmc->regs->norintsts = sdmmc->regs->norintsts; sdmmc->regs->clkcon &= ~TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE; + _sdmmc_parse_cmd_48(sdmmc, cmd); _sdmmc_get_clkcon(sdmmc); usleep(1); + _sdmmc_reset(sdmmc); + sdmmc->regs->clkcon |= TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE; _sdmmc_get_clkcon(sdmmc); @@ -533,10 +537,13 @@ static int _sdmmc_config_tuning_once(sdmmc_t *sdmmc, u32 cmd) return 1; } } + _sdmmc_reset(sdmmc); + sdmmc->regs->norintstsen &= 0xFFDF; _sdmmc_get_clkcon(sdmmc); usleep((1000 * 8 + sdmmc->divisor - 1) / sdmmc->divisor); + return 0; } @@ -563,8 +570,8 @@ int sdmmc_config_tuning(sdmmc_t *sdmmc, u32 type, u32 cmd) return 0; } - sdmmc->regs->ventunctl0 = (sdmmc->regs->ventunctl0 & 0xFFFF1FFF) | flag; - sdmmc->regs->ventunctl0 = (sdmmc->regs->ventunctl0 & 0xFFFFE03F) | 0x40; + sdmmc->regs->ventunctl0 = (sdmmc->regs->ventunctl0 & 0xFFFF1FFF) | flag; // Tries. + sdmmc->regs->ventunctl0 = (sdmmc->regs->ventunctl0 & 0xFFFFE03F) | 0x40; // Multiplier. sdmmc->regs->ventunctl0 |= 0x20000; sdmmc->regs->hostctl2 |= SDHCI_CTRL_EXEC_TUNING; @@ -577,6 +584,7 @@ int sdmmc_config_tuning(sdmmc_t *sdmmc, u32 type, u32 cmd) if (sdmmc->regs->hostctl2 & SDHCI_CTRL_TUNED_CLK) return 1; + return 0; } @@ -666,7 +674,7 @@ static void _sdmmc_autocal_execute(sdmmc_t *sdmmc, u32 power) { if (get_tmr_ms() > timeout) { - //In case autocalibration fails, we load suggested standard values. + // In case autocalibration fails, we load suggested standard values. _sdmmc_pad_config_fallback(sdmmc, power); sdmmc->regs->autocalcfg &= 0xDFFFFFFF; break; @@ -703,7 +711,7 @@ static int _sdmmc_check_mask_interrupt(sdmmc_t *sdmmc, u16 *pout, u16 mask) if (pout) *pout = norintsts; - //Check for error interrupt. + // Check for error interrupt. if (norintsts & TEGRA_MMC_NORINTSTS_ERR_INTERRUPT) { sdmmc->regs->errintsts = errintsts; @@ -714,7 +722,7 @@ static int _sdmmc_check_mask_interrupt(sdmmc_t *sdmmc, u16 *pout, u16 mask) sdmmc->regs->norintsts = norintsts & mask; return SDMMC_MASKINT_MASKED; } - + return SDMMC_MASKINT_NOERROR; } @@ -746,18 +754,22 @@ static int _sdmmc_stop_transmission_inner(sdmmc_t *sdmmc, u32 *rsp) return 0; _sdmmc_enable_interrupts(sdmmc); + cmd.cmd = MMC_STOP_TRANSMISSION; cmd.arg = 0; cmd.rsp_type = SDMMC_RSP_TYPE_1; cmd.check_busy = 1; + _sdmmc_parse_cmdbuf(sdmmc, &cmd, false); + int res = _sdmmc_wait_request(sdmmc); _sdmmc_mask_interrupts(sdmmc); if (!res) return 0; - + _sdmmc_cache_rsp(sdmmc, rsp, 4, SDMMC_RSP_TYPE_1); + return _sdmmc_wait_prnsts_type1(sdmmc); } @@ -777,6 +789,7 @@ int sdmmc_stop_transmission(sdmmc_t *sdmmc, u32 *rsp) int res = _sdmmc_stop_transmission_inner(sdmmc, rsp); usleep((8000 + sdmmc->divisor - 1) / sdmmc->divisor); + if (should_disable_sd_clock) sdmmc->regs->clkcon &= ~TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE; @@ -793,7 +806,7 @@ static int _sdmmc_config_dma(sdmmc_t *sdmmc, u32 *blkcnt_out, sdmmc_req_t *req) blkcnt = 0xFFFF; u32 admaaddr = (u32)req->buf; - //Check alignment. + // Check alignment. if (admaaddr << 29) return 0; @@ -817,7 +830,7 @@ static int _sdmmc_config_dma(sdmmc_t *sdmmc, u32 *blkcnt_out, sdmmc_req_t *req) trnmode |= TEGRA_MMC_TRNMOD_DATA_XFER_DIR_SEL_READ; if (req->is_auto_cmd12) trnmode = (trnmode & 0xFFF3) | TEGRA_MMC_TRNMOD_AUTO_CMD12; - + bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY, false); sdmmc->regs->trnmod = trnmode; return 1; @@ -836,15 +849,18 @@ static int _sdmmc_update_dma(sdmmc_t *sdmmc) while (1) { u16 intr = 0; - res = _sdmmc_check_mask_interrupt(sdmmc, &intr, + res = _sdmmc_check_mask_interrupt(sdmmc, &intr, TEGRA_MMC_NORINTSTS_XFER_COMPLETE | TEGRA_MMC_NORINTSTS_DMA_INTERRUPT); if (res < 0) break; if (intr & TEGRA_MMC_NORINTSTS_XFER_COMPLETE) - return 1; //Transfer complete. + { + bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY, false); + return 1; // Transfer complete. + } if (intr & TEGRA_MMC_NORINTSTS_DMA_INTERRUPT) { - //Update DMA. + // Update DMA. sdmmc->regs->admaaddr = sdmmc->dma_addr_next; sdmmc->regs->admaaddr_hi = 0; sdmmc->dma_addr_next += 0x80000; @@ -885,7 +901,7 @@ static int _sdmmc_execute_cmd_inner(sdmmc_t *sdmmc, sdmmc_cmd_t *cmd, sdmmc_req_ _sdmmc_parse_cmdbuf(sdmmc, cmd, is_data_present); int res = _sdmmc_wait_request(sdmmc); - DPRINTF("rsp(%d): %08X, %08X, %08X, %08X\n", res, + DPRINTF("rsp(%d): %08X, %08X, %08X, %08X\n", res, sdmmc->regs->rspreg0, sdmmc->regs->rspreg1, sdmmc->regs->rspreg2, sdmmc->regs->rspreg3); if (res) { @@ -906,6 +922,7 @@ static int _sdmmc_execute_cmd_inner(sdmmc_t *sdmmc, sdmmc_cmd_t *cmd, sdmmc_req_ { if (blkcnt_out) *blkcnt_out = blkcnt; + if (req->is_auto_cmd12) sdmmc->rsp3 = sdmmc->regs->rspreg3; } @@ -919,12 +936,14 @@ static int _sdmmc_execute_cmd_inner(sdmmc_t *sdmmc, sdmmc_cmd_t *cmd, sdmmc_req_ static int _sdmmc_config_sdmmc1() { - //Configure SD card detect. + // Configure SD card detect. PINMUX_AUX(PINMUX_AUX_GPIO_PZ1) = PINMUX_INPUT_ENABLE | PINMUX_PULL_UP | 1; //GPIO control, pull up. APB_MISC(APB_MISC_GP_VGPIO_GPIO_MUX_SEL) = 0; gpio_config(GPIO_PORT_Z, GPIO_PIN_1, GPIO_MODE_GPIO); gpio_output_enable(GPIO_PORT_Z, GPIO_PIN_1, GPIO_OUTPUT_DISABLE); usleep(100); + + // Check if SD card is inserted. if(!!gpio_read(GPIO_PORT_Z, GPIO_PIN_1)) return 0; @@ -937,8 +956,8 @@ static int _sdmmc_config_sdmmc1() * APB_MISC_GP_SDMMCx_CLK_LPBK_CONTROL = SDMMCx_CLK_PAD_E_LPBK for CLK */ - //Configure SDMMC1 pinmux. - APB_MISC(APB_MISC_GP_SDMMC1_CLK_LPBK_CONTROL) = 1; + // Configure SDMMC1 pinmux. + APB_MISC(APB_MISC_GP_SDMMC1_CLK_LPBK_CONTROL) = 1; // Enable deep loopback for SDMMC1 CLK pad. PINMUX_AUX(PINMUX_AUX_SDMMC1_CLK) = PINMUX_DRIVE_2X | PINMUX_INPUT_ENABLE | PINMUX_PARKED; PINMUX_AUX(PINMUX_AUX_SDMMC1_CMD) = PINMUX_DRIVE_2X | PINMUX_INPUT_ENABLE | PINMUX_PARKED | PINMUX_PULL_UP; PINMUX_AUX(PINMUX_AUX_SDMMC1_DAT3) = PINMUX_DRIVE_2X | PINMUX_INPUT_ENABLE | PINMUX_PARKED | PINMUX_PULL_UP; @@ -946,12 +965,12 @@ static int _sdmmc_config_sdmmc1() PINMUX_AUX(PINMUX_AUX_SDMMC1_DAT1) = PINMUX_DRIVE_2X | PINMUX_INPUT_ENABLE | PINMUX_PARKED | PINMUX_PULL_UP; PINMUX_AUX(PINMUX_AUX_SDMMC1_DAT0) = PINMUX_DRIVE_2X | PINMUX_INPUT_ENABLE | PINMUX_PARKED | PINMUX_PULL_UP; - //Make sure the SDMMC1 controller is powered. + // Make sure the SDMMC1 controller is powered. PMC(APBDEV_PMC_NO_IOPOWER) &= ~(1 << 12); - //Assume 3.3V SD card voltage. + // Assume 3.3V SD card voltage. PMC(APBDEV_PMC_PWR_DET_VAL) |= (1 << 12); - //Set enable SD card power. + // Set enable SD card power. PINMUX_AUX(PINMUX_AUX_DMIC3_CLK) = PINMUX_INPUT_ENABLE | PINMUX_PULL_DOWN | 1; //GPIO control, pull down. gpio_config(GPIO_PORT_E, GPIO_PIN_4, GPIO_MODE_GPIO); gpio_write(GPIO_PORT_E, GPIO_PIN_4, GPIO_HIGH); @@ -959,13 +978,13 @@ static int _sdmmc_config_sdmmc1() usleep(1000); - //Enable SD card power. + // Enable SD card power. max77620_regulator_set_voltage(REGULATOR_LDO2, 3300000); max77620_regulator_enable(REGULATOR_LDO2, 1); usleep(1000); - //For good measure. + // For good measure. APB_MISC(APB_MISC_GP_SDMMC1_PAD_CFGPADCTRL) = 0x10000000; usleep(1000); @@ -996,7 +1015,7 @@ int sdmmc_init(sdmmc_t *sdmmc, u32 id, u32 power, u32 bus_width, u32 type, int n u32 clock; u16 divisor; - clock_sdmmc_get_params(&clock, &divisor, type); + clock_sdmmc_get_card_clock_div(&clock, &divisor, type); clock_sdmmc_enable(id, clock); sdmmc->clock_stopped = 0; @@ -1009,18 +1028,23 @@ int sdmmc_init(sdmmc_t *sdmmc, u32 id, u32 power, u32 bus_width, u32 type, int n sdmmc->regs->sdmemcmppadctl = (sdmmc->regs->sdmemcmppadctl & 0xF) | 7; if (!_sdmmc_autocal_config_offset(sdmmc, power)) return 0; + _sdmmc_autocal_execute(sdmmc, power); + if (_sdmmc_enable_internal_clock(sdmmc)) { sdmmc_set_bus_width(sdmmc, bus_width); _sdmmc_set_voltage(sdmmc, power); + if (sdmmc_setup_clock(sdmmc, type)) { sdmmc_sd_clock_ctrl(sdmmc, no_sd); _sdmmc_sd_clock_enable(sdmmc); _sdmmc_get_clkcon(sdmmc); + return 1; } + return 0; } return 0; @@ -1031,7 +1055,7 @@ void sdmmc_end(sdmmc_t *sdmmc) if (!sdmmc->clock_stopped) { _sdmmc_sd_clock_disable(sdmmc); - // Disable SDMMC power. + // Disable SDMMC power. _sdmmc_set_voltage(sdmmc, SDMMC_POWER_OFF); // Disable SD card power. @@ -1039,8 +1063,8 @@ void sdmmc_end(sdmmc_t *sdmmc) { gpio_output_enable(GPIO_PORT_E, GPIO_PIN_4, GPIO_OUTPUT_DISABLE); max77620_regulator_enable(REGULATOR_LDO2, 0); - b_cfg.sd_timeoff = get_tmr_ms(); // Some sandisc U1 cards need 100ms for a power cycle. - msleep(1); // To power cycle, min 1ms without power is needed. + sd_power_cycle_time_start = get_tmr_ms(); // Some sandisc U1 cards need 100ms for a power cycle. + usleep(1000); // To power cycle, min 1ms without power is needed. } _sdmmc_get_clkcon(sdmmc); @@ -1062,7 +1086,7 @@ int sdmmc_execute_cmd(sdmmc_t *sdmmc, sdmmc_cmd_t *cmd, sdmmc_req_t *req, u32 *b if (!sdmmc->sd_clock_enabled) return 0; - //Recalibrate periodically for SDMMC1. + // Recalibrate periodically for SDMMC1. if (sdmmc->id == SDMMC_1 && sdmmc->no_sd) _sdmmc_autocal_execute(sdmmc, sdmmc_get_voltage(sdmmc)); @@ -1077,6 +1101,7 @@ int sdmmc_execute_cmd(sdmmc_t *sdmmc, sdmmc_cmd_t *cmd, sdmmc_req_t *req, u32 *b int res = _sdmmc_execute_cmd_inner(sdmmc, cmd, req, blkcnt_out); usleep((8000 + sdmmc->divisor - 1) / sdmmc->divisor); + if (should_disable_sd_clock) sdmmc->regs->clkcon &= ~TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE; @@ -1093,6 +1118,14 @@ int sdmmc_enable_low_voltage(sdmmc_t *sdmmc) _sdmmc_get_clkcon(sdmmc); + // Enable schmitt trigger for better duty cycle and low jitter clock. + PINMUX_AUX(PINMUX_AUX_SDMMC1_CLK) |= PINMUX_SCHMT; + PINMUX_AUX(PINMUX_AUX_SDMMC1_CMD) |= PINMUX_SCHMT; + PINMUX_AUX(PINMUX_AUX_SDMMC1_DAT3) |= PINMUX_SCHMT; + PINMUX_AUX(PINMUX_AUX_SDMMC1_DAT2) |= PINMUX_SCHMT; + PINMUX_AUX(PINMUX_AUX_SDMMC1_DAT1) |= PINMUX_SCHMT; + PINMUX_AUX(PINMUX_AUX_SDMMC1_DAT0) |= PINMUX_SCHMT; + max77620_regulator_set_voltage(REGULATOR_LDO2, 1800000); PMC(APBDEV_PMC_PWR_DET_VAL) &= ~(1 << 12); @@ -1101,12 +1134,12 @@ int sdmmc_enable_low_voltage(sdmmc_t *sdmmc) _sdmmc_set_voltage(sdmmc, SDMMC_POWER_1_8); _sdmmc_get_clkcon(sdmmc); msleep(5); - + if (sdmmc->regs->hostctl2 & SDHCI_CTRL_VDD_180) { sdmmc->regs->clkcon |= TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE; _sdmmc_get_clkcon(sdmmc); - msleep(1); + usleep(1000); if ((sdmmc->regs->prnsts & 0xF00000) == 0xF00000) return 1; } diff --git a/source/meme/external_utils.c b/source/tegraexplorer/emmc.c similarity index 74% rename from source/meme/external_utils.c rename to source/tegraexplorer/emmc.c index bd092b3..0799156 100644 --- a/source/meme/external_utils.c +++ b/source/tegraexplorer/emmc.c @@ -1,97 +1,84 @@ -#include "external_utils.h" #include -#include -#include -#include "../gfx/di.h" -#include "../gfx/gfx.h" -#include "../utils/btn.h" -#include "../utils/util.h" -#include "utils.h" -#include "../libs/fatfs/ff.h" -#include "../storage/sdmmc.h" -#include "graphics.h" -#include "../soc/hw_init.h" -#include "../mem/emc.h" -#include "../mem/sdram.h" -#include "../soc/t210.h" -#include "../sec/se.h" +#include "../mem/heap.h" +#include "gfx.h" +#include "fs.h" +#include "emmc.h" #include "../utils/types.h" +#include "../libs/fatfs/ff.h" +#include "../utils/sprintf.h" +#include "../utils/btn.h" +#include "../gfx/gfx.h" +#include "../utils/util.h" #include "../hos/pkg1.h" +#include "../storage/sdmmc.h" #include "../storage/nx_emmc.h" #include "../sec/tsec.h" #include "../soc/t210.h" #include "../soc/fuse.h" #include "../mem/mc.h" - -extern void reloc_patcher(u32 payload_dst, u32 payload_src, u32 payload_size); -extern boot_cfg_t b_cfg; -extern bool sd_mount(); -extern void sd_unmount(); -static bool _key_exists(const void *data) { return memcmp(data, zeros, 0x10); }; -static void _generate_kek(u32 ks, const void *key_source, void *master_key, const void *kek_seed, const void *key_seed); +#include "../sec/se.h" +#include "../soc/hw_init.h" +#include "../mem/emc.h" +#include "../mem/sdram.h" sdmmc_storage_t storage; emmc_part_t *system_part; sdmmc_t sdmmc; +__attribute__ ((aligned (16))) FATFS emmc; +LIST_INIT(gpt); -int launch_payload(char *path, bool update){ - if (!update) gfx_clear_grey(0x1B); - gfx_con_setpos(0, 0); - if (!path) - return 1; +u8 bis_key[4][32]; +short pkg1ver; - if (sd_mount()){ - FIL fp; - if (f_open(&fp, path, FA_READ)){ - EPRINTF("Payload missing!\n"); - return 2; - } +static bool _key_exists(const void *data) { return memcmp(data, zeros, 0x10); }; - void *buf; - u32 size = f_size(&fp); +static void _generate_kek(u32 ks, const void *key_source, void *master_key, const void *kek_seed, const void *key_seed) { + if (!_key_exists(key_source) || !_key_exists(master_key) || !_key_exists(kek_seed)) + return; - if (size < 0x30000) - buf = (void *)RCM_PAYLOAD_ADDR; - else - buf = (void *)COREBOOT_ADDR; - - if (f_read(&fp, buf, size, NULL)){ - f_close(&fp); - - return 3; - } - - f_close(&fp); - - sd_unmount(); - - if (size < 0x30000){ - reloc_patcher(PATCHED_RELOC_ENTRY, EXT_PAYLOAD_ADDR, ALIGN(size, 0x10)); - - reconfig_hw_workaround(false, byte_swap_32(*(u32 *)(buf + size - sizeof(u32)))); - } - else { - reloc_patcher(PATCHED_RELOC_ENTRY, EXT_PAYLOAD_ADDR, 0x7000); - reconfig_hw_workaround(true, 0); - } - - void (*ext_payload_ptr)() = (void *)EXT_PAYLOAD_ADDR; - void (*update_ptr)() = (void *)RCM_PAYLOAD_ADDR; - - msleep(100); - - if (!update) - (*ext_payload_ptr)(); - else { - EMC(EMC_SCRATCH0) |= EMC_HEKA_UPD; - (*update_ptr)(); - } - } - - return 4; + se_aes_key_set(ks, master_key, 0x10); + se_aes_unwrap_key(ks, ks, kek_seed); + se_aes_unwrap_key(ks, ks, key_source); + if (key_seed && _key_exists(key_seed)) + se_aes_unwrap_key(ks, ks, key_seed); } -int dump_biskeys(u8 bis_key[4][32]){ +void print_biskeys(){ + gfx_printf("\n"); + gfx_hexdump(0, bis_key[0], 32); + gfx_hexdump(0, bis_key[1], 32); + gfx_hexdump(0, bis_key[2], 32); +} + +int mount_emmc(char *partition, int biskeynumb){ + f_unmount("emmc:"); + + se_aes_key_set(8, bis_key[biskeynumb] + 0x00, 0x10); + se_aes_key_set(9, bis_key[biskeynumb] + 0x10, 0x10); + + system_part = nx_emmc_part_find(&gpt, partition); + if (!system_part) { + gfx_printf("Failed to locate %s partition.", partition); + return -1; + } + + if (f_mount(&emmc, "emmc:", 1)) { + gfx_printf("Mount failed of %s.", partition); + return -1; + } + + return 0; +} + +short returnpkg1ver(){ + return pkg1ver; +} + +void disconnect_emmc(){ + sdmmc_storage_end(&storage); +} + +int dump_biskeys(){ u8 temp_key[0x10], device_key[0x10] = {0}; tsec_ctxt_t tsec_ctxt; @@ -181,9 +168,7 @@ int dump_biskeys(u8 bis_key[4][32]){ sdmmc_storage_set_mmc_partition(&storage, 0); // Parse eMMC GPT. - LIST_INIT(gpt); nx_emmc_gpt_parse(&gpt, &storage); - /* char part_name[37] = "SYSTEM"; @@ -206,27 +191,19 @@ int dump_biskeys(u8 bis_key[4][32]){ se_aes_key_set(8, bis_key[2] + 0x00, 0x10); se_aes_key_set(9, bis_key[2] + 0x10, 0x10); + /* system_part = nx_emmc_part_find(&gpt, "SYSTEM"); if (!system_part) { gfx_printf("Failed to locate SYSTEM partition."); return -1; } - __attribute__ ((aligned (16))) FATFS emmc_fs; - if (f_mount(&emmc_fs, "emmc:", 1)) { - gfx_printf("Mount failed."); + if (f_mount(&emmc_sys, "system:", 1)) { + gfx_printf("Mount failed of SYSTEM."); return -1; } - return pkg1_id->kb; -} + */ -static void _generate_kek(u32 ks, const void *key_source, void *master_key, const void *kek_seed, const void *key_seed) { - if (!_key_exists(key_source) || !_key_exists(master_key) || !_key_exists(kek_seed)) - return; - - se_aes_key_set(ks, master_key, 0x10); - se_aes_unwrap_key(ks, ks, kek_seed); - se_aes_unwrap_key(ks, ks, key_source); - if (key_seed && _key_exists(key_seed)) - se_aes_unwrap_key(ks, ks, key_seed); + pkg1ver = pkg1_id->kb; + return 0; } \ No newline at end of file diff --git a/source/meme/external_utils.h b/source/tegraexplorer/emmc.h similarity index 76% rename from source/meme/external_utils.h rename to source/tegraexplorer/emmc.h index a90c7f9..751f283 100644 --- a/source/meme/external_utils.h +++ b/source/tegraexplorer/emmc.h @@ -1,21 +1,11 @@ #pragma once -#define RELOC_META_OFF 0x7C -#define PATCHED_RELOC_SZ 0x94 -#define PATCHED_RELOC_STACK 0x40007000 -#define PATCHED_RELOC_ENTRY 0x40010000 -#define EXT_PAYLOAD_ADDR 0xC03C0000 -#define RCM_PAYLOAD_ADDR (EXT_PAYLOAD_ADDR + ALIGN(PATCHED_RELOC_SZ, 0x10)) -#define COREBOOT_ADDR (0xD0000000 - 0x100000) -#define CBFS_DRAM_EN_ADDR 0x4003e000 -#define CBFS_DRAM_MAGIC 0x4452414D // "DRAM" -#define EMC_BASE 0x7001B000 -#define EMC(off) _REG(EMC_BASE, off) - -#include "../utils/types.h" - -int launch_payload(char *path, int update); -int dump_biskeys(u8 bis_key[4][32]); +//int mount_emmc_partition(const char *part, int logicnumb); +int dump_biskeys(); +void print_biskeys(); +int mount_emmc(char *partition, int biskeynumb); +short returnpkg1ver(); +void disconnect_emmc(); static const u8 zeros[0x10] = {0}; diff --git a/source/tegraexplorer/fs.c b/source/tegraexplorer/fs.c new file mode 100644 index 0000000..18468d2 --- /dev/null +++ b/source/tegraexplorer/fs.c @@ -0,0 +1,394 @@ +#include +#include "../mem/heap.h" +#include "gfx.h" +#include "fs.h" +#include "../utils/types.h" +#include "../libs/fatfs/ff.h" +#include "../utils/sprintf.h" +#include "../utils/btn.h" +#include "../gfx/gfx.h" +#include "../utils/util.h" + +fs_entry fileobjects[500]; +char rootpath[10] = ""; +char *currentpath = ""; +char *clipboard = ""; +u8 clipboardhelper = 0; +extern const char sizevalues[4][3]; +extern int launch_payload(char *path); + +menu_item explfilemenu[9] = { + {"-- File Menu --", COLOR_BLUE, -1, 0}, + {"FILE", COLOR_GREEN, -1, 0}, + {"\nSIZE", COLOR_VIOLET, -1, 0}, + {"\n\n\nBack", COLOR_WHITE, -1, 1}, + {"\nCopy to clipboard", COLOR_BLUE, COPY, 1}, + {"Move to clipboard", COLOR_BLUE, MOVE, 1}, + {"\nDelete file\n", COLOR_RED, DELETE, 1}, + {"Launch Payload", COLOR_ORANGE, PAYLOAD, 1}, + {"View Hex", COLOR_GREEN, HEXVIEW, 1} +}; + +void writecurpath(const char *in){ + if (currentpath != NULL) + free(currentpath); + + size_t len = strlen(in) + 1; + currentpath = (char*) malloc (len); + strcpy(currentpath, in); + + strcpy(currentpath, in); +} + +void writeclipboard(const char *in, bool move, bool folder){ + if (clipboard != NULL) + free(clipboard); + + clipboardhelper = 0; + + if (move) + clipboardhelper |= (OPERATIONMOVE); + else + clipboardhelper |= (OPERATIONCOPY); + + if (folder) + clipboardhelper |= (ISDIR); + + size_t len = strlen(in) + 1; + clipboard = (char*) malloc (len); + strcpy(clipboard, in); + + strcpy(clipboard, in); +} + +char *getnextloc(char *current, char *add){ + char *ret; + size_t size = strlen(current) + strlen(add) + 1; + ret = (char*) malloc (size); + if (!strcmp(rootpath, current)) + sprintf(ret, "%s%s", current, add); + else + sprintf(ret, "%s/%s", current, add); + + return ret; +} + +char *getprevloc(char *current){ + char *ret, *temp; + size_t size = strlen(current) + 1; + + ret = (char*) malloc (size); + strcpy(ret, current); + + temp = strrchr(ret, '/'); + memset(temp, '\0', 1); + + if (strlen(rootpath) > strlen(ret)) + strcpy(ret, rootpath); + + return ret; +} + +fs_entry getfileobj(int spot){ + return fileobjects[spot]; +} + +bool checkfile(char* path){ + FRESULT fr; + FILINFO fno; + + fr = f_stat(path, &fno); + + if (fr & FR_NO_FILE) + return false; + else + return true; +} + +void viewbytes(char *path){ + FIL in; + u8 print[2048]; + u32 size; + QWORD offset = 0; + int res; + + clearscreen(); + res = f_open(&in, path, FA_READ | FA_OPEN_EXISTING); + if (res != FR_OK){ + message("File Opening Failed", COLOR_RED); + return; + } + + msleep(200); + + while (1){ + f_lseek(&in, offset * 16); + + res = f_read(&in, &print, 2048 * sizeof(u8), &size); + if (res != FR_OK){ + message("Reading Failed", COLOR_RED); + return; + } + + printbytes(print, size, offset * 16); + res = btn_read(); + + if (!res) + res = btn_wait(); + + if (res & BTN_VOL_DOWN && 2048 * sizeof(u8) == size) + offset++; + if (res & BTN_VOL_UP && offset > 0) + offset--; + if (res & BTN_POWER) + break; + } + f_close(&in); +} + +int copy(const char *locin, const char *locout, bool print){ + FIL in, out; + u64 sizeoffile, sizecopied = 0, totalsize; + UINT temp1, temp2; + u8 *buff; + unsigned int x, y, i = 0; + + gfx_con_getpos(&x, &y); + + if (!strcmp(locin, locout)){ + return 3; + } + + if (f_open(&in, locin, FA_READ | FA_OPEN_EXISTING)){ + return 1; + } + + if (f_open(&out, locout, FA_CREATE_ALWAYS | FA_WRITE)){ + return 2; + } + + buff = malloc (BUFSIZE); + sizeoffile = f_size(&in); + totalsize = sizeoffile; + + while (sizeoffile > 0){ + if (f_read(&in, buff, (sizeoffile > BUFSIZE) ? BUFSIZE : sizeoffile, &temp1)) + return 3; + if (f_write(&out, buff, (sizeoffile > BUFSIZE) ? BUFSIZE : sizeoffile, &temp2)) + return 4; + + if (temp1 != temp2) + return 5; + + sizeoffile -= temp1; + sizecopied += temp1; + + if (print && 10 > i++){ + gfx_printf("%k[%d%%/100%%]%k", COLOR_GREEN, ((sizecopied * 100) / totalsize) ,COLOR_WHITE); + gfx_con_setpos(x, y); + + i = 0; + + if (btn_read() & BTN_VOL_DOWN){ + f_unlink(locout); + break; + } + } + } + + f_close(&in); + f_close(&out); + free(buff); + + return 0; +} + +void copyfile(const char *path, const char *outfolder){ + char *filename = strrchr(path, '/'); + char *outstring; + size_t outstringsize = strlen(filename) + strlen(outfolder) + 2; + int res; + + clearscreen(); + + outstring = (char*) malloc (outstringsize); + + if (strcmp(rootpath, outfolder)) + sprintf(outstring, "%s/%s", outfolder, filename + 1); + else + sprintf(outstring, "%s%s", outfolder, filename + 1); + + gfx_printf("Note:\nTo stop the transfer hold Vol-\n\n%s\nProgress: ", outstring); + + if (clipboardhelper & OPERATIONMOVE){ + if (strcmp(rootpath, "emmc:/")) + f_rename(path, outstring); + else + message("\nMoving in emummc is not allowed!", COLOR_RED); + } + + else if (clipboardhelper & OPERATIONCOPY) { + res = copy(path, outstring, true); + if (res){ + gfx_printf("\n\n%kSomething went wrong while copying!\n\nErrcode: %d%k", COLOR_RED, res, COLOR_WHITE); + btn_wait(); + } + } + + else { + message("\nClipboard is empty!", COLOR_RED); + } + + free (outstring); + clipboardhelper = 0; +} + +u64 getfilesize(char *path){ + FILINFO fno; + f_stat(path, &fno); + return fno.fsize; +} + +void addobject(char* name, int spot, bool isfol, bool isarc){ + size_t length = strlen(name) + 1; + u64 size = 0; + int sizes = 0; + fileobjects[spot].property = 0; + + if (fileobjects[spot].name != NULL){ + free(fileobjects[spot].name); + fileobjects[spot].name = NULL; + } + + fileobjects[spot].name = (char*) malloc (length); + strlcpy(fileobjects[spot].name, name, length); + + if (isfol) + fileobjects[spot].property |= (ISDIR); + else { + size = getfilesize(getnextloc(currentpath, name)); + + while (size > 1024){ + size /= 1024; + sizes++; + } + + if (sizes > 3) + sizes = 0; + + fileobjects[spot].property |= (1 << (4 + sizes)); + fileobjects[spot].size = size; + } + + if (isarc) + fileobjects[spot].property |= (ISARC); +} + +int readfolder(const char *path){ + DIR dir; + FILINFO fno; + int folderamount = 0, res; + + if (res = f_opendir(&dir, path)){ + char errmes[50] = ""; + sprintf(errmes, "Error during f_opendir: %d", res); + message(errmes, COLOR_RED); + } + + while (!f_readdir(&dir, &fno) && fno.fname[0] && folderamount < 500){ + addobject(fno.fname, folderamount++, (fno.fattrib & AM_DIR), (fno.fattrib & AM_ARC)); + } + + f_closedir(&dir); + return folderamount; +} + +int delfile(const char *path, const char *filename){ + char *tempmessage; + size_t tempmessagesize = strlen(filename) + 65; + tempmessage = (char*) malloc (tempmessagesize); + + sprintf(tempmessage, "Are you sure you want to delete:\n%s\n\nPress vol+/- to cancel\n", filename); + if (makewaitmenu(tempmessage, "Press power to delete", 3)){ + f_unlink(path); + return readfolder(currentpath); + } + else + return -1; +} + +void filemenu(const char *startpath){ + int amount, res, tempint; + char temp[100]; + strcpy(rootpath, startpath); + writecurpath(startpath); + amount = readfolder(currentpath); + + if (strcmp(rootpath, "emmc:/")) + explfilemenu[5].property = 1; + else + explfilemenu[5].property = -1; + + while (1){ + res = makefilemenu(fileobjects, amount, currentpath); + if (res < 1){ + if (res == -2){ + if (!strcmp(rootpath, currentpath)) + break; + else { + writecurpath(getprevloc(currentpath)); + amount = readfolder(currentpath); + } + } + if (res == -1){ + copyfile(clipboard, currentpath); + amount = readfolder(currentpath); + } + + if (res == 0) + break; + } + else { + if (fileobjects[res - 1].property & ISDIR){ + writecurpath(getnextloc(currentpath, fileobjects[res - 1].name)); + amount = readfolder(currentpath); + } + else { + strlcpy(explfilemenu[1].name, fileobjects[res - 1].name, 43); + + for (tempint = 4; tempint < 8; tempint++) + if ((fileobjects[res - 1].property & (1 << tempint))) + break; + + sprintf(temp, "\nSize: %d %s", fileobjects[res - 1].size, sizevalues[tempint - 4]); + strcpy(explfilemenu[2].name, temp); + + if (strstr(fileobjects[res - 1].name, ".bin") != NULL) + explfilemenu[7].property = 1; + else + explfilemenu[7].property = -1; + + tempint = makemenu(explfilemenu, 9); + + switch (tempint){ + case COPY: + writeclipboard(getnextloc(currentpath, fileobjects[res - 1].name), false, false); + break; + case MOVE: + writeclipboard(getnextloc(currentpath, fileobjects[res - 1].name), true, false); + break; + case DELETE: + if ((tempint = delfile(getnextloc(currentpath, fileobjects[res - 1].name), fileobjects[res - 1].name)) != -1) + amount = tempint; + break; + case PAYLOAD: + launch_payload(getnextloc(currentpath, fileobjects[res - 1].name)); + break; + case HEXVIEW: + viewbytes(getnextloc(currentpath, fileobjects[res - 1].name)); + break; + } + } + } + } +} \ No newline at end of file diff --git a/source/tegraexplorer/fs.h b/source/tegraexplorer/fs.h new file mode 100644 index 0000000..a44619e --- /dev/null +++ b/source/tegraexplorer/fs.h @@ -0,0 +1,44 @@ +#pragma once +#include "../utils/types.h" + +#define ISDIR (1 << 0) +#define ISARC (1 << 1) + +#define ISGB (1 << 7) +#define ISMB (1 << 6) +#define ISKB (1 << 5) +#define ISB (1 << 4) + +#define OPERATIONCOPY (1 << 1) +#define OPERATIONMOVE (1 << 2) + +#define BUFSIZE 32768 + +/* Bit table for property: +0000 0001: Directory bit +0000 0010: Archive bit +0001 0000: Size component is a Byte +0010 0000: Size component is a KiloByte +0100 0000: Size component is a MegaByte +1000 0000: Size component is a GigaByte : note that this won't surpass gigabytes, but i don't expect people to have a single file that's a terrabyte big +*/ + +typedef struct _fs_entry { + char* name; + u16 size; + u8 property; +} fs_entry; + +enum filemenuoptions { + COPY = 1, + MOVE, + DELETE, + PAYLOAD, + HEXVIEW +}; + +int readfolder(const char *path); +void filemenu(); +bool checkfile(char* path); +u64 getfilesize(char *path); +int copy(const char *locin, const char *locout, bool print); \ No newline at end of file diff --git a/source/tegraexplorer/gfx.c b/source/tegraexplorer/gfx.c new file mode 100644 index 0000000..94c1f82 --- /dev/null +++ b/source/tegraexplorer/gfx.c @@ -0,0 +1,207 @@ +#include +#include +#include +#include "../gfx/gfx.h" +#include "te.h" +#include "../utils/btn.h" +#include "../utils/util.h" +#include "gfx.h" +#include "fs.h" +#include "../mem/minerva.h" + +const char fixedoptions[3][50] = { + "Folder -> previous folder ", + "Clipboard -> Current folder ", + "Return to main menu " +}; + +const char sizevalues[4][3] = { + "B ", + "KB", + "MB", + "GB" +}; + +void clearscreen(){ + gfx_clear_grey(0x1B); + gfx_box(0, 0, 719, 15, COLOR_WHITE); + gfx_con_setpos(0, 0); + gfx_printf("%k%KTegraexplorer%k%K\n", COLOR_DEFAULT, COLOR_WHITE, COLOR_WHITE, COLOR_DEFAULT); +} + +int message(char* message, u32 color){ + clearscreen(); + gfx_printf("%k%s%k", color, message, COLOR_DEFAULT); + return btn_wait(); +} + +int makemenu(menu_item menu[], int menuamount){ + int currentpos = 1, i, res; + clearscreen(); + + while (1){ + gfx_con_setpos(0, 31); + + if (currentpos == 1){ + while (currentpos < menuamount && menu[currentpos - 1].property < 1) + currentpos++; + } + if (currentpos == menuamount){ + while (currentpos > 1 && menu[currentpos - 1].property < 1) + currentpos--; + } + + for (i = 0; i < menuamount; i++){ + if (menu[i].property < 0) + continue; + if (i == currentpos - 1) + gfx_printf("%k%K%s%K\n", COLOR_DEFAULT, COLOR_WHITE, menu[i].name, COLOR_DEFAULT); + else + gfx_printf("%k%s\n", menu[i].color, menu[i].name); + } + gfx_printf("\n%k%s", COLOR_WHITE, menuamount); + + res = btn_wait(); + + if (res & BTN_VOL_UP && currentpos > 1){ + currentpos--; + while(menu[currentpos - 1].property < 1 && currentpos > 1) + currentpos--; + } + + else if (res & BTN_VOL_DOWN && currentpos < menuamount){ + currentpos++; + while(menu[currentpos - 1].property < 1 && currentpos < menuamount) + currentpos++; + } + + else if (res & BTN_POWER) + return menu[currentpos - 1].internal_function; + } +} + +void printbytes(u8 print[], u32 size, u32 offset){ + gfx_con_setpos(0, 31); + gfx_hexdump(offset, print, size * sizeof(u8)); +} + +int makewaitmenu(char *initialmessage, char *hiddenmessage, int timer){ + clearscreen(); + int res; + u32 start = get_tmr_s(); + + gfx_printf(initialmessage); + + while(1){ + res = btn_read(); + + if (res & BTN_VOL_DOWN || res & BTN_VOL_UP) + return 0; + + if (start + timer > get_tmr_s()) + gfx_printf("\r ", timer + start - get_tmr_s()); + + else if (res & BTN_POWER) + return 1; + + else + gfx_printf("\r%k%s%k", COLOR_RED, hiddenmessage, COLOR_WHITE); + } +} + +void printfsentry(fs_entry file, bool highlight, bool refresh){ + int size = 0; + char *display; + int length; + + display = (char*) malloc (38); + memset(display + 37, '\0', 1); + + if (strlen(file.name) > 37){ + strlcpy(display, file.name, 37); + memset(display + 34, '.', 3); + } + else + strcpy(display, file.name); + + if (highlight) + gfx_printf("%K%k", COLOR_WHITE, COLOR_DEFAULT); + else + gfx_printf("%K%k", COLOR_DEFAULT, COLOR_WHITE); + + if (file.property & ISDIR) + gfx_printf("%s\n", display); + else { + for (size = 4; size < 8; size++) + if ((file.property & (1 << size))) + break; + + gfx_printf("%k%s%K", COLOR_VIOLET, display, COLOR_DEFAULT); + } + + if (refresh){ + length = strlen(display); + for (int i = 0; i < (42 - length); i++) + gfx_printf(" "); + } + + if (!(file.property & ISDIR)) + gfx_printf("\a%d\e%s", file.size, sizevalues[size - 4]); + + free(display); +} + +int makefilemenu(fs_entry *files, int amount, char *path){ + int currentpos = -2, i, res = 0, offset = 0, quickoffset = 300; + u32 timer; + bool refresh = false; + clearscreen(); + gfx_con_setpos(544, 0); + gfx_printf("%K%k%d / 500\n%K%k%s%k\n\n", COLOR_WHITE, COLOR_DEFAULT, amount, COLOR_DEFAULT, COLOR_GREEN, path, COLOR_DEFAULT); + while (1){ + gfx_con_setpos(0, 47); + timer = get_tmr_ms(); + for (i = -3 + offset; i < amount && i < 60 + offset; i++){ + if (i < 0){ + if (i == currentpos - 1) + gfx_printf("%k%K%s%K\n", COLOR_ORANGE, COLOR_WHITE, fixedoptions[i + 3], COLOR_DEFAULT); + else + gfx_printf("%k%K%s\n", COLOR_ORANGE, COLOR_DEFAULT, fixedoptions[i + 3]); + } + else + printfsentry(files[i], (i == currentpos - 1), refresh); + } + refresh = false; + gfx_printf("\n%k%K %s %s\n\nTime taken for screen draw: %dms ", COLOR_BLUE, COLOR_DEFAULT, (offset + 60 < amount) ? "v" : " ", (offset > 0) ? "^" : " ", get_tmr_ms() - timer); + + if (quickoffset == 300) + res = btn_wait(); + else { + msleep(quickoffset); + res = btn_read(); + } + + if (res == 0) + quickoffset = 300; + else if (quickoffset > 46) + quickoffset -= 45; + + if ((res & BTN_VOL_UP) && currentpos > -2){ + currentpos--; + if (offset != 0 && currentpos < offset - 2){ + offset--; + refresh = true; + } + } + if ((res & BTN_VOL_DOWN) && currentpos < amount){ + currentpos++; + if (currentpos - offset > 60){ + offset++; + refresh = true; + } + } + if (res & BTN_POWER) + return currentpos; + } + minerva_periodic_training(); +} \ No newline at end of file diff --git a/source/tegraexplorer/gfx.h b/source/tegraexplorer/gfx.h new file mode 100644 index 0000000..5db04b1 --- /dev/null +++ b/source/tegraexplorer/gfx.h @@ -0,0 +1,10 @@ +#pragma once +#include "te.h" +#include "fs.h" + +int makemenu(menu_item menu[], int menuamount); +int message(char* message, u32 color); +void clearscreen(); +int makefilemenu(fs_entry *files, int amount, char *path); +void printbytes(u8 print[], u32 size, u32 offset); +int makewaitmenu(char *initialmessage, char *hiddenmessage, int timer); \ No newline at end of file diff --git a/source/tegraexplorer/te.c b/source/tegraexplorer/te.c new file mode 100644 index 0000000..7c4c682 --- /dev/null +++ b/source/tegraexplorer/te.c @@ -0,0 +1,186 @@ +#include +#include +#include "te.h" +#include "gfx.h" +#include "../utils/util.h" +#include "tools.h" +#include "fs.h" +#include "../utils/btn.h" +#include "emmc.h" + +extern bool sd_mount(); +extern void sd_unmount(); +extern int launch_payload(char *path); +bool sd_mounted; + +menu_item mainmenu[MAINMENU_AMOUNT] = { + {"[SD:/] SD CARD", COLOR_GREEN, SD_CARD, 1}, + {"[SYSTEM:/] EMMC", COLOR_GREEN, EMMC_SYS, 1}, + {"\nMount/Unmount SD", COLOR_WHITE, MOUNT_SD, 1}, + {"Tools", COLOR_VIOLET, TOOLS, 1}, + {"SD format", COLOR_VIOLET, SD_FORMAT, 1}, + {"\nCredits", COLOR_WHITE, CREDITS, 1}, + {"Exit", COLOR_WHITE, EXIT, 1} +}; + +menu_item shutdownmenu[7] = { + {"-- EXIT --\n", COLOR_ORANGE, -1, 0}, + {"Back", COLOR_WHITE, -1, 1}, + {"\nReboot to RCM", COLOR_VIOLET, REBOOT_RCM, 1}, + {"Reboot normally", COLOR_ORANGE, REBOOT_NORMAL, 1}, + {"Power off\n", COLOR_BLUE, POWER_OFF, 1}, + {"Reboot to Hekate", COLOR_GREEN, HEKATE, -1}, + {"Reboot to Atmosphere", COLOR_GREEN, AMS, -1} +}; + +menu_item toolsmenu[5] = { + {"-- TOOLS --\n", COLOR_VIOLET, -1, 0}, + {"Back", COLOR_WHITE, -1, 1}, + {"\nDisplay Console Info", COLOR_GREEN, DISPLAY_INFO, 1}, + {"Display GPIO pins", COLOR_VIOLET, DISPLAY_GPIO, 1}, + {"Dump Firmware", COLOR_BLUE, DUMPFIRMWARE, 1} +}; + +menu_item formatmenu[4] = { + {"-- FORMAT SD --\n", COLOR_RED, -1, 0}, + {"Back\n", COLOR_WHITE, -1, 1}, + {"Format to FAT32", COLOR_RED, FORMAT_ALL_FAT32, 1}, + {"Format for EmuMMC setup", COLOR_RED, FORMAT_EMUMMC, 1} +}; + +void fillmainmenu(){ + int i; + + for (i = 0; i < MAINMENU_AMOUNT; i++){ + switch (i + 1) { + case 1: + case 5: + if (sd_mounted) + mainmenu[i].property = 1; + else + mainmenu[i].property = -1; + break; + case 3: + if (sd_mounted){ + mainmenu[i].property = 2; + strcpy(mainmenu[i].name, "\nUnmount SD"); + } + else { + mainmenu[i].property = 1; + strcpy(mainmenu[i].name, "\nMount SD"); + } + break; + } + } +} + +void te_main(){ + int res; + + dump_biskeys(); + mount_emmc("SYSTEM", 2); + + sd_mounted = sd_mount(); + + while (1){ + fillmainmenu(); + res = makemenu(mainmenu, MAINMENU_AMOUNT); + + switch(res){ + case SD_CARD: + filemenu("SD:/"); + break; + case EMMC_SYS: + if (makewaitmenu("You're about to enter EMMC\nModifying anything here\n can result in a BRICK!\n\nPlease only continue\n if you know what you're doing\n\nPress Vol+/- to return\n", "Press Power to enter", 4)) + filemenu("emmc:/"); + break; + /* + case EMMC_USR: + mount_emmc("USER", 2); + filemenu("emmc:/"); + break; + */ + case MOUNT_SD: + if (sd_mounted){ + sd_mounted = false; + sd_unmount(); + } + else + sd_mounted = sd_mount(); + + break; + + case TOOLS: + res = makemenu(toolsmenu, 5); + + switch(res){ + case DISPLAY_INFO: + displayinfo(); + break; + case DISPLAY_GPIO: + displaygpio(); + break; + case DUMPFIRMWARE: + dumpfirmware(); + break; + } + break; + + case SD_FORMAT: + res = makemenu(formatmenu, 4); + + if (res >= 0){ + if(makewaitmenu("Are you sure you want to format your sd?\nThis will delete everything on your SD card\nThis action is irreversible!\n\nPress Vol+/- to cancel\n", "Press Power to continue", 10)){ + if (format(res)){ + sd_unmount(); + sd_mounted = false; + } + } + } + + break; + + case CREDITS: + message(CREDITS_MESSAGE, COLOR_WHITE); + break; + + case EXIT: + if (sd_mounted){ + if (checkfile("/bootloader/update.bin")) + shutdownmenu[5].property = 1; + else + shutdownmenu[5].property = -1; + + if (checkfile("/atmosphere/reboot_payload.bin")) + shutdownmenu[6].property = 1; + else + shutdownmenu[6].property = -1; + } + else { + shutdownmenu[5].property = -1; + shutdownmenu[6].property = -1; + } + + res = makemenu(shutdownmenu, 7); + + switch(res){ + case REBOOT_RCM: + reboot_rcm(); + + case REBOOT_NORMAL: + reboot_normal(); + + case POWER_OFF: + power_off(); + + case HEKATE: + launch_payload("/bootloader/update.bin"); + + case AMS: + launch_payload("/atmosphere/reboot_payload.bin"); + } //todo declock bpmp + + break; + } + } +} \ No newline at end of file diff --git a/source/tegraexplorer/te.h b/source/tegraexplorer/te.h new file mode 100644 index 0000000..e107de6 --- /dev/null +++ b/source/tegraexplorer/te.h @@ -0,0 +1,46 @@ +#pragma once +#include "../utils/types.h" + +#define MAINMENU_AMOUNT 7 +#define CREDITS_MESSAGE "\nTegraexplorer, made by:\nSuch Meme, Many Skill\n\nProject based on:\nLockpick_RCM\nHekate\n\nCool people:\nshchmue\ndennthecafebabe\nDax" + +typedef struct _menu_item { + char name[50]; + u32 color; + short internal_function; + short property; +} menu_item; + +enum mainmenu_return { + SD_CARD = 1, + EMMC_SYS, + EMMC_USR, + MOUNT_SD, + TOOLS, + SD_FORMAT, + CREDITS, + EXIT +}; + +enum shutdownmenu_return { + REBOOT_RCM = 1, + REBOOT_NORMAL, + POWER_OFF, + HEKATE, + AMS +}; + +enum toolsmenu_return { + DISPLAY_INFO = 1, + DISPLAY_GPIO, + DUMPFIRMWARE +}; + +enum formatmenu_return { + FORMAT_EMUMMC = 0, + FORMAT_ALL_FAT32 +}; + +//menu_item mainmenu[MAINMENU_AMOUNT]; + +void te_main(); \ No newline at end of file diff --git a/source/tegraexplorer/tools.c b/source/tegraexplorer/tools.c new file mode 100644 index 0000000..46089ed --- /dev/null +++ b/source/tegraexplorer/tools.c @@ -0,0 +1,200 @@ +#include "tools.h" +#include "gfx.h" +#include "../libs/fatfs/ff.h" +#include "../gfx/gfx.h" +#include "../utils/btn.h" +#include "../soc/gpio.h" +#include "../utils/util.h" +#include "../utils/types.h" +#include "../libs/fatfs/diskio.h" +#include "../storage/sdmmc.h" +#include "../utils/sprintf.h" +#include "emmc.h" +#include "fs.h" + +extern bool sd_mount(); +extern void sd_unmount(); +extern sdmmc_storage_t sd_storage; + +void displayinfo(){ + clearscreen(); + + FATFS *fs; + DWORD fre_clust, fre_sect, tot_sect; + u32 capacity; + int res; + + gfx_printf("Biskeys:\n"); + print_biskeys(); + + if (!sd_mount()){ + gfx_printf("SD mount failed!\nFailed to display SD info\n"); + } + else { + gfx_printf("Getting storage info: please wait..."); + + res = f_getfree("sd:", &fre_clust, &fs); + gfx_printf("\nResult getfree: %d\n\n", res); + + tot_sect = (fs->n_fatent - 2) * fs->csize; + fre_sect = fre_clust * fs->csize; + capacity = sd_storage.csd.capacity; + + gfx_printf("Entire sd:\nSectors: %d\nSpace total: %d MB\n\n", capacity, capacity / 2048); + gfx_printf("First partition on SD:\nSectors: %d\nSpace total: %d MB\nSpace free: %d MB\n\n", tot_sect, tot_sect / 2048, fre_sect / 2048); + } + + gfx_printf("Press any key to continue"); + btn_wait(); +} + +void displaygpio(){ + int res; + clearscreen(); + gfx_printf("Updates gpio pins ever 50ms:\nPress power to exit"); + msleep(200); + while (1){ + msleep(10); + gfx_con_setpos(0, 63); + + for (int i = 0; i <= 30; i++){ + gfx_printf("\nPort %d: ", i); + for (int i2 = 7; i2 >= 0; i2--) + gfx_printf("%d", gpio_read(i, (1 << i2))); + } + + res = btn_read(); + if (res & BTN_POWER) + break; + } +} + +int dumpfirmware(){ + DIR dir; + FILINFO fno; + bool fail = false; + int ret, amount = 0; + char path[100] = "emmc:/Contents/registered"; + char sdfolderpath[100] = ""; + char syspath[100] = ""; + char sdpath[100] = ""; + short pkg1ver = returnpkg1ver(); + u32 timer = get_tmr_s(); + + clearscreen(); + + gfx_printf("PKG1 version: %d\n", pkg1ver); + + ret = f_mkdir("sd:/tegraexplorer"); + gfx_printf("Creating sd:/tegraexplorer %d\n", ret); + + ret = f_mkdir("sd:/tegraexplorer/Firmware"); + gfx_printf("Creating sd:/tegraexplorer/Firmware %d\n", ret); + + sprintf(sdfolderpath, "sd:/tegraexplorer/Firmware/%d", pkg1ver); + ret = f_mkdir(sdfolderpath); + gfx_printf("Creating %s %d\n", sdfolderpath, ret); + + ret = f_opendir(&dir, path); + gfx_printf("Result opening system:/ %d\n\n%k", ret, COLOR_GREEN); + + while(!f_readdir(&dir, &fno) && fno.fname[0] && !fail){ + sprintf(sdpath, "%s/%s", sdfolderpath, fno.fname); + + if (fno.fattrib & AM_DIR) + sprintf(syspath, "%s/%s/00", path, fno.fname); + else + sprintf(syspath, "%s/%s", path, fno.fname); + + ret = copy(syspath, sdpath, false); + + gfx_printf("%d %s\r", ++amount, fno.fname); + + if (ret != 0) + fail = true; + } + + if (fail) + gfx_printf("%k\n\nDump failed! Aborting (%d)", COLOR_RED, ret); + + gfx_printf("%k\n\nPress any button to continue...\nTime taken: %ds", COLOR_WHITE, get_tmr_s() - timer); + + btn_wait(); + + return fail; +} + +int format(int mode){ + clearscreen(); + int res; + bool fatalerror = false; + DWORD plist[] = {666, 61145088}; + u32 timer, totalsectors; + BYTE work[FF_MAX_SS]; + DWORD clustsize = 16 * 512; + BYTE formatoptions = 0; + formatoptions |= (FM_FAT32); + //formatoptions |= (FM_SFD); + + disconnect_emmc(); + + timer = get_tmr_s(); + totalsectors = sd_storage.csd.capacity; + + if (mode == 0){ + if (totalsectors < 61145088){ + gfx_printf("%k\nNot enough free space for emummc!", COLOR_RED); + fatalerror = true; + } + + if (!fatalerror){ + plist[0] = totalsectors - 61145088; + gfx_printf("\nStarting SD partitioning:\nTotalSectors: %d\nPartition1 (SD): %d\nPartition2 (EMUMMC): %d\n", totalsectors, plist[0], plist[1]); + } + } + else { + plist[0] = totalsectors; + plist[1] = 0; + } + + if (!fatalerror){ + gfx_printf("\nPartitioning SD...\n"); + res = f_fdisk(0, plist, &work); + + if (res){ + gfx_printf("%kf_fdisk returned %d!\n", COLOR_RED, res); + fatalerror = true; + } + else + gfx_printf("Done!\n"); + } + + if (!fatalerror){ + gfx_printf("\n\nFormatting Partition1...\n"); + res = f_mkfs("0:", formatoptions, clustsize, &work, sizeof work); + + if (res){ + gfx_printf("%kf_mkfs returned %d!\n", COLOR_RED, res); + fatalerror = true; + } + else + gfx_printf("Smells like a formatted SD\n\n"); + } + + sd_unmount(); + + if (!fatalerror){ + if (!sd_mount()) + gfx_printf("%kSd failed to mount!\n", COLOR_ORANGE); + else { + gfx_printf("Sd mounted!\n"); + } + } + + dump_biskeys(); + mount_emmc("SYSTEM", 2); + + gfx_printf("\nPress any button to return%k\nTotal time taken: %ds", COLOR_WHITE, (get_tmr_s() - timer)); + btn_wait(); + return fatalerror; +} \ No newline at end of file diff --git a/source/tegraexplorer/tools.h b/source/tegraexplorer/tools.h new file mode 100644 index 0000000..5b8678b --- /dev/null +++ b/source/tegraexplorer/tools.h @@ -0,0 +1,6 @@ +#pragma once + +void displayinfo(); +void displaygpio(); +int format(int mode); +int dumpfirmware(); \ No newline at end of file diff --git a/source/utils/btn.c b/source/utils/btn.c index ed1b39a..678b19f 100644 --- a/source/utils/btn.c +++ b/source/utils/btn.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2018 naehrwert - * Copyright (C) 2018 CTCaer + * 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, @@ -29,7 +29,7 @@ u8 btn_read() res |= BTN_VOL_DOWN; if (!gpio_read(GPIO_PORT_X, GPIO_PIN_6)) res |= BTN_VOL_UP; - if (i2c_recv_byte(4, MAX77620_I2C_ADDR, 0x15) & 0x4) + if (i2c_recv_byte(4, MAX77620_I2C_ADDR, MAX77620_REG_ONOFFSTAT) & 0x4) res |= BTN_POWER; return res; } @@ -61,16 +61,25 @@ u8 btn_wait() u8 btn_wait_timeout(u32 time_ms, u8 mask) { + u8 single_button = mask & BTN_SINGLE; + mask &= ~BTN_SINGLE; + u32 timeout = get_tmr_ms() + time_ms; - u8 res = btn_read() & mask; + u8 res = btn_read(); while (get_tmr_ms() < timeout) { - if (res == mask) - break; + if ((res & mask) == mask) + { + if (single_button && (res & ~mask)) // Undesired button detected. + res = btn_read(); + else + return (res & mask); + } else - res = btn_read() & mask; + res = btn_read(); }; - return res; + // Timed out. + return 0; } diff --git a/source/utils/btn.h b/source/utils/btn.h index ede13ac..d6cad0c 100644 --- a/source/utils/btn.h +++ b/source/utils/btn.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2018 naehrwert - * Copyright (C) 2018 CTCaer + * 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, @@ -23,6 +23,7 @@ #define BTN_POWER (1 << 0) #define BTN_VOL_DOWN (1 << 1) #define BTN_VOL_UP (1 << 2) +#define BTN_SINGLE (1 << 7) u8 btn_read(); u8 btn_wait(); diff --git a/source/utils/dirlist.c b/source/utils/dirlist.c new file mode 100644 index 0000000..2bb8eaf --- /dev/null +++ b/source/utils/dirlist.c @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2018 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include + +#include "../libs/fatfs/ff.h" +#include "../mem/heap.h" +#include "../utils/types.h" + +char *dirlist(const char *directory, const char *pattern, bool includeHiddenFiles) +{ + u8 max_entries = 61; + + int res = 0; + u32 i = 0, j = 0, k = 0; + DIR dir; + FILINFO fno; + + char *dir_entries = (char *)calloc(max_entries, 256); + char *temp = (char *)calloc(1, 256); + + if (!pattern && !f_opendir(&dir, directory)) + { + for (;;) + { + res = f_readdir(&dir, &fno); + if (res || !fno.fname[0]) + break; + if (!(fno.fattrib & AM_DIR) && (fno.fname[0] != '.') && (includeHiddenFiles || !(fno.fattrib & AM_HID))) + { + strcpy(dir_entries + (k * 256), fno.fname); + k++; + if (k > (max_entries - 1)) + break; + } + } + f_closedir(&dir); + } + else if (pattern && !f_findfirst(&dir, &fno, directory, pattern) && fno.fname[0]) + { + do + { + if (!(fno.fattrib & AM_DIR) && (fno.fname[0] != '.') && (includeHiddenFiles || !(fno.fattrib & AM_HID))) + { + strcpy(dir_entries + (k * 256), fno.fname); + k++; + if (k > (max_entries - 1)) + break; + } + res = f_findnext(&dir, &fno); + } while (fno.fname[0] && !res); + f_closedir(&dir); + } + + if (!k) + { + free(temp); + free(dir_entries); + + return NULL; + } + + // Reorder ini files by ASCII ordering. + for (i = 0; i < k - 1 ; i++) + { + for (j = i + 1; j < k; j++) + { + if (strcmp(&dir_entries[i * 256], &dir_entries[j * 256]) > 0) + { + strcpy(temp, &dir_entries[i * 256]); + strcpy(&dir_entries[i * 256], &dir_entries[j * 256]); + strcpy(&dir_entries[j * 256], temp); + } + } + } + + free(temp); + + return dir_entries; +} diff --git a/source/keys/keys.h b/source/utils/dirlist.h similarity index 81% rename from source/keys/keys.h rename to source/utils/dirlist.h index 9be86dd..4fb9af7 100644 --- a/source/keys/keys.h +++ b/source/utils/dirlist.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019 shchmue + * 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, @@ -14,9 +14,6 @@ * along with this program. If not, see . */ -#ifndef _KEYS_H_ -#define _KEYS_H_ +#include "../utils/types.h" -void dump_keys(); - -#endif +char *dirlist(const char *directory, const char *pattern, bool includeHiddenFiles); diff --git a/source/utils/sprintf.c b/source/utils/sprintf.c index 4708078..a310251 100644 --- a/source/utils/sprintf.c +++ b/source/utils/sprintf.c @@ -14,7 +14,7 @@ * along with this program. If not, see . */ -#include "types.h" +#include "sprintf.h" #include @@ -104,8 +104,9 @@ u32 sprintf(char *buffer, const char *fmt, ...) { goto out; default: _putc(buffer + count, '%'); + count++; _putc(buffer + count, *fmt); - count += 2; + count++; break; } } else { diff --git a/source/utils/sprintf.h b/source/utils/sprintf.h index 7cb94ef..18c36b5 100644 --- a/source/utils/sprintf.h +++ b/source/utils/sprintf.h @@ -17,6 +17,8 @@ #ifndef _SPRINTF_H_ #define _SPRINTF_H_ +#include "types.h" + u32 sprintf(char *buffer, const char *fmt, ...); #endif diff --git a/source/utils/types.h b/source/utils/types.h index 3721a1e..0f9f76b 100644 --- a/source/utils/types.h +++ b/source/utils/types.h @@ -20,6 +20,7 @@ #define NULL ((void *)0) #define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1)) +#define ALIGN_DOWN(x, a) (((x) - ((a) - 1)) & ~((a) - 1)) #define MAX(a, b) ((a) > (b) ? (a) : (b)) #define MIN(a, b) ((a) < (b) ? (a) : (b)) @@ -35,7 +36,9 @@ #define KB_FIRMWARE_VERSION_620 6 #define KB_FIRMWARE_VERSION_700 7 #define KB_FIRMWARE_VERSION_810 8 -#define KB_FIRMWARE_VERSION_MAX KB_FIRMWARE_VERSION_810 +#define KB_FIRMWARE_VERSION_900 9 +#define KB_FIRMWARE_VERSION_910 10 +#define KB_FIRMWARE_VERSION_MAX KB_FIRMWARE_VERSION_910 #define HOS_PKG11_MAGIC 0x31314B50 @@ -45,8 +48,8 @@ #define COLOR_GREEN 0xFF40FF00 #define COLOR_BLUE 0xFF00DDFF #define COLOR_VIOLET 0xFF8040FF -#define COLOR_DEFAULT 0xFF1B1B1B #define COLOR_WHITE 0xFFFFFFFF +#define COLOR_DEFAULT 0xFF1B1B1B typedef signed char s8; typedef short s16; @@ -69,6 +72,8 @@ typedef volatile unsigned char vu8; typedef volatile unsigned short vu16; typedef volatile unsigned int vu32; +static const u32 colors[6] = {COLOR_RED, COLOR_ORANGE, COLOR_YELLOW, COLOR_GREEN, COLOR_BLUE, COLOR_VIOLET}; + typedef int bool; #define true 1 #define false 0 @@ -77,14 +82,22 @@ typedef int bool; #define BOOT_CFG_FROM_LAUNCH (1 << 1) #define BOOT_CFG_SEPT_RUN (1 << 7) +#define EXTRA_CFG_DUMP_EMUMMC (1 << 0) + typedef struct __attribute__((__packed__)) _boot_cfg_t { - u8 boot_cfg; - u8 autoboot; - u8 autoboot_list; - u8 extra_cfg; - u32 sd_timeoff; - u8 rsvd[124]; + u8 boot_cfg; + u8 autoboot; + u8 autoboot_list; + u8 extra_cfg; + union + { + struct + { + char id[8]; + }; + u8 xt_str[0x80]; + }; } boot_cfg_t; typedef struct __attribute__((__packed__)) _reloc_meta_t diff --git a/source/utils/util.c b/source/utils/util.c index 6474d5a..cae1981 100644 --- a/source/utils/util.c +++ b/source/utils/util.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2018 naehrwert -* Copyright (C) 2018 CTCaer +* 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, @@ -17,12 +17,18 @@ #include "util.h" #include "../gfx/di.h" +#include "../mem/minerva.h" #include "../power/max77620.h" #include "../rtc/max77620-rtc.h" +#include "../soc/bpmp.h" #include "../soc/i2c.h" #include "../soc/pmc.h" #include "../soc/t210.h" +#define USE_RTC_TIMER + +extern volatile nyx_storage_t *nyx_str; + extern void sd_unmount(); u32 get_tmr_s() @@ -34,7 +40,7 @@ u32 get_tmr_ms() { // The registers must be read with the following order: // RTC_MILLI_SECONDS (0x10) -> RTC_SHADOW_SECONDS (0xC) - return (RTC(APBDEV_RTC_MILLI_SECONDS) | (RTC(APBDEV_RTC_SHADOW_SECONDS) << 10)); + return (RTC(APBDEV_RTC_MILLI_SECONDS) + (RTC(APBDEV_RTC_SHADOW_SECONDS) * 1000)); } u32 get_tmr_us() @@ -42,19 +48,32 @@ u32 get_tmr_us() return TMR(TIMERUS_CNTR_1US); //TIMERUS_CNTR_1US } -void msleep(u32 milliseconds) +void msleep(u32 ms) { - u32 start = RTC(APBDEV_RTC_MILLI_SECONDS) | (RTC(APBDEV_RTC_SHADOW_SECONDS) << 10); - while (((RTC(APBDEV_RTC_MILLI_SECONDS) | (RTC(APBDEV_RTC_SHADOW_SECONDS) << 10)) - start) <= milliseconds) +#ifdef USE_RTC_TIMER + u32 start = RTC(APBDEV_RTC_MILLI_SECONDS) + (RTC(APBDEV_RTC_SHADOW_SECONDS) * 1000); + // Casting to u32 is important! + while (((u32)(RTC(APBDEV_RTC_MILLI_SECONDS) + (RTC(APBDEV_RTC_SHADOW_SECONDS) * 1000)) - start) <= ms) ; +#else + bpmp_msleep(ms); +#endif } -void usleep(u32 microseconds) +void usleep(u32 us) { +#ifdef USE_RTC_TIMER u32 start = TMR(TIMERUS_CNTR_1US); - // Casting to u32 is important! - while ((u32)(TMR(TIMERUS_CNTR_1US) - start) <= microseconds) - ; + + // Check if timer is at upper limits and use BPMP sleep so it doesn't wake up immediately. + if ((start + us) < start) + bpmp_usleep(us); + else + while ((u32)(TMR(TIMERUS_CNTR_1US) - start) <= us) // Casting to u32 is important! + ; +#else + bpmp_usleep(us); +#endif } void exec_cfg(u32 *base, const cfg_op_t *ops, u32 num_ops) @@ -72,37 +91,49 @@ void panic(u32 val) TMR(TIMER_TMR9_TMR_PTV) = TIMER_EN | TIMER_PER_EN; TMR(TIMER_WDT4_CONFIG) = TIMER_SRC(9) | TIMER_PER(1) | TIMER_PMCRESET_EN; TMR(TIMER_WDT4_COMMAND) = TIMER_START_CNT; - while (1) - ; + + while (true) + usleep(1); } void reboot_normal() { + bpmp_mmu_disable(); + sd_unmount(); display_end(); + nyx_str->mtc_cfg.init_done = 0; + panic(0x21); // Bypass fuse programming in package1. } void reboot_rcm() { + bpmp_mmu_disable(); + sd_unmount(); display_end(); + nyx_str->mtc_cfg.init_done = 0; + PMC(APBDEV_PMC_SCRATCH0) = 2; // Reboot into rcm. PMC(APBDEV_PMC_CNTRL) |= PMC_CNTRL_MAIN_RST; while (true) - usleep(1); + bpmp_halt(); } void power_off() { sd_unmount(); + display_end(); // Stop the alarm, in case we injected and powered off too fast. max77620_rtc_stop_alarm(); - //TODO: we should probably make sure all regulators are powered off properly. i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_ONOFFCNFG1, MAX77620_ONOFFCNFG1_PWR_OFF); + + while (true) + bpmp_halt(); } diff --git a/source/utils/util.h b/source/utils/util.h index f261035..55f5f18 100644 --- a/source/utils/util.h +++ b/source/utils/util.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2018 naehrwert - * Copyright (C) 2018 CTCaer + * 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, @@ -19,6 +19,10 @@ #define _UTIL_H_ #include "types.h" +#include "../mem/minerva.h" + +#define NYX_CFG_DUMP (1 << 7) +#define NYX_CFG_MINERVA (1 << 8) #define byte_swap_32(num) (((num >> 24) & 0xff) | ((num << 8) & 0xff0000) | \ ((num >> 8 )& 0xff00) | ((num << 24) & 0xff000000)) @@ -29,11 +33,22 @@ 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(); -void usleep(u32 ticks); -void msleep(u32 milliseconds); +void usleep(u32 us); +void msleep(u32 ms); void panic(u32 val); void reboot_normal(); void reboot_rcm();