Compare commits

...

34 Commits
v4.2 ... v4.6

Author SHA1 Message Date
Kostas Missos
4781dc2ab4 Bump version to v4.6 2018-12-17 02:31:44 +02:00
Kostas Missos
e779e53406 Some tiny fixes 2018-12-17 02:31:00 +02:00
Kostas Missos
9f5b97620a Fix return to main when setting an autoboot option
This fixes the issue with "More configs".
2018-12-16 20:21:59 +02:00
Kostas Missos
98d715243a Fixes to update.bin reloc (breaking!)
This fixes a regression in chainloading update.bin where the added check for if it's update or not, didn't copy the reloc code. And the calling was not updated to reflect this.

Additionally:
- Delete the reloc.S relic
- Force running config_hw in case we change hw init again in the future.
2018-12-16 19:04:46 +02:00
Kostas Missos
e809745120 Auto HOS power off disabled by default
Enable it in options
2018-12-16 16:59:25 +02:00
Kostas Missos
0d9aebda7b Fix archive bits V2
It can now fix the whole nintendo folder.

A proposed usage is by using the first option and then the 2nd.
2018-12-16 16:57:49 +02:00
Kostas Missos
5ed875ce90 Make tsec checks faster and cover unluckiest cases
+ changes for readability
2018-12-16 16:55:56 +02:00
Kostas Missos
30d3c76655 Bugfixes 2018-12-16 16:52:38 +02:00
Kostas Missos
949a034500 Merge pull request #166 from balika011/warmboot
Add warmboot patches for efuse checks
2018-12-16 16:23:09 +02:00
balika011
b2893d7fb6 Add warmboot patches for efuse checks
Fixes sleep on downgrade
2018-12-16 15:21:17 +01:00
Kostas Missos
9a3fdd944e Merge pull request #165 from balika011/overclock
Fine-tune dram configs for OC
2018-12-16 16:17:51 +02:00
balika011
8b8f3c564c Fine-tune dram configs
Helps overclocking
2018-12-16 14:51:16 +01:00
Kostas Missos
cd1bb96241 Merge pull request #164 from balika011/ipatches_fix
Fix ipatch printing
2018-12-16 14:54:43 +02:00
balika011
8b59ddf3a8 Fix ipatch printing 2018-12-16 12:35:48 +01:00
Kostas Missos
09bfed9146 Merge pull request #162 from balika011/ipatches_fix
Fix ipatches backup on dumping
2018-12-15 21:45:26 +02:00
Kostas Missos
cbe75d7769 Merge pull request #158 from hyln9/master
Fix debug uart
2018-12-15 21:44:03 +02:00
balika011
dad380344f Fix ipatches backup on dumping 2018-12-15 17:04:14 +01:00
Yule Hou
71b0975730 Fix debug uart 2018-12-08 12:38:59 +08:00
Kostas Missos
20040ae70f Bump version to v4.5 2018-12-02 11:12:19 +02:00
Kostas Missos
22e179d1cf Add 6.2.0 support to tools
- Print TSEC info
- Dump pkg1/2
2018-12-02 11:11:07 +02:00
Kostas Missos
1b075c91bd Name hardcoded TSEC regs 2018-12-01 20:49:31 +02:00
Kostas Missos
1ac7f61f49 Add 6.2.0 exosphere support
And refactor it to its own file.
2018-12-01 20:46:59 +02:00
Kostas Missos
4b3599b2d8 6.2.0 support
Co-Authored-By: nwert <nwert@users.noreply.github.com>
Co-Authored-By: Balázs Triszka <balika011@gmail.com>
2018-11-30 23:20:15 +02:00
Kostas Missos
ceabbb0be0 Refactor hos.c 2018-11-28 21:26:16 +02:00
Kostas Missos
471c1e514c Major refactoring of main.c 2018-11-27 11:45:43 +02:00
Kostas Missos
267a04c4ac Fix HDCP + some bugfixes
Thanks @hexkyz for taking the time to recheck for the missing 6.x changes
2018-11-20 21:32:54 +02:00
Kostas Missos
4eb5b5f91b Name more hardcoded regs/vals 2018-11-10 14:11:42 +02:00
Kostas Missos
cfef8b4f72 Update libminerva to v1.1 2018-11-10 13:30:17 +02:00
Kostas Missos
683ca6af1d Merge pull request #142 from StevenMattera/master
Ignore hidden and dot files when using wildcards.
2018-11-11 01:03:19 +02:00
Steven Mattera
14cdcc1497 Ignore hidden files when using wildcards. 2018-11-08 19:09:14 -05:00
Kostas Missos
ec1bb508b3 Fix minerva build
This is still for testing it out.
The real usage will come later.
2018-11-05 10:54:31 +02:00
Kostas Missos
cae9044c17 Minerva our DRAM trainer
Supports up to 1600MHz and periodic training.

For more check here: https://github.com/CTCaer/minerva_tc
2018-11-04 03:15:32 +02:00
Kostas Missos
5674dad1e9 Merge pull request #125 from Huntereb/master
Add "Silent" auto full power off option
2018-09-30 20:34:13 +03:00
Hunter
288b5c08db Add "Silent" auto full power off option 2018-09-30 13:24:30 -04:00
58 changed files with 15823 additions and 2811 deletions

View File

@@ -6,7 +6,7 @@ include $(DEVKITARM)/base_rules
TARGET := hekate
BLVERSION_MAJOR := 4
BLVERSION_MINOR := 2
BLVERSION_MINOR := 6
BUILD := build
OUTPUT := output
SOURCEDIR = bootloader
@@ -15,6 +15,9 @@ VPATH = $(dir $(wildcard ./$(SOURCEDIR)/*/)) $(dir $(wildcard ./$(SOURCEDIR)/*/*
OBJS = $(addprefix $(BUILD)/$(TARGET)/, \
start.o \
main.o \
fe_emmc_tools.o \
fe_info.o \
fe_tools.o \
config.o \
btn.o \
clock.o \
@@ -23,6 +26,8 @@ OBJS = $(addprefix $(BUILD)/$(TARGET)/, \
gpio.o \
heap.o \
hos.o \
hos_config.o \
secmon_exo.o \
i2c.o \
kfuse.o \
bq24193.o \
@@ -43,9 +48,11 @@ OBJS = $(addprefix $(BUILD)/$(TARGET)/, \
se.o \
tsec.o \
uart.o \
hw_init.o \
dirlist.o \
ini.o \
ianos.o \
smmu.o \
)
OBJS += $(addprefix $(BUILD)/$(TARGET)/, \
@@ -54,9 +61,12 @@ OBJS += $(addprefix $(BUILD)/$(TARGET)/, \
elfload.o elfreloc_arm.o \
)
CUSTOMDEFINES := -DBLVERSIONMJ=$(BLVERSION_MAJOR) -DBLVERSIONMN=$(BLVERSION_MINOR) -DMENU_LOGO_ENABLE
#CUSTOMDEFINES += -DDEBUG
# 0: UART_A, 1: UART_B.
#CUSTOMDEFINES += -DDEBUG_UART_PORT=0
ARCH := -march=armv4t -mtune=arm7tdmi -mthumb -mthumb-interwork
CUSTOMDEFINES := -DBLVERSIONMJ=$(BLVERSION_MAJOR) -DBLVERSIONMN=$(BLVERSION_MINOR)
CUSTOMDEFINES += -DMENU_LOGO_ENABLE #-DDEBUG
CFLAGS = $(ARCH) -O2 -nostdlib -ffunction-sections -fdata-sections -fomit-frame-pointer -fno-inline -std=gnu11 -Wall $(CUSTOMDEFINES)
LDFLAGS = $(ARCH) -nostartfiles -lgcc -Wl,--nmagic,--gc-sections

View File

@@ -37,7 +37,7 @@ There are four possible type of entries. "**[ ]**": Boot entry, "**{ }**": Capti
| bootwait=3 | 0: Disable (It also disables bootlogo. Having **VOL-** pressed since injection goes to menu.), #: Time to wait for **VOL-** to enter menu. |
| customlogo=0 | 0: Use default hekate bootlogo, 1: Use bootlogo.bmp. |
| verification=2 | 0: Disable Backup/Restore verification, 1: Sparse (block based, fast and not 100% reliable), 2: Full (sha256 based, slow and 100% reliable). |
| autohosoff=1 | If woke up from HOS via an rtc alarm, power off completely.|
| autohosoff=1 | 0: Disable, 1: If woke up from HOS via an RTC alarm, shows logo, then powers off completely, 2: No logo, immediately powers off.|
| backlight=100 | Screen backlight level. 0-255. |

View File

@@ -46,7 +46,7 @@ void set_default_configuration()
h_cfg.se_keygen_done = 0;
h_cfg.sbar_time_keeping = 0;
h_cfg.backlight = 100;
h_cfg.autohosoff = 1;
h_cfg.autohosoff = 0;
h_cfg.errors = 0;
}
@@ -156,7 +156,7 @@ int create_config_entry()
return 0;
}
void _config_autoboot_list()
static void _config_autoboot_list(void *ent)
{
gfx_clear_grey(&gfx_ctxt, 0x1B);
gfx_con_setpos(&gfx_con, 0, 0);
@@ -231,6 +231,9 @@ void _config_autoboot_list()
else
EPRINTF("\nConfiguration saving failed!");
gfx_puts(&gfx_con, "\nPress any key...");
ment_t *tmp = (ment_t *)ent;
tmp->data = NULL;
}
else
goto out2;
@@ -251,9 +254,6 @@ out2:;
ini_free(&ini_sections);
sd_unmount();
if (temp_autoboot == NULL)
return;
}
void config_autoboot()
@@ -291,13 +291,13 @@ void config_autoboot()
ments[2].caption = " Disable";
ments[2].data = &boot_values[0];
ments[3].type = MENT_HANDLER;
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 = NULL;
ments[3].data = (void *)0xCAFE;
ments[4].type = MENT_CHGLINE;
@@ -645,10 +645,10 @@ void config_auto_hos_poweroff()
gfx_clear_grey(&gfx_ctxt, 0x1B);
gfx_con_setpos(&gfx_con, 0, 0);
ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * 5);
u32 *hp_values = (u32 *)malloc(sizeof(u32) * 2);
ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * 6);
u32 *hp_values = (u32 *)malloc(sizeof(u32) * 3);
for (u32 j = 0; j < 2; j++)
for (u32 j = 0; j < 3; j++)
{
hp_values[j] = j;
ments[j + 2].type = MENT_DATA;
@@ -660,19 +660,26 @@ void config_auto_hos_poweroff()
ments[1].type = MENT_CHGLINE;
if (h_cfg.autohosoff)
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[4], 0, sizeof(ment_t));
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(&gfx_con, &menu);

View File

@@ -45,7 +45,7 @@ int ini_parse(link_t *dst, char *ini_path, bool is_dir)
if (is_dir)
{
filelist = dirlist(filename, "*.ini");
filelist = dirlist(filename, "*.ini", false);
if (!filelist)
{
free(filename);
@@ -84,7 +84,7 @@ int ini_parse(link_t *dst, char *ini_path, bool is_dir)
lblen = strlen(lbuf);
// Remove trailing newline.
if (lbuf[lblen - 1] == '\n')
if (lbuf[lblen - 1] == '\n' || lbuf[lblen - 1] == '\r')
lbuf[lblen - 1] = 0;
if (lblen > 2 && lbuf[0] == '[') // Create new section.
@@ -96,7 +96,7 @@ int ini_parse(link_t *dst, char *ini_path, bool is_dir)
}
u32 i;
for (i = 0; i < lblen && lbuf[i] != '\n' && lbuf[i] != ']'; i++)
for (i = 0; i < lblen && lbuf[i] != ']' && lbuf[i] != '\n' && lbuf[i] != '\r'; i++)
;
lbuf[i] = 0;
@@ -114,7 +114,7 @@ int ini_parse(link_t *dst, char *ini_path, bool is_dir)
}
u32 i;
for (i = 0; i < lblen && lbuf[i] != '\n' && lbuf[i] != '}'; i++)
for (i = 0; i < lblen && lbuf[i] != '}' && lbuf[i] != '\n' && lbuf[i] != '\r'; i++)
;
lbuf[i] = 0;
@@ -132,7 +132,7 @@ int ini_parse(link_t *dst, char *ini_path, bool is_dir)
}
u32 i;
for (i = 0; i < lblen && lbuf[i] != '\n'; i++)
for (i = 0; i < lblen && lbuf[i] != '\n' && lbuf[i] != '\r'; i++)
;
lbuf[i] = 0;
@@ -155,7 +155,7 @@ int ini_parse(link_t *dst, char *ini_path, bool is_dir)
else if (csec && csec->type == INI_CHOICE) //Extract key/value.
{
u32 i;
for (i = 0; i < lblen && lbuf[i] != '\n' && lbuf[i] != '='; i++)
for (i = 0; i < lblen && lbuf[i] != '=' && lbuf[i] != '\n' && lbuf[i] != '\r'; i++)
;
lbuf[i] = 0;
@@ -230,9 +230,9 @@ void ini_free_section(ini_sec_t *cfg)
{
free(kv->key);
free(kv->val);
free(kv);
//free(kv);
}
free(cfg);
//free(cfg);
cfg = NULL;
}

View File

@@ -0,0 +1,887 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (c) 2018 Rajko Stojadinovic
* Copyright (c) 2018 CTCaer
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <string.h>
#include <stdlib.h>
#include "fe_emmc_tools.h"
#include "../config/config.h"
#include "../gfx/gfx.h"
#include "../gfx/tui.h"
#include "../libs/fatfs/ff.h"
#include "../mem/heap.h"
#include "../sec/se.h"
#include "../storage/nx_emmc.h"
#include "../storage/sdmmc.h"
#include "../utils/btn.h"
#include "../utils/util.h"
extern sdmmc_t sd_sdmmc;
extern sdmmc_storage_t sd_storage;
extern FATFS sd_fs;
extern hekate_config h_cfg;
extern gfx_ctxt_t gfx_ctxt;
extern gfx_con_t gfx_con;
extern bool sd_mount();
extern void sd_unmount();
extern void emmcsn_path_impl(char *path, char *sub_dir, char *filename, sdmmc_storage_t *storage);
//TODO: Create more macros (info, header, debug, etc) with different colors and utilize them for consistency.
#define EPRINTF(text) gfx_printf(&gfx_con, "%k"text"%k\n", 0xFFFF0000, 0xFFCCCCCC)
#define EPRINTFARGS(text, args...) gfx_printf(&gfx_con, "%k"text"%k\n", 0xFFFF0000, args, 0xFFCCCCCC)
#define WPRINTF(text) gfx_printf(&gfx_con, "%k"text"%k\n", 0xFFFFDD00, 0xFFCCCCCC)
#define WPRINTFARGS(text, args...) gfx_printf(&gfx_con, "%k"text"%k\n", 0xFFFFDD00, args, 0xFFCCCCCC)
static int _dump_emmc_verify(sdmmc_storage_t *storage, u32 lba_curr, char *outFilename, emmc_part_t *part)
{
FIL fp;
u32 btn = 0;
u32 prevPct = 200;
int res = 0;
u8 hashEm[0x20];
u8 hashSd[0x20];
if (f_open(&fp, outFilename, FA_READ) == FR_OK)
{
u32 totalSectorsVer = (u32)((u64)f_size(&fp) >> (u64)9);
u32 numSectorsPerIter = 0;
if (totalSectorsVer > 0x200000)
numSectorsPerIter = 8192; //4MB Cache
else
numSectorsPerIter = 512; //256KB Cache
u8 *bufEm = (u8 *)calloc(numSectorsPerIter, NX_EMMC_BLOCKSIZE);
u8 *bufSd = (u8 *)calloc(numSectorsPerIter, NX_EMMC_BLOCKSIZE);
u32 pct = (u64)((u64)(lba_curr - part->lba_start) * 100u) / (u64)(part->lba_end - part->lba_start);
tui_pbar(&gfx_con, 0, gfx_con.y, pct, 0xFF96FF00, 0xFF155500);
u32 num = 0;
while (totalSectorsVer > 0)
{
num = MIN(totalSectorsVer, numSectorsPerIter);
if (!sdmmc_storage_read(storage, lba_curr, num, bufEm))
{
gfx_con.fntsz = 16;
EPRINTFARGS("\nFailed to read %d blocks (@LBA %08X),\nfrom eMMC!\n\nVerification failed..\n",
num, lba_curr);
free(bufEm);
free(bufSd);
f_close(&fp);
return 1;
}
if (f_read(&fp, bufSd, num << 9, NULL))
{
gfx_con.fntsz = 16;
EPRINTFARGS("\nFailed to read %d blocks (@LBA %08X),\nfrom sd card!\n\nVerification failed..\n", num, lba_curr);
free(bufEm);
free(bufSd);
f_close(&fp);
return 1;
}
switch (h_cfg.verification)
{
case 1:
res = memcmp32sparse((u32 *)bufEm, (u32 *)bufSd, num << 9);
break;
case 2:
default:
se_calc_sha256(&hashEm, bufEm, num << 9);
se_calc_sha256(&hashSd, bufSd, num << 9);
res = memcmp(hashEm, hashSd, 0x10);
break;
}
if (res)
{
gfx_con.fntsz = 16;
EPRINTFARGS("\nSD card and eMMC data (@LBA %08X),\ndo not match!\n\nVerification failed..\n", lba_curr);
free(bufEm);
free(bufSd);
f_close(&fp);
return 1;
}
pct = (u64)((u64)(lba_curr - part->lba_start) * 100u) / (u64)(part->lba_end - part->lba_start);
if (pct != prevPct)
{
tui_pbar(&gfx_con, 0, gfx_con.y, pct, 0xFF96FF00, 0xFF155500);
prevPct = pct;
}
lba_curr += num;
totalSectorsVer -= num;
btn = btn_wait_timeout(0, BTN_VOL_DOWN | BTN_VOL_UP);
if ((btn & BTN_VOL_DOWN) && (btn & BTN_VOL_UP))
{
gfx_con.fntsz = 16;
WPRINTF("\n\nThe verification was cancelled!");
EPRINTF("\nPress any key...\n");
msleep(1500);
free(bufEm);
free(bufSd);
f_close(&fp);
return 0;
}
}
free(bufEm);
free(bufSd);
f_close(&fp);
tui_pbar(&gfx_con, 0, gfx_con.y, pct, 0xFFCCCCCC, 0xFF555555);
return 0;
}
else
{
gfx_con.fntsz = 16;
EPRINTF("\nFile not found or could not be loaded.\n\nVerification failed..\n");
return 1;
}
}
static int _dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t *part)
{
static const u32 FAT32_FILESIZE_LIMIT = 0xFFFFFFFF;
static const u32 SECTORS_TO_MIB_COEFF = 11;
u32 multipartSplitSize = (1u << 31);
u32 totalSectors = part->lba_end - part->lba_start + 1;
u32 currPartIdx = 0;
u32 numSplitParts = 0;
u32 maxSplitParts = 0;
u32 btn = 0;
bool isSmallSdCard = false;
bool partialDumpInProgress = false;
int res = 0;
char *outFilename = sd_path;
u32 sdPathLen = strlen(sd_path);
FIL partialIdxFp;
char partialIdxFilename[12];
memcpy(partialIdxFilename, "partial.idx", 12);
gfx_con.fntsz = 8;
gfx_printf(&gfx_con, "\nSD Card free space: %d MiB, Total backup size %d MiB\n\n",
sd_fs.free_clst * sd_fs.csize >> SECTORS_TO_MIB_COEFF,
totalSectors >> SECTORS_TO_MIB_COEFF);
// 1GB parts for sd cards 8GB and less.
if ((sd_storage.csd.capacity >> (20 - sd_storage.csd.read_blkbits)) <= 8192)
multipartSplitSize = (1u << 30);
// Maximum parts fitting the free space available.
maxSplitParts = (sd_fs.free_clst * sd_fs.csize) / (multipartSplitSize / 512);
// Check if the USER partition or the RAW eMMC fits the sd card free space.
if (totalSectors > (sd_fs.free_clst * sd_fs.csize))
{
isSmallSdCard = true;
gfx_printf(&gfx_con, "%k\nSD card free space is smaller than total backup size.%k\n", 0xFFFFBA00, 0xFFCCCCCC);
if (!maxSplitParts)
{
gfx_con.fntsz = 16;
EPRINTF("Not enough free space for Partial Backup.");
return 0;
}
}
// Check if we are continuing a previous raw eMMC or USER partition backup in progress.
if (f_open(&partialIdxFp, partialIdxFilename, FA_READ) == FR_OK && totalSectors > (FAT32_FILESIZE_LIMIT / NX_EMMC_BLOCKSIZE))
{
gfx_printf(&gfx_con, "%kFound Partial Backup in progress. Continuing...%k\n\n", 0xFFAEFD14, 0xFFCCCCCC);
partialDumpInProgress = true;
// Force partial dumping, even if the card is larger.
isSmallSdCard = true;
f_read(&partialIdxFp, &currPartIdx, 4, NULL);
f_close(&partialIdxFp);
if (!maxSplitParts)
{
gfx_con.fntsz = 16;
EPRINTF("Not enough free space for Partial Backup.");
return 0;
}
// Increase maxSplitParts to accommodate previously backed up parts.
maxSplitParts += currPartIdx;
}
else if (isSmallSdCard)
gfx_printf(&gfx_con, "%kPartial Backup enabled (with %d MiB parts)...%k\n\n", 0xFFFFBA00, multipartSplitSize >> 20, 0xFFCCCCCC);
// Check if filesystem is FAT32 or the free space is smaller and backup in parts.
if (((sd_fs.fs_type != FS_EXFAT) && totalSectors > (FAT32_FILESIZE_LIMIT / NX_EMMC_BLOCKSIZE)) | isSmallSdCard)
{
u32 multipartSplitSectors = multipartSplitSize / NX_EMMC_BLOCKSIZE;
numSplitParts = (totalSectors + multipartSplitSectors - 1) / multipartSplitSectors;
outFilename[sdPathLen++] = '.';
if (!partialDumpInProgress)
{
outFilename[sdPathLen] = '0';
if (numSplitParts >= 10)
{
outFilename[sdPathLen + 1] = '0';
outFilename[sdPathLen + 2] = 0;
}
else
outFilename[sdPathLen + 1] = 0;
}
// Continue from where we left, if Partial Backup in progress.
else
{
if (numSplitParts >= 10 && currPartIdx < 10)
{
outFilename[sdPathLen] = '0';
itoa(currPartIdx, &outFilename[sdPathLen + 1], 10);
}
else
itoa(currPartIdx, &outFilename[sdPathLen], 10);
}
}
FIL fp;
gfx_con_getpos(&gfx_con, &gfx_con.savedx, &gfx_con.savedy);
if (!f_open(&fp, outFilename, FA_READ))
{
f_close(&fp);
gfx_con.fntsz = 16;
WPRINTF("An existing backup has been detected!");
WPRINTF("Press POWER to Continue.\nPress VOL to go to the menu.\n");
msleep(500);
if (!(btn_wait() & BTN_POWER))
return 0;
gfx_con.fntsz = 8;
gfx_clear_partial_grey(&gfx_ctxt, 0x1B, gfx_con.savedy, 48);
}
gfx_con_setpos(&gfx_con, gfx_con.savedx, gfx_con.savedy);
gfx_printf(&gfx_con, "Filename: %s\n\n", outFilename);
res = f_open(&fp, outFilename, FA_CREATE_ALWAYS | FA_WRITE);
if (res)
{
gfx_con.fntsz = 16;
EPRINTFARGS("Error (%d) creating file %s.\n", res, outFilename);
return 0;
}
u32 numSectorsPerIter = 0;
if (totalSectors > 0x200000)
numSectorsPerIter = 8192;
else
numSectorsPerIter = 512;
u8 *buf = (u8 *)calloc(numSectorsPerIter, NX_EMMC_BLOCKSIZE);
u32 lba_curr = part->lba_start;
u32 lbaStartPart = part->lba_start;
u32 bytesWritten = 0;
u32 prevPct = 200;
int retryCount = 0;
// Continue from where we left, if Partial Backup in progress.
if (partialDumpInProgress)
{
lba_curr += currPartIdx * (multipartSplitSize / NX_EMMC_BLOCKSIZE);
totalSectors -= currPartIdx * (multipartSplitSize / NX_EMMC_BLOCKSIZE);
lbaStartPart = lba_curr; // Update the start LBA for verification.
}
u64 totalSize = (u64)((u64)totalSectors << 9);
if (!isSmallSdCard && sd_fs.fs_type == FS_EXFAT)
f_lseek(&fp, totalSize);
else
f_lseek(&fp, MIN(totalSize, multipartSplitSize));
f_lseek(&fp, 0);
u32 num = 0;
u32 pct = 0;
while (totalSectors > 0)
{
if (numSplitParts != 0 && bytesWritten >= multipartSplitSize)
{
f_close(&fp);
memset(&fp, 0, sizeof(fp));
currPartIdx++;
if (h_cfg.verification)
{
// Verify part.
if (_dump_emmc_verify(storage, lbaStartPart, outFilename, part))
{
EPRINTF("\nPress any key and try again...\n");
free(buf);
return 0;
}
}
if (numSplitParts >= 10 && currPartIdx < 10)
{
outFilename[sdPathLen] = '0';
itoa(currPartIdx, &outFilename[sdPathLen + 1], 10);
}
else
itoa(currPartIdx, &outFilename[sdPathLen], 10);
// Always create partial.idx before next part, in case a fatal error occurs.
if (isSmallSdCard)
{
// Create partial backup index file.
if (f_open(&partialIdxFp, partialIdxFilename, FA_CREATE_ALWAYS | FA_WRITE) == FR_OK)
{
f_write(&partialIdxFp, &currPartIdx, 4, NULL);
f_close(&partialIdxFp);
}
else
{
gfx_con.fntsz = 16;
EPRINTF("\nError creating partial.idx file.\n");
free(buf);
return 0;
}
// More parts to backup that do not currently fit the sd card free space or fatal error.
if (currPartIdx >= maxSplitParts)
{
gfx_puts(&gfx_con, "\n\n1. Press any key to unmount SD Card.\n\
2. Remove SD Card and move files to free space.\n\
Don\'t move the partial.idx file!\n\
3. Re-insert SD Card.\n\
4. Select the SAME option again to continue.\n");
gfx_con.fntsz = 16;
free(buf);
return 1;
}
}
// Create next part.
gfx_con_setpos(&gfx_con, gfx_con.savedx, gfx_con.savedy);
gfx_printf(&gfx_con, "Filename: %s\n\n", outFilename);
lbaStartPart = lba_curr;
res = f_open(&fp, outFilename, FA_CREATE_ALWAYS | FA_WRITE);
if (res)
{
gfx_con.fntsz = 16;
EPRINTFARGS("Error (%d) creating file %s.\n", res, outFilename);
free(buf);
return 0;
}
bytesWritten = 0;
totalSize = (u64)((u64)totalSectors << 9);
f_lseek(&fp, MIN(totalSize, multipartSplitSize));
f_lseek(&fp, 0);
}
retryCount = 0;
num = MIN(totalSectors, numSectorsPerIter);
while (!sdmmc_storage_read(storage, lba_curr, num, buf))
{
EPRINTFARGS("Error reading %d blocks @ LBA %08X,\nfrom eMMC (try %d), retrying...",
num, lba_curr, ++retryCount);
msleep(150);
if (retryCount >= 3)
{
gfx_con.fntsz = 16;
EPRINTFARGS("\nFailed to read %d blocks @ LBA %08X\nfrom eMMC. Aborting..\n",
num, lba_curr);
EPRINTF("\nPress any key and try again...\n");
free(buf);
f_close(&fp);
f_unlink(outFilename);
return 0;
}
}
res = f_write(&fp, buf, NX_EMMC_BLOCKSIZE * num, NULL);
if (res)
{
gfx_con.fntsz = 16;
EPRINTFARGS("\nFatal error (%d) when writing to SD Card", res);
EPRINTF("\nPress any key and try again...\n");
free(buf);
f_close(&fp);
f_unlink(outFilename);
return 0;
}
pct = (u64)((u64)(lba_curr - part->lba_start) * 100u) / (u64)(part->lba_end - part->lba_start);
if (pct != prevPct)
{
tui_pbar(&gfx_con, 0, gfx_con.y, pct, 0xFFCCCCCC, 0xFF555555);
prevPct = pct;
}
lba_curr += num;
totalSectors -= num;
bytesWritten += num * NX_EMMC_BLOCKSIZE;
// Force a flush after a lot of data if not splitting.
if (numSplitParts == 0 && bytesWritten >= multipartSplitSize)
{
f_sync(&fp);
bytesWritten = 0;
}
btn = btn_wait_timeout(0, BTN_VOL_DOWN | BTN_VOL_UP);
if ((btn & BTN_VOL_DOWN) && (btn & BTN_VOL_UP))
{
gfx_con.fntsz = 16;
WPRINTF("\n\nThe backup was cancelled!");
EPRINTF("\nPress any key...\n");
msleep(1500);
free(buf);
f_close(&fp);
f_unlink(outFilename);
return 0;
}
}
tui_pbar(&gfx_con, 0, gfx_con.y, 100, 0xFFCCCCCC, 0xFF555555);
// Backup operation ended successfully.
free(buf);
f_close(&fp);
if (h_cfg.verification)
{
// Verify last part or single file backup.
if (_dump_emmc_verify(storage, lbaStartPart, outFilename, part))
{
EPRINTF("\nPress any key and try again...\n");
return 0;
}
else
tui_pbar(&gfx_con, 0, gfx_con.y, 100, 0xFF96FF00, 0xFF155500);
}
gfx_con.fntsz = 16;
// Remove partial backup index file if no fatal errors occurred.
if (isSmallSdCard)
{
f_unlink(partialIdxFilename);
gfx_printf(&gfx_con, "%k\n\nYou can now join the files\nand get the complete eMMC RAW GPP backup.", 0xFFCCCCCC);
}
gfx_puts(&gfx_con, "\n\n");
return 1;
}
typedef enum
{
PART_BOOT = (1 << 0),
PART_SYSTEM = (1 << 1),
PART_USER = (1 << 2),
PART_RAW = (1 << 3),
PART_GP_ALL = (1 << 7)
} emmcPartType_t;
static void _dump_emmc_selected(emmcPartType_t dumpType)
{
int res = 0;
u32 timer = 0;
gfx_clear_partial_grey(&gfx_ctxt, 0x1B, 0, 1256);
tui_sbar(&gfx_con, true);
gfx_con_setpos(&gfx_con, 0, 0);
if (!sd_mount())
goto out;
gfx_puts(&gfx_con, "Checking for available free space...\n\n");
// Get SD Card free space for Partial Backup.
f_getfree("", &sd_fs.free_clst, NULL);
sdmmc_storage_t storage;
sdmmc_t sdmmc;
if (!sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4))
{
EPRINTF("Failed to init eMMC.");
goto out;
}
int i = 0;
char sdPath[80];
// Create Restore folders, if they do not exist.
emmcsn_path_impl(sdPath, "/restore", "", &storage);
emmcsn_path_impl(sdPath, "/restore/partitions", "", &storage);
timer = get_tmr_s();
if (dumpType & PART_BOOT)
{
const u32 BOOT_PART_SIZE = storage.ext_csd.boot_mult << 17;
emmc_part_t bootPart;
memset(&bootPart, 0, sizeof(bootPart));
bootPart.lba_start = 0;
bootPart.lba_end = (BOOT_PART_SIZE / NX_EMMC_BLOCKSIZE) - 1;
for (i = 0; i < 2; i++)
{
memcpy(bootPart.name, "BOOT", 5);
bootPart.name[4] = (u8)('0' + i);
bootPart.name[5] = 0;
gfx_printf(&gfx_con, "%k%02d: %s (%07X-%07X)%k\n", 0xFF00DDFF, i,
bootPart.name, bootPart.lba_start, bootPart.lba_end, 0xFFCCCCCC);
sdmmc_storage_set_mmc_partition(&storage, i + 1);
emmcsn_path_impl(sdPath, "", bootPart.name, &storage);
res = _dump_emmc_part(sdPath, &storage, &bootPart);
}
}
if ((dumpType & PART_SYSTEM) || (dumpType & PART_USER) || (dumpType & PART_RAW))
{
sdmmc_storage_set_mmc_partition(&storage, 0);
if ((dumpType & PART_SYSTEM) || (dumpType & PART_USER))
{
LIST_INIT(gpt);
nx_emmc_gpt_parse(&gpt, &storage);
LIST_FOREACH_ENTRY(emmc_part_t, part, &gpt, link)
{
if ((dumpType & PART_USER) == 0 && !strcmp(part->name, "USER"))
continue;
if ((dumpType & PART_SYSTEM) == 0 && strcmp(part->name, "USER"))
continue;
gfx_printf(&gfx_con, "%k%02d: %s (%07X-%07X)%k\n", 0xFF00DDFF, i++,
part->name, part->lba_start, part->lba_end, 0xFFCCCCCC);
emmcsn_path_impl(sdPath, "/partitions", part->name, &storage);
res = _dump_emmc_part(sdPath, &storage, part);
// If a part failed, don't continue.
if (!res)
break;
}
nx_emmc_gpt_free(&gpt);
}
if (dumpType & PART_RAW)
{
// Get GP partition size dynamically.
const u32 RAW_AREA_NUM_SECTORS = storage.sec_cnt;
emmc_part_t rawPart;
memset(&rawPart, 0, sizeof(rawPart));
rawPart.lba_start = 0;
rawPart.lba_end = RAW_AREA_NUM_SECTORS - 1;
strcpy(rawPart.name, "rawnand.bin");
{
gfx_printf(&gfx_con, "%k%02d: %s (%07X-%07X)%k\n", 0xFF00DDFF, i++,
rawPart.name, rawPart.lba_start, rawPart.lba_end, 0xFFCCCCCC);
emmcsn_path_impl(sdPath, "", rawPart.name, &storage);
res = _dump_emmc_part(sdPath, &storage, &rawPart);
}
}
}
gfx_putc(&gfx_con, '\n');
timer = get_tmr_s() - timer;
gfx_printf(&gfx_con, "Time taken: %dm %ds.\n", timer / 60, timer % 60);
sdmmc_storage_end(&storage);
if (res && h_cfg.verification)
gfx_printf(&gfx_con, "\n%kFinished and verified!%k\nPress any key...\n", 0xFF96FF00, 0xFFCCCCCC);
else if (res)
gfx_printf(&gfx_con, "\nFinished! Press any key...\n");
out:
sd_unmount();
btn_wait();
}
void dump_emmc_system() { _dump_emmc_selected(PART_SYSTEM); }
void dump_emmc_user() { _dump_emmc_selected(PART_USER); }
void dump_emmc_boot() { _dump_emmc_selected(PART_BOOT); }
void dump_emmc_rawnand() { _dump_emmc_selected(PART_RAW); }
static int _restore_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t *part)
{
static const u32 SECTORS_TO_MIB_COEFF = 11;
u32 totalSectors = part->lba_end - part->lba_start + 1;
u32 lbaStartPart = part->lba_start;
int res = 0;
char *outFilename = sd_path;
gfx_con.fntsz = 8;
FIL fp;
gfx_printf(&gfx_con, "\nFilename: %s\n", outFilename);
res = f_open(&fp, outFilename, FA_READ);
if (res)
{
if (res != FR_NO_FILE)
EPRINTFARGS("Error (%d) while opening backup. Continuing...\n", res);
else
WPRINTFARGS("Error (%d) file not found. Continuing...\n", res);
gfx_con.fntsz = 16;
return 0;
}
//TODO: Should we keep this check?
else if (((u32)((u64)f_size(&fp) >> (u64)9)) != totalSectors)
{
gfx_con.fntsz = 16;
EPRINTF("Size of the SD Card backup does not match,\neMMC's selected part size.\n");
f_close(&fp);
return 0;
}
else
gfx_printf(&gfx_con, "\nTotal restore size: %d MiB.\n\n", ((u32)((u64)f_size(&fp) >> (u64)9)) >> SECTORS_TO_MIB_COEFF);
u32 numSectorsPerIter = 0;
if (totalSectors > 0x200000)
numSectorsPerIter = 8192; //4MB Cache
else
numSectorsPerIter = 512; //256KB Cache
u8 *buf = (u8 *)calloc(numSectorsPerIter, NX_EMMC_BLOCKSIZE);
u32 lba_curr = part->lba_start;
u32 bytesWritten = 0;
u32 prevPct = 200;
int retryCount = 0;
u32 num = 0;
u32 pct = 0;
while (totalSectors > 0)
{
retryCount = 0;
num = MIN(totalSectors, numSectorsPerIter);
res = f_read(&fp, buf, NX_EMMC_BLOCKSIZE * num, NULL);
if (res)
{
gfx_con.fntsz = 16;
EPRINTFARGS("\nFatal error (%d) when reading from SD Card", res);
EPRINTF("\nYour device may be in an inoperative state!\n\nPress any key and try again now...\n");
free(buf);
f_close(&fp);
return 0;
}
while (!sdmmc_storage_write(storage, lba_curr, num, buf))
{
EPRINTFARGS("Error writing %d blocks @ LBA %08X\nto eMMC (try %d), retrying...",
num, lba_curr, ++retryCount);
msleep(150);
if (retryCount >= 3)
{
gfx_con.fntsz = 16;
EPRINTFARGS("\nFailed to write %d blocks @ LBA %08X\nfrom eMMC. Aborting..\n",
num, lba_curr);
EPRINTF("\nYour device may be in an inoperative state!\n\nPress any key and try again...\n");
free(buf);
f_close(&fp);
return 0;
}
}
pct = (u64)((u64)(lba_curr - part->lba_start) * 100u) / (u64)(part->lba_end - part->lba_start);
if (pct != prevPct)
{
tui_pbar(&gfx_con, 0, gfx_con.y, pct, 0xFFCCCCCC, 0xFF555555);
prevPct = pct;
}
lba_curr += num;
totalSectors -= num;
bytesWritten += num * NX_EMMC_BLOCKSIZE;
}
tui_pbar(&gfx_con, 0, gfx_con.y, 100, 0xFFCCCCCC, 0xFF555555);
// Restore operation ended successfully.
free(buf);
f_close(&fp);
if (h_cfg.verification)
{
// Verify restored data.
if (_dump_emmc_verify(storage, lbaStartPart, outFilename, part))
{
EPRINTF("\nPress any key and try again...\n");
return 0;
}
else
tui_pbar(&gfx_con, 0, gfx_con.y, 100, 0xFF96FF00, 0xFF155500);
}
gfx_con.fntsz = 16;
gfx_puts(&gfx_con, "\n\n");
return 1;
}
static void _restore_emmc_selected(emmcPartType_t restoreType)
{
int res = 0;
u32 timer = 0;
gfx_clear_partial_grey(&gfx_ctxt, 0x1B, 0, 1256);
tui_sbar(&gfx_con, true);
gfx_con_setpos(&gfx_con, 0, 0);
gfx_printf(&gfx_con, "%kThis is a dangerous operation\nand may render your device inoperative!\n\n", 0xFFFFDD00);
gfx_printf(&gfx_con, "Are you really sure?\n\n%k", 0xFFCCCCCC);
if ((restoreType & PART_BOOT) || (restoreType & PART_GP_ALL))
{
gfx_puts(&gfx_con, "The mode you selected will only restore\nthe ");
if (restoreType & PART_BOOT)
gfx_puts(&gfx_con, "boot ");
gfx_puts(&gfx_con, "partitions that it can find.\n");
gfx_puts(&gfx_con, "If it is not found, it will be skipped\nand continue with the next.\n\n");
}
gfx_con_getpos(&gfx_con, &gfx_con.savedx, &gfx_con.savedy);
u8 value = 10;
while (value > 0)
{
gfx_con_setpos(&gfx_con, gfx_con.savedx, gfx_con.savedy);
gfx_printf(&gfx_con, "%kWait... (%ds) %k", 0xFF888888, value, 0xFFCCCCCC);
msleep(1000);
value--;
}
gfx_con_setpos(&gfx_con, gfx_con.savedx, gfx_con.savedy);
gfx_puts(&gfx_con, "Press POWER to Continue.\nPress VOL to go to the menu.\n\n\n");
u32 btn = btn_wait();
if (!(btn & BTN_POWER))
goto out;
if (!sd_mount())
goto out;
sdmmc_storage_t storage;
sdmmc_t sdmmc;
if (!sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4))
{
EPRINTF("Failed to init eMMC.");
goto out;
}
int i = 0;
char sdPath[80];
timer = get_tmr_s();
if (restoreType & PART_BOOT)
{
const u32 BOOT_PART_SIZE = storage.ext_csd.boot_mult << 17;
emmc_part_t bootPart;
memset(&bootPart, 0, sizeof(bootPart));
bootPart.lba_start = 0;
bootPart.lba_end = (BOOT_PART_SIZE / NX_EMMC_BLOCKSIZE) - 1;
for (i = 0; i < 2; i++)
{
memcpy(bootPart.name, "BOOT", 4);
bootPart.name[4] = (u8)('0' + i);
bootPart.name[5] = 0;
gfx_printf(&gfx_con, "%k%02d: %s (%07X-%07X)%k\n", 0xFF00DDFF, i,
bootPart.name, bootPart.lba_start, bootPart.lba_end, 0xFFCCCCCC);
sdmmc_storage_set_mmc_partition(&storage, i + 1);
emmcsn_path_impl(sdPath, "/restore", bootPart.name, &storage);
res = _restore_emmc_part(sdPath, &storage, &bootPart);
}
}
if (restoreType & PART_GP_ALL)
{
sdmmc_storage_set_mmc_partition(&storage, 0);
LIST_INIT(gpt);
nx_emmc_gpt_parse(&gpt, &storage);
LIST_FOREACH_ENTRY(emmc_part_t, part, &gpt, link)
{
gfx_printf(&gfx_con, "%k%02d: %s (%07X-%07X)%k\n", 0xFF00DDFF, i++,
part->name, part->lba_start, part->lba_end, 0xFFCCCCCC);
emmcsn_path_impl(sdPath, "/restore/partitions/", part->name, &storage);
res = _restore_emmc_part(sdPath, &storage, part);
}
nx_emmc_gpt_free(&gpt);
}
if (restoreType & PART_RAW)
{
// Get GP partition size dynamically.
const u32 RAW_AREA_NUM_SECTORS = storage.sec_cnt;
emmc_part_t rawPart;
memset(&rawPart, 0, sizeof(rawPart));
rawPart.lba_start = 0;
rawPart.lba_end = RAW_AREA_NUM_SECTORS - 1;
strcpy(rawPart.name, "rawnand.bin");
{
gfx_printf(&gfx_con, "%k%02d: %s (%07X-%07X)%k\n", 0xFF00DDFF, i++,
rawPart.name, rawPart.lba_start, rawPart.lba_end, 0xFFCCCCCC);
emmcsn_path_impl(sdPath, "/restore", rawPart.name, &storage);
res = _restore_emmc_part(sdPath, &storage, &rawPart);
}
}
gfx_putc(&gfx_con, '\n');
timer = get_tmr_s() - timer;
gfx_printf(&gfx_con, "Time taken: %dm %ds.\n", timer / 60, timer % 60);
sdmmc_storage_end(&storage);
if (res && h_cfg.verification)
gfx_printf(&gfx_con, "\n%kFinished and verified!%k\nPress any key...\n", 0xFF96FF00, 0xFFCCCCCC);
else if (res)
gfx_printf(&gfx_con, "\nFinished! Press any key...\n");
out:
sd_unmount();
btn_wait();
}
void restore_emmc_boot() { _restore_emmc_selected(PART_BOOT); }
void restore_emmc_rawnand() { _restore_emmc_selected(PART_RAW); }
void restore_emmc_gpp_parts() { _restore_emmc_selected(PART_GP_ALL); }

