1
0
Fork 0
mirror of https://github.com/Scandal-UK/Incognito_RCM.git synced 2024-11-22 11:56:41 +00:00

incorporate lockpick & hekate changes

This commit is contained in:
jimzrt 2020-01-04 12:53:44 +01:00
parent 9bcd7c178f
commit d0c609dfd9
61 changed files with 3591 additions and 377 deletions

View file

@ -25,6 +25,7 @@ typedef struct _hnode
u32 size;
struct _hnode *prev;
struct _hnode *next;
u32 align[4]; // Align to arch cache line size.
} hnode_t;
typedef struct _heap
@ -32,3 +33,9 @@ typedef struct _heap
u32 start;
hnode_t *first;
} heap_t;
typedef struct
{
u32 total;
u32 used;
} heap_monitor_t;

39
common/common_module.h Normal file
View file

@ -0,0 +1,39 @@
/*
* Common Module Header
* Copyright (C) 2018 M4xw
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <stddef.h>
//TODO: Move it to BDK
#include "common_gfx.h"
#include "common_heap.h"
// Module Callback
typedef void (*cbMainModule_t)(const char *s);
typedef void (*memcpy_t)(void *, void *, size_t);
typedef void (*memset_t)(void *, int, size_t);
typedef struct _bdkParams_t
{
gfx_con_t *gfxCon;
gfx_ctxt_t *gfxCtx;
heap_t *sharedHeap;
memcpy_t memcpy;
memset_t memset;
} *bdkParams_t;
// Module Entrypoint
typedef void (*moduleEntrypoint_t)(void *, bdkParams_t);

87
common/memory_map.h Normal file
View file

@ -0,0 +1,87 @@
/*
* Copyright (c) 2019 CTCaer
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _MEMORY_MAP_H_
#define _MEMORY_MAP_H_
//#define IPL_STACK_TOP 0x4003FF00
/* --- BIT/BCT: 0x40000000 - 0x40003000 --- */
/* --- IPL: 0x40003000 - 0x40028000 --- */
#define IPL_LOAD_ADDR 0x40003000
#define IPL_SZ_MAX 0x20000 // 128KB.
//#define IRAM_LIB_ADDR 0x4002B000
#define SDRAM_PARAMS_ADDR 0x40030000 // SDRAM extraction buffer during sdram init.
#define CBFS_DRAM_EN_ADDR 0x4003e000 // u32.
/* --- DRAM START --- */
#define DRAM_START 0x80000000
/* Do not write anything in this area */
#define NYX_LOAD_ADDR 0x81000000
#define NYX_SZ_MAX 0x1000000
/* Stack theoretical max: 220MB */
#define IPL_STACK_TOP 0x90010000
#define IPL_HEAP_START 0x90020000
#define IPL_HEAP_SZ 0x24FE0000 // 592MB.
/* --- Gap: 0xB5000000 - 0xB5FFFFFF --- */
// SDMMC DMA buffers
#define SDXC_BUF_ALIGNED 0xB6000000
#define MIXD_BUF_ALIGNED 0xB7000000
#define EMMC_BUF_ALIGNED MIXD_BUF_ALIGNED
#define SDMMC_DMA_BUF_SZ 0x1000000 // 16MB (4MB currently used).
#define SDMMC_UPPER_BUFFER 0xB8000000
#define SDMMC_UP_BUF_SZ 0x8000000 // 128MB.
// Virtual disk / Chainloader buffers.
#define RAM_DISK_ADDR 0xC1000000
#define RAM_DISK_SZ 0x20000000
//#define DRAM_LIB_ADDR 0xE0000000
/* --- Chnldr: 252MB 0xC03C0000 - 0xCFFFFFFF --- */ //! Only used when chainloading.
/* --- Gap: 464MB 0xD0000000 - 0xECFFFFFF --- */
// Nyx buffers.
#define NYX_STORAGE_ADDR 0xED000000
#define NYX_RES_ADDR 0xEE000000
// Framebuffer addresses.
#define IPL_FB_ADDRESS 0xF0000000
#define IPL_FB_SZ 0x384000 // 720 x 1280 x 4.
#define LOG_FB_ADDRESS 0xF0400000
#define LOG_FB_SZ 0x334000 // 1280 x 656 x 4.
#define NYX_FB_ADDRESS 0xF0800000
#define NYX_FB_SZ 0x384000 // 1280 x 720 x 4.
// Nyx LvGL buffers.
#define NYX_LV_VDB_ADR 0xF0C00000
#define NYX_FB_SZ 0x384000 // 1280 x 720 x 4.
#define NYX_LV_MEM_ADR 0xF1000000
#define NYX_LV_MEM_SZ 0x8000000
// NX BIS driver sector cache.
#define NX_BIS_CACHE_ADDR 0xF9000000
#define NX_BIS_CACHE_SZ 0x8800
/* --- Gap: 111MB 0xF9008800 - 0xFFFFFFFF --- */
// #define EXT_PAYLOAD_ADDR 0xC03C0000
// #define RCM_PAYLOAD_ADDR (EXT_PAYLOAD_ADDR + ALIGN(PATCHED_RELOC_SZ, 0x10))
// #define COREBOOT_ADDR (0xD0000000 - 0x100000)
// NYX
// #define EXT_PAYLOAD_ADDR 0xC0000000
// #define RCM_PAYLOAD_ADDR (EXT_PAYLOAD_ADDR + ALIGN(PATCHED_RELOC_SZ, 0x10))
// #define COREBOOT_ADDR (0xD0000000 - 0x100000)
#endif

View file

@ -262,11 +262,12 @@ void display_color_screen(u32 color)
u32 *display_init_framebuffer()
{
// Sanitize framebuffer area.
memset((u32 *)FB_ADDRESS, 0, 0x3C0000);
memset((u32 *)IPL_FB_ADDRESS, 0, 0x3C0000);
// This configures the framebuffer @ IPL_FB_ADDRESS with a resolution of 1280x720 (line stride 720).
exec_cfg((u32 *)DISPLAY_A_BASE, cfg_display_framebuffer, 32);
usleep(35000);
return (u32 *)FB_ADDRESS;
return (u32 *)IPL_FB_ADDRESS;
}

View file

@ -1,6 +1,6 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (C) 2018 CTCaer
* Copyright (c) 2018 CTCaer
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@ -18,10 +18,9 @@
#ifndef _DI_H_
#define _DI_H_
#include "../../common/memory_map.h"
#include "../utils/types.h"
#define FB_ADDRESS 0xC0000000
/*! Display registers. */
#define _DIREG(reg) ((reg) * 4)

View file

