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