View File

@@ -0,0 +1,30 @@
/*
* Copyright (c) 2018 Rajko Stojadinovic
* Copyright (c) 2018 CTCaer
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _FE_EMMC_TOOLS_H_
#define _FE_EMMC_TOOLS_H_
void dump_emmc_system();
void dump_emmc_user();
void dump_emmc_boot();
void dump_emmc_rawnand();
void restore_emmc_boot();
void restore_emmc_rawnand();
void restore_emmc_gpp_parts();
#endif

View File

@@ -0,0 +1,706 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (c) 2018 CTCaer
* Copyright (c) 2018 balika011
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <string.h>
#include "fe_info.h"
#include "../gfx/gfx.h"
#include "../hos/hos.h"
#include "../hos/pkg1.h"
#include "../libs/fatfs/ff.h"
#include "../mem/heap.h"
#include "../power/bq24193.h"
#include "../power/max17050.h"
#include "../sec/tsec.h"
#include "../soc/fuse.h"
#include "../soc/i2c.h"
#include "../soc/kfuse.h"
#include "../soc/smmu.h"
#include "../soc/t210.h"
#include "../storage/mmc.h"
#include "../storage/nx_emmc.h"
#include "../storage/sdmmc.h"
#include "../utils/btn.h"
#include "../utils/util.h"
extern gfx_ctxt_t gfx_ctxt;
extern gfx_con_t gfx_con;
extern sdmmc_storage_t sd_storage;
extern FATFS sd_fs;
extern bool sd_mount();
extern void sd_unmount();
extern int sd_save_to_file(void *buf, u32 size, const char *filename);
extern void emmcsn_path_impl(char *path, char *sub_dir, char *filename, sdmmc_storage_t *storage);
//TODO: Create more macros (info, header, debug, etc) with different colors and utilize them for consistency.
#define EPRINTF(text) gfx_printf(&gfx_con, "%k"text"%k\n", 0xFFFF0000, 0xFFCCCCCC)
#define EPRINTFARGS(text, args...) gfx_printf(&gfx_con, "%k"text"%k\n", 0xFFFF0000, args, 0xFFCCCCCC)
#define WPRINTF(text) gfx_printf(&gfx_con, "%k"text"%k\n", 0xFFFFDD00, 0xFFCCCCCC)
#define WPRINTFARGS(text, args...) gfx_printf(&gfx_con, "%k"text"%k\n", 0xFFFFDD00, args, 0xFFCCCCCC)
void print_fuseinfo()
{
gfx_clear_partial_grey(&gfx_ctxt, 0x1B, 0, 1256);
gfx_con_setpos(&gfx_con, 0, 0);
u32 burntFuses = 0;
for (u32 i = 0; i < 32; i++)
{
if ((fuse_read_odm(7) >> i) & 1)
burntFuses++;
}
gfx_printf(&gfx_con, "\nSKU: %X - ", FUSE(FUSE_SKU_INFO));
switch (fuse_read_odm(4) & 3)
{
case 0:
gfx_printf(&gfx_con, "Retail\n");
break;
case 3:
gfx_printf(&gfx_con, "Dev\n");
break;
}
gfx_printf(&gfx_con, "Sdram ID: %d\n", (fuse_read_odm(4) >> 3) & 0x1F);
gfx_printf(&gfx_con, "Burnt fuses: %d\n", burntFuses);
gfx_printf(&gfx_con, "Secure key: %08X%08X%08X%08X\n\n\n",
byte_swap_32(FUSE(FUSE_PRIVATE_KEY0)), byte_swap_32(FUSE(FUSE_PRIVATE_KEY1)),
byte_swap_32(FUSE(FUSE_PRIVATE_KEY2)), byte_swap_32(FUSE(FUSE_PRIVATE_KEY3)));
gfx_printf(&gfx_con, "%k(Unlocked) fuse cache:\n\n%k", 0xFF00DDFF, 0xFFCCCCCC);
gfx_hexdump(&gfx_con, 0x7000F900, (u8 *)0x7000F900, 0x2FC);
gfx_puts(&gfx_con, "Press POWER to dump them to SD Card.\nPress VOL to go to the menu.\n");
u32 btn = btn_wait();
if (btn & BTN_POWER)
{
if (sd_mount())
{
char path[64];
emmcsn_path_impl(path, "/dumps", "fuses.bin", NULL);
if (!sd_save_to_file((u8 *)0x7000F900, 0x2FC, path))
gfx_puts(&gfx_con, "\nDone!\n");
sd_unmount();
}
btn_wait();
}
}
void print_kfuseinfo()
{
gfx_clear_partial_grey(&gfx_ctxt, 0x1B, 0, 1256);
gfx_con_setpos(&gfx_con, 0, 0);
gfx_printf(&gfx_con, "%kKFuse contents:\n\n%k", 0xFF00DDFF, 0xFFCCCCCC);
u32 buf[KFUSE_NUM_WORDS];
if (!kfuse_read(buf))
EPRINTF("CRC fail.");
else
gfx_hexdump(&gfx_con, 0, (u8 *)buf, KFUSE_NUM_WORDS * 4);
gfx_puts(&gfx_con, "\nPress POWER to dump them to SD Card.\nPress VOL to go to the menu.\n");
u32 btn = btn_wait();
if (btn & BTN_POWER)
{
if (sd_mount())
{
char path[64];
emmcsn_path_impl(path, "/dumps", "kfuses.bin", NULL);
if (!sd_save_to_file((u8 *)buf, KFUSE_NUM_WORDS * 4, path))
gfx_puts(&gfx_con, "\nDone!\n");
sd_unmount();
}
btn_wait();
}
}
void print_mmc_info()
{
gfx_clear_partial_grey(&gfx_ctxt, 0x1B, 0, 1256);
gfx_con_setpos(&gfx_con, 0, 0);
static const u32 SECTORS_TO_MIB_COEFF = 11;
sdmmc_storage_t storage;
sdmmc_t sdmmc;
if (!sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4))
{
EPRINTF("Failed to init eMMC.");
goto out;
}
else
{
u16 card_type;
u32 speed = 0;
gfx_printf(&gfx_con, "%kCID:%k\n", 0xFF00DDFF, 0xFFCCCCCC);
switch (storage.csd.mmca_vsn)
{
case 0: /* MMC v1.0 - v1.2 */
case 1: /* MMC v1.4 */
gfx_printf(&gfx_con,
" Vendor ID: %03X\n"
" Model: %c%c%c%c%c%c%c\n"
" HW rev: %X\n"
" FW rev: %X\n"
" S/N: %03X\n"
" Month/Year: %02d/%04d\n\n",
storage.cid.manfid,
storage.cid.prod_name[0], storage.cid.prod_name[1], storage.cid.prod_name[2],
storage.cid.prod_name[3], storage.cid.prod_name[4], storage.cid.prod_name[5],
storage.cid.prod_name[6], storage.cid.hwrev, storage.cid.fwrev,
storage.cid.serial, storage.cid.month, storage.cid.year);
break;
case 2: /* MMC v2.0 - v2.2 */
case 3: /* MMC v3.1 - v3.3 */
case 4: /* MMC v4 */
gfx_printf(&gfx_con,
" Vendor ID: %X\n"
" Card/BGA: %X\n"
" OEM ID: %02X\n"
" Model: %c%c%c%c%c%c\n"
" Prd Rev: %X\n"
" S/N: %04X\n"
" Month/Year: %02d/%04d\n\n",
storage.cid.manfid, storage.cid.card_bga, storage.cid.oemid,
storage.cid.prod_name[0], storage.cid.prod_name[1], storage.cid.prod_name[2],
storage.cid.prod_name[3], storage.cid.prod_name[4], storage.cid.prod_name[5],
storage.cid.prv, storage.cid.serial, storage.cid.month, storage.cid.year);
break;
default:
EPRINTFARGS("eMMC has unknown MMCA version %d", storage.csd.mmca_vsn);
break;
}
if (storage.csd.structure == 0)
EPRINTF("Unknown CSD structure.");
else
{
gfx_printf(&gfx_con, "%kExtended CSD V1.%d:%k\n",
0xFF00DDFF, storage.ext_csd.ext_struct, 0xFFCCCCCC);
card_type = storage.ext_csd.card_type;
u8 card_type_support[96];
u8 pos_type = 0;
card_type_support[0] = 0;
if (card_type & EXT_CSD_CARD_TYPE_HS_26)
{
memcpy(card_type_support, "HS26", 4);
speed = (26 << 16) | 26;
pos_type += 4;
}
if (card_type & EXT_CSD_CARD_TYPE_HS_52)
{
memcpy(card_type_support + pos_type, ", HS52", 6);
speed = (52 << 16) | 52;
pos_type += 6;
}
if (card_type & EXT_CSD_CARD_TYPE_DDR_1_8V)
{
memcpy(card_type_support + pos_type, ", DDR52_1.8V", 12);
speed = (52 << 16) | 104;
pos_type += 12;
}
if (card_type & EXT_CSD_CARD_TYPE_HS200_1_8V)
{
memcpy(card_type_support + pos_type, ", HS200_1.8V", 12);
speed = (200 << 16) | 200;
pos_type += 12;
}
if (card_type & EXT_CSD_CARD_TYPE_HS400_1_8V)
{
memcpy(card_type_support + pos_type, ", HS400_1.8V", 12);
speed = (200 << 16) | 400;
pos_type += 12;
}
card_type_support[pos_type] = 0;
gfx_printf(&gfx_con,
" Spec Version: %02X\n"
" Extended Rev: 1.%d\n"
" Dev Version: %d\n"
" Cmd Classes: %02X\n"
" Capacity: %s\n"
" Max Rate: %d MB/s (%d MHz)\n"
" Current Rate: %d MB/s\n"
" Type Support: ",
storage.csd.mmca_vsn, storage.ext_csd.rev, storage.ext_csd.dev_version, storage.csd.cmdclass,
storage.csd.capacity == (4096 * 512) ? "High" : "Low", speed & 0xFFFF, (speed >> 16) & 0xFFFF,
storage.csd.busspeed);
gfx_con.fntsz = 8;
gfx_printf(&gfx_con, "%s", card_type_support);
gfx_con.fntsz = 16;
gfx_printf(&gfx_con, "\n\n", card_type_support);
u32 boot_size = storage.ext_csd.boot_mult << 17;
u32 rpmb_size = storage.ext_csd.rpmb_mult << 17;
gfx_printf(&gfx_con, "%keMMC Partitions:%k\n", 0xFF00DDFF, 0xFFCCCCCC);
gfx_printf(&gfx_con, " 1: %kBOOT0 %k\n Size: %5d KiB (LBA Sectors: 0x%07X)\n", 0xFF96FF00, 0xFFCCCCCC,
boot_size / 1024, boot_size / 1024 / 512);
gfx_put_small_sep(&gfx_con);
gfx_printf(&gfx_con, " 2: %kBOOT1 %k\n Size: %5d KiB (LBA Sectors: 0x%07X)\n", 0xFF96FF00, 0xFFCCCCCC,
boot_size / 1024, boot_size / 1024 / 512);
gfx_put_small_sep(&gfx_con);
gfx_printf(&gfx_con, " 3: %kRPMB %k\n Size: %5d KiB (LBA Sectors: 0x%07X)\n", 0xFF96FF00, 0xFFCCCCCC,
rpmb_size / 1024, rpmb_size / 1024 / 512);
gfx_put_small_sep(&gfx_con);
gfx_printf(&gfx_con, " 0: %kGPP (USER) %k\n Size: %5d MiB (LBA Sectors: 0x%07X)\n\n", 0xFF96FF00, 0xFFCCCCCC,
storage.sec_cnt >> SECTORS_TO_MIB_COEFF, storage.sec_cnt);
gfx_put_small_sep(&gfx_con);
gfx_printf(&gfx_con, "%kGPP (eMMC USER) partition table:%k\n", 0xFF00DDFF, 0xFFCCCCCC);
sdmmc_storage_set_mmc_partition(&storage, 0);
LIST_INIT(gpt);
nx_emmc_gpt_parse(&gpt, &storage);
int gpp_idx = 0;
LIST_FOREACH_ENTRY(emmc_part_t, part, &gpt, link)
{
gfx_printf(&gfx_con, " %02d: %k%s%k\n Size: % 5d MiB (LBA Sectors 0x%07X)\n LBA Range: %08X-%08X\n",
gpp_idx++, 0xFFAEFD14, part->name, 0xFFCCCCCC, (part->lba_end - part->lba_start + 1) >> SECTORS_TO_MIB_COEFF,
part->lba_end - part->lba_start + 1, part->lba_start, part->lba_end);
gfx_put_small_sep(&gfx_con);
}
nx_emmc_gpt_free(&gpt);
}
}
out:
sdmmc_storage_end(&storage);
btn_wait();
}
void print_sdcard_info()
{
static const u32 SECTORS_TO_MIB_COEFF = 11;
gfx_clear_partial_grey(&gfx_ctxt, 0x1B, 0, 1256);
gfx_con_setpos(&gfx_con, 0, 0);
if (sd_mount())
{
u32 capacity;
gfx_printf(&gfx_con, "%kCard IDentification:%k\n", 0xFF00DDFF, 0xFFCCCCCC);
gfx_printf(&gfx_con,
" Vendor ID: %02x\n"
" OEM ID: %c%c\n"
" Model: %c%c%c%c%c\n"
" HW rev: %X\n"
" FW rev: %X\n"
" S/N: %08x\n"
" Month/Year: %02d/%04d\n\n",
sd_storage.cid.manfid, (sd_storage.cid.oemid >> 8) & 0xFF, sd_storage.cid.oemid & 0xFF,
sd_storage.cid.prod_name[0], sd_storage.cid.prod_name[1], sd_storage.cid.prod_name[2],
sd_storage.cid.prod_name[3], sd_storage.cid.prod_name[4],
sd_storage.cid.hwrev, sd_storage.cid.fwrev, sd_storage.cid.serial,
sd_storage.cid.month, sd_storage.cid.year);
gfx_printf(&gfx_con, "%kCard-Specific Data V%d.0:%k\n", 0xFF00DDFF, sd_storage.csd.structure + 1, 0xFFCCCCCC);
capacity = sd_storage.csd.capacity >> (20 - sd_storage.csd.read_blkbits);
gfx_printf(&gfx_con,
" Cmd Classes: %02X\n"
" Capacity: %d MiB\n"
" Bus Width: %d\n"
" Current Rate: %d MB/s (%d MHz)\n"
" Speed Class: %d\n"
" UHS Grade: U%d\n"
" Video Class: V%d\n"
" App perf class: A%d\n"
" Write Protect: %d\n\n",
sd_storage.csd.cmdclass, capacity,
sd_storage.ssr.bus_width, sd_storage.csd.busspeed, sd_storage.csd.busspeed * 2,
sd_storage.ssr.speed_class, sd_storage.ssr.uhs_grade, sd_storage.ssr.video_class,
sd_storage.ssr.app_class, sd_storage.csd.write_protect);
gfx_puts(&gfx_con, "Acquiring FAT volume info...\n\n");
f_getfree("", &sd_fs.free_clst, NULL);
gfx_printf(&gfx_con, "%kFound %s volume:%k\n Free: %d MiB\n Cluster: %d KiB\n",
0xFF00DDFF, sd_fs.fs_type == FS_EXFAT ? "exFAT" : "FAT32", 0xFFCCCCCC,
sd_fs.free_clst * sd_fs.csize >> SECTORS_TO_MIB_COEFF, (sd_fs.csize > 1) ? (sd_fs.csize >> 1) : 512);
sd_unmount();
}
btn_wait();
}
void print_tsec_key()
{
gfx_clear_partial_grey(&gfx_ctxt, 0x1B, 0, 1256);
gfx_con_setpos(&gfx_con, 0, 0);
u32 retries = 0;
u32 key_ver_max = 3;
tsec_ctxt_t tsec_ctxt;
sdmmc_storage_t storage;
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);
sdmmc_storage_end(&storage);
const pkg1_id_t *pkg1_id = pkg1_identify(pkg1);
if (!pkg1_id)
{
EPRINTFARGS("Unknown package1 version for reading\nTSEC firmware (= '%s').",
(char *)pkg1 + 0x10);
goto out_wait;
}
u8 keys[0x10 * 3];
tsec_ctxt.size = 0xF00;
tsec_ctxt.fw = (u8 *)pkg1 + pkg1_id->tsec_off;
tsec_ctxt.pkg1 = pkg1;
tsec_ctxt.pkg11_off = pkg1_id->pkg11_off;
tsec_ctxt.secmon_base = pkg1_id->secmon_base;
if (pkg1_id->kb >= KB_FIRMWARE_VERSION_620)
{
tsec_ctxt.size = 0x2900;
u8 *tsec_paged = (u8 *)page_alloc(3);
memcpy(tsec_paged, (void *)tsec_ctxt.fw, tsec_ctxt.size);
tsec_ctxt.fw = tsec_paged;
key_ver_max = 1;
}
for (u32 i = 1; i <= key_ver_max; i++)
{
tsec_ctxt.key_ver = i;
int res = 0;
while (tsec_query(keys + ((i - 1) * 0x10), pkg1_id->kb, &tsec_ctxt) < 0)
{
if (pkg1_id->kb <= KB_FIRMWARE_VERSION_600)
memset(keys + ((i - 1) * 0x10), 0x00, 0x10);
else
memset(keys, 0x00, 0x30);
retries++;
if (retries > 3)
{
res = -1;
break;
}
}
if (pkg1_id->kb <= KB_FIRMWARE_VERSION_600)
{
gfx_printf(&gfx_con, "%kTSEC key %d: %k", 0xFF00DDFF, i, 0xFFCCCCCC);
if (res >= 0)
{
for (u32 j = 0; j < 0x10; j++)
gfx_printf(&gfx_con, "%02X", keys[((i - 1) * 0x10) + j]);
}
else
EPRINTFARGS("ERROR %X", res);
gfx_putc(&gfx_con, '\n');
}
else
{
gfx_printf(&gfx_con, "%kTSEC key: %k", 0xFF00DDFF, 0xFFCCCCCC);
if (res >= 0)
{
for (u32 j = 0; j < 0x10; j++)
gfx_printf(&gfx_con, "%02X", keys[j]);
gfx_putc(&gfx_con, '\n');
gfx_printf(&gfx_con, "%kTSEC root: %k", 0xFF00DDFF, 0xFFCCCCCC);
for (u32 j = 0; j < 0x10; j++)
gfx_printf(&gfx_con, "%02X", keys[0x10 + j]);
}
else
EPRINTFARGS("ERROR %X", res);
gfx_putc(&gfx_con, '\n');
}
}
gfx_puts(&gfx_con, "\nPress POWER to dump them to SD Card.\nPress VOL to go to the menu.\n");
u32 btn = btn_wait();
if (btn & BTN_POWER)
{
if (sd_mount())
{
char path[64];
emmcsn_path_impl(path, "/dumps", "tsec_keys.bin", NULL);
if (!sd_save_to_file(keys, 0x10 * 3, path))
gfx_puts(&gfx_con, "\nDone!\n");
sd_unmount();
}
}
else
goto out;
out_wait:
btn_wait();
out:
free(pkg1);
}
void print_fuel_gauge_info()
{
int value = 0;
gfx_printf(&gfx_con, "%kFuel Gauge IC Info:\n%k", 0xFF00DDFF, 0xFFCCCCCC);
max17050_get_property(MAX17050_Age, &value);
gfx_printf(&gfx_con, "Age: %3d%\n", value);
max17050_get_property(MAX17050_RepSOC, &value);
gfx_printf(&gfx_con, "Capacity now: %3d%\n", value >> 8);
max17050_get_property(MAX17050_RepCap, &value);
gfx_printf(&gfx_con, "Capacity now: %4d mAh\n", value);
max17050_get_property(MAX17050_FullCAP, &value);
gfx_printf(&gfx_con, "Capacity full: %4d mAh\n", value);
max17050_get_property(MAX17050_DesignCap, &value);
gfx_printf(&gfx_con, "Capacity (design): %4d mAh\n", value);
max17050_get_property(MAX17050_Current, &value);
if (value >= 0)
gfx_printf(&gfx_con, "Current now: %d mA\n", value / 1000);
else
gfx_printf(&gfx_con, "Current now: -%d mA\n", ~value / 1000);
max17050_get_property(MAX17050_AvgCurrent, &value);
if (value >= 0)
gfx_printf(&gfx_con, "Current average: %d mA\n", value / 1000);
else
gfx_printf(&gfx_con, "Current average: -%d mA\n", ~value / 1000);
max17050_get_property(MAX17050_VCELL, &value);
gfx_printf(&gfx_con, "Voltage now: %4d mV\n", value);
max17050_get_property(MAX17050_OCVInternal, &value);
gfx_printf(&gfx_con, "Voltage open-circuit: %4d mV\n", value);
max17050_get_property(MAX17050_MinVolt, &value);
gfx_printf(&gfx_con, "Min voltage reached: %4d mV\n", value);
max17050_get_property(MAX17050_MaxVolt, &value);
gfx_printf(&gfx_con, "Max voltage reached: %4d mV\n", value);
max17050_get_property(MAX17050_V_empty, &value);
gfx_printf(&gfx_con, "Empty voltage (design): %4d mV\n", value);
max17050_get_property(MAX17050_TEMP, &value);
if (value >= 0)
gfx_printf(&gfx_con, "Battery temperature: %d.%d oC\n", value / 10, value % 10);
else
gfx_printf(&gfx_con, "Battery temperature: -%d.%d oC\n", ~value / 10, (~value) % 10);
}
void print_battery_charger_info()
{
int value = 0;
gfx_printf(&gfx_con, "%k\n\nBattery Charger IC Info:\n%k", 0xFF00DDFF, 0xFFCCCCCC);
bq24193_get_property(BQ24193_InputVoltageLimit, &value);
gfx_printf(&gfx_con, "Input voltage limit: %4d mV\n", value);
bq24193_get_property(BQ24193_InputCurrentLimit, &value);
gfx_printf(&gfx_con, "Input current limit: %4d mA\n", value);
bq24193_get_property(BQ24193_SystemMinimumVoltage, &value);
gfx_printf(&gfx_con, "Min voltage limit: %4d mV\n", value);
bq24193_get_property(BQ24193_FastChargeCurrentLimit, &value);
gfx_printf(&gfx_con, "Fast charge current limit: %4d mA\n", value);
bq24193_get_property(BQ24193_ChargeVoltageLimit, &value);
gfx_printf(&gfx_con, "Charge voltage limit: %4d mV\n", value);
bq24193_get_property(BQ24193_ChargeStatus, &value);
gfx_printf(&gfx_con, "Charge status: ");
switch (value)
{
case 0:
gfx_printf(&gfx_con, "Not charging\n");
break;
case 1:
gfx_printf(&gfx_con, "Pre-charging\n");
break;
case 2:
gfx_printf(&gfx_con, "Fast charging\n");
break;
case 3:
gfx_printf(&gfx_con, "Charge terminated\n");
break;
default:
gfx_printf(&gfx_con, "Unknown (%d)\n", value);
break;
}
bq24193_get_property(BQ24193_TempStatus, &value);
gfx_printf(&gfx_con, "Temperature status: ");
switch (value)
{
case 0:
gfx_printf(&gfx_con, "Normal\n");
break;
case 2:
gfx_printf(&gfx_con, "Warm\n");
break;
case 3:
gfx_printf(&gfx_con, "Cool\n");
break;
case 5:
gfx_printf(&gfx_con, "Cold\n");
break;
case 6:
gfx_printf(&gfx_con, "Hot\n");
break;
default:
gfx_printf(&gfx_con, "Unknown (%d)\n", value);
break;
}
}
void print_battery_info()
{
gfx_clear_partial_grey(&gfx_ctxt, 0x1B, 0, 1256);
gfx_con_setpos(&gfx_con, 0, 0);
print_fuel_gauge_info();
print_battery_charger_info();
u8 *buf = (u8 *)malloc(0x100 * 2);
gfx_printf(&gfx_con, "%k\n\nBattery Fuel Gauge Registers:\n%k", 0xFF00DDFF, 0xFFCCCCCC);
for (int i = 0; i < 0x200; i += 2)
{
i2c_recv_buf_small(buf + i, 2, I2C_1, 0x36, i >> 1);
usleep(2500);
}
gfx_hexdump(&gfx_con, 0, (u8 *)buf, 0x200);
gfx_puts(&gfx_con, "\nPress POWER to dump them to SD Card.\nPress VOL to go to the menu.\n");
u32 btn = btn_wait();
if (btn & BTN_POWER)
{
if (sd_mount())
{
char path[64];
emmcsn_path_impl(path, "/dumps", "fuel_gauge.bin", NULL);
if (sd_save_to_file((u8 *)buf, 0x200, path))
EPRINTF("\nError creating fuel.bin file.");
else
gfx_puts(&gfx_con, "\nDone!\n");
sd_unmount();
}
btn_wait();
}
free(buf);
}
void _ipatch_process(u32 offset, u32 value)
{
gfx_printf(&gfx_con, "%8x %8x", BOOTROM_BASE + offset, value);
u8 lo = value & 0xff;
switch (value >> 8)
{
case 0x20:
gfx_printf(&gfx_con, " MOVS R0, #0x%02X", lo);
break;
case 0xDF:
gfx_printf(&gfx_con, " SVC #0x%02X", lo);
break;
}
gfx_puts(&gfx_con, "\n");
}
void bootrom_ipatches_info()
{
gfx_clear_partial_grey(&gfx_ctxt, 0x1B, 0, 1256);
gfx_con_setpos(&gfx_con, 0, 0);
static const u32 BOOTROM_SIZE = 0x18000;
u32 res = fuse_read_ipatch(_ipatch_process);
if (res != 0)
EPRINTFARGS("Failed to read ipatches. Error: %d", res);
gfx_puts(&gfx_con, "\nPress POWER to dump them to SD Card.\nPress VOL to go to the menu.\n");
u32 btn = btn_wait();
if (btn & BTN_POWER)
{
if (sd_mount())
{
char path[64];
u32 iram_evp_thunks[0x200];
u32 iram_evp_thunks_len = sizeof(iram_evp_thunks);
res = fuse_read_evp_thunk(iram_evp_thunks, &iram_evp_thunks_len);
if (res == 0)
{
emmcsn_path_impl(path, "/dumps", "evp_thunks.bin", NULL);
if (!sd_save_to_file((u8 *)iram_evp_thunks, iram_evp_thunks_len, path))
gfx_puts(&gfx_con, "\nevp_thunks.bin saved!\n");
}
else
EPRINTFARGS("Failed to read evp_thunks. Error: %d", res);
u32 words[0x100];
read_raw_ipatch_fuses(words);
emmcsn_path_impl(path, "/dumps", "ipatches.bin", NULL);
if (!sd_save_to_file((u8 *)words, sizeof(words), path))
gfx_puts(&gfx_con, "\nipatches.bin saved!\n");
emmcsn_path_impl(path, "/dumps", "bootrom_patched.bin", NULL);
if (!sd_save_to_file((u8 *)BOOTROM_BASE, BOOTROM_SIZE, path))
gfx_puts(&gfx_con, "\nbootrom_patched.bin saved!\n");
u32 ipatch_backup[14];
memcpy(ipatch_backup, (void *)IPATCH_BASE, sizeof(ipatch_backup));
memset((void*)IPATCH_BASE, 0, sizeof(ipatch_backup));
emmcsn_path_impl(path, "/dumps", "bootrom_unpatched.bin", NULL);
if (!sd_save_to_file((u8 *)BOOTROM_BASE, BOOTROM_SIZE, path))
gfx_puts(&gfx_con, "\nbootrom_unpatched.bin saved!\n");
memcpy((void*)IPATCH_BASE, ipatch_backup, sizeof(ipatch_backup));
sd_unmount();
}
btn_wait();
}
}