@ -1,6 +1,6 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (C) 2018 CTCaer
* Copyright (c) 2018 CTCaer
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@ -415,7 +415,7 @@ static const cfg_op_t _display_config_11[113] = {
{DC_DISP_SYNC_WIDTH, 0x10048},
{DC_DISP_BACK_PORCH, 0x90048},
{DC_DISP_ACTIVE, 0x50002D0},
{DC_DISP_FRONT_PORCH, 0xA0088}, // Sources say that this should be above the DC_DISP_ACTIVE cmd.
{DC_DISP_FRONT_PORCH, 0xA0088}, // Sources say that this should be above the DC_DISP_ACTIVE cmd.
/* End of Display timings */
{DC_DISP_SHIFT_CLOCK_OPTIONS, SC1_H_QUALIFIER_NONE | SC0_H_QUALIFIER_NONE},
{DC_COM_PIN_OUTPUT_ENABLE(1), 0},
@ -548,7 +548,7 @@ static const cfg_op_t cfg_display_framebuffer[32] = {
{DC_WIN_LINE_STRIDE, UV_LINE_STRIDE(720 * 2) | LINE_STRIDE(720 * 4)}, //768*2x768*4 (= 0x600 x 0xC00) bytes, see TRM for alignment requirements.
{DC_WIN_BUFFER_CONTROL, 0},
{DC_WINBUF_SURFACE_KIND, 0}, //Regular surface.
{DC_WINBUF_START_ADDR, FB_ADDRESS}, //Framebuffer address.
{DC_WINBUF_START_ADDR, IPL_FB_ADDRESS}, // Framebuffer address.
{DC_WINBUF_ADDR_H_OFFSET, 0},
{DC_WINBUF_ADDR_V_OFFSET, 0},
{DC_WIN_WIN_OPTIONS, 0},

View file

@ -112,8 +112,9 @@ void *tui_do_menu(menu_t *menu)
{
gfx_con_setcol(0xFFCCCCCC, 1, 0xFF1B1B1B);
gfx_con_setpos(menu->x, menu->y);
gfx_print_header();
//gfx_printf("[%kLo%kck%kpi%kck%k_R%kCM%k v%d.%d.%d%k]\n\n",
// colors[0], colors[1], colors[2], colors[3], colors[4], colors[5], 0xFFFF00FF, LP_VER_MJ, LP_VER_MN, LP_VER_BF, 0xFFCCCCCC);
// Skip caption or seperator lines selection.
while (menu->ents[idx].type == MENT_CAPTION ||
@ -147,13 +148,11 @@ void *tui_do_menu(menu_t *menu)
gfx_con_setcol(0xFF1B1B1B, 1, 0xFFCCCCCC);
else
gfx_con_setcol(0xFFCCCCCC, 1, 0xFF1B1B1B);
// if (menu->ents[cnt].type == MENT_CAPTION)
// gfx_printf("%k %s", menu->ents[cnt].color, menu->ents[cnt].caption);
if (menu->ents[cnt].type != MENT_CHGLINE) {
if (menu->ents[cnt].type != MENT_CHGLINE && menu->ents[cnt].type != MENT_MENU) {
if (cnt == idx)
gfx_printf(" %s", menu->ents[cnt].caption);
else
gfx_printf("%k %s", menu->ents[cnt].color, menu->ents[cnt].caption);//gfx_printf(" %s", menu->ents[cnt].caption);
gfx_printf("%k %s", menu->ents[cnt].color, menu->ents[cnt].caption);
}
if(menu->ents[cnt].type == MENT_MENU)
gfx_printf("%k...", 0xFF0099EE);

View file

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

View file

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

View file

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

View file

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

131
source/ianos/ianos.c Normal file
View file

@ -0,0 +1,131 @@
/*
* Copyright (c) 2018 M4xw
* Copyright (c) 2018-2019 CTCaer
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <string.h>
#include "ianos.h"
#include "../utils/types.h"
#include "../libs/elfload/elfload.h"
#include "../../common/common_module.h"
#include "../mem/heap.h"
#include "../gfx/gfx.h"
#define IRAM_LIB_ADDR 0x4002B000
#define DRAM_LIB_ADDR 0xE0000000
extern heap_t _heap;
extern void *sd_file_read(const char *path, u32 *fsize);
extern bool sd_mount();
extern void sd_unmount();
void *elfBuf = NULL;
void *fileBuf = NULL;
static void _ianos_call_ep(moduleEntrypoint_t entrypoint, void *moduleConfig)
{
bdkParams_t bdkParameters = (bdkParams_t)malloc(sizeof(struct _bdkParams_t));
bdkParameters->gfxCon = &gfx_con;
bdkParameters->gfxCtx = &gfx_ctxt;
bdkParameters->memcpy = (memcpy_t)&memcpy;
bdkParameters->memset = (memset_t)&memset;
bdkParameters->sharedHeap = &_heap;
entrypoint(moduleConfig, bdkParameters);
}
static void *_ianos_alloc_cb(el_ctx *ctx, Elf_Addr phys, Elf_Addr virt, Elf_Addr size)
{
(void)ctx;
(void)phys;
(void)size;
return (void *)virt;
}
static bool _ianos_read_cb(el_ctx *ctx, void *dest, size_t numberBytes, size_t offset)
{
(void)ctx;
memcpy(dest, fileBuf + offset, numberBytes);
return true;
}
//TODO: Support shared libraries.
uintptr_t ianos_loader(bool sdmount, char *path, elfType_t type, void *moduleConfig)
{
uintptr_t epaddr = 0;
if (sdmount)
{
if (!sd_mount())
goto elfLoadFinalOut;
}
fileBuf = sd_file_read(path, NULL);
if (sdmount)
sd_unmount();
if (!fileBuf)
goto elfLoadFinalOut;
el_ctx ctx;
ctx.pread = _ianos_read_cb;
if (el_init(&ctx))
goto elfLoadFinalOut;
// Set our relocated library's buffer.
switch (type & 0xFFFF)
{
case EXEC_ELF:
case AR64_ELF:
elfBuf = (void *)DRAM_LIB_ADDR;
sd_unmount();
break;
default:
elfBuf = malloc(ctx.memsz); // Aligned to 0x10 by default.
}
if (!elfBuf)
goto elfLoadFinalOut;
// Load and relocate library.
ctx.base_load_vaddr = ctx.base_load_paddr = (uintptr_t)elfBuf;
if (el_load(&ctx, _ianos_alloc_cb))
goto elfFreeOut;
if (el_relocate(&ctx))
goto elfFreeOut;
// Launch.
epaddr = ctx.ehdr.e_entry + (uintptr_t)elfBuf;
moduleEntrypoint_t ep = (moduleEntrypoint_t)epaddr;
_ianos_call_ep(ep, moduleConfig);
elfFreeOut:
free(fileBuf);
elfBuf = NULL;
fileBuf = NULL;
elfLoadFinalOut:
return epaddr;
}

34
source/ianos/ianos.h Normal file
View file

@ -0,0 +1,34 @@
/*
* Copyright (c) 2018 M4xw
* Copyright (c) 2018 CTCaer
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef IANOS_H
#define IANOS_H
#include "../utils/types.h"
typedef enum
{
DRAM_LIB = 0, // DRAM library.
EXEC_ELF = 1, // Executable elf that does not return.
DR64_LIB = 2, // AARCH64 DRAM library.
AR64_ELF = 3, // Executable elf that does not return.
KEEP_IN_RAM = (1 << 31) // Shared library mask.
} elfType_t;
uintptr_t ianos_loader(bool sdmount, char *path, elfType_t type, void* config);
#endif

View file

@ -30,6 +30,7 @@ static const u8 master_kek_sources[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_VERSION
{0x9A, 0x3E, 0xA9, 0xAB, 0xFD, 0x56, 0x46, 0x1C, 0x9B, 0xF6, 0x48, 0x7F, 0x5C, 0xFA, 0x09, 0x5C}, //7.0.0
{0xDE, 0xDC, 0xE3, 0x39, 0x30, 0x88, 0x16, 0xF8, 0xAE, 0x97, 0xAD, 0xEC, 0x64, 0x2D, 0x41, 0x41}, //8.1.0
{0x1A, 0xEC, 0x11, 0x82, 0x2B, 0x32, 0x38, 0x7A, 0x2B, 0xED, 0xBA, 0x01, 0x47, 0x7E, 0x3B, 0x67}, //9.0.0
{0x30, 0x3F, 0x02, 0x7E, 0xD8, 0x38, 0xEC, 0xD7, 0x93, 0x25, 0x34, 0xB5, 0x30, 0xEB, 0xCA, 0x7A}, //9.1.0
};
static const u8 mkey_vectors[KB_FIRMWARE_VERSION_MAX+1][0x10] =
@ -44,6 +45,7 @@ static const u8 mkey_vectors[KB_FIRMWARE_VERSION_MAX+1][0x10] =
{0xA4, 0xD4, 0x52, 0x6F, 0xD1, 0xE4, 0x36, 0xAA, 0x9F, 0xCB, 0x61, 0x27, 0x1C, 0x67, 0x65, 0x1F}, /* Master key 06 encrypted with Master key 07. */
{0xEA, 0x60, 0xB3, 0xEA, 0xCE, 0x8F, 0x24, 0x46, 0x7D, 0x33, 0x9C, 0xD1, 0xBC, 0x24, 0x98, 0x29}, /* Master key 07 encrypted with Master key 08. */
{0x4D, 0xD9, 0x98, 0x42, 0x45, 0x0D, 0xB1, 0x3C, 0x52, 0x0C, 0x9A, 0x44, 0xBB, 0xAD, 0xAF, 0x80}, /* Master key 08 encrypted with Master key 09. */
{0xB8, 0x96, 0x9E, 0x4A, 0x00, 0x0D, 0xD6, 0x28, 0xB3, 0xD1, 0xDB, 0x68, 0x5F, 0xFB, 0xE1, 0x2A}, /* Master key 09 encrypted with Master key 0A. */
};
//======================================Keys======================================//
@ -79,6 +81,7 @@ static const u8 new_device_key_sources[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_VER
{0x8F, 0x77, 0x5A, 0x96, 0xB0, 0x94, 0xFD, 0x8D, 0x28, 0xE4, 0x19, 0xC8, 0x16, 0x1C, 0xDB, 0x3D}, /* 7.0.0 New Device Key Source. */
{0x67, 0x62, 0xD4, 0x8E, 0x55, 0xCF, 0xFF, 0x41, 0x31, 0x15, 0x3B, 0x24, 0x0C, 0x7C, 0x07, 0xAE}, /* 8.1.0 New Device Key Source. */
{0x4A, 0xC3, 0x4E, 0x14, 0x8B, 0x96, 0x4A, 0xD5, 0xD4, 0x99, 0x73, 0xC4, 0x45, 0xAB, 0x8B, 0x49}, /* 9.0.0 New Device Key Source. */
{0x14, 0xB8, 0x74, 0x12, 0xCB, 0xBD, 0x0B, 0x8F, 0x20, 0xFB, 0x30, 0xDA, 0x27, 0xE4, 0x58, 0x94}, /* 9.1.0 New Device Key Source. */
};
static const u8 new_device_keygen_sources[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_VERSION_400 + 1][0x10] = {
@ -88,7 +91,8 @@ static const u8 new_device_keygen_sources[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_
{0x81, 0x3C, 0x6C, 0xBF, 0x5D, 0x21, 0xDE, 0x77, 0x20, 0xD9, 0x6C, 0xE3, 0x22, 0x06, 0xAE, 0xBB}, /* 6.2.0 New Device Keygen Source. */
{0x86, 0x61, 0xB0, 0x16, 0xFA, 0x7A, 0x9A, 0xEA, 0xF6, 0xF5, 0xBE, 0x1A, 0x13, 0x5B, 0x6D, 0x9E}, /* 7.0.0 New Device Keygen Source. */
{0xA6, 0x81, 0x71, 0xE7, 0xB5, 0x23, 0x74, 0xB0, 0x39, 0x8C, 0xB7, 0xFF, 0xA0, 0x62, 0x9F, 0x8D}, /* 8.1.0 New Device Keygen Source. */
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* TODO: 9.0.0 New Device Keygen Source to be added on next change-of-keys. */
{0x03, 0xE7, 0xEB, 0x43, 0x1B, 0xCF, 0x5F, 0xB5, 0xED, 0xDC, 0x97, 0xAE, 0x21, 0x8D, 0x19, 0xED}, /* 9.0.0 New Device Keygen Source. */
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* TODO: 9.1.0 New Device Keygen Source to be added on next change-of-keys. */
};
// from SPL
@ -110,7 +114,7 @@ static const u8 bis_key_source[3][0x20] = {
0x4D, 0x12, 0xE1, 0x4B, 0x2A, 0x47, 0x4C, 0x1C, 0x09, 0xCB, 0x03, 0x59, 0xF0, 0x15, 0xF4, 0xE4}
};
static const u8 fs_hashes_sha256[10][0x20] = {
static const u8 fs_hashes_sha256[13][0x20] = {
{ // header_kek_source
0x18, 0x88, 0xca, 0xed, 0x55, 0x51, 0xb3, 0xed, 0xe0, 0x14, 0x99, 0xe8, 0x7c, 0xe0, 0xd8, 0x68,
0x27, 0xf8, 0x08, 0x20, 0xef, 0xb2, 0x75, 0x92, 0x10, 0x55, 0xaa, 0x4e, 0x2a, 0xbd, 0xff, 0xc2},
@ -132,6 +136,15 @@ static const u8 fs_hashes_sha256[10][0x20] = {
{ // save_mac_key_source
0xB4, 0x7B, 0x60, 0x0B, 0x1A, 0xD3, 0x14, 0xF9, 0x41, 0x14, 0x7D, 0x8B, 0x39, 0x1D, 0x4B, 0x19,
0x87, 0xCC, 0x8C, 0x88, 0x4A, 0xC8, 0x9F, 0xFC, 0x91, 0xCA, 0xE2, 0x21, 0xC5, 0x24, 0x51, 0xF7},
{ // save_mac_sd_card_kek_source
0x60, 0x1a, 0x60, 0xbe, 0x13, 0xf6, 0x3e, 0xda, 0xec, 0xcc, 0x96, 0x7f, 0x27, 0xa3, 0xa3, 0x64,
0x65, 0xcb, 0xe8, 0xf0, 0x29, 0xf0, 0xc4, 0x14, 0xb2, 0x36, 0x6a, 0x8b, 0x8a, 0x0f, 0x13, 0x00},
{ // save_mac_sd_card_key_source
0xc2, 0x22, 0x0a, 0x38, 0xb6, 0x87, 0x2b, 0x63, 0xee, 0x77, 0xac, 0x8c, 0x28, 0x24, 0x7a, 0x44,
0x02, 0xe6, 0xdd, 0x85, 0x24, 0x8b, 0x41, 0x9a, 0x6f, 0x9b, 0x17, 0x93, 0xc0, 0x50, 0x3f, 0x21},
{ // sd_card_custom_storage_key_source
0x6b, 0x8f, 0xd2, 0x6c, 0x76, 0x5b, 0x7c, 0x67, 0x70, 0x0c, 0x68, 0x54, 0x90, 0x8e, 0xbe, 0x88,
0x45, 0xb0, 0x55, 0xa6, 0xbb, 0xbb, 0xea, 0x0c, 0x06, 0x3a, 0x85, 0x04, 0x12, 0xd4, 0xca, 0x53},
{ // sd_card_kek_source
0x6B, 0x2E, 0xD8, 0x77, 0xC2, 0xC5, 0x23, 0x34, 0xAC, 0x51, 0xE5, 0x9A, 0xBF, 0xA7, 0xEC, 0x45,
0x7F, 0x4A, 0x7D, 0x01, 0xE4, 0x62, 0x91, 0xE9, 0xF2, 0xEA, 0xA4, 0x5F, 0x01, 0x1D, 0x24, 0xB7},

589
source/libs/elfload/elf.h Normal file
View file

@ -0,0 +1,589 @@
/* $OpenBSD: exec_elf.h,v 1.53 2014/01/03 03:00:39 guenther Exp $ */
/*
* Copyright (c) 1995, 1996 Erik Theisen. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* imported sys/exec_elf.h from OpenBSD */
#ifndef ELF_H
#define ELF_H
#include <stdint.h>
typedef uint8_t Elf_Byte;
typedef uint32_t Elf32_Addr; /* Unsigned program address */
typedef uint32_t Elf32_Off; /* Unsigned file offset */
typedef int32_t Elf32_Sword; /* Signed large integer */
typedef uint32_t Elf32_Word; /* Unsigned large integer */
typedef uint16_t Elf32_Half; /* Unsigned medium integer */
typedef uint64_t Elf64_Addr;
typedef uint64_t Elf64_Off;
typedef int32_t Elf64_Shalf;
#ifdef __alpha__
typedef int64_t Elf64_Sword;
typedef uint64_t Elf64_Word;
#else
typedef int32_t Elf64_Sword;
typedef uint32_t Elf64_Word;
#endif
typedef int64_t Elf64_Sxword;
typedef uint64_t Elf64_Xword;
typedef uint32_t Elf64_Half;
typedef uint16_t Elf64_Quarter;
/*
* e_ident[] identification indexes
* See http://www.sco.com/developers/gabi/latest/ch4.eheader.html
*/
#define EI_MAG0 0 /* file ID */
#define EI_MAG1 1 /* file ID */
#define EI_MAG2 2 /* file ID */
#define EI_MAG3 3 /* file ID */
#define EI_CLASS 4 /* file class */
#define EI_DATA 5 /* data encoding */
#define EI_VERSION 6 /* ELF header version */
#define EI_OSABI 7 /* OS/ABI ID */
#define EI_ABIVERSION 8 /* ABI version */
#define EI_PAD 9 /* start of pad bytes */
#define EI_NIDENT 16 /* Size of e_ident[] */
/* e_ident[] magic number */
#define ELFMAG0 0x7f /* e_ident[EI_MAG0] */
#define ELFMAG1 'E' /* e_ident[EI_MAG1] */
#define ELFMAG2 'L' /* e_ident[EI_MAG2] */
#define ELFMAG3 'F' /* e_ident[EI_MAG3] */
#define ELFMAG "\177ELF" /* magic */
#define SELFMAG 4 /* size of magic */
/* e_ident[] file class */
#define ELFCLASSNONE 0 /* invalid */
#define ELFCLASS32 1 /* 32-bit objs */
#define ELFCLASS64 2 /* 64-bit objs */
#define ELFCLASSNUM 3 /* number of classes */
/* e_ident[] data encoding */
#define ELFDATANONE 0 /* invalid */
#define ELFDATA2LSB 1 /* Little-Endian */
#define ELFDATA2MSB 2 /* Big-Endian */
#define ELFDATANUM 3 /* number of data encode defines */
/* e_ident[] Operating System/ABI */
#define ELFOSABI_SYSV 0 /* UNIX System V ABI */
#define ELFOSABI_HPUX 1 /* HP-UX operating system */
#define ELFOSABI_NETBSD 2 /* NetBSD */
#define ELFOSABI_LINUX 3 /* GNU/Linux */
#define ELFOSABI_HURD 4 /* GNU/Hurd */
#define ELFOSABI_86OPEN 5 /* 86Open common IA32 ABI */
#define ELFOSABI_SOLARIS 6 /* Solaris */
#define ELFOSABI_MONTEREY 7 /* Monterey */
#define ELFOSABI_IRIX 8 /* IRIX */
#define ELFOSABI_FREEBSD 9 /* FreeBSD */
#define ELFOSABI_TRU64 10 /* TRU64 UNIX */
#define ELFOSABI_MODESTO 11 /* Novell Modesto */
#define ELFOSABI_OPENBSD 12 /* OpenBSD */
#define ELFOSABI_ARM 97 /* ARM */
#define ELFOSABI_STANDALONE 255 /* Standalone (embedded) application */
/* e_ident */
#define IS_ELF(ehdr) ((ehdr).e_ident[EI_MAG0] == ELFMAG0 && \
(ehdr).e_ident[EI_MAG1] == ELFMAG1 && \
(ehdr).e_ident[EI_MAG2] == ELFMAG2 && \
(ehdr).e_ident[EI_MAG3] == ELFMAG3)
/* ELF Header */
typedef struct
{
unsigned char e_ident[EI_NIDENT]; /* ELF Identification */
Elf32_Half e_type; /* object file type */
Elf32_Half e_machine; /* machine */
Elf32_Word e_version; /* object file version */
Elf32_Addr e_entry; /* virtual entry point */
Elf32_Off e_phoff; /* program header table offset */
Elf32_Off e_shoff; /* section header table offset */
Elf32_Word e_flags; /* processor-specific flags */
Elf32_Half e_ehsize; /* ELF header size */
Elf32_Half e_phentsize; /* program header entry size */
Elf32_Half e_phnum; /* number of program header entries */
Elf32_Half e_shentsize; /* section header entry size */
Elf32_Half e_shnum; /* number of section header entries */
Elf32_Half e_shstrndx; /* section header table's "section
header string table" entry offset */
} Elf32_Ehdr;
typedef struct
{
unsigned char e_ident[EI_NIDENT]; /* Id bytes */
Elf64_Quarter e_type; /* file type */
Elf64_Quarter e_machine; /* machine type */
Elf64_Half e_version; /* version number */
Elf64_Addr e_entry; /* entry point */
Elf64_Off e_phoff; /* Program hdr offset */
Elf64_Off e_shoff; /* Section hdr offset */
Elf64_Half e_flags; /* Processor flags */
Elf64_Quarter e_ehsize; /* sizeof ehdr */
Elf64_Quarter e_phentsize; /* Program header entry size */
Elf64_Quarter e_phnum; /* Number of program headers */
Elf64_Quarter e_shentsize; /* Section header entry size */
Elf64_Quarter e_shnum; /* Number of section headers */
Elf64_Quarter e_shstrndx; /* String table index */
} Elf64_Ehdr;
/* e_type */
#define ET_NONE 0 /* No file type */
#define ET_REL 1 /* relocatable file */
#define ET_EXEC 2 /* executable file */
#define ET_DYN 3 /* shared object file */
#define ET_CORE 4 /* core file */
#define ET_NUM 5 /* number of types */
#define ET_LOPROC 0xff00 /* reserved range for processor */
#define ET_HIPROC 0xffff /* specific e_type */
/* e_machine */
#define EM_NONE 0 /* No Machine */
#define EM_M32 1 /* AT&T WE 32100 */
#define EM_SPARC 2 /* SPARC */
#define EM_386 3 /* Intel 80386 */
#define EM_68K 4 /* Motorola 68000 */
#define EM_88K 5 /* Motorola 88000 */
#define EM_486 6 /* Intel 80486 - unused? */
#define EM_860 7 /* Intel 80860 */
#define EM_MIPS 8 /* MIPS R3000 Big-Endian only */
/*
* Don't know if EM_MIPS_RS4_BE,
* EM_SPARC64, EM_PARISC,
* or EM_PPC are ABI compliant
*/
#define EM_MIPS_RS4_BE 10 /* MIPS R4000 Big-Endian */
#define EM_SPARC64 11 /* SPARC v9 64-bit unofficial */
#define EM_PARISC 15 /* HPPA */
#define EM_SPARC32PLUS 18 /* Enhanced instruction set SPARC */
#define EM_PPC 20 /* PowerPC */
#define EM_ARM 40 /* ARM AArch32 */
#define EM_ALPHA 41 /* DEC ALPHA */
#define EM_SH 42 /* Hitachi/Renesas Super-H */
#define EM_SPARCV9 43 /* SPARC version 9 */
#define EM_IA_64 50 /* Intel IA-64 Processor */
#define EM_AMD64 62 /* AMD64 architecture */
#define EM_VAX 75 /* DEC VAX */
#define EM_AARCH64 183 /* ARM AArch64 */
/* Non-standard */
#define EM_ALPHA_EXP 0x9026 /* DEC ALPHA */
/* Version */
#define EV_NONE 0 /* Invalid */
#define EV_CURRENT 1 /* Current */
#define EV_NUM 2 /* number of versions */
/* Section Header */
typedef struct
{
Elf32_Word sh_name; /* name - index into section header
* string table section */
Elf32_Word sh_type; /* type */
Elf32_Word sh_flags; /* flags */
Elf32_Addr sh_addr; /* address */
Elf32_Off sh_offset; /* file offset */
Elf32_Word sh_size; /* section size */
Elf32_Word sh_link; /* section header table index link */
Elf32_Word sh_info; /* extra information */
Elf32_Word sh_addralign; /* address alignment */
Elf32_Word sh_entsize; /* section entry size */
} Elf32_Shdr;
typedef struct
{
Elf64_Half sh_name; /* section name */
Elf64_Half sh_type; /* section type */
Elf64_Xword sh_flags; /* section flags */
Elf64_Addr sh_addr; /* virtual address */
Elf64_Off sh_offset; /* file offset */
Elf64_Xword sh_size; /* section size */
Elf64_Half sh_link; /* link to another */
Elf64_Half sh_info; /* misc info */
Elf64_Xword sh_addralign; /* memory alignment */
Elf64_Xword sh_entsize; /* table entry size */
} Elf64_Shdr;
/* Special Section Indexes */
#define SHN_UNDEF 0 /* undefined */
#define SHN_LORESERVE 0xff00 /* lower bounds of reserved indexes */
#define SHN_LOPROC 0xff00 /* reserved range for processor */
#define SHN_HIPROC 0xff1f /* specific section indexes */
#define SHN_ABS 0xfff1 /* absolute value */
#define SHN_COMMON 0xfff2 /* common symbol */
#define SHN_HIRESERVE 0xffff /* upper bounds of reserved indexes */
/* sh_type */
#define SHT_NULL 0 /* inactive */
#define SHT_PROGBITS 1 /* program defined information */
#define SHT_SYMTAB 2 /* symbol table section */
#define SHT_STRTAB 3 /* string table section */
#define SHT_RELA 4 /* relocation section with addends*/
#define SHT_HASH 5 /* symbol hash table section */
#define SHT_DYNAMIC 6 /* dynamic section */
#define SHT_NOTE 7 /* note section */
#define SHT_NOBITS 8 /* no space section */
#define SHT_REL 9 /* relation section without addends */
#define SHT_SHLIB 10 /* reserved - purpose unknown */
#define SHT_DYNSYM 11 /* dynamic symbol table section */
#define SHT_NUM 12 /* number of section types */
#define SHT_LOPROC 0x70000000 /* reserved range for processor */
#define SHT_HIPROC 0x7fffffff /* specific section header types */
#define SHT_LOUSER 0x80000000 /* reserved range for application */
#define SHT_HIUSER 0xffffffff /* specific indexes */
/* Section names */
#define ELF_BSS ".bss" /* uninitialized data */
#define ELF_DATA ".data" /* initialized data */
#define ELF_DEBUG ".debug" /* debug */
#define ELF_DYNAMIC ".dynamic" /* dynamic linking information */
#define ELF_DYNSTR ".dynstr" /* dynamic string table */
#define ELF_DYNSYM ".dynsym" /* dynamic symbol table */
#define ELF_FINI ".fini" /* termination code */
#define ELF_GOT ".got" /* global offset table */
#define ELF_HASH ".hash" /* symbol hash table */
#define ELF_INIT ".init" /* initialization code */
#define ELF_REL_DATA ".rel.data" /* relocation data */
#define ELF_REL_FINI ".rel.fini" /* relocation termination code */
#define ELF_REL_INIT ".rel.init" /* relocation initialization code */
#define ELF_REL_DYN ".rel.dyn" /* relocation dynamic link info */
#define ELF_REL_RODATA ".rel.rodata" /* relocation read-only data */
#define ELF_REL_TEXT ".rel.text" /* relocation code */
#define ELF_RODATA ".rodata" /* read-only data */
#define ELF_SHSTRTAB ".shstrtab" /* section header string table */
#define ELF_STRTAB ".strtab" /* string table */
#define ELF_SYMTAB ".symtab" /* symbol table */
#define ELF_TEXT ".text" /* code */
/* Section Attribute Flags - sh_flags */
#define SHF_WRITE 0x1 /* Writable */
#define SHF_ALLOC 0x2 /* occupies memory */
#define SHF_EXECINSTR 0x4 /* executable */
#define SHF_TLS 0x400 /* thread local storage */
#define SHF_MASKPROC 0xf0000000 /* reserved bits for processor \
* specific section attributes */
/* Symbol Table Entry */
typedef struct elf32_sym
{
Elf32_Word st_name; /* name - index into string table */
Elf32_Addr st_value; /* symbol value */
Elf32_Word st_size; /* symbol size */
unsigned char st_info; /* type and binding */
unsigned char st_other; /* 0 - no defined meaning */
Elf32_Half st_shndx; /* section header index */
} Elf32_Sym;
typedef struct
{
Elf64_Half st_name; /* Symbol name index in str table */
Elf_Byte st_info; /* type / binding attrs */
Elf_Byte st_other; /* unused */
Elf64_Quarter st_shndx; /* section index of symbol */
Elf64_Xword st_value; /* value of symbol */
Elf64_Xword st_size; /* size of symbol */
} Elf64_Sym;
/* Symbol table index */
#define STN_UNDEF 0 /* undefined */
/* Extract symbol info - st_info */
#define ELF32_ST_BIND(x) ((x) >> 4)
#define ELF32_ST_TYPE(x) (((unsigned int)x) & 0xf)
#define ELF32_ST_INFO(b, t) (((b) << 4) + ((t)&0xf))
#define ELF64_ST_BIND(x) ((x) >> 4)
#define ELF64_ST_TYPE(x) (((unsigned int)x) & 0xf)
#define ELF64_ST_INFO(b, t) (((b) << 4) + ((t)&0xf))
/* Symbol Binding - ELF32_ST_BIND - st_info */
#define STB_LOCAL 0 /* Local symbol */
#define STB_GLOBAL 1 /* Global symbol */
#define STB_WEAK 2 /* like global - lower precedence */
#define STB_NUM 3 /* number of symbol bindings */
#define STB_LOPROC 13 /* reserved range for processor */
#define STB_HIPROC 15 /* specific symbol bindings */
/* Symbol type - ELF32_ST_TYPE - st_info */
#define STT_NOTYPE 0 /* not specified */
#define STT_OBJECT 1 /* data object */
#define STT_FUNC 2 /* function */
#define STT_SECTION 3 /* section */
#define STT_FILE 4 /* file */
#define STT_TLS 6 /* thread local storage */
#define STT_LOPROC 13 /* reserved range for processor */
#define STT_HIPROC 15 /* specific symbol types */
/* Relocation entry with implicit addend */
typedef struct
{
Elf32_Addr r_offset; /* offset of relocation */
Elf32_Word r_info; /* symbol table index and type */
} Elf32_Rel;
/* Relocation entry with explicit addend */
typedef struct
{
Elf32_Addr r_offset; /* offset of relocation */
Elf32_Word r_info; /* symbol table index and type */
Elf32_Sword r_addend;
} Elf32_Rela;
/* Extract relocation info - r_info */
#define ELF32_R_SYM(i) ((i) >> 8)
#define ELF32_R_TYPE(i) ((unsigned char)(i))
#define ELF32_R_INFO(s, t) (((s) << 8) + (unsigned char)(t))
typedef struct
{
Elf64_Xword r_offset; /* where to do it */
Elf64_Xword r_info; /* index & type of relocation */
} Elf64_Rel;
typedef struct
{
Elf64_Xword r_offset; /* where to do it */
Elf64_Xword r_info; /* index & type of relocation */
Elf64_Sxword r_addend; /* adjustment value */
} Elf64_Rela;
#define ELF64_R_SYM(info) ((info) >> 32)
#define ELF64_R_TYPE(info) ((info)&0xFFFFFFFF)
#define ELF64_R_INFO(s, t) (((s) << 32) + (__uint32_t)(t))
#if defined(__mips64__) && defined(__MIPSEL__)
/*
* The 64-bit MIPS ELF ABI uses a slightly different relocation format
* than the regular ELF ABI: the r_info field is split into several
* pieces (see gnu/usr.bin/binutils/include/elf/mips.h for details).
*/
#undef ELF64_R_SYM
#undef ELF64_R_TYPE
#undef ELF64_R_INFO
#define ELF64_R_TYPE(info) (swap32((info) >> 32))
#define ELF64_R_SYM(info) ((info)&0xFFFFFFFF)
#define ELF64_R_INFO(s, t) (((__uint64_t)swap32(t) << 32) + (__uint32_t)(s))
#endif /* __mips64__ && __MIPSEL__ */
/* Program Header */
typedef struct
{
Elf32_Word p_type; /* segment type */
Elf32_Off p_offset; /* segment offset */
Elf32_Addr p_vaddr; /* virtual address of segment */
Elf32_Addr p_paddr; /* physical address - ignored? */
Elf32_Word p_filesz; /* number of bytes in file for seg. */
Elf32_Word p_memsz; /* number of bytes in mem. for seg. */
Elf32_Word p_flags; /* flags */
Elf32_Word p_align; /* memory alignment */
} Elf32_Phdr;
typedef struct
{
Elf64_Half p_type; /* entry type */
Elf64_Half p_flags; /* flags */
Elf64_Off p_offset; /* offset */
Elf64_Addr p_vaddr; /* virtual address */
Elf64_Addr p_paddr; /* physical address */
Elf64_Xword p_filesz; /* file size */
Elf64_Xword p_memsz; /* memory size */
Elf64_Xword p_align; /* memory & file alignment */
} Elf64_Phdr;
/* Segment types - p_type */
#define PT_NULL 0 /* unused */
#define PT_LOAD 1 /* loadable segment */
#define PT_DYNAMIC 2 /* dynamic linking section */
#define PT_INTERP 3 /* the RTLD */
#define PT_NOTE 4 /* auxiliary information */
#define PT_SHLIB 5 /* reserved - purpose undefined */
#define PT_PHDR 6 /* program header */
#define PT_TLS 7 /* thread local storage */
#define PT_LOOS 0x60000000 /* reserved range for OS */
#define PT_HIOS 0x6fffffff /* specific segment types */
#define PT_LOPROC 0x70000000 /* reserved range for processor */
#define PT_HIPROC 0x7fffffff /* specific segment types */
#define PT_OPENBSD_RANDOMIZE 0x65a3dbe6 /* fill with random data */
#define PT_GANDR_KERNEL 0x67646b6c /* gdkl */
/* Segment flags - p_flags */
#define PF_X 0x1 /* Executable */
#define PF_W 0x2 /* Writable */
#define PF_R 0x4 /* Readable */
#define PF_MASKPROC 0xf0000000 /* reserved bits for processor */
/* specific segment flags */
/* Dynamic structure */
typedef struct
{
Elf32_Sword d_tag; /* controls meaning of d_val */
union {
Elf32_Word d_val; /* Multiple meanings - see d_tag */
Elf32_Addr d_ptr; /* program virtual address */
} d_un;
} Elf32_Dyn;
typedef struct
{
Elf64_Xword d_tag; /* controls meaning of d_val */
union {
Elf64_Addr d_ptr;
Elf64_Xword d_val;
} d_un;
} Elf64_Dyn;
/* Dynamic Array Tags - d_tag */
#define DT_NULL 0 /* marks end of _DYNAMIC array */
#define DT_NEEDED 1 /* string table offset of needed lib */
#define DT_PLTRELSZ 2 /* size of relocation entries in PLT */
#define DT_PLTGOT 3 /* address PLT/GOT */
#define DT_HASH 4 /* address of symbol hash table */
#define DT_STRTAB 5 /* address of string table */
#define DT_SYMTAB 6 /* address of symbol table */
#define DT_RELA 7 /* address of relocation table */
#define DT_RELASZ 8 /* size of relocation table */
#define DT_RELAENT 9 /* size of relocation entry */
#define DT_STRSZ 10 /* size of string table */
#define DT_SYMENT 11 /* size of symbol table entry */
#define DT_INIT 12 /* address of initialization func. */
#define DT_FINI 13 /* address of termination function */
#define DT_SONAME 14 /* string table offset of shared obj */
#define DT_RPATH 15 /* string table offset of library \
* search path */
#define DT_SYMBOLIC 16 /* start sym search in shared obj. */
#define DT_REL 17 /* address of rel. tbl. w addends */
#define DT_RELSZ 18 /* size of DT_REL relocation table */
#define DT_RELENT 19 /* size of DT_REL relocation entry */
#define DT_PLTREL 20 /* PLT referenced relocation entry */
#define DT_DEBUG 21 /* bugger */
#define DT_TEXTREL 22 /* Allow rel. mod. to unwritable seg */
#define DT_JMPREL 23 /* add. of PLT's relocation entries */
#define DT_BIND_NOW 24 /* Bind now regardless of env setting */
#define DT_LOOS 0x6000000d /* reserved range for OS */
#define DT_HIOS 0x6ffff000 /* specific dynamic array tags */
#define DT_LOPROC 0x70000000 /* reserved range for processor */
#define DT_HIPROC 0x7fffffff /* specific dynamic array tags */
/* some other useful tags */
#define DT_RELACOUNT 0x6ffffff9 /* if present, number of RELATIVE */
#define DT_RELCOUNT 0x6ffffffa /* relocs, which must come first */
#define DT_FLAGS_1 0x6ffffffb
/* Dynamic Flags - DT_FLAGS_1 .dynamic entry */
#define DF_1_NOW 0x00000001
#define DF_1_GLOBAL 0x00000002
#define DF_1_GROUP 0x00000004
#define DF_1_NODELETE 0x00000008
#define DF_1_LOADFLTR 0x00000010
#define DF_1_INITFIRST 0x00000020
#define DF_1_NOOPEN 0x00000040
#define DF_1_ORIGIN 0x00000080
#define DF_1_DIRECT 0x00000100
#define DF_1_TRANS 0x00000200
#define DF_1_INTERPOSE 0x00000400
#define DF_1_NODEFLIB 0x00000800
#define DF_1_NODUMP 0x00001000
#define DF_1_CONLFAT 0x00002000
/* ld.so: number of low tags that are used saved internally (0 .. DT_NUM-1) */
#define DT_NUM (DT_JMPREL + 1)
/*
* Note Definitions
*/
typedef struct
{
Elf32_Word namesz;
Elf32_Word descsz;
Elf32_Word type;
} Elf32_Note;
typedef struct
{
Elf64_Half namesz;
Elf64_Half descsz;
Elf64_Half type;
} Elf64_Note;
#if defined(ELFSIZE) && (ELFSIZE == 32)
#define Elf_Ehdr Elf32_Ehdr
#define Elf_Phdr Elf32_Phdr
#define Elf_Shdr Elf32_Shdr
#define Elf_Sym Elf32_Sym
#define Elf_Rel Elf32_Rel
#define Elf_RelA Elf32_Rela
#define Elf_Dyn Elf32_Dyn
#define Elf_Half Elf32_Half
#define Elf_Word Elf32_Word
#define Elf_Sword Elf32_Sword
#define Elf_Addr Elf32_Addr
#define Elf_Off Elf32_Off
#define Elf_Nhdr Elf32_Nhdr
#define Elf_Note Elf32_Note
#define ELF_R_SYM ELF32_R_SYM
#define ELF_R_TYPE ELF32_R_TYPE
#define ELF_R_INFO ELF32_R_INFO
#define ELFCLASS ELFCLASS32
#define ELF_ST_BIND ELF32_ST_BIND
#define ELF_ST_TYPE ELF32_ST_TYPE
#define ELF_ST_INFO ELF32_ST_INFO
#elif defined(ELFSIZE) && (ELFSIZE == 64)
#define Elf_Ehdr Elf64_Ehdr
#define Elf_Phdr Elf64_Phdr
#define Elf_Shdr Elf64_Shdr
#define Elf_Sym Elf64_Sym
#define Elf_Rel Elf64_Rel
#define Elf_RelA Elf64_Rela
#define Elf_Dyn Elf64_Dyn
#define Elf_Half Elf64_Half
#define Elf_Word Elf64_Word
#define Elf_Sword Elf64_Sword
#define Elf_Addr Elf64_Addr
#define Elf_Off Elf64_Off
#define Elf_Nhdr Elf64_Nhdr
#define Elf_Note Elf64_Note
#define ELF_R_SYM ELF64_R_SYM
#define ELF_R_TYPE ELF64_R_TYPE
#define ELF_R_INFO ELF64_R_INFO
#define ELFCLASS ELFCLASS64
#define ELF_ST_BIND ELF64_ST_BIND
#define ELF_ST_TYPE ELF64_ST_TYPE
#define ELF_ST_INFO ELF64_ST_INFO
#endif
#endif

View file

@ -0,0 +1,49 @@
/*
* Copyright © 2014, Owen Shepherd
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef ELFARCH_H
#define ELFARCH_H
#if defined(__i386__)
#define EM_THIS EM_386
#define EL_ARCH_USES_REL
#elif defined(__amd64__)
#define EM_THIS EM_AMD64
#define EL_ARCH_USES_RELA
#elif defined(__arm__)
#define EM_THIS EM_ARM
#define EL_ARCH_USES_REL
#elif defined(__aarch64__)
#define EM_THIS EM_AARCH64
#define EL_ARCH_USES_RELA
#define EL_ARCH_USES_REL
#else
#error specify your ELF architecture
#endif
#if defined(__LP64__) || defined(__LLP64__)
#define ELFSIZE 64
#else
#define ELFSIZE 32
#endif
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
#define ELFDATATHIS ELFDATA2LSB
#else
#define ELFDATATHIS ELFDATA2MSB
#endif
#endif

View file

@ -0,0 +1,324 @@
/*
* Copyright © 2018, M4xw
* Copyright © 2014, Owen Shepherd
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#include <string.h>
#include "elfload.h"
el_status el_pread(el_ctx *ctx, void *def, size_t nb, size_t offset)
{
return ctx->pread(ctx, def, nb, offset) ? EL_OK : EL_EIO;
}
#define EL_PHOFF(ctx, num) (((ctx)->ehdr.e_phoff + (num) *(ctx)->ehdr.e_phentsize))
el_status el_findphdr(el_ctx *ctx, Elf_Phdr *phdr, uint32_t type, unsigned *i)
{
el_status rv = EL_OK;
for (; *i < ctx->ehdr.e_phnum; (*i)++)
{
if ((rv = el_pread(ctx, phdr, sizeof *phdr, EL_PHOFF(ctx, *i))))
return rv;
if (phdr->p_type == type)
{
return rv;
}
}
*i = -1;
return rv;
}
#define EL_SHOFF(ctx, num) (((ctx)->ehdr.e_shoff + (num) *(ctx)->ehdr.e_shentsize))
el_status el_findshdr(el_ctx *ctx, Elf_Shdr *shdr, uint32_t type, unsigned *i)
{
el_status rv = EL_OK;
for (; *i < ctx->ehdr.e_shnum; (*i)++)
{
if ((rv = el_pread(ctx, shdr, sizeof *shdr, EL_SHOFF(ctx, *i))))
return rv;
if (shdr->sh_type == type)
{
return rv;
}
}
*i = -1;
return rv;
}
el_status el_init(el_ctx *ctx)
{
el_status rv = EL_OK;
if ((rv = el_pread(ctx, &ctx->ehdr, sizeof ctx->ehdr, 0)))
return rv;
/* validate header */
if (!IS_ELF(ctx->ehdr))
return EL_NOTELF;
if (ctx->ehdr.e_ident[EI_CLASS] != ELFCLASS)
return EL_WRONGBITS;
if (ctx->ehdr.e_ident[EI_DATA] != ELFDATATHIS)
return EL_WRONGENDIAN;
if (ctx->ehdr.e_ident[EI_VERSION] != EV_CURRENT)
return EL_NOTELF;
if (ctx->ehdr.e_type != ET_EXEC && ctx->ehdr.e_type != ET_DYN)
return EL_NOTEXEC;
if (ctx->ehdr.e_machine != EM_THIS)
return EL_WRONGARCH;
if (ctx->ehdr.e_version != EV_CURRENT)
return EL_NOTELF;
/* load phdrs */
Elf_Phdr ph;
/* iterate through, calculate extents */
ctx->base_load_paddr = ctx->base_load_vaddr = 0;
ctx->align = 1;
ctx->memsz = 0;
unsigned i = 0;
for (;;)
{
if ((rv = el_findphdr(ctx, &ph, PT_LOAD, &i)))
return rv;
if (i == (unsigned)-1)
break;
Elf_Addr phend = ph.p_vaddr + ph.p_memsz;
if (phend > ctx->memsz)
ctx->memsz = phend;
if (ph.p_align > ctx->align)
ctx->align = ph.p_align;
i++;
}
// Program Header
if (ctx->ehdr.e_type == ET_DYN)
{
i = 0;
if ((rv = el_findphdr(ctx, &ph, PT_DYNAMIC, &i)))
return rv;
if (i == (unsigned)-1)
return EL_NODYN;
ctx->dynoff = ph.p_offset;
ctx->dynsize = ph.p_filesz;
}
else
{
ctx->dynoff = 0;
ctx->dynsize = 0;
}
// Section String Table
if (ctx->ehdr.e_type == ET_DYN)
{
i = ctx->ehdr.e_shstrndx - 1;
if ((rv = el_findshdr(ctx, &ctx->shstr, SHT_STRTAB, &i)))
return rv;
// Reset
i = 0;
if ((rv = el_findshdr(ctx, &ctx->symtab, SHT_SYMTAB, &i)))
return rv;
if (i == (unsigned)-1)
return EL_NODYN;
}
return rv;
}
/*
typedef void* (*el_alloc_cb)(
el_ctx *ctx,
Elf_Addr phys,
Elf_Addr virt,
Elf_Addr size);
*/
el_status el_load(el_ctx *ctx, el_alloc_cb alloc)
{
el_status rv = EL_OK;
/* address deltas */
Elf_Addr pdelta = ctx->base_load_paddr;
Elf_Addr vdelta = ctx->base_load_vaddr;
/* iterate paddrs */
Elf_Phdr ph;
unsigned i = 0;
for (;;)
{
if ((rv = el_findphdr(ctx, &ph, PT_LOAD, &i)))
return rv;
if (i == (unsigned)-1)
break;
Elf_Addr pload = ph.p_paddr + pdelta;
Elf_Addr vload = ph.p_vaddr + vdelta;
/* allocate mem */
char *dest = alloc(ctx, pload, vload, ph.p_memsz);
if (!dest)
return EL_ENOMEM;
EL_DEBUG("Loading seg fileoff %x, vaddr %x to %p\n",
ph.p_offset, ph.p_vaddr, dest);
/* read loaded portion */
if ((rv = el_pread(ctx, dest, ph.p_filesz, ph.p_offset)))
return rv;
/* zero mem-only portion */
memset(dest + ph.p_filesz, 0, ph.p_memsz - ph.p_filesz);
i++;
}
return rv;
}
el_status el_finddyn(el_ctx *ctx, Elf_Dyn *dyn, uint32_t tag)
{
el_status rv = EL_OK;
size_t ndyn = ctx->dynsize / sizeof(Elf_Dyn);
for (unsigned i = 0; i < ndyn; i++)
{
if ((rv = el_pread(ctx, dyn, sizeof *dyn, ctx->dynoff + i * sizeof *dyn)))
return rv;
if (dyn->d_tag == tag)
return EL_OK;
}
dyn->d_tag = DT_NULL;
return EL_OK;
}
el_status el_findrelocs(el_ctx *ctx, el_relocinfo *ri, uint32_t type)
{
el_status rv = EL_OK;
Elf_Dyn rel, relsz, relent;
if ((rv = el_finddyn(ctx, &rel, type)))
return rv;
if ((rv = el_finddyn(ctx, &relsz, type + 1)))
return rv;
if ((rv = el_finddyn(ctx, &relent, type + 2)))
return rv;
if (rel.d_tag == DT_NULL || relsz.d_tag == DT_NULL || relent.d_tag == DT_NULL)
{
ri->entrysize = 0;
ri->tablesize = 0;
ri->tableoff = 0;
}
else
{
ri->tableoff = rel.d_un.d_ptr;
ri->tablesize = relsz.d_un.d_val;
ri->entrysize = relent.d_un.d_val;
}
return rv;
}
extern el_status el_applyrel(el_ctx *ctx, Elf_Rel *rel);
extern el_status el_applyrela(el_ctx *ctx, Elf_RelA *rela);
el_status el_relocate(el_ctx *ctx)
{
el_status rv = EL_OK;
// not dynamic
if (ctx->ehdr.e_type != ET_DYN)
return EL_OK;
char *base = (char *)ctx->base_load_paddr;
el_relocinfo ri;
#ifdef EL_ARCH_USES_REL
if ((rv = el_findrelocs(ctx, &ri, DT_REL)))
return rv;
if (ri.entrysize != sizeof(Elf_Rel) && ri.tablesize)
{
EL_DEBUG("Relocation size %u doesn't match expected %u\n",
ri.entrysize, sizeof(Elf_Rel));
return EL_BADREL;
}
size_t relcnt = ri.tablesize / sizeof(Elf_Rel);
Elf_Rel *reltab = (Elf_Rel *)(base + ri.tableoff);
for (size_t i = 0; i < relcnt; i++)
{
if ((rv = el_applyrel(ctx, &reltab[i])))
return rv;
}
#endif
#ifdef EL_ARCH_USES_RELA
if ((rv = el_findrelocs(ctx, &ri, DT_RELA)))
return rv;
if (ri.entrysize != sizeof(Elf_RelA) && ri.tablesize)
{
EL_DEBUG("Relocation size %u doesn't match expected %u\n",
ri.entrysize, sizeof(Elf_RelA));
return EL_BADREL;
}
size_t relacnt = ri.tablesize / sizeof(Elf_RelA);
Elf_RelA *relatab = (Elf_RelA *)(base + ri.tableoff);
for (size_t i = 0; i < relacnt; i++)
{
if ((rv = el_applyrela(ctx, &relatab[i])))
return rv;
}
#endif
#if !defined(EL_ARCH_USES_REL) && !defined(EL_ARCH_USES_RELA)
#error No relocation type defined!
#endif
return rv;
}

View file

@ -0,0 +1,127 @@
/*
* Copyright © 2018, M4xw
* Copyright © 2014, Owen Shepherd
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef ELFLOAD_H
#define ELFLOAD_H
#include <stddef.h>
#include "elfarch.h"
#include "elf.h"
#include "../../utils/types.h"
#ifdef DEBUG
#include "../../gfx/gfx.h"
#define EL_DEBUG(format, ...) \
gfx_printf(format __VA_OPT__(, ) __VA_ARGS__)
#else
#define EL_DEBUG(...) \
do \
{ \
} while (0)
#endif
typedef enum
{
EL_OK = 0,
EL_EIO,
EL_ENOMEM,
EL_NOTELF,
EL_WRONGBITS,
EL_WRONGENDIAN,
EL_WRONGARCH,
EL_WRONGOS,
EL_NOTEXEC,
EL_NODYN,
EL_BADREL,
} el_status;
typedef struct el_ctx
{
bool (*pread)(struct el_ctx *ctx, void *dest, size_t nb, size_t offset);
/* base_load_* -> address we are actually going to load at
*/
Elf_Addr
base_load_paddr,
base_load_vaddr;
/* size in memory of binary */
Elf_Addr memsz;
/* required alignment */
Elf_Addr align;
/* ELF header */
Elf_Ehdr ehdr;
// Section Header Str Table
Elf_Shdr shstr;
Elf_Shdr symtab;
/* Offset of dynamic table (0 if not ET_DYN) */
Elf_Off dynoff;
/* Size of dynamic table (0 if not ET_DYN) */
Elf_Addr dynsize;
} el_ctx;
el_status el_pread(el_ctx *ctx, void *def, size_t nb, size_t offset);
el_status el_init(el_ctx *ctx);
typedef void *(*el_alloc_cb)(
el_ctx *ctx,
Elf_Addr phys,
Elf_Addr virt,
Elf_Addr size);
el_status el_load(el_ctx *ctx, el_alloc_cb alloccb);
/* find the next phdr of type \p type, starting at \p *i.
* On success, returns EL_OK with *i set to the phdr number, and the phdr loaded
* in *phdr.
*
* If the end of the phdrs table was reached, *i is set to -1 and the contents
* of *phdr are undefined
*/
el_status el_findphdr(el_ctx *ctx, Elf_Phdr *phdr, uint32_t type, unsigned *i);
/* Relocate the loaded executable */
el_status el_relocate(el_ctx *ctx);
/* find a dynamic table entry
* returns the entry on success, dyn->d_tag = DT_NULL on failure
*/
el_status el_finddyn(el_ctx *ctx, Elf_Dyn *dyn, uint32_t type);
typedef struct
{
Elf_Off tableoff;
Elf_Addr tablesize;
Elf_Addr entrysize;
} el_relocinfo;
/* find all information regarding relocations of a specific type.
*
* pass DT_REL or DT_RELA for type
* sets ri->entrysize = 0 if not found
*/
el_status el_findrelocs(el_ctx *ctx, el_relocinfo *ri, uint32_t type);
#endif

View file

@ -0,0 +1,84 @@
/*
* Copyright © 2014, Owen Shepherd
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#include "elfload.h"
#if defined(__aarch64__)
#define R_AARCH64_NONE 0
#define R_AARCH64_RELATIVE 1027
el_status el_applyrela(el_ctx *ctx, Elf_RelA *rel)
{
uintptr_t *p = (uintptr_t *)(rel->r_offset + ctx->base_load_paddr);
uint32_t type = ELF_R_TYPE(rel->r_info);
uint32_t sym = ELF_R_SYM(rel->r_info);
switch (type)
{
case R_AARCH64_NONE:
EL_DEBUG("R_AARCH64_NONE\n");
break;
case R_AARCH64_RELATIVE:
if (sym)
{
EL_DEBUG("R_AARCH64_RELATIVE with symbol ref!\n");
return EL_BADREL;
}
EL_DEBUG("Applying R_AARCH64_RELATIVE reloc @%p\n", p);
*p = rel->r_addend + ctx->base_load_vaddr;
break;
default:
EL_DEBUG("Bad relocation %u\n", type);
return EL_BADREL;
}
return EL_OK;
}
el_status el_applyrel(el_ctx *ctx, Elf_Rel *rel)
{
uintptr_t *p = (uintptr_t *)(rel->r_offset + ctx->base_load_paddr);
uint32_t type = ELF_R_TYPE(rel->r_info);
uint32_t sym = ELF_R_SYM(rel->r_info);
switch (type)
{
case R_AARCH64_NONE:
EL_DEBUG("R_AARCH64_NONE\n");
break;
case R_AARCH64_RELATIVE:
if (sym)
{
EL_DEBUG("R_AARCH64_RELATIVE with symbol ref!\n");
return EL_BADREL;
}
EL_DEBUG("Applying R_AARCH64_RELATIVE reloc @%p\n", p);
*p += ctx->base_load_vaddr;
break;
default:
EL_DEBUG("Bad relocation %u\n", type);
return EL_BADREL;
}
return EL_OK;
}
#endif

View file

@ -0,0 +1,66 @@
/*
* ----------------------------------------------------------------------------
* "THE BEER-WARE LICENSE" (Revision 42):
* <m4x@m4xw.net> wrote this file. As long as you retain this notice you can do
* whatever you want with this stuff. If we meet some day, and you think this
* stuff is worth it, you can buy me a beer in return. M4xw
* ----------------------------------------------------------------------------
*/
#include "elfload.h"
#if defined(__arm__)
// Taken from http://infocenter.arm.com/help/topic/com.arm.doc.ihi0044f/IHI0044F_aaelf.pdf
#define R_ARM_NONE 0
#define R_ARM_ABS32 2
#define R_ARM_JUMP_SLOT 22
#define R_ARM_GLOB_DAT 21
#define R_ARM_RELATIVE 23
el_status el_applyrel(el_ctx *ctx, Elf_Rel *rel)
{
uint32_t sym = ELF_R_SYM(rel->r_info); // Symbol offset
uint32_t type = ELF_R_TYPE(rel->r_info); // Relocation Type
uintptr_t *p = (uintptr_t *)(rel->r_offset + ctx->base_load_paddr); // Target Addr
#if 0 // For later symbol usage
Elf32_Sym *elfSym;
const char *symbolName;
// We resolve relocs from the originating elf-image
elfSym = (Elf32_Sym *)(ctx->symtab.sh_offset + (char *)buffteg) + sym;
int strtab_offset = ctx->shstr.sh_offset;
char *strtab = (char *)buffteg + strtab_offset;
symbolName = strtab + elfSym->st_name;
//EL_DEBUG("Str: %s sz: %x val: %x\n", symbolName, elfSym->st_size, elfSym->st_value);
#endif
switch (type)
{
case R_ARM_NONE:
EL_DEBUG("R_ARM_NONE\n");
break;
case R_ARM_JUMP_SLOT:
case R_ARM_ABS32:
case R_ARM_GLOB_DAT:
// Stubbed for later purpose
//*p += elfSym->st_value; // + vaddr from sec
//*p |= 0; // 1 if Thumb && STT_FUNC, ignored for now
break;
case R_ARM_RELATIVE: // Needed for PIE
if (sym)
{
return EL_BADREL;
}
*p += ctx->base_load_vaddr;
break;
default:
return EL_BADREL;
}
return EL_OK;
}
#endif

View file

@ -24,15 +24,15 @@
/*-----------------------------------------------------------------------*/
#include <string.h>
#include "../../../common/memory_map.h"
#include "diskio.h" /* FatFs lower layer API */
#include "../../mem/heap.h"
#include "../../sec/se.h"
#include "../../storage/nx_emmc.h"
#include "../../storage/sdmmc.h"
#define SDMMC_UPPER_BUFFER 0xB8000000
#define DRAM_START 0x80000000
extern sdmmc_storage_t sd_storage;
extern sdmmc_storage_t storage;
extern emmc_part_t *system_part;

View file

@ -19,134 +19,321 @@
#include <string.h>
#include "config/config.h"
#include "config/ini.h"
#include "gfx/di.h"
#include "gfx/gfx.h"
#include "gfx/tui.h"
#include "hos/pkg1.h"
#include "libs/fatfs/ff.h"
#include "mem/heap.h"
#include "mem/minerva.h"
#include "power/max77620.h"
#include "rtc/max77620-rtc.h"
#include "soc/bpmp.h"
#include "soc/hw_init.h"
#include "storage/emummc.h"
#include "storage/nx_emmc.h"
#include "storage/sdmmc.h"
#include "utils/btn.h"
#include "utils/dirlist.h"
#include "utils/sprintf.h"
#include "utils/util.h"
#include "utils/btn.h"
#include "incognito/incognito.h"
sdmmc_t sd_sdmmc;
sdmmc_storage_t sd_storage;
__attribute__((aligned(16))) FATFS sd_fs;
__attribute__ ((aligned (16))) FATFS sd_fs;
static bool sd_mounted;
hekate_config h_cfg;
boot_cfg_t __attribute__((section("._boot_cfg"))) b_cfg;
boot_cfg_t __attribute__((section ("._boot_cfg"))) b_cfg;
volatile nyx_storage_t *nyx_str = (nyx_storage_t *)NYX_STORAGE_ADDR;
bool sd_mount()
{
if (sd_mounted)
return true;
if (sd_mounted)
return true;
if (!sdmmc_storage_init_sd(&sd_storage, &sd_sdmmc, SDMMC_1, SDMMC_BUS_WIDTH_4, 11))
{
EPRINTF("Failed to init SD card.\nMake sure that it is inserted.\nOr that SD reader is properly seated!");
}
else
{
int res = 0;
res = f_mount(&sd_fs, "sd:", 1);
if (res == FR_OK)
{
sd_mounted = 1;
return true;
}
else
{
EPRINTFARGS("Failed to mount SD card (FatFS Error %d).\nMake sure that a FAT partition exists..", res);
}
}
if (!sdmmc_storage_init_sd(&sd_storage, &sd_sdmmc, SDMMC_1, SDMMC_BUS_WIDTH_4, 11))
{
EPRINTF("Failed to init SD card.\nMake sure that it is inserted.\nOr that SD reader is properly seated!");
}
else
{
int res = 0;
res = f_mount(&sd_fs, "sd:", 1);
if (res == FR_OK)
{
sd_mounted = 1;
return true;
}
else
{
EPRINTFARGS("Failed to mount SD card (FatFS Error %d).\nMake sure that a FAT partition exists..", res);
}
}
return false;
return false;
}
void sd_unmount()
{
if (sd_mounted)
{
f_mount(NULL, "sd:", 1);
sdmmc_storage_end(&sd_storage);
sd_mounted = false;
}
if (sd_mounted)
{
f_mount(NULL, "sd:", 1);
sdmmc_storage_end(&sd_storage);
sd_mounted = false;
}
}
void *sd_file_read(const char *path, u32 *fsize)
{
FIL fp;
if (f_open(&fp, path, FA_READ) != FR_OK)
return NULL;
FIL fp;
if (f_open(&fp, path, FA_READ) != FR_OK)
return NULL;
u32 size = f_size(&fp);
if (fsize)
*fsize = size;
u32 size = f_size(&fp);
if (fsize)
*fsize = size;
void *buf = malloc(size);
void *buf = malloc(size);
if (f_read(&fp, buf, size, NULL) != FR_OK)
{
free(buf);
f_close(&fp);
if (f_read(&fp, buf, size, NULL) != FR_OK)
{
free(buf);
f_close(&fp);
return NULL;
}
return NULL;
}
f_close(&fp);
f_close(&fp);
return buf;
return buf;
}
int sd_save_to_file(void *buf, u32 size, const char *filename)
{
FIL fp;
u32 res = 0;
res = f_open(&fp, filename, FA_CREATE_ALWAYS | FA_WRITE);
if (res)
{
EPRINTFARGS("Error (%d) creating file\n%s.\n", res, filename);
return res;
}
FIL fp;
u32 res = 0;
res = f_open(&fp, filename, FA_CREATE_ALWAYS | FA_WRITE);
if (res)
{
EPRINTFARGS("Error (%d) creating file\n%s.\n", res, filename);
return res;
}
f_write(&fp, buf, size, NULL);
f_close(&fp);
f_write(&fp, buf, size, NULL);
f_close(&fp);
return 0;
return 0;
}
// This is a safe and unused DRAM region for our payloads.
#define RELOC_META_OFF 0x7C
#define PATCHED_RELOC_SZ 0x94
#define RELOC_META_OFF 0x7C
#define PATCHED_RELOC_SZ 0x94
#define PATCHED_RELOC_STACK 0x40007000
#define COREBOOT_ADDR (0xD0000000 - 0x100000)
#define CBFS_DRAM_EN_ADDR 0x4003e000
#define CBFS_DRAM_MAGIC 0x4452414D // "DRAM"
#define PATCHED_RELOC_ENTRY 0x40010000
#define EXT_PAYLOAD_ADDR 0xC03C0000
#define RCM_PAYLOAD_ADDR (EXT_PAYLOAD_ADDR + ALIGN(PATCHED_RELOC_SZ, 0x10))
#define COREBOOT_ADDR (0xD0000000 - 0x100000)
#define CBFS_DRAM_EN_ADDR 0x4003e000
#define CBFS_DRAM_MAGIC 0x4452414D // "DRAM"
void reloc_patcher(u32 payload_dst, u32 payload_src, u32 payload_size)
{
memcpy((u8 *)payload_src, (u8 *)IPL_LOAD_ADDR, PATCHED_RELOC_SZ);
memcpy((u8 *)payload_src, (u8 *)IPL_LOAD_ADDR, PATCHED_RELOC_SZ);
volatile reloc_meta_t *relocator = (reloc_meta_t *)(payload_src + RELOC_META_OFF);
volatile reloc_meta_t *relocator = (reloc_meta_t *)(payload_src + RELOC_META_OFF);
relocator->start = payload_dst - ALIGN(PATCHED_RELOC_SZ, 0x10);
relocator->stack = PATCHED_RELOC_STACK;
relocator->end = payload_dst + payload_size;
relocator->ep = payload_dst;
relocator->start = payload_dst - ALIGN(PATCHED_RELOC_SZ, 0x10);
relocator->stack = PATCHED_RELOC_STACK;
relocator->end = payload_dst + payload_size;
relocator->ep = payload_dst;
if (payload_size == 0x7000)
{
memcpy((u8 *)(payload_src + ALIGN(PATCHED_RELOC_SZ, 0x10)), (u8 *)COREBOOT_ADDR, 0x7000); //Bootblock
*(vu32 *)CBFS_DRAM_EN_ADDR = CBFS_DRAM_MAGIC;
}
if (payload_size == 0x7000)
{
memcpy((u8 *)(payload_src + ALIGN(PATCHED_RELOC_SZ, 0x10)), (u8 *)COREBOOT_ADDR, 0x7000); //Bootblock
*(vu32 *)CBFS_DRAM_EN_ADDR = CBFS_DRAM_MAGIC;
}
}
int launch_payload(char *path)
{
gfx_clear_grey(0x1B);
gfx_con_setpos(0, 0);
if (!path)
return 1;
if (sd_mount())
{
FIL fp;
if (f_open(&fp, path, FA_READ))
{
EPRINTFARGS("Payload file is missing!\n(%s)", path);
sd_unmount();
return 1;
}
// Read and copy the payload to our chosen address
void *buf;
u32 size = f_size(&fp);
if (size < 0x30000)
buf = (void *)RCM_PAYLOAD_ADDR;
else
buf = (void *)COREBOOT_ADDR;
if (f_read(&fp, buf, size, NULL))
{
f_close(&fp);
sd_unmount();
return 1;
}
f_close(&fp);
sd_unmount();
if (size < 0x30000)
{
reloc_patcher(PATCHED_RELOC_ENTRY, EXT_PAYLOAD_ADDR, ALIGN(size, 0x10));
reconfig_hw_workaround(false, byte_swap_32(*(u32 *)(buf + size - sizeof(u32))));
}
else
{
reloc_patcher(PATCHED_RELOC_ENTRY, EXT_PAYLOAD_ADDR, 0x7000);
reconfig_hw_workaround(true, 0);
}
// Some cards (Sandisk U1), do not like a fast power cycle. Wait min 100ms.
sdmmc_storage_init_wait_sd();
void (*ext_payload_ptr)() = (void *)EXT_PAYLOAD_ADDR;
// Launch our payload.
(*ext_payload_ptr)();
}
return 1;
}
void launch_tools()
{
u8 max_entries = 61;
char *filelist = NULL;
char *file_sec = NULL;
char *dir = NULL;
ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * (max_entries + 3));
gfx_clear_grey(0x1B);
gfx_con_setpos(0, 0);
if (sd_mount())
{
dir = (char *)malloc(256);
memcpy(dir, "sd:/bootloader/payloads", 24);
filelist = dirlist(dir, NULL, false);
u32 i = 0;
u32 i_off = 2;
if (filelist)
{
// Build configuration menu.
u32 color_idx = 0;
ments[0].type = MENT_BACK;
ments[0].caption = "Back";
ments[0].color = colors[(color_idx++) % 6];
ments[1].type = MENT_CHGLINE;
ments[1].color = colors[(color_idx++) % 6];
if (!f_stat("sd:/atmosphere/reboot_payload.bin", NULL))
{
ments[i_off].type = INI_CHOICE;
ments[i_off].caption = "reboot_payload.bin";
ments[i_off].color = colors[(color_idx++) % 6];
ments[i_off].data = "sd:/atmosphere/reboot_payload.bin";
i_off++;
}
if (!f_stat("sd:/ReiNX.bin", NULL))
{
ments[i_off].type = INI_CHOICE;
ments[i_off].caption = "ReiNX.bin";
ments[i_off].color = colors[(color_idx++) % 6];
ments[i_off].data = "sd:/ReiNX.bin";
i_off++;
}
while (true)
{
if (i > max_entries || !filelist[i * 256])
break;
ments[i + i_off].type = INI_CHOICE;
ments[i + i_off].caption = &filelist[i * 256];
ments[i + i_off].color = colors[(color_idx++) % 6];
ments[i + i_off].data = &filelist[i * 256];
i++;
}
}
if (i > 0)
{
memset(&ments[i + i_off], 0, sizeof(ment_t));
menu_t menu = { ments, "Choose a file to launch", 0, 0 };
file_sec = (char *)tui_do_menu(&menu);
if (!file_sec)
{
free(ments);
free(dir);
free(filelist);
sd_unmount();
return;
}
}
else
EPRINTF("No payloads or modules found.");
free(ments);
free(filelist);
}
else
{
free(ments);
goto out;
}
if (file_sec)
{
if (memcmp("sd:/", file_sec, 4)) {
memcpy(dir + strlen(dir), "/", 2);
memcpy(dir + strlen(dir), file_sec, strlen(file_sec) + 1);
}
else
memcpy(dir, file_sec, strlen(file_sec) + 1);
if (launch_payload(dir))
{
EPRINTF("Failed to launch payload.");
free(dir);
}
}
out:
sd_unmount();
free(dir);
btn_wait();
}
void incognito_sysnand()
@ -274,6 +461,8 @@ ment_t ment_top[] = {
MDEF_HANDLER("Restore (emuMMC)", restore_emunand, COLOR_ORANGE),
MDEF_CAPTION("", COLOR_YELLOW),
MDEF_CAPTION("---------------", COLOR_YELLOW),
MDEF_HANDLER("Payloads...", launch_tools, COLOR_RED),
MDEF_CAPTION("---------------", COLOR_YELLOW),
MDEF_HANDLER("Reboot (Normal)", reboot_normal, COLOR_GREEN),
MDEF_HANDLER("Reboot (RCM)", reboot_rcm, COLOR_BLUE),
MDEF_HANDLER("Power off", power_off, COLOR_VIOLET),
@ -281,46 +470,52 @@ ment_t ment_top[] = {
menu_t menu_top = {ment_top, NULL, 0, 0};
#define IPL_STACK_TOP 0x4003F000
#define IPL_STACK_TOP 0x90010000
#define IPL_HEAP_START 0x90020000
extern void pivot_stack(u32 stack_top);
// todo: chainload to reboot payload or payloads folder option?
void ipl_main()
{
config_hw();
pivot_stack(IPL_STACK_TOP);
heap_init(IPL_HEAP_START);
config_hw();
pivot_stack(IPL_STACK_TOP);
heap_init(IPL_HEAP_START);
set_default_configuration();
set_default_configuration();
display_init();
u32 *fb = display_init_framebuffer();
gfx_init_ctxt(fb, 720, 1280, 720);
gfx_con_init();
display_backlight_pwm_init();
sd_mount();
minerva_init();
minerva_change_freq(FREQ_1600);
bpmp_clk_rate_set(BPMP_CLK_SUPER_BOOST);
display_init();
u32 *fb = display_init_framebuffer();
gfx_init_ctxt(fb, 720, 1280, 720);
gfx_con_init();
display_backlight_pwm_init();
h_cfg.emummc_force_disable = emummc_load_cfg();
bpmp_clk_rate_set(BPMP_CLK_DEFAULT_BOOST);
if (b_cfg.boot_cfg & BOOT_CFG_SEPT_RUN)
{
if (!(b_cfg.extra_cfg & EXTRA_CFG_DUMP_EMUMMC))
h_cfg.emummc_force_disable = true;
dump_keys();
}
h_cfg.emummc_force_disable = emummc_load_cfg();
if (h_cfg.emummc_force_disable)
{
ment_top[1].type = MENT_CAPTION;
ment_top[1].color = 0xFF555555;
ment_top[1].handler = NULL;
}
// if (b_cfg.boot_cfg & BOOT_CFG_SEPT_RUN)
// {
// if (!(b_cfg.extra_cfg & EXTRA_CFG_DUMP_EMUMMC))
// h_cfg.emummc_force_disable = true;
// dump_keys();
// }
while (true)
tui_do_menu(&menu_top);
if (h_cfg.emummc_force_disable)
{
ment_top[1].type = MENT_CAPTION;
ment_top[1].color = 0xFF555555;
ment_top[1].handler = NULL;
}
while (true)
bpmp_halt();
while (true)
tui_do_menu(&menu_top);
while (true)
bpmp_halt();
}

View file

@ -17,6 +17,7 @@
#include <string.h>
#include "heap.h"
#include "../gfx/gfx.h"
#include "../../common/common_heap.h"
static void _heap_create(heap_t *heap, u32 start)
@ -25,12 +26,13 @@ static void _heap_create(heap_t *heap, u32 start)
heap->first = NULL;
}
static u32 _heap_alloc(heap_t *heap, u32 size, u32 alignment)
// Node info is before node address.
static u32 _heap_alloc(heap_t *heap, u32 size)
{
hnode_t *node, *new;
int search = 1;
size = ALIGN(size, alignment);
// Align to cache line size.
size = ALIGN(size, sizeof(hnode_t));
if (!heap->first)
{
@ -45,27 +47,35 @@ static u32 _heap_alloc(heap_t *heap, u32 size, u32 alignment)
}
node = heap->first;
while (search)
while (true)
{
if (!node->used && size + sizeof(hnode_t) < node->size)
if (!node->used && (size <= node->size))
{
u32 new_size = node->size - size;
new = (hnode_t *)((u32)node + sizeof(hnode_t) + size);
new->size = node->size - sizeof(hnode_t) - size;
// If there's aligned leftover space, create a new node.
if (new_size >= (sizeof(hnode_t) << 2))
{
new->size = new_size - sizeof(hnode_t);
new->used = 0;
new->next = node->next;
new->next->prev = new;
new->prev = node;
node->next = new;
}
else
size += new_size;
node->size = size;
node->used = 1;
new->used = 0;
new->next = node->next;
new->next->prev = new;
new->prev = node;
node->next = new;
return (u32)node + sizeof(hnode_t);
}
if (node->next)
node = node->next;
else
search = 0;
break;
}
new = (hnode_t *)((u32)node + sizeof(hnode_t) + node->size);
@ -108,12 +118,12 @@ void heap_init(u32 base)
void *malloc(u32 size)
{
return (void *)_heap_alloc(&_heap, size, sizeof(hnode_t));
return (void *)_heap_alloc(&_heap, size);
}
void *calloc(u32 num, u32 size)
{
void *res = (void *)_heap_alloc(&_heap, num * size, sizeof(hnode_t));
void *res = (void *)_heap_alloc(&_heap, num * size);
memset(res, 0, num * size);
return res;
}
@ -123,3 +133,30 @@ void free(void *buf)
if ((u32)buf >= _heap.start)
_heap_free(&_heap, (u32)buf);
}
void heap_monitor(heap_monitor_t *mon, bool print_node_stats)
{
u32 count = 0;
memset(mon, 0, sizeof(heap_monitor_t));
hnode_t *node = _heap.first;
while (true)
{
if (node->used)
mon->used += node->size + sizeof(hnode_t);
else
mon->total += node->size + sizeof(hnode_t);
if (print_node_stats)
gfx_printf("%3d - %d, addr: 0x%08X, size: 0x%X\n",
count, node->used, (u32)node + sizeof(hnode_t), node->size);
count++;
if (node->next)
node = node->next;
else
break;
}
mon->total += mon->used;
}

View file

@ -18,10 +18,12 @@
#define _HEAP_H_
#include "../utils/types.h"
#include "../../common/common_heap.h"
void heap_init(u32 base);
void *malloc(u32 size);
void *calloc(u32 num, u32 size);
void free(void *buf);
void heap_monitor(heap_monitor_t *mon, bool print_node_stats);
#endif

106
source/mem/minerva.c Normal file
View file

@ -0,0 +1,106 @@
/*
* Copyright (c) 2019 CTCaer
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <string.h>
#include <stdlib.h>
#include "minerva.h"
#include "../soc/fuse.h"
#include "../utils/util.h"
#include "../soc/clock.h"
#include "../ianos/ianos.h"
#include "../soc/fuse.h"
#include "../soc/t210.h"
extern volatile nyx_storage_t *nyx_str;
u32 minerva_init()
{
u32 curr_ram_idx = 0;
minerva_cfg = NULL;
mtc_config_t *mtc_cfg = (mtc_config_t *)&nyx_str->mtc_cfg;
// Set table to nyx storage.
mtc_cfg->mtc_table = (emc_table_t *)&nyx_str->mtc_table;
mtc_cfg->sdram_id = (fuse_read_odm(4) >> 3) & 0x1F;
mtc_cfg->init_done = MTC_NEW_MAGIC; // Initialize mtc table.
u32 ep_addr = ianos_loader(false, "bootloader/sys/libsys_minerva.bso", DRAM_LIB, (void *)mtc_cfg);
// Ensure that Minerva is new.
if (mtc_cfg->init_done == MTC_INIT_MAGIC)
minerva_cfg = (void *)ep_addr;
if (!minerva_cfg)
return 1;
// Get current frequency
for (curr_ram_idx = 0; curr_ram_idx < 10; curr_ram_idx++)
{
if (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC) == mtc_cfg->mtc_table[curr_ram_idx].clk_src_emc)
break;
}
mtc_cfg->rate_from = mtc_cfg->mtc_table[curr_ram_idx].rate_khz;
mtc_cfg->rate_to = 204000;
mtc_cfg->train_mode = OP_TRAIN;
minerva_cfg(mtc_cfg, NULL);
mtc_cfg->rate_to = 800000;
minerva_cfg(mtc_cfg, NULL);
mtc_cfg->rate_to = 1600000;
minerva_cfg(mtc_cfg, NULL);
// FSP WAR.
mtc_cfg->train_mode = OP_SWITCH;
mtc_cfg->rate_to = 800000;
minerva_cfg(mtc_cfg, NULL);
// Switch to max.
mtc_cfg->rate_to = 1600000;
minerva_cfg(mtc_cfg, NULL);
return 0;
}
void minerva_change_freq(minerva_freq_t freq)
{
if (!minerva_cfg)
return;
mtc_config_t *mtc_cfg = (mtc_config_t *)&nyx_str->mtc_cfg;
if (mtc_cfg->rate_from != freq)
{
mtc_cfg->rate_to = freq;
mtc_cfg->train_mode = OP_SWITCH;
minerva_cfg(mtc_cfg, NULL);
}
}
void minerva_periodic_training()
{
if (!minerva_cfg)
return;
mtc_config_t *mtc_cfg = (mtc_config_t *)&nyx_str->mtc_cfg;
if (mtc_cfg->rate_from == FREQ_1600)
{
mtc_cfg->train_mode = OP_PERIODIC_TRAIN;
minerva_cfg(mtc_cfg, NULL);
}
}

65
source/mem/minerva.h Normal file
View file

@ -0,0 +1,65 @@
/*
* Copyright (c) 2019 CTCaer
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _FE_MINERVA_H_
#define _FE_MINERVA_H_
#include "mtc_table.h"
#include "../utils/types.h"
#define MTC_INIT_MAGIC 0x3043544D
#define MTC_NEW_MAGIC 0x5243544D
#define EMC_PERIODIC_TRAIN_MS 250
typedef struct
{
s32 rate_to;
s32 rate_from;
emc_table_t *mtc_table;
u32 table_entries;
emc_table_t *current_emc_table;
u32 train_mode;
u32 sdram_id;
u32 prev_temp;
bool emc_2X_clk_src_is_pllmb;
bool fsp_for_src_freq;
bool train_ram_patterns;
bool init_done;
} mtc_config_t;
enum train_mode_t
{
OP_SWITCH = 0,
OP_TRAIN = 1,
OP_TRAIN_SWITCH = 2,
OP_PERIODIC_TRAIN = 3,
OP_TEMP_COMP = 4
};
typedef enum
{
FREQ_204 = 204000,
FREQ_800 = 800000,
FREQ_1600 = 1600000
} minerva_freq_t;
void (*minerva_cfg)(mtc_config_t *mtc_cfg, void *);
u32 minerva_init();
void minerva_change_freq(minerva_freq_t freq);
void minerva_periodic_training();
#endif

560
source/mem/mtc_table.h Normal file
View file

@ -0,0 +1,560 @@
/*
* Minerva Training Cell
* DRAM Training for Tegra X1 SoC. Supports DDR2/3 and LPDDR3/4.
*
* Copyright (c) 2018 CTCaer <ctcaer@gmail.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _MTC_TABLE_H_
#define _MTC_TABLE_H_
#include "../utils/types.h"
typedef struct
{
s32 pll_osc_in;
s32 pll_out;
u32 pll_feedback_div;
u32 pll_input_div;
u32 pll_post_div;
} pllm_clk_config_t;
typedef struct
{
u32 emc_rc_idx;
u32 emc_rfc_idx;
u32 emc_rfcpb_idx;
u32 emc_refctrl2_idx;
u32 emc_rfc_slr_idx;
u32 emc_ras_idx;
u32 emc_rp_idx;
u32 emc_r2w_idx;
u32 emc_w2r_idx;
u32 emc_r2p_idx;
u32 emc_w2p_idx;
u32 emc_r2r_idx;
u32 emc_tppd_idx;
u32 emc_ccdmw_idx;
u32 emc_rd_rcd_idx;
u32 emc_wr_rcd_idx;
u32 emc_rrd_idx;
u32 emc_rext_idx;
u32 emc_wext_idx;
u32 emc_wdv_chk_idx;
u32 emc_wdv_idx;
u32 emc_wsv_idx;
u32 emc_wev_idx;
u32 emc_wdv_mask_idx;
u32 emc_ws_duration_idx;
u32 emc_we_duration_idx;
u32 emc_quse_idx;
u32 emc_quse_width_idx;
u32 emc_ibdly_idx;
u32 emc_obdly_idx;
u32 emc_einput_idx;
u32 emc_mrw6_idx;
u32 emc_einput_duration_idx;
u32 emc_puterm_extra_idx;
u32 emc_puterm_width_idx;
u32 emc_qrst_idx;
u32 emc_qsafe_idx;
u32 emc_rdv_idx;
u32 emc_rdv_mask_idx;
u32 emc_rdv_early_idx;
u32 emc_rdv_early_mask_idx;
u32 emc_refresh_idx;
u32 emc_burst_refresh_num_idx;
u32 emc_pre_refresh_req_cnt_idx;
u32 emc_pdex2wr_idx;
u32 emc_pdex2rd_idx;
u32 emc_pchg2pden_idx;
u32 emc_act2pden_idx;
u32 emc_ar2pden_idx;
u32 emc_rw2pden_idx;
u32 emc_cke2pden_idx;
u32 emc_pdex2cke_idx;
u32 emc_pdex2mrr_idx;
u32 emc_txsr_idx;
u32 emc_txsrdll_idx;
u32 emc_tcke_idx;
u32 emc_tckesr_idx;
u32 emc_tpd_idx;
u32 emc_tfaw_idx;
u32 emc_trpab_idx;
u32 emc_tclkstable_idx;
u32 emc_tclkstop_idx;
u32 emc_mrw7_idx;
u32 emc_trefbw_idx;
u32 emc_odt_write_idx;
u32 emc_fbio_cfg5_idx;
u32 emc_fbio_cfg7_idx;
u32 emc_cfg_dig_dll_idx;
u32 emc_cfg_dig_dll_period_idx;
u32 emc_pmacro_ib_rxrt_idx;
u32 emc_cfg_pipe_1_idx;
u32 emc_cfg_pipe_2_idx;
u32 emc_pmacro_quse_ddll_rank0_4_idx;
u32 emc_pmacro_quse_ddll_rank0_5_idx;
u32 emc_pmacro_quse_ddll_rank1_4_idx;
u32 emc_pmacro_quse_ddll_rank1_5_idx;
u32 emc_mrw8_idx;
u32 emc_pmacro_ob_ddll_long_dq_rank1_4_idx;
u32 emc_pmacro_ob_ddll_long_dq_rank1_5_idx;
u32 emc_pmacro_ob_ddll_long_dqs_rank0_0_idx;
u32 emc_pmacro_ob_ddll_long_dqs_rank0_1_idx;
u32 emc_pmacro_ob_ddll_long_dqs_rank0_2_idx;
u32 emc_pmacro_ob_ddll_long_dqs_rank0_3_idx;
u32 emc_pmacro_ob_ddll_long_dqs_rank0_4_idx;
u32 emc_pmacro_ob_ddll_long_dqs_rank0_5_idx;
u32 emc_pmacro_ob_ddll_long_dqs_rank1_0_idx;
u32 emc_pmacro_ob_ddll_long_dqs_rank1_1_idx;
u32 emc_pmacro_ob_ddll_long_dqs_rank1_2_idx;
u32 emc_pmacro_ob_ddll_long_dqs_rank1_3_idx;
u32 emc_pmacro_ob_ddll_long_dqs_rank1_4_idx;
u32 emc_pmacro_ob_ddll_long_dqs_rank1_5_idx;
u32 emc_pmacro_ddll_long_cmd_0_idx;
u32 emc_pmacro_ddll_long_cmd_1_idx;
u32 emc_pmacro_ddll_long_cmd_2_idx;
u32 emc_pmacro_ddll_long_cmd_3_idx;
u32 emc_pmacro_ddll_long_cmd_4_idx;
u32 emc_pmacro_ddll_short_cmd_0_idx;
u32 emc_pmacro_ddll_short_cmd_1_idx;
u32 emc_pmacro_ddll_short_cmd_2_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte0_3_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte1_3_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte2_3_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte3_3_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte4_3_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte5_3_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte6_3_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte7_3_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd0_3_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd1_3_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd2_3_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd3_3_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte0_3_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte1_3_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte2_3_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte3_3_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte4_3_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte5_3_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte6_3_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte7_3_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd0_0_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd0_1_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd0_2_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd0_3_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd1_0_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd1_1_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd1_2_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd1_3_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd2_0_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd2_1_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd2_2_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd2_3_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd3_0_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd3_1_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd3_2_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd3_3_idx;
u32 emc_txdsrvttgen_idx;
u32 emc_fdpd_ctrl_dq_idx;
u32 emc_fdpd_ctrl_cmd_idx;
u32 emc_fbio_spare_idx;
u32 emc_zcal_interval_idx;
u32 emc_zcal_wait_cnt_idx;
u32 emc_mrs_wait_cnt_idx;
u32 emc_mrs_wait_cnt2_idx;
u32 emc_auto_cal_channel_idx;
u32 emc_dll_cfg_0_idx;
u32 emc_dll_cfg_1_idx;
u32 emc_pmacro_autocal_cfg_common_idx;
u32 emc_pmacro_zctrl_idx;
u32 emc_cfg_idx;
u32 emc_cfg_pipe_idx;
u32 emc_dyn_self_ref_control_idx;
u32 emc_qpop_idx;
u32 emc_dqs_brlshft_0_idx;
u32 emc_dqs_brlshft_1_idx;
u32 emc_cmd_brlshft_2_idx;
u32 emc_cmd_brlshft_3_idx;
u32 emc_pmacro_pad_cfg_ctrl_idx;
u32 emc_pmacro_data_pad_rx_ctrl_idx;
u32 emc_pmacro_cmd_pad_rx_ctrl_idx;
u32 emc_pmacro_data_rx_term_mode_idx;
u32 emc_pmacro_cmd_rx_term_mode_idx;
u32 emc_pmacro_cmd_pad_tx_ctrl_idx;
u32 emc_pmacro_data_pad_tx_ctrl_idx;
u32 emc_pmacro_common_pad_tx_ctrl_idx;
u32 emc_pmacro_vttgen_ctrl_0_idx;
u32 emc_pmacro_vttgen_ctrl_1_idx;
u32 emc_pmacro_vttgen_ctrl_2_idx;
u32 emc_pmacro_brick_ctrl_rfu1_idx;
u32 emc_pmacro_cmd_brick_ctrl_fdpd_idx;
u32 emc_pmacro_brick_ctrl_rfu2_idx;
u32 emc_pmacro_data_brick_ctrl_fdpd_idx;
u32 emc_pmacro_bg_bias_ctrl_0_idx;
u32 emc_cfg_3_idx;
u32 emc_pmacro_tx_pwrd_0_idx;
u32 emc_pmacro_tx_pwrd_1_idx;
u32 emc_pmacro_tx_pwrd_2_idx;
u32 emc_pmacro_tx_pwrd_3_idx;
u32 emc_pmacro_tx_pwrd_4_idx;
u32 emc_pmacro_tx_pwrd_5_idx;
u32 emc_config_sample_delay_idx;
u32 emc_pmacro_tx_sel_clk_src_0_idx;
u32 emc_pmacro_tx_sel_clk_src_1_idx;
u32 emc_pmacro_tx_sel_clk_src_2_idx;
u32 emc_pmacro_tx_sel_clk_src_3_idx;
u32 emc_pmacro_tx_sel_clk_src_4_idx;
u32 emc_pmacro_tx_sel_clk_src_5_idx;
u32 emc_pmacro_ddll_bypass_idx;
u32 emc_pmacro_ddll_pwrd_0_idx;
u32 emc_pmacro_ddll_pwrd_1_idx;
u32 emc_pmacro_ddll_pwrd_2_idx;
u32 emc_pmacro_cmd_ctrl_0_idx;
u32 emc_pmacro_cmd_ctrl_1_idx;
u32 emc_pmacro_cmd_ctrl_2_idx;
u32 emc_tr_timing_0_idx;
u32 emc_tr_dvfs_idx;
u32 emc_tr_ctrl_1_idx;
u32 emc_tr_rdv_idx;
u32 emc_tr_qpop_idx;
u32 emc_tr_rdv_mask_idx;
u32 emc_mrw14_idx;
u32 emc_tr_qsafe_idx;
u32 emc_tr_qrst_idx;
u32 emc_training_ctrl_idx;
u32 emc_training_settle_idx;
u32 emc_training_vref_settle_idx;
u32 emc_training_ca_fine_ctrl_idx;
u32 emc_training_ca_ctrl_misc_idx;
u32 emc_training_ca_ctrl_misc1_idx;
u32 emc_training_ca_vref_ctrl_idx;
u32 emc_training_quse_cors_ctrl_idx;
u32 emc_training_quse_fine_ctrl_idx;
u32 emc_training_quse_ctrl_misc_idx;
u32 emc_training_quse_vref_ctrl_idx;
u32 emc_training_read_fine_ctrl_idx;
u32 emc_training_read_ctrl_misc_idx;
u32 emc_training_read_vref_ctrl_idx;
u32 emc_training_write_fine_ctrl_idx;
u32 emc_training_write_ctrl_misc_idx;
u32 emc_training_write_vref_ctrl_idx;
u32 emc_training_mpc_idx;
u32 emc_mrw15_idx;
} burst_regs_t;
typedef struct
{
u32 burst_regs[221];
u32 burst_reg_per_ch[8];
u32 shadow_regs_ca_train[221];
u32 shadow_regs_quse_train[221];
u32 shadow_regs_rdwr_train[221];
} burst_regs_table_t;
typedef struct
{
u32 ptfv_dqsosc_movavg_c0d0u0_idx;
u32 ptfv_dqsosc_movavg_c0d0u1_idx;
u32 ptfv_dqsosc_movavg_c0d1u0_idx;
u32 ptfv_dqsosc_movavg_c0d1u1_idx;
u32 ptfv_dqsosc_movavg_c1d0u0_idx;
u32 ptfv_dqsosc_movavg_c1d0u1_idx;
u32 ptfv_dqsosc_movavg_c1d1u0_idx;
u32 ptfv_dqsosc_movavg_c1d1u1_idx;
u32 ptfv_write_samples_idx;
u32 ptfv_dvfs_samples_idx;
u32 ptfv_movavg_weight_idx;
u32 ptfv_config_ctrl_idx;
} ptfv_list_table_t;
typedef struct
{
u32 emc0_mrw10_idx;
u32 emc1_mrw10_idx;
u32 emc0_mrw11_idx;
u32 emc1_mrw11_idx;
u32 emc0_mrw12_idx;
u32 emc1_mrw12_idx;
u32 emc0_mrw13_idx;
u32 emc1_mrw13_idx;
} burst_reg_per_ch_t;
typedef struct
{
u32 emc_pmacro_ib_ddll_long_dqs_rank0_0_idx;
u32 emc_pmacro_ib_ddll_long_dqs_rank0_1_idx;
u32 emc_pmacro_ib_ddll_long_dqs_rank0_2_idx;
u32 emc_pmacro_ib_ddll_long_dqs_rank0_3_idx;
u32 emc_pmacro_ib_ddll_long_dqs_rank1_0_idx;
u32 emc_pmacro_ib_ddll_long_dqs_rank1_1_idx;
u32 emc_pmacro_ib_ddll_long_dqs_rank1_2_idx;
u32 emc_pmacro_ib_ddll_long_dqs_rank1_3_idx;
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte0_0_idx;
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte0_1_idx;
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte0_2_idx;
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte1_0_idx;
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte1_1_idx;
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte1_2_idx;
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte2_0_idx;
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte2_1_idx;
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte2_2_idx;
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte3_0_idx;
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte3_1_idx;
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte3_2_idx;
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte4_0_idx;
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte4_1_idx;
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte4_2_idx;
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte5_0_idx;
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte5_1_idx;
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte5_2_idx;
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte6_0_idx;
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte6_1_idx;
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte6_2_idx;
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte7_0_idx;
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte7_1_idx;
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte7_2_idx;
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte0_0_idx;
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte0_1_idx;
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte0_2_idx;
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte1_0_idx;
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte1_1_idx;
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte1_2_idx;
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte2_0_idx;
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte2_1_idx;
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte2_2_idx;
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte3_0_idx;
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte3_1_idx;
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte3_2_idx;
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte4_0_idx;
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte4_1_idx;
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte4_2_idx;
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte5_0_idx;
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte5_1_idx;
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte5_2_idx;
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte6_0_idx;
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte6_1_idx;
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte6_2_idx;
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte7_0_idx;
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte7_1_idx;
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte7_2_idx;
u32 emc_pmacro_ib_vref_dqs_0_idx;
u32 emc_pmacro_ib_vref_dqs_1_idx;
u32 emc_pmacro_ib_vref_dq_0_idx;
u32 emc_pmacro_ib_vref_dq_1_idx;
u32 emc_pmacro_ob_ddll_long_dq_rank0_0_idx;
u32 emc_pmacro_ob_ddll_long_dq_rank0_1_idx;
u32 emc_pmacro_ob_ddll_long_dq_rank0_2_idx;
u32 emc_pmacro_ob_ddll_long_dq_rank0_3_idx;
u32 emc_pmacro_ob_ddll_long_dq_rank0_4_idx;
u32 emc_pmacro_ob_ddll_long_dq_rank0_5_idx;
u32 emc_pmacro_ob_ddll_long_dq_rank1_0_idx;
u32 emc_pmacro_ob_ddll_long_dq_rank1_1_idx;
u32 emc_pmacro_ob_ddll_long_dq_rank1_2_idx;
u32 emc_pmacro_ob_ddll_long_dq_rank1_3_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte0_0_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte0_1_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte0_2_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte1_0_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte1_1_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte1_2_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte2_0_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte2_1_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte2_2_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte3_0_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte3_1_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte3_2_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte4_0_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte4_1_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte4_2_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte5_0_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte5_1_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte5_2_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte6_0_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte6_1_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte6_2_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte7_0_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte7_1_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte7_2_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd0_0_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd0_1_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd0_2_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd1_0_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd1_1_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd1_2_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd2_0_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd2_1_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd2_2_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd3_0_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd3_1_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd3_2_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte0_0_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte0_1_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte0_2_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte1_0_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte1_1_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte1_2_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte2_0_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte2_1_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte2_2_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte3_0_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte3_1_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte3_2_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte4_0_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte4_1_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte4_2_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte5_0_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte5_1_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte5_2_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte6_0_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte6_1_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte6_2_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte7_0_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte7_1_idx;
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte7_2_idx;
u32 emc_pmacro_quse_ddll_rank0_0_idx;
u32 emc_pmacro_quse_ddll_rank0_1_idx;
u32 emc_pmacro_quse_ddll_rank0_2_idx;
u32 emc_pmacro_quse_ddll_rank0_3_idx;
u32 emc_pmacro_quse_ddll_rank1_0_idx;
u32 emc_pmacro_quse_ddll_rank1_1_idx;
u32 emc_pmacro_quse_ddll_rank1_2_idx;
u32 emc_pmacro_quse_ddll_rank1_3_idx;
} trim_regs_t;
typedef struct
{
u32 emc_cmd_brlshft_0_idx;
u32 emc_cmd_brlshft_1_idx;
u32 emc0_data_brlshft_0_idx;
u32 emc1_data_brlshft_0_idx;
u32 emc0_data_brlshft_1_idx;
u32 emc1_data_brlshft_1_idx;
u32 emc_quse_brlshft_0_idx;
u32 emc_quse_brlshft_1_idx;
u32 emc_quse_brlshft_2_idx;
u32 emc_quse_brlshft_3_idx;
} trim_perch_regs_t;
typedef struct
{
u32 t_rp;
u32 t_fc_lpddr4;
u32 t_rfc;
u32 t_pdex;
u32 rl;
} dram_timings_t;
typedef struct
{
u32 emc0_training_opt_dqs_ib_vref_rank0_idx;
u32 emc1_training_opt_dqs_ib_vref_rank0_idx;
u32 emc0_training_opt_dqs_ib_vref_rank1_idx;
u32 emc1_training_opt_dqs_ib_vref_rank1_idx;
} vref_perch_regs_t;
typedef struct
{
u32 trim_regs[138];
u32 trim_perch_regs[10];
u32 vref_perch_regs[4];
} trim_regs_table_t;
typedef struct
{
u32 rev;
char dvfs_ver[60];
u32 rate_khz;
u32 min_volt;
u32 gpu_min_volt;
char clock_src[32];
u32 clk_src_emc;
u32 needs_training;
u32 training_pattern;
u32 trained;
u32 periodic_training;
u32 trained_dram_clktree_c0d0u0;
u32 trained_dram_clktree_c0d0u1;
u32 trained_dram_clktree_c0d1u0;
u32 trained_dram_clktree_c0d1u1;
u32 trained_dram_clktree_c1d0u0;
u32 trained_dram_clktree_c1d0u1;
u32 trained_dram_clktree_c1d1u0;
u32 trained_dram_clktree_c1d1u1;
u32 current_dram_clktree_c0d0u0;
u32 current_dram_clktree_c0d0u1;
u32 current_dram_clktree_c0d1u0;
u32 current_dram_clktree_c0d1u1;
u32 current_dram_clktree_c1d0u0;
u32 current_dram_clktree_c1d0u1;
u32 current_dram_clktree_c1d1u0;
u32 current_dram_clktree_c1d1u1;
u32 run_clocks;
u32 tree_margin;
u32 num_burst;
u32 num_burst_per_ch;
u32 num_trim;
u32 num_trim_per_ch;
u32 num_mc_regs;
u32 num_up_down;
u32 vref_num;
u32 training_mod_num;
u32 dram_timing_num;
ptfv_list_table_t ptfv_list;
burst_regs_t burst_regs;
burst_reg_per_ch_t burst_reg_per_ch;
burst_regs_t shadow_regs_ca_train;
burst_regs_t shadow_regs_quse_train;
burst_regs_t shadow_regs_rdwr_train;
trim_regs_t trim_regs;
trim_perch_regs_t trim_perch_regs;
vref_perch_regs_t vref_perch_regs;
dram_timings_t dram_timings;
u32 training_mod_regs[20];
u32 save_restore_mod_regs[12];
u32 burst_mc_regs[33];
u32 la_scale_regs[24];
u32 min_mrs_wait;
u32 emc_mrw;
u32 emc_mrw2;
u32 emc_mrw3;
u32 emc_mrw4;
u32 emc_mrw9;
u32 emc_mrs;
u32 emc_emrs;
u32 emc_emrs2;
u32 emc_auto_cal_config;
u32 emc_auto_cal_config2;
u32 emc_auto_cal_config3;
u32 emc_auto_cal_config4;
u32 emc_auto_cal_config5;
u32 emc_auto_cal_config6;
u32 emc_auto_cal_config7;
u32 emc_auto_cal_config8;
u32 emc_cfg_2;
u32 emc_sel_dpd_ctrl;
u32 emc_fdpd_ctrl_cmd_no_ramp;
u32 dll_clk_src;
u32 clk_out_enb_x_0_clk_enb_emc_dll;
u32 latency;
} emc_table_t;
#endif

View file

@ -16,17 +16,18 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "../soc/i2c.h"
#include "../soc/t210.h"
#include "mc.h"
#include "emc.h"
#include "sdram_param_t210.h"
#include "../soc/pmc.h"
#include "../utils/util.h"
#include "../soc/fuse.h"
#include "../../common/memory_map.h"
#include "../power/max77620.h"
#include "../power/max7762x.h"
#include "../soc/clock.h"
#include "../soc/fuse.h"
#include "../soc/i2c.h"
#include "../soc/pmc.h"
#include "../soc/t210.h"
#include "../utils/util.h"
#define CONFIG_SDRAM_COMPRESS_CFG
@ -50,19 +51,31 @@ static u32 _get_sdram_id()
static void _sdram_config(const sdram_params_t *params)
{
PMC(APBDEV_PMC_IO_DPD3_REQ) = (((4 * params->emc_pmc_scratch1 >> 2) + 0x80000000) ^ 0xFFFF) & 0xC000FFFF;
// Program DPD3/DPD4 regs (coldboot path).
// Enable sel_dpd on unused pins.
u32 dpd_req = (params->emc_pmc_scratch1 & 0x3FFFFFFF) | 0x80000000;
PMC(APBDEV_PMC_IO_DPD3_REQ) = (dpd_req ^ 0xFFFF) & 0xC000FFFF;
usleep(params->pmc_io_dpd3_req_wait);
u32 req = (4 * params->emc_pmc_scratch2 >> 2) + 0x80000000;
PMC(APBDEV_PMC_IO_DPD4_REQ) = (req >> 16 << 16) ^ 0x3FFF0000;
// Disable e_dpd_vttgen.
dpd_req = (params->emc_pmc_scratch2 & 0x3FFFFFFF) | 0x80000000;
PMC(APBDEV_PMC_IO_DPD4_REQ) = (dpd_req & 0xFFFF0000) ^ 0x3FFF0000;
usleep(params->pmc_io_dpd4_req_wait);
PMC(APBDEV_PMC_IO_DPD4_REQ) = (req ^ 0xFFFF) & 0xC000FFFF;
// Disable e_dpd_bg.
PMC(APBDEV_PMC_IO_DPD4_REQ) = (dpd_req ^ 0xFFFF) & 0xC000FFFF;
usleep(params->pmc_io_dpd4_req_wait);
PMC(APBDEV_PMC_WEAK_BIAS) = 0;
usleep(1);
// Start clocks.
CLOCK(CLK_RST_CONTROLLER_PLLM_MISC1) = params->pllm_setup_control;
CLOCK(CLK_RST_CONTROLLER_PLLM_MISC2) = 0;
// u32 tmp = (params->pllm_feedback_divider << 8) | params->pllm_input_divider | ((params->pllm_post_divider & 0xFFFF) << 20);
// CLOCK(CLK_RST_CONTROLLER_PLLM_BASE) = tmp;
// CLOCK(CLK_RST_CONTROLLER_PLLM_BASE) = tmp | 0x40000000;
CLOCK(CLK_RST_CONTROLLER_PLLM_BASE) = (params->pllm_feedback_divider << 8) | params->pllm_input_divider | 0x40000000 | ((params->pllm_post_divider & 0xFFFF) << 20);
u32 wait_end = get_tmr_us() + 300;
@ -72,24 +85,35 @@ static void _sdram_config(const sdram_params_t *params)
goto break_nosleep;
}
usleep(10);
break_nosleep:
break_nosleep:
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC) = ((params->mc_emem_arb_misc0 >> 11) & 0x10000) | (params->emc_clock_source & 0xFFFEFFFF);
if (params->emc_clock_source_dll)
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC_DLL) = params->emc_clock_source_dll;
if (params->clear_clock2_mc1)
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_W_CLR) = 0x40000000;
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) = 0x2000001;
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_X_SET) = 0x4000;
CLOCK(CLK_RST_CONTROLLER_RST_DEV_H_CLR) = 0x2000001;
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) = 0x2000001; // Enable EMC and MEM clocks.
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_X_SET) = 0x4000; // Enable EMC_DLL clock.
CLOCK(CLK_RST_CONTROLLER_RST_DEV_H_CLR) = 0x2000001; // Clear EMC and MEM resets.
// Set pad macros.
EMC(EMC_PMACRO_VTTGEN_CTRL_0) = params->emc_pmacro_vttgen_ctrl0;
EMC(EMC_PMACRO_VTTGEN_CTRL_1) = params->emc_pmacro_vttgen_ctrl1;
EMC(EMC_PMACRO_VTTGEN_CTRL_2) = params->emc_pmacro_vttgen_ctrl2;
EMC(EMC_TIMING_CONTROL) = 1;
usleep(1);
EMC(EMC_TIMING_CONTROL) = 1; // Trigger timing update so above writes take place.
usleep(10); // Ensure the regulators settle.
// Select EMC write mux.
EMC(EMC_DBG) = (params->emc_dbg_write_mux << 1) | params->emc_dbg;
// Patch 2 using BCT spare variables.
if (params->emc_bct_spare2)
*(vu32 *)params->emc_bct_spare2 = params->emc_bct_spare3;
// Program CMD mapping. Required before brick mapping, else
// we can't guarantee CK will be differential at all times.
EMC(EMC_FBIO_CFG7) = params->emc_fbio_cfg7;
EMC(EMC_CMD_MAPPING_CMD0_0) = params->emc_cmd_mapping_cmd0_0;
EMC(EMC_CMD_MAPPING_CMD0_1) = params->emc_cmd_mapping_cmd0_1;
@ -104,25 +128,40 @@ break_nosleep:
EMC(EMC_CMD_MAPPING_CMD3_1) = params->emc_cmd_mapping_cmd3_1;
EMC(EMC_CMD_MAPPING_CMD3_2) = params->emc_cmd_mapping_cmd3_2;
EMC(EMC_CMD_MAPPING_BYTE) = params->emc_cmd_mapping_byte;
// Program brick mapping.
EMC(EMC_PMACRO_BRICK_MAPPING_0) = params->emc_pmacro_brick_mapping0;
EMC(EMC_PMACRO_BRICK_MAPPING_1) = params->emc_pmacro_brick_mapping1;
EMC(EMC_PMACRO_BRICK_MAPPING_2) = params->emc_pmacro_brick_mapping2;
EMC(EMC_PMACRO_BRICK_CTRL_RFU1) = (params->emc_pmacro_brick_ctrl_rfu1 & 0x1120112) | 0x1EED1EED;
// This is required to do any reads from the pad macros.
EMC(EMC_CONFIG_SAMPLE_DELAY) = params->emc_config_sample_delay;
EMC(EMC_FBIO_CFG8) = params->emc_fbio_cfg8;
// Set swizzle for Rank 0.
EMC(EMC_SWIZZLE_RANK0_BYTE0) = params->emc_swizzle_rank0_byte0;
EMC(EMC_SWIZZLE_RANK0_BYTE1) = params->emc_swizzle_rank0_byte1;
EMC(EMC_SWIZZLE_RANK0_BYTE2) = params->emc_swizzle_rank0_byte2;
EMC(EMC_SWIZZLE_RANK0_BYTE3) = params->emc_swizzle_rank0_byte3;
// Set swizzle for Rank 1.
EMC(EMC_SWIZZLE_RANK1_BYTE0) = params->emc_swizzle_rank1_byte0;
EMC(EMC_SWIZZLE_RANK1_BYTE1) = params->emc_swizzle_rank1_byte1;
EMC(EMC_SWIZZLE_RANK1_BYTE2) = params->emc_swizzle_rank1_byte2;
EMC(EMC_SWIZZLE_RANK1_BYTE3) = params->emc_swizzle_rank1_byte3;
// Patch 4 using BCT spare variables.
if (params->emc_bct_spare6)
*(vu32 *)params->emc_bct_spare6 = params->emc_bct_spare7;
// Set pad controls.
EMC(EMC_XM2COMPPADCTRL) = params->emc_xm2_comp_pad_ctrl;
EMC(EMC_XM2COMPPADCTRL2) = params->emc_xm2_comp_pad_ctrl2;
EMC(EMC_XM2COMPPADCTRL3) = params->emc_xm2_comp_pad_ctrl3;
// Program Autocal controls with shadowed register fields.
EMC(EMC_AUTO_CAL_CONFIG2) = params->emc_auto_cal_config2;
EMC(EMC_AUTO_CAL_CONFIG3) = params->emc_auto_cal_config3;
EMC(EMC_AUTO_CAL_CONFIG4) = params->emc_auto_cal_config4;
@ -130,6 +169,7 @@ break_nosleep:
EMC(EMC_AUTO_CAL_CONFIG6) = params->emc_auto_cal_config6;
EMC(EMC_AUTO_CAL_CONFIG7) = params->emc_auto_cal_config7;
EMC(EMC_AUTO_CAL_CONFIG8) = params->emc_auto_cal_config8;
EMC(EMC_PMACRO_RX_TERM) = params->emc_pmacro_rx_term;
EMC(EMC_PMACRO_DQ_TX_DRV) = params->emc_pmacro_dq_tx_drive;
EMC(EMC_PMACRO_CA_TX_DRV) = params->emc_pmacro_ca_tx_drive;
@ -137,9 +177,11 @@ break_nosleep:
EMC(EMC_PMACRO_AUTOCAL_CFG_COMMON) = params->emc_pmacro_auto_cal_common;
EMC(EMC_AUTO_CAL_CHANNEL) = params->emc_auto_cal_channel;
EMC(EMC_PMACRO_ZCTRL) = params->emc_pmacro_zcrtl;
EMC(EMC_DLL_CFG_0) = params->emc_dll_cfg0;
EMC(EMC_DLL_CFG_1) = params->emc_dll_cfg1;
EMC(EMC_CFG_DIG_DLL_1) = params->emc_cfg_dig_dll_1;
EMC(EMC_DATA_BRLSHFT_0) = params->emc_data_brlshft0;
EMC(EMC_DATA_BRLSHFT_1) = params->emc_data_brlshft1;
EMC(EMC_DQS_BRLSHFT_0) = params->emc_dqs_brlshft0;
@ -152,8 +194,10 @@ break_nosleep:
EMC(EMC_QUSE_BRLSHFT_1) = params->emc_quse_brlshft1;
EMC(EMC_QUSE_BRLSHFT_2) = params->emc_quse_brlshft2;
EMC(EMC_QUSE_BRLSHFT_3) = params->emc_quse_brlshft3;
EMC(EMC_PMACRO_BRICK_CTRL_RFU1) = (params->emc_pmacro_brick_ctrl_rfu1 & 0x1BF01BF) | 0x1E401E40;
EMC(EMC_PMACRO_PAD_CFG_CTRL) = params->emc_pmacro_pad_cfg_ctrl;
EMC(EMC_PMACRO_CMD_BRICK_CTRL_FDPD) = params->emc_pmacro_cmd_brick_ctrl_fdpd;
EMC(EMC_PMACRO_BRICK_CTRL_RFU2) = params->emc_pmacro_brick_ctrl_rfu2 & 0xFF7FFF7F;
EMC(EMC_PMACRO_DATA_BRICK_CTRL_FDPD) = params->emc_pmacro_data_brick_ctrl_fdpd;
@ -164,6 +208,7 @@ break_nosleep:
EMC(EMC_PMACRO_DATA_RX_TERM_MODE) = params->emc_pmacro_data_rx_term_mode;
EMC(EMC_PMACRO_CMD_RX_TERM_MODE) = params->emc_pmacro_cmd_rx_term_mode;
EMC(EMC_PMACRO_CMD_PAD_TX_CTRL) = params->emc_pmacro_cmd_pad_tx_ctrl;
EMC(EMC_CFG_3) = params->emc_cfg3;
EMC(EMC_PMACRO_TX_PWRD_0) = params->emc_pmacro_tx_pwrd0;
EMC(EMC_PMACRO_TX_PWRD_1) = params->emc_pmacro_tx_pwrd1;
@ -189,6 +234,7 @@ break_nosleep:
EMC(EMC_PMACRO_IB_VREF_DQS_0) = params->emc_pmacro_ib_vref_dqs_0;
EMC(EMC_PMACRO_IB_VREF_DQS_1) = params->emc_pmacro_ib_vref_dqs_1;
EMC(EMC_PMACRO_IB_RXRT) = params->emc_pmacro_ib_rxrt;
EMC(EMC_PMACRO_QUSE_DDLL_RANK0_0) = params->emc_pmacro_quse_ddll_rank0_0;
EMC(EMC_PMACRO_QUSE_DDLL_RANK0_1) = params->emc_pmacro_quse_ddll_rank0_1;
EMC(EMC_PMACRO_QUSE_DDLL_RANK0_2) = params->emc_pmacro_quse_ddll_rank0_2;
@ -202,6 +248,7 @@ break_nosleep:
EMC(EMC_PMACRO_QUSE_DDLL_RANK1_4) = params->emc_pmacro_quse_ddll_rank1_4;
EMC(EMC_PMACRO_QUSE_DDLL_RANK1_5) = params->emc_pmacro_quse_ddll_rank1_5;
EMC(EMC_PMACRO_BRICK_CTRL_RFU1) = params->emc_pmacro_brick_ctrl_rfu1;
EMC(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_0) = params->emc_pmacro_ob_ddll_long_dq_rank0_0;
EMC(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_1) = params->emc_pmacro_ob_ddll_long_dq_rank0_1;
EMC(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_2) = params->emc_pmacro_ob_ddll_long_dq_rank0_2;
@ -214,6 +261,7 @@ break_nosleep:
EMC(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_3) = params->emc_pmacro_ob_ddll_long_dq_rank1_3;
EMC(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_4) = params->emc_pmacro_ob_ddll_long_dq_rank1_4;
EMC(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_5) = params->emc_pmacro_ob_ddll_long_dq_rank1_5;
EMC(EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_0) = params->emc_pmacro_ob_ddll_long_dqs_rank0_0;
EMC(EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_1) = params->emc_pmacro_ob_ddll_long_dqs_rank0_1;
EMC(EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_2) = params->emc_pmacro_ob_ddll_long_dqs_rank0_2;
@ -234,6 +282,7 @@ break_nosleep:
EMC(EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_1) = params->emc_pmacro_ib_ddll_long_dqs_rank1_1;
EMC(EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_2) = params->emc_pmacro_ib_ddll_long_dqs_rank1_2;
EMC(EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_3) = params->emc_pmacro_ib_ddll_long_dqs_rank1_3;
EMC(EMC_PMACRO_DDLL_LONG_CMD_0) = params->emc_pmacro_ddll_long_cmd_0;
EMC(EMC_PMACRO_DDLL_LONG_CMD_1) = params->emc_pmacro_ddll_long_cmd_1;
EMC(EMC_PMACRO_DDLL_LONG_CMD_2) = params->emc_pmacro_ddll_long_cmd_2;
@ -242,10 +291,17 @@ break_nosleep:
EMC(EMC_PMACRO_DDLL_SHORT_CMD_0) = params->emc_pmacro_ddll_short_cmd_0;
EMC(EMC_PMACRO_DDLL_SHORT_CMD_1) = params->emc_pmacro_ddll_short_cmd_1;
EMC(EMC_PMACRO_DDLL_SHORT_CMD_2) = params->emc_pmacro_ddll_short_cmd_2;
// Common pad macro (cpm).
EMC(EMC_PMACRO_COMMON_PAD_TX_CTRL) = (params->emc_pmacro_common_pad_tx_ctrl & 1) | 0xE;
// Patch 3 using BCT spare variables.
if (params->emc_bct_spare4)
*(vu32 *)params->emc_bct_spare4 = params->emc_bct_spare5;
EMC(EMC_TIMING_CONTROL) = 1;
EMC(EMC_TIMING_CONTROL) = 1; // Trigger timing update so above writes take place.
// Initialize MC VPR settings.
MC(MC_VIDEO_PROTECT_BOM) = params->mc_video_protect_bom;
MC(MC_VIDEO_PROTECT_BOM_ADR_HI) = params->mc_video_protect_bom_adr_hi;
MC(MC_VIDEO_PROTECT_SIZE_MB) = params->mc_video_protect_size_mb;
@ -253,20 +309,32 @@ break_nosleep:
MC(MC_VIDEO_PROTECT_VPR_OVERRIDE1) = params->mc_video_protect_vpr_override1;
MC(MC_VIDEO_PROTECT_GPU_OVERRIDE_0) = params->mc_video_protect_gpu_override0;
MC(MC_VIDEO_PROTECT_GPU_OVERRIDE_1) = params->mc_video_protect_gpu_override1;
// Program SDRAM geometry parameters.
MC(MC_EMEM_ADR_CFG) = params->mc_emem_adr_cfg;
MC(MC_EMEM_ADR_CFG_DEV0) = params->mc_emem_adr_cfg_dev0;
MC(MC_EMEM_ADR_CFG_DEV1) = params->mc_emem_adr_cfg_dev1;
MC(MC_EMEM_ADR_CFG_CHANNEL_MASK) = params->mc_emem_adr_cfg_channel_mask;
// Program bank swizzling.
MC(MC_EMEM_ADR_CFG_BANK_MASK_0) = params->mc_emem_adr_cfg_bank_mask0;
MC(MC_EMEM_ADR_CFG_BANK_MASK_1) = params->mc_emem_adr_cfg_bank_mask1;
MC(MC_EMEM_ADR_CFG_BANK_MASK_2) = params->mc_emem_adr_cfg_bank_mask2;
// Program external memory aperture (base and size).
MC(MC_EMEM_CFG) = params->mc_emem_cfg;
// Program SEC carveout (base and size).
MC(MC_SEC_CARVEOUT_BOM) = params->mc_sec_carveout_bom;
MC(MC_SEC_CARVEOUT_ADR_HI) = params->mc_sec_carveout_adr_hi;
MC(MC_SEC_CARVEOUT_SIZE_MB) = params->mc_sec_carveout_size_mb;
// Program MTS carveout (base and size).
MC(MC_MTS_CARVEOUT_BOM) = params->mc_mts_carveout_bom;
MC(MC_MTS_CARVEOUT_ADR_HI) = params->mc_mts_carveout_adr_hi;
MC(MC_MTS_CARVEOUT_SIZE_MB) = params->mc_mts_carveout_size_mb;
// Program the memory arbiter.
MC(MC_EMEM_ARB_CFG) = params->mc_emem_arb_cfg;
MC(MC_EMEM_ARB_OUTSTANDING_REQ) = params->mc_emem_arb_outstanding_req;
MC(MC_EMEM_ARB_REFPB_HP_CTRL) = params->emc_emem_arb_refpb_hp_ctrl;
@ -295,21 +363,38 @@ break_nosleep:
MC(MC_EMEM_ARB_OVERRIDE_1) = params->mc_emem_arb_override1;
MC(MC_EMEM_ARB_RSV) = params->mc_emem_arb_rsv;
MC(MC_DA_CONFIG0) = params->mc_da_cfg0;
MC(MC_TIMING_CONTROL) = 1;
MC(MC_TIMING_CONTROL) = 1; // Trigger MC timing update.
// Program second-level clock enable overrides.
MC(MC_CLKEN_OVERRIDE) = params->mc_clken_override;
// Program statistics gathering.
MC(MC_STAT_CONTROL) = params->mc_stat_control;
// Program SDRAM geometry parameters.
EMC(EMC_ADR_CFG) = params->emc_adr_cfg;
// Program second-level clock enable overrides.
EMC(EMC_CLKEN_OVERRIDE) = params->emc_clken_override;
// Program EMC pad auto calibration.
EMC(EMC_PMACRO_AUTOCAL_CFG_0) = params->emc_pmacro_auto_cal_cfg0;
EMC(EMC_PMACRO_AUTOCAL_CFG_1) = params->emc_pmacro_auto_cal_cfg1;
EMC(EMC_PMACRO_AUTOCAL_CFG_2) = params->emc_pmacro_auto_cal_cfg2;
EMC(EMC_AUTO_CAL_VREF_SEL_0) = params->emc_auto_cal_vref_sel0;
EMC(EMC_AUTO_CAL_VREF_SEL_1) = params->emc_auto_cal_vref_sel1;
EMC(EMC_AUTO_CAL_INTERVAL) = params->emc_auto_cal_interval;
EMC(EMC_AUTO_CAL_CONFIG) = params->emc_auto_cal_config;
usleep(params->emc_auto_cal_wait);
// Patch 5 using BCT spare variables.
if (params->emc_bct_spare8)
*(vu32 *)params->emc_bct_spare8 = params->emc_bct_spare9;
// Program EMC timing configuration.
EMC(EMC_CFG_2) = params->emc_cfg2;
EMC(EMC_CFG_PIPE) = params->emc_cfg_pipe;
EMC(EMC_CFG_PIPE_1) = params->emc_cfg_pipe1;
@ -354,9 +439,11 @@ break_nosleep:
EMC(EMC_EINPUT_DURATION) = params->emc_einput_duration;
EMC(EMC_PUTERM_EXTRA) = params->emc_puterm_extra;
EMC(EMC_PUTERM_WIDTH) = params->emc_puterm_width;
EMC(EMC_PMACRO_COMMON_PAD_TX_CTRL) = params->emc_pmacro_common_pad_tx_ctrl;
EMC(EMC_DBG) = params->emc_dbg;
EMC(EMC_QRST) = params->emc_qrst;
EMC(EMC_ISSUE_QRST) = 1;
EMC(EMC_ISSUE_QRST) = 0;
EMC(EMC_QSAFE) = params->emc_qsafe;
EMC(EMC_RDV) = params->emc_rdv;
@ -389,6 +476,8 @@ break_nosleep:
EMC(EMC_ODT_WRITE) = params->emc_odt_write;
EMC(EMC_CFG_DIG_DLL) = params->emc_cfg_dig_dll;
EMC(EMC_CFG_DIG_DLL_PERIOD) = params->emc_cfg_dig_dll_period;
// Don't write CFG_ADR_EN (bit 1) here - lock bit written later.
EMC(EMC_FBIO_SPARE) = params->emc_fbio_spare & 0xFFFFFFFD;
EMC(EMC_CFG_RSV) = params->emc_cfg_rsv;
EMC(EMC_PMC_SCRATCH1) = params->emc_pmc_scratch1;
@ -396,70 +485,104 @@ break_nosleep:
EMC(EMC_PMC_SCRATCH3) = params->emc_pmc_scratch3;
EMC(EMC_ACPD_CONTROL) = params->emc_acpd_control;
EMC(EMC_TXDSRVTTGEN) = params->emc_txdsrvttgen;
// Set pipe bypass enable bits before sending any DRAM commands.
EMC(EMC_CFG) = (params->emc_cfg & 0xE) | 0x3C00000;
// Patch BootROM.
if (params->boot_rom_patch_control & (1 << 31))
{
*(vu32 *)(APB_MISC_BASE + params->boot_rom_patch_control * 4) = params->boot_rom_patch_data;
MC(MC_TIMING_CONTROL) = 1;
MC(MC_TIMING_CONTROL) = 1; // Trigger MC timing update.
}
PMC(APBDEV_PMC_IO_DPD3_REQ) = ((4 * params->emc_pmc_scratch1 >> 2) + 0x40000000) & 0xCFFF0000;
// Release SEL_DPD_CMD.
PMC(APBDEV_PMC_IO_DPD3_REQ) = ((params->emc_pmc_scratch1 & 0x3FFFFFFF) | 0x40000000) & 0xCFFF0000;
usleep(params->pmc_io_dpd3_req_wait);
// Set autocal interval if not configured.
if (!params->emc_auto_cal_interval)
EMC(EMC_AUTO_CAL_CONFIG) = params->emc_auto_cal_config | 0x200;
EMC(EMC_PMACRO_BRICK_CTRL_RFU2) = params->emc_pmacro_brick_ctrl_rfu2;
// ZQ CAL setup (not actually issuing ZQ CAL now).
if (params->emc_zcal_warm_cold_boot_enables & 1)
{
if (params->memory_type == 2)
EMC(EMC_ZCAL_WAIT_CNT) = 8 * params->emc_zcal_wait_cnt;
EMC(EMC_ZCAL_WAIT_CNT) = params->emc_zcal_wait_cnt << 3;
if (params->memory_type == 3)
{
EMC(EMC_ZCAL_WAIT_CNT) = params->emc_zcal_wait_cnt;
EMC(EMC_ZCAL_MRW_CMD) = params->emc_zcal_mrw_cmd;
}
}
EMC(EMC_TIMING_CONTROL) = 1;
EMC(EMC_TIMING_CONTROL) = 1; // Trigger timing update so above writes take place.
usleep(params->emc_timing_control_wait);
// Deassert HOLD_CKE_LOW.
PMC(APBDEV_PMC_DDR_CNTRL) &= 0xFFF8007F;
usleep(params->pmc_ddr_ctrl_wait);
if (params->memory_type == 2)
// Set clock enable signal.
u32 pin_gpio_cfg = (params->emc_pin_gpio_enable << 16) | (params->emc_pin_gpio << 12);
if (params->memory_type == 2 || params->memory_type == 3)
{
EMC(EMC_PIN) = (params->emc_pin_gpio_enable << 16) | (params->emc_pin_gpio << 12);
EMC(EMC_PIN) = pin_gpio_cfg;
(void)EMC(EMC_PIN);
usleep(params->emc_pin_extra_wait + 200);
EMC(EMC_PIN) = ((params->emc_pin_gpio_enable << 16) | (params->emc_pin_gpio << 12)) + 256;
usleep(params->emc_pin_extra_wait + 500);
EMC(EMC_PIN) = pin_gpio_cfg | 0x100;
(void)EMC(EMC_PIN);
}
if (params->memory_type == 3)
{
EMC(EMC_PIN) = (params->emc_pin_gpio_enable << 16) | (params->emc_pin_gpio << 12);
usleep(params->emc_pin_extra_wait + 200);
EMC(EMC_PIN) = ((params->emc_pin_gpio_enable << 16) | (params->emc_pin_gpio << 12)) + 256;
usleep(params->emc_pin_extra_wait + 2000);
}
EMC(EMC_PIN) = ((params->emc_pin_gpio_enable << 16) | (params->emc_pin_gpio << 12)) + 0x101;
else if (params->memory_type == 2)
usleep(params->emc_pin_extra_wait + 500);
// Enable clock enable signal.
EMC(EMC_PIN) = pin_gpio_cfg | 0x101;
(void)EMC(EMC_PIN);
usleep(params->emc_pin_program_wait);
// Send NOP (trigger just needs to be non-zero).
if (params->memory_type != 3)
EMC(EMC_NOP) = (params->emc_dev_select << 30) + 1;
// On coldboot w/LPDDR2/3, wait 200 uSec after asserting CKE high.
if (params->memory_type == 1)
usleep(params->emc_pin_extra_wait + 200);
// Init zq calibration,
if (params->memory_type == 3)
{
// Patch 6 using BCT spare variables.
if (params->emc_bct_spare10)
*(vu32 *)params->emc_bct_spare10 = params->emc_bct_spare11;
// Write mode registers.
EMC(EMC_MRW2) = params->emc_mrw2;
EMC(EMC_MRW) = params->emc_mrw1;
EMC(EMC_MRW3) = params->emc_mrw3;
EMC(EMC_MRW4) = params->emc_mrw4;
EMC(EMC_MRW6) = params->emc_mrw6;
EMC(EMC_MRW14) = params->emc_mrw14;
EMC(EMC_MRW8) = params->emc_mrw8;
EMC(EMC_MRW12) = params->emc_mrw12;
EMC(EMC_MRW9) = params->emc_mrw9;
EMC(EMC_MRW13) = params->emc_mrw13;
if (params->emc_zcal_warm_cold_boot_enables & 1)
{
// Issue ZQCAL start, device 0.
EMC(EMC_ZQ_CAL) = params->emc_zcal_init_dev0;
usleep(params->emc_zcal_init_wait);
// Issue ZQCAL latch.
EMC(EMC_ZQ_CAL) = params->emc_zcal_init_dev0 ^ 3;
// Same for device 1.
if (!(params->emc_dev_select & 2))
{
EMC(EMC_ZQ_CAL) = params->emc_zcal_init_dev1;
@ -468,42 +591,64 @@ break_nosleep:
}
}
}
// Set package and DPD pad control.
PMC(APBDEV_PMC_DDR_CFG) = params->pmc_ddr_cfg;
// Start periodic ZQ calibration (LPDDRx only).
if (params->memory_type - 1 <= 2)
{
EMC(EMC_ZCAL_INTERVAL) = params->emc_zcal_interval;
EMC(EMC_ZCAL_WAIT_CNT) = params->emc_zcal_wait_cnt;
EMC(EMC_ZCAL_MRW_CMD) = params->emc_zcal_mrw_cmd;
}
// Patch 7 using BCT spare variables.
if (params->emc_bct_spare12)
*(vu32 *)params->emc_bct_spare12 = params->emc_bct_spare13;
EMC(EMC_TIMING_CONTROL) = 1;
EMC(EMC_TIMING_CONTROL) = 1; // Trigger timing update so above writes take place.
if (params->emc_extra_refresh_num)
EMC(EMC_REF) = ((1 << params->emc_extra_refresh_num << 8) - 0xFD) | (params->emc_pin_gpio << 30);
EMC(EMC_REF) = (((1 << params->emc_extra_refresh_num) - 1) << 8) | (params->emc_dev_select << 30) | 3;
// Enable refresh.
EMC(EMC_REFCTRL) = params->emc_dev_select | 0x80000000;
EMC(EMC_DYN_SELF_REF_CONTROL) = params->emc_dyn_self_ref_control;
EMC(EMC_CFG_UPDATE) = params->emc_cfg_update;
EMC(EMC_CFG) = params->emc_cfg;
EMC(EMC_FDPD_CTRL_DQ) = params->emc_fdpd_ctrl_dq;
EMC(EMC_FDPD_CTRL_CMD) = params->emc_fdpd_ctrl_cmd;
EMC(EMC_SEL_DPD_CTRL) = params->emc_sel_dpd_ctrl;
// Write addr swizzle lock bit.
EMC(EMC_FBIO_SPARE) = params->emc_fbio_spare | 2;
EMC(EMC_TIMING_CONTROL) = 1;
EMC(EMC_TIMING_CONTROL) = 1; // Re-trigger timing to latch power saving functions.
// Enable EMC pipe clock gating.
EMC(EMC_CFG_PIPE_CLK) = params->emc_cfg_pipe_clk;
// Depending on freqency, enable CMD/CLK fdpd.
EMC(EMC_FDPD_CTRL_CMD_NO_RAMP) = params->emc_fdpd_ctrl_cmd_no_ramp;
SYSREG(AHB_ARBITRATION_XBAR_CTRL) = (SYSREG(AHB_ARBITRATION_XBAR_CTRL) & 0xFFFEFFFF) | ((params->ahb_arbitration_xbar_ctrl_meminit_done & 0xFFFF) << 16);
// Enable arbiter.
SYSREG(AHB_ARBITRATION_XBAR_CTRL) = (SYSREG(AHB_ARBITRATION_XBAR_CTRL) & 0xFFFEFFFF) | (params->ahb_arbitration_xbar_ctrl_meminit_done << 16);
// Lock carveouts per BCT cfg.
MC(MC_VIDEO_PROTECT_REG_CTRL) = params->mc_video_protect_write_access;
MC(MC_SEC_CARVEOUT_REG_CTRL) = params->mc_sec_carveout_protect_write_access;
MC(MC_MTS_CARVEOUT_REG_CTRL) = params->mc_mts_carveout_reg_ctrl;
MC(MC_EMEM_CFG_ACCESS_CTRL) = 1; //Disable write access to a bunch of EMC registers.
//Disable write access to a bunch of EMC registers.
MC(MC_EMEM_CFG_ACCESS_CTRL) = 1;
}
sdram_params_t *sdram_get_params()
{
//TODO: sdram_id should be in [0, 7].
#ifdef CONFIG_SDRAM_COMPRESS_CFG
u8 *buf = (u8 *)0x40030000;
u8 *buf = (u8 *)SDRAM_PARAMS_ADDR;
LZ_Uncompress(_dram_cfg_lz, buf, sizeof(_dram_cfg_lz));
return (sdram_params_t *)&buf[sizeof(sdram_params_t) * _get_sdram_id()];
#else
@ -535,7 +680,17 @@ sdram_params_t *sdram_get_params_patched()
// Disable Warmboot signature check.
sdram_params->boot_rom_patch_control = (1 << 31) | (((IPATCH_BASE + 4) - APB_MISC_BASE) / 4);
sdram_params->boot_rom_patch_data = IPATCH_CONFIG(0x10459E, 0x2000);
/*
// Disable SBK lock.
sdram_params->emc_bct_spare8 = (IPATCH_BASE + 7 * 4);
sdram_params->emc_bct_spare9 = IPATCH_CONFIG(0x10210E, 0x2000);
// Disable bootrom read lock.
sdram_params->emc_bct_spare10 = (IPATCH_BASE + 10 * 4);
sdram_params->emc_bct_spare11 = IPATCH_CONFIG(0x100FDC, 0xF000);
sdram_params->emc_bct_spare12 = (IPATCH_BASE + 11 * 4);
sdram_params->emc_bct_spare13 = IPATCH_CONFIG(0x100FDE, 0xE320);
*/
return sdram_params;
}
@ -544,16 +699,24 @@ void sdram_init()
//TODO: sdram_id should be in [0,4].
const sdram_params_t *params = (const sdram_params_t *)sdram_get_params();
// Set DRAM voltage.
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_SD_CFG2, 0x05);
max77620_regulator_set_voltage(REGULATOR_SD1, 1100000); // Set DRAM voltage.
max77620_regulator_set_voltage(REGULATOR_SD1, 1100000);
// VDDP Select.
PMC(APBDEV_PMC_VDDP_SEL) = params->pmc_vddp_sel;
usleep(params->pmc_vddp_sel_wait);
// Set DDR pad voltage.
PMC(APBDEV_PMC_DDR_PWR) = PMC(APBDEV_PMC_DDR_PWR);
// Turn on MEM IO Power.
PMC(APBDEV_PMC_NO_IOPOWER) = params->pmc_no_io_power;
PMC(APBDEV_PMC_REG_SHORT) = params->pmc_reg_short;
PMC(APBDEV_PMC_DDR_CNTRL) = params->pmc_ddr_ctrl;
// Patch 1 using BCT spare variables
if (params->emc_bct_spare0)
*(vu32 *)params->emc_bct_spare0 = params->emc_bct_spare1;

View file

@ -1,7 +1,7 @@
/*
* Copyright (c) 2013-2015, NVIDIA CORPORATION. All rights reserved.
* Copyright 2014 Google Inc.
* Copyright (C) 2018 CTCaer
* Copyright (c) 2018 CTCaer
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,

View file

@ -1,9 +1,9 @@
/*
* Fuel gauge driver for Nintendo Switch's Maxim 17050
*
* Copyright (C) 2011 Samsung Electronics
* Copyright (c) 2011 Samsung Electronics
* MyungJoo Ham <myungjoo.ham@samsung.com>
* Copyright (C) 2018 CTCaer
* Copyright (c) 2018 CTCaer
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -43,6 +43,9 @@
#define MAX17050_VMAX_TOLERANCE 50 /* 50 mV */
#pragma GCC push_options
#pragma GCC optimize ("Os")
int max17050_get_property(enum MAX17050_reg reg, int *value)
{
u16 data;
@ -264,3 +267,5 @@ int max17050_fix_configuration()
return 0;
}
#pragma GCC pop_options

View file

@ -2,9 +2,9 @@
* Fuel gauge driver for Nintendo Switch's Maxim 17050
* Note that Maxim 8966 and 8997 are mfd and this is its subdevice.
*
* Copyright (C) 2011 Samsung Electronics
* Copyright (c) 2011 Samsung Electronics
* MyungJoo Ham <myungjoo.ham@samsung.com>
* Copyright (C) 2018 CTCaer
* Copyright (c) 2018 CTCaer
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View file

@ -1,7 +1,7 @@
/*
* Defining registers address and its bit definitions of MAX77620 and MAX20024
*
* Copyright (C) 2016 NVIDIA CORPORATION. All rights reserved.
* Copyright (c) 2016 NVIDIA CORPORATION. All rights reserved.
* Copyright (c) 2019 CTCaer
*
* This program is free software; you can redistribute it and/or modify it
@ -19,9 +19,19 @@
#define MAX77620_CNFGGLBL1_LBDAC_EN (1 << 7)
#define MAX77620_CNFGGLBL1_MPPLD (1 << 6)
#define MAX77620_CNFGGLBL1_LBHYST ((1 << 5) | (1 << 4))
#define MAX77620_CNFGGLBL1_LBHYST_N (1 << 4)
#define MAX77620_CNFGGLBL1_LBDAC 0x0E
#define MAX77620_CNFGGLBL1_LBDAC_N (1 << 1)
#define MAX77620_CNFGGLBL1_LBHYST_100 (0 << 4)
#define MAX77620_CNFGGLBL1_LBHYST_200 (1 << 4)
#define MAX77620_CNFGGLBL1_LBHYST_300 (2 << 4)
#define MAX77620_CNFGGLBL1_LBHYST_400 (3 << 4)
#define MAX77620_CNFGGLBL1_LBDAC_MASK 0x0E
#define MAX77620_CNFGGLBL1_LBDAC_2700 (0 << 1)
#define MAX77620_CNFGGLBL1_LBDAC_2800 (1 << 1)
#define MAX77620_CNFGGLBL1_LBDAC_2900 (2 << 1)
#define MAX77620_CNFGGLBL1_LBDAC_3000 (3 << 1)
#define MAX77620_CNFGGLBL1_LBDAC_3100 (4 << 1)
#define MAX77620_CNFGGLBL1_LBDAC_3200 (5 << 1)
#define MAX77620_CNFGGLBL1_LBDAC_3300 (6 << 1)
#define MAX77620_CNFGGLBL1_LBDAC_3400 (7 << 1)
#define MAX77620_CNFGGLBL1_LBRSTEN (1 << 0)
#define MAX77620_REG_CNFGGLBL2 0x01

View file

@ -64,6 +64,16 @@ static const max77620_regulator_t _pmic_regulators[] = {
{ REGULATOR_LDO, "ldo8", 0x00, 50000, 800000, 1050000, 1050000, MAX77620_REG_LDO8_CFG, MAX77620_REG_LDO8_CFG2, MAX77620_LDO_VOLT_MASK, MAX77620_LDO_POWER_MODE_MASK, MAX77620_LDO_POWER_MODE_SHIFT, 0x00, MAX77620_REG_FPS_LDO8, 3, 7, 0 }
};
static void _max77620_try_set_reg(u8 reg, u8 val)
{
u8 tmp;
do
{
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, reg, val);
tmp = i2c_recv_byte(I2C_5, MAX77620_I2C_ADDR, reg);
} while (val != tmp);
}
int max77620_regulator_get_status(u32 id)
{
if (id > REGULATOR_MAX)
@ -83,7 +93,7 @@ int max77620_regulator_config_fps(u32 id)
const max77620_regulator_t *reg = &_pmic_regulators[id];
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, reg->fps_addr,
_max77620_try_set_reg(reg->fps_addr,
(reg->fps_src << MAX77620_FPS_SRC_SHIFT) | (reg->pu_period << MAX77620_FPS_PU_PERIOD_SHIFT) | (reg->pd_period));
return 1;
@ -102,7 +112,7 @@ int max77620_regulator_set_voltage(u32 id, u32 mv)
u32 mult = (mv + reg->mv_step - 1 - reg->mv_min) / reg->mv_step;
u8 val = i2c_recv_byte(I2C_5, MAX77620_I2C_ADDR, reg->volt_addr);
val = (val & ~reg->volt_mask) | (mult & reg->volt_mask);
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, reg->volt_addr, val);
_max77620_try_set_reg(reg->volt_addr, val);
usleep(1000);
return 1;
@ -121,7 +131,7 @@ int max77620_regulator_enable(u32 id, int enable)
val = (val & ~reg->enable_mask) | ((MAX77620_POWER_MODE_NORMAL << reg->enable_shift) & reg->enable_mask);
else
val &= ~reg->enable_mask;
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, addr, val);
_max77620_try_set_reg(addr, val);
usleep(1000);
return 1;
@ -139,7 +149,7 @@ int max77620_regulator_set_volt_and_flags(u32 id, u32 mv, u8 flags)
u32 mult = (mv + reg->mv_step - 1 - reg->mv_min) / reg->mv_step;
u8 val = ((flags << reg->enable_shift) & ~reg->volt_mask) | (mult & reg->volt_mask);
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, reg->volt_addr, val);
_max77620_try_set_reg(reg->volt_addr, val);
usleep(1000);
return 1;
@ -155,11 +165,12 @@ void max77620_config_default()
if (_pmic_regulators[i].fps_src != MAX77620_FPS_SRC_NONE)
max77620_regulator_enable(i, 1);
}
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_SD_CFG2, 4);
_max77620_try_set_reg(MAX77620_REG_SD_CFG2, 4);
}
void max77620_low_battery_monitor_config()
{
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_CNFGGLBL1,
MAX77620_CNFGGLBL1_LBDAC_EN | MAX77620_CNFGGLBL1_LBHYST_N | MAX77620_CNFGGLBL1_LBDAC_N);
_max77620_try_set_reg(MAX77620_REG_CNFGGLBL1,
MAX77620_CNFGGLBL1_LBDAC_EN | MAX77620_CNFGGLBL1_MPPLD |
MAX77620_CNFGGLBL1_LBHYST_200 | MAX77620_CNFGGLBL1_LBDAC_2800);
}

View file

@ -33,6 +33,9 @@ typedef struct _se_ll_t
vu32 size;
} se_ll_t;
static u32 _se_rsa_mod_sizes[TEGRA_SE_RSA_KEYSLOT_COUNT];
static u32 _se_rsa_exp_sizes[TEGRA_SE_RSA_KEYSLOT_COUNT];
static void _gf256_mul_x(void *block)
{
u8 *pdata = (u8 *)block;
@ -83,25 +86,23 @@ static int _se_wait()
while (!(SE(SE_INT_STATUS_REG_OFFSET) & SE_INT_OP_DONE(INT_SET)))
;
if (SE(SE_INT_STATUS_REG_OFFSET) & SE_INT_ERROR(INT_SET) ||
SE(SE_STATUS_0) & 3 ||
SE(SE_ERR_STATUS_0) != 0)
SE(SE_STATUS_0) & SE_STATUS_0_STATE_WAIT_IN ||
SE(SE_ERR_STATUS_0) != SE_ERR_STATUS_0_SE_NS_ACCESS_CLEAR)
return 0;
return 1;
}
static int _se_execute(u32 op, void *dst, u32 dst_size, const void *src, u32 src_size)
{
se_ll_t *ll_dst = NULL, *ll_src = NULL;
se_ll_t *ll_dst = (se_ll_t *)0xECFFFFE0, *ll_src = (se_ll_t *)0xECFFFFF0;
if (dst)
{
ll_dst = (se_ll_t *)malloc(sizeof(se_ll_t));
_se_ll_init(ll_dst, (u32)dst, dst_size);
}
if (src)
{
ll_src = (se_ll_t *)malloc(sizeof(se_ll_t));
_se_ll_init(ll_src, (u32)src, src_size);
}
@ -110,17 +111,12 @@ static int _se_execute(u32 op, void *dst, u32 dst_size, const void *src, u32 src
SE(SE_ERR_STATUS_0) = SE(SE_ERR_STATUS_0);
SE(SE_INT_STATUS_REG_OFFSET) = SE(SE_INT_STATUS_REG_OFFSET);
bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY);
bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY, false);
SE(SE_OPERATION_REG_OFFSET) = SE_OPERATION(op);
int res = _se_wait();
bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY);
if (src)
free(ll_src);
if (dst)
free(ll_dst);
bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY, false);
return res;
}
@ -152,17 +148,79 @@ static void _se_aes_ctr_set(void *ctr)
void se_rsa_acc_ctrl(u32 rs, u32 flags)
{
if (flags & 0x7F)
SE(SE_RSA_KEYTABLE_ACCESS_REG_OFFSET + 4 * rs) = (((flags >> 4) & 4) | (flags & 3)) ^ 7;
if (flags & 0x80)
if (flags & SE_RSA_KEY_TBL_DIS_KEY_ALL_FLAG)
SE(SE_RSA_KEYTABLE_ACCESS_REG_OFFSET + 4 * rs) =
((flags >> SE_RSA_KEY_TBL_DIS_KEYUSE_FLAG_SHIFT) & SE_RSA_KEY_TBL_DIS_KEYUSE_FLAG) |
((flags & SE_RSA_KEY_TBL_DIS_KEY_READ_UPDATE_FLAG) ^ SE_RSA_KEY_TBL_DIS_KEY_ALL_COMMON_FLAG);
if (flags & SE_RSA_KEY_TBL_DIS_KEY_LOCK_FLAG)
SE(SE_RSA_KEYTABLE_ACCESS_LOCK_OFFSET) &= ~(1 << rs);
}
// se_rsa_key_set() was derived from Atmosphère's set_rsa_keyslot
void se_rsa_key_set(u32 ks, const void *mod, u32 mod_size, const void *exp, u32 exp_size)
{
u32 *data = (u32 *)mod;
for (u32 i = 0; i < mod_size / 4; i++)
{
SE(SE_RSA_KEYTABLE_ADDR) = RSA_KEY_NUM(ks) | RSA_KEY_TYPE(RSA_KEY_TYPE_MOD) | i;
SE(SE_RSA_KEYTABLE_DATA) = byte_swap_32(data[mod_size / 4 - i - 1]);
}
data = (u32 *)exp;
for (u32 i = 0; i < exp_size / 4; i++)
{
SE(SE_RSA_KEYTABLE_ADDR) = RSA_KEY_NUM(ks) | RSA_KEY_TYPE(RSA_KEY_TYPE_EXP) | i;
SE(SE_RSA_KEYTABLE_DATA) = byte_swap_32(data[exp_size / 4 - i - 1]);
}
_se_rsa_mod_sizes[ks] = mod_size;
_se_rsa_exp_sizes[ks] = exp_size;
}
// se_rsa_key_clear() was derived from Atmosphère's clear_rsa_keyslot
void se_rsa_key_clear(u32 ks)
{
for (u32 i = 0; i < TEGRA_SE_RSA2048_DIGEST_SIZE / 4; i++)
{
SE(SE_RSA_KEYTABLE_ADDR) = RSA_KEY_NUM(ks) | RSA_KEY_TYPE(RSA_KEY_TYPE_MOD) | i;
SE(SE_RSA_KEYTABLE_DATA) = 0;
}
for (u32 i = 0; i < TEGRA_SE_RSA2048_DIGEST_SIZE / 4; i++)
{
SE(SE_RSA_KEYTABLE_ADDR) = RSA_KEY_NUM(ks) | RSA_KEY_TYPE(RSA_KEY_TYPE_EXP) | i;
SE(SE_RSA_KEYTABLE_DATA) = 0;
}
}
// se_rsa_exp_mod() was derived from Atmosphère's se_synchronous_exp_mod and se_get_exp_mod_output
int se_rsa_exp_mod(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_size)
{
int res;
u8 stack_buf[TEGRA_SE_RSA2048_DIGEST_SIZE];
for (u32 i = 0; i < src_size; i++)
stack_buf[i] = *((u8 *)src + src_size - i - 1);
SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_ENC_ALG(ALG_RSA) | SE_CONFIG_DST(DST_RSAREG);
SE(SE_RSA_CONFIG) = RSA_KEY_SLOT(ks);
SE(SE_RSA_KEY_SIZE_REG_OFFSET) = (_se_rsa_mod_sizes[ks] >> 6) - 1;
SE(SE_RSA_EXP_SIZE_REG_OFFSET) = _se_rsa_exp_sizes[ks] >> 2;
res = _se_execute(OP_START, NULL, 0, stack_buf, src_size);
// Copy output hash.
u32 *dst32 = (u32 *)dst;
for (u32 i = 0; i < dst_size / 4; i++)
dst32[dst_size / 4 - i - 1] = byte_swap_32(SE(SE_RSA_OUTPUT + (i << 2)));
return res;
}
void se_key_acc_ctrl(u32 ks, u32 flags)
{
if (flags & 0x7F)
if (flags & SE_KEY_TBL_DIS_KEY_ACCESS_FLAG)
SE(SE_KEY_TABLE_ACCESS_REG_OFFSET + 4 * ks) = ~flags;
if (flags & 0x80)
if (flags & SE_KEY_TBL_DIS_KEY_LOCK_FLAG)
SE(SE_KEY_TABLE_ACCESS_LOCK_OFFSET) &= ~(1 << ks);
}
@ -240,7 +298,8 @@ int se_aes_crypt_ctr(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_s
SE(SE_SPARE_0_REG_OFFSET) = 1;
SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_ENC_ALG(ALG_AES_ENC) | SE_CONFIG_DST(DST_MEMORY);
SE(SE_CRYPTO_REG_OFFSET) = SE_CRYPTO_KEY_INDEX(ks) | SE_CRYPTO_CORE_SEL(CORE_ENCRYPT) |
SE_CRYPTO_XOR_POS(XOR_BOTTOM) | SE_CRYPTO_INPUT_SEL(INPUT_LNR_CTR) | SE_CRYPTO_CTR_VAL(1);
SE_CRYPTO_XOR_POS(XOR_BOTTOM) | SE_CRYPTO_INPUT_SEL(INPUT_LNR_CTR) | SE_CRYPTO_CTR_VAL(1) |
SE_CRYPTO_VCTRAM_SEL(VCTRAM_AHB);
_se_aes_ctr_set(ctr);
u32 src_size_aligned = src_size & 0xFFFFFFF0;
@ -277,10 +336,6 @@ int se_aes_xts_crypt_sec(u32 ks1, u32 ks2, u32 enc, u64 sec, void *dst, const vo
if (!se_aes_crypt_block_ecb(ks1, 1, tweak, tweak))
goto out;
u8 temptweak[0x10];
memcpy(temptweak, tweak, 0x10);
//We are assuming a 0x10-aligned sector size in this implementation.
for (u32 i = 0; i < secsize / 0x10; i++)
{
@ -295,19 +350,6 @@ int se_aes_xts_crypt_sec(u32 ks1, u32 ks2, u32 enc, u64 sec, void *dst, const vo
pdst += 0x10;
}
se_aes_crypt_ecb(ks2, enc, dst, secsize, src, secsize);
pdst = (u8 *)dst;
memcpy(tweak, temptweak, 0x10);
for (u32 i = 0; i < secsize / 0x10; i++) {
for (u32 j = 0; j < 0x10; j++)
pdst[j] = pdst[j] ^ tweak[j];
_gf256_mul_x_le(tweak);
pdst += 0x10;
}
res = 1;
out:;
@ -342,7 +384,9 @@ int se_aes_cmac(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_size)
_gf256_mul_x(key);
SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_ENC_ALG(ALG_AES_ENC) | SE_CONFIG_DST(DST_HASHREG);
SE(SE_CRYPTO_REG_OFFSET) = SE_CRYPTO_KEY_INDEX(ks) | 0x145;
SE(SE_CRYPTO_REG_OFFSET) = SE_CRYPTO_KEY_INDEX(ks) | SE_CRYPTO_INPUT_SEL(INPUT_AHB) |
SE_CRYPTO_XOR_POS(XOR_TOP) | SE_CRYPTO_VCTRAM_SEL(VCTRAM_AESOUT) | SE_CRYPTO_HASH(HASH_ENABLE) |
SE_CRYPTO_CORE_SEL(CORE_ENCRYPT);
se_aes_key_iv_clear(ks);
u32 num_blocks = (src_size + 0xf) >> 4;
@ -382,15 +426,15 @@ int se_calc_sha256(void *dst, const void *src, u32 src_size)
int res;
// Setup config for SHA256, size = BITS(src_size).
SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_ENC_MODE(MODE_SHA256) | SE_CONFIG_ENC_ALG(ALG_SHA) | SE_CONFIG_DST(DST_HASHREG);
SE(SE_SHA_CONFIG_REG_OFFSET) = SHA_ENABLE;
SE(SE_SHA_MSG_LENGTH_REG_OFFSET) = (u32)(src_size << 3);
SE(SE_SHA_MSG_LENGTH_REG_OFFSET + 4 * 1) = 0;
SE(SE_SHA_MSG_LENGTH_REG_OFFSET + 4 * 2) = 0;
SE(SE_SHA_MSG_LENGTH_REG_OFFSET + 4 * 3) = 0;
SE(SE_SHA_MSG_LEFT_REG_OFFSET) = (u32)(src_size << 3);
SE(SE_SHA_MSG_LEFT_REG_OFFSET + 4 * 1) = 0;
SE(SE_SHA_MSG_LEFT_REG_OFFSET + 4 * 2) = 0;
SE(SE_SHA_MSG_LEFT_REG_OFFSET + 4 * 3) = 0;
SE(SE_SHA_CONFIG_REG_OFFSET) = SHA_INIT_HASH;
SE(SE_SHA_MSG_LENGTH_0_REG_OFFSET) = (u32)(src_size << 3);
SE(SE_SHA_MSG_LENGTH_1_REG_OFFSET) = 0;
SE(SE_SHA_MSG_LENGTH_2_REG_OFFSET) = 0;
SE(SE_SHA_MSG_LENGTH_3_REG_OFFSET) = 0;
SE(SE_SHA_MSG_LEFT_0_REG_OFFSET) = (u32)(src_size << 3);
SE(SE_SHA_MSG_LEFT_1_REG_OFFSET) = 0;
SE(SE_SHA_MSG_LEFT_2_REG_OFFSET) = 0;
SE(SE_SHA_MSG_LEFT_3_REG_OFFSET) = 0;
// Trigger the operation.
res = _se_execute(OP_START, NULL, 0, src, src_size);
@ -402,3 +446,46 @@ int se_calc_sha256(void *dst, const void *src, u32 src_size)
return res;
}
int se_calc_hmac_sha256(void *dst, const void *src, u32 src_size, const void *key, u32 key_size) {
int res = 0;
u8 *secret = (u8 *)malloc(0x40);
u8 *ipad = (u8 *)malloc(0x40 + src_size);
u8 *opad = (u8 *)malloc(0x60);
if (key_size > 0x40)
{
if (!se_calc_sha256(secret, key, key_size))
goto out;
memset(secret + 0x20, 0, 0x20);
}
else
{
memcpy(secret, key, key_size);
memset(secret + key_size, 0, 0x40 - key_size);
}
u32 *secret32 = (u32 *)secret;
u32 *ipad32 = (u32 *)ipad;
u32 *opad32 = (u32 *)opad;
for (u32 i = 0; i < 0x10; i++)
{
ipad32[i] = secret32[i] ^ 0x36363636;
opad32[i] = secret32[i] ^ 0x5C5C5C5C;
}
memcpy(ipad + 0x40, src, src_size);
if (!se_calc_sha256(dst, ipad, 0x40 + src_size))
goto out;
memcpy(opad + 0x40, dst, 0x20);
if (!se_calc_sha256(dst, opad, 0x60))
goto out;
res = 1;
out:;
free(secret);
free(ipad);
free(opad);
return res;
}

View file

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

View file

@ -36,6 +36,8 @@
#define SE_SECURITY_0 0x000
#define SE_KEY_SCHED_READ_SHIFT 3
#define SE_TZRAM_SECURITY_0 0x004
#define SE_CONFIG_REG_OFFSET 0x014
#define SE_CONFIG_ENC_ALG_SHIFT 12
#define SE_CONFIG_DEC_ALG_SHIFT 8
@ -209,8 +211,12 @@
#define SE_INT_OP_DONE(x) (x << SE_INT_OP_DONE_SHIFT)
#define SE_INT_ERROR_SHIFT 16
#define SE_INT_ERROR(x) (x << SE_INT_ERROR_SHIFT)
#define SE_STATUS_0 0x800
#define SE_STATUS_0_STATE_WAIT_IN 3
#define SE_ERR_STATUS_0 0x804
#define SE_ERR_STATUS_0_SE_NS_ACCESS_CLEAR 0
#define SE_CRYPTO_KEYTABLE_DST_REG_OFFSET 0X330
#define SE_CRYPTO_KEYTABLE_DST_WORD_QUAD_SHIFT 0
@ -231,11 +237,17 @@
#define SE_SPARE_0_REG_OFFSET 0x80c
#define SE_SHA_CONFIG_REG_OFFSET 0x200
#define SHA_DISABLE 0
#define SHA_ENABLE 1
#define SHA_CONTINUE 0
#define SHA_INIT_HASH 1
#define SE_SHA_MSG_LENGTH_REG_OFFSET 0x204
#define SE_SHA_MSG_LEFT_REG_OFFSET 0x214
#define SE_SHA_MSG_LENGTH_0_REG_OFFSET 0x204
#define SE_SHA_MSG_LENGTH_1_REG_OFFSET 0x208
#define SE_SHA_MSG_LENGTH_2_REG_OFFSET 0x20C
#define SE_SHA_MSG_LENGTH_3_REG_OFFSET 0x210
#define SE_SHA_MSG_LEFT_0_REG_OFFSET 0x214
#define SE_SHA_MSG_LEFT_1_REG_OFFSET 0x218
#define SE_SHA_MSG_LEFT_2_REG_OFFSET 0x21C
#define SE_SHA_MSG_LEFT_3_REG_OFFSET 0x220
#define SE_HASH_RESULT_REG_COUNT 16
#define SE_HASH_RESULT_REG_OFFSET 0x030
@ -254,13 +266,24 @@
TEGRA_SE_RNG_DT_SIZE)
#define TEGRA_SE_AES_CMAC_DIGEST_SIZE 16
#define TEGRA_SE_RSA512_DIGEST_SIZE 64
#define TEGRA_SE_RSA512_DIGEST_SIZE 64
#define TEGRA_SE_RSA1024_DIGEST_SIZE 128
#define TEGRA_SE_RSA1536_DIGEST_SIZE 192
#define TEGRA_SE_RSA2048_DIGEST_SIZE 256
#define SE_KEY_TABLE_ACCESS_LOCK_OFFSET 0x280
#define SE_KEY_TBL_DIS_KEY_LOCK_FLAG 0x80
#define SE_KEY_TABLE_ACCESS_REG_OFFSET 0x284
#define SE_KEY_TBL_DIS_KEYREAD_FLAG (1 << 0)
#define SE_KEY_TBL_DIS_KEYUPDATE_FLAG (1 << 1)
#define SE_KEY_TBL_DIS_OIVREAD_FLAG (1 << 2)
#define SE_KEY_TBL_DIS_OIVUPDATE_FLAG (1 << 3)
#define SE_KEY_TBL_DIS_UIVREAD_FLAG (1 << 4)
#define SE_KEY_TBL_DIS_UIVUPDATE_FLAG (1 << 5)
#define SE_KEY_TBL_DIS_KEYUSE_FLAG (1 << 6)
#define SE_KEY_TBL_DIS_KEY_ACCESS_FLAG 0x7F
#define SE_KEY_READ_DISABLE_SHIFT 0
#define SE_KEY_UPDATE_DISABLE_SHIFT 1
@ -312,7 +335,16 @@
#define TEGRA_SE_RSA_KEYSLOT_COUNT 2
#define SE_RSA_KEYTABLE_ACCESS_LOCK_OFFSET 0x40C
#define SE_RSA_KEY_TBL_DIS_KEY_LOCK_FLAG 0x80
#define SE_RSA_KEYTABLE_ACCESS_REG_OFFSET 0x410
#define SE_RSA_KEY_TBL_DIS_KEYREAD_FLAG (1 << 0)
#define SE_RSA_KEY_TBL_DIS_KEYUPDATE_FLAG (1 << 1)
#define SE_RSA_KEY_TBL_DIS_KEY_READ_UPDATE_FLAG (SE_RSA_KEY_TBL_DIS_KEYREAD_FLAG | SE_RSA_KEY_TBL_DIS_KEYUPDATE_FLAG)
#define SE_RSA_KEY_TBL_DIS_KEYUSE_FLAG (1 << 2)
#define SE_RSA_KEY_TBL_DIS_KEYUSE_FLAG_SHIFT (1 << 2)
#define SE_RSA_KEY_TBL_DIS_KEY_ALL_COMMON_FLAG 7
#define SE_RSA_KEY_TBL_DIS_KEY_ALL_FLAG 0x7F
#define SE_RSA_KEYTABLE_ADDR 0x420
#define SE_RSA_KEYTABLE_DATA 0x424

View file

@ -23,6 +23,7 @@
#include "../sec/se_t210.h"
#include "../soc/bpmp.h"
#include "../soc/clock.h"
#include "../soc/kfuse.h"
#include "../soc/smmu.h"
#include "../soc/t210.h"
#include "../mem/heap.h"
@ -77,6 +78,8 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt)
clock_enable_sor1();
clock_enable_kfuse();
kfuse_wait_ready();
//Configure Falcon.
TSEC(TSEC_DMACTL) = 0;
TSEC(TSEC_IRQMSET) =
@ -208,7 +211,7 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt)
res = -6;
smmu_deinit_for_tsec();
goto out;
goto out_free;
}
// Give some extra time to make sure PKG1.1 is decrypted.
@ -278,7 +281,7 @@ out:;
clock_disable_sor_safe();
clock_disable_tsec();
bpmp_mmu_enable();
bpmp_clk_rate_set(BPMP_CLK_SUPER_BOOST);
bpmp_clk_rate_set(BPMP_CLK_DEFAULT_BOOST);
return res;
}

View file

@ -19,6 +19,7 @@
#include "bpmp.h"
#include "clock.h"
#include "t210.h"
#include "../../common/memory_map.h"
#include "../utils/util.h"
#define BPMP_CACHE_CONFIG 0x0
@ -74,13 +75,13 @@
bpmp_mmu_entry_t mmu_entries[] =
{
{ 0x80000000, 0xFFFFFFFF, MMU_EN_READ | MMU_EN_WRITE | MMU_EN_EXEC | MMU_EN_CACHED, true },
{ IPL_LOAD_ADDR, 0x40040000, MMU_EN_READ | MMU_EN_WRITE | MMU_EN_EXEC | MMU_EN_CACHED, true }
{ DRAM_START, 0xFFFFFFFF, MMU_EN_READ | MMU_EN_WRITE | MMU_EN_EXEC | MMU_EN_CACHED, true },
{ IRAM_BASE, 0x4003FFFF, MMU_EN_READ | MMU_EN_WRITE | MMU_EN_EXEC | MMU_EN_CACHED, true }
};
void bpmp_mmu_maintenance(u32 op)
void bpmp_mmu_maintenance(u32 op, bool force)
{
if (!(BPMP_CACHE_CTRL(BPMP_CACHE_CONFIG) & CFG_ENABLE))
if (!force && !(BPMP_CACHE_CTRL(BPMP_CACHE_CONFIG) & CFG_ENABLE))
return;
BPMP_CACHE_CTRL(BPMP_CACHE_INT_CLEAR) = INT_CLR_MAINT_DONE;
@ -132,13 +133,13 @@ void bpmp_mmu_enable()
BPMP_CACHE_CTRL(BPMP_CACHE_MMU_CMD) = MMU_CMD_COPY_SHADOW;
// Invalidate cache.
bpmp_mmu_maintenance(BPMP_MMU_MAINT_INVALID_WAY);
bpmp_mmu_maintenance(BPMP_MMU_MAINT_INVALID_WAY, true);
// Enable cache.
BPMP_CACHE_CTRL(BPMP_CACHE_CONFIG) = CFG_ENABLE | CFG_FORCE_WRITE_THROUGH | CFG_TAG_CHK_ABRT_ON_ERR;
// HW bug. Invalidate cache again.
bpmp_mmu_maintenance(BPMP_MMU_MAINT_INVALID_WAY);
bpmp_mmu_maintenance(BPMP_MMU_MAINT_INVALID_WAY, false);
}
void bpmp_mmu_disable()
@ -147,21 +148,19 @@ void bpmp_mmu_disable()
return;
// Clean and invalidate cache.
bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY);
bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY, false);
// Disable cache.
BPMP_CACHE_CTRL(BPMP_CACHE_CONFIG) = 0;
// HW bug. Invalidate cache again.
bpmp_mmu_maintenance(BPMP_MMU_MAINT_INVALID_WAY);
}
const u8 pllc4_divn[] = {
0, // BPMP_CLK_NORMAL: 408MHz 0% - 136MHz APB.
85, // BPMP_CLK_LOW_BOOST: 544MHz 33% - 136MHz APB.
90, // BPMP_CLK_MID_BOOST: 576MHz 41% - 144MHz APB.
94 // BPMP_CLK_SUPER_BOOST: 602MHz 48% - 150MHz APB.
//95 // BPMP_CLK_SUPER_BOOST: 608MHz 49% - 152MHz APB.
85, // BPMP_CLK_HIGH_BOOST: 544MHz 33% - 136MHz APB.
90, // BPMP_CLK_SUPER_BOOST: 576MHz 41% - 144MHz APB.
92 // BPMP_CLK_HYPER_BOOST: 589MHz 44% - 147MHz APB.
// Do not use for public releases!
//95 // BPMP_CLK_DEV_BOOST: 608MHz 49% - 152MHz APB.
};
bpmp_freq_t bpmp_clock_set = BPMP_CLK_NORMAL;

View file

@ -36,13 +36,16 @@ typedef struct _bpmp_mmu_entry_t
typedef enum
{
BPMP_CLK_NORMAL, // 408MHz 0% - 136MHz APB.
BPMP_CLK_LOW_BOOST, // 544MHz 33% - 136MHz APB.
BPMP_CLK_MID_BOOST, // 576MHz 41% - 144MHz APB.
BPMP_CLK_SUPER_BOOST, // 608MHz 49% - 152MHz APB.
BPMP_CLK_HIGH_BOOST, // 544MHz 33% - 136MHz APB.
BPMP_CLK_SUPER_BOOST, // 576MHz 41% - 144MHz APB.
BPMP_CLK_HYPER_BOOST, // 589MHz 44% - 147MHz APB.
//BPMP_CLK_DEV_BOOST, // 608MHz 49% - 152MHz APB.
BPMP_CLK_MAX
} bpmp_freq_t;
void bpmp_mmu_maintenance(u32 op);
#define BPMP_CLK_DEFAULT_BOOST BPMP_CLK_HYPER_BOOST
void bpmp_mmu_maintenance(u32 op, bool force);
void bpmp_mmu_set_entry(int idx, bpmp_mmu_entry_t *entry, bool apply);
void bpmp_mmu_enable();
void bpmp_mmu_disable();

View file

@ -15,7 +15,6 @@
*/
#include "../soc/clock.h"
#include "../soc/kfuse.h"
#include "../soc/t210.h"
#include "../utils/util.h"
#include "../storage/sdmmc.h"
@ -30,13 +29,14 @@ static const clock_t _clock_uart[] = {
/* UART E */ { CLK_RST_CONTROLLER_RST_DEVICES_Y, CLK_RST_CONTROLLER_CLK_OUT_ENB_Y, CLK_RST_CONTROLLER_CLK_SOURCE_UARTAPE, 20, 0, 2 }
};
//I2C default parameters - TLOW: 4, THIGH: 2, DEBOUNCE: 0 FM_DIV: 26.
static const clock_t _clock_i2c[] = {
/* I2C1 */ { CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_I2C1, 12, 6, 0 }, // 0, 19 }, // 100KHz
/* 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, 15, 6, 0 }, // 0, 4 }, // 400KHz
/* I2C6 */ { 0 }
/* I2C1 */ { CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_I2C1, 12, 0, 19 }, //20.4MHz -> 100KHz
/* I2C2 */ { CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_RST_CONTROLLER_CLK_SOURCE_I2C2, 22, 0, 4 }, //81.6MHz -> 400KHz
/* I2C3 */ { CLK_RST_CONTROLLER_RST_DEVICES_U, CLK_RST_CONTROLLER_CLK_OUT_ENB_U, CLK_RST_CONTROLLER_CLK_SOURCE_I2C3, 3, 0, 4 }, //81.6MHz -> 400KHz
/* I2C4 */ { CLK_RST_CONTROLLER_RST_DEVICES_V, CLK_RST_CONTROLLER_CLK_OUT_ENB_V, CLK_RST_CONTROLLER_CLK_SOURCE_I2C4, 7, 0, 19 }, //20.4MHz -> 100KHz
/* I2C5 */ { CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_RST_CONTROLLER_CLK_SOURCE_I2C5, 15, 0, 4 }, //81.6MHz -> 400KHz
/* I2C6 */ { CLK_RST_CONTROLLER_RST_DEVICES_X, CLK_RST_CONTROLLER_CLK_OUT_ENB_X, CLK_RST_CONTROLLER_CLK_SOURCE_I2C6, 6, 0, 19 } //20.4MHz -> 100KHz
};
static clock_t _clock_se = {
@ -74,7 +74,7 @@ static clock_t _clock_coresight = {
};
static clock_t _clock_pwm = {
CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_PWM, 17, 6, 4 // Freference: 6.2MHz.
CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_PWM, 17, 6, 4 // Fref: 6.2MHz.
};
void clock_enable(const clock_t *clk)
@ -88,6 +88,8 @@ void clock_enable(const clock_t *clk)
CLOCK(clk->source) = clk->clk_div | (clk->clk_src << 29);
// Enable.
CLOCK(clk->enable) = (CLOCK(clk->enable) & ~(1 << clk->index)) | (1 << clk->index);
usleep(2);
// Take clock off reset.
CLOCK(clk->reset) &= ~(1 << clk->index);
}
@ -189,7 +191,6 @@ void clock_enable_kfuse()
usleep(10);
CLOCK(CLK_RST_CONTROLLER_RST_DEVICES_H) &= 0xFFFFFEFF;
usleep(20);
kfuse_wait_ready();
}
void clock_disable_kfuse()
@ -368,7 +369,7 @@ static void _clock_sdmmc_clear_enable(u32 id)
static u32 _clock_sdmmc_table[8] = { 0 };
#define PLLP_OUT0 0x0
static int _clock_sdmmc_config_clock_source_inner(u32 *pout, u32 id, u32 val)
static int _clock_sdmmc_config_clock_host(u32 *pout, u32 id, u32 val)
{
u32 divisor = 0;
u32 source = PLLP_OUT0;
@ -416,6 +417,7 @@ static int _clock_sdmmc_config_clock_source_inner(u32 *pout, u32 id, u32 val)
_clock_sdmmc_table[2 * id] = val;
_clock_sdmmc_table[2 * id + 1] = *pout;
// Set SDMMC clock.
switch (id)
{
case SDMMC_1:
@ -446,15 +448,16 @@ void clock_sdmmc_config_clock_source(u32 *pout, u32 id, u32 val)
int is_enabled = _clock_sdmmc_is_enabled(id);
if (is_enabled)
_clock_sdmmc_clear_enable(id);
_clock_sdmmc_config_clock_source_inner(pout, id, val);
_clock_sdmmc_config_clock_host(pout, id, val);
if (is_enabled)
_clock_sdmmc_set_enable(id);
_clock_sdmmc_is_reset(id);
}
}
void clock_sdmmc_get_params(u32 *pout, u16 *pdivisor, u32 type)
void clock_sdmmc_get_card_clock_div(u32 *pout, u16 *pdivisor, u32 type)
{
// Get Card clock divisor.
switch (type)
{
case 0:
@ -515,7 +518,7 @@ void clock_sdmmc_enable(u32 id, u32 val)
if (_clock_sdmmc_is_enabled(id))
_clock_sdmmc_clear_enable(id);
_clock_sdmmc_set_reset(id);
_clock_sdmmc_config_clock_source_inner(&div, id, val);
_clock_sdmmc_config_clock_host(&div, id, val);
_clock_sdmmc_set_enable(id);
_clock_sdmmc_is_reset(id);
usleep((100000 + div - 1) / div);

View file

@ -104,6 +104,7 @@
#define CLK_RST_CONTROLLER_CLK_SOURCE_SYS 0x400
#define CLK_RST_CONTROLLER_CLK_SOURCE_SOR1 0x410
#define CLK_RST_CONTROLLER_CLK_SOURCE_SE 0x42C
#define CLK_RST_CONTROLLER_RST_DEV_V_CLR 0x434
#define CLK_RST_CONTROLLER_CLK_ENB_V_SET 0x440
#define CLK_RST_CONTROLLER_CLK_ENB_V_CLR 0x444
#define CLK_RST_CONTROLLER_CLK_ENB_W_SET 0x448
@ -181,7 +182,7 @@ void clock_disable_coresight();
void clock_enable_pwm();
void clock_disable_pwm();
void clock_sdmmc_config_clock_source(u32 *pout, u32 id, u32 val);
void clock_sdmmc_get_params(u32 *pout, u16 *pdivisor, u32 type);
void clock_sdmmc_get_card_clock_div(u32 *pout, u16 *pdivisor, u32 type);
int clock_sdmmc_is_not_reset_and_enabled(u32 id);
void clock_sdmmc_enable(u32 id, u32 val);
void clock_sdmmc_disable(u32 id);

View file

@ -80,9 +80,9 @@ void cluster_boot_cpu0(u32 entry)
_cluster_enable_power();
if (!(CLOCK(CLK_RST_CONTROLLER_PLLX_BASE) & 0x40000000))
if (!(CLOCK(CLK_RST_CONTROLLER_PLLX_BASE) & 0x40000000)) // PLLX_ENABLE.
{
CLOCK(CLK_RST_CONTROLLER_PLLX_MISC_3) &= 0xFFFFFFF7;
CLOCK(CLK_RST_CONTROLLER_PLLX_MISC_3) &= 0xFFFFFFF7; // Disable IDDQ.
usleep(2);
CLOCK(CLK_RST_CONTROLLER_PLLX_BASE) = 0x80404E02;
CLOCK(CLK_RST_CONTROLLER_PLLX_BASE) = 0x404E02;
@ -127,6 +127,9 @@ void cluster_boot_cpu0(u32 entry)
SB(SB_CSR) = SB_CSR_NS_RST_VEC_WR_DIS;
(void)SB(SB_CSR);
// Tighten up the security aperture.
// MC(MC_TZ_SECURITY_CTRL) = 1;
// Clear MSELECT reset.
CLOCK(CLK_RST_CONTROLLER_RST_DEVICES_V) &= 0xFFFFFFF7;
// Clear NONCPU reset.

View file

@ -22,6 +22,34 @@
#include "../soc/fuse.h"
#include "../soc/t210.h"
#define ARRAYSIZE(x) (sizeof(x) / sizeof(*x))
static const u32 evp_thunk_template[] = {
0xe92d0007, // STMFD SP!, {R0-R2}
0xe1a0200e, // MOV R2, LR
0xe2422002, // SUB R2, R2, #2
0xe5922000, // LDR R2, [R2]
0xe20220ff, // AND R2, R2, #0xFF
0xe1a02082, // MOV R2, R2,LSL#1
0xe59f001c, // LDR R0, =evp_thunk_template
0xe59f101c, // LDR R1, =thunk_end
0xe0411000, // SUB R1, R1, R0
0xe59f0018, // LDR R0, =iram_evp_thunks
0xe0800001, // ADD R0, R0, R1
0xe0822000, // ADD R2, R2, R0
0xe3822001, // ORR R2, R2, #1
0xe8bd0003, // LDMFD SP!, {R0,R1}
0xe12fff12, // BX R2
0x001007b0, // off_1007EC DCD evp_thunk_template
0x001007f8, // off_1007F0 DCD thunk_end
0x40004c30, // off_1007F4 DCD iram_evp_thunks
// thunk_end is here
};
static const u32 evp_thunk_template_len = sizeof(evp_thunk_template);
// treated as 12bit values
static const u32 hash_vals[] = {1, 2, 4, 8, 0, 3, 5, 6, 7, 9, 10, 11};
void fuse_disable_program()
{
FUSE(FUSE_DISABLEREGPROGRAM) = 1;
@ -31,3 +59,291 @@ u32 fuse_read_odm(u32 idx)
{
return FUSE(FUSE_RESERVED_ODMX(idx));
}
void fuse_wait_idle()
{
u32 ctrl;
do
{
ctrl = FUSE(FUSE_CTRL);
} while (((ctrl >> 16) & 0x1f) != 4);
}
u32 fuse_read(u32 addr)
{
FUSE(FUSE_ADDR) = addr;
FUSE(FUSE_CTRL) = (FUSE(FUSE_ADDR) & ~FUSE_CMD_MASK) | FUSE_READ;
fuse_wait_idle();
return FUSE(FUSE_RDATA);
}
void fuse_read_array(u32 *words)
{
for (u32 i = 0; i < 192; i++)
words[i] = fuse_read(i);
}
static u32 _parity32_even(u32 *words, u32 count)
{
u32 acc = words[0];
for (u32 i = 1; i < count; i++)
{
acc ^= words[i];
}
u32 lo = ((acc & 0xffff) ^ (acc >> 16)) & 0xff;
u32 hi = ((acc & 0xffff) ^ (acc >> 16)) >> 8;
u32 x = hi ^ lo;
lo = ((x & 0xf) ^ (x >> 4)) & 3;
hi = ((x & 0xf) ^ (x >> 4)) >> 2;
x = hi ^ lo;
return (x & 1) ^ (x >> 1);
}
static int _patch_hash_one(u32 *word)
{
u32 bits20_31 = *word & 0xfff00000;
u32 parity_bit = _parity32_even(&bits20_31, 1);
u32 hash = 0;
for (u32 i = 0; i < 12; i++)
{
if (*word & (1 << (20 + i)))
{
hash ^= hash_vals[i];
}
}
if (hash == 0)
{
if (parity_bit == 0)
{
return 0;
}
*word ^= 1 << 24;
return 1;
}
if (parity_bit == 0)
{
return 3;
}
for (u32 i = 0; i < ARRAYSIZE(hash_vals); i++)
{
if (hash_vals[i] == hash)
{
*word ^= 1 << (20 + i);
return 1;
}
}
return 2;
}
static int _patch_hash_multi(u32 *words, u32 count)
{
u32 parity_bit = _parity32_even(words, count);
u32 bits0_14 = words[0] & 0x7fff;
u32 bit15 = words[0] & 0x8000;
u32 bits16_19 = words[0] & 0xf0000;
u32 hash = 0;
words[0] = bits16_19;
for (u32 i = 0; i < count; i++)
{
u32 w = words[i];
if (w)
{
for (u32 bitpos = 0; bitpos < 32; bitpos++)
{
if ((w >> bitpos) & 1)
{
hash ^= 0x4000 + i * 32 + bitpos;
}
}
}
}
hash ^= bits0_14;
// stupid but this is what original code does.
// equivalent to original words[0] &= 0xfff00000
words[0] = bits16_19 ^ bit15 ^ bits0_14;
if (hash == 0)
{
if (parity_bit == 0)
{
return 0;
}
words[0] ^= 0x8000;
return 1;
}
if (parity_bit == 0)
{
return 3;
}
u32 bitcount = hash - 0x4000;
if (bitcount < 16 || bitcount >= count * 32)
{
u32 num_set = 0;
for (u32 bitpos = 0; bitpos < 15; bitpos++)
{
if ((hash >> bitpos) & 1)
{
num_set++;
}
}
if (num_set != 1)
{
return 2;
}
words[0] ^= hash;
return 1;
}
words[bitcount / 32] ^= 1 << (hash & 0x1f);
return 1;
}
int fuse_read_ipatch(void (*ipatch)(u32 offset, u32 value))
{
u32 words[80];
u32 word_count;
u32 word_addr;
u32 word0 = 0;
u32 total_read = 0;
word_count = FUSE(FUSE_FIRST_BOOTROM_PATCH_SIZE);
word_count &= 0x7F;
word_addr = 191;
while (word_count)
{
total_read += word_count;
if (total_read >= ARRAYSIZE(words))
{
break;
}
for (u32 i = 0; i < word_count; i++)
words[i] = fuse_read(word_addr--);
word0 = words[0];
if (_patch_hash_multi(words, word_count) >= 2)
{
return 1;
}
u32 ipatch_count = (words[0] >> 16) & 0xF;
if (ipatch_count)
{
for (u32 i = 0; i < ipatch_count; i++)
{
u32 word = words[i + 1];
u32 addr = (word >> 16) * 2;
u32 data = word & 0xFFFF;
ipatch(addr, data);
}
}
words[0] = word0;
if ((word0 >> 25) == 0)
break;
if (_patch_hash_one(&word0) >= 2)
{
return 3;
}
word_count = word0 >> 25;
}
return 0;
}
int fuse_read_evp_thunk(u32 *iram_evp_thunks, u32 *iram_evp_thunks_len)
{
u32 words[80];
u32 word_count;
u32 word_addr;
u32 word0 = 0;
u32 total_read = 0;
int evp_thunk_written = 0;
void *evp_thunk_dst_addr = 0;
memset(iram_evp_thunks, 0, *iram_evp_thunks_len);
word_count = FUSE(FUSE_FIRST_BOOTROM_PATCH_SIZE);
word_count &= 0x7F;
word_addr = 191;
while (word_count)
{
total_read += word_count;
if (total_read >= ARRAYSIZE(words))
{
break;
}
for (u32 i = 0; i < word_count; i++)
words[i] = fuse_read(word_addr--);
word0 = words[0];
if (_patch_hash_multi(words, word_count) >= 2)
{
return 1;
}
u32 ipatch_count = (words[0] >> 16) & 0xF;
u32 insn_count = word_count - ipatch_count - 1;
if (insn_count)
{
if (!evp_thunk_written)
{
evp_thunk_dst_addr = (void *)iram_evp_thunks;
memcpy(evp_thunk_dst_addr, (void *)evp_thunk_template, evp_thunk_template_len);
evp_thunk_dst_addr += evp_thunk_template_len;
evp_thunk_written = 1;
*iram_evp_thunks_len = evp_thunk_template_len;
//write32(TEGRA_EXCEPTION_VECTORS_BASE + 0x208, iram_evp_thunks);
}
u32 thunk_patch_len = insn_count * sizeof(u32);
memcpy(evp_thunk_dst_addr, &words[ipatch_count + 1], thunk_patch_len);
evp_thunk_dst_addr += thunk_patch_len;
*iram_evp_thunks_len += thunk_patch_len;
}
words[0] = word0;
if ((word0 >> 25) == 0)
break;
if (_patch_hash_one(&word0) >= 2)
{
return 3;
}
word_count = word0 >> 25;
}
return 0;
}
bool fuse_check_patched_rcm()
{
// Check if XUSB in use.
if (FUSE(FUSE_RESERVED_SW) & (1<<7))
return true;
// Check if RCM is ipatched.
u32 word_count = FUSE(FUSE_FIRST_BOOTROM_PATCH_SIZE) & 0x7F;
u32 word_addr = 191;
while (word_count)
{
u32 word0 = fuse_read(word_addr);
u32 ipatch_count = (word0 >> 16) & 0xF;
for (u32 i = 0; i < ipatch_count; i++)
{
u32 word = fuse_read(word_addr - (i + 1));
u32 addr = (word >> 16) * 2;
if (addr == 0x769A)
return true;
}
word_addr -= word_count;
word_count = word0 >> 25;
}
return false;
}

View file

@ -54,6 +54,7 @@
#define FUSE_PRIVATE_KEY3 0x1B0
#define FUSE_PRIVATE_KEY4 0x1B4
#define FUSE_RESERVED_SW 0x1C0
#define FUSE_SKU_DIRECT_CONFIG 0x1F4
#define FUSE_OPT_VENDOR_CODE 0x200
#define FUSE_OPT_FAB_CODE 0x204
#define FUSE_OPT_LOT_CODE_0 0x208
@ -74,5 +75,10 @@
void fuse_disable_program();
u32 fuse_read_odm(u32 idx);
void fuse_wait_idle();
int fuse_read_ipatch(void (*ipatch)(u32 offset, u32 value));
int fuse_read_evp_thunk(u32 *iram_evp_thunks, u32 *iram_evp_thunks_len);
void fuse_read_array(u32 *words);
bool fuse_check_patched_rcm();
#endif

View file

@ -28,6 +28,7 @@
#include "t210.h"
#include "../gfx/di.h"
#include "../mem/mc.h"
#include "../mem/minerva.h"
#include "../mem/sdram.h"
#include "../power/max77620.h"
#include "../power/max7762x.h"
@ -218,7 +219,7 @@ void _config_regulators()
{
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_CNFGBBC, MAX77620_CNFGBBC_RESISTOR_1K);
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_ONOFFCNFG1,
(1 << 6) | (1 << MAX77620_ONOFFCNFG1_MRT_SHIFT)); // PWR delay for forced shutdown off.
(1 << 6) | (3 << MAX77620_ONOFFCNFG1_MRT_SHIFT)); // PWR delay for forced shutdown off.
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_CFG0,
(7 << MAX77620_FPS_TIME_PERIOD_SHIFT));
@ -256,7 +257,7 @@ void _config_regulators()
MAX77621_T_JUNCTION_120 | MAX77621_FT_ENABLE | MAX77621_CKKADV_TRIP_75mV_PER_US_HIST_DIS |
MAX77621_CKKADV_TRIP_150mV_PER_US | MAX77621_INDUCTOR_NOMINAL);
// Disable low battery shutdown monitor.
// Enable low battery shutdown monitor for < 2800mV.
max77620_low_battery_monitor_config();
}
@ -273,6 +274,7 @@ void config_hw()
// Enable fuse clock.
clock_enable_fuse(true);
// Disable fuse programming.
fuse_disable_program();
@ -309,6 +311,7 @@ void reconfig_hw_workaround(bool extra_reconfig, u32 magic)
// Flush and disable MMU.
bpmp_mmu_disable();
bpmp_clk_rate_set(BPMP_CLK_NORMAL);
minerva_change_freq(FREQ_204);
// Re-enable clocks to Audio Processing Engine as a workaround to hanging.
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_V) |= (1 << 10); // Enable AHUB clock.