View File

@@ -1,5 +1,7 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (c) 2018 CTCaer
* Copyright (c) 2018 balika011
*
* 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,21 +16,17 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* TODO: the placement of the relocator is a bit fragile atm, maybe we
* should include it in start.S and copy it to some known good
* place in IRAM instead. Basically we want it as far back atm
* as it might be overwritten during relocation.
*/
#ifndef _FE_INFO_H_
#define _FE_INFO_H_
.section .text.reloc
.arm
void print_fuseinfo();
void print_kfuseinfo();
void print_mmc_info();
void print_sdcard_info();
void print_tsec_key();
void print_fuel_gauge_info();
void print_battery_charger_info();
void print_battery_info();
void bootrom_ipatches_info();
.globl _reloc_ipl
.type _reloc_ipl, %function
_reloc_ipl:
LDMIA R0!, {R4-R7}
STMIA R1!, {R4-R7}
SUBS R2, #0x10
BNE _reloc_ipl
BX R3
#endif

View File

@@ -0,0 +1,606 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (c) 2018 CTCaer
* Copyright (c) 2018 Reisyukaku
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <string.h>
#include <stdlib.h>
#include "fe_tools.h"
#include "../config/config.h"
#include "../gfx/gfx.h"
#include "../gfx/tui.h"
#include "../hos/hos.h"
#include "../hos/pkg1.h"
#include "../hos/pkg2.h"
#include "../libs/fatfs/ff.h"
#include "../mem/heap.h"
#include "../power/max7762x.h"
#include "../sec/se.h"
#include "../storage/nx_emmc.h"
#include "../storage/sdmmc.h"
#include "../utils/btn.h"
#include "../utils/util.h"
extern hekate_config h_cfg;
extern gfx_ctxt_t gfx_ctxt;
extern gfx_con_t gfx_con;
extern sdmmc_storage_t sd_storage;
extern bool sd_mount();
extern void sd_unmount();
extern int sd_save_to_file(void *buf, u32 size, const char *filename);
extern void emmcsn_path_impl(char *path, char *sub_dir, char *filename, sdmmc_storage_t *storage);
//TODO: Create more macros (info, header, debug, etc) with different colors and utilize them for consistency.
#define EPRINTF(text) gfx_printf(&gfx_con, "%k"text"%k\n", 0xFFFF0000, 0xFFCCCCCC)
#define EPRINTFARGS(text, args...) gfx_printf(&gfx_con, "%k"text"%k\n", 0xFFFF0000, args, 0xFFCCCCCC)
void dump_packages12()
{
if (!sd_mount())
return;
u8 *pkg1 = (u8 *)calloc(1, 0x40000);
u8 *warmboot = (u8 *)calloc(1, 0x40000);
u8 *secmon = (u8 *)calloc(1, 0x40000);
u8 *loader = (u8 *)calloc(1, 0x40000);
u8 *pkg2 = NULL;
u8 kb = 0;
tsec_ctxt_t tsec_ctxt;
gfx_clear_partial_grey(&gfx_ctxt, 0x1B, 0, 1256);
gfx_con_setpos(&gfx_con, 0, 0);
sdmmc_storage_t storage;
sdmmc_t sdmmc;
if (!sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4))
{
EPRINTF("Failed to init eMMC.");
goto out_free;
}
sdmmc_storage_set_mmc_partition(&storage, 1);
// Read package1.
sdmmc_storage_read(&storage, 0x100000 / NX_EMMC_BLOCKSIZE, 0x40000 / NX_EMMC_BLOCKSIZE, pkg1);
const pkg1_id_t *pkg1_id = pkg1_identify(pkg1);
const pk11_hdr_t *hdr = (pk11_hdr_t *)(pkg1 + pkg1_id->pkg11_off + 0x20);
if (!pkg1_id)
{
gfx_con.fntsz = 8;
EPRINTFARGS("Unknown package1 version for reading\nTSEC firmware (= '%s').", (char *)pkg1 + 0x10);
goto out_free;
}
kb = pkg1_id->kb;
if (!h_cfg.se_keygen_done || kb >= KB_FIRMWARE_VERSION_620)
{
tsec_ctxt.key_ver = 1;
tsec_ctxt.fw = (void *)pkg1 + pkg1_id->tsec_off;
tsec_ctxt.pkg1 = (void *)pkg1;
tsec_ctxt.pkg11_off = pkg1_id->pkg11_off;
tsec_ctxt.secmon_base = pkg1_id->secmon_base;
// Read keyblob.
u8 *keyblob = (u8 *)calloc(NX_EMMC_BLOCKSIZE, 1);
sdmmc_storage_read(&storage, 0x180000 / NX_EMMC_BLOCKSIZE + kb, 1, keyblob);
// Decrypt.
keygen(keyblob, kb, &tsec_ctxt);
h_cfg.se_keygen_done = 1;
free(keyblob);
}
if (kb <= KB_FIRMWARE_VERSION_600)
pkg1_decrypt(pkg1_id, pkg1);
pkg1_unpack(warmboot, secmon, loader, pkg1_id, pkg1);
// Display info.
gfx_printf(&gfx_con, "%kNX Bootloader size: %k0x%05X\n\n", 0xFFC7EA46, 0xFFCCCCCC, hdr->ldr_size);
gfx_printf(&gfx_con, "%kSecure monitor addr: %k0x%05X\n", 0xFFC7EA46, 0xFFCCCCCC, pkg1_id->secmon_base);
gfx_printf(&gfx_con, "%kSecure monitor size: %k0x%05X\n\n", 0xFFC7EA46, 0xFFCCCCCC, hdr->sm_size);
gfx_printf(&gfx_con, "%kWarmboot addr: %k0x%05X\n", 0xFFC7EA46, 0xFFCCCCCC, pkg1_id->warmboot_base);
gfx_printf(&gfx_con, "%kWarmboot size: %k0x%05X\n\n", 0xFFC7EA46, 0xFFCCCCCC, hdr->wb_size);
char path[64];
// Dump package1.1.
emmcsn_path_impl(path, "/pkg1", "pkg1_decr.bin", &storage);
if (sd_save_to_file(pkg1, 0x40000, path))
goto out_free;
gfx_puts(&gfx_con, "\nFull package1 dumped to pkg1_decr.bin\n");
// Dump nxbootloader.
emmcsn_path_impl(path, "/pkg1", "nxloader.bin", &storage);
if (sd_save_to_file(loader, hdr->ldr_size, path))
goto out_free;
gfx_puts(&gfx_con, "NX Bootloader dumped to nxloader.bin\n");
// Dump secmon.
emmcsn_path_impl(path, "/pkg1", "secmon.bin", &storage);
if (sd_save_to_file(secmon, hdr->sm_size, path))
goto out_free;
gfx_puts(&gfx_con, "Secure Monitor dumped to secmon.bin\n");
// Dump warmboot.
emmcsn_path_impl(path, "/pkg1", "warmboot.bin", &storage);
if (sd_save_to_file(warmboot, hdr->wb_size, path))
goto out_free;
gfx_puts(&gfx_con, "Warmboot dumped to warmboot.bin\n\n\n");
// Dump package2.1.
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)
goto out;
// 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);
// 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.
pkg2_hdr_t *pkg2_hdr = pkg2_decrypt(pkg2);
// Display info.
u32 kernel_crc32 = crc32c(pkg2_hdr->data, pkg2_hdr->sec_size[PKG2_SEC_KERNEL]);
gfx_printf(&gfx_con, "\n%kKernel CRC32C: %k0x%08X\n\n", 0xFFC7EA46, 0xFFCCCCCC, kernel_crc32);
gfx_printf(&gfx_con, "%kKernel size: %k0x%05X\n\n", 0xFFC7EA46, 0xFFCCCCCC, pkg2_hdr->sec_size[PKG2_SEC_KERNEL]);
gfx_printf(&gfx_con, "%kINI1 size: %k0x%05X\n\n", 0xFFC7EA46, 0xFFCCCCCC, pkg2_hdr->sec_size[PKG2_SEC_INI1]);
// Dump pkg2.1.
emmcsn_path_impl(path, "/pkg2", "pkg2_decr.bin", &storage);
if (sd_save_to_file(pkg2, pkg2_hdr->sec_size[PKG2_SEC_KERNEL] + pkg2_hdr->sec_size[PKG2_SEC_INI1], path))
goto out;
gfx_puts(&gfx_con, "\nFull package2 dumped to pkg2_decr.bin\n");
// Dump kernel.
emmcsn_path_impl(path, "/pkg2", "kernel.bin", &storage);
if (sd_save_to_file(pkg2_hdr->data, pkg2_hdr->sec_size[PKG2_SEC_KERNEL], path))
goto out;
gfx_puts(&gfx_con, "Kernel dumped to kernel.bin\n");
// Dump INI1.
emmcsn_path_impl(path, "/pkg2", "ini1.bin", &storage);
if (sd_save_to_file(pkg2_hdr->data + pkg2_hdr->sec_size[PKG2_SEC_KERNEL],
pkg2_hdr->sec_size[PKG2_SEC_INI1], path))
goto out;
gfx_puts(&gfx_con, "INI1 kip1 package dumped to ini1.bin\n");
gfx_puts(&gfx_con, "\nDone. Press any key...\n");
out:
nx_emmc_gpt_free(&gpt);
out_free:
free(pkg1);
free(secmon);
free(warmboot);
free(loader);
free(pkg2);
sdmmc_storage_end(&storage);
sd_unmount();
if (kb >= KB_FIRMWARE_VERSION_620)
se_aes_key_clear(8);
btn_wait();
}
void _toggle_autorcm(bool enable)
{
sdmmc_storage_t storage;
sdmmc_t sdmmc;
u8 randomXor = 0;
gfx_clear_partial_grey(&gfx_ctxt, 0x1B, 0, 1256);
gfx_con_setpos(&gfx_con, 0, 0);
if (!sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4))
{
EPRINTF("Failed to init eMMC.");
goto out;
}
u8 *tempbuf = (u8 *)malloc(0x200);
sdmmc_storage_set_mmc_partition(&storage, 1);
int i, sect = 0;
for (i = 0; i < 4; i++)
{
sect = (0x200 + (0x4000 * i)) / NX_EMMC_BLOCKSIZE;
sdmmc_storage_read(&storage, sect, 1, tempbuf);
if (enable)
{
do
{
randomXor = get_tmr_us() & 0xFF; // Bricmii style of bricking.
} while (!randomXor); // Avoid the lottery.
tempbuf[0x10] ^= randomXor;
}
else
tempbuf[0x10] = 0xF7;
sdmmc_storage_write(&storage, sect, 1, tempbuf);
}
free(tempbuf);
sdmmc_storage_end(&storage);
if (enable)
gfx_printf(&gfx_con, "%kAutoRCM mode enabled!%k", 0xFFFFBA00, 0xFFCCCCCC);
else
gfx_printf(&gfx_con, "%kAutoRCM mode disabled!%k", 0xFF96FF00, 0xFFCCCCCC);
gfx_printf(&gfx_con, "\n\nPress any key...\n");
out:
btn_wait();
}
void _enable_autorcm() { _toggle_autorcm(true); }
void _disable_autorcm() { _toggle_autorcm(false); }
void menu_autorcm()
{
gfx_clear_grey(&gfx_ctxt, 0x1B);
gfx_con_setpos(&gfx_con, 0, 0);
// Do a simple check on the main BCT.
sdmmc_storage_t storage;
sdmmc_t sdmmc;
bool disabled = true;
if (!sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4))
{
EPRINTF("Failed to init eMMC.");
btn_wait();
return;
}
u8 *tempbuf = (u8 *)malloc(0x200);
sdmmc_storage_set_mmc_partition(&storage, 1);
sdmmc_storage_read(&storage, 0x200 / NX_EMMC_BLOCKSIZE, 1, tempbuf);
if (tempbuf[0x10] != 0xF7)
disabled = false;
free(tempbuf);
sdmmc_storage_end(&storage);
// Create AutoRCM menu.
ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * 6);
ments[0].type = MENT_BACK;
ments[0].caption = "Back";
ments[1].type = MENT_CHGLINE;
ments[2].type = MENT_CAPTION;
ments[3].type = MENT_CHGLINE;
if (disabled)
{
ments[2].caption = "Status: Disabled!";
ments[2].color = 0xFF96FF00;
ments[4].caption = "Enable AutoRCM";
ments[4].handler = _enable_autorcm;
}
else
{
ments[2].caption = "Status: Enabled!";
ments[2].color = 0xFFFFBA00;
ments[4].caption = "Disable AutoRCM";
ments[4].handler = _disable_autorcm;
}
ments[4].type = MENT_HDLR_RE;
ments[4].data = NULL;
memset(&ments[5], 0, sizeof(ment_t));
menu_t menu = {ments, "This corrupts your BOOT0!", 0, 0};
tui_do_menu(&gfx_con, &menu);
}
int _fix_attributes(char *path, u32 *total, u32 hos_folder, u32 check_first_run)
{
FRESULT res;
DIR dir;
u32 dirLength = 0;
static FILINFO fno;
if (check_first_run)
{
// Read file attributes.
res = f_stat(path, &fno);
if (res != FR_OK)
return res;
// Check if archive bit is set.
if (fno.fattrib & AM_ARC)
{
*(u32 *)total = *(u32 *)total + 1;
f_chmod(path, 0, AM_ARC);
}
}
// Open directory.
res = f_opendir(&dir, path);
if (res != FR_OK)
return res;
dirLength = strlen(path);
for (;;)
{
// Clear file or folder path.
path[dirLength] = 0;
// Read a directory item.
res = f_readdir(&dir, &fno);
// Break on error or end of dir.
if (res != FR_OK || fno.fname[0] == 0)
break;
// Skip official Nintendo dir if started from root.
if (!hos_folder && !strcmp(fno.fname, "Nintendo"))
continue;
// Set new directory or file.
memcpy(&path[dirLength], "/", 1);
memcpy(&path[dirLength + 1], fno.fname, strlen(fno.fname) + 1);
// Check if archive bit is set.
if (fno.fattrib & AM_ARC)
{
*total = *total + 1;
f_chmod(path, 0, AM_ARC);
}
// Is it a directory?
if (fno.fattrib & AM_DIR)
{
// Set archive bit to NCA folders.
if (hos_folder && !strcmp(fno.fname + strlen(fno.fname) - 4, ".nca"))
{
*total = *total + 1;
f_chmod(path, AM_ARC, AM_ARC);
}
// Enter the directory.
res = _fix_attributes(path, total, hos_folder, 0);
if (res != FR_OK)
break;
}
}
f_closedir(&dir);
return res;
}
void _fix_sd_attr(u32 type)
{
gfx_clear_partial_grey(&gfx_ctxt, 0x1B, 0, 1256);
gfx_con_setpos(&gfx_con, 0, 0);
char path[256];
char label[16];
u32 total = 0;
if (sd_mount())
{
switch (type)
{
case 0:
memcpy(path, "/", 2);
memcpy(label, "SD Card", 8);
break;
case 1:
default:
memcpy(path, "/Nintendo", 10);
memcpy(label, "Nintendo folder", 16);
break;
}
gfx_printf(&gfx_con, "Traversing all %s files!\nThis may take some time, please wait...\n\n", label);
_fix_attributes(path, &total, type, type);
gfx_printf(&gfx_con, "%kTotal archive bits cleared: %d!%k\n\nDone! Press any key...", 0xFF96FF00, total, 0xFFCCCCCC);
sd_unmount();
}
btn_wait();
}
void fix_sd_all_attr() { _fix_sd_attr(0); }
void fix_sd_nin_attr() { _fix_sd_attr(1); }
void fix_battery_desync()
{
gfx_clear_partial_grey(&gfx_ctxt, 0x1B, 0, 1256);
gfx_con_setpos(&gfx_con, 0, 0);
max77620_low_battery_monitor_config();
gfx_puts(&gfx_con, "\nDone!\n");
btn_wait();
}
/* void fix_fuel_gauge_configuration()
{
gfx_clear_partial_grey(&gfx_ctxt, 0x1B, 0, 1256);
gfx_con_setpos(&gfx_con, 0, 0);
int battVoltage, avgCurrent;
max17050_get_property(MAX17050_VCELL, &battVoltage);
max17050_get_property(MAX17050_AvgCurrent, &avgCurrent);
// Check if still charging. If not, check if battery is >= 95% (4.1V).
if (avgCurrent < 0 && battVoltage > 4100)
{
if ((avgCurrent / 1000) < -10)
EPRINTF("You need to be connected to a wall adapter,\nto apply this fix!");
else
{
gfx_printf(&gfx_con, "%kAre you really sure?\nThis will reset your fuel gauge completely!\n", 0xFFFFDD00);
gfx_printf(&gfx_con, "Additionally this will power off your console.\n%k", 0xFFCCCCCC);
gfx_puts(&gfx_con, "\nPress POWER to Continue.\nPress VOL to go to the menu.\n\n\n");
u32 btn = btn_wait();
if (btn & BTN_POWER)
{
max17050_fix_configuration();
msleep(1000);
gfx_con_getpos(&gfx_con, &gfx_con.savedx, &gfx_con.savedy);
u16 value = 0;
gfx_printf(&gfx_con, "%kThe console will power off in 45 seconds.\n%k", 0xFFFFDD00, 0xFFCCCCCC);
while (value < 46)
{
gfx_con_setpos(&gfx_con, gfx_con.savedx, gfx_con.savedy);
gfx_printf(&gfx_con, "%2ds elapsed", value);
msleep(1000);
value++;
}
msleep(2000);
power_off();
}
return;
}
}
else
EPRINTF("You need a fully charged battery\nand connected to a wall adapter,\nto apply this fix!");
msleep(500);
btn_wait();
} */
/*void reset_pmic_fuel_gauge_charger_config()
{
int avgCurrent;
gfx_clear_partial_grey(&gfx_ctxt, 0x1B, 0, 1256);
gfx_con_setpos(&gfx_con, 0, 0);
gfx_printf(&gfx_con, "%k\nThis will wipe your battery stats completely!\n"
"%kAnd it may not power on without physically\nremoving and re-inserting the battery.\n%k"
"\nAre you really sure?%k\n", 0xFFFFDD00, 0xFFFF0000, 0xFFFFDD00, 0xFFCCCCCC);
gfx_puts(&gfx_con, "\nPress POWER to Continue.\nPress VOL to go to the menu.\n\n\n");
u32 btn = btn_wait();
if (btn & BTN_POWER)
{
gfx_clear_partial_grey(&gfx_ctxt, 0x1B, 0, 1256);
gfx_con_setpos(&gfx_con, 0, 0);
gfx_printf(&gfx_con, "%kKeep the USB cable connected!%k\n\n", 0xFFFFDD00, 0xFFCCCCCC);
gfx_con_getpos(&gfx_con, &gfx_con.savedx, &gfx_con.savedy);
u8 value = 30;
while (value > 0)
{
gfx_con_setpos(&gfx_con, gfx_con.savedx, gfx_con.savedy);
gfx_printf(&gfx_con, "%kWait... (%ds) %k", 0xFF888888, value, 0xFFCCCCCC);
msleep(1000);
value--;
}
gfx_con_setpos(&gfx_con, gfx_con.savedx, gfx_con.savedy);
//Check if still connected.
max17050_get_property(MAX17050_AvgCurrent, &avgCurrent);
if ((avgCurrent / 1000) < -10)
EPRINTF("You need to be connected to a wall adapter\nor PC to apply this fix!");
else
{
// Apply fix.
bq24193_fake_battery_removal();
gfx_printf(&gfx_con, "Done! \n"
"%k1. Remove the USB cable\n"
"2. Press POWER for 15s.\n"
"3. Reconnect the USB to power-on!%k\n", 0xFFFFDD00, 0xFFCCCCCC);
}
msleep(500);
btn_wait();
}
}*/
/*
//#include "../modules/hekate_libsys_minerva/mtc.h"
//mtc_config_t mtc_cfg;
void minerva()
{
gfx_clear_partial_grey(&gfx_ctxt, 0x1B, 0, 1256);
gfx_con_setpos(&gfx_con, 0, 0);
u32 curr_ram_idx = 0;
if (!sd_mount())
return;
gfx_printf(&gfx_con, "-- Minerva Training Cell --\n\n");
// Set table to ram.
mtc_cfg.mtc_table = NULL;
mtc_cfg.sdram_id = (fuse_read_odm(4) >> 3) & 0x1F;
ianos_loader(false, "bootloader/sys/libsys_minerva.bso", DRAM_LIB, (void *)&mtc_cfg);
gfx_printf(&gfx_con, "\nStarting training process..\n\n");
// 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 = 800000;
mtc_cfg.train_mode = OP_TRAIN_SWITCH;
gfx_printf(&gfx_con, "Training and switching %7d -> %7d\n\n", mtc_cfg.mtc_table[curr_ram_idx].rate_khz, 800000);
ianos_loader(false, "bootloader/sys/libsys_minerva.bso", DRAM_LIB, (void *)&mtc_cfg);
// Thefollowing frequency needs periodic training every 100ms.
//msleep(200);
//mtc_cfg.rate_to = 1600000;
//gfx_printf(&gfx_con, "Training and switching %7d -> %7d\n\n", mtc_cfg.current_emc_table->rate_khz, 1600000);
//ianos_loader(false, "bootloader/sys/libsys_minerva.bso", DRAM_LIB, (void *)&mtc_cfg);
//mtc_cfg.train_mode = OP_PERIODIC_TRAIN;
sd_unmount();
gfx_printf(&gfx_con, "Finished!");
btn_wait();
}
*/

View File

@@ -0,0 +1,27 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (c) 2018 CTCaer
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _FE_TOOLS_H_
#define _FE_TOOLS_H_
void dump_packages12();
void fix_sd_all_attr();
void fix_sd_nin_attr();
void fix_battery_desync();
void menu_autorcm();
#endif

View File

@@ -81,7 +81,7 @@ void display_init()
gpio_write(GPIO_PORT_V, GPIO_PIN_1, GPIO_HIGH); // Backlight Enable enable.
// Config display interface and display.
MIPI_CAL(0x60) = 0;
MIPI_CAL(MIPI_CAL_MIPI_BIAS_PAD_CFG2) = 0;
exec_cfg((u32 *)CLOCK_BASE, _display_config_1, 4);
exec_cfg((u32 *)DISPLAY_A_BASE, _display_config_2, 94);
@@ -94,11 +94,11 @@ void display_init()
usleep(60000);
DSI(_DSIREG(DSI_BTA_TIMING)) = 0x50204;
DSI(_DSIREG(DSI_WR_DATA)) = 0x337;
DSI(_DSIREG(DSI_WR_DATA)) = 0x337; // MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE
DSI(_DSIREG(DSI_TRIGGER)) = DSI_TRIGGER_HOST;
_display_dsi_wait(250000, _DSIREG(DSI_TRIGGER), DSI_TRIGGER_HOST | DSI_TRIGGER_VIDEO);
DSI(_DSIREG(DSI_WR_DATA)) = 0x406;
DSI(_DSIREG(DSI_WR_DATA)) = 0x406; // MIPI_DCS_GET_DISPLAY_ID
DSI(_DSIREG(DSI_TRIGGER)) = DSI_TRIGGER_HOST;
_display_dsi_wait(250000, _DSIREG(DSI_TRIGGER), DSI_TRIGGER_HOST | DSI_TRIGGER_VIDEO);
@@ -111,12 +111,12 @@ void display_init()
if (_display_ver == 0x10)
exec_cfg((u32 *)DSI_BASE, _display_config_4, 43);
DSI(_DSIREG(DSI_WR_DATA)) = 0x1105;
DSI(_DSIREG(DSI_WR_DATA)) = 0x1105; // MIPI_DCS_EXIT_SLEEP_MODE
DSI(_DSIREG(DSI_TRIGGER)) = DSI_TRIGGER_HOST;
usleep(180000);
DSI(_DSIREG(DSI_WR_DATA)) = 0x2905;
DSI(_DSIREG(DSI_WR_DATA)) = 0x2905; // MIPI_DCS_SET_DISPLAY_ON
DSI(_DSIREG(DSI_TRIGGER)) = DSI_TRIGGER_HOST;
usleep(20000);
@@ -187,7 +187,7 @@ void display_end()
display_backlight_brightness(0, 1000);
DSI(_DSIREG(DSI_VIDEO_MODE_CONTROL)) = 1;
DSI(_DSIREG(DSI_WR_DATA)) = 0x2805;
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;
@@ -200,7 +200,7 @@ void display_end()
if (_display_ver == 0x10)
exec_cfg((u32 *)DSI_BASE, _display_config_14, 22);
DSI(_DSIREG(DSI_WR_DATA)) = 0x1005;
DSI(_DSIREG(DSI_WR_DATA)) = 0x1005; // MIPI_DCS_ENTER_SLEEP_MODE
DSI(_DSIREG(DSI_TRIGGER)) = DSI_TRIGGER_HOST;
usleep(50000);