View file

@ -17,7 +17,21 @@
#include "../soc/kfuse.h"
#include "../soc/clock.h"
#include "../soc/t210.h"
#include "../utils/util.h"
#pragma GCC push_options
#pragma GCC optimize ("Os")
int kfuse_wait_ready()
{
// Wait for KFUSE to finish init and verification of data.
while (!(KFUSE(KFUSE_STATE) & KFUSE_STATE_DONE))
;
if (!(KFUSE(KFUSE_STATE) & KFUSE_STATE_CRCPASS))
return 0;
return 1;
}
int kfuse_read(u32 *buf)
{
@ -25,10 +39,7 @@ int kfuse_read(u32 *buf)
clock_enable_kfuse();
while (!(KFUSE(KFUSE_STATE) & KFUSE_STATE_DONE))
;
if (!(KFUSE(KFUSE_STATE) & KFUSE_STATE_CRCPASS))
if (!kfuse_wait_ready())
goto out;
KFUSE(KFUSE_KEYADDR) = KFUSE_KEYADDR_AUTOINC;
@ -42,16 +53,4 @@ out:;
return res;
}
int kfuse_wait_ready()
{
// Wait for KFUSE to finish init and verification of data.
while (!(KFUSE(KFUSE_STATE) & KFUSE_STATE_DONE))
{
usleep(500);
}
if (!(KFUSE(KFUSE_STATE) & KFUSE_STATE_CRCPASS))
return 0;
return 1;
}
#pragma GCC pop_options