View File

@@ -342,9 +342,10 @@
#define DSI_PAD_PREEMP_PU(x) (((x) & 0x3) << 0)
#define DSI_PAD_CONTROL_4 0x52
#define DSI_INIT_SEQ_DATA_15 0x5F
#define MIPI_CAL_MIPI_BIAS_PAD_CFG2 0x60
/*! Display backlight related PWM registers. */
#define PWM_CONTROLLER_PWM_CSR 0x00

View File

@@ -287,12 +287,12 @@ static const cfg_op_t _display_config_7[10] = {
//MIPI CAL config.
static const cfg_op_t _display_config_8[6] = {
{0x18, 0},
{2, 0xF3F10000},
{0x16, 0},
{0x18, 0},
{0x18, 0x10010},
{0x17, 0x300}
{0x18, 0}, // MIPI_CAL_MIPI_BIAS_PAD_CFG2
{0x02, 0xF3F10000}, // MIPI_CAL_CIL_MIPI_CAL_STATUS
{0x16, 0}, // MIPI_CAL_MIPI_BIAS_PAD_CFG0
{0x18, 0}, // MIPI_CAL_MIPI_BIAS_PAD_CFG2
{0x18, 0x10010}, // MIPI_CAL_MIPI_BIAS_PAD_CFG2
{0x17, 0x300} // MIPI_CAL_MIPI_BIAS_PAD_CFG1
};
//DSI config.
@@ -305,22 +305,22 @@ static const cfg_op_t _display_config_9[4] = {
//MIPI CAL config.
static const cfg_op_t _display_config_10[16] = {
{0xE, 0x200200},
{0xF, 0x200200},
{0x19, 0x200002},
{0x1A, 0x200002},
{5, 0},
{6, 0},
{7, 0},
{8, 0},
{9, 0},
{0xA, 0},
{0x10, 0},
{0x11, 0},
{0x1A, 0},
{0x1C, 0},
{0x1D, 0},
{0, 0x2A000001}
{0x0E, 0x200200}, // MIPI_CAL_DSIA_MIPI_CAL_CONFIG
{0x0F, 0x200200}, // MIPI_CAL_DSIB_MIPI_CAL_CONFIG
{0x19, 0x200002}, // MIPI_CAL_DSIA_MIPI_CAL_CONFIG_2
{0x1A, 0x200002}, // MIPI_CAL_DSIB_MIPI_CAL_CONFIG_2
{0x05, 0}, // MIPI_CAL_CILA_MIPI_CAL_CONFIG
{0x06, 0}, // MIPI_CAL_CILB_MIPI_CAL_CONFIG
{0x07, 0}, // MIPI_CAL_CILC_MIPI_CAL_CONFIG
{0x08, 0}, // MIPI_CAL_CILD_MIPI_CAL_CONFIG
{0x09, 0}, // MIPI_CAL_CILE_MIPI_CAL_CONFIG
{0x0A, 0}, // MIPI_CAL_CILF_MIPI_CAL_CONFIG
{0x10, 0}, // MIPI_CAL_DSIC_MIPI_CAL_CONFIG
{0x11, 0}, // MIPI_CAL_DSID_MIPI_CAL_CONFIG
{0x1A, 0}, // MIPI_CAL_DSIB_MIPI_CAL_CONFIG_2
{0x1C, 0}, // MIPI_CAL_DSIC_MIPI_CAL_CONFIG_2
{0x1D, 0}, // MIPI_CAL_DSID_MIPI_CAL_CONFIG_2
{0, 0x2A000001} // MIPI_CAL_DSIA_MIPI_CAL_CONFIG
};
//Display A config.

View File

@@ -206,8 +206,10 @@ void *tui_do_menu(gfx_con_t *con, menu_t *menu)
return NULL;
break;
case MENT_HDLR_RE:
ent->handler(ent->data);
return NULL;
ent->handler(ent);
if (!ent->data)
return NULL;
break;
default:
break;
}

View File

@@ -2,7 +2,7 @@
* Copyright (c) 2018 naehrwert
* Copyright (c) 2018 st4rk
* Copyright (c) 2018 Ced2911
* Copyright (C) 2018 CTCaer
* Copyright (c) 2018 CTCaer
* Copyright (c) 2018 balika011
*
* This program is free software; you can redistribute it and/or modify it
@@ -21,28 +21,28 @@
#include <string.h>
#include "hos.h"
#include "../storage/sdmmc.h"
#include "../storage/nx_emmc.h"
#include "../soc/t210.h"
#include "hos_config.h"
#include "secmon_exo.h"
#include "../config/config.h"
#include "../gfx/di.h"
#include "../mem/heap.h"
#include "../mem/mc.h"
#include "../sec/se.h"
#include "../sec/se_t210.h"
#include "../soc/pmc.h"
#include "../soc/cluster.h"
#include "../mem/heap.h"
#include "../sec/tsec.h"
#include "../utils/util.h"
#include "pkg1.h"
#include "pkg2.h"
#include "../libs/fatfs/ff.h"
#include "../gfx/di.h"
#include "../config/config.h"
#include "../mem/mc.h"
#include "../soc/cluster.h"
#include "../soc/fuse.h"
#include "../utils/dirlist.h"
#include "../soc/pmc.h"
#include "../soc/smmu.h"
#include "../soc/t210.h"
#include "../storage/nx_emmc.h"
#include "../storage/sdmmc.h"
#include "../utils/util.h"
#include "../gfx/gfx.h"
extern gfx_ctxt_t gfx_ctxt;
extern gfx_con_t gfx_con;
extern hekate_config h_cfg;
extern void sd_unmount();
@@ -50,49 +50,6 @@ extern void sd_unmount();
//#define DPRINTF(...) gfx_printf(&gfx_con, __VA_ARGS__)
#define DPRINTF(...)
typedef struct _launch_ctxt_t
{
void *keyblob;
void *pkg1;
const pkg1_id_t *pkg1_id;
const pkg2_kernel_id_t *pkg2_kernel_id;
void *warmboot;
u32 warmboot_size;
void *secmon;
u32 secmon_size;
void *pkg2;
u32 pkg2_size;
void *kernel;
u32 kernel_size;
link_t kip1_list;
char* kip1_patches;
bool svcperm;
bool debugmode;
bool atmosphere;
} launch_ctxt_t;
typedef struct _merge_kip_t
{
void *kip1;
link_t link;
} merge_kip_t;
#define KB_FIRMWARE_VERSION_100_200 0
#define KB_FIRMWARE_VERSION_300 1
#define KB_FIRMWARE_VERSION_301 2
#define KB_FIRMWARE_VERSION_400 3
#define KB_FIRMWARE_VERSION_500 4
#define KB_FIRMWARE_VERSION_600 5
#define KB_FIRMWARE_VERSION_MAX KB_FIRMWARE_VERSION_600
// Exosphère magic "XBC0".
#define MAGIC_EXOSPHERE 0x30434258
static const u8 keyblob_keyseeds[][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
@@ -114,26 +71,32 @@ static const u8 console_keyseed[0x10] =
static const u8 key8_keyseed[] =
{ 0xFB, 0x8B, 0x6A, 0x9C, 0x79, 0x00, 0xC8, 0x49, 0xEF, 0xD2, 0x4D, 0x85, 0x4D, 0x30, 0xA0, 0xC7 };
static const u8 master_keyseed_4xx_5xx[0x10] =
static const u8 master_keyseed_4xx_5xx_610[0x10] =
{ 0x2D, 0xC1, 0xF4, 0x8D, 0xF3, 0x5B, 0x69, 0x33, 0x42, 0x10, 0xAC, 0x65, 0xDA, 0x90, 0x46, 0x66 };
static const u8 master_keyseed_620[0x10] =
{ 0x37, 0x4B, 0x77, 0x29, 0x59, 0xB4, 0x04, 0x30, 0x81, 0xF6, 0xE5, 0x8C, 0x6D, 0x36, 0x17, 0x9A };
static const u8 console_keyseed_4xx_5xx[0x10] =
{ 0x0C, 0x91, 0x09, 0xDB, 0x93, 0x93, 0x07, 0x81, 0x07, 0x3C, 0xC4, 0x16, 0x22, 0x7C, 0x6C, 0x28 };
static void _se_lock()
static void _se_lock(bool lock_se)
{
for (u32 i = 0; i < 16; i++)
if (lock_se)
{
for (u32 i = 0; i < 16; i++)
se_key_acc_ctrl(i, 0x15);
for (u32 i = 0; i < 2; i++)
se_rsa_acc_ctrl(i, 1);
for (u32 i = 0; i < 2; i++)
se_rsa_acc_ctrl(i, 1);
SE(0x4) = 0; // Make this reg secure only.
SE(SE_KEY_TABLE_ACCESS_LOCK_OFFSET) = 0; // Make all key access regs secure only.
SE(SE_RSA_KEYTABLE_ACCESS_LOCK_OFFSET) = 0; // Make all RSA access regs secure only.
SE(SE_SECURITY_0) &= 0xFFFFFFFB; // Make access lock regs secure only.
}
SE(0x4) = 0; // Make this reg secure only.
SE(SE_KEY_TABLE_ACCESS_LOCK_OFFSET) = 0; // Make all key access regs secure only.
SE(SE_RSA_KEYTABLE_ACCESS_LOCK_OFFSET) = 0; // Make all RSA access regs secure only.
SE(SE_SECURITY_0) &= 0xFFFFFFFB; // Make access lock regs secure only.
memset((void *)IPATCH_BASE, 0, 13);
memset((void *)IPATCH_BASE, 0, 14 * sizeof(u32));
SB(SB_CSR) = 0x10; // Protected IROM enable.
// This is useful for documenting the bits in the SE config registers, so we can keep it around.
@@ -169,7 +132,6 @@ void _pmc_scratch_lock(u32 kb)
case KB_FIRMWARE_VERSION_400:
case KB_FIRMWARE_VERSION_500:
case KB_FIRMWARE_VERSION_600:
default:
PMC(APBDEV_PMC_SEC_DISABLE2) |= 0x3FCFFFF;
PMC(APBDEV_PMC_SEC_DISABLE4) |= 0x3F3FFFFF;
PMC(APBDEV_PMC_SEC_DISABLE5) = 0xFFFFFFFF;
@@ -180,75 +142,130 @@ void _pmc_scratch_lock(u32 kb)
}
}
int keygen(u8 *keyblob, u32 kb, void *tsec_fw)
void _sysctr0_reset()
{
u8 tmp[0x10];
SYSCTR0(SYSCTR0_CNTFID0) = 19200000;
SYSCTR0(SYSCTR0_CNTCR) = 0;
SYSCTR0(SYSCTR0_COUNTERID0) = 0;
SYSCTR0(SYSCTR0_COUNTERID1) = 0;
SYSCTR0(SYSCTR0_COUNTERID2) = 0;
SYSCTR0(SYSCTR0_COUNTERID3) = 0;
SYSCTR0(SYSCTR0_COUNTERID4) = 0;
SYSCTR0(SYSCTR0_COUNTERID5) = 0;
SYSCTR0(SYSCTR0_COUNTERID6) = 0;
SYSCTR0(SYSCTR0_COUNTERID7) = 0;
SYSCTR0(SYSCTR0_COUNTERID8) = 0;
SYSCTR0(SYSCTR0_COUNTERID9) = 0;
SYSCTR0(SYSCTR0_COUNTERID10) = 0;
SYSCTR0(SYSCTR0_COUNTERID11) = 0;
}
int keygen(u8 *keyblob, u32 kb, tsec_ctxt_t *tsec_ctxt)
{
u8 tmp[0x20];
u32 retries = 0;
tsec_ctxt->size = 0xF00;
if (kb > KB_FIRMWARE_VERSION_MAX)
return 0;
se_key_acc_ctrl(13, 0x15);
se_key_acc_ctrl(14, 0x15);
// Get TSEC key.
if (tsec_query(tmp, 1, tsec_fw) < 0)
return 0;
se_aes_key_set(13, tmp, 0x10);
// Derive keyblob keys from TSEC+SBK.
se_aes_crypt_block_ecb(13, 0, tmp, keyblob_keyseeds[0]);
se_aes_unwrap_key(15, 14, tmp);
se_aes_crypt_block_ecb(13, 0, tmp, keyblob_keyseeds[kb]);
se_aes_unwrap_key(13, 14, tmp);
// Clear SBK.
se_aes_key_clear(14);
//TODO: verify keyblob CMAC.
//se_aes_unwrap_key(11, 13, cmac_keyseed);
//se_aes_cmac(tmp, 0x10, 11, keyblob + 0x10, 0xA0);
//if (!memcmp(keyblob, tmp, 0x10))
// return 0;
se_aes_crypt_block_ecb(13, 0, tmp, cmac_keyseed);
se_aes_unwrap_key(11, 13, cmac_keyseed);
// Decrypt keyblob and set keyslots.
se_aes_crypt_ctr(13, keyblob + 0x20, 0x90, keyblob + 0x20, 0x90, keyblob + 0x10);
se_aes_key_set(11, keyblob + 0x20 + 0x80, 0x10); // Package1 key.
se_aes_key_set(12, keyblob + 0x20, 0x10);
se_aes_key_set(13, keyblob + 0x20, 0x10);
se_aes_crypt_block_ecb(12, 0, tmp, master_keyseed_retail);
switch (kb)
if (kb >= KB_FIRMWARE_VERSION_620)
{
case KB_FIRMWARE_VERSION_100_200:
case KB_FIRMWARE_VERSION_300:
case KB_FIRMWARE_VERSION_301:
se_aes_unwrap_key(13, 15, console_keyseed);
se_aes_unwrap_key(12, 12, master_keyseed_retail);
break;
case KB_FIRMWARE_VERSION_400:
se_aes_unwrap_key(13, 15, console_keyseed_4xx_5xx);
se_aes_unwrap_key(15, 15, console_keyseed);
se_aes_unwrap_key(14, 12, master_keyseed_4xx_5xx);
se_aes_unwrap_key(12, 12, master_keyseed_retail);
break;
case KB_FIRMWARE_VERSION_500:
case KB_FIRMWARE_VERSION_600:
default:
se_aes_unwrap_key(10, 15, console_keyseed_4xx_5xx);
se_aes_unwrap_key(15, 15, console_keyseed);
se_aes_unwrap_key(14, 12, master_keyseed_4xx_5xx);
se_aes_unwrap_key(12, 12, master_keyseed_retail);
break;
tsec_ctxt->size = 0x2900;
u8 *tsec_paged = (u8 *)page_alloc(3);
memcpy(tsec_paged, (void *)tsec_ctxt->fw, tsec_ctxt->size);
tsec_ctxt->fw = tsec_paged;
}
// Package2 key.
se_key_acc_ctrl(8, 0x15);
se_aes_unwrap_key(8, 12, key8_keyseed);
while (tsec_query(tmp, kb, tsec_ctxt) < 0)
{
memset(tmp, 0x00, 0x20);
retries++;
// We rely on racing conditions, make sure we cover even the unluckiest cases.
if (retries > 15)
{
gfx_printf(&gfx_con, "%k\nFailed to get TSEC keys. Please try again.%k\n\n", 0xFFFF0000, 0xFFCCCCCC);
return 0;
}
}
if (kb >= KB_FIRMWARE_VERSION_620)
{
// Set TSEC key.
se_aes_key_set(12, tmp, 0x10);
// Set TSEC root key.
se_aes_key_set(13, tmp + 0x10, 0x10);
// Package2 key.
se_aes_key_set(8, tmp + 0x10, 0x10);
se_aes_unwrap_key(8, 8, master_keyseed_620);
se_aes_unwrap_key(8, 8, master_keyseed_retail);
se_aes_unwrap_key(8, 8, key8_keyseed);
}
else
{
se_key_acc_ctrl(13, 0x15);
se_key_acc_ctrl(14, 0x15);
// Set TSEC key.
se_aes_key_set(13, tmp, 0x10);
// Derive keyblob keys from TSEC+SBK.
se_aes_crypt_block_ecb(13, 0, tmp, keyblob_keyseeds[0]);
se_aes_unwrap_key(15, 14, tmp);
se_aes_crypt_block_ecb(13, 0, tmp, keyblob_keyseeds[kb]);
se_aes_unwrap_key(13, 14, tmp);
// Clear SBK.
se_aes_key_clear(14);
//TODO: verify keyblob CMAC.
//se_aes_unwrap_key(11, 13, cmac_keyseed);
//se_aes_cmac(tmp, 0x10, 11, keyblob + 0x10, 0xA0);
//if (!memcmp(keyblob, tmp, 0x10))
// return 0;
se_aes_crypt_block_ecb(13, 0, tmp, cmac_keyseed);
se_aes_unwrap_key(11, 13, cmac_keyseed);
// Decrypt keyblob and set keyslots.
se_aes_crypt_ctr(13, keyblob + 0x20, 0x90, keyblob + 0x20, 0x90, keyblob + 0x10);
se_aes_key_set(11, keyblob + 0x20 + 0x80, 0x10); // Package1 key.
se_aes_key_set(12, keyblob + 0x20, 0x10);
se_aes_key_set(13, keyblob + 0x20, 0x10);
se_aes_crypt_block_ecb(12, 0, tmp, master_keyseed_retail);
switch (kb)
{
case KB_FIRMWARE_VERSION_100_200:
case KB_FIRMWARE_VERSION_300:
case KB_FIRMWARE_VERSION_301:
se_aes_unwrap_key(13, 15, console_keyseed);
se_aes_unwrap_key(12, 12, master_keyseed_retail);
break;
case KB_FIRMWARE_VERSION_400:
se_aes_unwrap_key(13, 15, console_keyseed_4xx_5xx);
se_aes_unwrap_key(15, 15, console_keyseed);
se_aes_unwrap_key(14, 12, master_keyseed_4xx_5xx_610);
se_aes_unwrap_key(12, 12, master_keyseed_retail);
break;
case KB_FIRMWARE_VERSION_500:
case KB_FIRMWARE_VERSION_600:
se_aes_unwrap_key(10, 15, console_keyseed_4xx_5xx);
se_aes_unwrap_key(15, 15, console_keyseed);
se_aes_unwrap_key(14, 12, master_keyseed_4xx_5xx_610);
se_aes_unwrap_key(12, 12, master_keyseed_retail);
break;
}
// Package2 key.
se_key_acc_ctrl(8, 0x15);
se_aes_unwrap_key(8, 12, key8_keyseed);
}
return 1;
}
@@ -262,16 +279,16 @@ static int _read_emmc_pkg1(launch_ctxt_t *ctxt)
sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4);
// Read package1.
ctxt->pkg1 = (u8 *)malloc(0x40000);
ctxt->pkg1 = (void *)malloc(0x40000);
sdmmc_storage_set_mmc_partition(&storage, 1);
sdmmc_storage_read(&storage, 0x100000 / NX_EMMC_BLOCKSIZE, 0x40000 / NX_EMMC_BLOCKSIZE, ctxt->pkg1);
ctxt->pkg1_id = pkg1_identify(ctxt->pkg1);
if (!ctxt->pkg1_id)
{
gfx_printf(&gfx_con, "%kUnknown package1,\nVersion (= '%s').%k\n", 0xFFFF0000, (char *)ctxt->pkg1 + 0x10, 0xFFCCCCCC);
gfx_printf(&gfx_con, "%kUnknown pkg1,\nVersion (= '%s').%k\n", 0xFFFF0000, (char *)ctxt->pkg1 + 0x10, 0xFFCCCCCC);
goto out;
}
gfx_printf(&gfx_con, "Identified package1 ('%s'),\nKeyblob version %d\n\n", (char *)(ctxt->pkg1 + 0x10), ctxt->pkg1_id->kb);
gfx_printf(&gfx_con, "Identified pkg1 ('%s'),\nKeyblob version %d\n\n", (char *)(ctxt->pkg1 + 0x10), ctxt->pkg1_id->kb);
// Read the correct keyblob.
ctxt->keyblob = (u8 *)calloc(NX_EMMC_BLOCKSIZE, 1);
@@ -326,199 +343,10 @@ static u8 *_read_emmc_pkg2(launch_ctxt_t *ctxt)
out:;
nx_emmc_gpt_free(&gpt);
sdmmc_storage_end(&storage);
return bctBuf;
}
static int _config_warmboot(launch_ctxt_t *ctxt, const char *value)
{
FIL fp;
if (f_open(&fp, value, FA_READ) != FR_OK)
return 0;
ctxt->warmboot_size = f_size(&fp);
ctxt->warmboot = malloc(ctxt->warmboot_size);
f_read(&fp, ctxt->warmboot, ctxt->warmboot_size, NULL);
f_close(&fp);
return 1;
}
static int _config_secmon(launch_ctxt_t *ctxt, const char *value)
{
FIL fp;
if (f_open(&fp, value, FA_READ) != FR_OK)
return 0;
ctxt->secmon_size = f_size(&fp);
ctxt->secmon = malloc(ctxt->secmon_size);
f_read(&fp, ctxt->secmon, ctxt->secmon_size, NULL);
f_close(&fp);
return 1;
}
static int _config_kernel(launch_ctxt_t *ctxt, const char *value)
{
FIL fp;
if (f_open(&fp, value, FA_READ) != FR_OK)
return 0;
ctxt->kernel_size = f_size(&fp);
ctxt->kernel = malloc(ctxt->kernel_size);
f_read(&fp, ctxt->kernel, ctxt->kernel_size, NULL);
f_close(&fp);
return 1;
}
static int _config_kip1(launch_ctxt_t *ctxt, const char *value)
{
FIL fp;
if (!memcmp(value + strlen(value) - 1, "*", 1))
{
char *dir = (char *)malloc(256);
memcpy(dir, value, strlen(value) + 1);
u32 dirlen = 0;
dir[strlen(dir) - 2] = 0;
char *filelist = dirlist(dir, "*.kip*");
memcpy(dir + strlen(dir), "/", 2);
dirlen = strlen(dir);
u32 i = 0;
if (filelist)
{
while (true)
{
if (!filelist[i * 256])
break;
memcpy(dir + dirlen, &filelist[i * 256], strlen(&filelist[i * 256]) + 1);
if (f_open(&fp, dir, FA_READ))
{
free(dir);
free(filelist);
return 0;
}
merge_kip_t *mkip1 = (merge_kip_t *)malloc(sizeof(merge_kip_t));
mkip1->kip1 = malloc(f_size(&fp));
f_read(&fp, mkip1->kip1, f_size(&fp), NULL);
DPRINTF("Loaded kip1 from SD (size %08X)\n", f_size(&fp));
f_close(&fp);
list_append(&ctxt->kip1_list, &mkip1->link);
i++;
}
}
free(dir);
free(filelist);
}
else
{
if (f_open(&fp, value, FA_READ))
return 0;
merge_kip_t *mkip1 = (merge_kip_t *)malloc(sizeof(merge_kip_t));
mkip1->kip1 = malloc(f_size(&fp));
f_read(&fp, mkip1->kip1, f_size(&fp), NULL);
DPRINTF("Loaded kip1 from SD (size %08X)\n", f_size(&fp));
f_close(&fp);
list_append(&ctxt->kip1_list, &mkip1->link);
}
return 1;
}
static int _config_svcperm(launch_ctxt_t *ctxt, const char *value)
{
if (*value == '1')
{
DPRINTF("Disabled SVC verification\n");
ctxt->svcperm = true;
}
return 1;
}
static int _config_debugmode(launch_ctxt_t *ctxt, const char *value)
{
if (*value == '1')
{
DPRINTF("Enabled Debug mode\n");
ctxt->debugmode = true;
}
return 1;
}
static int _config_atmosphere(launch_ctxt_t *ctxt, const char *value)
{
if (*value == '1')
{
DPRINTF("Enabled atmosphere patching\n");
ctxt->atmosphere = true;
}
return 1;
}
static int _config_kip1patch(launch_ctxt_t *ctxt, const char *value)
{
if (value == NULL)
return 0;
int valueLen = strlen(value);
if (!valueLen)
return 0;
if (ctxt->kip1_patches == NULL)
{
ctxt->kip1_patches = malloc(valueLen + 1);
memcpy(ctxt->kip1_patches, value, valueLen);
ctxt->kip1_patches[valueLen] = 0;
}
else
{
char *oldAlloc = ctxt->kip1_patches;
int oldSize = strlen(oldAlloc);
ctxt->kip1_patches = malloc(oldSize + 1 + valueLen + 1);
memcpy(ctxt->kip1_patches, oldAlloc, oldSize);
free(oldAlloc);
oldAlloc = NULL;
ctxt->kip1_patches[oldSize++] = ',';
memcpy(&ctxt->kip1_patches[oldSize], value, valueLen);
ctxt->kip1_patches[oldSize + valueLen] = 0;
}
return 1;
}
typedef struct _cfg_handler_t
{
const char *key;
int (*handler)(launch_ctxt_t *ctxt, const char *value);
} cfg_handler_t;
static const cfg_handler_t _config_handlers[] = {
{ "warmboot", _config_warmboot },
{ "secmon", _config_secmon },
{ "kernel", _config_kernel },
{ "kip1", _config_kip1 },
{ "kip1patch", _config_kip1patch },
{ "fullsvcperm", _config_svcperm },
{ "debugmode", _config_debugmode },
{ "atmosphere", _config_atmosphere },
{ NULL, NULL },
};
static int _config(launch_ctxt_t *ctxt, ini_sec_t *cfg)
{
LIST_FOREACH_ENTRY(ini_kv_t, kv, &cfg->kvs, link)
{
for(u32 i = 0; _config_handlers[i].key; i++)
{
if (!strcmp(_config_handlers[i].key, kv->key))
if (!_config_handlers[i].handler(ctxt, kv->val))
return 0;
}
}
return 1;
}
static void _free_launch_components(launch_ctxt_t *ctxt)
{
free(ctxt->keyblob);
@@ -532,10 +360,8 @@ static void _free_launch_components(launch_ctxt_t *ctxt)
int hos_launch(ini_sec_t *cfg)
{
int bootStateDramPkg2 = 0;
int bootStatePkg2Continue = 0;
int exoFwNumber = 0;
launch_ctxt_t ctxt;
tsec_ctxt_t tsec_ctxt;
memset(&ctxt, 0, sizeof(launch_ctxt_t));
list_init(&ctxt.kip1_list);
@@ -545,7 +371,7 @@ int hos_launch(ini_sec_t *cfg)
gfx_con_setpos(&gfx_con, 0, 0);
// Try to parse config if present.
if (cfg && !_config(&ctxt, cfg))
if (cfg && !_parse_boot_config(&ctxt, cfg))
return 0;
gfx_printf(&gfx_con, "Initializing...\n\n");
@@ -554,27 +380,46 @@ int hos_launch(ini_sec_t *cfg)
if (!_read_emmc_pkg1(&ctxt))
return 0;
gfx_printf(&gfx_con, "Loaded package1 and keyblob\n");
gfx_printf(&gfx_con, "Loaded pkg1 and keyblob\n");
// Generate keys.
if (!h_cfg.se_keygen_done)
if (!h_cfg.se_keygen_done || ctxt.pkg1_id->kb >= KB_FIRMWARE_VERSION_620)
{
keygen(ctxt.keyblob, ctxt.pkg1_id->kb, (u8 *)ctxt.pkg1 + ctxt.pkg1_id->tsec_off);
h_cfg.se_keygen_done = 1;
tsec_ctxt.key_ver = 1;
tsec_ctxt.fw = (u8 *)ctxt.pkg1 + ctxt.pkg1_id->tsec_off;
tsec_ctxt.pkg1 = ctxt.pkg1;
tsec_ctxt.pkg11_off = ctxt.pkg1_id->pkg11_off;
tsec_ctxt.secmon_base = ctxt.pkg1_id->secmon_base;
if (!keygen(ctxt.keyblob, ctxt.pkg1_id->kb, &tsec_ctxt))
return 0;
DPRINTF("Generated keys\n");
h_cfg.se_keygen_done = 1;
}
// Decrypt and unpack package1 if we require parts of it.
if (!ctxt.warmboot || !ctxt.secmon)
{
pkg1_decrypt(ctxt.pkg1_id, ctxt.pkg1);
if (ctxt.pkg1_id->kb <= KB_FIRMWARE_VERSION_600)
pkg1_decrypt(ctxt.pkg1_id, ctxt.pkg1);
pkg1_unpack((void *)ctxt.pkg1_id->warmboot_base, (void *)ctxt.pkg1_id->secmon_base, NULL, ctxt.pkg1_id, ctxt.pkg1);
gfx_printf(&gfx_con, "Decrypted and unpacked package1\n");
gfx_printf(&gfx_con, "Decrypted and unpacked pkg1\n");
}
// Replace 'warmboot.bin' if requested.
if (ctxt.warmboot)
memcpy((void *)ctxt.pkg1_id->warmboot_base, ctxt.warmboot, ctxt.warmboot_size);
else
{
// Else we patch it to allow downgrading.
patch_t *warmboot_patchset = ctxt.pkg1_id->warmboot_patchset;
gfx_printf(&gfx_con, "%kPatching Warmboot%k\n", 0xFFFFBA00, 0xFFCCCCCC);
for (u32 i = 0; warmboot_patchset[i].off != 0xFFFFFFFF; i++)
*(vu32 *)(ctxt.pkg1_id->warmboot_base + warmboot_patchset[i].off) = warmboot_patchset[i].val;
}
// Set warmboot address in PMC if required.
if (ctxt.pkg1_id->set_warmboot)
PMC(APBDEV_PMC_SCRATCH1) = ctxt.pkg1_id->warmboot_base;
@@ -598,10 +443,15 @@ int hos_launch(ini_sec_t *cfg)
if (!bootConfigBuf)
return 0;
gfx_printf(&gfx_con, "Read package2\n");
gfx_printf(&gfx_con, "Read pkg2\n");
// Decrypt package2 and parse KIP1 blobs in INI1 section.
pkg2_hdr_t *pkg2_hdr = pkg2_decrypt(ctxt.pkg2);
if (!pkg2_hdr)
{
gfx_printf(&gfx_con, "Pkg2 decryption failed!\n");
return 0;
}
LIST_INIT(kip1_info);
pkg2_parse_kips(&kip1_info, pkg2_hdr);
@@ -628,7 +478,7 @@ int hos_launch(ini_sec_t *cfg)
for (u32 i = 0; kernel_patchset[i].id != 0xFFFFFFFF; i++)
{
if ((ctxt.svcperm && kernel_patchset[i].id == SVC_VERIFY_DS)
|| (ctxt.debugmode && kernel_patchset[i].id == DEBUG_MODE_EN)
|| (ctxt.debugmode && kernel_patchset[i].id == DEBUG_MODE_EN && !(ctxt.atmosphere && ctxt.secmon))
|| (ctxt.atmosphere && kernel_patchset[i].id == ATM_GEN_PATCH))
*(vu32 *)(ctxt.kernel + kernel_patchset[i].off) = kernel_patchset[i].val;
else if (ctxt.atmosphere && kernel_patchset[i].id == ATM_ARR_PATCH)
@@ -658,27 +508,25 @@ int hos_launch(ini_sec_t *cfg)
// Rebuild and encrypt package2.
pkg2_build_encrypt((void *)0xA9800000, ctxt.kernel, ctxt.kernel_size, &kip1_info);
gfx_printf(&gfx_con, "Rebuilt and loaded package2\n");
gfx_printf(&gfx_con, "Rebuilt and loaded pkg2\n");
// Unmount SD card.
sd_unmount();
gfx_printf(&gfx_con, "\n%kBooting...%k\n", 0xFF96FF00, 0xFFCCCCCC);
// Clear pkg1/pkg2 keys.
se_aes_key_clear(8);
se_aes_key_clear(11);
// Final per firmware configuration.
// Finalize per firmware keys.
int bootStateDramPkg2 = 0;
int bootStatePkg2Continue = 0;
switch (ctxt.pkg1_id->kb)
{
case KB_FIRMWARE_VERSION_100_200:
if (!exoFwNumber)
{
if (!strcmp(ctxt.pkg1_id->id, "20161121183008"))
exoFwNumber = 1;
else
exoFwNumber = 2;
}
case KB_FIRMWARE_VERSION_300:
case KB_FIRMWARE_VERSION_301:
if (ctxt.pkg1_id->kb == KB_FIRMWARE_VERSION_300)
@@ -689,32 +537,20 @@ int hos_launch(ini_sec_t *cfg)
se_key_acc_ctrl(13, 0xFF);
bootStateDramPkg2 = 2;
bootStatePkg2Continue = 3;
if (!exoFwNumber)
exoFwNumber = 3;
break;
case KB_FIRMWARE_VERSION_400:
if (!exoFwNumber)
exoFwNumber = 4;
case KB_FIRMWARE_VERSION_500:
if (!exoFwNumber)
exoFwNumber = 5;
case KB_FIRMWARE_VERSION_600:
default:
se_key_acc_ctrl(12, 0xFF);
se_key_acc_ctrl(15, 0xFF);
case KB_FIRMWARE_VERSION_620:
bootStateDramPkg2 = 2;
bootStatePkg2Continue = 4;
if (!exoFwNumber)
exoFwNumber = 6;
break;
}
// Free allocated memory.
ini_free_section(cfg);
_free_launch_components(&ctxt);
// Clear BCT area for retail units and copy it over if dev unit.
if (ctxt.pkg1_id->kb < KB_FIRMWARE_VERSION_600)
if (ctxt.pkg1_id->kb <= KB_FIRMWARE_VERSION_500)
{
memset((void *)0x4003D000, 0, 0x3000);
if ((fuse_read_odm(4) & 3) == 3)
@@ -728,25 +564,30 @@ int hos_launch(ini_sec_t *cfg)
}
free(bootConfigBuf);
// Config Exosphère if booting Atmosphère.
if (ctxt.atmosphere)
{
vu32 *mb_exo_magic = (vu32 *)0x40002E40;
vu32 *mb_exo_fw_no = (vu32 *)0x40002E44;
// Config Exosphère if booting full Atmosphère.
if (ctxt.atmosphere && ctxt.secmon)
config_exosphere(ctxt.pkg1_id->id, ctxt.pkg1_id->kb, ctxt.debugmode);
*mb_exo_magic = MAGIC_EXOSPHERE;
*mb_exo_fw_no = exoFwNumber;
}
// Finalize MC carveout.
if (ctxt.pkg1_id->kb <= KB_FIRMWARE_VERSION_301)
mc_config_carveout();
// Finalize MC carveout and lock SE before starting 'SecureMonitor'.
mc_config_carveout_finalize();
_se_lock();
// Lock SE before starting 'SecureMonitor' if < 6.2.0, otherwise lock bootrom and ipatches.
_se_lock(ctxt.pkg1_id->kb <= KB_FIRMWARE_VERSION_600);
//TODO: pkg1.1 locks PMC scratches, we can do that too at some point. For <4.0.0 after secmon?
// Reset sysctr0 counters.
if (ctxt.pkg1_id->kb >= KB_FIRMWARE_VERSION_620)
_sysctr0_reset();
// Free allocated memory.
ini_free_section(cfg);
_free_launch_components(&ctxt);
// < 4.0.0 pkg1.1 locks PMC scratches.
//_pmc_scratch_lock(ctxt.pkg1_id->kb);
// < 4.0.0 Signals - 0: Nothing ready, 1: BCT ready, 2: DRAM and pkg2 ready, 3: Continue boot.
// >= 4.0.0 Signals - 0: Nothing ready, 1: BCT ready, 2: DRAM ready, 4: pkg2 ready and continue boot.
// < 4.0.0 Signals - 0: Not ready, 1: BCT ready, 2: DRAM and pkg2 ready, 3: Continue boot.
// >= 4.0.0 Signals - 0: Not ready, 1: BCT ready, 2: DRAM ready, 4: pkg2 ready and continue boot.
vu32 *mb_in = (vu32 *)0x40002EF8;
// Non-zero: Secmon ready.
vu32 *mb_out = (vu32 *)0x40002EFC;
@@ -759,7 +600,10 @@ int hos_launch(ini_sec_t *cfg)
display_end();
// Wait for secmon to get ready.
cluster_boot_cpu0(ctxt.pkg1_id->secmon_base);
if (smmu_is_used())
smmu_exit();
else
cluster_boot_cpu0(ctxt.pkg1_id->secmon_base);
while (!*mb_out)
usleep(1); // This only works when in IRAM or with a trained DRAM.

View File

@@ -17,10 +17,56 @@
#ifndef _HOS_H_
#define _HOS_H_
#include "pkg1.h"
#include "pkg2.h"
#include "../utils/types.h"
#include "../config/ini.h"
#include "../sec/tsec.h"
#define KB_FIRMWARE_VERSION_100_200 0
#define KB_FIRMWARE_VERSION_300 1
#define KB_FIRMWARE_VERSION_301 2
#define KB_FIRMWARE_VERSION_400 3
#define KB_FIRMWARE_VERSION_500 4
#define KB_FIRMWARE_VERSION_600 5
#define KB_FIRMWARE_VERSION_620 6
#define KB_FIRMWARE_VERSION_MAX KB_FIRMWARE_VERSION_620
#define HOS_PKG11_MAGIC 0x31314B50
typedef struct _launch_ctxt_t
{
void *keyblob;
void *pkg1;
const pkg1_id_t *pkg1_id;
const pkg2_kernel_id_t *pkg2_kernel_id;
void *warmboot;
u32 warmboot_size;
void *secmon;
u32 secmon_size;
void *pkg2;
u32 pkg2_size;
void *kernel;
u32 kernel_size;
link_t kip1_list;
char* kip1_patches;
bool svcperm;
bool debugmode;
bool atmosphere;
} launch_ctxt_t;
typedef struct _merge_kip_t
{
void *kip1;
link_t link;
} merge_kip_t;
int hos_launch(ini_sec_t *cfg);
int keygen(u8 *keyblob, u32 kb, void *tsec_fw);
int keygen(u8 *keyblob, u32 kb, tsec_ctxt_t *tsec_ctxt);
#endif

221
bootloader/hos/hos_config.c Normal file
View File

@@ -0,0 +1,221 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (c) 2018 CTCaer
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <string.h>
#include "hos.h"
#include "hos_config.h"
#include "../libs/fatfs/ff.h"
#include "../mem/heap.h"
#include "../utils/dirlist.h"
#include "../gfx/gfx.h"
extern gfx_con_t gfx_con;
//#define DPRINTF(...) gfx_printf(&gfx_con, __VA_ARGS__)
#define DPRINTF(...)
static int _config_warmboot(launch_ctxt_t *ctxt, const char *value)
{
FIL fp;
if (f_open(&fp, value, FA_READ) != FR_OK)
return 0;
ctxt->warmboot_size = f_size(&fp);
ctxt->warmboot = malloc(ctxt->warmboot_size);
f_read(&fp, ctxt->warmboot, ctxt->warmboot_size, NULL);
f_close(&fp);
return 1;
}
static int _config_secmon(launch_ctxt_t *ctxt, const char *value)
{
FIL fp;
if (f_open(&fp, value, FA_READ) != FR_OK)
return 0;
ctxt->secmon_size = f_size(&fp);
ctxt->secmon = malloc(ctxt->secmon_size);
f_read(&fp, ctxt->secmon, ctxt->secmon_size, NULL);
f_close(&fp);
return 1;
}
static int _config_kernel(launch_ctxt_t *ctxt, const char *value)
{
FIL fp;
if (f_open(&fp, value, FA_READ) != FR_OK)
return 0;
ctxt->kernel_size = f_size(&fp);
ctxt->kernel = malloc(ctxt->kernel_size);
f_read(&fp, ctxt->kernel, ctxt->kernel_size, NULL);
f_close(&fp);
return 1;
}
static int _config_kip1(launch_ctxt_t *ctxt, const char *value)
{
FIL fp;
if (!memcmp(value + strlen(value) - 1, "*", 1))
{
char *dir = (char *)malloc(256);
memcpy(dir, value, strlen(value) + 1);
u32 dirlen = 0;
dir[strlen(dir) - 2] = 0;
char *filelist = dirlist(dir, "*.kip*", false);
memcpy(dir + strlen(dir), "/", 2);
dirlen = strlen(dir);
u32 i = 0;
if (filelist)
{
while (true)
{
if (!filelist[i * 256])
break;
memcpy(dir + dirlen, &filelist[i * 256], strlen(&filelist[i * 256]) + 1);
if (f_open(&fp, dir, FA_READ))
{
free(dir);
free(filelist);
return 0;
}
merge_kip_t *mkip1 = (merge_kip_t *)malloc(sizeof(merge_kip_t));
mkip1->kip1 = malloc(f_size(&fp));
f_read(&fp, mkip1->kip1, f_size(&fp), NULL);
DPRINTF("Loaded kip1 from SD (size %08X)\n", f_size(&fp));
f_close(&fp);
list_append(&ctxt->kip1_list, &mkip1->link);
i++;
}
}
free(dir);
free(filelist);
}
else
{
if (f_open(&fp, value, FA_READ))
return 0;
merge_kip_t *mkip1 = (merge_kip_t *)malloc(sizeof(merge_kip_t));
mkip1->kip1 = malloc(f_size(&fp));
f_read(&fp, mkip1->kip1, f_size(&fp), NULL);
DPRINTF("Loaded kip1 from SD (size %08X)\n", f_size(&fp));
f_close(&fp);
list_append(&ctxt->kip1_list, &mkip1->link);
}
return 1;
}
static int _config_svcperm(launch_ctxt_t *ctxt, const char *value)
{
if (*value == '1')
{
DPRINTF("Disabled SVC verification\n");
ctxt->svcperm = true;
}
return 1;
}
static int _config_debugmode(launch_ctxt_t *ctxt, const char *value)
{
if (*value == '1')
{
DPRINTF("Enabled Debug mode\n");
ctxt->debugmode = true;
}
return 1;
}
static int _config_atmosphere(launch_ctxt_t *ctxt, const char *value)
{
if (*value == '1')
{
DPRINTF("Enabled atmosphere patching\n");
ctxt->atmosphere = true;
}
return 1;
}
static int _config_kip1patch(launch_ctxt_t *ctxt, const char *value)
{
if (value == NULL)
return 0;
int valueLen = strlen(value);
if (!valueLen)
return 0;
if (ctxt->kip1_patches == NULL)
{
ctxt->kip1_patches = malloc(valueLen + 1);
memcpy(ctxt->kip1_patches, value, valueLen);
ctxt->kip1_patches[valueLen] = 0;
}
else
{
char *oldAlloc = ctxt->kip1_patches;
int oldSize = strlen(oldAlloc);
ctxt->kip1_patches = malloc(oldSize + 1 + valueLen + 1);
memcpy(ctxt->kip1_patches, oldAlloc, oldSize);
free(oldAlloc);
oldAlloc = NULL;
ctxt->kip1_patches[oldSize++] = ',';
memcpy(&ctxt->kip1_patches[oldSize], value, valueLen);
ctxt->kip1_patches[oldSize + valueLen] = 0;
}
return 1;
}
typedef struct _cfg_handler_t
{
const char *key;
int (*handler)(launch_ctxt_t *ctxt, const char *value);
} cfg_handler_t;
static const cfg_handler_t _config_handlers[] = {
{ "warmboot", _config_warmboot },
{ "secmon", _config_secmon },
{ "kernel", _config_kernel },
{ "kip1", _config_kip1 },
{ "kip1patch", _config_kip1patch },
{ "fullsvcperm", _config_svcperm },
{ "debugmode", _config_debugmode },
{ "atmosphere", _config_atmosphere },
{ NULL, NULL },
};
int _parse_boot_config(launch_ctxt_t *ctxt, ini_sec_t *cfg)
{
LIST_FOREACH_ENTRY(ini_kv_t, kv, &cfg->kvs, link)
{
for(u32 i = 0; _config_handlers[i].key; i++)
{
if (!strcmp(_config_handlers[i].key, kv->key))
if (!_config_handlers[i].handler(ctxt, kv->val))
return 0;
}
}
return 1;
}

View File

@@ -0,0 +1,25 @@
/*
* Copyright (c) 2018 naehrwert
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _HOS_CONFIG_H_
#define _HOS_CONFIG_H_
#include "hos.h"
int _parse_boot_config(launch_ctxt_t *ctxt, ini_sec_t *cfg);
#endif

View File

@@ -2,6 +2,7 @@
* Copyright (c) 2018 naehrwert
* Copyright (c) 2018 st4rk
* Copyright (c) 2018 CTCaer
* Copyright (c) 2018 balika011
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@@ -22,6 +23,8 @@
#include "../utils/aarch64_util.h"
#include "../sec/se.h"
#define _NOPv7() 0xE320F000
#define SM_100_ADR 0x4002B020
PATCHSET_DEF(_secmon_1_patchset,
// Patch the relocator to be able to run from SM_100_ADR.
@@ -71,6 +74,47 @@ PATCHSET_DEF(_secmon_6_patchset,
{ 0xDC8 + 0x112C, _NOP() } //Sections SHA2.
);
PATCHSET_DEF(_secmon_620_patchset,
// Patch package2 decryption and signature/hash checks.
{ 0xDC8 + 0x604, _NOP() }, //package2 structure.
{ 0xDC8 + 0x610, _NOP() }, //Version.
{ 0xDC8 + 0xC74, _NOP() }, //Header signature.
{ 0xDC8 + 0xF10, _NOP() } //Sections SHA2.
);
PATCHSET_DEF(_warmboot_1_patchset,
{ 0x4DC, _NOPv7() } // Fuse check.
);
PATCHSET_DEF(_warmboot_2_patchset,
{ 0x4DC, _NOPv7() } // Fuse check.
);
PATCHSET_DEF(_warmboot_3_patchset,
{ 0x4DC, _NOPv7() }, // Fuse check.
{ 0x4F0, _NOPv7() } // Segment id check.
);
PATCHSET_DEF(_warmboot_4_patchset,
{ 0x544, _NOPv7() }, // Fuse check.
{ 0x558, _NOPv7() } // Segment id check.
);
PATCHSET_DEF(_warmboot_5_patchset,
{ 0x544, _NOPv7() }, // Fuse check.
{ 0x558, _NOPv7() } // Segment id check.
);
PATCHSET_DEF(_warmboot_6_patchset,
{ 0x544, _NOPv7() }, // Fuse check.
{ 0x558, _NOPv7() } // Segment id check.
);
PATCHSET_DEF(_warmboot_620_patchset,
{ 0x544, _NOPv7() }, // Fuse check.
{ 0x558, _NOPv7() } // Segment id check.
);
/*
* package1.1 header: <wb, ldr, sm>
* package1.1 layout:
@@ -81,16 +125,18 @@ PATCHSET_DEF(_secmon_6_patchset,
* 4.0: {ldr, sm, wb} { 1, 2, 0 }
* 5.0: {ldr, sm, wb} { 1, 2, 0 }
* 6.0: {ldr, sm, wb} { 1, 2, 0 }
* 6.2: {ldr, sm, wb} { 1, 2, 0 }
*/
static const pkg1_id_t _pkg1_ids[] = {
{ "20161121183008", 0, 0x1900, 0x3FE0, { 2, 1, 0 }, SM_100_ADR, 0x8000D000, true, _secmon_1_patchset }, //1.0.0 (Patched relocator)
{ "20170210155124", 0, 0x1900, 0x3FE0, { 0, 1, 2 }, 0x4002D000, 0x8000D000, true, _secmon_2_patchset }, //2.0.0 - 2.3.0
{ "20170519101410", 1, 0x1A00, 0x3FE0, { 0, 1, 2 }, 0x4002D000, 0x8000D000, true, _secmon_3_patchset }, //3.0.0
{ "20170710161758", 2, 0x1A00, 0x3FE0, { 0, 1, 2 }, 0x4002D000, 0x8000D000, true, _secmon_3_patchset }, //3.0.1 - 3.0.2
{ "20170921172629", 3, 0x1800, 0x3FE0, { 1, 2, 0 }, 0x4002B000, 0x4003B000, false, _secmon_4_patchset }, //4.0.0 - 4.1.0
{ "20180220163747", 4, 0x1900, 0x3FE0, { 1, 2, 0 }, 0x4002B000, 0x4003B000, false, _secmon_5_patchset }, //5.0.0 - 5.1.0
{ "20180802162753", 5, 0x1900, 0x3FE0, { 1, 2, 0 }, 0x4002B000, 0x4003D800, false, _secmon_6_patchset }, //6.0.0 - 6.0.0
{ "20161121183008", 0, 0x1900, 0x3FE0, { 2, 1, 0 }, SM_100_ADR, 0x8000D000, true, _secmon_1_patchset, _warmboot_1_patchset }, //1.0.0 (Patched relocator)
{ "20170210155124", 0, 0x1900, 0x3FE0, { 0, 1, 2 }, 0x4002D000, 0x8000D000, true, _secmon_2_patchset, _warmboot_2_patchset }, //2.0.0 - 2.3.0
{ "20170519101410", 1, 0x1A00, 0x3FE0, { 0, 1, 2 }, 0x4002D000, 0x8000D000, true, _secmon_3_patchset, _warmboot_3_patchset }, //3.0.0
{ "20170710161758", 2, 0x1A00, 0x3FE0, { 0, 1, 2 }, 0x4002D000, 0x8000D000, true, _secmon_3_patchset, _warmboot_3_patchset }, //3.0.1 - 3.0.2
{ "20170921172629", 3, 0x1800, 0x3FE0, { 1, 2, 0 }, 0x4002B000, 0x4003B000, false, _secmon_4_patchset, _warmboot_4_patchset }, //4.0.0 - 4.1.0
{ "20180220163747", 4, 0x1900, 0x3FE0, { 1, 2, 0 }, 0x4002B000, 0x4003B000, false, _secmon_5_patchset, _warmboot_5_patchset }, //5.0.0 - 5.1.0
{ "20180802162753", 5, 0x1900, 0x3FE0, { 1, 2, 0 }, 0x4002B000, 0x4003D800, false, _secmon_6_patchset, _warmboot_6_patchset }, //6.0.0 - 6.1.0
{ "20181107105733", 6, 0x0E00, 0x6FE0, { 1, 2, 0 }, 0x4002B000, 0x4003D800, false, _secmon_620_patchset, _warmboot_620_patchset }, //6.2.0
{ NULL } //End.
};

View File

@@ -42,6 +42,7 @@ typedef struct _pkg1_id_t
u32 warmboot_base;
bool set_warmboot;
patch_t *secmon_patchset;
patch_t *warmboot_patchset;
} pkg1_id_t;
typedef struct _pk11_hdr_t

View File

@@ -254,7 +254,7 @@ static const pkg2_kernel_id_t _pkg2_kernel_ids[] =
{ 0xe0e8cdc4, _kernel_302_patchset }, //3.0.2
{ 0x485d0157, _kernel_4_patchset }, //4.0.0 - 4.1.0
{ 0xf3c363f2, _kernel_5_patchset }, //5.0.0 - 5.1.0
{ 0x64ce1a44, _kernel_6_patchset }, //6.0.0
{ 0x64ce1a44, _kernel_6_patchset }, //6.0.0 - 6.2.0
{ 0, 0 } //End.
};

View File

@@ -0,0 +1,66 @@
/*
* Copyright (C) 2018 CTCaer
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <string.h>
#include "hos.h"
#include "../utils/types.h"
// Exosphère mailbox defines.
#define EXO_MAGIC_ADDR 0x40002E40
#define EXO_MAGIC_VAL 0x31434258
#define EXO_FWNO_ADDR 0x40002E44
#define EXO_FLAGS_ADDR 0x40002E48
#define EXO_FLAG_620_KGN (1 << 0)
#define EXO_FLAG_DBG_PRIV (1 << 1)
#define EXO_FLAG_DBG_USER (1 << 2)
void config_exosphere(const char *id, u32 kb, bool debug)
{
u32 exoFwNo = 0;
u32 exoFlags = 0;
vu32 *mb_exo_magic = (vu32 *)EXO_MAGIC_ADDR;
vu32 *mb_exo_fw_no = (vu32 *)EXO_FWNO_ADDR;
vu32 *mb_exo_flags = (vu32 *)EXO_FLAGS_ADDR;
switch (kb)
{
case KB_FIRMWARE_VERSION_100_200:
if (!strcmp(id, "20161121183008"))
exoFwNo = 1;
else
exoFwNo = 2;
break;
case KB_FIRMWARE_VERSION_300:
exoFwNo = 3;
break;
default:
exoFwNo = kb + 1;
break;
}
if (kb >= KB_FIRMWARE_VERSION_620)
exoFlags |= EXO_FLAG_620_KGN;
if (debug)
exoFlags |= EXO_FLAG_DBG_PRIV;
// Set mailbox values.
*mb_exo_magic = EXO_MAGIC_VAL;
*mb_exo_fw_no = exoFwNo;
*mb_exo_flags = exoFlags;
}

View File

@@ -0,0 +1,24 @@
/*
* Copyright (C) 2018 CTCaer
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _SECMON_EXO_H_
#define _SECMON_EXO_H_
#include "../utils/types.h"
void config_exosphere(const char *id, u32 kb, bool debug);
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -28,6 +28,7 @@ void mc_config_carveout()
MC(MC_MTS_CARVEOUT_SIZE_MB) = 0;
MC(MC_MTS_CARVEOUT_ADR_HI) = 0;
MC(MC_MTS_CARVEOUT_REG_CTRL) = 1;
MC(MC_SECURITY_CARVEOUT1_BOM) = 0;
MC(MC_SECURITY_CARVEOUT1_BOM_HI) = 0;
MC(MC_SECURITY_CARVEOUT1_SIZE_128KB) = 0;
@@ -43,6 +44,21 @@ void mc_config_carveout()
MC(MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS4) = 0;
MC(MC_SECURITY_CARVEOUT1_CFG0) = 0x4000006;
MC(MC_SECURITY_CARVEOUT2_BOM) = 0x80020000;
MC(MC_SECURITY_CARVEOUT2_BOM_HI) = 0;
MC(MC_SECURITY_CARVEOUT2_SIZE_128KB) = 2;
MC(MC_SECURITY_CARVEOUT2_CLIENT_ACCESS0) = 0;
MC(MC_SECURITY_CARVEOUT2_CLIENT_ACCESS1) = 0;
MC(MC_SECURITY_CARVEOUT2_CLIENT_ACCESS2) = 0x3100000;
MC(MC_SECURITY_CARVEOUT2_CLIENT_ACCESS3) = 0;
MC(MC_SECURITY_CARVEOUT2_CLIENT_ACCESS4) = 0x300;
MC(MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS0) = 0;
MC(MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS1) = 0;
MC(MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS2) = 0;
MC(MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS3) = 0;
MC(MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS4) = 0;
MC(MC_SECURITY_CARVEOUT2_CFG0) = 0x440167E;
MC(MC_SECURITY_CARVEOUT3_BOM) = 0;
MC(MC_SECURITY_CARVEOUT3_BOM_HI) = 0;
MC(MC_SECURITY_CARVEOUT3_SIZE_128KB) = 0;
@@ -57,6 +73,7 @@ void mc_config_carveout()
MC(MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS3) = 0;
MC(MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS4) = 0;
MC(MC_SECURITY_CARVEOUT3_CFG0) = 0x4401E7E;
MC(MC_SECURITY_CARVEOUT4_BOM) = 0;
MC(MC_SECURITY_CARVEOUT4_BOM_HI) = 0;
MC(MC_SECURITY_CARVEOUT4_SIZE_128KB) = 0;
@@ -71,6 +88,7 @@ void mc_config_carveout()
MC(MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS3) = 0;
MC(MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS4) = 0;
MC(MC_SECURITY_CARVEOUT4_CFG0) = 0x8F;
MC(MC_SECURITY_CARVEOUT5_BOM) = 0;
MC(MC_SECURITY_CARVEOUT5_BOM_HI) = 0;
MC(MC_SECURITY_CARVEOUT5_SIZE_128KB) = 0;
@@ -87,26 +105,9 @@ void mc_config_carveout()
MC(MC_SECURITY_CARVEOUT5_CFG0) = 0x8F;
}
void mc_config_carveout_finalize()
{
MC(MC_SECURITY_CARVEOUT2_BOM) = 0x80020000;
MC(MC_SECURITY_CARVEOUT2_BOM_HI) = 0;
MC(MC_SECURITY_CARVEOUT2_SIZE_128KB) = 2;
MC(MC_SECURITY_CARVEOUT2_CLIENT_ACCESS0) = 0;
MC(MC_SECURITY_CARVEOUT2_CLIENT_ACCESS1) = 0;
MC(MC_SECURITY_CARVEOUT2_CLIENT_ACCESS2) = 0x3000000;
MC(MC_SECURITY_CARVEOUT2_CLIENT_ACCESS3) = 0;
MC(MC_SECURITY_CARVEOUT2_CLIENT_ACCESS4) = 0x300;
MC(MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS0) = 0;
MC(MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS1) = 0;
MC(MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS2) = 0;
MC(MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS3) = 0;
MC(MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS4) = 0;
MC(MC_SECURITY_CARVEOUT2_CFG0) = 0x440167E;
}
void mc_enable_ahb_redirect()
{
// Enable ARC_CLK_OVR_ON.
CLOCK(CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRD) = (CLOCK(CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRD) & 0xFFF7FFFF) | 0x80000;
//MC(MC_IRAM_REG_CTRL) &= 0xFFFFFFFE;
MC(MC_IRAM_BOM) = 0x40000000;
@@ -119,7 +120,8 @@ void mc_disable_ahb_redirect()
MC(MC_IRAM_TOM) = 0;
// Disable IRAM_CFG_WRITE_ACCESS (sticky).
//MC(MC_IRAM_REG_CTRL) = MC(MC_IRAM_REG_CTRL) & 0xFFFFFFFE | 1;
CLOCK(0x3A4) &= 0xFFF7FFFF;
// Disable ARC_CLK_OVR_ON.
CLOCK(CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRD) &= 0xFFF7FFFF;
}
void mc_enable()
@@ -131,7 +133,7 @@ void mc_enable()
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) = (CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) & 0xFFFFFFFE) | 1;
// Enable EMC DLL clock.
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_X_SET) = (CLOCK(CLK_RST_CONTROLLER_CLK_ENB_X_SET) & 0xFFFFBFFF) | 0x4000;
CLOCK(CLK_RST_CONTROLLER_RST_DEV_H_SET) = 0x2000001; //Clear EMC and MC reset.
CLOCK(CLK_RST_CONTROLLER_RST_DEV_H_CLR) = 0x2000001; //Clear EMC and MC reset.
usleep(5);
//#ifdef CONFIG_ENABLE_AHB_REDIRECT

View File

@@ -41,7 +41,7 @@ static u32 _get_sdram_id()
static void _sdram_config(const sdram_params_t *params)
{
PMC(0x45C) = (((4 * params->emc_pmc_scratch1 >> 2) + 0x80000000) ^ 0xFFFF) & 0xC000FFFF;
PMC(APBDEV_PMC_IO_DPD3_REQ) = (((4 * params->emc_pmc_scratch1 >> 2) + 0x80000000) ^ 0xFFFF) & 0xC000FFFF;
usleep(params->pmc_io_dpd3_req_wait);
u32 req = (4 * params->emc_pmc_scratch2 >> 2) + 0x80000000;
@@ -393,7 +393,7 @@ break_nosleep:
*(vu32 *)(4 * (params->boot_rom_patch_control + 0x1C000000)) = params->boot_rom_patch_data;
MC(MC_TIMING_CONTROL) = 1;
}
PMC(0x45C) = ((4 * params->emc_pmc_scratch1 >> 2) + 0x40000000) & 0xCFFF0000;
PMC(APBDEV_PMC_IO_DPD3_REQ) = ((4 * params->emc_pmc_scratch1 >> 2) + 0x40000000) & 0xCFFF0000;
usleep(params->pmc_io_dpd3_req_wait);
if (!params->emc_auto_cal_interval)
EMC(EMC_AUTO_CAL_CONFIG) = params->emc_auto_cal_config | 0x200;
@@ -410,7 +410,7 @@ break_nosleep:
}
EMC(EMC_TIMING_CONTROL) = 1;
usleep(params->emc_timing_control_wait);
PMC(0x4E4) &= 0xFFF8007F;
PMC(APBDEV_PMC_DDR_CNTRL) &= 0xFFF8007F;
usleep(params->pmc_ddr_ctrl_wait);
if (params->memory_type == 2)
{
@@ -459,7 +459,7 @@ break_nosleep:
}
}
}
PMC(0x1D0) = params->pmc_ddr_cfg;
PMC(APBDEV_PMC_DDR_CFG) = params->pmc_ddr_cfg;
if (params->memory_type - 1 <= 2)
{
EMC(EMC_ZCAL_INTERVAL) = params->emc_zcal_interval;
@@ -486,7 +486,7 @@ break_nosleep:
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 MC registers.
MC(MC_EMEM_CFG_ACCESS_CTRL) = 1; //Disable write access to a bunch of EMC registers.
}
const void *sdram_get_params()

View File

@@ -1,5 +1,6 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (c) 2018 balika011
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@@ -171,7 +172,7 @@ static const u8 _dram_cfg_0[1896] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x46, 0x2C, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0xEC, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF,
0x01, 0x77, 0x00, 0xFC, 0x00, 0x20, 0xCF, 0x22, 0x00, 0x00, 0xF0, 0xFF,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
@@ -332,7 +333,7 @@ static const u8 _dram_cfg_1[1896] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x46, 0x2C, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0xEC, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF,
0x01, 0x77, 0x00, 0xFC, 0x00, 0x20, 0xCF, 0x22, 0x00, 0x00, 0xF0, 0xFF,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
@@ -493,7 +494,7 @@ static const u8 _dram_cfg_2[1896] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x46, 0x2C, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0xEC, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF,
0x01, 0x77, 0x00, 0xFC, 0x00, 0x20, 0xCF, 0x22, 0x00, 0x00, 0xF0, 0xFF,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
@@ -654,7 +655,7 @@ static const u8 _dram_cfg_3[1896] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x46, 0x2C, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0xEC, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF,
0x01, 0x77, 0x00, 0xFC, 0x00, 0x20, 0xCF, 0x22, 0x00, 0x00, 0xF0, 0xFF,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
@@ -815,7 +816,7 @@ static const u8 _dram_cfg_4[1896] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x46, 0x2C, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0xEC, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF,
0x01, 0x77, 0x00, 0xFC, 0x00, 0x20, 0xCF, 0x22, 0x00, 0x00, 0xF0, 0xFF,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
@@ -976,7 +977,7 @@ static const u8 _dram_cfg_5[1896] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x46, 0x2C, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0xEC, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF,
0x01, 0x77, 0x00, 0xFC, 0x00, 0x20, 0xCF, 0x22, 0x00, 0x00, 0xF0, 0xFF,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
@@ -1137,7 +1138,7 @@ static const u8 _dram_cfg_6[1896] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x46, 0x2C, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0xEC, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF,
0x01, 0x77, 0x00, 0xFC, 0x00, 0x20, 0xCF, 0x22, 0x00, 0x00, 0xF0, 0xFF,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};

View File

@@ -1,5 +1,6 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (c) 2018 balika011
*
* 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,7 +15,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
static const u8 _dram_cfg_lz[1262] = {
static const u8 _dram_cfg_lz[1270] = {
0x17, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00,
0x00, 0x2C, 0x17, 0x04, 0x09, 0x00, 0x17, 0x04, 0x04, 0x17, 0x08, 0x08,
0x17, 0x10, 0x10, 0x00, 0x00, 0x68, 0xBC, 0x01, 0x70, 0x0A, 0x00, 0x00,
@@ -103,22 +104,22 @@ static const u8 _dram_cfg_lz[1262] = {
0x17, 0x17, 0x3A, 0x7E, 0x16, 0x40, 0x17, 0x0C, 0x8B, 0x1F, 0x17, 0x2A,
0x38, 0x1E, 0x17, 0x0A, 0x38, 0x17, 0x13, 0x81, 0x28, 0x00, 0xC0, 0x17,
0x17, 0x55, 0x46, 0x24, 0x17, 0x0A, 0x81, 0x28, 0x17, 0x14, 0x38, 0x17,
0x18, 0x81, 0x60, 0x46, 0x2C, 0x17, 0x06, 0x38, 0xEC, 0x17, 0x0D, 0x16,
0x17, 0x0E, 0x82, 0x3C, 0x17, 0x82, 0x0C, 0x8E, 0x68, 0x17, 0x04, 0x24,
0x17, 0x5C, 0x8E, 0x68, 0x17, 0x07, 0x82, 0x5F, 0x80, 0x17, 0x87, 0x01,
0x8E, 0x68, 0x02, 0x17, 0x81, 0x4A, 0x8E, 0x68, 0x17, 0x0C, 0x87, 0x78,
0x17, 0x85, 0x28, 0x8E, 0x68, 0x17, 0x8E, 0x68, 0x9D, 0x50, 0x17, 0x81,
0x24, 0x8E, 0x68, 0x17, 0x04, 0x2C, 0x17, 0x28, 0x8E, 0x68, 0x17, 0x04,
0x30, 0x17, 0x85, 0x3C, 0x8E, 0x68, 0x12, 0x17, 0x07, 0x85, 0x70, 0x17,
0x88, 0x74, 0x8E, 0x68, 0x17, 0x87, 0x3E, 0x9D, 0x50, 0x0C, 0x17, 0x04,
0x04, 0x17, 0x12, 0x8E, 0x68, 0x18, 0x17, 0x87, 0x12, 0xBB, 0x20, 0x17,
0x83, 0x04, 0x9D, 0x50, 0x15, 0x17, 0x05, 0x8D, 0x76, 0x17, 0x0F, 0x8B,
0x49, 0x17, 0x0B, 0x18, 0x32, 0x00, 0x2F, 0x00, 0x32, 0x00, 0x31, 0x00,
0x34, 0x00, 0x36, 0x00, 0x2F, 0x00, 0x33, 0x17, 0x09, 0x84, 0x0C, 0x17,
0x18, 0x18, 0x17, 0x20, 0x8E, 0x68, 0x15, 0x17, 0x07, 0x5A, 0x17, 0x06,
0x5E, 0x16, 0x00, 0x15, 0x17, 0x82, 0x40, 0x9D, 0x50, 0x17, 0x86, 0x5F,
0xBB, 0x20, 0x3A, 0x00, 0x00, 0x00, 0x1D, 0x17, 0x81, 0x4F, 0xAC, 0x38,
0x3B, 0x17, 0x04, 0x04, 0x17, 0x86, 0x30, 0x8E, 0x68, 0x17, 0x81, 0x53,
0xAC, 0x38, 0x07, 0x17, 0x0D, 0x8E, 0x68, 0xA3, 0x72, 0x17, 0x83, 0x10,
0x8E, 0x68
0x18, 0x81, 0x60, 0x46, 0x2C, 0x17, 0x06, 0x38, 0xEC, 0x00, 0x00, 0x00,
0x01, 0x77, 0x00, 0xFC, 0x00, 0x20, 0xCF, 0x22, 0x17, 0x10, 0x82, 0x3C,
0x17, 0x82, 0x0C, 0x8E, 0x68, 0x17, 0x04, 0x24, 0x17, 0x5C, 0x8E, 0x68,
0x17, 0x07, 0x82, 0x5F, 0x80, 0x17, 0x87, 0x01, 0x8E, 0x68, 0x02, 0x17,
0x81, 0x4A, 0x8E, 0x68, 0x17, 0x0C, 0x87, 0x78, 0x17, 0x85, 0x28, 0x8E,
0x68, 0x17, 0x8E, 0x68, 0x9D, 0x50, 0x17, 0x81, 0x24, 0x8E, 0x68, 0x17,
0x04, 0x2C, 0x17, 0x28, 0x8E, 0x68, 0x17, 0x04, 0x30, 0x17, 0x85, 0x3C,
0x8E, 0x68, 0x12, 0x17, 0x07, 0x85, 0x70, 0x17, 0x88, 0x74, 0x8E, 0x68,
0x17, 0x87, 0x3E, 0x9D, 0x50, 0x0C, 0x17, 0x04, 0x04, 0x17, 0x12, 0x8E,
0x68, 0x18, 0x17, 0x87, 0x12, 0xBB, 0x20, 0x17, 0x83, 0x04, 0x9D, 0x50,
0x15, 0x17, 0x05, 0x8D, 0x76, 0x17, 0x0F, 0x8B, 0x49, 0x17, 0x0B, 0x18,
0x32, 0x00, 0x2F, 0x00, 0x32, 0x00, 0x31, 0x00, 0x34, 0x00, 0x36, 0x00,
0x2F, 0x00, 0x33, 0x17, 0x09, 0x84, 0x0C, 0x17, 0x18, 0x18, 0x17, 0x20,
0x8E, 0x68, 0x15, 0x17, 0x07, 0x5A, 0x17, 0x06, 0x5E, 0x16, 0x00, 0x15,
0x17, 0x82, 0x40, 0x9D, 0x50, 0x17, 0x86, 0x5F, 0xBB, 0x20, 0x3A, 0x00,
0x00, 0x00, 0x1D, 0x17, 0x81, 0x4F, 0xAC, 0x38, 0x3B, 0x17, 0x04, 0x04,
0x17, 0x86, 0x30, 0x8E, 0x68, 0x17, 0x81, 0x53, 0xAC, 0x38, 0x07, 0x17,
0x0D, 0x8E, 0x68, 0xA3, 0x72, 0x17, 0x83, 0x10, 0x8E, 0x68
};

View File

@@ -1,5 +1,7 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (c) 2018 CTCaer
* Copyright (c) 2018 balika011
*
* 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,16 +19,24 @@
#include <string.h>
#include "../sec/tsec.h"
#include "../sec/tsec_t210.h"
#include "../sec/se_t210.h"
#include "../soc/clock.h"
#include "../soc/smmu.h"
#include "../soc/t210.h"
#include "../mem/heap.h"
#include "../mem/mc.h"
#include "../utils/util.h"
#include "../hos/hos.h"
/* #include "../gfx/gfx.h"
extern gfx_con_t gfx_con; */
static int _tsec_dma_wait_idle()
{
u32 timeout = get_tmr_ms() + 10000;
while (!(TSEC(0x1118) & 2))
while (!(TSEC(TSEC_DMATRFCMD) & TSEC_DMATRFCMD_IDLE))
if (get_tmr_ms() > timeout)
return 0;
@@ -38,20 +48,23 @@ static int _tsec_dma_pa_to_internal_100(int not_imem, int i_offset, int pa_offse
u32 cmd;
if (not_imem)
cmd = 0x600; // DMA 0x100 bytes
cmd = TSEC_DMATRFCMD_SIZE_256B; // DMA 256 bytes
else
cmd = 0x10; // dma imem
cmd = TSEC_DMATRFCMD_IMEM; // DMA IMEM (Instruction memmory)
TSEC(0x1114) = i_offset; // tsec_dmatrfmoffs_r
TSEC(0x111C) = pa_offset; // tsec_dmatrffboffs_r
TSEC(0x1118) = cmd; // tsec_dmatrfcmd_r
TSEC(TSEC_DMATRFMOFFS) = i_offset;
TSEC(TSEC_DMATRFFBOFFS) = pa_offset;
TSEC(TSEC_DMATRFCMD) = cmd;
return _tsec_dma_wait_idle();
}
int tsec_query(u8 *dst, u32 rev, void *fw)
int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt)
{
int res = 0;
u8 *fwbuf = NULL;
u32 *pdir, *car, *fuse, *pmc, *flowctrl, *se, *mc, *iram, *evec;
u32 *pkg11_magic_off;
//Enable clocks.
clock_enable_host1x();
@@ -62,64 +75,192 @@ int tsec_query(u8 *dst, u32 rev, void *fw)
clock_enable_kfuse();
//Configure Falcon.
TSEC(0x110C) = 0; // tsec_dmactl_r
TSEC(0x1010) = 0xFFF2; // tsec_irqmset_r
TSEC(0x101C) = 0xFFF0; // tsec_irqdest_r
TSEC(0x1048) = 3; // tsec_itfen_r
TSEC(TSEC_DMACTL) = 0;
TSEC(TSEC_IRQMSET) =
TSEC_IRQMSET_EXT(0xFF) |
TSEC_IRQMSET_WDTMR |
TSEC_IRQMSET_HALT |
TSEC_IRQMSET_EXTERR |
TSEC_IRQMSET_SWGEN0 |
TSEC_IRQMSET_SWGEN1;
TSEC(TSEC_IRQDEST) =
TSEC_IRQDEST_EXT(0xFF) |
TSEC_IRQDEST_HALT |
TSEC_IRQDEST_EXTERR |
TSEC_IRQDEST_SWGEN0 |
TSEC_IRQDEST_SWGEN1;
TSEC(TSEC_ITFEN) = TSEC_ITFEN_CTXEN | TSEC_ITFEN_MTHDEN;
if (!_tsec_dma_wait_idle())
{
res = -1;
goto out;
}
//Load firmware.
u8 *fwbuf = (u8 *)malloc(0x2000);
u8 *fwbuf_aligned = (u8 *)ALIGN((u32)fwbuf + 0x1000, 0x100);
memcpy(fwbuf_aligned, fw, 0xF00);
TSEC(0x1110) = (u32)fwbuf_aligned >> 8;// tsec_dmatrfbase_r
for (u32 addr = 0; addr < 0xF00; addr += 0x100)
if (!_tsec_dma_pa_to_internal_100(0, addr, addr))
//Load firmware or emulate memio environment for newer TSEC fw.
if (kb <= KB_FIRMWARE_VERSION_600)
{
fwbuf = (u8 *)malloc(0x2000);
u8 *fwbuf_aligned = (u8 *)ALIGN((u32)fwbuf + 0x1000, 0x100);
memcpy(fwbuf_aligned, tsec_ctxt->fw, tsec_ctxt->size);
TSEC(TSEC_DMATRFBASE) = (u32)fwbuf_aligned >> 8;
}
else
TSEC(TSEC_DMATRFBASE) = (u32)tsec_ctxt->fw >> 8;
for (u32 addr = 0; addr < tsec_ctxt->size; addr += 0x100)
{
if (!_tsec_dma_pa_to_internal_100(false, addr, addr))
{
res = -2;
goto out_free;
}
}
if (kb >= KB_FIRMWARE_VERSION_620)
{
// Init SMMU translation for TSEC.
pdir = smmu_init_for_tsec();
smmu_init(tsec_ctxt->secmon_base);
// Enable SMMU
if (!smmu_is_used())
smmu_enable();
// Clock reset controller.
car = page_alloc(1);
memcpy(car, (void *)CLOCK_BASE, 0x1000);
car[CLK_RST_CONTROLLER_CLK_SOURCE_TSEC / 4] = 2;
smmu_map(pdir, CLOCK_BASE, (u32)car, 1, _WRITABLE | _READABLE | _NONSECURE);
// Fuse driver.
fuse = page_alloc(1);
memcpy((void *)&fuse[0x800/4], (void *)FUSE_BASE, 0x400);
fuse[0x82C / 4] = 0;
fuse[0x9E0 / 4] = (1 << (kb + 2)) - 1;
fuse[0x9E4 / 4] = (1 << (kb + 2)) - 1;
smmu_map(pdir, (FUSE_BASE - 0x800), (u32)fuse, 1, _READABLE | _NONSECURE);
// Power management controller.
pmc = page_alloc(1);
smmu_map(pdir, RTC_BASE, (u32)pmc, 1, _READABLE | _NONSECURE);
// Flow control.
flowctrl = page_alloc(1);
smmu_map(pdir, FLOW_CTLR_BASE, (u32)flowctrl, 1, _WRITABLE | _NONSECURE);
// Security engine.
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);
mc[MC_IRAM_BOM / 4] = 0;
mc[MC_IRAM_TOM / 4] = 0x80000000;
smmu_map(pdir, MC_BASE, (u32)mc, 1, _READABLE | _NONSECURE);
// IRAM
iram = page_alloc(0x30);
memcpy(iram, tsec_ctxt->pkg1, 0x30000);
// PKG1.1 magic offset.
pkg11_magic_off = (u32 *)(iram + ((tsec_ctxt->pkg11_off + 0x20) / 4));
smmu_map(pdir, 0x40010000, (u32)iram, 0x30, _READABLE | _WRITABLE | _NONSECURE);
// Exception vectors
evec = page_alloc(1);
smmu_map(pdir, EXCP_VEC_BASE, (u32)evec, 1, _READABLE | _WRITABLE | _NONSECURE);
}
//Execute firmware.
HOST1X(0x3300) = 0x34C2E1DA;
TSEC(0x1044) = 0;
TSEC(0x1040) = rev;
TSEC(0x1104) = 0; // tsec_bootvec_r
TSEC(0x1100) = 2; // tsec_cpuctl_r
if (!_tsec_dma_wait_idle())
TSEC(TSEC_STATUS) = 0;
TSEC(TSEC_BOOTKEYVER) = tsec_ctxt->key_ver;
TSEC(TSEC_BOOTVEC) = 0;
TSEC(TSEC_CPUCTL) = TSEC_CPUCTL_STARTCPU;
if (kb <= KB_FIRMWARE_VERSION_600)
{
res = -3;
goto out_free;
}
u32 timeout = get_tmr_ms() + 2000;
while (!TSEC(0x1044))
if (get_tmr_ms() > timeout)
if (!_tsec_dma_wait_idle())
{
res = -4;
res = -3;
goto out_free;
}
u32 timeout = get_tmr_ms() + 2000;
while (!TSEC(TSEC_STATUS))
if (get_tmr_ms() > timeout)
{
res = -4;
goto out_free;
}
if (TSEC(TSEC_STATUS) != 0xB0B0B0B0)
{
res = -5;
goto out_free;
}
if (TSEC(0x1044) != 0xB0B0B0B0)
{
res = -5;
goto out_free;
}
//Fetch result.
HOST1X(0x3300) = 0;
u32 buf[4];
buf[0] = SOR1(0x1E8);
buf[1] = SOR1(0x21C);
buf[2] = SOR1(0x208);
buf[3] = SOR1(0x20C);
SOR1(0x1E8) = 0;
SOR1(0x21C) = 0;
SOR1(0x208) = 0;
SOR1(0x20C) = 0;
memcpy(dst, &buf, 0x10);
//Fetch result.
HOST1X(0x3300) = 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);
buf[2] = SOR1(SOR_NV_PDISP_SOR_TMDS_HDCP_CN_MSB);
buf[3] = SOR1(SOR_NV_PDISP_SOR_TMDS_HDCP_CN_LSB);
SOR1(SOR_NV_PDISP_SOR_DP_HDCP_BKSV_LSB) = 0;
SOR1(SOR_NV_PDISP_SOR_TMDS_HDCP_BKSV_LSB) = 0;
SOR1(SOR_NV_PDISP_SOR_TMDS_HDCP_CN_MSB) = 0;
SOR1(SOR_NV_PDISP_SOR_TMDS_HDCP_CN_LSB) = 0;
memcpy(tsec_keys, &buf, 0x10);
}
else
{
u32 start = get_tmr_us();
u32 k = se[SE_KEYTABLE_DATA0_REG_OFFSET / 4];
u32 key[16] = {0};
u32 kidx = 0;
while (*pkg11_magic_off != HOS_PKG11_MAGIC)
{
smmu_flush_all();
if (k == se[SE_KEYTABLE_DATA0_REG_OFFSET / 4])
continue;
k = se[SE_KEYTABLE_DATA0_REG_OFFSET / 4];
key[kidx++] = k;
// Failsafe.
if ((u32)get_tmr_us() - start > 125000)
break;
}
if (kidx != 8)
{
res = -6;
smmu_deinit_for_tsec();
goto out;
}
// Give some extra time to make sure PKG1.1 is decrypted.
msleep(50);
memcpy(tsec_keys, &key, 0x20);
memcpy(tsec_ctxt->pkg1, iram, 0x30000);
smmu_deinit_for_tsec();
// for (int i = 0; i < kidx; i++)
// gfx_printf(&gfx_con, "key %08X\n", key[i]);
// gfx_printf(&gfx_con, "cpuctl (%08X) mbox (%08X)\n", TSEC(TSEC_CPUCTL), TSEC(TSEC_STATUS));
// u32 errst = MC(MC_ERR_STATUS);
// gfx_printf(&gfx_con, " MC %08X %08X %08X\n", MC(MC_INTSTATUS), errst, MC(MC_ERR_ADR));
// gfx_printf(&gfx_con, " type: %02X\n", errst >> 28);
// gfx_printf(&gfx_con, " smmu: %02X\n", (errst >> 25) & 3);
// gfx_printf(&gfx_con, " dir: %s\n", (errst >> 16) & 1 ? "W" : "R");
// gfx_printf(&gfx_con, " cid: %02x\n", errst & 0xFF);
}
out_free:;
free(fwbuf);