View file

@ -36,7 +36,7 @@
#define KFUSE_NUM_WORDS 144
int kfuse_read(u32 *buf);
int kfuse_wait_ready();
int kfuse_read(u32 *buf);
#endif

View file

@ -106,7 +106,7 @@ bool smmu_is_used()
void smmu_exit()
{
*(uint32_t *)(smmu_payload + 0x14) = _NOP();
*(u32 *)(smmu_payload + 0x14) = _NOP();
}
u32 *smmu_init_domain4(u32 dev_base, u32 asid)

View file

@ -108,6 +108,14 @@
/*! EVP registers. */
#define EVP_CPU_RESET_VECTOR 0x100
#define EVP_COP_RESET_VECTOR 0x200
#define EVP_COP_UNDEF_VECTOR 0x204
#define EVP_COP_SWI_VECTOR 0x208
#define EVP_COP_PREFETCH_ABORT_VECTOR 0x20C
#define EVP_COP_DATA_ABORT_VECTOR 0x210
#define EVP_COP_RSVD_VECTOR 0x214
#define EVP_COP_IRQ_VECTOR 0x218
#define EVP_COP_FIQ_VECTOR 0x21C
/*! Misc registers. */
#define APB_MISC_PP_STRAPPING_OPT_A 0x08
@ -208,7 +216,7 @@
#define HALT_COP_JTAG (1 << 28)
#define HALT_COP_WAIT_EVENT (1 << 30)
#define HALT_COP_WAIT_IRQ (1 << 31)
#define HALT_COP_MAX_CNT 0xFF
#define HALT_COP_MAX_CNT 0xFF
#define FLOW_CTLR_HALT_CPU0_EVENTS 0x0
#define FLOW_CTLR_HALT_CPU1_EVENTS 0x14
#define FLOW_CTLR_HALT_CPU2_EVENTS 0x1C