View File

@@ -1,5 +1,6 @@
/*
* 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,
@@ -19,6 +20,16 @@
#include "../utils/types.h"
int tsec_query(u8 *dst, u32 rev, void *fw);
typedef struct _tsec_ctxt_t
{
u32 key_ver;
void *fw;
u32 size;
void *pkg1;
u32 pkg11_off;
u32 secmon_base;
} tsec_ctxt_t;
int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt);
#endif

View File

@@ -0,0 +1,50 @@
/*
* Copyright (c) 2018 CTCaer
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _TSEC_T210_H_
#define _TSEC_T210_H_
#define TSEC_BOOTKEYVER 0x1040
#define TSEC_STATUS 0x1044
#define TSEC_ITFEN 0x1048
#define TSEC_ITFEN_CTXEN (1 << 0)
#define TSEC_ITFEN_MTHDEN (1 << 1)
#define TSEC_IRQMSET 0x1010
#define TSEC_IRQMSET_WDTMR (1 << 1)
#define TSEC_IRQMSET_HALT (1 << 4)
#define TSEC_IRQMSET_EXTERR (1 << 5)
#define TSEC_IRQMSET_SWGEN0 (1 << 6)
#define TSEC_IRQMSET_SWGEN1 (1 << 7)
#define TSEC_IRQMSET_EXT(val) (((val) & 0xFF) << 8)
#define TSEC_IRQDEST 0x101C
#define TSEC_IRQDEST_HALT (1 << 4)
#define TSEC_IRQDEST_EXTERR (1 << 5)
#define TSEC_IRQDEST_SWGEN0 (1 << 6)
#define TSEC_IRQDEST_SWGEN1 (1 << 7)
#define TSEC_IRQDEST_EXT(val) (((val) & 0xFF) << 8)
#define TSEC_CPUCTL 0x1100
#define TSEC_CPUCTL_STARTCPU (1 << 1)
#define TSEC_BOOTVEC 0x1104
#define TSEC_DMACTL 0x110C
#define TSEC_DMATRFBASE 0x1110
#define TSEC_DMATRFMOFFS 0x1114
#define TSEC_DMATRFCMD 0x1118
#define TSEC_DMATRFCMD_IDLE (1 << 1)
#define TSEC_DMATRFCMD_IMEM (1 << 4)
#define TSEC_DMATRFCMD_SIZE_256B (6 << 8)
#define TSEC_DMATRFFBOFFS 0x111C
#endif

View File

@@ -19,37 +19,61 @@
#include "../utils/util.h"
#include "../storage/sdmmc.h"
/* 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 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 }
};
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, 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 }
};
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 };
static clock_t _clock_unk2 = { CLK_RST_CONTROLLER_RST_DEVICES_V, CLK_RST_CONTROLLER_CLK_OUT_ENB_V, CLK_RST_CONTROLLER_RST_SOURCE, 0x1E, 0, 0 };
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
};
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_host1x = { CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_HOST1X, 0x1C, 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 };
static clock_t _clock_sor_safe = { CLK_RST_CONTROLLER_RST_DEVICES_Y, CLK_RST_CONTROLLER_CLK_OUT_ENB_Y, CLK_RST_CONTROLLER_RST_SOURCE, 0x1E, 0, 0 };
static clock_t _clock_sor0 = { CLK_RST_CONTROLLER_RST_DEVICES_X, CLK_RST_CONTROLLER_CLK_OUT_ENB_X, CLK_RST_CONTROLLER_RST_SOURCE, 0x16, 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 };
static clock_t _clock_kfuse = { CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_RST_CONTROLLER_RST_SOURCE, 8, 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
};
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
};
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
};
static clock_t _clock_sor0 = {
CLK_RST_CONTROLLER_RST_DEVICES_X, CLK_RST_CONTROLLER_CLK_OUT_ENB_X, CLK_NO_SOURCE, 0x16, 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
};
static clock_t _clock_kfuse = {
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_RST_CONTROLLER_RST_SOURCE, 0x1B, 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};
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
};
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
};
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};
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
};
void clock_enable(const clock_t *clk)
{
@@ -157,11 +181,11 @@ void clock_disable_sor1()
void clock_enable_kfuse()
{
//clock_enable(&_clock_kfuse);
CLOCK(0x8) = (CLOCK(0x8) & 0xFFFFFEFF) | 0x100;
CLOCK(0x14) &= 0xFFFFFEFF;
CLOCK(0x14) = (CLOCK(0x14) & 0xFFFFFEFF) | 0x100;
CLOCK(CLK_RST_CONTROLLER_RST_DEVICES_H) = (CLOCK(CLK_RST_CONTROLLER_RST_DEVICES_H) & 0xFFFFFEFF) | 0x100;
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_H) &= 0xFFFFFEFF;
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_H) = (CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_H) & 0xFFFFFEFF) | 0x100;
usleep(10);
CLOCK(0x8) &= 0xFFFFFEFF;
CLOCK(CLK_RST_CONTROLLER_RST_DEVICES_H) &= 0xFFFFFEFF;
usleep(20);
}

View File

@@ -116,6 +116,8 @@
#define CLK_RST_CONTROLLER_CLK_SOURCE_NVENC 0x6A0
#define CLK_RST_CONTROLLER_SE_SUPER_CLK_DIVIDER 0x704
#define CLK_NO_SOURCE 0x0
/*! Generic clock descriptor. */
typedef struct _clock_t
{

View File

@@ -30,10 +30,12 @@ void _cluster_enable_power()
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_GPIO5, MAX77620_CNFG_GPIO_DRV_PUSHPULL | MAX77620_CNFG_GPIO_OUTPUT_VAL_HIGH);
// 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); // 1-3.x: MAX77621_NFSR_ENABLE
MAX77621_AD_ENABLE | MAX77621_NFSR_ENABLE | MAX77621_SNS_ENABLE);
// 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); // 1-3.x: MAX77621_T_JUNCTION_120 | MAX77621_CKKADV_TRIP_DISABLE | MAX77621_INDUCTOR_NOMINAL
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);
}
@@ -112,7 +114,7 @@ void cluster_boot_cpu0(u32 entry)
while (!(FLOW_CTLR(FLOW_CTLR_RAM_REPAIR) & 2))
;
EXCP_VEC(0x100) = 0;
EXCP_VEC(EVP_CPU_RESET_VECTOR) = 0;
// Set reset vector.
SB(SB_AA64_RESET_LOW) = entry | 1;
@@ -125,6 +127,7 @@ void cluster_boot_cpu0(u32 entry)
CLOCK(CLK_RST_CONTROLLER_RST_DEVICES_V) &= 0xFFFFFFF7;
// Clear NONCPU reset.
CLOCK(CLK_RST_CONTROLLER_RST_CPUG_CMPLX_CLR) = 0x20000000;
// Clear CPU{0,1,2,3} POR and CORE, CX0, L2, and DBG reset.
CLOCK(CLK_RST_CONTROLLER_RST_CPUG_CMPLX_CLR) = 0x411F000F;
// Clear CPU0 reset.
// < 5.x: 0x411F000F, Clear CPU{0,1,2,3} POR and CORE, CX0, L2, and DBG reset.
CLOCK(CLK_RST_CONTROLLER_RST_CPUG_CMPLX_CLR) = 0x41010001;
}