View file

@ -47,7 +47,6 @@ bool emummc_load_cfg()
emu_cfg.file_based_part_size = 0;
emu_cfg.active_part = 0;
emu_cfg.fs_ver = 0;
free(emu_cfg.emummc_file_based_path);
emu_cfg.emummc_file_based_path = (char *)malloc(0x80);
LIST_INIT(ini_sections);

View file

@ -36,7 +36,7 @@ void nx_emmc_gpt_parse(link_t *gpt, sdmmc_storage_t *storage)
part->lba_end = ent->lba_end;
part->attrs = ent->attrs;
//HACK
// ASCII conversion. Copy only the LSByte of the UTF-16LE name.
for (u32 i = 0; i < 36; i++)
part->name[i] = ent->name[i];
part->name[36] = 0;
@ -74,6 +74,5 @@ int nx_emmc_part_write(sdmmc_storage_t *storage, emmc_part_t *part, u32 sector_o
// The last LBA is inclusive.
if (part->lba_start + sector_off > part->lba_end)
return 0;
//return sdmmc_storage_write(storage, part->lba_start + sector_off, num_sectors, buf);
return emummc_storage_write(storage, part->lba_start + sector_off, num_sectors, buf);
return sdmmc_storage_write(storage, part->lba_start + sector_off, num_sectors, buf);
}

View file

@ -1,8 +1,8 @@
/*
* include/linux/mmc/sd.h
*
* Copyright (C) 2005-2007 Pierre Ossman, All Rights Reserved.
* Copyright (C) 2018 CTCaer
* Copyright (c) 2005-2007 Pierre Ossman, All Rights Reserved.
* Copyright (c) 2018 CTCaer
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -40,7 +40,9 @@
#define SD_ROCR_S18A SD_OCR_S18R /* 1.8V switching accepted by card */
#define SD_OCR_XPC (1 << 28) /* SDXC power control */
#define SD_OCR_CCS (1 << 30) /* Card Capacity Status */
#define SD_OCR_VDD_27_34 (0x7F << 15) /* VDD voltage 2.7 ~ 3.4 */
#define SD_OCR_VDD_32_33 (1 << 20) /* VDD voltage 3.2 ~ 3.3 */
#define SD_OCR_VDD_18 (1 << 7) /* VDD voltage 1.8 */
/*
* SD_SWITCH argument format:

View file

@ -1,6 +1,6 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (C) 2018-2019 CTCaer
* Copyright (c) 2018-2019 CTCaer
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@ -19,6 +19,7 @@
#include "sdmmc.h"
#include "mmc.h"
#include "sd.h"
#include "../../common/memory_map.h"
#include "../gfx/gfx.h"
#include "../mem/heap.h"
#include "../utils/util.h"
@ -220,10 +221,10 @@ static int _mmc_storage_get_op_cond_inner(sdmmc_storage_t *storage, u32 *pout, u
switch (power)
{
case SDMMC_POWER_1_8:
arg = 0x40000080; //Sector access, voltage.
arg = SD_OCR_CCS | SD_OCR_VDD_18;
break;
case SDMMC_POWER_3_3:
arg = 0x403F8000; //Sector access, voltage.
arg = SD_OCR_CCS | SD_OCR_VDD_27_34;
break;
default:
return 0;
@ -248,7 +249,7 @@ static int _mmc_storage_get_op_cond(sdmmc_storage_t *storage, u32 power)
if (cond & MMC_CARD_BUSY)
{
if (cond & 0x40000000)
if (cond & SD_OCR_CCS)
storage->has_sector_access = 1;
return 1;
@ -569,7 +570,7 @@ DPRINTF("[MMC] BKOPS disabled\n");
if (!_mmc_storage_enable_highspeed(storage, storage->ext_csd.card_type, type))
return 0;
DPRINTF("[MMC] succesfully switched to highspeed mode\n");
DPRINTF("[MMC] succesfully switched to HS mode\n");
sdmmc_sd_clock_ctrl(storage->sdmmc, 1);
@ -819,17 +820,17 @@ void _sd_storage_set_current_limit(sdmmc_storage_t *storage, u8 *buf)
switch (pwr)
{
case SD_SET_CURRENT_LIMIT_800:
DPRINTF("[SD] Power limit raised to 800mA\n");
DPRINTF("[SD] power limit raised to 800mA\n");
break;
case SD_SET_CURRENT_LIMIT_600:
DPRINTF("[SD] Power limit raised to 600mA\n");
DPRINTF("[SD] power limit raised to 600mA\n");
break;
case SD_SET_CURRENT_LIMIT_400:
DPRINTF("[SD] Power limit raised to 800mA\n");
DPRINTF("[SD] power limit raised to 800mA\n");
break;
default:
case SD_SET_CURRENT_LIMIT_200:
DPRINTF("[SD] Power limit defaulted to 200mA\n");
DPRINTF("[SD] power limit defaulted to 200mA\n");
break;
}
}
@ -857,7 +858,7 @@ DPRINTF("[SD] SD supports selected (U)HS mode\n");
return 1;
}
int _sd_storage_enable_highspeed_low_volt(sdmmc_storage_t *storage, u32 type, u8 *buf)
int _sd_storage_enable_uhs_low_volt(sdmmc_storage_t *storage, u32 type, u8 *buf)
{
// Try to raise the current limit to let the card perform better.
_sd_storage_set_current_limit(storage, buf);
@ -878,7 +879,7 @@ int _sd_storage_enable_highspeed_low_volt(sdmmc_storage_t *storage, u32 type, u8
{
type = 11;
hs_type = UHS_SDR104_BUS_SPEED;
DPRINTF("[SD] Bus speed set to SDR104\n");
DPRINTF("[SD] bus speed set to SDR104\n");
storage->csd.busspeed = 104;
break;
}
@ -887,7 +888,7 @@ DPRINTF("[SD] Bus speed set to SDR104\n");
{
type = 10;
hs_type = UHS_SDR50_BUS_SPEED;
DPRINTF("[SD] Bus speed set to SDR50\n");
DPRINTF("[SD] bus speed set to SDR50\n");
storage->csd.busspeed = 50;
break;
}
@ -896,7 +897,7 @@ DPRINTF("[SD] Bus speed set to SDR50\n");
return 0;
type = 8;
hs_type = UHS_SDR12_BUS_SPEED;
DPRINTF("[SD] Bus speed set to SDR12\n");
DPRINTF("[SD] bus speed set to SDR12\n");
storage->csd.busspeed = 12;
break;
default:
@ -916,7 +917,7 @@ DPRINTF("[SD] config tuning\n");
return _sdmmc_storage_check_status(storage);
}
int _sd_storage_enable_highspeed_high_volt(sdmmc_storage_t *storage, u8 *buf)
int _sd_storage_enable_hs_high_volt(sdmmc_storage_t *storage, u8 *buf)
{
if (!_sd_storage_switch_get(storage, buf))
return 0;
@ -1064,8 +1065,9 @@ void sdmmc_storage_init_wait_sd()
int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32 bus_width, u32 type)
{
int is_version_1 = 0;
u8 *buf = (u8 *)SDMMC_UPPER_BUFFER;
// Some cards (Sandisk U1), do not like a fast power cycle. Wait min 100ms.
// Some cards (SanDisk U1), do not like a fast power cycle. Wait min 100ms.
sdmmc_storage_init_wait_sd();
memset(storage, 0, sizeof(sdmmc_storage_t));
@ -1138,12 +1140,8 @@ DPRINTF("[SD] set blocklen to 512\n");
return 0;
DPRINTF("[SD] cleared card detect\n");
u8 *buf = (u8 *)malloc(512);
if (!_sd_storage_get_scr(storage, buf))
{
free(buf);
return 0;
}
//gfx_hexdump(0, storage->raw_scr, 8);
DPRINTF("[SD] got scr\n");
@ -1152,10 +1150,8 @@ DPRINTF("[SD] got scr\n");
if (bus_width == SDMMC_BUS_WIDTH_4 && (storage->scr.bus_widths & 4) && (storage->scr.sda_vsn & 0xF))
{
if (!_sd_storage_execute_app_cmd_type1(storage, &tmp, SD_APP_SET_BUS_WIDTH, SD_BUS_WIDTH_4, 0, R1_STATE_TRAN))
{
free(buf);
return 0;
}
sdmmc_set_bus_width(storage->sdmmc, SDMMC_BUS_WIDTH_4);
DPRINTF("[SD] switched to wide bus width\n");
}
@ -1166,20 +1162,15 @@ DPRINTF("[SD] SD does not support wide bus width\n");
if (storage->is_low_voltage)
{
if (!_sd_storage_enable_highspeed_low_volt(storage, type, buf))
{
free(buf);
if (!_sd_storage_enable_uhs_low_volt(storage, type, buf))
return 0;
}
DPRINTF("[SD] enabled UHS\n");
}
else if (type != 6 && (storage->scr.sda_vsn & 0xF) != 0)
{
if (!_sd_storage_enable_highspeed_high_volt(storage, buf))
{
free(buf);
if (!_sd_storage_enable_hs_high_volt(storage, buf))
return 0;
}
DPRINTF("[SD] enabled HS\n");
storage->csd.busspeed = 25;
}
@ -1192,7 +1183,6 @@ DPRINTF("[SD] enabled HS\n");
DPRINTF("[SD] got sd status\n");
}
free(buf);
return 1;
}

View file

@ -1,6 +1,6 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (C) 2018 CTCaer
* Copyright (c) 2018 CTCaer
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,

View file

@ -252,7 +252,7 @@ int sdmmc_setup_clock(sdmmc_t *sdmmc, u32 type)
u32 tmp;
u16 divisor;
clock_sdmmc_get_params(&tmp, &divisor, type);
clock_sdmmc_get_card_clock_div(&tmp, &divisor, type);
clock_sdmmc_config_clock_source(&tmp, sdmmc->id, tmp);
sdmmc->divisor = (tmp + divisor - 1) / divisor;
@ -830,7 +830,7 @@ static int _sdmmc_config_dma(sdmmc_t *sdmmc, u32 *blkcnt_out, sdmmc_req_t *req)
trnmode |= TEGRA_MMC_TRNMOD_DATA_XFER_DIR_SEL_READ;
if (req->is_auto_cmd12)
trnmode = (trnmode & 0xFFF3) | TEGRA_MMC_TRNMOD_AUTO_CMD12;
bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY);
bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY, false);
sdmmc->regs->trnmod = trnmode;
return 1;
@ -855,7 +855,7 @@ static int _sdmmc_update_dma(sdmmc_t *sdmmc)
break;
if (intr & TEGRA_MMC_NORINTSTS_XFER_COMPLETE)
{
bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY);
bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY, false);
return 1; // Transfer complete.
}
if (intr & TEGRA_MMC_NORINTSTS_DMA_INTERRUPT)
@ -1015,7 +1015,7 @@ int sdmmc_init(sdmmc_t *sdmmc, u32 id, u32 power, u32 bus_width, u32 type, int n
u32 clock;
u16 divisor;
clock_sdmmc_get_params(&clock, &divisor, type);
clock_sdmmc_get_card_clock_div(&clock, &divisor, type);
clock_sdmmc_enable(id, clock);
sdmmc->clock_stopped = 0;

View file

@ -1,6 +1,6 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (C) 2018 CTCaer
* Copyright (c) 2018 CTCaer
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@ -61,16 +61,25 @@ u8 btn_wait()
u8 btn_wait_timeout(u32 time_ms, u8 mask)
{
u8 single_button = mask & BTN_SINGLE;
mask &= ~BTN_SINGLE;
u32 timeout = get_tmr_ms() + time_ms;
u8 res = btn_read() & mask;
u8 res = btn_read();
while (get_tmr_ms() < timeout)
{
if (res == mask)
break;
if ((res & mask) == mask)
{
if (single_button && (res & ~mask)) // Undesired button detected.
res = btn_read();
else
return (res & mask);
}
else
res = btn_read() & mask;
res = btn_read();
};
return res;
// Timed out.
return 0;
}

View file

@ -1,6 +1,6 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (C) 2018 CTCaer
* Copyright (c) 2018 CTCaer
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@ -23,6 +23,7 @@
#define BTN_POWER (1 << 0)
#define BTN_VOL_DOWN (1 << 1)
#define BTN_VOL_UP (1 << 2)
#define BTN_SINGLE (1 << 7)
u8 btn_read();
u8 btn_wait();

View file

@ -42,7 +42,7 @@ char *dirlist(const char *directory, const char *pattern, bool includeHiddenFile
break;
if (!(fno.fattrib & AM_DIR) && (fno.fname[0] != '.') && (includeHiddenFiles || !(fno.fattrib & AM_HID)))
{
memcpy(dir_entries + (k * 256), fno.fname, strlen(fno.fname) + 1);
strcpy(dir_entries + (k * 256), fno.fname);
k++;
if (k > (max_entries - 1))
break;
@ -56,7 +56,7 @@ char *dirlist(const char *directory, const char *pattern, bool includeHiddenFile
{
if (!(fno.fattrib & AM_DIR) && (fno.fname[0] != '.') && (includeHiddenFiles || !(fno.fattrib & AM_HID)))
{
memcpy(dir_entries + (k * 256), fno.fname, strlen(fno.fname) + 1);
strcpy(dir_entries + (k * 256), fno.fname);
k++;
if (k > (max_entries - 1))
break;
@ -81,9 +81,9 @@ char *dirlist(const char *directory, const char *pattern, bool includeHiddenFile
{
if (strcmp(&dir_entries[i * 256], &dir_entries[j * 256]) > 0)
{
memcpy(temp, &dir_entries[i * 256], strlen(&dir_entries[i * 256]) + 1);
memcpy(&dir_entries[i * 256], &dir_entries[j * 256], strlen(&dir_entries[j * 256]) + 1);
memcpy(&dir_entries[j * 256], temp, strlen(temp) + 1);
strcpy(temp, &dir_entries[i * 256]);
strcpy(&dir_entries[i * 256], &dir_entries[j * 256]);
strcpy(&dir_entries[j * 256], temp);
}
}
}

View file

@ -20,6 +20,7 @@
#define NULL ((void *)0)
#define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1))
#define ALIGN_DOWN(x, a) (((x) - ((a) - 1)) & ~((a) - 1))
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#define MIN(a, b) ((a) < (b) ? (a) : (b))

View file

@ -1,6 +1,6 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (C) 2018 CTCaer
* Copyright (c) 2018 CTCaer
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@ -17,6 +17,7 @@
#include "util.h"
#include "../gfx/di.h"
#include "../mem/minerva.h"
#include "../power/max77620.h"
#include "../rtc/max77620-rtc.h"
#include "../soc/bpmp.h"
@ -26,6 +27,8 @@
#define USE_RTC_TIMER
extern volatile nyx_storage_t *nyx_str;
extern void sd_unmount();
u32 get_tmr_s()
@ -100,6 +103,8 @@ void reboot_normal()
sd_unmount();
display_end();
nyx_str->mtc_cfg.init_done = 0;
panic(0x21); // Bypass fuse programming in package1.
}
@ -110,6 +115,8 @@ void reboot_rcm()
sd_unmount();
display_end();
nyx_str->mtc_cfg.init_done = 0;
PMC(APBDEV_PMC_SCRATCH0) = 2; // Reboot into rcm.
PMC(APBDEV_PMC_CNTRL) |= PMC_CNTRL_MAIN_RST;

View file

@ -1,6 +1,6 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (C) 2018 CTCaer
* Copyright (c) 2018 CTCaer
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@ -19,6 +19,10 @@
#define _UTIL_H_
#include "types.h"
#include "../mem/minerva.h"
#define NYX_CFG_DUMP (1 << 7)
#define NYX_CFG_MINERVA (1 << 8)
#define byte_swap_32(num) (((num >> 24) & 0xff) | ((num << 8) & 0xff0000) | \
((num >> 8 )& 0xff00) | ((num << 24) & 0xff000000))
@ -29,6 +33,17 @@ typedef struct _cfg_op_t
u32 val;
} cfg_op_t;
typedef struct _nyx_storage_t
{
u32 version;
u32 cfg;
u8 irama[0x8000];
u8 hekate[0x30000];
u8 rsvd[0x800000];
mtc_config_t mtc_cfg;
emc_table_t mtc_table;
} nyx_storage_t;
u32 get_tmr_us();
u32 get_tmr_ms();
u32 get_tmr_s();