View File

@@ -20,10 +20,10 @@
#include "../utils/types.h"
/*! Flow controller registers. */
#define LOW_CTLR_HALT_CPU0_EVENTS 0x0
#define LOW_CTLR_HALT_CPU1_EVENTS 0x14
#define LOW_CTLR_HALT_CPU2_EVENTS 0x1C
#define LOW_CTLR_HALT_CPU3_EVENTS 0x24
#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

View File

@@ -222,7 +222,7 @@ int fuse_read_ipatch(void (*ipatch)(u32 offset, u32 value))
{
for (u32 i = 0; i < ipatch_count; i++)
{
u32 word = words[i];
u32 word = words[i + 1];
u32 addr = (word >> 16) * 2;
u32 data = word & 0xffff;

View File

@@ -36,7 +36,12 @@
#define FUSE_DISABLEREGPROGRAM 0x2C
#define FUSE_WRITE_ACCESS_SW 0x30
#define FUSE_PWR_GOOD_SW 0x34
#define FUSE_SKU_INFO 0x110
#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
/*! Fuse commands. */
#define FUSE_READ 0x1

264
bootloader/soc/hw_init.c Normal file
View File

@@ -0,0 +1,264 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (c) 2018 CTCaer
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <string.h>
#include "hw_init.h"
#include "../gfx/di.h"
#include "../mem/mc.h"
#include "../mem/sdram.h"
#include "../power/max77620.h"
#include "../power/max7762x.h"
#include "../sec/se.h"
#include "../sec/se_t210.h"
#include "../soc/clock.h"
#include "../soc/fuse.h"
#include "../soc/gpio.h"
#include "../soc/i2c.h"
#include "../soc/pinmux.h"
#include "../soc/pmc.h"
#include "../soc/t210.h"
#include "../soc/uart.h"
#include "../storage/sdmmc.h"
#include "../utils/util.h"
extern sdmmc_t sd_sdmmc;
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;
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;
}
void _config_gpios()
{
PINMUX_AUX(PINMUX_AUX_UART2_TX) = 0;
PINMUX_AUX(PINMUX_AUX_UART3_TX) = 0;
PINMUX_AUX(PINMUX_AUX_GPIO_PE6) = PINMUX_INPUT_ENABLE;
PINMUX_AUX(PINMUX_AUX_GPIO_PH6) = PINMUX_INPUT_ENABLE;
#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
gpio_config(GPIO_PORT_E, GPIO_PIN_6, GPIO_MODE_GPIO);
gpio_config(GPIO_PORT_H, GPIO_PIN_6, GPIO_MODE_GPIO);
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);
gpio_output_enable(GPIO_PORT_H, GPIO_PIN_6, GPIO_OUTPUT_DISABLE);
pinmux_config_i2c(I2C_1);
pinmux_config_i2c(I2C_5);
pinmux_config_uart(UART_A);
// Configure volume up/down as inputs.
gpio_config(GPIO_PORT_X, GPIO_PIN_6, GPIO_MODE_GPIO);
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);
}
void _config_pmc_scratch()
{
PMC(APBDEV_PMC_SCRATCH20) &= 0xFFF3FFFF;
PMC(APBDEV_PMC_SCRATCH190) &= 0xFFFFFFFE;
PMC(APBDEV_PMC_SECURE_SCRATCH21) |= 0x10;
}
void _mbist_workaround()
{
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;
usleep(2);
I2S(I2S1_CTRL) |= I2S_CTRL_MASTER_EN;
I2S(I2S1_CG) &= ~I2S_CG_SLCG_ENABLE;
I2S(I2S2_CTRL) |= I2S_CTRL_MASTER_EN;
I2S(I2S2_CG) &= ~I2S_CG_SLCG_ENABLE;
I2S(I2S3_CTRL) |= I2S_CTRL_MASTER_EN;
I2S(I2S3_CG) &= ~I2S_CG_SLCG_ENABLE;
I2S(I2S4_CTRL) |= I2S_CTRL_MASTER_EN;
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;
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;
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;
}
void _config_se_brom()
{
// Bootrom part we skipped.
u32 sbk[4] = {
FUSE(FUSE_PRIVATE_KEY0),
FUSE(FUSE_PRIVATE_KEY1),
FUSE(FUSE_PRIVATE_KEY2),
FUSE(FUSE_PRIVATE_KEY3)
};
// Set SBK to slot 14.
se_aes_key_set(14, sbk, 0x10);
// Lock SBK from being read.
SE(SE_KEY_TABLE_ACCESS_REG_OFFSET + 14 * 4) = 0x7E;
// This memset needs to happen here, else TZRAM will behave weirdly later on.
memset((void *)TZRAM_BASE, 0, 0x10000);
PMC(APBDEV_PMC_CRYPTO_OP) = 0;
SE(SE_INT_STATUS_REG_OFFSET) = 0x1F;
// Lock SSK (although it's not set and unused anyways).
SE(SE_KEY_TABLE_ACCESS_REG_OFFSET + 15 * 4) = 0x7E;
// Clear the boot reason to avoid problems later
PMC(APBDEV_PMC_SCRATCH200) = 0x0;
PMC(APBDEV_PMC_RST_STATUS) = 0x0;
APB_MISC(APB_MISC_PP_STRAPPING_OPT_A) = (APB_MISC(APB_MISC_PP_STRAPPING_OPT_A) & 0xF0) | (7 << 10);
}
void config_hw()
{
// 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();
#ifdef DEBUG_UART_PORT
clock_enable_uart(DEBUG_UART_PORT);
uart_init(DEBUG_UART_PORT, 115200);
#endif
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, 0x40);
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_ONOFFCNFG1, 0x78); // PWR delay for forced shutdown off.
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_CFG0, 0x38);
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_CFG1, 0x3A);
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_CFG2, 0x38);
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_LDO4, 0xF);
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_LDO8, 0xC7);
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_SD0, 0x4F);
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_SD1, 0x29);
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_SD3, 0x1B);
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_GPIO3, 0x22); // 3.x+
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_SD0, 42); //42 = (1125000uV - 600000) / 12500 -> 1.125V
_config_pmc_scratch(); // Missing from 4.x+
CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = (CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) & 0xFFFF8888) | 0x3333;
sdram_init();
}
void reconfig_hw_workaround(bool extra_reconfig, u32 magic)
{
// 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.
if (extra_reconfig)
{
msleep(10);
PMC(APBDEV_PMC_PWR_DET_VAL) |= PMC_PWR_DET_SDMMC1_IO_EN;
clock_disable_cl_dvfs();
// Disable Joy-con GPIOs.
gpio_config(GPIO_PORT_G, GPIO_PIN_0, GPIO_MODE_SPIO);
gpio_config(GPIO_PORT_D, GPIO_PIN_1, GPIO_MODE_SPIO);
gpio_config(GPIO_PORT_E, GPIO_PIN_6, GPIO_MODE_SPIO);
gpio_config(GPIO_PORT_H, GPIO_PIN_6, GPIO_MODE_SPIO);
}
// Power off display.
display_end();
// Enable clock to USBD and init SDMMC1 to avoid hangs with bad hw inits.
if (magic == 0xBAADF00D)
{
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_L) |= (1 << 22);
sdmmc_init(&sd_sdmmc, SDMMC_1, SDMMC_POWER_3_3, SDMMC_BUS_WIDTH_1, 5, 0);
clock_disable_cl_dvfs();
msleep(200);
}
}

26
bootloader/soc/hw_init.h Normal file
View File

@@ -0,0 +1,26 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (c) 2018 CTCaer
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _HW_INIT_H_
#define _HW_INIT_H_
#include "../utils/types.h"
void config_hw();
void reconfig_hw_workaround(bool extra_reconfig, u32 magic);
#endif

View File

@@ -19,8 +19,8 @@
void pinmux_config_uart(u32 idx)
{
PINMUX_AUX(PINMUX_AUX_UARTX_RX(idx)) = 0;
PINMUX_AUX(PINMUX_AUX_UARTX_TX(idx)) = PINMUX_INPUT_ENABLE | PINMUX_PULL_UP;
PINMUX_AUX(PINMUX_AUX_UARTX_TX(idx)) = 0;
PINMUX_AUX(PINMUX_AUX_UARTX_RX(idx)) = PINMUX_INPUT_ENABLE | PINMUX_PULL_UP;
PINMUX_AUX(PINMUX_AUX_UARTX_RTS(idx)) = 0;
PINMUX_AUX(PINMUX_AUX_UARTX_CTS(idx)) = PINMUX_INPUT_ENABLE | PINMUX_PULL_DOWN;
}

View File

@@ -19,6 +19,8 @@
#define _PMC_H_
/*! PMC registers. */
#define APBDEV_PMC_CNTRL 0x0
#define PMC_CNTRL_MAIN_RST (1 << 4)
#define APBDEV_PMC_SEC_DISABLE 0x4
#define APBDEV_PMC_PWRGATE_TOGGLE 0x30
#define APBDEV_PMC_PWRGATE_STATUS 0x38
@@ -27,6 +29,7 @@
#define APBDEV_PMC_SCRATCH1 0x54
#define APBDEV_PMC_SCRATCH20 0xA0
#define APBDEV_PMC_PWR_DET_VAL 0xE4
#define PMC_PWR_DET_SDMMC1_IO_EN (1 << 12)
#define APBDEV_PMC_DDR_PWR 0xE8
#define APBDEV_PMC_CRYPTO_OP 0xF4
#define APBDEV_PMC_OSC_EDPD_OVER 0x1A4
@@ -34,6 +37,7 @@
#define APBDEV_PMC_IO_DPD_REQ 0x1B8
#define APBDEV_PMC_IO_DPD2_REQ 0x1C0
#define APBDEV_PMC_VDDP_SEL 0x1CC
#define APBDEV_PMC_DDR_CFG 0x1D0
#define APBDEV_PMC_SCRATCH49 0x244
#define APBDEV_PMC_TSC_MULT 0x2B4
#define APBDEV_PMC_SEC_DISABLE2 0x2C4
@@ -44,6 +48,7 @@
#define APBDEV_PMC_SECURE_SCRATCH32 0x360
#define APBDEV_PMC_SECURE_SCRATCH49 0x3A4
#define APBDEV_PMC_CNTRL2 0x440
#define APBDEV_PMC_IO_DPD3_REQ 0x45C
#define APBDEV_PMC_IO_DPD4_REQ 0x464
#define APBDEV_PMC_UTMIP_PAD_CFG1 0x4C4
#define APBDEV_PMC_UTMIP_PAD_CFG3 0x4CC

171
bootloader/soc/smmu.c Normal file
View File

@@ -0,0 +1,171 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (c) 2018 balika011
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <string.h>
#include "smmu.h"
#include "../soc/cluster.h"
#include "../soc/t210.h"
#include "../mem/mc_t210.h"
#include "../utils/util.h"
#include "../utils/aarch64_util.h"
bool smmu_used = false;
u8 *_pageheap = (u8 *)SMMU_HEAP_ADDR;
//Enabling SMMU requires a TZ secure write: MC(MC_SMMU_CONFIG) = 1;
u8 smmu_payload[] __attribute__((aligned(16))) = {
0x41, 0x01, 0x00, 0x58, // 0x00: LDR X1, =0x70019010
0x20, 0x00, 0x80, 0xD2, // 0x04: MOV X0, #0x1
0x20, 0x00, 0x00, 0xB9, // 0x08: STR W0, [X1]
0x1F, 0x71, 0x08, 0xD5, // 0x0C: IC IALLUIS
0x9F, 0x3B, 0x03, 0xD5, // 0x10: DSB ISH
0xFE, 0xFF, 0xFF, 0x17, // 0x14: B loop
0x00, 0x00, 0x80, 0xD2, // 0x18: MOV X0, #0x0
0x20, 0x00, 0x00, 0xB9, // 0x1C: STR W0, [X1]
0x80, 0x00, 0x00, 0x58, // 0x20: LDR X0, =0x4002B000
0x00, 0x00, 0x1F, 0xD6, // 0x28: BR X0
0x10, 0x90, 0x01, 0x70, // 0x28: MC_SMMU_CONFIG
0x00, 0x00, 0x00, 0x00, // 0x2C:
0x00, 0x00, 0x00, 0x00, // 0x30: secmon address
0x00, 0x00, 0x00, 0x00 // 0x34:
};
void *page_alloc(u32 num)
{
u8 *res = _pageheap;
_pageheap += 0x1000 * num;
memset(res, 0, 0x1000 * num);
return res;
}
u32 *smmu_alloc_pdir()
{
u32 *pdir = (u32 *)page_alloc(1);
for (int pdn = 0; pdn < SMMU_PDIR_COUNT; pdn++)
pdir[pdn] = _PDE_VACANT(pdn);
return pdir;
}
void smmu_flush_regs()
{
(void)MC(MC_SMMU_PTB_DATA);
}
void smmu_flush_all()
{
MC(MC_SMMU_PTC_FLUSH) = 0;
smmu_flush_regs();
MC(MC_SMMU_TLB_FLUSH) = 0;
smmu_flush_regs();
}
void smmu_init(u32 secmon_base)
{
MC(MC_SMMU_PTB_ASID) = 0;
MC(MC_SMMU_PTB_DATA) = 0;
MC(MC_SMMU_TLB_CONFIG) = 0x30000030;
MC(MC_SMMU_PTC_CONFIG) = 0x28000F3F;
MC(MC_SMMU_PTC_FLUSH) = 0;
MC(MC_SMMU_TLB_FLUSH) = 0;
// Set the secmon address
*(u32 *)(smmu_payload + 0x30) = secmon_base;
}
void smmu_enable()
{
if (smmu_used)
return;
cluster_boot_cpu0((u32)smmu_payload);
smmu_used = true;
msleep(150);
smmu_flush_all();
}
bool smmu_is_used()
{
return smmu_used;
}
void smmu_exit()
{
*(uint32_t *)(smmu_payload + 0x14) = _NOP();
}
u32 *smmu_init_domain4(u32 dev_base, u32 asid)
{
u32 *pdir = smmu_alloc_pdir();
MC(MC_SMMU_PTB_ASID) = asid;
MC(MC_SMMU_PTB_DATA) = SMMU_MK_PDIR((u32)pdir, _PDIR_ATTR);
smmu_flush_regs();
MC(dev_base) = 0x80000000 | (asid << 24) | (asid << 16) | (asid << 8) | (asid);
smmu_flush_regs();
return pdir;
}
u32 *smmu_get_pte(u32 *pdir, u32 iova)
{
u32 ptn = SMMU_ADDR_TO_PFN(iova);
u32 pdn = SMMU_ADDR_TO_PDN(iova);
u32 *ptbl;
if (pdir[pdn] != _PDE_VACANT(pdn))
ptbl = (u32 *)((pdir[pdn] & SMMU_PFN_MASK) << SMMU_PDIR_SHIFT);
else
{
ptbl = (u32 *)page_alloc(1);
u32 addr = SMMU_PDN_TO_ADDR(pdn);
for (int pn = 0; pn < SMMU_PTBL_COUNT; pn++, addr += SMMU_PAGE_SIZE)
ptbl[pn] = _PTE_VACANT(addr);
pdir[pdn] = SMMU_MK_PDE((u32)ptbl, _PDE_ATTR | _PDE_NEXT);
smmu_flush_all();
}
return &ptbl[ptn % SMMU_PTBL_COUNT];
}
void smmu_map(u32 *pdir, u32 addr, u32 page, int cnt, u32 attr)
{
for (int i = 0; i < cnt; i++)
{
u32 *pte = smmu_get_pte(pdir, addr);
*pte = SMMU_ADDR_TO_PFN(page) | attr;
addr += 0x1000;
page += 0x1000;
}
smmu_flush_all();
}
u32 *smmu_init_for_tsec()
{
return smmu_init_domain4(MC_SMMU_TSEC_ASID, 1);
}
void smmu_deinit_for_tsec()
{
MC(MC_SMMU_PTB_ASID) = 1;
MC(MC_SMMU_PTB_DATA) = 0;
MC(MC_SMMU_TSEC_ASID) = 0;
smmu_flush_regs();
}

82
bootloader/soc/smmu.h Normal file
View File

@@ -0,0 +1,82 @@
/*
* Copyright (c) 2018 naehrwert
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "../utils/types.h"
#define SMMU_HEAP_ADDR 0xA0000000
#define MC_INTSTATUS 0x0
#define MC_INTMASK 0x4
#define MC_ERR_STATUS 0x8
#define MC_ERR_ADR 0xc
#define MC_SMMU_CONFIG 0x10
#define MC_SMMU_TLB_CONFIG 0x14
#define MC_SMMU_PTC_CONFIG 0x18
#define MC_SMMU_PTB_ASID 0x1c
#define MC_SMMU_PTB_DATA 0x20
#define MC_SMMU_TLB_FLUSH 0x30
#define MC_SMMU_PTC_FLUSH 0x34
#define MC_SMMU_ASID_SECURITY 0x38
#define MC_SMMU_TSEC_ASID 0x294
#define MC_SMMU_TRANSLATION_ENABLE_0 0x228
#define MC_SMMU_TRANSLATION_ENABLE_1 0x22c
#define MC_SMMU_TRANSLATION_ENABLE_2 0x230
#define MC_SMMU_TRANSLATION_ENABLE_3 0x234
#define MC_SMMU_TRANSLATION_ENABLE_4 0xb98
#define SMMU_PDE_NEXT_SHIFT 28
#define MC_SMMU_PTB_DATA_0_ASID_NONSECURE_SHIFT 29
#define MC_SMMU_PTB_DATA_0_ASID_WRITABLE_SHIFT 30
#define MC_SMMU_PTB_DATA_0_ASID_READABLE_SHIFT 31
#define SMMU_PAGE_SHIFT 12
#define SMMU_PAGE_SIZE (1 << SMMU_PAGE_SHIFT)
#define SMMU_PDIR_COUNT 1024
#define SMMU_PDIR_SIZE (sizeof(u32) * SMMU_PDIR_COUNT)
#define SMMU_PTBL_COUNT 1024
#define SMMU_PTBL_SIZE (sizeof(u32) * SMMU_PTBL_COUNT)
#define SMMU_PDIR_SHIFT 12
#define SMMU_PDE_SHIFT 12
#define SMMU_PTE_SHIFT 12
#define SMMU_PFN_MASK 0x000FFFFF
#define SMMU_ADDR_TO_PFN(addr) ((addr) >> 12)
#define SMMU_ADDR_TO_PDN(addr) ((addr) >> 22)
#define SMMU_PDN_TO_ADDR(addr) ((pdn) << 22)
#define _READABLE (1 << MC_SMMU_PTB_DATA_0_ASID_READABLE_SHIFT)
#define _WRITABLE (1 << MC_SMMU_PTB_DATA_0_ASID_WRITABLE_SHIFT)
#define _NONSECURE (1 << MC_SMMU_PTB_DATA_0_ASID_NONSECURE_SHIFT)
#define _PDE_NEXT (1 << SMMU_PDE_NEXT_SHIFT)
#define _MASK_ATTR (_READABLE | _WRITABLE | _NONSECURE)
#define _PDIR_ATTR (_READABLE | _WRITABLE | _NONSECURE)
#define _PDE_ATTR (_READABLE | _WRITABLE | _NONSECURE)
#define _PDE_VACANT(pdn) (((pdn) << 10) | _PDE_ATTR)
#define _PTE_ATTR (_READABLE | _WRITABLE | _NONSECURE)
#define _PTE_VACANT(addr) (((addr) >> SMMU_PAGE_SHIFT) | _PTE_ATTR)
#define SMMU_MK_PDIR(page, attr) (((page) >> SMMU_PDIR_SHIFT) | (attr))
#define SMMU_MK_PDE(page, attr) (((page) >> SMMU_PDE_SHIFT) | (attr))
void *page_alloc(u32 num);
u32 *smmu_alloc_pdir();
void smmu_flush_regs();
void smmu_flush_all();
void smmu_init(u32 secmon_base);
void smmu_enable();
bool smmu_is_used();
void smmu_exit();
u32 *smmu_init_domain4(u32 dev_base, u32 asid);
u32 *smmu_get_pte(u32 *pdir, u32 iova);
void smmu_map(u32 *pdir, u32 addr, u32 page, int cnt, u32 attr);
u32 *smmu_init_for_tsec();
void smmu_deinit_for_tsec();

View File

@@ -56,8 +56,9 @@
#define MC_BASE 0x70019000
#define EMC_BASE 0x7001B000
#define MIPI_CAL_BASE 0x700E3000
#define I2S_BASE 0x702D1000
#define CL_DVFS_BASE 0x70110000
#define I2S_BASE 0x702D1000
#define TZRAM_BASE 0x7C010000
#define _REG(base, off) *(vu32 *)((base) + (off))
@@ -99,6 +100,9 @@
#define CL_DVFS(off) _REG(CL_DVFS_BASE, off)
#define TEST_REG(off) _REG(0x0, off)
/*! EVP registers. */
#define EVP_CPU_RESET_VECTOR 0x100
/*! Misc registers. */
#define APB_MISC_PP_STRAPPING_OPT_A 0x08
#define APB_MISC_PP_PINMUX_GLOBAL 0x40
@@ -112,10 +116,65 @@
/*! Secure boot registers. */
#define SB_CSR 0x0
#define SB_AA64_RESET_LOW 0x30
#define SB_AA64_RESET_LOW 0x30
#define SB_AA64_RESET_HIGH 0x34
/*! SOR registers. */
#define SOR_NV_PDISP_SOR_DP_HDCP_BKSV_LSB 0x1E8
#define SOR_NV_PDISP_SOR_TMDS_HDCP_BKSV_LSB 0x21C
#define SOR_NV_PDISP_SOR_TMDS_HDCP_CN_MSB 0x208
#define SOR_NV_PDISP_SOR_TMDS_HDCP_CN_LSB 0x20C
/*! RTC registers. */
#define APBDEV_RTC_SECONDS 0x8
#define APBDEV_RTC_SHADOW_SECONDS 0xC
#define APBDEV_RTC_MILLI_SECONDS 0x10
/*! SYSCTR0 registers. */
#define SYSCTR0_CNTFID0 0x20
#define SYSCTR0_CNTFID0 0x20
#define SYSCTR0_CNTCR 0x00
#define SYSCTR0_COUNTERID0 0xFE0
#define SYSCTR0_COUNTERID1 0xFE4
#define SYSCTR0_COUNTERID2 0xFE8
#define SYSCTR0_COUNTERID3 0xFEC
#define SYSCTR0_COUNTERID4 0xFD0
#define SYSCTR0_COUNTERID5 0xFD4
#define SYSCTR0_COUNTERID6 0xFD8
#define SYSCTR0_COUNTERID7 0xFDC
#define SYSCTR0_COUNTERID8 0xFF0
#define SYSCTR0_COUNTERID9 0xFF4
#define SYSCTR0_COUNTERID10 0xFF8
#define SYSCTR0_COUNTERID11 0xFFC
/*! TMR registers. */
#define TIMERUS_CNTR_1US (0x10 + 0x0)
#define TIMERUS_USEC_CFG (0x10 + 0x4)
#define TIMER_TMR9_TMR_PTV 0x80
#define TIMER_EN (1 << 31)
#define TIMER_PER_EN (1 << 30)
#define TIMER_WDT4_CONFIG (0x100 + 0x80)
#define TIMER_SRC(TMR) (TMR & 0xF)
#define TIMER_PER(PER) ((PER & 0xFF) << 4)
#define TIMER_SYSRESET_EN (1 << 14)
#define TIMER_PMCRESET_EN (1 << 15)
#define TIMER_WDT4_COMMAND (0x108 + 0x80)
#define TIMER_START_CNT (1 << 0)
#define TIMER_CNT_DISABLE (1 << 1)
#define TIMER_WDT4_UNLOCK_PATTERN (0x10C + 0x80)
#define TIMER_MAGIC_PTRN 0xC45A
/*! I2S registers. */
#define I2S1_CG 0x88
#define I2S1_CTRL 0xA0
#define I2S2_CG 0x188
#define I2S2_CTRL 0x1A0
#define I2S3_CG 0x288
#define I2S3_CTRL 0x2A0
#define I2S4_CG 0x388
#define I2S4_CTRL 0x3A0
#define I2S5_CG 0x488
#define I2S5_CTRL 0x4A0
#define I2S_CG_SLCG_ENABLE (1 << 0)
#define I2S_CTRL_MASTER_EN (1 << 10)
#endif

View File

@@ -25,32 +25,37 @@ void uart_init(u32 idx, u32 baud)
{
uart_t *uart = (uart_t *)(UART_BASE + uart_baseoff[idx]);
//Set baud rate.
u32 rate = (8 * baud + 408000000) / (16 * baud);
uart->UART_LCR = 0x80; //Enable DLAB.
uart->UART_THR_DLAB = (u8)rate; //Divisor latch LSB.
uart->UART_IER_DLAB = (u8)(rate >> 8); //Divisor latch MSB.
uart->UART_LCR = 0; //Diable DLAB.
// Make sure no data is being sent.
uart_wait_idle(idx, UART_TX_IDLE);
//Setup UART in fifo mode.
uart->UART_IER_DLAB = 0;
uart->UART_IIR_FCR = 7; //Enable and clear TX and RX FIFOs.
(void)uart->UART_LSR;
// Misc settings.
u32 rate = (8 * baud + 408000000) / (16 * baud);
uart->UART_IER_DLAB = 0; // Disable interrupts.
uart->UART_MCR = 0; // Disable hardware flow control.
uart->UART_LCR = UART_LCR_DLAB | UART_LCR_WORD_LENGTH_8; // Enable DLAB & set 8n1 mode.
uart->UART_THR_DLAB = (u8)rate; // Divisor latch LSB.
uart->UART_IER_DLAB = (u8)(rate >> 8); // Divisor latch MSB.
uart->UART_LCR = UART_LCR_WORD_LENGTH_8; // Diable DLAB.
// Setup and flush fifo.
uart->UART_IIR_FCR = UART_IIR_FCR_EN_FIFO | UART_IIR_FCR_RX_CLR | UART_IIR_FCR_TX_CLR;
usleep(3 * ((baud + 999999) / baud));
uart->UART_LCR = 3; //Set word length 8.
uart->UART_MCR = 0;
uart->UART_MSR = 0;
uart->UART_IRDA_CSR = 0;
uart->UART_RX_FIFO_CFG = 1;
uart->UART_MIE = 0;
uart->UART_ASR = 0;
uart_wait_idle(idx, UART_TX_IDLE | UART_RX_IDLE);
}
void uart_wait_idle(u32 idx, u32 which)
{
uart_t *uart = (uart_t *)(UART_BASE + uart_baseoff[idx]);
while (!(uart->UART_VENDOR_STATUS & which))
;
if (UART_TX_IDLE & which)
{
while (!(uart->UART_LSR & UART_LSR_TMTY))
;
}
if (UART_RX_IDLE & which)
{
while (uart->UART_LSR & UART_LSR_RDR)
;
}
}
void uart_send(u32 idx, u8 *buf, u32 len)
@@ -59,7 +64,7 @@ void uart_send(u32 idx, u8 *buf, u32 len)
for (u32 i = 0; i != len; i++)
{
while (uart->UART_LSR & UART_TX_FIFO_FULL)
while (!(uart->UART_LSR & UART_LSR_THRE))
;
uart->UART_THR_DLAB = buf[i];
};
@@ -71,7 +76,7 @@ void uart_recv(u32 idx, u8 *buf, u32 len)
for (u32 i = 0; i != len; i++)
{
while (uart->UART_LSR & UART_RX_FIFO_EMPTY)
while (!(uart->UART_LSR & UART_LSR_RDR))
;
buf[i] = uart->UART_THR_DLAB;
};

View File

@@ -28,11 +28,21 @@
#define BAUD_115200 115200
#define UART_TX_IDLE 0x00000001
#define UART_RX_IDLE 0x00000002
#define UART_TX_IDLE 0x1
#define UART_RX_IDLE 0x2
#define UART_TX_FIFO_FULL 0x100
#define UART_RX_FIFO_EMPTY 0x200
#define UART_LCR_DLAB 0x80
#define UART_LCR_WORD_LENGTH_8 0x3
#define UART_LSR_RDR 0x1
#define UART_LSR_THRE 0x20
#define UART_LSR_TMTY 0x40
#define UART_IIR_FCR_TX_CLR 0x4
#define UART_IIR_FCR_RX_CLR 0x2
#define UART_IIR_FCR_EN_FIFO 0x1
typedef struct _uart_t
{
/* 0x00 */ vu32 UART_THR_DLAB;

View File

@@ -21,7 +21,7 @@
#include "../mem/heap.h"
#include "../utils/types.h"
char *dirlist(const char *directory, const char *pattern)
char *dirlist(const char *directory, const char *pattern, bool includeHiddenFiles)
{
u8 max_entries = 61;
@@ -40,7 +40,7 @@ char *dirlist(const char *directory, const char *pattern)
res = f_readdir(&dir, &fno);
if (res || !fno.fname[0])
break;
if (!(fno.fattrib & AM_DIR))
if (!(fno.fattrib & AM_DIR) && (fno.fname[0] != '.') && (includeHiddenFiles || !(fno.fattrib & AM_HID)))
{
memcpy(dir_entries + (k * 256), fno.fname, strlen(fno.fname) + 1);
k++;
@@ -54,7 +54,7 @@ char *dirlist(const char *directory, const char *pattern)
{
do
{
if (!(fno.fattrib & AM_DIR))
if (!(fno.fattrib & AM_DIR) && (fno.fname[0] != '.') && (includeHiddenFiles || !(fno.fattrib & AM_HID)))
{
memcpy(dir_entries + (k * 256), fno.fname, strlen(fno.fname) + 1);
k++;

View File

@@ -16,4 +16,4 @@
#include "../utils/types.h"
char *dirlist(const char *directory, const char *pattern);
char *dirlist(const char *directory, const char *pattern, bool includeHiddenFiles);

View File

@@ -20,32 +20,33 @@
u32 get_tmr_s()
{
return RTC(0x8); //RTC_SECONDS
return RTC(APBDEV_RTC_SECONDS);
}
u32 get_tmr_ms()
{
// The registers must be read with the following order:
// -> RTC_MILLI_SECONDS (0x10) -> RTC_SHADOW_SECONDS (0xC)
return (RTC(0x10) | (RTC(0xC)<< 10));
return (RTC(APBDEV_RTC_MILLI_SECONDS) | (RTC(APBDEV_RTC_SHADOW_SECONDS) << 10));
}
u32 get_tmr_us()
{
return TMR(0x10); //TIMERUS_CNTR_1US
return TMR(TIMERUS_CNTR_1US); //TIMERUS_CNTR_1US
}
void msleep(u32 milliseconds)
{
u32 start = RTC(0x10) | (RTC(0xC)<< 10);
while (((RTC(0x10) | (RTC(0xC)<< 10)) - start) <= milliseconds)
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)
;
}
void usleep(u32 microseconds)
{
u32 start = TMR(0x10);
while ((TMR(0x10) - start) <= microseconds)
u32 start = TMR(TIMERUS_CNTR_1US);
// Casting to u32 is important!
while ((u32)(TMR(TIMERUS_CNTR_1US) - start) <= microseconds)
;
}

View File

@@ -0,0 +1,32 @@
ifeq ($(strip $(DEVKITARM)),)
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM")
endif
include $(DEVKITARM)/base_rules
TARGET := libsys_minerva
BUILD := ../../build/$(TARGET)
OUTPUT := ../../output
VPATH = $(dir $(wildcard ./*/)) $(dir $(wildcard ./*/*/))
OBJS = $(addprefix $(BUILD)/,\
sys_sdrammtc.o \
)
ARCH := -march=armv4t -mtune=arm7tdmi -mthumb-interwork
CFLAGS = $(ARCH) -O2 -nostdlib -fpie -ffunction-sections -fdata-sections -fomit-frame-pointer -fno-inline -std=gnu11 -Wall $(CUSTOMDEFINES)
LDFLAGS = $(ARCH) -fpie -pie -nostartfiles -lgcc
.PHONY: clean all
all: $(TARGET).bso
$(BUILD)/%.o: ./%.c
@mkdir -p "$(BUILD)"
$(CC) $(CFLAGS) -c $< -o $@
$(TARGET).bso: $(OBJS)
$(CC) $(LDFLAGS) -e _minerva_init $^ -o $(OUTPUT)/$(TARGET).bso
$(STRIP) -g $(OUTPUT)/$(TARGET).bso
clean:
@rm -rf $(OUTPUT)/$(TARGET).bso

View File

@@ -0,0 +1,13 @@
# Minerva Training Cell
### Custom Nvidia Tegra X1 DRAM trainer.
For more, check [Here](https://github.com/CTCaer/minerva_tc).
```
Minerva Training Cell (C) 2018 CTCaer.
/* Pain... And suffering. */
```

View File

@@ -0,0 +1,142 @@
/*
* Minerva Training Cell
* DRAM Training for Tegra X1 SoC. Supports DDR2/3 and LPDDR3/4.
*
* Copyright (c) 2018 CTCaer <ctcaer@gmail.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _MTC_H_
#define _MTC_H_
#include "mtc_table.h"
#include "types.h"
/* Address bases and access macros - Change these for mapped access */
#define TMR_BASE 0x60005000
#define CLOCK_BASE 0x60006000
#define MC_BASE 0x70019000
#define EMC_BASE 0x7001B000
#define EMC0_BASE 0x7001E000
#define EMC1_BASE 0x7001F000
#define MTC_TABLE 0x8F000000
#define _REG(base, off) *(vu32 *)((base) + (off))
#define TMR(off) _REG(TMR_BASE, off)
#define CLOCK(off) _REG(CLOCK_BASE, off)
#define MC(off) _REG(MC_BASE, off)
#define EMC(off) _REG(EMC_BASE, off)
#define EMC_CH0(off) _REG(EMC0_BASE, off)
#define EMC_CH1(off) _REG(EMC1_BASE, off)
/* End of addresses and access macros */
#define EMC_TABLE_SIZE_R7 49280
#define EMC_TABLE_ENTRY_SIZE_R7 4928
#define EMC_STATUS_UPDATE_TIMEOUT 1000
#define EMC_PERIODIC_TRAIN_MS 100
#define EMC_TEMP_COMP_MS 1000
typedef struct
{
s32 rate_to;
s32 rate_from;
emc_table_t *mtc_table;
u32 table_entries;
emc_table_t *current_emc_table;
u32 train_mode;
u32 sdram_id;
u32 prev_temp;
bool emc_2X_clk_src_is_pllmb;
bool fsp_for_src_freq;
bool train_ram_patterns;
} mtc_config_t;
enum train_mode_t
{
OP_SWITCH = 0,
OP_TRAIN = 1,
OP_TRAIN_SWITCH = 2,
OP_PERIODIC_TRAIN = 3,
OP_TEMP_COMP = 4
};
enum comp_seq_t
{
DVFS_SEQUENCE = 1,
WRITE_TRAINING_SEQUENCE = 2,
PERIODIC_TRAINING_SEQUENCE = 3
};
enum tree_update_mode_t
{
DVFS_PT1 = 10,
DVFS_UPDATE = 11,
TRAINING_PT1 = 12,
TRAINING_UPDATE = 13,
PERIODIC_TRAINING_UPDATE = 14
};
enum emc_channels
{
EMC_CH0 = 0,
EMC_CH1 = 1
};
enum EMC_2X_CLK_SRC
{
PLLM_OUT0 = 0x0,
PLLC_OUT0 = 0x1,
PLLP_OUT0 = 0x2,
CLK_M = 0x3,
PLLM_UD = 0x4,
PLLMB_UD = 0x5,
PLLMB_OUT0 = 0x6,
PLLP_UD = 0x7
};
enum DRAM_TYPE
{
DRAM_TYPE_DDR3 = 0,
DRAM_TYPE_LPDDR4 = 1,
DRAM_TYPE_LPDDR2 = 2,
DRAM_TYPE_DDR2 = 3
};
enum DRAM_DEV_NO
{
ONE_RANK = 1,
TWO_RANK = 2
};
enum DRAM_OVER_TEMP_REF
{
REFRESH_X2 = 1,
REFRESH_X4 = 2
};
/* Timers for the below two compensation functions should be paused when changing timings. */
/* Change refresh rate based on dram temps. Run every 1000ms. */
/* Timer should be run only when another component reports over temperature. */
void _minerva_do_over_temp_compensation(mtc_config_t *mtc_cfg);
/* Periodic compensation only for tight timings that need it. Run every 100ms. */
/* Over temp and periodic compensation, should not access EMC_MRR at the same time. */
u32 _minerva_do_periodic_compensation(emc_table_t *mtc_table_entry);
/* Main function used to access all Minerva functions. */
void _minerva_init(mtc_config_t *mtc_cfg, void* bp);
#endif

View File

@@ -0,0 +1,626 @@
/*
* Minerva Training Cell
* DRAM Training for Tegra X1 SoC. Supports DDR2/3 and LPDDR3/4.
*
* Copyright (c) 2018 CTCaer <ctcaer@gmail.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _MTC_MC_EMC_REGS_H_
#define _MTC_MC_EMC_REGS_H_
/* Clock controller registers */
#define CLK_RST_CONTROLLER_PLLM_BASE 0x90
#define CLK_RST_CONTROLLER_PLLM_MISC2 0x9C
#define PLLM_ENABLE (1 << 30)
#define PLLM_LOCK (1 << 27)
#define CLK_RST_CONTROLLER_CLK_SOURCE_EMC 0x19C
#define EMC_2X_CLK_SRC_SHIFT 29
#define CLK_RST_CONTROLLER_CLK_OUT_ENB_X 0x280
#define CLK_RST_CONTROLLER_CLK_ENB_X_SET 0x284
#define CLK_RST_CONTROLLER_CLK_ENB_X_CLR 0x288
#define CLK_RST_CONTROLLER_PLLMB_BASE 0x5E8
#define CLK_RST_CONTROLLER_CLK_SOURCE_EMC_DLL 0x664
#define CLK_RST_CONTROLLER_CLK_SOURCE_EMC_SAFE 0x724
/* Memory controller registers */
#define MC_EMEM_ADR_CFG 0x54
#define MC_EMEM_ARB_CFG 0x90
#define MC_EMEM_ARB_OUTSTANDING_REQ 0x94
#define MC_EMEM_ARB_TIMING_RCD 0x98
#define MC_EMEM_ARB_TIMING_RP 0x9C
#define MC_EMEM_ARB_TIMING_RC 0xA0
#define MC_EMEM_ARB_TIMING_RAS 0xA4
#define MC_EMEM_ARB_TIMING_FAW 0xA8
#define MC_EMEM_ARB_TIMING_RRD 0xAC
#define MC_EMEM_ARB_TIMING_RAP2PRE 0xB0
#define MC_EMEM_ARB_TIMING_WAP2PRE 0xB4
#define MC_EMEM_ARB_TIMING_R2R 0xB8
#define MC_EMEM_ARB_TIMING_W2W 0xBC
#define MC_EMEM_ARB_TIMING_R2W 0xC0
#define MC_EMEM_ARB_TIMING_W2R 0xC4
#define MC_EMEM_ARB_MISC2 0xC8
#define MC_EMEM_ARB_DA_TURNS 0xD0
#define MC_EMEM_ARB_DA_COVERS 0xD4
#define MC_EMEM_ARB_MISC0 0xD8
#define MC_EMEM_ARB_MISC1 0xDC
#define MC_EMEM_ARB_RING1_THROTTLE 0xE0
#define MC_LATENCY_ALLOWANCE_AVPC_0 0x2E4
#define MC_LATENCY_ALLOWANCE_HC_0 0x310
#define MC_LATENCY_ALLOWANCE_HC_1 0x314
#define MC_LATENCY_ALLOWANCE_MPCORE_0 0x320
#define MC_LATENCY_ALLOWANCE_NVENC_0 0x328
#define MC_LATENCY_ALLOWANCE_PPCS_0 0x344
#define MC_LATENCY_ALLOWANCE_PPCS_1 0x348
#define MC_LATENCY_ALLOWANCE_ISP2_0 0x370
#define MC_LATENCY_ALLOWANCE_ISP2_1 0x374
#define MC_LATENCY_ALLOWANCE_XUSB_0 0x37C
#define MC_LATENCY_ALLOWANCE_XUSB_1 0x380
#define MC_LATENCY_ALLOWANCE_TSEC_0 0x390
#define MC_LATENCY_ALLOWANCE_VIC_0 0x394
#define MC_LATENCY_ALLOWANCE_VI2_0 0x398
#define MC_LATENCY_ALLOWANCE_GPU_0 0x3AC
#define MC_LATENCY_ALLOWANCE_SDMMCA_0 0x3B8
#define MC_LATENCY_ALLOWANCE_SDMMCAA_0 0x3BC
#define MC_LATENCY_ALLOWANCE_SDMMC_0 0x3C0
#define MC_LATENCY_ALLOWANCE_SDMMCAB_0 0x3C4
#define MC_LATENCY_ALLOWANCE_NVDEC_0 0x3D8
#define MC_LATENCY_ALLOWANCE_GPU2_0 0x3E8
#define MC_MLL_MPCORER_PTSA_RATE 0x44C
#define MC_FTOP_PTSA_RATE 0x50C
#define MC_EMEM_ARB_TIMING_RFCPB 0x6C0
#define MC_EMEM_ARB_TIMING_CCDMW 0x6C4
#define MC_EMEM_ARB_REFPB_HP_CTRL 0x6F0
#define MC_EMEM_ARB_REFPB_BANK_CTRL 0x6F4
#define MC_PTSA_GRANT_DECREMENT 0x960
#define MC_EMEM_ARB_DHYST_CTRL 0xBCC
#define MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_0 0xBD0
#define MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_1 0xBD4
#define MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_2 0xBD8
#define MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_3 0xBDC
#define MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_4 0xBE0
#define MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_5 0xBE4
#define MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_6 0xBE8
#define MC_EMEM_ARB_DHYST_TIMEOUT_UTIL_7 0xBEC
/* External Memory controller registers */
#define EMC_INTSTATUS 0x0
#define CLKCHANGE_COMPLETE_INT (1 << 4)
#define EMC_DBG 0x8
#define EMC_CFG 0xC
#define EMC_PIN 0x24
#define EMC_TIMING_CONTROL 0x28
#define EMC_RC 0x2C
#define EMC_RFC 0x30
#define EMC_RAS 0x34
#define EMC_RP 0x38
#define EMC_R2W 0x3C
#define EMC_W2R 0x40
#define EMC_R2P 0x44
#define EMC_W2P 0x48
#define EMC_RD_RCD 0x4C
#define EMC_WR_RCD 0x50
#define EMC_RRD 0x54
#define EMC_REXT 0x58
#define EMC_WDV 0x5C
#define EMC_QUSE 0x60
#define EMC_QRST 0x64
#define EMC_QSAFE 0x68
#define EMC_RDV 0x6C
#define EMC_REFRESH 0x70
#define EMC_BURST_REFRESH_NUM 0x74
#define EMC_PDEX2WR 0x78
#define EMC_PDEX2RD 0x7C
#define EMC_PCHG2PDEN 0x80
#define EMC_ACT2PDEN 0x84
#define EMC_AR2PDEN 0x88
#define EMC_RW2PDEN 0x8C
#define EMC_TXSR 0x90
#define EMC_TCKE 0x94
#define EMC_TFAW 0x98
#define EMC_TRPAB 0x9C
#define EMC_TCLKSTABLE 0xA0
#define EMC_TCLKSTOP 0xA4
#define EMC_TREFBW 0xA8
#define EMC_TPPD 0xAC
#define EMC_ODT_WRITE 0xB0
#define EMC_PDEX2MRR 0xB4
#define EMC_WEXT 0xB8
#define EMC_RFC_SLR 0xC0
#define EMC_MRS_WAIT_CNT2 0xC4
#define EMC_MRS_WAIT_CNT 0xC8
#define EMC_MRS 0xCC
#define EMC_EMRS 0xD0
#define EMC_REF 0xD4
#define EMC_MRW 0xE8
#define EMC_SELF_REF 0xE0
#define EMC_MRR 0xEC
#define EMC_FBIO_SPARE 0x100
#define EMC_FBIO_CFG5 0x104
#define EMC_PDEX2CKE 0x118
#define EMC_CKE2PDEN 0x11C
#define EMC_MPC 0x128
#define EMC_EMRS2 0x12C
#define EMC_MRW2 0x134
#define EMC_MRW3 0x138
#define EMC_MRW4 0x13C
#define EMC_R2R 0x144
#define EMC_EINPUT 0x14C
#define EMC_EINPUT_DURATION 0x150
#define EMC_PUTERM_EXTRA 0x154
#define EMC_TCKESR 0x158
#define EMC_TPD 0x15C
#define EMC_AUTO_CAL_CONFIG 0x2A4
#define EMC_EMC_STATUS 0x2B4
#define TIMING_UPDATE_STALLED (1 << 23)
#define MRR_DIVLD (1 << 20)
#define IN_SELF_REFRESH_MASK (3 << 8)
#define IN_POWERDOWN_MASK (3 << 4)
#define REQ_FIFO_EMPTY (1 << 0)
#define EMC_CFG_2 0x2B8
#define EMC_CFG_DIG_DLL 0x2BC
#define EMC_CFG_DIG_DLL_PERIOD 0x2C0
#define EMC_DIG_DLL_STATUS 0x2C4
#define EMC_RDV_MASK 0x2CC
#define EMC_WDV_MASK 0x2D0
#define EMC_RDV_EARLY_MASK 0x2D4
#define EMC_RDV_EARLY 0x2D8
#define EMC_AUTO_CAL_CONFIG8 0x2DC
#define EMC_ZCAL_INTERVAL 0x2E0
#define EMC_ZCAL_WAIT_CNT 0x2E4
#define EMC_ZQ_CAL 0x2EC
#define EMC_FDPD_CTRL_DQ 0x310
#define EMC_FDPD_CTRL_CMD 0x314
#define EMC_PMACRO_CMD_BRICK_CTRL_FDPD 0x318
#define EMC_PMACRO_DATA_BRICK_CTRL_FDPD 0x31C
#define EMC_SCRATCH0 0x324
#define EMC_PMACRO_BRICK_CTRL_RFU1 0x330
#define EMC_PMACRO_BRICK_CTRL_RFU2 0x334
#define EMC_TR_TIMING_0 0x3B4
#define EMC_TR_CTRL_0 0x3B8
#define EMC_TR_CTRL_1 0x3BC
#define EMC_SWITCH_BACK_CTRL 0x3C0
#define EMC_TR_RDV 0x3C4
#define EMC_STALL_THEN_EXE_AFTER_CLKCHANGE 0x3CC
#define EMC_SEL_DPD_CTRL 0x3D8
#define EMC_PRE_REFRESH_REQ_CNT 0x3DC
#define EMC_DYN_SELF_REF_CONTROL 0x3E0
#define EMC_TXSRDLL 0x3E4
#define EMC_CCFIFO_ADDR 0x3E8
#define EMC_CCFIFO_DATA 0x3EC
#define EMC_CCFIFO_STATUS 0x3F0
#define EMC_TR_QPOP 0x3F4
#define EMC_TR_RDV_MASK 0x3F8
#define EMC_TR_QSAFE 0x3FC
#define EMC_TR_QRST 0x400
#define EMC_AUTO_CAL_CONFIG2 0x458
#define EMC_AUTO_CAL_CONFIG3 0x45C
#define EMC_TR_DVFS 0x460
#define EMC_AUTO_CAL_CHANNEL 0x464
#define EMC_IBDLY 0x468
#define EMC_OBDLY 0x46c
#define EMC_TXDSRVTTGEN 0x480
#define EMC_WE_DURATION 0x48C
#define EMC_WS_DURATION 0x490
#define EMC_WEV 0x494
#define EMC_WSV 0x498
#define EMC_CFG_3 0x49C
#define EMC_MRW6 0x4A4
#define EMC_MRW7 0x4A8
#define EMC_MRW8 0x4AC
#define EMC_MRW14 0x4C4
#define EMC_MRW15 0x4D0
#define EMC_CFG_SYNC 0x4D4
#define EMC_FDPD_CTRL_CMD_NO_RAMP 0x4D8
#define EMC_WDV_CHK 0x4E0
#define EMC_CFG_PIPE_2 0x554
#define EMC_CFG_PIPE_CLK 0x558
#define EMC_CFG_PIPE_1 0x55C
#define EMC_CFG_PIPE 0x560
#define EMC_QPOP 0x564
#define EMC_QUSE_WIDTH 0x568
#define EMC_PUTERM_WIDTH 0x56C
#define EMC_AUTO_CAL_CONFIG7 0x574
#define EMC_REFCTRL2 0x580
#define EMC_FBIO_CFG7 0x584
#define EMC_DATA_BRLSHFT_0 0x588
#define EMC_DATA_BRLSHFT_0_RANK0_BYTE0_DATA_BRLSHFT_SHIFT 0
#define EMC_DATA_BRLSHFT_0_RANK0_BYTE1_DATA_BRLSHFT_SHIFT 3
#define EMC_DATA_BRLSHFT_0_RANK0_BYTE2_DATA_BRLSHFT_SHIFT 6
#define EMC_DATA_BRLSHFT_0_RANK0_BYTE3_DATA_BRLSHFT_SHIFT 9
#define EMC_DATA_BRLSHFT_0_RANK0_BYTE4_DATA_BRLSHFT_SHIFT 12
#define EMC_DATA_BRLSHFT_0_RANK0_BYTE5_DATA_BRLSHFT_SHIFT 15
#define EMC_DATA_BRLSHFT_0_RANK0_BYTE6_DATA_BRLSHFT_SHIFT 18
#define EMC_DATA_BRLSHFT_0_RANK0_BYTE7_DATA_BRLSHFT_SHIFT 21
#define EMC_DATA_BRLSHFT_1 0x58C
#define EMC_DATA_BRLSHFT_1_RANK1_BYTE0_DATA_BRLSHFT_SHIFT 0
#define EMC_DATA_BRLSHFT_1_RANK1_BYTE1_DATA_BRLSHFT_SHIFT 3
#define EMC_DATA_BRLSHFT_1_RANK1_BYTE2_DATA_BRLSHFT_SHIFT 6
#define EMC_DATA_BRLSHFT_1_RANK1_BYTE3_DATA_BRLSHFT_SHIFT 9
#define EMC_DATA_BRLSHFT_1_RANK1_BYTE4_DATA_BRLSHFT_SHIFT 12
#define EMC_DATA_BRLSHFT_1_RANK1_BYTE5_DATA_BRLSHFT_SHIFT 15
#define EMC_DATA_BRLSHFT_1_RANK1_BYTE6_DATA_BRLSHFT_SHIFT 18
#define EMC_DATA_BRLSHFT_1_RANK1_BYTE7_DATA_BRLSHFT_SHIFT 21
#define EMC_RFCPB 0x590
#define EMC_DQS_BRLSHFT_0 0x594
#define EMC_DQS_BRLSHFT_1 0x598
#define EMC_CMD_BRLSHFT_0 0x59C
#define EMC_CMD_BRLSHFT_1 0x5A0
#define EMC_CMD_BRLSHFT_2 0x5A4
#define EMC_CMD_BRLSHFT_3 0x5A8
#define EMC_QUSE_BRLSHFT_0 0x5AC
#define EMC_AUTO_CAL_CONFIG4 0x5B0
#define EMC_AUTO_CAL_CONFIG5 0x5B4
#define EMC_QUSE_BRLSHFT_1 0x5B8
#define EMC_QUSE_BRLSHFT_2 0x5BC
#define EMC_CCDMW 0x5C0
#define EMC_QUSE_BRLSHFT_3 0x5C4
#define EMC_AUTO_CAL_CONFIG6 0x5CC
#define EMC_DLL_CFG_0 0x5E4
#define EMC_DLL_CFG_1 0x5E8
#define EMC_CONFIG_SAMPLE_DELAY 0x5F0
#define EMC_CFG_UPDATE 0x5F4
#define EMC_PMACRO_QUSE_DDLL_RANK0_0 0x600
#define EMC_PMACRO_QUSE_DDLL_RANK0_1 0x604
#define EMC_PMACRO_QUSE_DDLL_RANK0_2 0x608
#define EMC_PMACRO_QUSE_DDLL_RANK0_3 0x60C
#define EMC_PMACRO_QUSE_DDLL_RANK0_4 0x610
#define EMC_PMACRO_QUSE_DDLL_RANK0_5 0x614
#define EMC_PMACRO_QUSE_DDLL_RANK1_4 0x630
#define EMC_PMACRO_QUSE_DDLL_RANK1_5 0x634
#define EMC_PMACRO_QUSE_DDLL_RANK1_0 0x620
#define EMC_PMACRO_QUSE_DDLL_RANK1_1 0x624
#define EMC_PMACRO_QUSE_DDLL_RANK1_2 0x628
#define EMC_PMACRO_QUSE_DDLL_RANK1_3 0x62C
#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_0 0x640
#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_1 0x644
#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_2 0x648
#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_3 0x64C
#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_4 0x650
#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_5 0x654
#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_0 0x660
#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_1 0x664
#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_2 0x668
#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_3 0x66C
#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_4 0x670
#define EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_5 0x674
#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_0 0x680
#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_1 0x684
#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_2 0x688
#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_3 0x68C
#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_4 0x690
#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_5 0x694
#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_0 0x6A0
#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_1 0x6A4
#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_2 0x6A8
#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_3 0x6AC
#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_4 0x6B0
#define EMC_PMACRO_OB_DDLL_LONG_DQS_RANK1_5 0x6B4
#define EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_0 0x6C0
#define EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_1 0x6C4
#define EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_2 0x6C8
#define EMC_PMACRO_IB_DDLL_LONG_DQS_RANK0_3 0x6CC
#define EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_0 0x6E0
#define EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_1 0x6E4
#define EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_2 0x6E8
#define EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_3 0x6EC
#define EMC_PMACRO_TX_PWRD_0 0x720
#define EMC_PMACRO_TX_PWRD_1 0x724
#define EMC_PMACRO_TX_PWRD_2 0x728
#define EMC_PMACRO_TX_PWRD_3 0x72C
#define EMC_PMACRO_TX_PWRD_4 0x730
#define EMC_PMACRO_TX_PWRD_5 0x734
#define EMC_PMACRO_TX_SEL_CLK_SRC_0 0x740
#define EMC_PMACRO_TX_SEL_CLK_SRC_1 0x744
#define EMC_PMACRO_TX_SEL_CLK_SRC_3 0x74C
#define EMC_PMACRO_TX_SEL_CLK_SRC_2 0x748
#define EMC_PMACRO_TX_SEL_CLK_SRC_4 0x750
#define EMC_PMACRO_TX_SEL_CLK_SRC_5 0x754
#define EMC_PMACRO_DDLL_BYPASS 0x760
#define EMC_PMACRO_DDLL_PWRD_0 0x770
#define EMC_PMACRO_DDLL_PWRD_1 0x774
#define EMC_PMACRO_DDLL_PWRD_2 0x778
#define EMC_PMACRO_CMD_CTRL_0 0x780
#define EMC_PMACRO_CMD_CTRL_1 0x784
#define EMC_PMACRO_CMD_CTRL_2 0x788
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE0_0 0x800
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE0_1 0x804
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE0_2 0x808
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE0_3 0x80C
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE1_0 0x810
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE1_1 0x814
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE1_2 0x818
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE1_3 0x81C
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE2_0 0x820
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE2_1 0x824
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE2_2 0x828
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE2_3 0x82C
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE3_0 0x830
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE3_1 0x834
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE3_2 0x838
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE3_3 0x83C
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE4_0 0x840
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE4_1 0x844
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE4_2 0x848
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE4_3 0x84C
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE5_0 0x850
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE5_1 0x854
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE5_2 0x858
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE5_3 0x85C
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE6_0 0x860
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE6_1 0x864
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE6_2 0x868
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE6_3 0x86C
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE7_0 0x870
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE7_1 0x874
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE7_2 0x878
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_BYTE7_3 0x87C
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD0_0 0x880
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD0_1 0x884
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD0_2 0x888
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD0_3 0x88C
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD1_0 0x890
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD1_1 0x894
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD1_2 0x898
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD1_3 0x89C
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD2_0 0x8A0
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD2_1 0x8A4
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD2_2 0x8A8
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD2_3 0x8AC
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD3_0 0x8B0
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD3_1 0x8B4
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD3_2 0x8B8
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK0_CMD3_3 0x8BC
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE0_0 0x900
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE0_1 0x904
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE0_2 0x908
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE0_3 0x90C
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE1_0 0x910
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE1_1 0x914
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE1_2 0x918
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE1_3 0x91C
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE2_0 0x920
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE2_1 0x924
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE2_2 0x928
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE2_3 0x92C
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE3_0 0x930
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE3_1 0x934
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE3_2 0x938
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE3_3 0x93C
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE4_0 0x940
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE4_1 0x944
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE4_2 0x948
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE4_3 0x94C
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE5_0 0x950
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE5_1 0x954
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE5_2 0x958
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE5_3 0x95C
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE6_0 0x960
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE6_1 0x964
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE6_2 0x968
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE6_3 0x96C
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE7_0 0x970
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE7_1 0x974
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE7_2 0x978
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_BYTE7_3 0x97C
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD0_0 0x980
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD0_1 0x984
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD0_2 0x988
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD0_3 0x98C
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD1_0 0x990
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD1_1 0x994
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD1_2 0x998
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD1_3 0x99C
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD2_0 0x9A0
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD2_1 0x9A4
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD2_2 0x9A8
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD2_3 0x9AC
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD3_0 0x9B0
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD3_1 0x9B4
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD3_2 0x9B8
#define EMC_PMACRO_OB_DDLL_SHORT_DQ_RANK1_CMD3_3 0x9BC
#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE0_0 0xA00
#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE0_1 0xA04
#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE0_2 0xA08
#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE1_0 0xA10
#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE1_1 0xA14
#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE1_2 0xA18
#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE2_0 0xA20
#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE2_1 0xA24
#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE2_2 0xA28
#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE3_0 0xA30
#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE3_1 0xA34
#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE3_2 0xA38
#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE4_0 0xA40
#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE4_1 0xA44
#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE4_2 0xA48
#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE5_0 0xA50
#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE5_1 0xA54
#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE5_2 0xA58
#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE6_0 0xA60
#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE6_1 0xA64
#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE6_2 0xA68
#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE7_0 0xA70
#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE7_1 0xA74
#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK0_BYTE7_2 0xA78
#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE0_0 0xB00
#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE0_1 0xB04
#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE0_2 0xB08
#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE1_0 0xB10
#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE1_1 0xB14
#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE1_2 0xB18
#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE2_0 0xB20
#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE2_1 0xB24
#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE2_2 0xB28
#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE3_0 0xB30
#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE3_1 0xB34
#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE3_2 0xB38
#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE4_0 0xB40
#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE4_1 0xB44
#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE4_2 0xB48
#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE5_0 0xB50
#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE5_1 0xB54
#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE5_2 0xB58
#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE6_0 0xB60
#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE6_1 0xB64
#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE6_2 0xB68
#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE7_0 0xB70
#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE7_1 0xB74
#define EMC_PMACRO_IB_DDLL_SHORT_DQ_RANK1_BYTE7_2 0xB78
#define EMC_PMACRO_IB_VREF_DQ_0 0xBE0
#define EMC_PMACRO_IB_VREF_DQ_1 0xBE4
#define EMC_PMACRO_IB_VREF_DQS_0 0xBF0
#define EMC_PMACRO_IB_VREF_DQS_1 0xBF4
#define EMC_PMACRO_DDLL_LONG_CMD_0 0xC00
#define EMC_PMACRO_DDLL_LONG_CMD_1 0xC04
#define EMC_PMACRO_DDLL_LONG_CMD_2 0xC08
#define EMC_PMACRO_DDLL_LONG_CMD_3 0xC0C
#define EMC_PMACRO_DDLL_LONG_CMD_4 0xC10
#define EMC_PMACRO_DDLL_SHORT_CMD_0 0xC20
#define EMC_PMACRO_DDLL_SHORT_CMD_1 0xC24
#define EMC_PMACRO_DDLL_SHORT_CMD_2 0xC28
#define EMC_PMACRO_CFG_PM_GLOBAL_0 0xC30
#define EMC_PMACRO_VTTGEN_CTRL_0 0xC34
#define EMC_PMACRO_VTTGEN_CTRL_1 0xC38
#define EMC_PMACRO_BG_BIAS_CTRL_0 0xC3C
#define EMC_PMACRO_PAD_CFG_CTRL 0xC40
#define EMC_PMACRO_ZCTRL 0xC44
#define EMC_PMACRO_CMD_PAD_RX_CTRL 0xC50
#define EMC_PMACRO_DATA_PAD_RX_CTRL 0xC54
#define EMC_PMACRO_CMD_RX_TERM_MODE 0xC58
#define EMC_PMACRO_DATA_RX_TERM_MODE 0xC5C
#define EMC_PMACRO_CMD_PAD_TX_CTRL 0xC60
#define EMC_PMACRO_DATA_PAD_TX_CTRL 0xC64
#define EMC_PMACRO_COMMON_PAD_TX_CTRL 0xC68
#define EMC_PMACRO_AUTOCAL_CFG_COMMON 0xC78
#define EMC_PMACRO_VTTGEN_CTRL_2 0xCF0
#define EMC_PMACRO_IB_RXRT 0xCF4
#define EMC_PMACRO_TRAINING_CTRL_0 0xCF8
#define CH0_TRAINING_E_WRPTR (1 << 3)
#define EMC_PMACRO_TRAINING_CTRL_1 0xCFC
#define EMC_TRAINING_CMD 0xE00
#define EMC_TRAINING_CTRL 0xE04
#define EMC_TRAINING_STATUS 0xE08
#define EMC_TRAINING_QUSE_CORS_CTRL 0xE0C
#define EMC_TRAINING_QUSE_FINE_CTRL 0xE10
#define EMC_TRAINING_QUSE_CTRL_MISC 0xE14
#define EMC_TRAINING_WRITE_FINE_CTRL 0xE18
#define EMC_TRAINING_WRITE_CTRL_MISC 0xE1C
#define EMC_TRAINING_WRITE_VREF_CTRL 0xE20
#define EMC_TRAINING_READ_FINE_CTRL 0xE24
#define EMC_TRAINING_READ_CTRL_MISC 0xE28
#define EMC_TRAINING_READ_VREF_CTRL 0xE2C
#define EMC_TRAINING_CA_FINE_CTRL 0xE30
#define EMC_TRAINING_CA_CTRL_MISC 0xE34
#define EMC_TRAINING_CA_CTRL_MISC1 0xE38
#define EMC_TRAINING_CA_VREF_CTRL 0xE3C
#define EMC_TRAINING_SETTLE 0xE44
#define EMC_TRAINING_MPC 0xE5C
#define EMC_TRAINING_PATRAM_CTRL 0xE60
#define EMC_TRAINING_PATRAM_DQ 0xE64
#define EMC_TRAINING_PATRAM_DMI 0xE68
#define EMC_TRAINING_VREF_SETTLE 0xE6C
#define EMC_TRAINING_OPT_CA_VREF 0xEC0
#define EMC_TRAINING_OPT_DQ_OB_VREF 0xEC4
#define EMC_TRAINING_QUSE_VREF_CTRL 0xED0
#define EMC_TRAINING_OPT_DQS_IB_VREF_RANK0 0xED4
#define EMC_TRAINING_OPT_DQS_IB_VREF_RANK1 0xED8
/* Per channel registers offsets. Should be used with EMC_BASE */
#define EMC0_MRW10 0x34B4
#define EMC0_MRW11 0x34B8
#define EMC0_MRW12 0x34BC
#define EMC0_MRW13 0x34C0
#define EMC0_DATA_BRLSHFT_0 0x3588
#define EMC0_DATA_BRLSHFT_1 0x358C
#define EMC0_CMD_BRLSHFT_0 0x359C
#define EMC0_QUSE_BRLSHFT_0 0x35AC
#define EMC0_QUSE_BRLSHFT_2 0x35BC
#define EMC0_TRAINING_RW_OFFSET_IB_BYTE0 0x3E98
#define EMC0_TRAINING_RW_OFFSET_IB_BYTE1 0x3E9C
#define EMC0_TRAINING_RW_OFFSET_IB_BYTE2 0x3EA0
#define EMC0_TRAINING_RW_OFFSET_IB_BYTE3 0x3EA4
#define EMC0_TRAINING_RW_OFFSET_IB_MISC 0x3EA8
#define EMC0_TRAINING_RW_OFFSET_OB_BYTE0 0x3EAC
#define EMC0_TRAINING_RW_OFFSET_OB_BYTE1 0x3EB0
#define EMC0_TRAINING_RW_OFFSET_OB_BYTE2 0x3EB4
#define EMC0_TRAINING_RW_OFFSET_OB_BYTE3 0x3EB8
#define EMC0_TRAINING_RW_OFFSET_OB_MISC 0x3EBC
#define EMC0_TRAINING_OPT_DQS_IB_VREF_RANK0 0x3ED4
#define EMC0_TRAINING_OPT_DQS_IB_VREF_RANK1 0x3ED8
#define EMC1_MRW10 0x44B4
#define EMC1_MRW11 0x44B8
#define EMC1_MRW12 0x44BC
#define EMC1_MRW13 0x44C0
#define EMC1_DATA_BRLSHFT_0 0x4588
#define EMC1_DATA_BRLSHFT_1 0x458C
#define EMC1_CMD_BRLSHFT_1 0x45A0
#define EMC1_QUSE_BRLSHFT_1 0x45B8
#define EMC1_QUSE_BRLSHFT_3 0x45C4
#define EMC1_TRAINING_RW_OFFSET_IB_BYTE0 0x4E98
#define EMC1_TRAINING_RW_OFFSET_IB_BYTE1 0x4E9C
#define EMC1_TRAINING_RW_OFFSET_IB_BYTE2 0x4EA0
#define EMC1_TRAINING_RW_OFFSET_IB_BYTE3 0x4EA4
#define EMC1_TRAINING_RW_OFFSET_IB_MISC 0x4EA8
#define EMC1_TRAINING_RW_OFFSET_OB_BYTE0 0x4EAC
#define EMC1_TRAINING_RW_OFFSET_OB_BYTE1 0x4EB0
#define EMC1_TRAINING_RW_OFFSET_OB_BYTE2 0x4EB4
#define EMC1_TRAINING_RW_OFFSET_OB_BYTE3 0x4EB8
#define EMC1_TRAINING_RW_OFFSET_OB_MISC 0x4EBC
#define EMC1_TRAINING_OPT_DQS_IB_VREF_RANK0 0x4ED4
#define EMC1_TRAINING_OPT_DQS_IB_VREF_RANK1 0x4ED8
#define EMC_PMACRO_OB_DDLL_LONG_DQ_BYTE0_SHIFT 0
#define EMC_PMACRO_OB_DDLL_LONG_DQ_BYTE1_SHIFT 16
#define EMC_PMACRO_OB_DDLL_LONG_DQ_BYTE2_SHIFT 0
#define EMC_PMACRO_OB_DDLL_LONG_DQ_BYTE3_SHIFT 16
#define EMC_PMACRO_OB_DDLL_LONG_DQ_BYTE4_SHIFT 0
#define EMC_PMACRO_OB_DDLL_LONG_DQ_BYTE5_SHIFT 16
#define EMC_PMACRO_OB_DDLL_LONG_DQ_BYTE6_SHIFT 0
#define EMC_PMACRO_OB_DDLL_LONG_DQ_BYTE7_SHIFT 16
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,560 @@
/*
* Minerva Training Cell
* DRAM Training for Tegra X1 SoC. Supports DDR2/3 and LPDDR3/4.
*
* Copyright (c) 2018 CTCaer <ctcaer@gmail.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _MTC_TABLE_H_
#define _MTC_TABLE_H_
#include "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

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,54 @@
/*
* Copyright (c) 2018 naehrwert
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _TYPES_H_
#define _TYPES_H_
#define NULL ((void *)0)
#define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1))
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define OFFSET_OF(t, m) ((u32)&((t *)NULL)->m)
#define CONTAINER_OF(mp, t, mn) ((t *)((u32)mp - OFFSET_OF(t, mn)))
typedef char s8;
typedef short s16;
typedef short SHORT;
typedef int s32;
typedef int INT;
typedef long LONG;
typedef long long int s64;
typedef unsigned char u8;
typedef unsigned char BYTE;
typedef unsigned short u16;
typedef unsigned short WORD;
typedef unsigned short WCHAR;
typedef unsigned int u32;
typedef unsigned int UINT;
typedef unsigned long DWORD;
typedef unsigned long long QWORD;
typedef unsigned long long int u64;
typedef volatile unsigned char vu8;
typedef volatile unsigned short vu16;
typedef volatile unsigned int vu32;
typedef int bool;
#define true 1
#define false 0
#endif

38
tools/smmu_payload.py Normal file
View File

@@ -0,0 +1,38 @@
'''
Copyright (c) 2018 balika011
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
version 2, as published by the Free Software Foundation.
This program is distributed in the hope it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
'''
from keystone import *
CODE = b'''
LDR X1, =0x70019010
MOV X0, #0x1
STR W0, [X1]
loop:
IC IALLUIS
DSB ISH
B loop
MOV X0, #0x0
STR W0, [X1]
LDR X0, =0x4002B000
BR X0
'''
try:
ks = Ks(KS_ARCH_ARM64, KS_MODE_LITTLE_ENDIAN)
encoding, count = ks.asm(CODE, 0x0)
print("%s = %s (number of statements: %u)" %(CODE, ', '.join([('0x%02x' % (x)) for x in encoding]), count))
except KsError as e:
print("ERROR: %s" %e)