mirror of
https://github.com/suchmememanyskill/TegraExplorer.git
synced 2025-01-10 03:37:33 -03:00
Start rewrite
- Rewrite everything - Starting with up-to-date lockpickrcm
This commit is contained in:
parent
e8ddc9cf2f
commit
ff062a232b
95 changed files with 7043 additions and 1844 deletions
4
Makefile
4
Makefile
|
@ -9,7 +9,7 @@ include $(DEVKITARM)/base_rules
|
|||
################################################################################
|
||||
|
||||
IPL_LOAD_ADDR := 0x40003000
|
||||
LPVERSION_MAJOR := 1
|
||||
LPVERSION_MAJOR := 2
|
||||
LPVERSION_MINOR := 0
|
||||
LPVERSION_BUGFX := 0
|
||||
|
||||
|
@ -29,7 +29,7 @@ OBJS = $(patsubst $(SOURCEDIR)/%.S, $(BUILDDIR)/$(TARGET)/%.o, \
|
|||
CUSTOMDEFINES := -DIPL_LOAD_ADDR=$(IPL_LOAD_ADDR)
|
||||
CUSTOMDEFINES += -DLP_VER_MJ=$(LPVERSION_MAJOR) -DLP_VER_MN=$(LPVERSION_MINOR) -DLP_VER_BF=$(LPVERSION_BUGFX)
|
||||
|
||||
ARCH := -march=armv4t -mtune=arm7tdmi -mthumb-interwork
|
||||
ARCH := -march=armv4t -mtune=arm7tdmi -mthumb -mthumb-interwork
|
||||
CFLAGS = $(ARCH) -O2 -nostdlib -ffunction-sections -fdata-sections -fomit-frame-pointer -std=gnu11 -Wall $(CUSTOMDEFINES)
|
||||
LDFLAGS = $(ARCH) -nostartfiles -lgcc -Wl,--nmagic,--gc-sections -Xlinker --defsym=IPL_LOAD_ADDR=$(IPL_LOAD_ADDR)
|
||||
|
||||
|
|
39
common/common_module.h
Normal file
39
common/common_module.h
Normal 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);
|
54
source/config/config.c
Normal file
54
source/config/config.c
Normal file
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* 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 <stdlib.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "ini.h"
|
||||
#include "../gfx/gfx.h"
|
||||
#include "../libs/fatfs/ff.h"
|
||||
#include "../soc/t210.h"
|
||||
#include "../storage/sdmmc.h"
|
||||
#include "../utils/btn.h"
|
||||
#include "../utils/list.h"
|
||||
#include "../utils/util.h"
|
||||
|
||||
extern hekate_config h_cfg;
|
||||
extern bool sd_mount();
|
||||
extern void sd_unmount();
|
||||
|
||||
void set_default_configuration()
|
||||
{
|
||||
h_cfg.autoboot = 0;
|
||||
h_cfg.autoboot_list = 0;
|
||||
h_cfg.bootwait = 3;
|
||||
h_cfg.verification = 1;
|
||||
h_cfg.se_keygen_done = 0;
|
||||
h_cfg.sbar_time_keeping = 0;
|
||||
h_cfg.backlight = 100;
|
||||
h_cfg.autohosoff = 0;
|
||||
h_cfg.autonogc = 1;
|
||||
h_cfg.brand = NULL;
|
||||
h_cfg.tagline = NULL;
|
||||
h_cfg.errors = 0;
|
||||
h_cfg.sept_run = EMC(EMC_SCRATCH0) & EMC_SEPT_RUN;
|
||||
h_cfg.rcm_patched = true;
|
||||
h_cfg.emummc_force_disable = false;
|
||||
|
||||
sd_power_cycle_time_start = 0xFFFFFFF;
|
||||
}
|
||||
|
50
source/config/config.h
Normal file
50
source/config/config.h
Normal file
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#ifndef _CONFIG_H_
|
||||
#define _CONFIG_H_
|
||||
|
||||
#include "../utils/types.h"
|
||||
|
||||
typedef struct _hekate_config
|
||||
{
|
||||
// Non-volatile config.
|
||||
u32 autoboot;
|
||||
u32 autoboot_list;
|
||||
u32 bootwait;
|
||||
u32 verification;
|
||||
u32 backlight;
|
||||
u32 autohosoff;
|
||||
u32 autonogc;
|
||||
char *brand;
|
||||
char *tagline;
|
||||
// Global temporary config.
|
||||
bool se_keygen_done;
|
||||
bool sept_run;
|
||||
bool emummc_force_disable;
|
||||
bool rcm_patched;
|
||||
u32 sbar_time_keeping;
|
||||
u32 errors;
|
||||
} hekate_config;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
ERR_LIBSYS_LP0 = (1 << 0),
|
||||
} hsysmodule_t;
|
||||
|
||||
void set_default_configuration();
|
||||
|
||||
#endif /* _CONFIG_H_ */
|
193
source/config/ini.c
Normal file
193
source/config/ini.c
Normal file
|
@ -0,0 +1,193 @@
|
|||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (C) 2018-2019 CTCaer
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "ini.h"
|
||||
#include "../libs/fatfs/ff.h"
|
||||
#include "../mem/heap.h"
|
||||
#include "../utils/dirlist.h"
|
||||
|
||||
static char *_strdup(char *str)
|
||||
{
|
||||
if (!str)
|
||||
return NULL;
|
||||
|
||||
// Remove starting space.
|
||||
if (str[0] == ' ' && strlen(str))
|
||||
str++;
|
||||
|
||||
char *res = (char *)malloc(strlen(str) + 1);
|
||||
strcpy(res, str);
|
||||
|
||||
// Remove trailing space.
|
||||
if (strlen(res) && res[strlen(res) - 1] == ' ')
|
||||
res[strlen(res) - 1] = 0;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
u32 _find_section_name(char *lbuf, u32 lblen, char schar)
|
||||
{
|
||||
u32 i;
|
||||
for (i = 0; i < lblen && lbuf[i] != schar && lbuf[i] != '\n' && lbuf[i] != '\r'; i++)
|
||||
;
|
||||
lbuf[i] = 0;
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
ini_sec_t *_ini_create_section(link_t *dst, ini_sec_t *csec, char *name, u8 type)
|
||||
{
|
||||
if (csec)
|
||||
{
|
||||
list_append(dst, &csec->link);
|
||||
csec = NULL;
|
||||
}
|
||||
|
||||
csec = (ini_sec_t *)malloc(sizeof(ini_sec_t));
|
||||
csec->name = _strdup(name);
|
||||
csec->type = type;
|
||||
|
||||
return csec;
|
||||
}
|
||||
|
||||
int ini_parse(link_t *dst, char *ini_path, bool is_dir)
|
||||
{
|
||||
u32 lblen;
|
||||
u32 pathlen = strlen(ini_path);
|
||||
u32 k = 0;
|
||||
char lbuf[512];
|
||||
char *filelist = NULL;
|
||||
FIL fp;
|
||||
ini_sec_t *csec = NULL;
|
||||
|
||||
char *filename = (char *)malloc(256);
|
||||
|
||||
memcpy(filename, ini_path, pathlen + 1);
|
||||
|
||||
// Get all ini filenames.
|
||||
if (is_dir)
|
||||
{
|
||||
filelist = dirlist(filename, "*.ini", false);
|
||||
if (!filelist)
|
||||
{
|
||||
free(filename);
|
||||
return 0;
|
||||
}
|
||||
memcpy(filename + pathlen, "/", 2);
|
||||
pathlen++;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
// Copy ini filename in path string.
|
||||
if (is_dir)
|
||||
{
|
||||
if (filelist[k * 256])
|
||||
{
|
||||
memcpy(filename + pathlen, &filelist[k * 256], strlen(&filelist[k * 256]) + 1);
|
||||
k++;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
// Open ini.
|
||||
if (f_open(&fp, filename, FA_READ) != FR_OK)
|
||||
{
|
||||
free(filelist);
|
||||
free(filename);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
// Fetch one line.
|
||||
lbuf[0] = 0;
|
||||
f_gets(lbuf, 512, &fp);
|
||||
lblen = strlen(lbuf);
|
||||
|
||||
// Remove trailing newline.
|
||||
if (lbuf[lblen - 1] == '\n' || lbuf[lblen - 1] == '\r')
|
||||
lbuf[lblen - 1] = 0;
|
||||
|
||||
if (lblen > 2 && lbuf[0] == '[') // Create new section.
|
||||
{
|
||||
_find_section_name(lbuf, lblen, ']');
|
||||
|
||||
csec = _ini_create_section(dst, csec, &lbuf[1], INI_CHOICE);
|
||||
list_init(&csec->kvs);
|
||||
}
|
||||
else if (lblen > 2 && lbuf[0] == '{') //Create new caption.
|
||||
{
|
||||
_find_section_name(lbuf, lblen, '}');
|
||||
|
||||
csec = _ini_create_section(dst, csec, &lbuf[1], INI_CAPTION);
|
||||
csec->color = 0xFF0AB9E6;
|
||||
}
|
||||
else if (lblen > 2 && lbuf[0] == '#') //Create empty lines and comments.
|
||||
{
|
||||
_find_section_name(lbuf, lblen, '\0');
|
||||
|
||||
csec = _ini_create_section(dst, csec, &lbuf[1], INI_COMMENT);
|
||||
}
|
||||
else if (lblen < 2)
|
||||
{
|
||||
csec = _ini_create_section(dst, csec, NULL, INI_NEWLINE);
|
||||
}
|
||||
else if (csec && csec->type == INI_CHOICE) //Extract key/value.
|
||||
{
|
||||
u32 i = _find_section_name(lbuf, lblen, '=');
|
||||
|
||||
ini_kv_t *kv = (ini_kv_t *)malloc(sizeof(ini_kv_t));
|
||||
kv->key = _strdup(&lbuf[0]);
|
||||
kv->val = _strdup(&lbuf[i + 1]);
|
||||
list_append(&csec->kvs, &kv->link);
|
||||
}
|
||||
} while (!f_eof(&fp));
|
||||
|
||||
f_close(&fp);
|
||||
|
||||
if (csec)
|
||||
{
|
||||
list_append(dst, &csec->link);
|
||||
if (is_dir)
|
||||
csec = NULL;
|
||||
}
|
||||
} while (is_dir);
|
||||
|
||||
free(filename);
|
||||
free(filelist);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
char *ini_check_payload_section(ini_sec_t *cfg)
|
||||
{
|
||||
if (cfg == NULL)
|
||||
return NULL;
|
||||
|
||||
LIST_FOREACH_ENTRY(ini_kv_t, kv, &cfg->kvs, link)
|
||||
{
|
||||
if (!strcmp("payload", kv->key))
|
||||
return kv->val;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
50
source/config/ini.h
Normal file
50
source/config/ini.h
Normal file
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (C) 2018 CTCaer
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _INI_H_
|
||||
#define _INI_H_
|
||||
|
||||
#include "../utils/types.h"
|
||||
#include "../utils/list.h"
|
||||
|
||||
#define INI_CHOICE 3
|
||||
#define INI_CAPTION 5
|
||||
#define INI_CHGLINE 6
|
||||
#define INI_NEWLINE 0xFE
|
||||
#define INI_COMMENT 0xFF
|
||||
|
||||
typedef struct _ini_kv_t
|
||||
{
|
||||
char *key;
|
||||
char *val;
|
||||
link_t link;
|
||||
} ini_kv_t;
|
||||
|
||||
typedef struct _ini_sec_t
|
||||
{
|
||||
char *name;
|
||||
link_t kvs;
|
||||
link_t link;
|
||||
u32 type;
|
||||
u32 color;
|
||||
} ini_sec_t;
|
||||
|
||||
int ini_parse(link_t *dst, char *ini_path, bool is_dir);
|
||||
char *ini_check_payload_section(ini_sec_t *cfg);
|
||||
|
||||
#endif
|
||||
|
112
source/gfx/di.c
112
source/gfx/di.c
|
@ -18,15 +18,16 @@
|
|||
#include <string.h>
|
||||
|
||||
#include "di.h"
|
||||
#include "../soc/t210.h"
|
||||
#include "../utils/util.h"
|
||||
#include "../soc/i2c.h"
|
||||
#include "../soc/pmc.h"
|
||||
#include "../gfx/gfx.h"
|
||||
#include "../power/max77620.h"
|
||||
#include "../power/max7762x.h"
|
||||
#include "../soc/gpio.h"
|
||||
#include "../soc/pinmux.h"
|
||||
#include "../soc/clock.h"
|
||||
#include "../soc/gpio.h"
|
||||
#include "../soc/i2c.h"
|
||||
#include "../soc/pinmux.h"
|
||||
#include "../soc/pmc.h"
|
||||
#include "../soc/t210.h"
|
||||
#include "../utils/util.h"
|
||||
|
||||
#include "di.inl"
|
||||
|
||||
|
@ -46,54 +47,61 @@ void display_init()
|
|||
max77620_regulator_set_volt_and_flags(REGULATOR_LDO0, 1200000, MAX77620_POWER_MODE_NORMAL); // Configure to 1.2V.
|
||||
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_GPIO7, MAX77620_CNFG_GPIO_OUTPUT_VAL_HIGH | MAX77620_CNFG_GPIO_DRV_PUSHPULL);
|
||||
|
||||
// Enable MIPI CAL, DSI, DISP1, HOST1X, UART_FST_MIPI_CAL, DSIA LP clocks.
|
||||
CLOCK(CLK_RST_CONTROLLER_RST_DEV_H_CLR) = 0x1010000;
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) = 0x1010000;
|
||||
CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_CLR) = 0x18000000;
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_SET) = 0x18000000;
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_X_SET) = 0x20000;
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_UART_FST_MIP_CAL) = 0xA;
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_W_SET) = 0x80000;
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_DSIA_LP) = 0xA;
|
||||
// Enable Display Interface specific clocks.
|
||||
CLOCK(CLK_RST_CONTROLLER_RST_DEV_H_CLR) = 0x1010000; // Clear reset DSI, MIPI_CAL.
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) = 0x1010000; // Set enable clock DSI, MIPI_CAL.
|
||||
|
||||
// DPD idle.
|
||||
CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_CLR) = 0x18000000; // Clear reset DISP1, HOST1X.
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_SET) = 0x18000000; // Set enable clock DISP1, HOST1X.
|
||||
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_X_SET) = 0x20000; // Set enable clock UART_FST_MIPI_CAL.
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_UART_FST_MIPI_CAL) = 10; // Set PLLP_OUT3 and div 6 (17MHz).
|
||||
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_W_SET) = 0x80000; // Set enable clock DSIA_LP.
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_DSIA_LP) = 10; // Set PLLP_OUT and div 6 (68MHz).
|
||||
|
||||
// Disable deap power down.
|
||||
PMC(APBDEV_PMC_IO_DPD_REQ) = 0x40000000;
|
||||
PMC(APBDEV_PMC_IO_DPD2_REQ) = 0x40000000;
|
||||
|
||||
// Config pins.
|
||||
// Config LCD and Backlight pins.
|
||||
PINMUX_AUX(PINMUX_AUX_NFC_EN) &= ~PINMUX_TRISTATE;
|
||||
PINMUX_AUX(PINMUX_AUX_NFC_INT) &= ~PINMUX_TRISTATE;
|
||||
PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) &= ~PINMUX_TRISTATE;
|
||||
PINMUX_AUX(PINMUX_AUX_LCD_BL_EN) &= ~PINMUX_TRISTATE;
|
||||
PINMUX_AUX(PINMUX_AUX_LCD_RST) &= ~PINMUX_TRISTATE;
|
||||
|
||||
gpio_config(GPIO_PORT_I, GPIO_PIN_0 | GPIO_PIN_1, GPIO_MODE_GPIO); // Backlight +-5V.
|
||||
gpio_output_enable(GPIO_PORT_I, GPIO_PIN_0 | GPIO_PIN_1, GPIO_OUTPUT_ENABLE); // Backlight +-5V.
|
||||
// Set Backlight +-5V pins mode and direction
|
||||
gpio_config(GPIO_PORT_I, GPIO_PIN_0 | GPIO_PIN_1, GPIO_MODE_GPIO);
|
||||
gpio_output_enable(GPIO_PORT_I, GPIO_PIN_0 | GPIO_PIN_1, GPIO_OUTPUT_ENABLE);
|
||||
|
||||
// Enable Backlight power.
|
||||
gpio_write(GPIO_PORT_I, GPIO_PIN_0, GPIO_HIGH); // Backlight +5V enable.
|
||||
|
||||
usleep(10000);
|
||||
|
||||
gpio_write(GPIO_PORT_I, GPIO_PIN_1, GPIO_HIGH); // Backlight -5V enable.
|
||||
|
||||
usleep(10000);
|
||||
|
||||
gpio_config(GPIO_PORT_V, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2, GPIO_MODE_GPIO); // Backlight PWM, Enable, Reset.
|
||||
// Configure Backlight pins (PWM, EN, RST).
|
||||
gpio_config(GPIO_PORT_V, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2, GPIO_MODE_GPIO);
|
||||
gpio_output_enable(GPIO_PORT_V, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2, GPIO_OUTPUT_ENABLE);
|
||||
gpio_write(GPIO_PORT_V, GPIO_PIN_1, GPIO_HIGH); // Backlight Enable enable.
|
||||
gpio_write(GPIO_PORT_V, GPIO_PIN_1, GPIO_HIGH); // Enable Backlight EN.
|
||||
|
||||
// Config display interface and display.
|
||||
// Power up supply regulator for display interface.
|
||||
MIPI_CAL(MIPI_CAL_MIPI_BIAS_PAD_CFG2) = 0;
|
||||
|
||||
// Set DISP1 clock source and parrent clock.
|
||||
exec_cfg((u32 *)CLOCK_BASE, _display_config_1, 4);
|
||||
|
||||
// Setup display communication interfaces.
|
||||
exec_cfg((u32 *)DISPLAY_A_BASE, _display_config_2, 94);
|
||||
exec_cfg((u32 *)DSI_BASE, _display_config_3, 61);
|
||||
|
||||
usleep(10000);
|
||||
|
||||
gpio_write(GPIO_PORT_V, GPIO_PIN_2, GPIO_HIGH); // Backlight Reset enable.
|
||||
|
||||
// Enable Backlight Reset.
|
||||
gpio_write(GPIO_PORT_V, GPIO_PIN_2, GPIO_HIGH);
|
||||
usleep(60000);
|
||||
|
||||
// Setups DSI packet configuration and request display id.
|
||||
DSI(_DSIREG(DSI_BTA_TIMING)) = 0x50204;
|
||||
DSI(_DSIREG(DSI_WR_DATA)) = 0x337; // MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE
|
||||
DSI(_DSIREG(DSI_TRIGGER)) = DSI_TRIGGER_HOST;
|
||||
|
@ -122,19 +130,22 @@ void display_init()
|
|||
|
||||
usleep(20000);
|
||||
|
||||
// Configure PLLD for DISP1.
|
||||
exec_cfg((u32 *)CLOCK_BASE, _display_config_6, 3);
|
||||
|
||||
// Finalize DSI configuration.
|
||||
exec_cfg((u32 *)DSI_BASE, _display_config_5, 21);
|
||||
DISPLAY_A(_DIREG(DC_DISP_DISP_CLOCK_CONTROL)) = 4;
|
||||
exec_cfg((u32 *)DSI_BASE, _display_config_7, 10);
|
||||
|
||||
usleep(10000);
|
||||
|
||||
// Calibrate display communication pads.
|
||||
exec_cfg((u32 *)MIPI_CAL_BASE, _display_config_8, 6);
|
||||
exec_cfg((u32 *)DSI_BASE, _display_config_9, 4);
|
||||
exec_cfg((u32 *)MIPI_CAL_BASE, _display_config_10, 16);
|
||||
|
||||
usleep(10000);
|
||||
|
||||
// Enable video display controller.
|
||||
exec_cfg((u32 *)DISPLAY_A_BASE, _display_config_11, 113);
|
||||
}
|
||||
|
||||
|
@ -142,11 +153,10 @@ void display_backlight_pwm_init()
|
|||
{
|
||||
clock_enable_pwm();
|
||||
|
||||
PWM(PWM_CONTROLLER_PWM_CSR_0) = (1 << 31); // Enable PWM
|
||||
PWM(PWM_CONTROLLER_PWM_CSR_0) = PWM_CSR_EN; // Enable PWM and set it to 25KHz PFM.
|
||||
|
||||
PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) = (PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) >> 2) << 2 | 1; // PWM clock source.
|
||||
PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) = (PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) & 0xFFFFFFFC) | 1; // PWM clock source.
|
||||
gpio_config(GPIO_PORT_V, GPIO_PIN_0, GPIO_MODE_SPIO); // Backlight power mode.
|
||||
|
||||
}
|
||||
|
||||
void display_backlight(bool enable)
|
||||
|
@ -167,7 +177,7 @@ void display_backlight_brightness(u32 brightness, u32 step_delay)
|
|||
{
|
||||
for (u32 i = old_value; i < brightness + 1; i++)
|
||||
{
|
||||
PWM(PWM_CONTROLLER_PWM_CSR_0) = (1 << 31) | (i << 16); // Enable PWM
|
||||
PWM(PWM_CONTROLLER_PWM_CSR_0) = PWM_CSR_EN | (i << 16); // Enable PWM and set it to 25KHz PFM.
|
||||
usleep(step_delay);
|
||||
}
|
||||
}
|
||||
|
@ -175,7 +185,7 @@ void display_backlight_brightness(u32 brightness, u32 step_delay)
|
|||
{
|
||||
for (u32 i = old_value; i > brightness; i--)
|
||||
{
|
||||
PWM(PWM_CONTROLLER_PWM_CSR_0) = (1 << 31) | (i << 16); // Enable PWM
|
||||
PWM(PWM_CONTROLLER_PWM_CSR_0) = PWM_CSR_EN | (i << 16); // Enable PWM and set it to 25KHz PFM.
|
||||
usleep(step_delay);
|
||||
}
|
||||
}
|
||||
|
@ -191,13 +201,14 @@ void display_end()
|
|||
DSI(_DSIREG(DSI_WR_DATA)) = 0x2805; // MIPI_DCS_SET_DISPLAY_OFF
|
||||
|
||||
DISPLAY_A(_DIREG(DC_CMD_STATE_ACCESS)) = READ_MUX | WRITE_MUX;
|
||||
DSI(_DSIREG(DSI_VIDEO_MODE_CONTROL)) = 0;
|
||||
DSI(_DSIREG(DSI_VIDEO_MODE_CONTROL)) = 0; // Disable host cmd packet.
|
||||
|
||||
// De-initialize video controller.
|
||||
exec_cfg((u32 *)DISPLAY_A_BASE, _display_config_12, 17);
|
||||
exec_cfg((u32 *)DSI_BASE, _display_config_13, 16);
|
||||
|
||||
usleep(10000);
|
||||
|
||||
// De-initialize display panel.
|
||||
if (_display_ver == 0x10)
|
||||
exec_cfg((u32 *)DSI_BASE, _display_config_14, 22);
|
||||
|
||||
|
@ -206,31 +217,31 @@ void display_end()
|
|||
|
||||
usleep(50000);
|
||||
|
||||
// Disable display and backlight pins.
|
||||
gpio_write(GPIO_PORT_V, GPIO_PIN_2, GPIO_LOW); //Backlight Reset disable.
|
||||
|
||||
usleep(10000);
|
||||
|
||||
gpio_write(GPIO_PORT_I, GPIO_PIN_1, GPIO_LOW); //Backlight -5V disable.
|
||||
|
||||
usleep(10000);
|
||||
|
||||
gpio_write(GPIO_PORT_I, GPIO_PIN_0, GPIO_LOW); //Backlight +5V disable.
|
||||
|
||||
usleep(10000);
|
||||
|
||||
// Disable clocks.
|
||||
CLOCK(CLK_RST_CONTROLLER_RST_DEV_H_SET) = 0x1010000;
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_CLR) = 0x1010000;
|
||||
CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = 0x18000000;
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_CLR) = 0x18000000;
|
||||
// Disable Display Interface specific clocks.
|
||||
CLOCK(CLK_RST_CONTROLLER_RST_DEV_H_SET) = 0x1010000; // Set reset clock DSI, MIPI_CAL.
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_CLR) = 0x1010000; // Clear enable clock DSI, MIPI_CAL.
|
||||
CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = 0x18000000; // Set reset DISP1, HOST1X.
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_CLR) = 0x18000000; // Clear enable DISP1, HOST1X.
|
||||
|
||||
// Power down pads.
|
||||
DSI(_DSIREG(DSI_PAD_CONTROL_0)) = DSI_PAD_CONTROL_VS1_PULLDN_CLK | DSI_PAD_CONTROL_VS1_PULLDN(0xF) | DSI_PAD_CONTROL_VS1_PDIO_CLK | DSI_PAD_CONTROL_VS1_PDIO(0xF);
|
||||
DSI(_DSIREG(DSI_POWER_CONTROL)) = 0;
|
||||
|
||||
// Switch to automatic function mode.
|
||||
gpio_config(GPIO_PORT_V, GPIO_PIN_0, GPIO_MODE_SPIO); // Backlight PWM.
|
||||
|
||||
PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) = (PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) & ~PINMUX_TRISTATE) | PINMUX_TRISTATE;
|
||||
PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) = (PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) >> 2) << 2 | 1;
|
||||
PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) = (PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) & 0xFFFFFFFC)| 1;
|
||||
}
|
||||
|
||||
void display_color_screen(u32 color)
|
||||
|
@ -243,7 +254,6 @@ void display_color_screen(u32 color)
|
|||
DISPLAY_A(_DIREG(DC_WIN_CD_WIN_OPTIONS)) = 0;
|
||||
DISPLAY_A(_DIREG(DC_DISP_BLEND_BACKGROUND_COLOR)) = color;
|
||||
DISPLAY_A(_DIREG(DC_CMD_STATE_CONTROL)) = (DISPLAY_A(_DIREG(DC_CMD_STATE_CONTROL)) & 0xFFFFFFFE) | GENERAL_ACT_REQ;
|
||||
|
||||
usleep(35000);
|
||||
|
||||
display_backlight(true);
|
||||
|
@ -252,11 +262,11 @@ void display_color_screen(u32 color)
|
|||
u32 *display_init_framebuffer()
|
||||
{
|
||||
// Sanitize framebuffer area.
|
||||
memset((u32 *)0xC0000000, 0, 0x3C0000);
|
||||
// This configures the framebuffer @ 0xC0000000 with a resolution of 1280x720 (line stride 768).
|
||||
memset((u32 *)FB_ADDRESS, 0, 0x3C0000);
|
||||
// This configures the framebuffer @ IPL_FB_ADDRESS with a resolution of 1280x720 (line stride 720).
|
||||
exec_cfg((u32 *)DISPLAY_A_BASE, cfg_display_framebuffer, 32);
|
||||
|
||||
usleep(35000);
|
||||
|
||||
return (u32 *)0xC0000000;
|
||||
return (u32 *)FB_ADDRESS;
|
||||
}
|
||||
|
||||
|
|
|
@ -20,6 +20,8 @@
|
|||
|
||||
#include "../utils/types.h"
|
||||
|
||||
#define FB_ADDRESS 0xC0000000
|
||||
|
||||
/*! Display registers. */
|
||||
#define _DIREG(reg) ((reg) * 4)
|
||||
|
||||
|
@ -233,7 +235,7 @@
|
|||
#define UV_LINE_STRIDE(x) (((x) & 0xffff) << 16)
|
||||
#define DC_WIN_DV_CONTROL 0x70E
|
||||
|
||||
// The following registers are A/B/C shadows of the 0xBC0/0xDC0/0xFC0 registers (see DISPLAY_WINDOW_HEADER).
|
||||
/*! The following registers are A/B/C shadows of the 0xBC0/0xDC0/0xFC0 registers (see DISPLAY_WINDOW_HEADER). */
|
||||
#define DC_WINBUF_START_ADDR 0x800
|
||||
#define DC_WINBUF_ADDR_H_OFFSET 0x806
|
||||
#define DC_WINBUF_ADDR_V_OFFSET 0x808
|
||||
|
@ -333,7 +335,7 @@
|
|||
#define DSI_PAD_CONTROL_VS1_PDIO_CLK (1 << 8)
|
||||
#define DSI_PAD_CONTROL_VS1_PDIO(x) (((x) & 0xf) << 0)
|
||||
|
||||
#define DSI_PAD_CONTROL_CD 0x4c
|
||||
#define DSI_PAD_CONTROL_CD 0x4C
|
||||
#define DSI_VIDEO_MODE_CONTROL 0x4E
|
||||
|
||||
#define DSI_PAD_CONTROL_1 0x4F
|
||||
|
|
|
@ -122,7 +122,7 @@ static const cfg_op_t _display_config_2[94] = {
|
|||
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT},
|
||||
{DC_WIN_WIN_OPTIONS, 0},
|
||||
{DC_DISP_DISP_WIN_OPTIONS, 0},
|
||||
{DC_CMD_DISPLAY_COMMAND, 0},
|
||||
{DC_CMD_DISPLAY_COMMAND, DISP_CTRL_MODE_STOP},
|
||||
{DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE | WIN_B_UPDATE | WIN_C_UPDATE},
|
||||
{DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ | WIN_B_ACT_REQ | WIN_C_ACT_REQ}
|
||||
};
|
||||
|
@ -405,7 +405,7 @@ static const cfg_op_t _display_config_11[113] = {
|
|||
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT},
|
||||
{DC_WIN_WIN_OPTIONS, 0},
|
||||
{DC_DISP_DISP_WIN_OPTIONS, 0},
|
||||
{DC_CMD_DISPLAY_COMMAND, 0},
|
||||
{DC_CMD_DISPLAY_COMMAND, DISP_CTRL_MODE_STOP},
|
||||
{DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE | WIN_B_UPDATE | WIN_C_UPDATE},
|
||||
{DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ | WIN_B_ACT_REQ | WIN_C_ACT_REQ},
|
||||
{DC_CMD_STATE_ACCESS, 0},
|
||||
|
@ -455,7 +455,7 @@ static const cfg_op_t _display_config_12[17] = {
|
|||
{DC_CMD_STATE_ACCESS, 0},
|
||||
{DC_CMD_INT_ENABLE, 0},
|
||||
{DC_CMD_CONT_SYNCPT_VSYNC, 0},
|
||||
{DC_CMD_DISPLAY_COMMAND, 0},
|
||||
{DC_CMD_DISPLAY_COMMAND, DISP_CTRL_MODE_STOP},
|
||||
{DC_CMD_STATE_CONTROL, GENERAL_UPDATE},
|
||||
{DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ},
|
||||
{DC_CMD_STATE_CONTROL, GENERAL_UPDATE},
|
||||
|
@ -548,7 +548,7 @@ static const cfg_op_t cfg_display_framebuffer[32] = {
|
|||
{DC_WIN_LINE_STRIDE, UV_LINE_STRIDE(720 * 2) | LINE_STRIDE(720 * 4)}, //768*2x768*4 (= 0x600 x 0xC00) bytes, see TRM for alignment requirements.
|
||||
{DC_WIN_BUFFER_CONTROL, 0},
|
||||
{DC_WINBUF_SURFACE_KIND, 0}, //Regular surface.
|
||||
{DC_WINBUF_START_ADDR, 0xC0000000}, //Framebuffer address.
|
||||
{DC_WINBUF_START_ADDR, FB_ADDRESS}, //Framebuffer address.
|
||||
{DC_WINBUF_ADDR_H_OFFSET, 0},
|
||||
{DC_WINBUF_ADDR_V_OFFSET, 0},
|
||||
{DC_WIN_WIN_OPTIONS, 0},
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include "gfx.h"
|
||||
//#include "../utils/types.h"
|
||||
|
||||
static const u8 _gfx_font[] = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Char 032 ( )
|
||||
|
@ -129,12 +128,12 @@ void gfx_init_ctxt(u32 *fb, u32 width, u32 height, u32 stride)
|
|||
|
||||
void gfx_clear_grey(u8 color)
|
||||
{
|
||||
memset(gfx_ctxt.fb, color, 0x3C0000);
|
||||
memset(gfx_ctxt.fb, color, gfx_ctxt.width * gfx_ctxt.height * 4);
|
||||
}
|
||||
|
||||
void gfx_clear_color(u32 color)
|
||||
{
|
||||
for (u32 i = 0; i < gfx_ctxt.height * gfx_ctxt.stride; i++)
|
||||
for (u32 i = 0; i < gfx_ctxt.width * gfx_ctxt.height; i++)
|
||||
gfx_ctxt.fb[i] = color;
|
||||
}
|
||||
|
||||
|
@ -153,8 +152,7 @@ void gfx_con_init()
|
|||
gfx_con.savedy = 0;
|
||||
gfx_con.fgcol = 0xFFCCCCCC;
|
||||
gfx_con.fillbg = 1;
|
||||
//gfx_con.bgcol = 0xFF1B1B1B;
|
||||
gfx_con.bgcol = 0xFF009600;
|
||||
gfx_con.bgcol = 0xFF1B1B1B;
|
||||
gfx_con.mute = 0;
|
||||
}
|
||||
|
||||
|
@ -217,7 +215,7 @@ void gfx_putc(char c)
|
|||
}
|
||||
}
|
||||
gfx_con.x += 16;
|
||||
if (gfx_con.x >= gfx_ctxt.width - 8) {
|
||||
if (gfx_con.x >= gfx_ctxt.width - 16) {
|
||||
gfx_con.x = 0;
|
||||
gfx_con.y += 16;
|
||||
}
|
||||
|
@ -229,9 +227,6 @@ void gfx_putc(char c)
|
|||
if (gfx_con.y > gfx_ctxt.height - 16)
|
||||
gfx_con.y = 0;
|
||||
}
|
||||
else if (c == '\r'){
|
||||
gfx_con.x = 0;
|
||||
}
|
||||
break;
|
||||
case 8:
|
||||
default:
|
||||
|
@ -268,7 +263,6 @@ void gfx_putc(char c)
|
|||
}
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void gfx_puts(const char *s)
|
||||
|
@ -371,8 +365,6 @@ void gfx_printf(const char *fmt, ...)
|
|||
_gfx_putn(va_arg(ap, u32), 10, fill, fcnt);
|
||||
break;
|
||||
case 'p':
|
||||
gfx_con.bgcol = va_arg(ap, u32);
|
||||
break;
|
||||
case 'P':
|
||||
case 'x':
|
||||
case 'X':
|
||||
|
@ -495,14 +487,6 @@ void gfx_line(int x0, int y0, int x1, int y1, u32 color)
|
|||
}
|
||||
}
|
||||
|
||||
void gfx_box(int x0, int y0, int x1, int y1, u32 color){
|
||||
int i = y0;
|
||||
while(y1 >= i){
|
||||
gfx_line(x0, i, x1, i, color);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
void gfx_set_rect_grey(const u8 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y)
|
||||
{
|
||||
u32 pos = 0;
|
||||
|
@ -516,6 +500,13 @@ void gfx_set_rect_grey(const u8 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos
|
|||
}
|
||||
}
|
||||
|
||||
void gfx_box(int x0, int y0, int x1, int y1, u32 color){
|
||||
int i = y0;
|
||||
while(y1 >= i){
|
||||
gfx_line(x0, i, x1, i, color);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
void gfx_set_rect_rgb(const u8 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y)
|
||||
{
|
||||
|
|
|
@ -41,13 +41,13 @@ void gfx_hexdump(u32 base, const u8 *buf, u32 len);
|
|||
|
||||
void gfx_set_pixel(u32 x, u32 y, u32 color);
|
||||
void gfx_line(int x0, int y0, int x1, int y1, u32 color);
|
||||
void gfx_box(int x0, int y0, int x1, int y1, u32 color);
|
||||
void gfx_put_small_sep();
|
||||
void gfx_put_big_sep();
|
||||
void gfx_set_rect_grey(const u8 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y);
|
||||
void gfx_set_rect_rgb(const u8 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y);
|
||||
void gfx_set_rect_argb(const u32 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y);
|
||||
void gfx_render_bmp_argb(const u32 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y);
|
||||
void gfx_box(int x0, int y0, int x1, int y1, u32 color);
|
||||
|
||||
// Global gfx console and context.
|
||||
gfx_ctxt_t gfx_ctxt;
|
||||
|
|
225
source/gfx/tui.c
Normal file
225
source/gfx/tui.c
Normal file
|
@ -0,0 +1,225 @@
|
|||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (c) 2018 CTCaer
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "di.h"
|
||||
#include "tui.h"
|
||||
#include "../utils/btn.h"
|
||||
#include "../config/config.h"
|
||||
#include "../power/max17050.h"
|
||||
#include "../utils/util.h"
|
||||
|
||||
#ifdef MENU_LOGO_ENABLE
|
||||
extern u8 *Kc_MENU_LOGO;
|
||||
#define X_MENU_LOGO 119
|
||||
#define Y_MENU_LOGO 57
|
||||
#define X_POS_MENU_LOGO 577
|
||||
#define Y_POS_MENU_LOGO 1179
|
||||
#endif //MENU_LOGO_ENABLE
|
||||
|
||||
extern hekate_config h_cfg;
|
||||
|
||||
void tui_sbar(bool force_update)
|
||||
{
|
||||
u32 cx, cy;
|
||||
|
||||
u32 timePassed = get_tmr_s() - h_cfg.sbar_time_keeping;
|
||||
if (!force_update)
|
||||
if (timePassed < 5)
|
||||
return;
|
||||
|
||||
u8 prevFontSize = gfx_con.fntsz;
|
||||
gfx_con.fntsz = 16;
|
||||
h_cfg.sbar_time_keeping = get_tmr_s();
|
||||
|
||||
u32 battPercent = 0;
|
||||
int battVoltCurr = 0;
|
||||
|
||||
gfx_con_getpos(&cx, &cy);
|
||||
gfx_con_setpos(0, 1260);
|
||||
|
||||
max17050_get_property(MAX17050_RepSOC, (int *)&battPercent);
|
||||
max17050_get_property(MAX17050_VCELL, &battVoltCurr);
|
||||
|
||||
gfx_clear_partial_grey(0x30, 1256, 24);
|
||||
gfx_printf("%K%k Battery: %d.%d%% (%d mV) - Charge:", 0xFF303030, 0xFF888888,
|
||||
(battPercent >> 8) & 0xFF, (battPercent & 0xFF) / 26, battVoltCurr);
|
||||
|
||||
max17050_get_property(MAX17050_Current, &battVoltCurr);
|
||||
|
||||
if (battVoltCurr >= 0)
|
||||
gfx_printf(" %k+%d mA%k%K\n",
|
||||
0xFF008800, battVoltCurr / 1000, 0xFFCCCCCC, 0xFF1B1B1B);
|
||||
else
|
||||
gfx_printf(" %k-%d mA%k%K\n",
|
||||
0xFF880000, (~battVoltCurr) / 1000, 0xFFCCCCCC, 0xFF1B1B1B);
|
||||
gfx_con.fntsz = prevFontSize;
|
||||
gfx_con_setpos(cx, cy);
|
||||
}
|
||||
|
||||
void tui_pbar(int x, int y, u32 val, u32 fgcol, u32 bgcol)
|
||||
{
|
||||
u32 cx, cy;
|
||||
if (val > 200)
|
||||
val = 200;
|
||||
|
||||
gfx_con_getpos(&cx, &cy);
|
||||
|
||||
gfx_con_setpos(x, y);
|
||||
|
||||
gfx_printf("%k[%3d%%]%k", fgcol, val, 0xFFCCCCCC);
|
||||
|
||||
x += 7 * gfx_con.fntsz;
|
||||
|
||||
for (int i = 0; i < (gfx_con.fntsz >> 3) * 6; i++)
|
||||
{
|
||||
gfx_line(x, y + i + 1, x + 3 * val, y + i + 1, fgcol);
|
||||
gfx_line(x + 3 * val, y + i + 1, x + 3 * 100, y + i + 1, bgcol);
|
||||
}
|
||||
|
||||
gfx_con_setpos(cx, cy);
|
||||
|
||||
// Update status bar.
|
||||
tui_sbar(false);
|
||||
}
|
||||
|
||||
void *tui_do_menu(menu_t *menu)
|
||||
{
|
||||
int idx = 0, prev_idx = 0, cnt = 0x7FFFFFFF;
|
||||
|
||||
gfx_clear_partial_grey(0x1B, 0, 1256);
|
||||
tui_sbar(true);
|
||||
|
||||
#ifdef MENU_LOGO_ENABLE
|
||||
gfx_set_rect_rgb(Kc_MENU_LOGO,
|
||||
X_MENU_LOGO, Y_MENU_LOGO, X_POS_MENU_LOGO, Y_POS_MENU_LOGO);
|
||||
#endif //MENU_LOGO_ENABLE
|
||||
|
||||
while (true)
|
||||
{
|
||||
gfx_con_setcol(0xFFCCCCCC, 1, 0xFF1B1B1B);
|
||||
gfx_con_setpos(menu->x, menu->y);
|
||||
gfx_printf("[%kLo%kck%kpi%kck%k_R%kCM%k v%d.%d.%d%k]\n\n",
|
||||
colors[0], colors[1], colors[2], colors[3], colors[4], colors[5], 0xFFFF00FF, LP_VER_MJ, LP_VER_MN, LP_VER_BF, 0xFFCCCCCC);
|
||||
|
||||
// Skip caption or seperator lines selection.
|
||||
while (menu->ents[idx].type == MENT_CAPTION ||
|
||||
menu->ents[idx].type == MENT_CHGLINE)
|
||||
{
|
||||
if (prev_idx <= idx || (!idx && prev_idx == cnt - 1))
|
||||
{
|
||||
idx++;
|
||||
if (idx > (cnt - 1))
|
||||
{
|
||||
idx = 0;
|
||||
prev_idx = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
idx--;
|
||||
if (idx < 0)
|
||||
{
|
||||
idx = cnt - 1;
|
||||
prev_idx = cnt;
|
||||
}
|
||||
}
|
||||
}
|
||||
prev_idx = idx;
|
||||
|
||||
// Draw the menu.
|
||||
for (cnt = 0; menu->ents[cnt].type != MENT_END; cnt++)
|
||||
{
|
||||
if (cnt == idx)
|
||||
gfx_con_setcol(0xFF1B1B1B, 1, 0xFFCCCCCC);
|
||||
else
|
||||
gfx_con_setcol(0xFFCCCCCC, 1, 0xFF1B1B1B);
|
||||
if (menu->ents[cnt].type != MENT_CHGLINE && menu->ents[cnt].type != MENT_MENU) {
|
||||
if (cnt == idx)
|
||||
gfx_printf(" %s", menu->ents[cnt].caption);
|
||||
else
|
||||
gfx_printf("%k %s", menu->ents[cnt].color, menu->ents[cnt].caption);
|
||||
}
|
||||
if(menu->ents[cnt].type == MENT_MENU)
|
||||
gfx_printf("%k...", 0xFF0099EE);
|
||||
gfx_printf(" \n");
|
||||
}
|
||||
gfx_con_setcol(0xFFCCCCCC, 1, 0xFF1B1B1B);
|
||||
gfx_putc('\n');
|
||||
|
||||
// Print help and battery status.
|
||||
gfx_con_setpos(0, 1127);
|
||||
if (h_cfg.emummc_force_disable)
|
||||
gfx_printf("%kNo emuMMC config found.\n", 0xFF800000);
|
||||
gfx_con_setpos(0, 1191);
|
||||
gfx_printf("%k VOL: Move up/down\n PWR: Select option%k", 0xFF555555, 0xFFCCCCCC);
|
||||
|
||||
display_backlight_brightness(h_cfg.backlight, 1000);
|
||||
|
||||
// Wait for user command.
|
||||
u32 btn = btn_wait();
|
||||
|
||||
if (btn & BTN_VOL_DOWN && idx < (cnt - 1))
|
||||
idx++;
|
||||
else if (btn & BTN_VOL_DOWN && idx == (cnt - 1))
|
||||
{
|
||||
idx = 0;
|
||||
prev_idx = -1;
|
||||
}
|
||||
if (btn & BTN_VOL_UP && idx > 0)
|
||||
idx--;
|
||||
else if (btn & BTN_VOL_UP && idx == 0)
|
||||
{
|
||||
idx = cnt - 1;
|
||||
prev_idx = cnt;
|
||||
}
|
||||
if (btn & BTN_POWER)
|
||||
{
|
||||
ment_t *ent = &menu->ents[idx];
|
||||
switch (ent->type)
|
||||
{
|
||||
case MENT_HANDLER:
|
||||
ent->handler(ent->data);
|
||||
break;
|
||||
case MENT_MENU:
|
||||
return tui_do_menu(ent->menu);
|
||||
break;
|
||||
case MENT_DATA:
|
||||
return ent->data;
|
||||
break;
|
||||
case MENT_BACK:
|
||||
return NULL;
|
||||
break;
|
||||
case MENT_HDLR_RE:
|
||||
ent->handler(ent);
|
||||
if (!ent->data)
|
||||
return NULL;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
gfx_con.fntsz = 16;
|
||||
gfx_clear_partial_grey(0x1B, 0, 1256);
|
||||
#ifdef MENU_LOGO_ENABLE
|
||||
gfx_set_rect_rgb(Kc_MENU_LOGO,
|
||||
X_MENU_LOGO, Y_MENU_LOGO, X_POS_MENU_LOGO, Y_POS_MENU_LOGO);
|
||||
#endif //MENU_LOGO_ENABLE
|
||||
}
|
||||
tui_sbar(false);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
66
source/gfx/tui.h
Normal file
66
source/gfx/tui.h
Normal file
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (C) 2018 CTCaer
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _TUI_H_
|
||||
#define _TUI_H_
|
||||
|
||||
#include "../utils/types.h"
|
||||
#include "gfx.h"
|
||||
|
||||
#define MENT_END 0
|
||||
#define MENT_HANDLER 1
|
||||
#define MENT_MENU 2
|
||||
#define MENT_DATA 3
|
||||
#define MENT_BACK 4
|
||||
#define MENT_CAPTION 5
|
||||
#define MENT_CHGLINE 6
|
||||
#define MENT_HDLR_RE 7
|
||||
|
||||
typedef struct _ment_t
|
||||
{
|
||||
u32 type;
|
||||
const char *caption;
|
||||
u32 color;
|
||||
void *data;
|
||||
union
|
||||
{
|
||||
void(*handler)(void *);
|
||||
struct _menu_t *menu;
|
||||
};
|
||||
} ment_t;
|
||||
|
||||
typedef struct _menu_t
|
||||
{
|
||||
ment_t *ents;
|
||||
const char *caption;
|
||||
u32 x;
|
||||
u32 y;
|
||||
} menu_t;
|
||||
|
||||
#define MDEF_END() {MENT_END}
|
||||
#define MDEF_HANDLER(caption, _handler, color) { MENT_HANDLER, caption, color, NULL, { .handler = _handler } }
|
||||
#define MDEF_HANDLER_EX(caption, data, _handler, color) { MENT_HANDLER, caption, color, data, { .handler = _handler } }
|
||||
#define MDEF_MENU(caption, _menu) { MENT_MENU, caption, 0, NULL, { .menu = _menu } }
|
||||
#define MDEF_BACK() { MENT_BACK, "Back" }
|
||||
#define MDEF_CAPTION(caption, color) { MENT_CAPTION, caption, color }
|
||||
#define MDEF_CHGLINE() {MENT_CHGLINE}
|
||||
|
||||
void tui_sbar(bool force_update);
|
||||
void tui_pbar(int x, int y, u32 val, u32 fgcol, u32 bgcol);
|
||||
void *tui_do_menu(menu_t *menu);
|
||||
|
||||
#endif
|
|
@ -22,20 +22,25 @@
|
|||
#include "pkg1.h"
|
||||
#include "../sec/se.h"
|
||||
|
||||
#define HASH_ORDER_100_100 {2, 3, 4, 0, 5, 6, 1}
|
||||
#define HASH_ORDER_200_510 {2, 3, 4, 0, 5, 7, 10, 12, 11, 6, 8, 1}
|
||||
#define HASH_ORDER_600_620 {6, 5, 10, 7, 8, 2, 3, 4, 0, 12, 11, 1}
|
||||
#define HASH_ORDER_700_9xx {6, 5, 10, 7, 8, 2, 3, 4, 0, 12, 11, 9, 1}
|
||||
|
||||
static const pkg1_id_t _pkg1_ids[] = {
|
||||
{ "20161121183008", 0 }, //1.0.0
|
||||
{ "20170210155124", 0 }, //2.0.0 - 2.3.0
|
||||
{ "20170519101410", 1 }, //3.0.0
|
||||
{ "20170710161758", 2 }, //3.0.1 - 3.0.2
|
||||
{ "20170921172629", 3 }, //4.0.0 - 4.1.0
|
||||
{ "20180220163747", 4 }, //5.0.0 - 5.1.0
|
||||
{ "20180802162753", 5 }, //6.0.0 - 6.1.0
|
||||
{ "20181107105733", 6 }, //6.2.0
|
||||
{ "20181218175730", 7 }, //7.0.0
|
||||
{ "20190208150037", 7 }, //7.0.1
|
||||
{ "20190314172056", 7 }, //8.0.0
|
||||
{ "20190531152432", 8 }, //8.1.0
|
||||
{ "20190809135709", 9 }, //9.0.0
|
||||
{ "20161121183008", 0, {0x1b517, 0x125bc2, 1, 16, 6, HASH_ORDER_100_100, 0, 0x449dc} }, //1.0.0
|
||||
{ "20170210155124", 0, {0x1d226, 0x26fe, 0, 16, 11, HASH_ORDER_200_510, 0x557b, 0x3d41a} }, //2.0.0 - 2.3.0
|
||||
{ "20170519101410", 1, {0x1ffa6, 0x298b, 0, 16, 11, HASH_ORDER_200_510, 0x552d, 0x3cb81} }, //3.0.0
|
||||
{ "20170710161758", 2, {0x20026, 0x29ab, 0, 16, 11, HASH_ORDER_200_510, 0x552d, 0x3cb81} }, //3.0.1 - 3.0.2
|
||||
{ "20170921172629", 3, {0x1c64c, 0x37eb, 0, 16, 11, HASH_ORDER_200_510, 0x5382, 0x3711c} }, //4.0.0 - 4.1.0
|
||||
{ "20180220163747", 4, {0x1f3b4, 0x465b, 0, 16, 11, HASH_ORDER_200_510, 0x5a63, 0x37901} }, //5.0.0 - 5.1.0
|
||||
{ "20180802162753", 5, {0x27350, 0x17ff5, 1, 8, 11, HASH_ORDER_600_620, 0x5674, 0x1d5be} }, //6.0.0 - 6.1.0
|
||||
{ "20181107105733", 6, {0x27350, 0x17ff5, 1, 8, 11, HASH_ORDER_600_620, 0x5674, 0x1d5be} }, //6.2.0
|
||||
{ "20181218175730", 7, {0x29c50, 0x6a73, 0, 8, 12, HASH_ORDER_700_9xx, 0x5563, 0x1d437} }, //7.0.0
|
||||
{ "20190208150037", 7, {0x29c50, 0x6a73, 0, 8, 12, HASH_ORDER_700_9xx, 0x5563, 0x1d437} }, //7.0.1
|
||||
{ "20190314172056", 7, {0x29c50, 0x6a73, 0, 8, 12, HASH_ORDER_700_9xx, 0x5563, 0x1d437} }, //8.0.0 - 8.0.1
|
||||
{ "20190531152432", 8, {0x29c50, 0x6a73, 0, 8, 12, HASH_ORDER_700_9xx, 0x5563, 0x1d437} }, //8.1.0
|
||||
{ "20190809135709", 9, {0x2ec10, 0x5573, 0, 1, 12, HASH_ORDER_700_9xx, 0x6495, 0x1d807} }, //9.0.0 - 9.0.1
|
||||
{ NULL } //End.
|
||||
};
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -39,14 +39,25 @@ static u32 _pkg2_calc_kip1_size(pkg2_kip1_t *kip1)
|
|||
return size;
|
||||
}
|
||||
|
||||
void pkg2_parse_kips(link_t *info, pkg2_hdr_t *pkg2)
|
||||
void pkg2_get_newkern_info(u8 *kern_data)
|
||||
{
|
||||
u32 info_op = *(u32 *)(kern_data + PKG2_NEWKERN_GET_INI1);
|
||||
pkg2_newkern_ini1_val = ((info_op & 0xFFFF) >> 3) + PKG2_NEWKERN_GET_INI1; // Parse ADR and PC.
|
||||
|
||||
pkg2_newkern_ini1_start = *(u32 *)(kern_data + pkg2_newkern_ini1_val);
|
||||
pkg2_newkern_ini1_end = *(u32 *)(kern_data + pkg2_newkern_ini1_val + 0x8);
|
||||
}
|
||||
|
||||
void pkg2_parse_kips(link_t *info, pkg2_hdr_t *pkg2, bool *new_pkg2)
|
||||
{
|
||||
u8 *ptr;
|
||||
// Check for new pkg2 type.
|
||||
if (!pkg2->sec_size[PKG2_SEC_INI1])
|
||||
{
|
||||
u32 kernel_ini1_off = *(u32 *)(pkg2->data + PKG2_NEWKERN_INI1_START);
|
||||
ptr = pkg2->data + kernel_ini1_off;
|
||||
pkg2_get_newkern_info(pkg2->data);
|
||||
|
||||
ptr = pkg2->data + pkg2_newkern_ini1_start;
|
||||
*new_pkg2 = true;
|
||||
}
|
||||
else
|
||||
ptr = pkg2->data + pkg2->sec_size[PKG2_SEC_KERNEL];
|
||||
|
@ -128,7 +139,6 @@ 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;
|
||||
|
||||
|
|
|
@ -26,7 +26,11 @@
|
|||
#define PKG2_SEC_KERNEL 0
|
||||
#define PKG2_SEC_INI1 1
|
||||
|
||||
#define PKG2_NEWKERN_INI1_START 0x168
|
||||
#define PKG2_NEWKERN_GET_INI1 0x44
|
||||
|
||||
u32 pkg2_newkern_ini1_val;
|
||||
u32 pkg2_newkern_ini1_start;
|
||||
u32 pkg2_newkern_ini1_end;
|
||||
|
||||
typedef struct _pkg2_hdr_t
|
||||
{
|
||||
|
@ -83,7 +87,7 @@ typedef struct _pkg2_kip1_info_t
|
|||
link_t link;
|
||||
} pkg2_kip1_info_t;
|
||||
|
||||
void pkg2_parse_kips(link_t *info, pkg2_hdr_t *pkg2);
|
||||
void pkg2_parse_kips(link_t *info, pkg2_hdr_t *pkg2, bool *new_pkg2);
|
||||
int pkg2_decompress_kip(pkg2_kip1_info_t* ki, u32 sectsToDecomp);
|
||||
pkg2_hdr_t *pkg2_decrypt(void *data);
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "../gfx/di.h"
|
||||
#include "../libs/fatfs/ff.h"
|
||||
#include "../mem/heap.h"
|
||||
#include "../soc/hw_init.h"
|
||||
#include "../soc/pmc.h"
|
||||
#include "../soc/t210.h"
|
||||
#include "../storage/nx_emmc.h"
|
||||
|
@ -55,6 +56,7 @@ u8 warmboot_reboot[] = {
|
|||
#define SEPT_STG2_ADDR (SEPT_PK1T_ADDR + 0x60E0)
|
||||
#define SEPT_PKG_SZ (0x2F100 + WB_RST_SIZE)
|
||||
|
||||
extern u32 color_idx;
|
||||
extern boot_cfg_t b_cfg;
|
||||
extern void sd_unmount();
|
||||
extern void reloc_patcher(u32 payload_dst, u32 payload_src, u32 payload_size);
|
||||
|
@ -80,10 +82,17 @@ int reboot_to_sept(const u8 *tsec_fw, const u32 tsec_size, const u32 kb)
|
|||
f_close(&fp);
|
||||
|
||||
// Copy sept-secondary.
|
||||
if ((kb == 7) && f_open(&fp, "sd:/sept/sept-secondary.enc", FA_READ) && f_open(&fp, "sd:/sept/sept-secondary_00.enc", FA_READ))
|
||||
if (kb < KB_FIRMWARE_VERSION_810)
|
||||
{
|
||||
if (f_open(&fp, "sd:/sept/sept-secondary_00.enc", FA_READ))
|
||||
if (f_open(&fp, "sd:/sept/sept-secondary.enc", FA_READ)) // Try the deprecated version.
|
||||
goto error;
|
||||
else if ((kb == 8) && f_open(&fp, "sd:/sept/sept-secondary_01.enc", FA_READ))
|
||||
}
|
||||
else
|
||||
{
|
||||
if (f_open(&fp, "sd:/sept/sept-secondary_01.enc", FA_READ))
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (f_read(&fp, (u8 *)SEPT_STG2_ADDR, f_size(&fp), NULL))
|
||||
{
|
||||
|
@ -98,8 +107,10 @@ int reboot_to_sept(const u8 *tsec_fw, const u32 tsec_size, const u32 kb)
|
|||
|
||||
tmp_cfg->boot_cfg |= BOOT_CFG_SEPT_RUN;
|
||||
|
||||
if (f_open(&fp, "sd:/sept/payload.bin", FA_READ | FA_WRITE))
|
||||
if (f_open(&fp, "sd:/sept/payload.bin", FA_READ | FA_WRITE)) {
|
||||
free(tmp_cfg);
|
||||
goto error;
|
||||
}
|
||||
|
||||
f_lseek(&fp, PATCHED_RELOC_SZ);
|
||||
f_write(&fp, tmp_cfg, sizeof(boot_cfg_t), NULL);
|
||||
|
@ -107,8 +118,7 @@ int reboot_to_sept(const u8 *tsec_fw, const u32 tsec_size, const u32 kb)
|
|||
f_close(&fp);
|
||||
|
||||
sd_unmount();
|
||||
gfx_printf("\n%kPress Power or Vol +/-\n%k to Reboot to Sept...", COLOR_BLUE, COLOR_VIOLET);
|
||||
btn_wait();
|
||||
gfx_printf("\n%kPress Power or Vol +/-\n to Reboot to Sept...", colors[(color_idx++) % 6]);
|
||||
|
||||
u32 pk1t_sept = SEPT_PK1T_ADDR - (ALIGN(PATCHED_RELOC_SZ, 0x10) + WB_RST_SIZE);
|
||||
|
||||
|
@ -123,12 +133,12 @@ int reboot_to_sept(const u8 *tsec_fw, const u32 tsec_size, const u32 kb)
|
|||
PMC(APBDEV_PMC_SCRATCH33) = SEPT_PRI_ADDR;
|
||||
PMC(APBDEV_PMC_SCRATCH40) = 0x6000F208;
|
||||
|
||||
display_end();
|
||||
reconfig_hw_workaround(false, 0);
|
||||
|
||||
(*sept)();
|
||||
|
||||
error:
|
||||
EPRINTF("Sept files not found in sd:/sept!\nPlace appropriate files and try again.");
|
||||
EPRINTF("\nSept files not found in sd:/sept!\nPlace appropriate files and try again.");
|
||||
display_backlight_brightness(100, 1000);
|
||||
|
||||
btn_wait();
|
||||
|
|
131
source/ianos/ianos.c
Normal file
131
source/ianos/ianos.c
Normal 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
34
source/ianos/ianos.h
Normal 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
|
|
@ -29,6 +29,7 @@ static const u8 master_kek_sources[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_VERSION
|
|||
{0x37, 0x4B, 0x77, 0x29, 0x59, 0xB4, 0x04, 0x30, 0x81, 0xF6, 0xE5, 0x8C, 0x6D, 0x36, 0x17, 0x9A}, //6.2.0
|
||||
{0x9A, 0x3E, 0xA9, 0xAB, 0xFD, 0x56, 0x46, 0x1C, 0x9B, 0xF6, 0x48, 0x7F, 0x5C, 0xFA, 0x09, 0x5C}, //7.0.0
|
||||
{0xDE, 0xDC, 0xE3, 0x39, 0x30, 0x88, 0x16, 0xF8, 0xAE, 0x97, 0xAD, 0xEC, 0x64, 0x2D, 0x41, 0x41}, //8.1.0
|
||||
{0x1A, 0xEC, 0x11, 0x82, 0x2B, 0x32, 0x38, 0x7A, 0x2B, 0xED, 0xBA, 0x01, 0x47, 0x7E, 0x3B, 0x67}, //9.0.0
|
||||
};
|
||||
|
||||
static const u8 mkey_vectors[KB_FIRMWARE_VERSION_MAX+1][0x10] =
|
||||
|
@ -42,6 +43,7 @@ static const u8 mkey_vectors[KB_FIRMWARE_VERSION_MAX+1][0x10] =
|
|||
{0x1E, 0x1E, 0x22, 0xC0, 0x5A, 0x33, 0x3C, 0xB9, 0x0B, 0xA9, 0x03, 0x04, 0xBA, 0xDB, 0x07, 0x57}, /* Master key 05 encrypted with Master key 06. */
|
||||
{0xA4, 0xD4, 0x52, 0x6F, 0xD1, 0xE4, 0x36, 0xAA, 0x9F, 0xCB, 0x61, 0x27, 0x1C, 0x67, 0x65, 0x1F}, /* Master key 06 encrypted with Master key 07. */
|
||||
{0xEA, 0x60, 0xB3, 0xEA, 0xCE, 0x8F, 0x24, 0x46, 0x7D, 0x33, 0x9C, 0xD1, 0xBC, 0x24, 0x98, 0x29}, /* Master key 07 encrypted with Master key 08. */
|
||||
{0x4D, 0xD9, 0x98, 0x42, 0x45, 0x0D, 0xB1, 0x3C, 0x52, 0x0C, 0x9A, 0x44, 0xBB, 0xAD, 0xAF, 0x80}, /* Master key 08 encrypted with Master key 09. */
|
||||
};
|
||||
|
||||
//======================================Keys======================================//
|
||||
|
@ -66,6 +68,28 @@ static const u8 master_key_source[0x10] = {
|
|||
0xD8, 0xA2, 0x41, 0x0A, 0xC6, 0xC5, 0x90, 0x01, 0xC6, 0x1D, 0x6A, 0x26, 0x7C, 0x51, 0x3F, 0x3C};
|
||||
static const u8 per_console_key_source[0x10] = {
|
||||
0x4F, 0x02, 0x5F, 0x0E, 0xB6, 0x6D, 0x11, 0x0E, 0xDC, 0x32, 0x7D, 0x41, 0x86, 0xC2, 0xF4, 0x78};
|
||||
static const u8 per_console_key_source_4x[0x10] = {
|
||||
0x0C, 0x91, 0x09, 0xDB, 0x93, 0x93, 0x07, 0x81, 0x07, 0x3C, 0xC4, 0x16, 0x22, 0x7C, 0x6C, 0x28};
|
||||
|
||||
static const u8 new_device_key_sources[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_VERSION_400 + 1][0x10] = {
|
||||
{0x8B, 0x4E, 0x1C, 0x22, 0x42, 0x07, 0xC8, 0x73, 0x56, 0x94, 0x08, 0x8B, 0xCC, 0x47, 0x0F, 0x5D}, /* 4.x New Device Key Source. */
|
||||
{0x6C, 0xEF, 0xC6, 0x27, 0x8B, 0xEC, 0x8A, 0x91, 0x99, 0xAB, 0x24, 0xAC, 0x4F, 0x1C, 0x8F, 0x1C}, /* 5.x New Device Key Source. */
|
||||
{0x70, 0x08, 0x1B, 0x97, 0x44, 0x64, 0xF8, 0x91, 0x54, 0x9D, 0xC6, 0x84, 0x8F, 0x1A, 0xB2, 0xE4}, /* 6.x New Device Key Source. */
|
||||
{0x8E, 0x09, 0x1F, 0x7A, 0xBB, 0xCA, 0x6A, 0xFB, 0xB8, 0x9B, 0xD5, 0xC1, 0x25, 0x9C, 0xA9, 0x17}, /* 6.2.0 New Device Key Source. */
|
||||
{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. */
|
||||
};
|
||||
|
||||
static const u8 new_device_keygen_sources[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_VERSION_400 + 1][0x10] = {
|
||||
{0x88, 0x62, 0x34, 0x6E, 0xFA, 0xF7, 0xD8, 0x3F, 0xE1, 0x30, 0x39, 0x50, 0xF0, 0xB7, 0x5D, 0x5D}, /* 4.x New Device Keygen Source. */
|
||||
{0x06, 0x1E, 0x7B, 0xE9, 0x6D, 0x47, 0x8C, 0x77, 0xC5, 0xC8, 0xE7, 0x94, 0x9A, 0xA8, 0x5F, 0x2E}, /* 5.x New Device Keygen Source. */
|
||||
{0x99, 0xFA, 0x98, 0xBD, 0x15, 0x1C, 0x72, 0xFD, 0x7D, 0x9A, 0xD5, 0x41, 0x00, 0xFD, 0xB2, 0xEF}, /* 6.x New Device Keygen Source. */
|
||||
{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. */
|
||||
};
|
||||
|
||||
// from SPL
|
||||
static const u8 aes_key_generation_source[0x10] = {
|
||||
|
@ -86,7 +110,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},
|
||||
|
@ -108,6 +132,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},
|
||||
|
|
File diff suppressed because it is too large
Load diff
821
source/keys/save.c
Normal file
821
source/keys/save.c
Normal file
|
@ -0,0 +1,821 @@
|
|||
#include <string.h>
|
||||
#include "save.h"
|
||||
|
||||
#include "../gfx/gfx.h"
|
||||
#include "../mem/heap.h"
|
||||
#include "../sec/se.h"
|
||||
#include "../utils/types.h"
|
||||
#include "../utils/util.h"
|
||||
|
||||
#define REMAP_ENTRY_LENGTH 0x20
|
||||
|
||||
static inline void save_bitmap_set_bit(void *buffer, size_t bit_offset) {
|
||||
*((uint8_t *)buffer + (bit_offset >> 3)) |= 1 << (bit_offset & 7);
|
||||
}
|
||||
|
||||
static inline void save_bitmap_clear_bit(void *buffer, size_t bit_offset) {
|
||||
*((uint8_t *)buffer + (bit_offset >> 3)) &= ~(uint8_t)(1 << (bit_offset & 7));
|
||||
}
|
||||
|
||||
static inline uint8_t save_bitmap_check_bit(const void *buffer, size_t bit_offset) {
|
||||
return *((uint8_t *)buffer + (bit_offset >> 3)) & (1 << (bit_offset & 7));
|
||||
}
|
||||
|
||||
void save_duplex_storage_init(duplex_storage_ctx_t *ctx, duplex_fs_layer_info_t *layer, void *bitmap, uint64_t bitmap_size) {
|
||||
ctx->data_a = layer->data_a;
|
||||
ctx->data_b = layer->data_b;
|
||||
ctx->bitmap_storage = (uint8_t *)bitmap;
|
||||
ctx->block_size = 1 << layer->info.block_size_power;
|
||||
|
||||
ctx->bitmap.data = ctx->bitmap_storage;
|
||||
ctx->bitmap.bitmap = malloc(bitmap_size >> 3);
|
||||
|
||||
uint32_t bits_remaining = bitmap_size;
|
||||
uint32_t bitmap_pos = 0;
|
||||
uint32_t *buffer_pos = (uint32_t *)bitmap;
|
||||
while (bits_remaining) {
|
||||
uint32_t bits_to_read = bits_remaining < 32 ? bits_remaining : 32;
|
||||
uint32_t val = *buffer_pos;
|
||||
for (uint32_t i = 0; i < bits_to_read; i++) {
|
||||
if (val & 0x80000000)
|
||||
save_bitmap_set_bit(ctx->bitmap.bitmap, bitmap_pos);
|
||||
else
|
||||
save_bitmap_clear_bit(ctx->bitmap.bitmap, bitmap_pos);
|
||||
bitmap_pos++;
|
||||
bits_remaining--;
|
||||
val <<= 1;
|
||||
}
|
||||
buffer_pos++;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t save_duplex_storage_read(duplex_storage_ctx_t *ctx, void *buffer, uint64_t offset, size_t count) {
|
||||
uint64_t in_pos = offset;
|
||||
uint32_t out_pos = 0;
|
||||
uint32_t remaining = count;
|
||||
|
||||
while (remaining) {
|
||||
uint32_t block_num = (uint32_t)(in_pos / ctx->block_size);
|
||||
uint32_t block_pos = (uint32_t)(in_pos % ctx->block_size);
|
||||
uint32_t bytes_to_read = ctx->block_size - block_pos < remaining ? ctx->block_size - block_pos : remaining;
|
||||
|
||||
uint8_t *data = save_bitmap_check_bit(ctx->bitmap.bitmap, block_num) ? ctx->data_b : ctx->data_a;
|
||||
memcpy((uint8_t *)buffer + out_pos, data + in_pos, bytes_to_read);
|
||||
|
||||
out_pos += bytes_to_read;
|
||||
in_pos += bytes_to_read;
|
||||
remaining -= bytes_to_read;
|
||||
}
|
||||
return out_pos;
|
||||
}
|
||||
|
||||
remap_segment_ctx_t *save_remap_init_segments(remap_header_t *header, remap_entry_ctx_t *map_entries, uint32_t num_map_entries) {
|
||||
remap_segment_ctx_t *segments = malloc(sizeof(remap_segment_ctx_t) * header->map_segment_count);
|
||||
unsigned int entry_idx = 0;
|
||||
|
||||
for (unsigned int i = 0; i < header->map_segment_count; i++) {
|
||||
remap_segment_ctx_t *seg = &segments[i];
|
||||
seg->entries = malloc(sizeof(remap_entry_ctx_t));
|
||||
memcpy(seg->entries, &map_entries[entry_idx], sizeof(remap_entry_ctx_t));
|
||||
seg->offset = map_entries[entry_idx].virtual_offset;
|
||||
map_entries[entry_idx].segment = seg;
|
||||
seg->entry_count = 1;
|
||||
entry_idx++;
|
||||
|
||||
while (entry_idx < num_map_entries && map_entries[entry_idx - 1].virtual_offset_end == map_entries[entry_idx].virtual_offset) {
|
||||
map_entries[entry_idx].segment = seg;
|
||||
map_entries[entry_idx - 1].next = &map_entries[entry_idx];
|
||||
seg->entries = malloc(sizeof(remap_entry_ctx_t));
|
||||
memcpy(seg->entries, &map_entries[entry_idx], sizeof(remap_entry_ctx_t));
|
||||
seg->entry_count++;
|
||||
entry_idx++;
|
||||
}
|
||||
seg->length = seg->entries[seg->entry_count - 1].virtual_offset_end - seg->entries[0].virtual_offset;
|
||||
}
|
||||
return segments;
|
||||
}
|
||||
|
||||
remap_entry_ctx_t *save_remap_get_map_entry(remap_storage_ctx_t *ctx, uint64_t offset) {
|
||||
uint32_t segment_idx = (uint32_t)(offset >> (64 - ctx->header->segment_bits));
|
||||
if (segment_idx < ctx->header->map_segment_count) {
|
||||
for (unsigned int i = 0; i < ctx->segments[segment_idx].entry_count; i++)
|
||||
if (ctx->segments[segment_idx].entries[i].virtual_offset_end > offset)
|
||||
return &ctx->segments[segment_idx].entries[i];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uint32_t save_remap_read(remap_storage_ctx_t *ctx, void *buffer, uint64_t offset, size_t count) {
|
||||
remap_entry_ctx_t *entry = save_remap_get_map_entry(ctx, offset);
|
||||
uint64_t in_pos = offset;
|
||||
uint32_t out_pos = 0;
|
||||
uint32_t remaining = count;
|
||||
|
||||
while (remaining) {
|
||||
uint64_t entry_pos = in_pos - entry->virtual_offset;
|
||||
uint32_t bytes_to_read = entry->virtual_offset_end - in_pos < remaining ? (uint32_t)(entry->virtual_offset_end - in_pos) : remaining;
|
||||
|
||||
switch (ctx->type) {
|
||||
case STORAGE_BYTES:
|
||||
f_lseek(ctx->file, ctx->base_storage_offset + entry->physical_offset + entry_pos);
|
||||
f_read(ctx->file, (uint8_t *)buffer + out_pos, bytes_to_read, NULL);
|
||||
break;
|
||||
case STORAGE_DUPLEX:
|
||||
save_duplex_storage_read(ctx->duplex, (uint8_t *)buffer + out_pos, ctx->base_storage_offset + entry->physical_offset + entry_pos, bytes_to_read);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
out_pos += bytes_to_read;
|
||||
in_pos += bytes_to_read;
|
||||
remaining -= bytes_to_read;
|
||||
|
||||
if (in_pos >= entry->virtual_offset_end)
|
||||
entry = entry->next;
|
||||
}
|
||||
return out_pos;
|
||||
}
|
||||
|
||||
uint32_t save_journal_storage_read(journal_storage_ctx_t *ctx, remap_storage_ctx_t *remap, void *buffer, uint64_t offset, size_t count) {
|
||||
uint64_t in_pos = offset;
|
||||
uint32_t out_pos = 0;
|
||||
uint32_t remaining = count;
|
||||
|
||||
while (remaining) {
|
||||
uint32_t block_num = (uint32_t)(in_pos / ctx->block_size);
|
||||
uint32_t block_pos = (uint32_t)(in_pos % ctx->block_size);
|
||||
uint64_t physical_offset = ctx->map.entries[block_num].physical_index * ctx->block_size + block_pos;
|
||||
uint32_t bytes_to_read = ctx->block_size - block_pos < remaining ? ctx->block_size - block_pos : remaining;
|
||||
|
||||
save_remap_read(remap, (uint8_t *)buffer + out_pos, ctx->journal_data_offset + physical_offset, bytes_to_read);
|
||||
|
||||
out_pos += bytes_to_read;
|
||||
in_pos += bytes_to_read;
|
||||
remaining -= bytes_to_read;
|
||||
}
|
||||
return out_pos;
|
||||
}
|
||||
|
||||
void save_ivfc_storage_init(hierarchical_integrity_verification_storage_ctx_t *ctx, uint64_t master_hash_offset, ivfc_save_hdr_t *ivfc) {
|
||||
ivfc_level_save_ctx_t *levels = ctx->levels;
|
||||
levels[0].type = STORAGE_BYTES;
|
||||
levels[0].hash_offset = master_hash_offset;
|
||||
for (unsigned int i = 1; i < 4; i++) {
|
||||
ivfc_level_hdr_t *level = &ivfc->level_headers[i - 1];
|
||||
levels[i].type = STORAGE_REMAP;
|
||||
levels[i].data_offset = level->logical_offset;
|
||||
levels[i].data_size = level->hash_data_size;
|
||||
}
|
||||
if (ivfc->num_levels == 5) {
|
||||
ivfc_level_hdr_t *data_level = &ivfc->level_headers[ivfc->num_levels - 2];
|
||||
levels[ivfc->num_levels - 1].type = STORAGE_JOURNAL;
|
||||
levels[ivfc->num_levels - 1].data_offset = data_level->logical_offset;
|
||||
levels[ivfc->num_levels - 1].data_size = data_level->hash_data_size;
|
||||
}
|
||||
|
||||
struct salt_source_t {
|
||||
char string[50];
|
||||
uint32_t length;
|
||||
};
|
||||
|
||||
static struct salt_source_t salt_sources[6] = {
|
||||
{"HierarchicalIntegrityVerificationStorage::Master", 48},
|
||||
{"HierarchicalIntegrityVerificationStorage::L1", 44},
|
||||
{"HierarchicalIntegrityVerificationStorage::L2", 44},
|
||||
{"HierarchicalIntegrityVerificationStorage::L3", 44},
|
||||
{"HierarchicalIntegrityVerificationStorage::L4", 44},
|
||||
{"HierarchicalIntegrityVerificationStorage::L5", 44}
|
||||
};
|
||||
integrity_verification_info_ctx_t init_info[ivfc->num_levels];
|
||||
|
||||
init_info[0].data = &levels[0];
|
||||
init_info[0].block_size = 0;
|
||||
for (unsigned int i = 1; i < ivfc->num_levels; i++) {
|
||||
init_info[i].data = &levels[i];
|
||||
init_info[i].block_size = 1 << ivfc->level_headers[i - 1].block_size;
|
||||
se_calc_hmac_sha256(init_info[i].salt, ivfc->salt_source, 0x20, salt_sources[i - 1].string, salt_sources[i - 1].length);
|
||||
}
|
||||
|
||||
ctx->integrity_storages[0].next_level = NULL;
|
||||
ctx->level_validities = malloc(sizeof(validity_t *) * (ivfc->num_levels - 1));
|
||||
for (unsigned int i = 1; i < ivfc->num_levels; i++) {
|
||||
integrity_verification_storage_ctx_t *level_data = &ctx->integrity_storages[i - 1];
|
||||
level_data->hash_storage = &levels[i - 1];
|
||||
level_data->base_storage = &levels[i];
|
||||
level_data->sector_size = init_info[i].block_size;
|
||||
level_data->_length = init_info[i].data->data_size;
|
||||
level_data->sector_count = (level_data->_length + level_data->sector_size - 1) / level_data->sector_size;
|
||||
memcpy(level_data->salt, init_info[i].salt, 0x20);
|
||||
level_data->block_validities = calloc(1, sizeof(validity_t) * level_data->sector_count);
|
||||
ctx->level_validities[i - 1] = level_data->block_validities;
|
||||
if (i > 1) {
|
||||
level_data->next_level = &ctx->integrity_storages[i - 2];
|
||||
}
|
||||
}
|
||||
ctx->data_level = &levels[ivfc->num_levels - 1];
|
||||
ctx->_length = ctx->integrity_storages[ivfc->num_levels - 2]._length;
|
||||
}
|
||||
|
||||
size_t save_ivfc_level_fread(ivfc_level_save_ctx_t *ctx, void *buffer, uint64_t offset, size_t count) {
|
||||
switch (ctx->type) {
|
||||
case STORAGE_BYTES:
|
||||
f_lseek(ctx->save_ctx->file, ctx->hash_offset + offset);
|
||||
UINT br = 0;
|
||||
f_read(ctx->save_ctx->file, buffer, count, &br);
|
||||
return br;
|
||||
case STORAGE_REMAP:
|
||||
save_remap_read(&ctx->save_ctx->meta_remap_storage, buffer, ctx->data_offset + offset, count);
|
||||
return count;
|
||||
case STORAGE_JOURNAL:
|
||||
save_journal_storage_read(&ctx->save_ctx->journal_storage, &ctx->save_ctx->data_remap_storage, buffer, ctx->data_offset + offset, count);
|
||||
return count;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void save_ivfc_storage_read(integrity_verification_storage_ctx_t *ctx, void *buffer, uint64_t offset, size_t count, uint32_t verify) {
|
||||
if (count > ctx->sector_size) {
|
||||
EPRINTF("IVFC read exceeds sector size!\n");
|
||||
}
|
||||
|
||||
uint64_t block_index = offset / ctx->sector_size;
|
||||
|
||||
if (ctx->block_validities[block_index] == VALIDITY_INVALID && verify) {
|
||||
EPRINTFARGS("Hash error from previous check\n found at offset %x count %x!\n", (u32)offset, count);
|
||||
}
|
||||
|
||||
uint8_t hash_buffer[0x20] = {0};
|
||||
uint8_t zeroes[0x20] = {0};
|
||||
uint64_t hash_pos = block_index * 0x20;
|
||||
if (ctx->next_level) {
|
||||
save_ivfc_storage_read(ctx->next_level, hash_buffer, hash_pos, 0x20, verify);
|
||||
} else {
|
||||
save_ivfc_level_fread(ctx->hash_storage, hash_buffer, hash_pos, 0x20);
|
||||
}
|
||||
|
||||
if (!memcmp(hash_buffer, zeroes, 0x20)) {
|
||||
memset(buffer, 0, count);
|
||||
ctx->block_validities[block_index] = VALIDITY_VALID;
|
||||
return;
|
||||
}
|
||||
|
||||
save_ivfc_level_fread(ctx->base_storage, buffer, offset, count);
|
||||
|
||||
if (!(verify && ctx->block_validities[block_index] == VALIDITY_UNCHECKED)) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t hash[0x20] = {0};
|
||||
uint8_t *data_buffer = calloc(1, ctx->sector_size + 0x20);
|
||||
memcpy(data_buffer, ctx->salt, 0x20);
|
||||
memcpy(data_buffer + 0x20, buffer, count);
|
||||
|
||||
se_calc_sha256(hash, data_buffer, ctx->sector_size + 0x20);
|
||||
hash[0x1F] |= 0x80;
|
||||
|
||||
free(data_buffer);
|
||||
if (memcmp(hash_buffer, hash, 0x20)) {
|
||||
ctx->block_validities[block_index] = VALIDITY_INVALID;
|
||||
} else {
|
||||
ctx->block_validities[block_index] = VALIDITY_VALID;
|
||||
}
|
||||
|
||||
if (ctx->block_validities[block_index] == VALIDITY_INVALID && verify) {
|
||||
EPRINTFARGS("Hash error from current check\n found at offset %x count %x!\n", (u32)offset, count);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t save_allocation_table_read_entry_with_length(allocation_table_ctx_t *ctx, allocation_table_entry_t *entry) {
|
||||
uint32_t length = 1;
|
||||
uint32_t entry_index = allocation_table_block_to_entry_index(entry->next);
|
||||
|
||||
allocation_table_entry_t *entries = (allocation_table_entry_t *)((uint8_t *)(ctx->base_storage) + entry_index * SAVE_FAT_ENTRY_SIZE);
|
||||
if ((entries[0].next & 0x80000000) == 0) {
|
||||
if (entries[0].prev & 0x80000000 && entries[0].prev != 0x80000000) {
|
||||
EPRINTF("Invalid range entry in allocation table!\n");
|
||||
}
|
||||
} else {
|
||||
length = entries[1].next - entry_index + 1;
|
||||
}
|
||||
|
||||
if (allocation_table_is_list_end(&entries[0])) {
|
||||
entry->next = 0xFFFFFFFF;
|
||||
} else {
|
||||
entry->next = allocation_table_entry_index_to_block(allocation_table_get_next(&entries[0]));
|
||||
}
|
||||
|
||||
if (allocation_table_is_list_start(&entries[0])) {
|
||||
entry->prev = 0xFFFFFFFF;
|
||||
} else {
|
||||
entry->prev = allocation_table_entry_index_to_block(allocation_table_get_prev(&entries[0]));
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
uint32_t save_allocation_table_get_list_length(allocation_table_ctx_t *ctx, uint32_t block_index) {
|
||||
allocation_table_entry_t entry;
|
||||
entry.next = block_index;
|
||||
uint32_t total_length = 0;
|
||||
uint32_t table_size = ctx->header->allocation_table_block_count;
|
||||
uint32_t nodes_iterated = 0;
|
||||
|
||||
while (entry.next != 0xFFFFFFFF) {
|
||||
total_length += save_allocation_table_read_entry_with_length(ctx, &entry);
|
||||
nodes_iterated++;
|
||||
if (nodes_iterated > table_size) {
|
||||
EPRINTF("Cycle detected in allocation table!\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return total_length;
|
||||
}
|
||||
|
||||
uint64_t save_allocation_table_get_free_space_size(save_filesystem_ctx_t *ctx) {
|
||||
uint32_t free_list_start = save_allocation_table_get_free_list_block_index(&ctx->allocation_table);
|
||||
|
||||
if (free_list_start == 0xFFFFFFFF) return 0;
|
||||
|
||||
return ctx->header->block_size * save_allocation_table_get_list_length(&ctx->allocation_table, free_list_start);
|
||||
}
|
||||
|
||||
void save_allocation_table_iterator_begin(allocation_table_iterator_ctx_t *ctx, allocation_table_ctx_t *table, uint32_t initial_block) {
|
||||
ctx->fat = table;
|
||||
ctx->physical_block = initial_block;
|
||||
ctx->virtual_block = 0;
|
||||
|
||||
allocation_table_entry_t entry;
|
||||
entry.next = initial_block;
|
||||
ctx->current_segment_size = save_allocation_table_read_entry_with_length(ctx->fat, &entry);
|
||||
ctx->next_block = entry.next;
|
||||
ctx->prev_block = entry.prev;
|
||||
|
||||
if (ctx->prev_block != 0xFFFFFFFF) {
|
||||
EPRINTFARGS("Attempted to start FAT iteration from\n invalid block %x!\n", initial_block);
|
||||
}
|
||||
}
|
||||
|
||||
int save_allocation_table_iterator_move_next(allocation_table_iterator_ctx_t *ctx) {
|
||||
if (ctx->next_block == 0xFFFFFFFF) return 0;
|
||||
|
||||
ctx->virtual_block += ctx->current_segment_size;
|
||||
ctx->physical_block = ctx->next_block;
|
||||
|
||||
allocation_table_entry_t entry;
|
||||
entry.next = ctx->next_block;
|
||||
ctx->current_segment_size = save_allocation_table_read_entry_with_length(ctx->fat, &entry);
|
||||
ctx->next_block = entry.next;
|
||||
ctx->prev_block = entry.prev;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int save_allocation_table_iterator_move_prev(allocation_table_iterator_ctx_t *ctx) {
|
||||
if (ctx->prev_block == 0xFFFFFFFF) return 0;
|
||||
|
||||
ctx->physical_block = ctx->prev_block;
|
||||
|
||||
allocation_table_entry_t entry;
|
||||
entry.next = ctx->prev_block;
|
||||
ctx->current_segment_size = save_allocation_table_read_entry_with_length(ctx->fat, &entry);
|
||||
ctx->next_block = entry.next;
|
||||
ctx->prev_block = entry.prev;
|
||||
|
||||
ctx->virtual_block -= ctx->current_segment_size;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int save_allocation_table_iterator_seek(allocation_table_iterator_ctx_t *ctx, uint32_t block) {
|
||||
while (1) {
|
||||
if (block < ctx->virtual_block) {
|
||||
if (!save_allocation_table_iterator_move_prev(ctx)) return 0;
|
||||
} else if (block >= ctx->virtual_block + ctx->current_segment_size) {
|
||||
if (!save_allocation_table_iterator_move_next(ctx)) return 0;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t save_allocation_table_storage_read(allocation_table_storage_ctx_t *ctx, void *buffer, uint64_t offset, size_t count) {
|
||||
allocation_table_iterator_ctx_t iterator;
|
||||
save_allocation_table_iterator_begin(&iterator, ctx->fat, ctx->initial_block);
|
||||
uint64_t in_pos = offset;
|
||||
uint32_t out_pos = 0;
|
||||
uint32_t remaining = count;
|
||||
|
||||
while (remaining) {
|
||||
uint32_t block_num = (uint32_t)(in_pos / ctx->block_size);
|
||||
save_allocation_table_iterator_seek(&iterator, block_num);
|
||||
|
||||
uint32_t segment_pos = (uint32_t)(in_pos - (uint64_t)iterator.virtual_block * ctx->block_size);
|
||||
uint64_t physical_offset = iterator.physical_block * ctx->block_size + segment_pos;
|
||||
|
||||
uint32_t remaining_in_segment = iterator.current_segment_size * ctx->block_size - segment_pos;
|
||||
uint32_t bytes_to_read = remaining < remaining_in_segment ? remaining : remaining_in_segment;
|
||||
|
||||
uint32_t sector_size = ctx->base_storage->integrity_storages[3].sector_size;
|
||||
uint32_t chunk_remaining = bytes_to_read;
|
||||
for (unsigned int i = 0; i < bytes_to_read; i += sector_size) {
|
||||
uint32_t bytes_to_request = chunk_remaining < sector_size ? chunk_remaining : sector_size;
|
||||
save_ivfc_storage_read(&ctx->base_storage->integrity_storages[3], (uint8_t *)buffer + out_pos + i, physical_offset + i, bytes_to_request, ctx->base_storage->data_level->save_ctx->tool_ctx.action & ACTION_VERIFY);
|
||||
chunk_remaining -= bytes_to_request;
|
||||
}
|
||||
|
||||
out_pos += bytes_to_read;
|
||||
in_pos += bytes_to_read;
|
||||
remaining -= bytes_to_read;
|
||||
}
|
||||
return out_pos;
|
||||
}
|
||||
|
||||
uint32_t save_fs_list_get_capacity(save_filesystem_list_ctx_t *ctx) {
|
||||
if (!ctx->capacity)
|
||||
save_allocation_table_storage_read(&ctx->storage, &ctx->capacity, 4, 4);
|
||||
return ctx->capacity;
|
||||
}
|
||||
|
||||
uint32_t save_fs_list_read_entry(save_filesystem_list_ctx_t *ctx, uint32_t index, save_fs_list_entry_t *entry) {
|
||||
return save_allocation_table_storage_read(&ctx->storage, entry, index * SAVE_FS_LIST_ENTRY_SIZE, SAVE_FS_LIST_ENTRY_SIZE);
|
||||
}
|
||||
|
||||
int save_fs_list_get_value(save_filesystem_list_ctx_t *ctx, uint32_t index, save_fs_list_entry_t *value) {
|
||||
if (index >= save_fs_list_get_capacity(ctx)) {
|
||||
return 0;
|
||||
}
|
||||
save_fs_list_read_entry(ctx, index, value);
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint32_t save_fs_get_index_from_key(save_filesystem_list_ctx_t *ctx, save_entry_key_t *key, uint32_t *prev_index) {
|
||||
save_fs_list_entry_t entry;
|
||||
uint32_t capacity = save_fs_list_get_capacity(ctx);
|
||||
save_fs_list_read_entry(ctx, ctx->used_list_head_index, &entry);
|
||||
uint32_t prev;
|
||||
if (!prev_index) {
|
||||
prev_index = &prev;
|
||||
}
|
||||
*prev_index = ctx->used_list_head_index;
|
||||
uint32_t index = entry.next;
|
||||
while (index) {
|
||||
if (index > capacity) {
|
||||
EPRINTFARGS("Save entry index %d out of range!", index);
|
||||
}
|
||||
save_fs_list_read_entry(ctx, index, &entry);
|
||||
if (entry.parent == key->parent && !strcmp(entry.name, key->name)) {
|
||||
return index;
|
||||
}
|
||||
*prev_index = index;
|
||||
index = entry.next;
|
||||
}
|
||||
*prev_index = 0xFFFFFFFF;
|
||||
return 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
int save_hierarchical_file_table_find_path_recursive(hierarchical_save_file_table_ctx_t *ctx, save_entry_key_t *key, char *path) {
|
||||
key->parent = 0;
|
||||
char *pos = strchr(path, '/');
|
||||
while (pos) {
|
||||
memset(key->name, 0, SAVE_FS_LIST_MAX_NAME_LENGTH);
|
||||
char *tmp = strchr(pos, '/');
|
||||
if (!tmp) {
|
||||
memcpy(key->name, pos, strlen(pos));
|
||||
break;
|
||||
}
|
||||
memcpy(key->name, pos, tmp - pos);
|
||||
key->parent = save_fs_get_index_from_key(&ctx->directory_table, key, NULL);
|
||||
if (key->parent == 0xFFFFFFFF)
|
||||
return 0;
|
||||
pos = tmp + 1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int save_hierarchical_file_table_find_next_file(hierarchical_save_file_table_ctx_t *ctx, save_find_position_t *position, save_file_info_t *info, char *name) {
|
||||
if (position->next_file == 0) {
|
||||
return 0;
|
||||
}
|
||||
save_fs_list_entry_t entry;
|
||||
if(!save_fs_list_get_value(&ctx->file_table, position->next_file, &entry)) {
|
||||
return 0;
|
||||
}
|
||||
position->next_file = entry.value.next_sibling;
|
||||
memcpy(name, &entry.name, SAVE_FS_LIST_MAX_NAME_LENGTH);
|
||||
memcpy(info, &entry.value.save_file_info, sizeof(save_file_info_t));
|
||||
return 1;
|
||||
}
|
||||
|
||||
int save_hierarchical_file_table_find_next_directory(hierarchical_save_file_table_ctx_t *ctx, save_find_position_t *position, char *name) {
|
||||
if (position->next_directory == 0) {
|
||||
return 0;
|
||||
}
|
||||
save_fs_list_entry_t entry;
|
||||
if(!save_fs_list_get_value(&ctx->directory_table, position->next_directory, &entry)) {
|
||||
return 0;
|
||||
}
|
||||
position->next_directory = entry.value.next_sibling;
|
||||
memcpy(name, &entry.name, SAVE_FS_LIST_MAX_NAME_LENGTH);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int save_hierarchical_file_table_get_file_entry_by_path(hierarchical_save_file_table_ctx_t *ctx, char *path, save_fs_list_entry_t *entry) {
|
||||
save_entry_key_t key;
|
||||
if (!save_hierarchical_file_table_find_path_recursive(ctx, &key, path)) {
|
||||
EPRINTF("Unable to locate file.");
|
||||
return 0;
|
||||
}
|
||||
u32 index = save_fs_get_index_from_key(&ctx->file_table, &key, NULL);
|
||||
if (index == 0xFFFFFFFF) {
|
||||
EPRINTF("Unable to get table index for file.");
|
||||
return 0;
|
||||
}
|
||||
if (!save_fs_list_get_value(&ctx->file_table, index, entry)) {
|
||||
EPRINTF("Unable to get file entry from index.");
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void save_open_fat_storage(save_filesystem_ctx_t *ctx, allocation_table_storage_ctx_t *storage_ctx, uint32_t block_index) {
|
||||
storage_ctx->base_storage = ctx->base_storage;
|
||||
storage_ctx->fat = &ctx->allocation_table;
|
||||
storage_ctx->block_size = (uint32_t)ctx->header->block_size;
|
||||
storage_ctx->initial_block = block_index;
|
||||
storage_ctx->_length = block_index == 0xFFFFFFFF ? 0 : save_allocation_table_get_list_length(storage_ctx->fat, block_index) * storage_ctx->block_size;
|
||||
}
|
||||
|
||||
void save_filesystem_init(save_filesystem_ctx_t *ctx, void *fat, save_fs_header_t *save_fs_header, fat_header_t *fat_header) {
|
||||
ctx->allocation_table.base_storage = fat;
|
||||
ctx->allocation_table.header = fat_header;
|
||||
ctx->allocation_table.free_list_entry_index = 0;
|
||||
ctx->header = save_fs_header;
|
||||
|
||||
save_open_fat_storage(ctx, &ctx->file_table.directory_table.storage, fat_header->directory_table_block);
|
||||
save_open_fat_storage(ctx, &ctx->file_table.file_table.storage, fat_header->file_table_block);
|
||||
ctx->file_table.file_table.free_list_head_index = 0;
|
||||
ctx->file_table.file_table.used_list_head_index = 1;
|
||||
ctx->file_table.directory_table.free_list_head_index = 0;
|
||||
ctx->file_table.directory_table.used_list_head_index = 1;
|
||||
}
|
||||
|
||||
validity_t save_ivfc_validate(hierarchical_integrity_verification_storage_ctx_t *ctx, ivfc_save_hdr_t *ivfc) {
|
||||
validity_t result = VALIDITY_VALID;
|
||||
for (unsigned int i = 0; i < ivfc->num_levels - 1 && result != VALIDITY_INVALID; i++) {
|
||||
integrity_verification_storage_ctx_t *storage = &ctx->integrity_storages[i];
|
||||
|
||||
uint64_t block_size = storage->sector_size;
|
||||
uint32_t block_count = (uint32_t)((storage->_length + block_size - 1) / block_size);
|
||||
|
||||
uint8_t *buffer = malloc(block_size);
|
||||
|
||||
for (unsigned int j = 0; j < block_count; j++) {
|
||||
if (ctx->level_validities[ivfc->num_levels - 2][j] == VALIDITY_UNCHECKED) {
|
||||
uint32_t to_read = storage->_length - block_size * j < block_size ? storage->_length - block_size * j : block_size;
|
||||
save_ivfc_storage_read(storage, buffer, block_size * j, to_read, 1);
|
||||
}
|
||||
if (ctx->level_validities[ivfc->num_levels - 2][j] == VALIDITY_INVALID) {
|
||||
result = VALIDITY_INVALID;
|
||||
break;
|
||||
}
|
||||
}
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void save_ivfc_set_level_validities(hierarchical_integrity_verification_storage_ctx_t *ctx, ivfc_save_hdr_t *ivfc) {
|
||||
for (unsigned int i = 0; i < ivfc->num_levels - 1; i++) {
|
||||
validity_t level_validity = VALIDITY_VALID;
|
||||
for (unsigned int j = 0; j < ctx->integrity_storages[i].sector_count; j++) {
|
||||
if (ctx->level_validities[i][j] == VALIDITY_INVALID) {
|
||||
level_validity = VALIDITY_INVALID;
|
||||
break;
|
||||
}
|
||||
if (ctx->level_validities[i][j] == VALIDITY_UNCHECKED && level_validity != VALIDITY_INVALID) {
|
||||
level_validity = VALIDITY_UNCHECKED;
|
||||
}
|
||||
}
|
||||
ctx->levels[i].hash_validity = level_validity;
|
||||
}
|
||||
}
|
||||
|
||||
validity_t save_filesystem_verify(save_ctx_t *ctx) {
|
||||
validity_t journal_validity = save_ivfc_validate(&ctx->core_data_ivfc_storage, &ctx->header.data_ivfc_header);
|
||||
save_ivfc_set_level_validities(&ctx->core_data_ivfc_storage, &ctx->header.data_ivfc_header);
|
||||
|
||||
if (!ctx->fat_ivfc_storage.levels[0].save_ctx) return journal_validity;
|
||||
|
||||
validity_t fat_validity = save_ivfc_validate(&ctx->fat_ivfc_storage, &ctx->header.fat_ivfc_header);
|
||||
save_ivfc_set_level_validities(&ctx->fat_ivfc_storage, &ctx->header.fat_ivfc_header);
|
||||
|
||||
if (journal_validity != VALIDITY_VALID) return journal_validity;
|
||||
if (fat_validity != VALIDITY_VALID) return fat_validity;
|
||||
|
||||
return journal_validity;
|
||||
}
|
||||
|
||||
void save_process(save_ctx_t *ctx) {
|
||||
/* Try to parse Header A. */
|
||||
f_lseek(ctx->file, 0);
|
||||
if (f_read(ctx->file, &ctx->header, sizeof(ctx->header), NULL)) {
|
||||
EPRINTF("Failed to read save header!\n");
|
||||
}
|
||||
|
||||
save_process_header(ctx);
|
||||
|
||||
if (ctx->header_hash_validity == VALIDITY_INVALID) {
|
||||
/* Try to parse Header B. */
|
||||
f_lseek(ctx->file, 0x4000);
|
||||
if (f_read(ctx->file, &ctx->header, sizeof(ctx->header), NULL)) {
|
||||
EPRINTF("Failed to read save header!\n");
|
||||
}
|
||||
|
||||
save_process_header(ctx);
|
||||
|
||||
if (ctx->header_hash_validity == VALIDITY_INVALID) {
|
||||
EPRINTF("Error: Save header is invalid!\n");
|
||||
}
|
||||
}
|
||||
|
||||
unsigned char cmac[0x10];
|
||||
memset(cmac, 0, 0x10);
|
||||
se_aes_key_set(3, ctx->save_mac_key, 0x10);
|
||||
se_aes_cmac(3, cmac, 0x10, &ctx->header.layout, sizeof(ctx->header.layout));
|
||||
if (memcmp(cmac, &ctx->header.cmac, 0x10) == 0) {
|
||||
ctx->header_cmac_validity = VALIDITY_VALID;
|
||||
} else {
|
||||
ctx->header_cmac_validity = VALIDITY_INVALID;
|
||||
}
|
||||
|
||||
/* Initialize remap storages. */
|
||||
ctx->data_remap_storage.type = STORAGE_BYTES;
|
||||
ctx->data_remap_storage.base_storage_offset = ctx->header.layout.file_map_data_offset;
|
||||
ctx->data_remap_storage.header = &ctx->header.main_remap_header;
|
||||
ctx->data_remap_storage.map_entries = malloc(sizeof(remap_entry_ctx_t) * ctx->data_remap_storage.header->map_entry_count);
|
||||
ctx->data_remap_storage.file = ctx->file;
|
||||
f_lseek(ctx->file, ctx->header.layout.file_map_entry_offset);
|
||||
for (unsigned int i = 0; i < ctx->data_remap_storage.header->map_entry_count; i++) {
|
||||
f_read(ctx->file, &ctx->data_remap_storage.map_entries[i], 0x20, NULL);
|
||||
ctx->data_remap_storage.map_entries[i].physical_offset_end = ctx->data_remap_storage.map_entries[i].physical_offset + ctx->data_remap_storage.map_entries[i].size;
|
||||
ctx->data_remap_storage.map_entries[i].virtual_offset_end = ctx->data_remap_storage.map_entries[i].virtual_offset + ctx->data_remap_storage.map_entries[i].size;
|
||||
}
|
||||
|
||||
/* Initialize data remap storage. */
|
||||
ctx->data_remap_storage.segments = save_remap_init_segments(ctx->data_remap_storage.header, ctx->data_remap_storage.map_entries, ctx->data_remap_storage.header->map_entry_count);
|
||||
|
||||
/* Initialize duplex storage. */
|
||||
ctx->duplex_layers[0].data_a = (uint8_t *)&ctx->header + ctx->header.layout.duplex_master_offset_a;
|
||||
ctx->duplex_layers[0].data_b = (uint8_t *)&ctx->header + ctx->header.layout.duplex_master_offset_b;
|
||||
memcpy(&ctx->duplex_layers[0].info, &ctx->header.duplex_header.layers[0], sizeof(duplex_info_t));
|
||||
|
||||
ctx->duplex_layers[1].data_a = malloc(ctx->header.layout.duplex_l1_size);
|
||||
save_remap_read(&ctx->data_remap_storage, ctx->duplex_layers[1].data_a, ctx->header.layout.duplex_l1_offset_a, ctx->header.layout.duplex_l1_size);
|
||||
ctx->duplex_layers[1].data_b = malloc(ctx->header.layout.duplex_l1_size);
|
||||
save_remap_read(&ctx->data_remap_storage, ctx->duplex_layers[1].data_b, ctx->header.layout.duplex_l1_offset_b, ctx->header.layout.duplex_l1_size);
|
||||
memcpy(&ctx->duplex_layers[1].info, &ctx->header.duplex_header.layers[1], sizeof(duplex_info_t));
|
||||
|
||||
ctx->duplex_layers[2].data_a = malloc(ctx->header.layout.duplex_data_size);
|
||||
save_remap_read(&ctx->data_remap_storage, ctx->duplex_layers[2].data_a, ctx->header.layout.duplex_data_offset_a, ctx->header.layout.duplex_data_size);
|
||||
ctx->duplex_layers[2].data_b = malloc(ctx->header.layout.duplex_data_size);
|
||||
save_remap_read(&ctx->data_remap_storage, ctx->duplex_layers[2].data_b, ctx->header.layout.duplex_data_offset_b, ctx->header.layout.duplex_data_size);
|
||||
memcpy(&ctx->duplex_layers[2].info, &ctx->header.duplex_header.layers[2], sizeof(duplex_info_t));
|
||||
|
||||
/* Initialize hierarchical duplex storage. */
|
||||
uint8_t *bitmap = ctx->header.layout.duplex_index == 1 ? ctx->duplex_layers[0].data_b : ctx->duplex_layers[0].data_a;
|
||||
save_duplex_storage_init(&ctx->duplex_storage.layers[0], &ctx->duplex_layers[1], bitmap, ctx->header.layout.duplex_master_size);
|
||||
ctx->duplex_storage.layers[0]._length = ctx->header.layout.duplex_l1_size;
|
||||
|
||||
bitmap = malloc(ctx->duplex_storage.layers[0]._length);
|
||||
save_duplex_storage_read(&ctx->duplex_storage.layers[0], bitmap, 0, ctx->duplex_storage.layers[0]._length);
|
||||
save_duplex_storage_init(&ctx->duplex_storage.layers[1], &ctx->duplex_layers[2], bitmap, ctx->duplex_storage.layers[0]._length);
|
||||
ctx->duplex_storage.layers[1]._length = ctx->header.layout.duplex_data_size;
|
||||
|
||||
ctx->duplex_storage.data_layer = ctx->duplex_storage.layers[1];
|
||||
|
||||
/* Initialize meta remap storage. */
|
||||
ctx->meta_remap_storage.type = STORAGE_DUPLEX;
|
||||
ctx->meta_remap_storage.duplex = &ctx->duplex_storage.data_layer;
|
||||
ctx->meta_remap_storage.header = &ctx->header.meta_remap_header;
|
||||
ctx->meta_remap_storage.map_entries = malloc(sizeof(remap_entry_ctx_t) * ctx->meta_remap_storage.header->map_entry_count);
|
||||
ctx->meta_remap_storage.file = ctx->file;
|
||||
f_lseek(ctx->file, ctx->header.layout.meta_map_entry_offset);
|
||||
for (unsigned int i = 0; i < ctx->meta_remap_storage.header->map_entry_count; i++) {
|
||||
f_read(ctx->file, &ctx->meta_remap_storage.map_entries[i], 0x20, NULL);
|
||||
ctx->meta_remap_storage.map_entries[i].physical_offset_end = ctx->meta_remap_storage.map_entries[i].physical_offset + ctx->meta_remap_storage.map_entries[i].size;
|
||||
ctx->meta_remap_storage.map_entries[i].virtual_offset_end = ctx->meta_remap_storage.map_entries[i].virtual_offset + ctx->meta_remap_storage.map_entries[i].size;
|
||||
}
|
||||
|
||||
ctx->meta_remap_storage.segments = save_remap_init_segments(ctx->meta_remap_storage.header, ctx->meta_remap_storage.map_entries, ctx->meta_remap_storage.header->map_entry_count);
|
||||
|
||||
/* Initialize journal map. */
|
||||
ctx->journal_map_info.map_storage = malloc(ctx->header.layout.journal_map_table_size);
|
||||
save_remap_read(&ctx->meta_remap_storage, ctx->journal_map_info.map_storage, ctx->header.layout.journal_map_table_offset, ctx->header.layout.journal_map_table_size);
|
||||
|
||||
/* Initialize journal storage. */
|
||||
ctx->journal_storage.header = &ctx->header.journal_header;
|
||||
ctx->journal_storage.journal_data_offset = ctx->header.layout.journal_data_offset;
|
||||
ctx->journal_storage._length = ctx->journal_storage.header->total_size - ctx->journal_storage.header->journal_size;
|
||||
ctx->journal_storage.file = ctx->file;
|
||||
ctx->journal_storage.map.header = &ctx->header.map_header;
|
||||
ctx->journal_storage.map.map_storage = ctx->journal_map_info.map_storage;
|
||||
ctx->journal_storage.map.entries = malloc(sizeof(journal_map_entry_t) * ctx->journal_storage.map.header->main_data_block_count);
|
||||
uint32_t *pos = (uint32_t *)ctx->journal_storage.map.map_storage;
|
||||
for (unsigned int i = 0; i < ctx->journal_storage.map.header->main_data_block_count; i++) {
|
||||
ctx->journal_storage.map.entries[i].virtual_index = i;
|
||||
ctx->journal_storage.map.entries[i].physical_index = *pos & 0x7FFFFFFF;
|
||||
pos += 2;
|
||||
}
|
||||
ctx->journal_storage.block_size = ctx->journal_storage.header->block_size;
|
||||
ctx->journal_storage._length = ctx->journal_storage.header->total_size - ctx->journal_storage.header->journal_size;
|
||||
|
||||
/* Initialize core IVFC storage. */
|
||||
for (unsigned int i = 0; i < 5; i++) {
|
||||
ctx->core_data_ivfc_storage.levels[i].save_ctx = ctx;
|
||||
}
|
||||
save_ivfc_storage_init(&ctx->core_data_ivfc_storage, ctx->header.layout.ivfc_master_hash_offset_a, &ctx->header.data_ivfc_header);
|
||||
|
||||
/* Initialize FAT storage. */
|
||||
if (ctx->header.layout.version < 0x50000) {
|
||||
ctx->fat_storage = malloc(ctx->header.layout.fat_size);
|
||||
save_remap_read(&ctx->meta_remap_storage, ctx->fat_storage, ctx->header.layout.fat_offset, ctx->header.layout.fat_size);
|
||||
} else {
|
||||
for (unsigned int i = 0; i < 5; i++) {
|
||||
ctx->fat_ivfc_storage.levels[i].save_ctx = ctx;
|
||||
}
|
||||
save_ivfc_storage_init(&ctx->fat_ivfc_storage, ctx->header.layout.fat_ivfc_master_hash_a, &ctx->header.fat_ivfc_header);
|
||||
ctx->fat_storage = malloc(ctx->fat_ivfc_storage._length);
|
||||
save_remap_read(&ctx->meta_remap_storage, ctx->fat_storage, ctx->header.fat_ivfc_header.level_headers[ctx->header.fat_ivfc_header.num_levels - 2].logical_offset, ctx->fat_ivfc_storage._length);
|
||||
}
|
||||
|
||||
if (ctx->tool_ctx.action & ACTION_VERIFY) {
|
||||
save_filesystem_verify(ctx);
|
||||
}
|
||||
|
||||
/* Initialize core save filesystem. */
|
||||
ctx->save_filesystem_core.base_storage = &ctx->core_data_ivfc_storage;
|
||||
save_filesystem_init(&ctx->save_filesystem_core, ctx->fat_storage, &ctx->header.save_header, &ctx->header.fat_header);
|
||||
}
|
||||
|
||||
void save_process_header(save_ctx_t *ctx) {
|
||||
if (ctx->header.layout.magic != MAGIC_DISF || ctx->header.duplex_header.magic != MAGIC_DPFS ||
|
||||
ctx->header.data_ivfc_header.magic != MAGIC_IVFC || ctx->header.journal_header.magic != MAGIC_JNGL ||
|
||||
ctx->header.save_header.magic != MAGIC_SAVE || ctx->header.main_remap_header.magic != MAGIC_RMAP ||
|
||||
ctx->header.meta_remap_header.magic != MAGIC_RMAP) {
|
||||
EPRINTF("Error: Save header is corrupt!\n");
|
||||
}
|
||||
|
||||
ctx->data_ivfc_master = (uint8_t *)&ctx->header + ctx->header.layout.ivfc_master_hash_offset_a;
|
||||
ctx->fat_ivfc_master = (uint8_t *)&ctx->header + ctx->header.layout.fat_ivfc_master_hash_a;
|
||||
|
||||
uint8_t hash[0x20];
|
||||
se_calc_sha256(hash, &ctx->header.duplex_header, 0x3D00);
|
||||
ctx->header_hash_validity = memcmp(hash, ctx->header.layout.hash, 0x20) == 0 ? VALIDITY_VALID : VALIDITY_INVALID;
|
||||
|
||||
ctx->header.data_ivfc_header.num_levels = 5;
|
||||
|
||||
if (ctx->header.layout.version >= 0x50000) {
|
||||
ctx->header.fat_ivfc_header.num_levels = 4;
|
||||
}
|
||||
}
|
||||
|
||||
void save_free_contexts(save_ctx_t *ctx) {
|
||||
for (unsigned int i = 0; i < ctx->data_remap_storage.header->map_segment_count; i++) {
|
||||
for (unsigned int j = 0; j < ctx->data_remap_storage.segments[i].entry_count; j++) {
|
||||
free(&ctx->data_remap_storage.segments[i].entries[j]);
|
||||
}
|
||||
}
|
||||
free(ctx->data_remap_storage.segments);
|
||||
for (unsigned int i = 0; i < ctx->meta_remap_storage.header->map_segment_count; i++) {
|
||||
for (unsigned int j = 0; j < ctx->meta_remap_storage.segments[i].entry_count; j++) {
|
||||
free(&ctx->meta_remap_storage.segments[i].entries[j]);
|
||||
}
|
||||
}
|
||||
free(ctx->meta_remap_storage.segments);
|
||||
free(ctx->data_remap_storage.map_entries);
|
||||
free(ctx->meta_remap_storage.map_entries);
|
||||
free(ctx->duplex_storage.layers[0].bitmap.bitmap);
|
||||
free(ctx->duplex_storage.layers[1].bitmap.bitmap);
|
||||
free(ctx->duplex_storage.layers[1].bitmap_storage);
|
||||
for (unsigned int i = 1; i < 3; i++) {
|
||||
free(ctx->duplex_layers[i].data_a);
|
||||
free(ctx->duplex_layers[i].data_b);
|
||||
}
|
||||
free(ctx->journal_map_info.map_storage);
|
||||
free(ctx->journal_storage.map.entries);
|
||||
for (unsigned int i = 0; i < ctx->header.data_ivfc_header.num_levels - 1; i++) {
|
||||
free(ctx->core_data_ivfc_storage.integrity_storages[i].block_validities);
|
||||
}
|
||||
free(ctx->core_data_ivfc_storage.level_validities);
|
||||
if (ctx->header.layout.version >= 0x50000) {
|
||||
for (unsigned int i = 0; i < ctx->header.fat_ivfc_header.num_levels - 1; i++) {
|
||||
free(ctx->fat_ivfc_storage.integrity_storages[i].block_validities);
|
||||
}
|
||||
}
|
||||
free(ctx->fat_ivfc_storage.level_validities);
|
||||
free(ctx->fat_storage);
|
||||
}
|
489
source/keys/save.h
Normal file
489
source/keys/save.h
Normal file
|
@ -0,0 +1,489 @@
|
|||
#ifndef _SAVE_H
|
||||
#define _SAVE_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "../libs/fatfs/ff.h"
|
||||
|
||||
#define SAVE_HEADER_SIZE 0x4000
|
||||
#define SAVE_FAT_ENTRY_SIZE 8
|
||||
#define SAVE_FS_LIST_MAX_NAME_LENGTH 0x40
|
||||
#define SAVE_FS_LIST_ENTRY_SIZE 0x60
|
||||
|
||||
#define IVFC_MAX_LEVEL 6
|
||||
|
||||
#define MAGIC_DISF 0x46534944
|
||||
#define MAGIC_DPFS 0x53465044
|
||||
#define MAGIC_JNGL 0x4C474E4A
|
||||
#define MAGIC_SAVE 0x45564153
|
||||
#define MAGIC_RMAP 0x50414D52
|
||||
#define MAGIC_IVFC 0x43465649
|
||||
|
||||
typedef enum {
|
||||
VALIDITY_UNCHECKED = 0,
|
||||
VALIDITY_INVALID,
|
||||
VALIDITY_VALID
|
||||
} validity_t;
|
||||
|
||||
typedef struct save_ctx_t save_ctx_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t magic; /* DISF */
|
||||
uint32_t version;
|
||||
uint8_t hash[0x20];
|
||||
uint64_t file_map_entry_offset;
|
||||
uint64_t file_map_entry_size;
|
||||
uint64_t meta_map_entry_offset;
|
||||
uint64_t meta_map_entry_size;
|
||||
uint64_t file_map_data_offset;
|
||||
uint64_t file_map_data_size;
|
||||
uint64_t duplex_l1_offset_a;
|
||||
uint64_t duplex_l1_offset_b;
|
||||
uint64_t duplex_l1_size;
|
||||
uint64_t duplex_data_offset_a;
|
||||
uint64_t duplex_data_offset_b;
|
||||
uint64_t duplex_data_size;
|
||||
uint64_t journal_data_offset;
|
||||
uint64_t journal_data_size_a;
|
||||
uint64_t journal_data_size_b;
|
||||
uint64_t journal_size;
|
||||
uint64_t duplex_master_offset_a;
|
||||
uint64_t duplex_master_offset_b;
|
||||
uint64_t duplex_master_size;
|
||||
uint64_t ivfc_master_hash_offset_a;
|
||||
uint64_t ivfc_master_hash_offset_b;
|
||||
uint64_t ivfc_master_hash_size;
|
||||
uint64_t journal_map_table_offset;
|
||||
uint64_t journal_map_table_size;
|
||||
uint64_t journal_physical_bitmap_offset;
|
||||
uint64_t journal_physical_bitmap_size;
|
||||
uint64_t journal_virtual_bitmap_offset;
|
||||
uint64_t journal_virtual_bitmap_size;
|
||||
uint64_t journal_free_bitmap_offset;
|
||||
uint64_t journal_free_bitmap_size;
|
||||
uint64_t ivfc_l1_offset;
|
||||
uint64_t ivfc_l1_size;
|
||||
uint64_t ivfc_l2_offset;
|
||||
uint64_t ivfc_l2_size;
|
||||
uint64_t ivfc_l3_offset;
|
||||
uint64_t ivfc_l3_size;
|
||||
uint64_t fat_offset;
|
||||
uint64_t fat_size;
|
||||
uint64_t duplex_index;
|
||||
uint64_t fat_ivfc_master_hash_a;
|
||||
uint64_t fat_ivfc_master_hash_b;
|
||||
uint64_t fat_ivfc_l1_offset;
|
||||
uint64_t fat_ivfc_l1_size;
|
||||
uint64_t fat_ivfc_l2_offset;
|
||||
uint64_t fat_ivfc_l2_size;
|
||||
uint8_t _0x190[0x70];
|
||||
} fs_layout_t;
|
||||
|
||||
#pragma pack(push, 1)
|
||||
typedef struct {
|
||||
uint64_t offset;
|
||||
uint64_t length;
|
||||
uint32_t block_size_power;
|
||||
} duplex_info_t;
|
||||
#pragma pack(pop)
|
||||
|
||||
typedef struct {
|
||||
uint32_t magic; /* DPFS */
|
||||
uint32_t version;
|
||||
duplex_info_t layers[3];
|
||||
} duplex_header_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t version;
|
||||
uint32_t main_data_block_count;
|
||||
uint32_t journal_block_count;
|
||||
uint32_t _0x0C;
|
||||
} journal_map_header_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t magic; /* JNGL */
|
||||
uint32_t version;
|
||||
uint64_t total_size;
|
||||
uint64_t journal_size;
|
||||
uint64_t block_size;
|
||||
} journal_header_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t magic; /* SAVE */
|
||||
uint32_t version;
|
||||
uint64_t block_count;
|
||||
uint64_t block_size;
|
||||
} save_fs_header_t;
|
||||
|
||||
typedef struct {
|
||||
uint64_t block_size;
|
||||
uint64_t allocation_table_offset;
|
||||
uint32_t allocation_table_block_count;
|
||||
uint32_t _0x14;
|
||||
uint64_t data_offset;
|
||||
uint32_t data_block_count;
|
||||
uint32_t _0x24;
|
||||
uint32_t directory_table_block;
|
||||
uint32_t file_table_block;
|
||||
} fat_header_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t magic; /* RMAP */
|
||||
uint32_t version;
|
||||
uint32_t map_entry_count;
|
||||
uint32_t map_segment_count;
|
||||
uint32_t segment_bits;
|
||||
uint8_t _0x14[0x2C];
|
||||
} remap_header_t;
|
||||
|
||||
typedef struct remap_segment_ctx_t remap_segment_ctx_t;
|
||||
typedef struct remap_entry_ctx_t remap_entry_ctx_t;
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct remap_entry_ctx_t {
|
||||
uint64_t virtual_offset;
|
||||
uint64_t physical_offset;
|
||||
uint64_t size;
|
||||
uint32_t alignment;
|
||||
uint32_t _0x1C;
|
||||
uint64_t virtual_offset_end;
|
||||
uint64_t physical_offset_end;
|
||||
remap_segment_ctx_t *segment;
|
||||
remap_entry_ctx_t *next;
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
struct remap_segment_ctx_t{
|
||||
uint64_t offset;
|
||||
uint64_t length;
|
||||
remap_entry_ctx_t *entries;
|
||||
uint64_t entry_count;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
uint8_t *data;
|
||||
uint8_t *bitmap;
|
||||
} duplex_bitmap_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t block_size;
|
||||
uint8_t *bitmap_storage;
|
||||
uint8_t *data_a;
|
||||
uint8_t *data_b;
|
||||
duplex_bitmap_t bitmap;
|
||||
uint64_t _length;
|
||||
} duplex_storage_ctx_t;
|
||||
|
||||
enum base_storage_type {
|
||||
STORAGE_BYTES = 0,
|
||||
STORAGE_DUPLEX = 1,
|
||||
STORAGE_REMAP = 2,
|
||||
STORAGE_JOURNAL = 3
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
remap_header_t *header;
|
||||
remap_entry_ctx_t *map_entries;
|
||||
remap_segment_ctx_t *segments;
|
||||
enum base_storage_type type;
|
||||
uint64_t base_storage_offset;
|
||||
duplex_storage_ctx_t *duplex;
|
||||
FIL *file;
|
||||
} remap_storage_ctx_t;
|
||||
|
||||
typedef struct {
|
||||
uint64_t title_id;
|
||||
uint8_t user_id[0x10];
|
||||
uint64_t save_id;
|
||||
uint8_t save_data_type;
|
||||
uint8_t _0x21[0x1F];
|
||||
uint64_t save_owner_id;
|
||||
uint64_t timestamp;
|
||||
uint64_t _0x50;
|
||||
uint64_t data_size;
|
||||
uint64_t journal_size;
|
||||
uint64_t commit_id;
|
||||
} extra_data_t;
|
||||
|
||||
typedef struct {
|
||||
uint64_t logical_offset;
|
||||
uint64_t hash_data_size;
|
||||
uint32_t block_size;
|
||||
uint32_t reserved;
|
||||
} ivfc_level_hdr_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t magic;
|
||||
uint32_t id;
|
||||
uint32_t master_hash_size;
|
||||
uint32_t num_levels;
|
||||
ivfc_level_hdr_t level_headers[IVFC_MAX_LEVEL];
|
||||
uint8_t salt_source[0x20];
|
||||
} ivfc_save_hdr_t;
|
||||
|
||||
#pragma pack(push, 1)
|
||||
typedef struct {
|
||||
uint8_t cmac[0x10];
|
||||
uint8_t _0x10[0xF0];
|
||||
fs_layout_t layout;
|
||||
duplex_header_t duplex_header;
|
||||
ivfc_save_hdr_t data_ivfc_header;
|
||||
uint32_t _0x404;
|
||||
journal_header_t journal_header;
|
||||
journal_map_header_t map_header;
|
||||
uint8_t _0x438[0x1D0];
|
||||
save_fs_header_t save_header;
|
||||
fat_header_t fat_header;
|
||||
remap_header_t main_remap_header, meta_remap_header;
|
||||
uint64_t _0x6D0;
|
||||
extra_data_t extra_data;
|
||||
uint8_t _0x748[0x390];
|
||||
ivfc_save_hdr_t fat_ivfc_header;
|
||||
uint8_t _0xB98[0x3468];
|
||||
} save_header_t;
|
||||
#pragma pack(pop)
|
||||
|
||||
typedef struct {
|
||||
duplex_storage_ctx_t layers[2];
|
||||
duplex_storage_ctx_t data_layer;
|
||||
uint64_t _length;
|
||||
} hierarchical_duplex_storage_ctx_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t *data_a;
|
||||
uint8_t *data_b;
|
||||
duplex_info_t info;
|
||||
} duplex_fs_layer_info_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t *map_storage;
|
||||
uint8_t *physical_block_bitmap;
|
||||
uint8_t *virtual_block_bitmap;
|
||||
uint8_t *free_block_bitmap;
|
||||
} journal_map_params_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t physical_index;
|
||||
uint32_t virtual_index;
|
||||
} journal_map_entry_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
journal_map_header_t *header;
|
||||
journal_map_entry_t *entries;
|
||||
uint8_t *map_storage;
|
||||
} journal_map_ctx_t;
|
||||
|
||||
typedef struct {
|
||||
journal_map_ctx_t map;
|
||||
journal_header_t *header;
|
||||
uint32_t block_size;
|
||||
uint64_t journal_data_offset;
|
||||
uint64_t _length;
|
||||
FIL *file;
|
||||
} journal_storage_ctx_t;
|
||||
|
||||
typedef struct {
|
||||
uint64_t data_offset;
|
||||
uint64_t data_size;
|
||||
uint64_t hash_offset;
|
||||
uint32_t hash_block_size;
|
||||
validity_t hash_validity;
|
||||
enum base_storage_type type;
|
||||
save_ctx_t *save_ctx;
|
||||
} ivfc_level_save_ctx_t;
|
||||
|
||||
typedef struct {
|
||||
ivfc_level_save_ctx_t *data;
|
||||
uint32_t block_size;
|
||||
uint8_t salt[0x20];
|
||||
} integrity_verification_info_ctx_t;
|
||||
|
||||
|
||||
typedef struct integrity_verification_storage_ctx_t integrity_verification_storage_ctx_t;
|
||||
|
||||
struct integrity_verification_storage_ctx_t {
|
||||
ivfc_level_save_ctx_t *hash_storage;
|
||||
ivfc_level_save_ctx_t *base_storage;
|
||||
validity_t *block_validities;
|
||||
uint8_t salt[0x20];
|
||||
uint32_t sector_size;
|
||||
uint32_t sector_count;
|
||||
uint64_t _length;
|
||||
integrity_verification_storage_ctx_t *next_level;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
ivfc_level_save_ctx_t levels[5];
|
||||
ivfc_level_save_ctx_t *data_level;
|
||||
validity_t **level_validities;
|
||||
uint64_t _length;
|
||||
integrity_verification_storage_ctx_t integrity_storages[4];
|
||||
} hierarchical_integrity_verification_storage_ctx_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t prev;
|
||||
uint32_t next;
|
||||
} allocation_table_entry_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t free_list_entry_index;
|
||||
void *base_storage;
|
||||
fat_header_t *header;
|
||||
} allocation_table_ctx_t;
|
||||
|
||||
typedef struct {
|
||||
hierarchical_integrity_verification_storage_ctx_t *base_storage;
|
||||
uint32_t block_size;
|
||||
uint32_t initial_block;
|
||||
allocation_table_ctx_t *fat;
|
||||
uint64_t _length;
|
||||
} allocation_table_storage_ctx_t;
|
||||
|
||||
typedef struct {
|
||||
allocation_table_ctx_t *fat;
|
||||
uint32_t virtual_block;
|
||||
uint32_t physical_block;
|
||||
uint32_t current_segment_size;
|
||||
uint32_t next_block;
|
||||
uint32_t prev_block;
|
||||
} allocation_table_iterator_ctx_t;
|
||||
|
||||
typedef struct {
|
||||
char name[SAVE_FS_LIST_MAX_NAME_LENGTH];
|
||||
uint32_t parent;
|
||||
} save_entry_key_t;
|
||||
|
||||
#pragma pack(push, 1)
|
||||
typedef struct {
|
||||
uint32_t start_block;
|
||||
uint64_t length;
|
||||
uint32_t _0xC[2];
|
||||
} save_file_info_t;
|
||||
#pragma pack(pop)
|
||||
|
||||
#pragma pack(push, 1)
|
||||
typedef struct {
|
||||
uint32_t next_directory;
|
||||
uint32_t next_file;
|
||||
uint32_t _0x8[3];
|
||||
} save_find_position_t;
|
||||
#pragma pack(pop)
|
||||
|
||||
#pragma pack(push, 1)
|
||||
typedef struct {
|
||||
uint32_t next_sibling;
|
||||
union { /* Save table entry type. Size = 0x14. */
|
||||
save_file_info_t save_file_info;
|
||||
save_find_position_t save_find_position;
|
||||
};
|
||||
} save_table_entry_t;
|
||||
#pragma pack(pop)
|
||||
|
||||
#pragma pack(push, 1)
|
||||
typedef struct {
|
||||
uint32_t parent;
|
||||
char name[SAVE_FS_LIST_MAX_NAME_LENGTH];
|
||||
save_table_entry_t value;
|
||||
uint32_t next;
|
||||
} save_fs_list_entry_t;
|
||||
#pragma pack(pop)
|
||||
|
||||
typedef struct {
|
||||
uint32_t free_list_head_index;
|
||||
uint32_t used_list_head_index;
|
||||
allocation_table_storage_ctx_t storage;
|
||||
uint32_t capacity;
|
||||
} save_filesystem_list_ctx_t;
|
||||
|
||||
typedef struct {
|
||||
save_filesystem_list_ctx_t file_table;
|
||||
save_filesystem_list_ctx_t directory_table;
|
||||
} hierarchical_save_file_table_ctx_t;
|
||||
|
||||
typedef struct {
|
||||
hierarchical_integrity_verification_storage_ctx_t *base_storage;
|
||||
allocation_table_ctx_t allocation_table;
|
||||
save_fs_header_t *header;
|
||||
hierarchical_save_file_table_ctx_t file_table;
|
||||
} save_filesystem_ctx_t;
|
||||
|
||||
#define ACTION_VERIFY (1<<2)
|
||||
|
||||
struct save_ctx_t {
|
||||
save_header_t header;
|
||||
FIL *file;
|
||||
struct {
|
||||
FIL *file;
|
||||
uint32_t action;
|
||||
} tool_ctx;
|
||||
validity_t header_cmac_validity;
|
||||
validity_t header_hash_validity;
|
||||
uint8_t *data_ivfc_master;
|
||||
uint8_t *fat_ivfc_master;
|
||||
remap_storage_ctx_t data_remap_storage;
|
||||
remap_storage_ctx_t meta_remap_storage;
|
||||
duplex_fs_layer_info_t duplex_layers[3];
|
||||
hierarchical_duplex_storage_ctx_t duplex_storage;
|
||||
journal_storage_ctx_t journal_storage;
|
||||
journal_map_params_t journal_map_info;
|
||||
hierarchical_integrity_verification_storage_ctx_t core_data_ivfc_storage;
|
||||
hierarchical_integrity_verification_storage_ctx_t fat_ivfc_storage;
|
||||
uint8_t *fat_storage;
|
||||
save_filesystem_ctx_t save_filesystem_core;
|
||||
uint8_t save_mac_key[0x10];
|
||||
};
|
||||
|
||||
static inline uint32_t allocation_table_entry_index_to_block(uint32_t entry_index) {
|
||||
return entry_index - 1;
|
||||
}
|
||||
|
||||
static inline uint32_t allocation_table_block_to_entry_index(uint32_t block_index) {
|
||||
return block_index + 1;
|
||||
}
|
||||
|
||||
static inline int allocation_table_is_list_end(allocation_table_entry_t *entry) {
|
||||
return (entry->next & 0x7FFFFFFF) == 0;
|
||||
}
|
||||
|
||||
static inline int allocation_table_is_list_start(allocation_table_entry_t *entry) {
|
||||
return entry->prev == 0x80000000;
|
||||
}
|
||||
|
||||
|
||||
static inline int allocation_table_get_next(allocation_table_entry_t *entry) {
|
||||
return entry->next & 0x7FFFFFFF;
|
||||
}
|
||||
|
||||
static inline int allocation_table_get_prev(allocation_table_entry_t *entry) {
|
||||
return entry->prev & 0x7FFFFFFF;
|
||||
}
|
||||
|
||||
static inline allocation_table_entry_t *save_allocation_table_read_entry(allocation_table_ctx_t *ctx, uint32_t entry_index) {
|
||||
return (allocation_table_entry_t *)((uint8_t *)ctx->base_storage + entry_index * SAVE_FAT_ENTRY_SIZE);
|
||||
}
|
||||
|
||||
static inline uint32_t save_allocation_table_get_free_list_entry_index(allocation_table_ctx_t *ctx) {
|
||||
return allocation_table_get_next(save_allocation_table_read_entry(ctx, ctx->free_list_entry_index));
|
||||
}
|
||||
|
||||
static inline uint32_t save_allocation_table_get_free_list_block_index(allocation_table_ctx_t *ctx) {
|
||||
return allocation_table_entry_index_to_block(save_allocation_table_get_free_list_entry_index(ctx));
|
||||
}
|
||||
|
||||
void save_process(save_ctx_t *ctx);
|
||||
void save_process_header(save_ctx_t *ctx);
|
||||
void save_save(save_ctx_t *ctx);
|
||||
void save_print(save_ctx_t *ctx);
|
||||
|
||||
void save_free_contexts(save_ctx_t *ctx);
|
||||
|
||||
void save_open_fat_storage(save_filesystem_ctx_t *ctx, allocation_table_storage_ctx_t *storage_ctx, uint32_t block_index);
|
||||
uint32_t save_allocation_table_storage_read(allocation_table_storage_ctx_t *ctx, void *buffer, uint64_t offset, size_t count);
|
||||
int save_fs_list_get_value(save_filesystem_list_ctx_t *ctx, uint32_t index, save_fs_list_entry_t *value);
|
||||
uint32_t save_fs_get_index_from_key(save_filesystem_list_ctx_t *ctx, save_entry_key_t *key, uint32_t *prev_index);
|
||||
int save_hierarchical_file_table_find_path_recursive(hierarchical_save_file_table_ctx_t *ctx, save_entry_key_t *key, char *path);
|
||||
int save_hierarchical_file_table_get_file_entry_by_path(hierarchical_save_file_table_ctx_t *ctx, char *path, save_fs_list_entry_t *entry);
|
||||
|
||||
#endif
|
589
source/libs/elfload/elf.h
Normal file
589
source/libs/elfload/elf.h
Normal 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
|
49
source/libs/elfload/elfarch.h
Normal file
49
source/libs/elfload/elfarch.h
Normal 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
|
324
source/libs/elfload/elfload.c
Normal file
324
source/libs/elfload/elfload.c
Normal 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;
|
||||
}
|
127
source/libs/elfload/elfload.h
Normal file
127
source/libs/elfload/elfload.h
Normal 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
|
84
source/libs/elfload/elfreloc_aarch64.c
Normal file
84
source/libs/elfload/elfreloc_aarch64.c
Normal 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
|
66
source/libs/elfload/elfreloc_arm.c
Normal file
66
source/libs/elfload/elfreloc_arm.c
Normal 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
|
|
@ -42,11 +42,13 @@ typedef struct {
|
|||
u32 visit_count;
|
||||
u8 tweak[0x10];
|
||||
u8 cached_sector[0x200];
|
||||
u8 align[8];
|
||||
} sector_cache_t;
|
||||
|
||||
#define MAX_SEC_CACHE_ENTRIES 64
|
||||
static sector_cache_t *sector_cache = (sector_cache_t*)0x40020000;
|
||||
static sector_cache_t *sector_cache = NULL;
|
||||
static u32 secindex = 0;
|
||||
bool clear_sector_cache = false;
|
||||
|
||||
DSTATUS disk_status (
|
||||
BYTE pdrv /* Physical drive number to identify the drive */
|
||||
|
@ -105,7 +107,7 @@ static inline int _emmc_xts(u32 ks1, u32 ks2, u32 enc, u8 *tweak, bool regen_twe
|
|||
pdst += 0x10;
|
||||
}
|
||||
|
||||
se_aes_crypt_ecb(ks2, 0, dst, secsize, src, secsize);
|
||||
se_aes_crypt_ecb(ks2, enc, dst, secsize, src, secsize);
|
||||
|
||||
pdst = (u8 *)dst;
|
||||
|
||||
|
@ -134,14 +136,28 @@ DRESULT disk_read (
|
|||
switch (pdrv)
|
||||
{
|
||||
case 0:
|
||||
if (((u32)buff >= DRAM_START) && !((u32)buff % 8))
|
||||
return sdmmc_storage_read(&sd_storage, sector, count, buff) ? RES_OK : RES_ERROR;
|
||||
u8 *buf = (u8 *)SDMMC_UPPER_BUFFER;
|
||||
if (sdmmc_storage_read(&sd_storage, sector, count, buf))
|
||||
{
|
||||
memcpy(buff, buf, 512 * count);
|
||||
return RES_OK;
|
||||
}
|
||||
return RES_ERROR;
|
||||
|
||||
case 1:;
|
||||
__attribute__ ((aligned (16))) static u8 tweak[0x10];
|
||||
__attribute__ ((aligned (16))) static u64 prev_cluster = -1;
|
||||
__attribute__ ((aligned (16))) static u32 prev_sector = 0;
|
||||
u32 tweak_exp = 0;
|
||||
bool regen_tweak = true, cache_sector = false;
|
||||
bool needs_cache_sector = false;
|
||||
|
||||
if (secindex == 0 || clear_sector_cache) {
|
||||
if (!sector_cache)
|
||||
sector_cache = (sector_cache_t *)malloc(sizeof(sector_cache_t) * MAX_SEC_CACHE_ENTRIES);
|
||||
clear_sector_cache = false;
|
||||
secindex = 0;
|
||||
}
|
||||
|
||||
u32 s = 0;
|
||||
if (count == 1) {
|
||||
|
@ -159,12 +175,14 @@ DRESULT disk_read (
|
|||
if (s == secindex && s < MAX_SEC_CACHE_ENTRIES) {
|
||||
sector_cache[s].sector = sector;
|
||||
sector_cache[s].visit_count++;
|
||||
cache_sector = true;
|
||||
needs_cache_sector = true;
|
||||
secindex++;
|
||||
}
|
||||
}
|
||||
|
||||
if (nx_emmc_part_read(&storage, system_part, sector, count, buff)) {
|
||||
u32 tweak_exp = 0;
|
||||
bool regen_tweak = true;
|
||||
if (prev_cluster != sector / 0x20) { // sector in different cluster than last read
|
||||
prev_cluster = sector / 0x20;
|
||||
tweak_exp = sector % 0x20;
|
||||
|
@ -177,7 +195,7 @@ DRESULT disk_read (
|
|||
|
||||
// fatfs will never pull more than a cluster
|
||||
_emmc_xts(9, 8, 0, tweak, regen_tweak, tweak_exp, prev_cluster, buff, buff, count * 0x200);
|
||||
if (cache_sector) {
|
||||
if (needs_cache_sector) {
|
||||
memcpy(sector_cache[s].cached_sector, buff, 0x200);
|
||||
memcpy(sector_cache[s].tweak, tweak, 0x10);
|
||||
}
|
||||
|
@ -198,7 +216,14 @@ DRESULT disk_write (
|
|||
{
|
||||
if (pdrv == 1)
|
||||
return RES_WRPRT;
|
||||
|
||||
if (((u32)buff >= DRAM_START) && !((u32)buff % 8))
|
||||
return sdmmc_storage_write(&sd_storage, sector, count, (void *)buff) ? RES_OK : RES_ERROR;
|
||||
u8 *buf = (u8 *)SDMMC_UPPER_BUFFER; //TODO: define this somewhere.
|
||||
memcpy(buf, buff, 512 * count);
|
||||
if (sdmmc_storage_write(&sd_storage, sector, count, buf))
|
||||
return RES_OK;
|
||||
return RES_ERROR;
|
||||
}
|
||||
|
||||
DRESULT disk_ioctl (
|
||||
|
|
|
@ -1,10 +1,25 @@
|
|||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (c) 2018-2019 CTCaer
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/*----------------------------------------------------------------------------/
|
||||
/ FatFs - Generic FAT Filesystem Module R0.13c (p3) /
|
||||
/ FatFs - Generic FAT Filesystem Module R0.13c (p4) /
|
||||
/-----------------------------------------------------------------------------/
|
||||
/
|
||||
/ Copyright (C) 2018, ChaN, all right reserved.
|
||||
/ Copyright (c) 2018 naehrwert
|
||||
/ Copyright (C) 2018-2019 CTCaer
|
||||
/
|
||||
/ FatFs module is an open source software. Redistribution and use of FatFs in
|
||||
/ source and binary forms, with or without modification, are permitted provided
|
||||
|
@ -3472,7 +3487,7 @@ static FRESULT find_volume ( /* FR_OK(0): successful, !=0: an error occurred */
|
|||
#if FF_USE_LFN == 1
|
||||
fs->lfnbuf = LfnBuf; /* Static LFN working buffer */
|
||||
#if FF_FS_EXFAT
|
||||
fs->dirbuf = DirBuf; /* Static directory block scratchpad buuffer */
|
||||
fs->dirbuf = DirBuf; /* Static directory block scratchpad buffer */
|
||||
#endif
|
||||
#endif
|
||||
#if FF_FS_RPATH != 0
|
||||
|
@ -4243,9 +4258,9 @@ FRESULT f_getcwd (
|
|||
TCHAR *tp = buff;
|
||||
#if FF_VOLUMES >= 2
|
||||
UINT vl;
|
||||
#endif
|
||||
#if FF_STR_VOLUME_ID
|
||||
const char *vp;
|
||||
#endif
|
||||
#endif
|
||||
FILINFO fno;
|
||||
DEF_NAMBUF
|
||||
|
@ -4726,7 +4741,7 @@ FRESULT f_getfree (
|
|||
/* Get logical drive */
|
||||
res = find_volume(&path, &fs, 0);
|
||||
if (res == FR_OK) {
|
||||
*fatfs = fs; /* Return ptr to the fs object */
|
||||
if (fatfs) *fatfs = fs; /* Return ptr to the fs object */
|
||||
/* If free_clst is valid, return it without full FAT scan */
|
||||
if (fs->free_clst <= fs->n_fatent - 2) {
|
||||
*nclst = fs->free_clst;
|
||||
|
@ -6632,4 +6647,3 @@ FRESULT f_setcp (
|
|||
return FR_OK;
|
||||
}
|
||||
#endif /* FF_CODE_PAGE == 0 */
|
||||
|
||||
|
|
|
@ -95,6 +95,7 @@ typedef DWORD FSIZE_t;
|
|||
/* Filesystem object structure (FATFS) */
|
||||
|
||||
typedef struct {
|
||||
BYTE win[FF_MAX_SS]; /* Disk access window for Directory, FAT (and file data at tiny cfg) */
|
||||
BYTE fs_type; /* Filesystem type (0:not mounted) */
|
||||
BYTE pdrv; /* Associated physical drive */
|
||||
BYTE n_fats; /* Number of FATs (1 or 2) */
|
||||
|
@ -137,8 +138,6 @@ typedef struct {
|
|||
DWORD bitbase; /* Allocation bitmap base sector */
|
||||
#endif
|
||||
DWORD winsect; /* Current sector appearing in the win[] */
|
||||
DWORD padding; /* Ensure window is 16-aligned */
|
||||
BYTE win[FF_MAX_SS]; /* Disk access window for Directory, FAT (and file data at tiny cfg) */
|
||||
} FATFS;
|
||||
|
||||
|
||||
|
@ -169,6 +168,9 @@ typedef struct {
|
|||
/* File object structure (FIL) */
|
||||
|
||||
typedef struct {
|
||||
#if !FF_FS_TINY
|
||||
BYTE buf[FF_MAX_SS]; /* File private data read/write window */
|
||||
#endif
|
||||
FFOBJID obj; /* Object identifier (must be the 1st member to detect invalid object pointer) */
|
||||
BYTE flag; /* File status flags */
|
||||
BYTE err; /* Abort flag (error code) */
|
||||
|
@ -179,9 +181,6 @@ typedef struct {
|
|||
DWORD dir_sect; /* Sector number containing the directory entry (not used at exFAT) */
|
||||
BYTE* dir_ptr; /* Pointer to the directory entry in the win[] (not used at exFAT) */
|
||||
#endif
|
||||
#if !FF_FS_TINY
|
||||
BYTE buf[FF_MAX_SS]; /* File private data read/write window */
|
||||
#endif
|
||||
#if FF_USE_FASTSEEK
|
||||
DWORD* cltbl; /* Pointer to the cluster link map table (nulled on open, set by application) */
|
||||
#endif
|
||||
|
@ -280,7 +279,7 @@ FRESULT f_getfree (const TCHAR* path, DWORD* nclst, FATFS** fatfs); /* Get numbe
|
|||
FRESULT f_getlabel (const TCHAR* path, TCHAR* label, DWORD* vsn); /* Get volume label */
|
||||
FRESULT f_setlabel (const TCHAR* label); /* Set volume label */
|
||||
FRESULT f_forward (FIL* fp, UINT(*func)(const BYTE*,UINT), UINT btf, UINT* bf); /* Forward data to the stream */
|
||||
FRESULT f_expand (FIL* fp, FSIZE_t szf, BYTE opt); /* Allocate a contiguous block to the file */
|
||||
FRESULT f_expand (FIL* fp, FSIZE_t fsz, BYTE opt); /* Allocate a contiguous block to the file */
|
||||
FRESULT f_mount (FATFS* fs, const TCHAR* path, BYTE opt); /* Mount/Unmount a logical drive */
|
||||
FRESULT f_mkfs (const TCHAR* path, BYTE opt, DWORD au, void* work, UINT len); /* Create a FAT volume */
|
||||
FRESULT f_fdisk (BYTE pdrv, const DWORD* szt, void* work); /* Divide a physical drive into some partitions */
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
/ 3: f_lseek() function is removed in addition to 2. */
|
||||
|
||||
|
||||
#define FF_USE_STRFUNC 0
|
||||
#define FF_USE_STRFUNC 2
|
||||
/* This option switches string functions, f_gets(), f_putc(), f_puts() and f_printf().
|
||||
/
|
||||
/ 0: Disable string functions.
|
||||
|
@ -33,7 +33,7 @@
|
|||
/ 2: Enable with LF-CRLF conversion. */
|
||||
|
||||
|
||||
#define FF_USE_FIND 0
|
||||
#define FF_USE_FIND 1
|
||||
/* This option switches filtered directory read functions, f_findfirst() and
|
||||
/ f_findnext(). (0:Disable, 1:Enable 2:Enable with matching altname[] too) */
|
||||
|
||||
|
@ -50,7 +50,7 @@
|
|||
/* This option switches f_expand function. (0:Disable or 1:Enable) */
|
||||
|
||||
|
||||
#define FF_USE_CHMOD 0
|
||||
#define FF_USE_CHMOD 1
|
||||
/* This option switches attribute manipulation functions, f_chmod() and f_utime().
|
||||
/ (0:Disable or 1:Enable) Also FF_FS_READONLY needs to be 0 to enable this option. */
|
||||
|
||||
|
@ -97,7 +97,7 @@
|
|||
*/
|
||||
|
||||
|
||||
#define FF_USE_LFN 1
|
||||
#define FF_USE_LFN 3
|
||||
#define FF_MAX_LFN 255
|
||||
/* The FF_USE_LFN switches the support for LFN (long file name).
|
||||
/
|
||||
|
|
|
@ -34,7 +34,6 @@
|
|||
#define MERGE2(a, b) a ## b
|
||||
#define CVTBL(tbl, cp) MERGE2(tbl, cp)
|
||||
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Code Conversion Tables */
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
@ -623,5 +622,4 @@ DWORD ff_wtoupper ( /* Returns up-converted code point */
|
|||
return uni;
|
||||
}
|
||||
|
||||
|
||||
#endif /* #if FF_USE_LFN */
|
||||
|
|
304
source/main.c
304
source/main.c
|
@ -18,24 +18,36 @@
|
|||
|
||||
#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/util.h"
|
||||
#include "utils/btn.h"
|
||||
#include "meme/main.h"
|
||||
#include "meme/utils.h"
|
||||
#include "utils/dirlist.h"
|
||||
#include "utils/sprintf.h"
|
||||
#include "utils/util.h"
|
||||
#include "tegraexplorer/te.h"
|
||||
|
||||
//#include "keys/keys.h"
|
||||
|
||||
sdmmc_t sd_sdmmc;
|
||||
sdmmc_storage_t sd_storage;
|
||||
__attribute__ ((aligned (16))) FATFS sd_fs;
|
||||
static bool sd_mounted;
|
||||
|
||||
hekate_config h_cfg;
|
||||
boot_cfg_t __attribute__((section ("._boot_cfg"))) b_cfg;
|
||||
|
||||
bool sd_mount()
|
||||
|
@ -108,7 +120,7 @@ int sd_save_to_file(void *buf, u32 size, const char *filename)
|
|||
if (res)
|
||||
{
|
||||
EPRINTFARGS("Error (%d) creating file\n%s.\n", res, filename);
|
||||
return 1;
|
||||
return res;
|
||||
}
|
||||
|
||||
f_write(&fp, buf, size, NULL);
|
||||
|
@ -121,11 +133,13 @@ int sd_save_to_file(void *buf, u32 size, const char *filename)
|
|||
#define RELOC_META_OFF 0x7C
|
||||
#define PATCHED_RELOC_SZ 0x94
|
||||
#define PATCHED_RELOC_STACK 0x40007000
|
||||
#define PATCHED_RELOC_ENTRY 0x40010000
|
||||
#define EXT_PAYLOAD_ADDR 0xC03C0000
|
||||
#define RCM_PAYLOAD_ADDR (EXT_PAYLOAD_ADDR + ALIGN(PATCHED_RELOC_SZ, 0x10))
|
||||
#define COREBOOT_ADDR (0xD0000000 - 0x100000)
|
||||
#define CBFS_DRAM_EN_ADDR 0x4003e000
|
||||
#define CBFS_DRAM_MAGIC 0x4452414D // "DRAM"
|
||||
|
||||
|
||||
void reloc_patcher(u32 payload_dst, u32 payload_src, u32 payload_size)
|
||||
{
|
||||
memcpy((u8 *)payload_src, (u8 *)IPL_LOAD_ADDR, PATCHED_RELOC_SZ);
|
||||
|
@ -144,23 +158,297 @@ void reloc_patcher(u32 payload_dst, u32 payload_src, u32 payload_size)
|
|||
}
|
||||
}
|
||||
|
||||
#define IPL_STACK_TOP 0x4003F000
|
||||
int launch_payload(char *path)
|
||||
{
|
||||
gfx_clear_grey(0x1B);
|
||||
gfx_con_setpos(0, 0);
|
||||
if (!path)
|
||||
return 1;
|
||||
|
||||
if (sd_mount())
|
||||
{
|
||||
FIL fp;
|
||||
if (f_open(&fp, path, FA_READ))
|
||||
{
|
||||
EPRINTFARGS("Payload file is missing!\n(%s)", path);
|
||||
sd_unmount();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Read and copy the payload to our chosen address
|
||||
void *buf;
|
||||
u32 size = f_size(&fp);
|
||||
|
||||
if (size < 0x30000)
|
||||
buf = (void *)RCM_PAYLOAD_ADDR;
|
||||
else
|
||||
buf = (void *)COREBOOT_ADDR;
|
||||
|
||||
if (f_read(&fp, buf, size, NULL))
|
||||
{
|
||||
f_close(&fp);
|
||||
sd_unmount();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
f_close(&fp);
|
||||
|
||||
sd_unmount();
|
||||
|
||||
if (size < 0x30000)
|
||||
{
|
||||
reloc_patcher(PATCHED_RELOC_ENTRY, EXT_PAYLOAD_ADDR, ALIGN(size, 0x10));
|
||||
|
||||
reconfig_hw_workaround(false, byte_swap_32(*(u32 *)(buf + size - sizeof(u32))));
|
||||
}
|
||||
else
|
||||
{
|
||||
reloc_patcher(PATCHED_RELOC_ENTRY, EXT_PAYLOAD_ADDR, 0x7000);
|
||||
reconfig_hw_workaround(true, 0);
|
||||
}
|
||||
|
||||
// Some cards (Sandisk U1), do not like a fast power cycle. Wait min 100ms.
|
||||
sdmmc_storage_init_wait_sd();
|
||||
|
||||
void (*ext_payload_ptr)() = (void *)EXT_PAYLOAD_ADDR;
|
||||
|
||||
// Launch our payload.
|
||||
(*ext_payload_ptr)();
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void launch_tools()
|
||||
{
|
||||
u8 max_entries = 61;
|
||||
char *filelist = NULL;
|
||||
char *file_sec = NULL;
|
||||
char *dir = NULL;
|
||||
|
||||
ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * (max_entries + 3));
|
||||
|
||||
gfx_clear_grey(0x1B);
|
||||
gfx_con_setpos(0, 0);
|
||||
|
||||
if (sd_mount())
|
||||
{
|
||||
dir = (char *)malloc(256);
|
||||
|
||||
memcpy(dir, "sd:/bootloader/payloads", 24);
|
||||
|
||||
filelist = dirlist(dir, NULL, false);
|
||||
|
||||
u32 i = 0;
|
||||
u32 i_off = 2;
|
||||
|
||||
if (filelist)
|
||||
{
|
||||
// Build configuration menu.
|
||||
u32 color_idx = 0;
|
||||
|
||||
ments[0].type = MENT_BACK;
|
||||
ments[0].caption = "Back";
|
||||
ments[0].color = colors[(color_idx++) % 6];
|
||||
ments[1].type = MENT_CHGLINE;
|
||||
ments[1].color = colors[(color_idx++) % 6];
|
||||
if (!f_stat("sd:/atmosphere/reboot_payload.bin", NULL))
|
||||
{
|
||||
ments[i_off].type = INI_CHOICE;
|
||||
ments[i_off].caption = "reboot_payload.bin";
|
||||
ments[i_off].color = colors[(color_idx++) % 6];
|
||||
ments[i_off].data = "sd:/atmosphere/reboot_payload.bin";
|
||||
i_off++;
|
||||
}
|
||||
if (!f_stat("sd:/ReiNX.bin", NULL))
|
||||
{
|
||||
ments[i_off].type = INI_CHOICE;
|
||||
ments[i_off].caption = "ReiNX.bin";
|
||||
ments[i_off].color = colors[(color_idx++) % 6];
|
||||
ments[i_off].data = "sd:/ReiNX.bin";
|
||||
i_off++;
|
||||
}
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (i > max_entries || !filelist[i * 256])
|
||||
break;
|
||||
ments[i + i_off].type = INI_CHOICE;
|
||||
ments[i + i_off].caption = &filelist[i * 256];
|
||||
ments[i + i_off].color = colors[(color_idx++) % 6];
|
||||
ments[i + i_off].data = &filelist[i * 256];
|
||||
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
if (i > 0)
|
||||
{
|
||||
memset(&ments[i + i_off], 0, sizeof(ment_t));
|
||||
menu_t menu = { ments, "Choose a file to launch", 0, 0 };
|
||||
|
||||
file_sec = (char *)tui_do_menu(&menu);
|
||||
|
||||
if (!file_sec)
|
||||
{
|
||||
free(ments);
|
||||
free(dir);
|
||||
free(filelist);
|
||||
sd_unmount();
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
EPRINTF("No payloads or modules found.");
|
||||
|
||||
free(ments);
|
||||
free(filelist);
|
||||
}
|
||||
else
|
||||
{
|
||||
free(ments);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (file_sec)
|
||||
{
|
||||
if (memcmp("sd:/", file_sec, 4)) {
|
||||
memcpy(dir + strlen(dir), "/", 2);
|
||||
memcpy(dir + strlen(dir), file_sec, strlen(file_sec) + 1);
|
||||
}
|
||||
else
|
||||
memcpy(dir, file_sec, strlen(file_sec) + 1);
|
||||
|
||||
if (launch_payload(dir))
|
||||
{
|
||||
EPRINTF("Failed to launch payload.");
|
||||
free(dir);
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
sd_unmount();
|
||||
free(dir);
|
||||
|
||||
btn_wait();
|
||||
}
|
||||
|
||||
void dump_sysnand()
|
||||
{
|
||||
h_cfg.emummc_force_disable = true;
|
||||
b_cfg.extra_cfg &= ~EXTRA_CFG_DUMP_EMUMMC;
|
||||
dump_keys();
|
||||
}
|
||||
|
||||
void dump_emunand()
|
||||
{
|
||||
if (h_cfg.emummc_force_disable)
|
||||
return;
|
||||
emu_cfg.enabled = 1;
|
||||
b_cfg.extra_cfg |= EXTRA_CFG_DUMP_EMUMMC;
|
||||
dump_keys();
|
||||
}
|
||||
|
||||
ment_t ment_top[] = {
|
||||
MDEF_HANDLER("Dump from SysNAND | Key generation: unk", dump_sysnand, COLOR_RED),
|
||||
MDEF_HANDLER("Dump from EmuNAND | Key generation: unk", dump_emunand, COLOR_ORANGE),
|
||||
MDEF_CAPTION("---------------", COLOR_YELLOW),
|
||||
MDEF_HANDLER("Payloads...", launch_tools, COLOR_GREEN),
|
||||
MDEF_CAPTION("---------------", COLOR_BLUE),
|
||||
MDEF_HANDLER("Reboot (Normal)", reboot_normal, COLOR_VIOLET),
|
||||
MDEF_HANDLER("Reboot (RCM)", reboot_rcm, COLOR_RED),
|
||||
MDEF_HANDLER("Power off", power_off, COLOR_ORANGE),
|
||||
MDEF_END()
|
||||
};
|
||||
|
||||
menu_t menu_top = { ment_top, NULL, 0, 0 };
|
||||
|
||||
void _get_key_generations(char *sysnand_label, char *emunand_label) {
|
||||
sdmmc_t sdmmc;
|
||||
sdmmc_storage_t storage;
|
||||
sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4);
|
||||
u8 *pkg1 = (u8 *)malloc(NX_EMMC_BLOCKSIZE);
|
||||
sdmmc_storage_set_mmc_partition(&storage, 1);
|
||||
sdmmc_storage_read(&storage, 0x100000 / NX_EMMC_BLOCKSIZE, 1, pkg1);
|
||||
const pkg1_id_t *pkg1_id = pkg1_identify(pkg1);
|
||||
sdmmc_storage_end(&storage);
|
||||
|
||||
if (pkg1_id)
|
||||
sprintf(sysnand_label + 36, "% 3d", pkg1_id->kb);
|
||||
ment_top[0].caption = sysnand_label;
|
||||
if (h_cfg.emummc_force_disable) {
|
||||
free(pkg1);
|
||||
return;
|
||||
}
|
||||
|
||||
emummc_storage_init_mmc(&storage, &sdmmc);
|
||||
memset(pkg1, 0, NX_EMMC_BLOCKSIZE);
|
||||
emummc_storage_set_mmc_partition(&storage, 1);
|
||||
emummc_storage_read(&storage, 0x100000 / NX_EMMC_BLOCKSIZE, 1, pkg1);
|
||||
pkg1_id = pkg1_identify(pkg1);
|
||||
emummc_storage_end(&storage);
|
||||
|
||||
if (pkg1_id)
|
||||
sprintf(emunand_label + 36, "% 3d", pkg1_id->kb);
|
||||
free(pkg1);
|
||||
ment_top[1].caption = emunand_label;
|
||||
}
|
||||
|
||||
#define IPL_STACK_TOP 0x90010000
|
||||
#define IPL_HEAP_START 0x90020000
|
||||
|
||||
extern void pivot_stack(u32 stack_top);
|
||||
|
||||
// todo: chainload to reboot payload or payloads folder option?
|
||||
|
||||
void ipl_main()
|
||||
{
|
||||
config_hw();
|
||||
pivot_stack(IPL_STACK_TOP);
|
||||
heap_init(IPL_HEAP_START);
|
||||
|
||||
set_default_configuration();
|
||||
|
||||
sd_mount();
|
||||
minerva_init();
|
||||
minerva_change_freq(FREQ_1600);
|
||||
|
||||
display_init();
|
||||
u32 *fb = display_init_framebuffer();
|
||||
gfx_init_ctxt(fb, 720, 1280, 720);
|
||||
gfx_con_init();
|
||||
display_backlight_pwm_init();
|
||||
display_backlight_brightness(100, 1000);
|
||||
|
||||
meme_main();
|
||||
sd_unmount();
|
||||
bpmp_clk_rate_set(BPMP_CLK_SUPER_BOOST);
|
||||
|
||||
/*
|
||||
h_cfg.emummc_force_disable = emummc_load_cfg();
|
||||
|
||||
if (b_cfg.boot_cfg & BOOT_CFG_SEPT_RUN)
|
||||
{
|
||||
if (!(b_cfg.extra_cfg & EXTRA_CFG_DUMP_EMUMMC))
|
||||
h_cfg.emummc_force_disable = true;
|
||||
dump_keys();
|
||||
}
|
||||
|
||||
if (h_cfg.emummc_force_disable)
|
||||
{
|
||||
ment_top[1].type = MENT_CAPTION;
|
||||
ment_top[1].color = 0xFF555555;
|
||||
ment_top[1].handler = NULL;
|
||||
}
|
||||
|
||||
_get_key_generations((char *)ment_top[0].caption, (char *)ment_top[1].caption);
|
||||
|
||||
while (true)
|
||||
tui_do_menu(&menu_top);
|
||||
*/
|
||||
|
||||
te_main();
|
||||
|
||||
while (true)
|
||||
bpmp_halt();
|
||||
}
|
||||
|
|
|
@ -56,6 +56,7 @@ static u32 _heap_alloc(heap_t *heap, u32 size, u32 alignment)
|
|||
node->used = 1;
|
||||
new->used = 0;
|
||||
new->next = node->next;
|
||||
new->next->prev = new;
|
||||
new->prev = node;
|
||||
node->next = new;
|
||||
|
||||
|
@ -107,17 +108,12 @@ void heap_init(u32 base)
|
|||
|
||||
void *malloc(u32 size)
|
||||
{
|
||||
return (void *)_heap_alloc(&_heap, size, 0x10);
|
||||
}
|
||||
|
||||
void *memalign(u32 align, u32 size)
|
||||
{
|
||||
return (void *)_heap_alloc(&_heap, size, align);
|
||||
return (void *)_heap_alloc(&_heap, size, sizeof(hnode_t));
|
||||
}
|
||||
|
||||
void *calloc(u32 num, u32 size)
|
||||
{
|
||||
void *res = (void *)_heap_alloc(&_heap, num * size, 0x10);
|
||||
void *res = (void *)_heap_alloc(&_heap, num * size, sizeof(hnode_t));
|
||||
memset(res, 0, num * size);
|
||||
return res;
|
||||
}
|
||||
|
|
|
@ -23,6 +23,5 @@ void heap_init(u32 base);
|
|||
void *malloc(u32 size);
|
||||
void *calloc(u32 num, u32 size);
|
||||
void free(void *buf);
|
||||
void *memalign(u32 align, u32 size);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -127,7 +127,7 @@ void mc_disable_ahb_redirect()
|
|||
void mc_enable()
|
||||
{
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC) & 0x1FFFFFFF) | 0x40000000;
|
||||
// Enable MIPI CAL clock.
|
||||
// Enable EMC clock.
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) = (CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) & 0xFDFFFFFF) | 0x2000000;
|
||||
// Enable MC clock.
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) = (CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) & 0xFFFFFFFE) | 1;
|
||||
|
|
88
source/mem/minerva.c
Normal file
88
source/mem/minerva.c
Normal file
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
* Copyright (c) 2019 CTCaer
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <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"
|
||||
|
||||
volatile nyx_storage_t *nyx_str = (nyx_storage_t *)0xED000000;
|
||||
|
||||
void minerva_init()
|
||||
{
|
||||
u32 curr_ram_idx = 0;
|
||||
|
||||
mtc_config_t *mtc_cfg = (mtc_config_t *)&nyx_str->mtc_cfg;
|
||||
|
||||
// Set table to ram.
|
||||
mtc_cfg->mtc_table = NULL;
|
||||
mtc_cfg->sdram_id = (fuse_read_odm(4) >> 3) & 0x1F;
|
||||
u32 ep_addr = ianos_loader(false, "bootloader/sys/libsys_minerva.bso", DRAM_LIB, (void *)mtc_cfg);
|
||||
minerva_cfg = (void *)ep_addr;
|
||||
|
||||
if (!minerva_cfg)
|
||||
return;
|
||||
|
||||
// Get current frequency
|
||||
for (curr_ram_idx = 0; curr_ram_idx < 10; curr_ram_idx++)
|
||||
{
|
||||
if (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC) == mtc_cfg->mtc_table[curr_ram_idx].clk_src_emc)
|
||||
break;
|
||||
}
|
||||
|
||||
mtc_cfg->rate_from = mtc_cfg->mtc_table[curr_ram_idx].rate_khz;
|
||||
mtc_cfg->rate_to = 204000;
|
||||
mtc_cfg->train_mode = OP_TRAIN;
|
||||
minerva_cfg(mtc_cfg, NULL);
|
||||
mtc_cfg->rate_to = 800000;
|
||||
minerva_cfg(mtc_cfg, NULL);
|
||||
mtc_cfg->rate_to = 1600000;
|
||||
minerva_cfg(mtc_cfg, NULL);
|
||||
}
|
||||
|
||||
void minerva_change_freq(minerva_freq_t freq)
|
||||
{
|
||||
if (!minerva_cfg)
|
||||
return;
|
||||
|
||||
mtc_config_t *mtc_cfg = (mtc_config_t *)&nyx_str->mtc_cfg;
|
||||
if (minerva_cfg && (mtc_cfg->rate_from != freq))
|
||||
{
|
||||
mtc_cfg->rate_to = freq;
|
||||
mtc_cfg->train_mode = OP_SWITCH;
|
||||
minerva_cfg(mtc_cfg, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
void minerva_periodic_training()
|
||||
{
|
||||
if (!minerva_cfg)
|
||||
return;
|
||||
|
||||
mtc_config_t *mtc_cfg = (mtc_config_t *)&nyx_str->mtc_cfg;
|
||||
if (minerva_cfg && mtc_cfg->rate_from == FREQ_1600)
|
||||
{
|
||||
mtc_cfg->train_mode = OP_PERIODIC_TRAIN;
|
||||
minerva_cfg(mtc_cfg, NULL);
|
||||
}
|
||||
}
|
61
source/mem/minerva.h
Normal file
61
source/mem/minerva.h
Normal file
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* Copyright (c) 2019 CTCaer
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _FE_MINERVA_H_
|
||||
#define _FE_MINERVA_H_
|
||||
|
||||
#include "mtc_table.h"
|
||||
#include "../utils/types.h"
|
||||
|
||||
#define EMC_PERIODIC_TRAIN_MS 100
|
||||
|
||||
typedef struct
|
||||
{
|
||||
s32 rate_to;
|
||||
s32 rate_from;
|
||||
emc_table_t *mtc_table;
|
||||
u32 table_entries;
|
||||
emc_table_t *current_emc_table;
|
||||
u32 train_mode;
|
||||
u32 sdram_id;
|
||||
u32 prev_temp;
|
||||
bool emc_2X_clk_src_is_pllmb;
|
||||
bool fsp_for_src_freq;
|
||||
bool train_ram_patterns;
|
||||
} mtc_config_t;
|
||||
|
||||
enum train_mode_t
|
||||
{
|
||||
OP_SWITCH = 0,
|
||||
OP_TRAIN = 1,
|
||||
OP_TRAIN_SWITCH = 2,
|
||||
OP_PERIODIC_TRAIN = 3,
|
||||
OP_TEMP_COMP = 4
|
||||
};
|
||||
|
||||
typedef enum
|
||||
{
|
||||
FREQ_204 = 204000,
|
||||
FREQ_800 = 800000,
|
||||
FREQ_1600 = 1600000
|
||||
} minerva_freq_t;
|
||||
|
||||
void (*minerva_cfg)(mtc_config_t *mtc_cfg, void *);
|
||||
void minerva_init();
|
||||
void minerva_change_freq(minerva_freq_t freq);
|
||||
void minerva_periodic_training();
|
||||
|
||||
#endif
|
560
source/mem/mtc_table.h
Normal file
560
source/mem/mtc_table.h
Normal 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
|
|
@ -39,7 +39,13 @@
|
|||
|
||||
static u32 _get_sdram_id()
|
||||
{
|
||||
return (fuse_read_odm(4) & 0x38) >> 3;
|
||||
u32 sdram_id = (fuse_read_odm(4) & 0x38) >> 3;
|
||||
|
||||
// Check if id is proper.
|
||||
if (sdram_id > 7)
|
||||
sdram_id = 0;
|
||||
|
||||
return sdram_id;
|
||||
}
|
||||
|
||||
static void _sdram_config(const sdram_params_t *params)
|
||||
|
@ -539,7 +545,7 @@ void sdram_init()
|
|||
const sdram_params_t *params = (const sdram_params_t *)sdram_get_params();
|
||||
|
||||
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_SD_CFG2, 0x05);
|
||||
max77620_regulator_set_voltage(REGULATOR_SD1, 1100000);
|
||||
max77620_regulator_set_voltage(REGULATOR_SD1, 1100000); // Set DRAM voltage.
|
||||
|
||||
PMC(APBDEV_PMC_VDDP_SEL) = params->pmc_vddp_sel;
|
||||
usleep(params->pmc_vddp_sel_wait);
|
||||
|
|
|
@ -1,232 +0,0 @@
|
|||
#include "external_utils.h"
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include "../gfx/di.h"
|
||||
#include "../gfx/gfx.h"
|
||||
#include "../utils/btn.h"
|
||||
#include "../utils/util.h"
|
||||
#include "utils.h"
|
||||
#include "../libs/fatfs/ff.h"
|
||||
#include "../storage/sdmmc.h"
|
||||
#include "graphics.h"
|
||||
#include "../soc/hw_init.h"
|
||||
#include "../mem/emc.h"
|
||||
#include "../mem/sdram.h"
|
||||
#include "../soc/t210.h"
|
||||
#include "../sec/se.h"
|
||||
#include "../utils/types.h"
|
||||
#include "../hos/pkg1.h"
|
||||
#include "../storage/nx_emmc.h"
|
||||
#include "../sec/tsec.h"
|
||||
#include "../soc/t210.h"
|
||||
#include "../soc/fuse.h"
|
||||
#include "../mem/mc.h"
|
||||
|
||||
extern void reloc_patcher(u32 payload_dst, u32 payload_src, u32 payload_size);
|
||||
extern boot_cfg_t b_cfg;
|
||||
extern bool sd_mount();
|
||||
extern void sd_unmount();
|
||||
static bool _key_exists(const void *data) { return memcmp(data, zeros, 0x10); };
|
||||
static void _generate_kek(u32 ks, const void *key_source, void *master_key, const void *kek_seed, const void *key_seed);
|
||||
|
||||
sdmmc_storage_t storage;
|
||||
emmc_part_t *system_part;
|
||||
sdmmc_t sdmmc;
|
||||
|
||||
int launch_payload(char *path, bool update){
|
||||
if (!update) 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)){
|
||||
EPRINTF("Payload missing!\n");
|
||||
return 2;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
return 3;
|
||||
}
|
||||
|
||||
f_close(&fp);
|
||||
|
||||
sd_unmount();
|
||||
|
||||
if (size < 0x30000){
|
||||
reloc_patcher(PATCHED_RELOC_ENTRY, EXT_PAYLOAD_ADDR, ALIGN(size, 0x10));
|
||||
|
||||
reconfig_hw_workaround(false, byte_swap_32(*(u32 *)(buf + size - sizeof(u32))));
|
||||
}
|
||||
else {
|
||||
reloc_patcher(PATCHED_RELOC_ENTRY, EXT_PAYLOAD_ADDR, 0x7000);
|
||||
reconfig_hw_workaround(true, 0);
|
||||
}
|
||||
|
||||
void (*ext_payload_ptr)() = (void *)EXT_PAYLOAD_ADDR;
|
||||
void (*update_ptr)() = (void *)RCM_PAYLOAD_ADDR;
|
||||
|
||||
msleep(100);
|
||||
|
||||
if (!update)
|
||||
(*ext_payload_ptr)();
|
||||
else {
|
||||
EMC(EMC_SCRATCH0) |= EMC_HEKA_UPD;
|
||||
(*update_ptr)();
|
||||
}
|
||||
}
|
||||
|
||||
return 4;
|
||||
}
|
||||
|
||||
int dump_biskeys(u8 bis_key[4][32]){
|
||||
u8 temp_key[0x10], device_key[0x10] = {0};
|
||||
tsec_ctxt_t tsec_ctxt;
|
||||
|
||||
int retries = 0;
|
||||
|
||||
sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4);
|
||||
|
||||
// Read package1.
|
||||
u8 *pkg1 = (u8 *)malloc(0x40000);
|
||||
sdmmc_storage_set_mmc_partition(&storage, 1);
|
||||
sdmmc_storage_read(&storage, 0x100000 / NX_EMMC_BLOCKSIZE, 0x40000 / NX_EMMC_BLOCKSIZE, pkg1);
|
||||
const pkg1_id_t *pkg1_id = pkg1_identify(pkg1);
|
||||
if (!pkg1_id) {
|
||||
EPRINTF("Unknown pkg1 version.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool found_tsec_fw = false;
|
||||
for (const u32 *pos = (const u32 *)pkg1; (u8 *)pos < pkg1 + 0x40000; pos += 0x100 / sizeof(u32)) {
|
||||
if (*pos == 0xCF42004D) {
|
||||
tsec_ctxt.fw = (u8 *)pos;
|
||||
found_tsec_fw = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found_tsec_fw) {
|
||||
EPRINTF("Failed to locate TSEC firmware.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
u8 tsec_keys[0x10] = {0};
|
||||
|
||||
tsec_key_data_t *key_data = (tsec_key_data_t *)(tsec_ctxt.fw + TSEC_KEY_DATA_ADDR);
|
||||
tsec_ctxt.pkg1 = pkg1;
|
||||
tsec_ctxt.size = 0x100 + key_data->blob0_size + key_data->blob1_size + key_data->blob2_size + key_data->blob3_size + key_data->blob4_size;
|
||||
if (pkg1_id->kb >= KB_FIRMWARE_VERSION_700) {
|
||||
// Exit after TSEC key generation.
|
||||
*((vu16 *)((u32)tsec_ctxt.fw + 0x2DB5)) = 0x02F8;
|
||||
}
|
||||
|
||||
int res = 0;
|
||||
|
||||
mc_disable_ahb_redirect();
|
||||
|
||||
while (tsec_query(tsec_keys, 0, &tsec_ctxt) < 0) {
|
||||
memset(tsec_keys, 0x00, 0x10);
|
||||
retries++;
|
||||
if (retries > 15) {
|
||||
res = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
free(pkg1);
|
||||
|
||||
mc_enable_ahb_redirect();
|
||||
|
||||
if (res < 0) {
|
||||
gfx_printf("ERROR %x dumping TSEC.\n", res);
|
||||
return -1;
|
||||
}
|
||||
|
||||
u32 sbk[4] = {FUSE(FUSE_PRIVATE_KEY0), FUSE(FUSE_PRIVATE_KEY1),
|
||||
FUSE(FUSE_PRIVATE_KEY2), FUSE(FUSE_PRIVATE_KEY3)};
|
||||
se_aes_key_set(8, tsec_keys, 0x10);
|
||||
se_aes_key_set(9, sbk, 0x10);
|
||||
se_aes_crypt_block_ecb(8, 0, temp_key, keyblob_key_source);
|
||||
se_aes_crypt_block_ecb(9, 0, temp_key, temp_key);
|
||||
se_aes_key_set(7, temp_key, 0x10);
|
||||
se_aes_crypt_block_ecb(7, 0, device_key, per_console_key_source);
|
||||
|
||||
/* key = unwrap(source, wrapped_key):
|
||||
key_set(ks, wrapped_key), block_ecb(ks, 0, key, source) -> final key in key
|
||||
*/
|
||||
if (_key_exists(device_key)) {
|
||||
se_aes_key_set(8, device_key, 0x10);
|
||||
se_aes_unwrap_key(8, 8, retail_specific_aes_key_source); // kek = unwrap(rsaks, devkey)
|
||||
se_aes_crypt_block_ecb(8, 0, bis_key[0] + 0x00, bis_key_source[0] + 0x00); // bkey = unwrap(bkeys, kek)
|
||||
se_aes_crypt_block_ecb(8, 0, bis_key[0] + 0x10, bis_key_source[0] + 0x10);
|
||||
// kek = generate_kek(bkeks, devkey, aeskek, aeskey)
|
||||
_generate_kek(8, bis_kek_source, device_key, aes_kek_generation_source, aes_key_generation_source);
|
||||
se_aes_crypt_block_ecb(8, 0, bis_key[1] + 0x00, bis_key_source[1] + 0x00); // bkey = unwrap(bkeys, kek)
|
||||
se_aes_crypt_block_ecb(8, 0, bis_key[1] + 0x10, bis_key_source[1] + 0x10);
|
||||
se_aes_crypt_block_ecb(8, 0, bis_key[2] + 0x00, bis_key_source[2] + 0x00);
|
||||
se_aes_crypt_block_ecb(8, 0, bis_key[2] + 0x10, bis_key_source[2] + 0x10);
|
||||
memcpy(bis_key[3], bis_key[2], 0x20);
|
||||
}
|
||||
|
||||
sdmmc_storage_set_mmc_partition(&storage, 0);
|
||||
// Parse eMMC GPT.
|
||||
LIST_INIT(gpt);
|
||||
nx_emmc_gpt_parse(&gpt, &storage);
|
||||
|
||||
/*
|
||||
char part_name[37] = "SYSTEM";
|
||||
|
||||
// todo: menu selection for this
|
||||
|
||||
u32 bis_key_index = 0;
|
||||
if (strcmp(part_name, "PRODINFOF") == 0)
|
||||
bis_key_index = 0;
|
||||
else if (strcmp(part_name, "SAFE") == 0)
|
||||
bis_key_index = 1;
|
||||
else if (strcmp(part_name, "SYSTEM") == 0)
|
||||
bis_key_index = 2;
|
||||
else if (strcmp(part_name, "USER") == 0)
|
||||
bis_key_index = 3;
|
||||
else {
|
||||
gfx_printf("Partition name %s unrecognized.", part_name);
|
||||
return;
|
||||
}
|
||||
*/
|
||||
se_aes_key_set(8, bis_key[2] + 0x00, 0x10);
|
||||
se_aes_key_set(9, bis_key[2] + 0x10, 0x10);
|
||||
|
||||
system_part = nx_emmc_part_find(&gpt, "SYSTEM");
|
||||
if (!system_part) {
|
||||
gfx_printf("Failed to locate SYSTEM partition.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
__attribute__ ((aligned (16))) FATFS emmc_fs;
|
||||
if (f_mount(&emmc_fs, "emmc:", 1)) {
|
||||
gfx_printf("Mount failed.");
|
||||
return -1;
|
||||
}
|
||||
return pkg1_id->kb;
|
||||
}
|
||||
|
||||
static void _generate_kek(u32 ks, const void *key_source, void *master_key, const void *kek_seed, const void *key_seed) {
|
||||
if (!_key_exists(key_source) || !_key_exists(master_key) || !_key_exists(kek_seed))
|
||||
return;
|
||||
|
||||
se_aes_key_set(ks, master_key, 0x10);
|
||||
se_aes_unwrap_key(ks, ks, kek_seed);
|
||||
se_aes_unwrap_key(ks, ks, key_source);
|
||||
if (key_seed && _key_exists(key_seed))
|
||||
se_aes_unwrap_key(ks, ks, key_seed);
|
||||
}
|
|
@ -1,53 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#define RELOC_META_OFF 0x7C
|
||||
#define PATCHED_RELOC_SZ 0x94
|
||||
#define PATCHED_RELOC_STACK 0x40007000
|
||||
#define PATCHED_RELOC_ENTRY 0x40010000
|
||||
#define EXT_PAYLOAD_ADDR 0xC03C0000
|
||||
#define RCM_PAYLOAD_ADDR (EXT_PAYLOAD_ADDR + ALIGN(PATCHED_RELOC_SZ, 0x10))
|
||||
#define COREBOOT_ADDR (0xD0000000 - 0x100000)
|
||||
#define CBFS_DRAM_EN_ADDR 0x4003e000
|
||||
#define CBFS_DRAM_MAGIC 0x4452414D // "DRAM"
|
||||
#define EMC_BASE 0x7001B000
|
||||
#define EMC(off) _REG(EMC_BASE, off)
|
||||
|
||||
#include "../utils/types.h"
|
||||
|
||||
int launch_payload(char *path, int update);
|
||||
int dump_biskeys(u8 bis_key[4][32]);
|
||||
|
||||
static const u8 zeros[0x10] = {0};
|
||||
|
||||
static const u8 keyblob_key_source[0x10] = {
|
||||
0xDF, 0x20, 0x6F, 0x59, 0x44, 0x54, 0xEF, 0xDC, 0x70, 0x74, 0x48, 0x3B, 0x0D, 0xED, 0x9F, 0xD3};
|
||||
|
||||
//======================================Keys======================================//
|
||||
// from Package1 -> Secure_Monitor
|
||||
static const u8 aes_kek_generation_source[0x10] = {
|
||||
0x4D, 0x87, 0x09, 0x86, 0xC4, 0x5D, 0x20, 0x72, 0x2F, 0xBA, 0x10, 0x53, 0xDA, 0x92, 0xE8, 0xA9};
|
||||
static const u8 retail_specific_aes_key_source[0x10] = {
|
||||
0xE2, 0xD6, 0xB8, 0x7A, 0x11, 0x9C, 0xB8, 0x80, 0xE8, 0x22, 0x88, 0x8A, 0x46, 0xFB, 0xA1, 0x95};
|
||||
|
||||
// from Package1ldr (or Secure_Monitor on 6.2.0)
|
||||
static const u8 per_console_key_source[0x10] = {
|
||||
0x4F, 0x02, 0x5F, 0x0E, 0xB6, 0x6D, 0x11, 0x0E, 0xDC, 0x32, 0x7D, 0x41, 0x86, 0xC2, 0xF4, 0x78};
|
||||
|
||||
// from SPL
|
||||
static const u8 aes_key_generation_source[0x10] = {
|
||||
0x89, 0x61, 0x5E, 0xE0, 0x5C, 0x31, 0xB6, 0x80, 0x5F, 0xE5, 0x8F, 0x3D, 0xA2, 0x4F, 0x7A, 0xA8};
|
||||
|
||||
// from FS
|
||||
static const u8 bis_kek_source[0x10] = {
|
||||
0x34, 0xC1, 0xA0, 0xC4, 0x82, 0x58, 0xF8, 0xB4, 0xFA, 0x9E, 0x5E, 0x6A, 0xDA, 0xFC, 0x7E, 0x4F};
|
||||
static const u8 bis_key_source[3][0x20] = {
|
||||
{
|
||||
0xF8, 0x3F, 0x38, 0x6E, 0x2C, 0xD2, 0xCA, 0x32, 0xA8, 0x9A, 0xB9, 0xAA, 0x29, 0xBF, 0xC7, 0x48,
|
||||
0x7D, 0x92, 0xB0, 0x3A, 0xA8, 0xBF, 0xDE, 0xE1, 0xA7, 0x4C, 0x3B, 0x6E, 0x35, 0xCB, 0x71, 0x06},
|
||||
{
|
||||
0x41, 0x00, 0x30, 0x49, 0xDD, 0xCC, 0xC0, 0x65, 0x64, 0x7A, 0x7E, 0xB4, 0x1E, 0xED, 0x9C, 0x5F,
|
||||
0x44, 0x42, 0x4E, 0xDA, 0xB4, 0x9D, 0xFC, 0xD9, 0x87, 0x77, 0x24, 0x9A, 0xDC, 0x9F, 0x7C, 0xA4},
|
||||
{
|
||||
0x52, 0xC2, 0xE9, 0xEB, 0x09, 0xE3, 0xEE, 0x29, 0x32, 0xA1, 0x0C, 0x1F, 0xB6, 0xA0, 0x92, 0x6C,
|
||||
0x4D, 0x12, 0xE1, 0x4B, 0x2A, 0x47, 0x4C, 0x1C, 0x09, 0xCB, 0x03, 0x59, 0xF0, 0x15, 0xF4, 0xE4}
|
||||
};
|
|
@ -1,144 +0,0 @@
|
|||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include "../gfx/di.h"
|
||||
#include "../gfx/gfx.h"
|
||||
#include "../utils/btn.h"
|
||||
#include "../utils/util.h"
|
||||
#include "graphics.h"
|
||||
#include "utils.h"
|
||||
|
||||
int _copystring(char *out, const char *in, int copynumb){
|
||||
strncpy(out, in, copynumb - 1);
|
||||
int strlength = strlen(in);
|
||||
if (strlength > copynumb + 1) strlength = copynumb;
|
||||
memset(out + strlength, '\0', 1);
|
||||
int ret = copynumb - strlength;
|
||||
return ret + 4;
|
||||
}
|
||||
|
||||
int messagebox(char *message){
|
||||
int ret = -1;
|
||||
meme_clearscreen();
|
||||
gfx_printf("%s", message);
|
||||
msleep(100);
|
||||
u8 res = btn_wait();
|
||||
if (res & BTN_POWER) ret = 0;
|
||||
else ret = 1;
|
||||
meme_clearscreen();
|
||||
return ret;
|
||||
}
|
||||
|
||||
int gfx_menulist(int ypos, char *list[], int length){
|
||||
int i = 0;
|
||||
int highlight = 1;
|
||||
while(1){
|
||||
gfx_con_setpos(0, ypos);
|
||||
while(i < length){
|
||||
if (i == highlight - 1) gfx_printf("%k%p%s%k%p\n", COLOR_DEFAULT, COLOR_WHITE, list[i], COLOR_WHITE, COLOR_DEFAULT);
|
||||
else gfx_printf("%s\n", list[i]);
|
||||
i++;
|
||||
}
|
||||
i = 0;
|
||||
u8 res = btn_wait();
|
||||
if (res & BTN_VOL_UP) highlight--;
|
||||
else if (res & BTN_VOL_DOWN) highlight++;
|
||||
else if (res & BTN_POWER) break;
|
||||
if (highlight < 1) highlight = 1;
|
||||
if (highlight > length) highlight = length;
|
||||
}
|
||||
return highlight;
|
||||
}
|
||||
|
||||
void meme_clearscreen(){
|
||||
gfx_clear_grey(0x1B);
|
||||
gfx_con_setpos(0, 0);
|
||||
gfx_box(0, 0, 719, 15, COLOR_WHITE);
|
||||
gfx_printf("%k%pTegraExplorer\n%k%p", COLOR_DEFAULT, COLOR_WHITE, COLOR_WHITE, COLOR_DEFAULT);
|
||||
}
|
||||
|
||||
void _printwithhighlight(int offset, int folderamount, char *items[], int highlight, unsigned int *muhbits, int *filesizes){
|
||||
char temp[39];
|
||||
int i = 0;
|
||||
int ret = 0;
|
||||
gfx_con_setpos(0, 32);
|
||||
while(i < folderamount && i < 76){
|
||||
ret = _copystring(temp, items[i + offset], 39);
|
||||
if(i == highlight - 1) gfx_printf("\n%k%p%s%k%p", COLOR_DEFAULT, COLOR_WHITE, temp, COLOR_WHITE, COLOR_DEFAULT);
|
||||
else if ((i == 0 || i == 1) && offset == 0) gfx_printf("%k\n%s%k", COLOR_ORANGE, temp, COLOR_WHITE);
|
||||
else if (muhbits[i+offset] & OPTION1) gfx_printf("\n%s", temp);
|
||||
else gfx_printf("%k\n%s%k", COLOR_VIOLET, temp, COLOR_WHITE);
|
||||
|
||||
while(ret >= 0){
|
||||
gfx_printf(" ");
|
||||
ret = ret - 1;
|
||||
}
|
||||
|
||||
gfx_con.x = 720 - (16 * 6);
|
||||
if (!(muhbits[i + offset] & OPTION1)) { //should change later
|
||||
char temp[6];
|
||||
return_readable_byte_amounts(filesizes[i + offset], temp);
|
||||
gfx_printf("%s", temp);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
int fileexplorergui(char *items[], unsigned int *muhbits, const char path[], int folderamount){
|
||||
bool change = true;
|
||||
int select = 1;
|
||||
int sleepvalue = 300;
|
||||
int offset = 0;
|
||||
char temp[43];
|
||||
int *filesizes;
|
||||
int i = 0;
|
||||
filesizes = (int*) calloc(500, sizeof(int));
|
||||
gfx_con_setpos(0, 48);
|
||||
for (i = 0; i < folderamount; i++){
|
||||
if(!(muhbits[i] & OPTION1)){
|
||||
char temppath[PATHSIZE];
|
||||
strcpy(temppath, path);
|
||||
strcat(temppath, "/");
|
||||
strcat(temppath, items[i]);
|
||||
filesizes[i] = getfilesize(temppath);
|
||||
gfx_printf("Calcing filesizes: %d / %d\r", i, folderamount - 2);
|
||||
}
|
||||
}
|
||||
_copystring(temp, path, 43);
|
||||
gfx_con_setpos(0, 16);
|
||||
gfx_printf("%k%s\n%k", COLOR_GREEN, temp, COLOR_WHITE);
|
||||
while(1){
|
||||
if (change){
|
||||
_printwithhighlight(offset, folderamount, items, select, muhbits, filesizes);
|
||||
change = false;
|
||||
msleep(sleepvalue);
|
||||
}
|
||||
|
||||
u8 res = btn_read();
|
||||
if (res & BTN_VOL_UP){
|
||||
select = select - 1, change = true;
|
||||
sleepvalue = sleepvalue - 75;
|
||||
}
|
||||
else if (res & BTN_VOL_DOWN){
|
||||
select++, change = true;
|
||||
sleepvalue = sleepvalue - 75;
|
||||
}
|
||||
else {
|
||||
sleepvalue = 300;
|
||||
}
|
||||
if (res & BTN_POWER) break;
|
||||
if (select < 1){
|
||||
select = 1;
|
||||
if (offset > 0) offset = offset - 1;
|
||||
}
|
||||
if (select > folderamount) select = folderamount;
|
||||
if (select > 76){
|
||||
select = 76;
|
||||
if (76 + offset < folderamount) offset++;
|
||||
}
|
||||
if (sleepvalue < 30) sleepvalue = 30;
|
||||
}
|
||||
int ret = select + offset;
|
||||
free(filesizes);
|
||||
return ret;
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
int fileexplorergui(char *items[], unsigned int *muhbits, const char path[], int folderamount);
|
||||
void meme_clearscreen();
|
||||
int gfx_menulist(int ypos, char *list[], int length);
|
||||
int messagebox(char *message);
|
|
@ -1,131 +0,0 @@
|
|||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include "../gfx/di.h"
|
||||
#include "../gfx/gfx.h"
|
||||
#include "../utils/btn.h"
|
||||
#include "utils.h"
|
||||
#include "main.h"
|
||||
#include "mainfunctions.h"
|
||||
#include "../libs/fatfs/ff.h"
|
||||
#include "../utils/util.h"
|
||||
#include "graphics.h"
|
||||
#include "external_utils.h"
|
||||
|
||||
extern bool sd_mount();
|
||||
extern void sd_unmount();
|
||||
|
||||
static u32 bis_keys[4][8];
|
||||
|
||||
void meme_main(){
|
||||
utils_gfx_init();
|
||||
//dump_keys();
|
||||
|
||||
/*
|
||||
sdmmc_storage_t storage;
|
||||
sdmmc_t sdmmc;
|
||||
|
||||
sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4);
|
||||
sdmmc_storage_set_mmc_partition(&storage, 1); */
|
||||
|
||||
int firmver = -1;
|
||||
firmver = dump_biskeys(bis_keys); // add succeed check
|
||||
|
||||
char *options[6];
|
||||
char *itemsinfolder[1000];
|
||||
unsigned int muhbits[1000];
|
||||
bool sd_mounted = false;
|
||||
sd_mounted = sd_mount();
|
||||
if (!sd_mounted) messagebox("\nSD INIT FAILED");
|
||||
|
||||
while (1){
|
||||
int i = 0, ret = 0;
|
||||
if (sd_mounted){
|
||||
addchartoarray("[SD:/] SD card", options, i);
|
||||
i++;
|
||||
}
|
||||
addchartoarray("[emmc:/] SYSTEM", options, i);
|
||||
if (!sd_mounted) addchartoarray("\nMount SD", options, i+1);
|
||||
else addchartoarray("\nUnmount SD", options, i+1);
|
||||
addchartoarray("\nTools", options, i+2);
|
||||
addchartoarray("About", options, i+3);
|
||||
addchartoarray("Exit", options, i+4);
|
||||
meme_clearscreen();
|
||||
ret = gfx_menulist(32, options, (i + 5));
|
||||
|
||||
if (strcmp(options[ret - 1], "[SD:/] SD card") == 0){
|
||||
sdexplorer(itemsinfolder, muhbits, "sd:/");
|
||||
}
|
||||
else if (strcmp(options[ret - 1], "About") == 0){
|
||||
messagebox(ABOUT_MESSAGE);
|
||||
}
|
||||
else if (strcmp(options[ret - 1], "\nMount SD") == 0 || strcmp(options[ret - 1], "\nUnmount SD") == 0){
|
||||
if (sd_mounted){
|
||||
sd_unmount();
|
||||
sd_mounted = false;
|
||||
}
|
||||
else {
|
||||
sd_mounted = sd_mount();
|
||||
if (!sd_mounted) messagebox("\nSD INIT FAILED");
|
||||
}
|
||||
}
|
||||
else if (strcmp(options[ret - 1], "[emmc:/] SYSTEM") == 0){
|
||||
ret = messagebox(SYSTEM_WARNING_MESSAGE); // note: maybe add some sort of color system for messageboxes
|
||||
if (ret == 0) sdexplorer(itemsinfolder, muhbits, "emmc:/");
|
||||
}
|
||||
else if (strcmp(options[ret - 1], "\nTools") == 0){
|
||||
meme_clearscreen();
|
||||
addchartoarray("Back", options, 0);
|
||||
addchartoarray("\nPrint BISKEYS", options, 1);
|
||||
addchartoarray("Dump firmware", options, 2);
|
||||
ret = gfx_menulist(32, options, 3);
|
||||
switch(ret){
|
||||
case 2:
|
||||
meme_clearscreen();
|
||||
gfx_printf("\nBisKey 0:\n");
|
||||
gfx_hexdump(0, bis_keys[0], 0x20 * sizeof(u8));
|
||||
gfx_printf("\n\nBisKey 1:\n");
|
||||
gfx_hexdump(0, bis_keys[1], 0x20 * sizeof(u8));
|
||||
gfx_printf("\n\nBisKey 2 + 3:\n");
|
||||
gfx_hexdump(0, bis_keys[2], 0x20 * sizeof(u8));
|
||||
btn_wait();
|
||||
break;
|
||||
case 3:
|
||||
ret = messagebox("\nThis will dump your firmware to your sd!\nThis might take a while\n\nVol-/+ to cancel\nPower to continue...");
|
||||
if (ret == 0 && sd_mounted) sdexplorer(itemsinfolder, muhbits, "DumpFirmware");
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
meme_clearscreen();
|
||||
addchartoarray("Back", options, 0);
|
||||
addchartoarray("\nReboot to RCM", options, 1);
|
||||
addchartoarray("Reboot normally", options, 2);
|
||||
addchartoarray("Power off", options, 3);
|
||||
ret = gfx_menulist(32, options, 4);
|
||||
if (ret != 1) sd_unmount();
|
||||
switch(ret){
|
||||
case 2:
|
||||
reboot_rcm();
|
||||
case 3:
|
||||
reboot_normal();
|
||||
case 4:
|
||||
power_off();
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//if (sd_mounted){
|
||||
|
||||
|
||||
//write file and folder menu
|
||||
//make clipboard and shit like that
|
||||
//figure out time from keys.c
|
||||
//figure out how to reboot to payloads https://github.com/CTCaer/hekate/blob/101c8bc1d0813da10016be771a9919c9e8112277/bootloader/main.c#L266
|
||||
//gfx_printf("%k\n\nExited main loop, vol+ to reboot to rcm\nvol- to reboot normally\npower to power off\n", COLOR_GREEN);
|
||||
//}
|
||||
//else gfx_printf("%k%pSD INIT FAILED\n\nvol+ to reboot to rcm\nvol- to reboot normally\npower to power off", COLOR_RED, COLOR_DEFAULT);
|
||||
|
||||
//utils_waitforpower();
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#define ABOUT_MESSAGE "\nCreator: Such Meme, Many Skill#2921\nCool people: Denn, shchmue\nTesters: PhazonicRidley, huhen\n\n\nProject based on Lockpick_RCM\n With additional code from Hekate"
|
||||
#define SYSTEM_WARNING_MESSAGE "\nNOTICE!\n\nAbout to enter SYSTEM:/\nThis is a SYSTEM partition!\nMessing something up here \n will brick your switch!\n\nVol+/- to cancel\nPower to continue..."
|
||||
|
||||
void meme_main();
|
|
@ -1,179 +0,0 @@
|
|||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include "../gfx/di.h"
|
||||
#include "../gfx/gfx.h"
|
||||
#include "../utils/btn.h"
|
||||
#include "utils.h"
|
||||
#include "mainfunctions.h"
|
||||
#include "../libs/fatfs/ff.h"
|
||||
#include "../storage/sdmmc.h"
|
||||
#include "graphics.h"
|
||||
#include "external_utils.h"
|
||||
|
||||
int _openfilemenu(char *path, char *clipboardpath){
|
||||
meme_clearscreen();
|
||||
FILINFO fno;
|
||||
f_stat(path, &fno);
|
||||
char *options[6];
|
||||
int res = 0;
|
||||
int mres = -1;
|
||||
int ret = -1;
|
||||
int i = 4;
|
||||
|
||||
addchartoarray("Back\n", options, 0);
|
||||
addchartoarray("Copy to clipboard", options, 1);
|
||||
addchartoarray("Move to clipboard", options, 2);
|
||||
addchartoarray("Delete file\n", options, 3);
|
||||
if (strstr(path, ".bin") != NULL){
|
||||
addchartoarray("Launch payload", options, i);
|
||||
i++;
|
||||
}
|
||||
if (strcmp(strstr(path, "emmc:/"), path) == 0){
|
||||
addchartoarray("Dump to SD", options, i);
|
||||
i++;
|
||||
}
|
||||
|
||||
gfx_printf("%kPath: %s%k\n\n", COLOR_GREEN, path, COLOR_WHITE);
|
||||
|
||||
char size[6];
|
||||
return_readable_byte_amounts(fno.fsize, size);
|
||||
|
||||
gfx_printf("Size: %s", size);
|
||||
|
||||
res = gfx_menulist(160, options, i);
|
||||
switch(res){
|
||||
case 1:
|
||||
break;
|
||||
case 2:
|
||||
ret = 0;
|
||||
strcpy(clipboardpath, path);
|
||||
break;
|
||||
case 3:
|
||||
ret = 1;
|
||||
strcpy(clipboardpath, path);
|
||||
break;
|
||||
case 4:
|
||||
mres = messagebox("Are you sure you want to delete this file?\nPower to confirm\nVOL to cancel");
|
||||
if (mres == 0) f_unlink(path);
|
||||
break;
|
||||
default:
|
||||
if (strcmp(options[res - 1], "Launch payload") == 0) launch_payload(path, 0);
|
||||
else if (strcmp(options[res - 1], "Dump to SD") == 0) {
|
||||
int res = 0;
|
||||
res = dumptosd(path);
|
||||
if (res == 1) messagebox("Copy Failed\nInput or Output is invalid");
|
||||
}
|
||||
}
|
||||
|
||||
meme_clearscreen();
|
||||
return ret;
|
||||
}
|
||||
|
||||
int dumpfirmware(char *items[], unsigned int *muhbits){
|
||||
DIR dir;
|
||||
FILINFO fno;
|
||||
char path[28] = "emmc:/Contents/registered";
|
||||
char sdpath[28] = "sd:/tegraexplorer/firmware";
|
||||
char tempnand[100] = "";
|
||||
char tempsd[100] = "";
|
||||
int ret = 0, i = 0, foldersize = 0;
|
||||
|
||||
meme_clearscreen();
|
||||
gfx_printf("\nStarting copy of firmware\n\n");
|
||||
|
||||
f_mkdir("sd:/tegraexplorer");
|
||||
f_mkdir("sd:/tegraexplorer/firmware");
|
||||
|
||||
if (f_opendir(&dir, path)) {
|
||||
messagebox("Failed to open directory!");
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (!f_readdir(&dir, &fno) && fno.fname[0]){
|
||||
addchartoarray(fno.fname, items, foldersize);
|
||||
mallocandaddfolderbit(muhbits, foldersize, fno.fattrib & AM_DIR);
|
||||
foldersize++;
|
||||
}
|
||||
|
||||
f_closedir(&dir);
|
||||
|
||||
for (i = 0; i < foldersize; i++){
|
||||
if (muhbits[i] & AM_DIR){
|
||||
sprintf(tempnand, "%s/%s/00", path, items[i]);
|
||||
sprintf(tempsd, "%s/%s", sdpath, items[i]);
|
||||
ret = copy(tempnand, tempsd, 0);
|
||||
if (ret != 0) {
|
||||
messagebox("Copy failed! (infolder)");
|
||||
return 1;
|
||||
}
|
||||
f_closedir(&dir);
|
||||
}
|
||||
else {
|
||||
sprintf(tempnand, "%s/%s", path, items[i]);
|
||||
sprintf(tempsd, "%s/%s", sdpath, items[i]);
|
||||
ret = copy(tempnand, tempsd, 0);
|
||||
if (ret != 0) {
|
||||
messagebox("Copy failed! (infile)");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
gfx_printf("Copied %d / %d nca files\r", i + 1, foldersize);
|
||||
}
|
||||
messagebox("\nDump completed!\n\nThe firmware dump is located \n in sd:/tegraexplorer/firmware");
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sdexplorer(char *items[], unsigned int *muhbits, char *rootpath){
|
||||
if (strcmp(rootpath, "DumpFirmware") == 0){
|
||||
dumpfirmware(items, muhbits);
|
||||
return;
|
||||
}
|
||||
int value = 1;
|
||||
int copymode = -1;
|
||||
int folderamount = 0;
|
||||
char path[PATHSIZE] = "";
|
||||
char clipboard[PATHSIZE + 1] = "";
|
||||
strcpy(path, rootpath);
|
||||
char app[20], rpp[20];
|
||||
int temp = -1;
|
||||
strcpy(app, rootpath);
|
||||
strcpy(rpp, app);
|
||||
removepartpath(rpp, "rpp");
|
||||
//static const u32 colors[8] = {COLOR_RED, COLOR_ORANGE, COLOR_YELLOW, COLOR_GREEN, COLOR_BLUE, COLOR_VIOLET, COLOR_DEFAULT, COLOR_WHITE};
|
||||
|
||||
while(1){
|
||||
gfx_clear_grey(0x1B);
|
||||
gfx_con_setpos(0, 0);
|
||||
gfx_box(0, 0, 719, 15, COLOR_WHITE);
|
||||
folderamount = readfolder(items, muhbits, path);
|
||||
if (folderamount == -1){
|
||||
messagebox("\nInvalid path\n\nReturning to main menu");
|
||||
break;
|
||||
}
|
||||
gfx_printf("%k%pTegraExplorer - %s", COLOR_DEFAULT, COLOR_WHITE, app);
|
||||
gfx_con_setpos(39 * 16, 0);
|
||||
gfx_printf("%d\n%k%p", folderamount - 2, COLOR_WHITE, COLOR_DEFAULT);
|
||||
value = fileexplorergui(items, muhbits, path, folderamount);
|
||||
|
||||
if (value == 1) {
|
||||
if (strcmp(app, path) == 0) break;
|
||||
else removepartpath(path, rpp);
|
||||
}
|
||||
else if (value == 2) {
|
||||
if (copymode != -1){
|
||||
copywithpath(clipboard, path, copymode, app);
|
||||
copymode = -1;
|
||||
}
|
||||
else messagebox("\nThe Clipboard is empty!");
|
||||
}
|
||||
else {
|
||||
if(muhbits[value - 1] & OPTION1) addpartpath(path, items[value - 1], app);
|
||||
else {
|
||||
addpartpath(path, items[value - 1], app);
|
||||
temp = _openfilemenu(path, clipboard);
|
||||
if (temp != -1) copymode = temp;
|
||||
removepartpath(path, rpp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,5 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
void sdexplorer(char *items[], unsigned int *muhbits, char *rootpath);
|
||||
int dumpfirmware(char *items[], unsigned int *muhbits);
|
||||
void wtf(char *items[], unsigned int *muhbits);
|
|
@ -1,201 +0,0 @@
|
|||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include "../gfx/di.h"
|
||||
#include "../gfx/gfx.h"
|
||||
#include "../utils/btn.h"
|
||||
#include "../utils/util.h"
|
||||
#include "utils.h"
|
||||
#include "../libs/fatfs/ff.h"
|
||||
#include "../storage/sdmmc.h"
|
||||
#include "graphics.h"
|
||||
#include "external_utils.h"
|
||||
|
||||
void utils_gfx_init(){
|
||||
display_backlight_brightness(100, 1000);
|
||||
gfx_clear_grey(0x1B);
|
||||
gfx_con_setpos(0, 0);
|
||||
}
|
||||
|
||||
void removepartpath(char *path, char *root){
|
||||
char *ret;
|
||||
char temproot[20];
|
||||
ret = strrchr(path, '/');
|
||||
memset(ret, '\0', 1);
|
||||
sprintf(temproot, "%s%s", root, "/");
|
||||
if (strcmp(path, root) == 0) strcpy(path, temproot);
|
||||
}
|
||||
|
||||
int dumptosd(const char *path){
|
||||
f_mkdir("sd:/tegraexplorer");
|
||||
f_mkdir("sd:/tegraexplorer/nanddump");
|
||||
FILINFO fno;
|
||||
int res = 0;
|
||||
f_stat(path, &fno);
|
||||
char pathname[PATHSIZE];
|
||||
char foldername[75];
|
||||
strcpy(pathname, path);
|
||||
removepartpath(pathname, "emmc:");
|
||||
strcpy(foldername, strrchr(pathname, '/'));
|
||||
if (strcmp(foldername, "/") == 0) strcpy(foldername, "/root");
|
||||
sprintf(pathname, "%s%s", "sd:/tegraexplorer/nanddump", foldername);
|
||||
f_mkdir(pathname);
|
||||
sprintf(pathname, "%s%s%s%s", "sd:/tegraexplorer/nanddump", foldername, "/", fno.fname);
|
||||
res = copy(path, pathname, 1);
|
||||
return res;
|
||||
}
|
||||
|
||||
void addpartpath(char *path, char *add, char *root){
|
||||
if (strcmp(path, root) != 0) strcat(path, "/");
|
||||
strcat(path, add);
|
||||
}
|
||||
|
||||
void return_readable_byte_amounts(unsigned long int size, char *in){
|
||||
char type[3];
|
||||
unsigned long int sizetemp = size;
|
||||
int muhbytes = 0;
|
||||
while(sizetemp > 1024){
|
||||
muhbytes++;
|
||||
sizetemp = sizetemp / 1024;
|
||||
}
|
||||
|
||||
switch(muhbytes){
|
||||
case 0:
|
||||
strcpy(type, "B");
|
||||
break;
|
||||
case 1:
|
||||
strcpy(type, "KB");
|
||||
break;
|
||||
case 2:
|
||||
strcpy(type, "MB");
|
||||
break;
|
||||
case 3:
|
||||
strcpy(type, "GB");
|
||||
break;
|
||||
default:
|
||||
strcpy(type, "GB");
|
||||
break;
|
||||
}
|
||||
sprintf(in, "%d%s", sizetemp, type);
|
||||
}
|
||||
|
||||
int getfilesize(const char *path){
|
||||
FILINFO fno;
|
||||
f_stat(path, &fno);
|
||||
return fno.fsize;
|
||||
}
|
||||
|
||||
void addchartoarray(char *add, char *items[], int spot){
|
||||
size_t size = strlen(add) + 1;
|
||||
items[spot] = (char*) malloc (size);
|
||||
strlcpy(items[spot], add, size);
|
||||
}
|
||||
|
||||
void mallocandaddfolderbit(unsigned int *muhbits, int spot, bool value){
|
||||
muhbits[spot] = (unsigned int) malloc (sizeof(int));
|
||||
if (value) muhbits[spot] |= (OPTION1);
|
||||
//ff.h line 368
|
||||
}
|
||||
|
||||
int readfolder(char *items[], unsigned int *muhbits, const char *path){
|
||||
DIR dir;
|
||||
FILINFO fno;
|
||||
int i = 2;
|
||||
addchartoarray("Current folder -> One folder up", items, 0);
|
||||
addchartoarray("Clipboard -> Current folder", items, 1);
|
||||
mallocandaddfolderbit(muhbits, 0, true);
|
||||
mallocandaddfolderbit(muhbits, 1, true);
|
||||
|
||||
|
||||
if (f_opendir(&dir, path)) {
|
||||
gfx_printf("\nFailed to open %s", path);
|
||||
return -1;
|
||||
}
|
||||
else {
|
||||
while (!f_readdir(&dir, &fno) && fno.fname[0]){
|
||||
addchartoarray(fno.fname, items, i);
|
||||
mallocandaddfolderbit(muhbits, i, fno.fattrib & AM_DIR);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
f_closedir(&dir);
|
||||
return i;
|
||||
}
|
||||
|
||||
int copy(const char *src, const char *dst, int print){
|
||||
FIL in;
|
||||
FIL out;
|
||||
unsigned int res = 0;
|
||||
char temp[100];
|
||||
if (strcmp(src, dst) == 0){
|
||||
//in and out are the same, aborting!
|
||||
return 2;
|
||||
}
|
||||
res = f_open(&in, src, FA_READ | FA_OPEN_EXISTING);
|
||||
if (res != FR_OK){
|
||||
//something has gone wrong
|
||||
//sprintf(temp, "%s %d", src, res);
|
||||
//messagebox(temp);
|
||||
|
||||
return 1;
|
||||
}
|
||||
if (f_open(&out, dst, FA_CREATE_ALWAYS | FA_WRITE) != FR_OK){
|
||||
//something has gone wrong
|
||||
return 1;
|
||||
}
|
||||
|
||||
int BUFFSIZ = 32768;
|
||||
u64 size = f_size(&in);
|
||||
unsigned long totalsize = size, kbwritten = 0;
|
||||
void *buff = malloc(BUFFSIZ);
|
||||
int mbwritten = 0, percentage = 0;
|
||||
bool abort = false;
|
||||
if (print == 1) {
|
||||
meme_clearscreen();
|
||||
gfx_printf("press VOL- to abort the file transfer!\n\n");
|
||||
}
|
||||
while(size > BUFFSIZ){
|
||||
int res1, res2;
|
||||
res1 = f_read(&in, buff, BUFFSIZ, NULL);
|
||||
res2 = f_write(&out, buff, BUFFSIZ, NULL);
|
||||
|
||||
kbwritten = kbwritten + (BUFFSIZ / 1024);
|
||||
mbwritten = kbwritten / 1024;
|
||||
percentage = (mbwritten * 100) / ((totalsize / 1024) / 1024);
|
||||
|
||||
size = size - BUFFSIZ;
|
||||
if (print == 1){
|
||||
gfx_printf("Written %dMB [%k%d%k%%]\r", mbwritten, COLOR_GREEN, percentage, COLOR_WHITE);
|
||||
if (btn_read() & BTN_VOL_DOWN) size = 0, abort = true;
|
||||
}
|
||||
}
|
||||
|
||||
if(size != 0){
|
||||
f_read(&in, buff, size, NULL);
|
||||
f_write(&out, buff, size, NULL);
|
||||
}
|
||||
|
||||
f_close(&in);
|
||||
f_close(&out);
|
||||
|
||||
if(abort){
|
||||
f_unlink(dst);
|
||||
}
|
||||
|
||||
free(buff);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int copywithpath(const char *src, const char *dstpath, int mode, char *app){
|
||||
FILINFO fno;
|
||||
f_stat(src, &fno);
|
||||
char dst[PATHSIZE];
|
||||
strcpy(dst, dstpath);
|
||||
if (strcmp(dstpath, app) != 0) strcat(dst, "/");
|
||||
strcat(dst, fno.fname);
|
||||
int ret = -1;
|
||||
if (mode == 0) ret = copy(src, dst, 1);
|
||||
if (mode == 1) f_rename(src, dst);
|
||||
return ret;
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#define OPTION1 (1 << 0)
|
||||
#define OPTION2 (1 << 1)
|
||||
#define OPTION3 (1 << 2)
|
||||
#define OPTION4 (1 << 3)
|
||||
|
||||
#define PATHSIZE 512
|
||||
|
||||
void utils_gfx_init();
|
||||
void removepartpath(char *path, char *root);
|
||||
void addpartpath(char *path, char *add, char *root);
|
||||
int readfolder(char *items[], unsigned int *muhbits, const char *path);
|
||||
int copy(const char *src, const char *dst, int print);
|
||||
void addchartoarray(char *add, char *items[], int spot);
|
||||
int copywithpath(const char *src, const char *dstpath, int mode, char *app);
|
||||
void return_readable_byte_amounts(unsigned long int size, char *in);
|
||||
int getfilesize(const char *path);
|
||||
int dumptosd(const char *path);
|
||||
void mallocandaddfolderbit(unsigned int *muhbits, int spot, bool value);
|
|
@ -130,7 +130,7 @@
|
|||
#define MAX77620_POWER_MODE_DISABLE 0
|
||||
#define MAX20024_LDO_CFG2_MPOK_MASK (1 << 2)
|
||||
#define MAX77620_LDO_CFG2_ADE_MASK (1 << 1)
|
||||
#define MAX77620_LDO_CFG2_ADE_DISABLE 0
|
||||
#define MAX77620_LDO_CFG2_ADE_DISABLE (0 << 1)
|
||||
#define MAX77620_LDO_CFG2_ADE_ENABLE (1 << 1)
|
||||
#define MAX77620_LDO_CFG2_SS_MASK (1 << 0)
|
||||
#define MAX77620_LDO_CFG2_SS_FAST (1 << 0)
|
||||
|
@ -153,6 +153,24 @@
|
|||
#define MAX77620_REG_PUE_GPIO 0x3E
|
||||
#define MAX77620_REG_PDE_GPIO 0x3F
|
||||
#define MAX77620_REG_AME_GPIO 0x40
|
||||
#define MAX77620_CNFG_GPIO_DRV_MASK (1 << 0)
|
||||
#define MAX77620_CNFG_GPIO_DRV_PUSHPULL (1 << 0)
|
||||
#define MAX77620_CNFG_GPIO_DRV_OPENDRAIN (0 << 0)
|
||||
#define MAX77620_CNFG_GPIO_DIR_MASK (1 << 1)
|
||||
#define MAX77620_CNFG_GPIO_DIR_INPUT (1 << 1)
|
||||
#define MAX77620_CNFG_GPIO_DIR_OUTPUT (0 << 1)
|
||||
#define MAX77620_CNFG_GPIO_INPUT_VAL_MASK (1 << 2)
|
||||
#define MAX77620_CNFG_GPIO_OUTPUT_VAL_MASK (1 << 3)
|
||||
#define MAX77620_CNFG_GPIO_OUTPUT_VAL_HIGH (1 << 3)
|
||||
#define MAX77620_CNFG_GPIO_OUTPUT_VAL_LOW (0 << 3)
|
||||
#define MAX77620_CNFG_GPIO_INT_MASK (0x3 << 4)
|
||||
#define MAX77620_CNFG_GPIO_INT_FALLING (1 << 4)
|
||||
#define MAX77620_CNFG_GPIO_INT_RISING (1 << 5)
|
||||
#define MAX77620_CNFG_GPIO_DBNC_MASK (0x3 << 6)
|
||||
#define MAX77620_CNFG_GPIO_DBNC_None (0x0 << 6)
|
||||
#define MAX77620_CNFG_GPIO_DBNC_8ms (0x1 << 6)
|
||||
#define MAX77620_CNFG_GPIO_DBNC_16ms (0x2 << 6)
|
||||
#define MAX77620_CNFG_GPIO_DBNC_32ms (0x3 << 6)
|
||||
|
||||
#define MAX77620_REG_ONOFFCNFG1 0x41
|
||||
#define MAX77620_ONOFFCNFG1_SFT_RST (1 << 7)
|
||||
|
@ -259,25 +277,6 @@
|
|||
#define MAX77620_SD_CFG1_FSRADE_SD_DISABLE 0
|
||||
#define MAX77620_SD_CFG1_FSRADE_SD_ENABLE (1 << 0)
|
||||
|
||||
#define MAX77620_CNFG_GPIO_DRV_MASK (1 << 0)
|
||||
#define MAX77620_CNFG_GPIO_DRV_PUSHPULL (1 << 0)
|
||||
#define MAX77620_CNFG_GPIO_DRV_OPENDRAIN 0
|
||||
#define MAX77620_CNFG_GPIO_DIR_MASK (1 << 1)
|
||||
#define MAX77620_CNFG_GPIO_DIR_INPUT (1 << 1)
|
||||
#define MAX77620_CNFG_GPIO_DIR_OUTPUT 0
|
||||
#define MAX77620_CNFG_GPIO_INPUT_VAL_MASK (1 << 2)
|
||||
#define MAX77620_CNFG_GPIO_OUTPUT_VAL_MASK (1 << 3)
|
||||
#define MAX77620_CNFG_GPIO_OUTPUT_VAL_HIGH (1 << 3)
|
||||
#define MAX77620_CNFG_GPIO_OUTPUT_VAL_LOW 0
|
||||
#define MAX77620_CNFG_GPIO_INT_MASK (0x3 << 4)
|
||||
#define MAX77620_CNFG_GPIO_INT_FALLING (1 << 4)
|
||||
#define MAX77620_CNFG_GPIO_INT_RISING (1 << 5)
|
||||
#define MAX77620_CNFG_GPIO_DBNC_MASK (0x3 << 6)
|
||||
#define MAX77620_CNFG_GPIO_DBNC_None (0x0 << 6)
|
||||
#define MAX77620_CNFG_GPIO_DBNC_8ms (0x1 << 6)
|
||||
#define MAX77620_CNFG_GPIO_DBNC_16ms (0x2 << 6)
|
||||
#define MAX77620_CNFG_GPIO_DBNC_32ms (0x3 << 6)
|
||||
|
||||
#define MAX77620_IRQ_LVL2_GPIO_EDGE0 (1 << 0)
|
||||
#define MAX77620_IRQ_LVL2_GPIO_EDGE1 (1 << 1)
|
||||
#define MAX77620_IRQ_LVL2_GPIO_EDGE2 (1 << 2)
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
* Switch Power domains (max77620):
|
||||
* Name | Usage | uV step | uV min | uV default | uV max | Init
|
||||
*-------+---------------+---------+--------+------------+---------+------------------
|
||||
* sd0 | core | 12500 | 600000 | 625000 | 1400000 | 1.125V (pkg1.1)
|
||||
* sd0 | SoC | 12500 | 600000 | 625000 | 1400000 | 1.125V (pkg1.1)
|
||||
* sd1 | SDRAM | 12500 | 600000 | 1125000 | 1125000 | 1.1V (pkg1.1)
|
||||
* sd2 | ldo{0-1, 7-8} | 12500 | 600000 | 1325000 | 1350000 | 1.325V (pcv)
|
||||
* sd3 | 1.8V general | 12500 | 600000 | 1800000 | 1800000 |
|
||||
|
@ -71,6 +71,8 @@
|
|||
/* MAX77621_VOUT */
|
||||
#define MAX77621_VOUT_ENABLE (1 << 7)
|
||||
#define MAX77621_VOUT_MASK 0x7F
|
||||
#define MAX77621_VOUT_0_95V 0x37
|
||||
#define MAX77621_VOUT_1_09V 0x4F
|
||||
|
||||
/* MAX77621_VOUT_DVC_DVS */
|
||||
#define MAX77621_DVS_VOUT_MASK 0x7F
|
||||
|
|
|
@ -52,7 +52,7 @@ void max77620_rtc_get_time(rtc_time_t *time)
|
|||
}
|
||||
|
||||
// Get date.
|
||||
time->date = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_DATE_REG) & 0x1f;
|
||||
time->day = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_DATE_REG) & 0x1f;
|
||||
time->month = (i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_MONTH_REG) & 0xF) - 1;
|
||||
time->year = (i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_YEAR_REG) & 0x7F) + 2000;
|
||||
}
|
||||
|
|
|
@ -64,7 +64,7 @@ typedef struct _rtc_time_t {
|
|||
u8 sec;
|
||||
u8 min;
|
||||
u8 hour;
|
||||
u8 date;
|
||||
u8 day;
|
||||
u8 month;
|
||||
u16 year;
|
||||
} rtc_time_t;
|
||||
|
|
135
source/sec/se.c
135
source/sec/se.c
|
@ -21,6 +21,7 @@
|
|||
|
||||
#include "../sec/se.h"
|
||||
#include "../mem/heap.h"
|
||||
#include "../soc/bpmp.h"
|
||||
#include "../soc/t210.h"
|
||||
#include "../sec/se_t210.h"
|
||||
#include "../utils/util.h"
|
||||
|
@ -32,6 +33,9 @@ typedef struct _se_ll_t
|
|||
vu32 size;
|
||||
} se_ll_t;
|
||||
|
||||
static u32 _se_rsa_mod_sizes[TEGRA_SE_RSA_KEYSLOT_COUNT];
|
||||
static u32 _se_rsa_exp_sizes[TEGRA_SE_RSA_KEYSLOT_COUNT];
|
||||
|
||||
static void _gf256_mul_x(void *block)
|
||||
{
|
||||
u8 *pdata = (u8 *)block;
|
||||
|
@ -90,17 +94,15 @@ static int _se_wait()
|
|||
|
||||
static int _se_execute(u32 op, void *dst, u32 dst_size, const void *src, u32 src_size)
|
||||
{
|
||||
se_ll_t *ll_dst = NULL, *ll_src = NULL;
|
||||
se_ll_t *ll_dst = (se_ll_t *)0xECFFFFE0, *ll_src = (se_ll_t *)0xECFFFFF0;
|
||||
|
||||
if (dst)
|
||||
{
|
||||
ll_dst = (se_ll_t *)malloc(sizeof(se_ll_t));
|
||||
_se_ll_init(ll_dst, (u32)dst, dst_size);
|
||||
}
|
||||
|
||||
if (src)
|
||||
{
|
||||
ll_src = (se_ll_t *)malloc(sizeof(se_ll_t));
|
||||
_se_ll_init(ll_src, (u32)src, src_size);
|
||||
}
|
||||
|
||||
|
@ -108,14 +110,13 @@ static int _se_execute(u32 op, void *dst, u32 dst_size, const void *src, u32 src
|
|||
|
||||
SE(SE_ERR_STATUS_0) = SE(SE_ERR_STATUS_0);
|
||||
SE(SE_INT_STATUS_REG_OFFSET) = SE(SE_INT_STATUS_REG_OFFSET);
|
||||
SE(SE_OPERATION_REG_OFFSET) = SE_OPERATION(op);
|
||||
|
||||
bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY);
|
||||
|
||||
SE(SE_OPERATION_REG_OFFSET) = SE_OPERATION(op);
|
||||
int res = _se_wait();
|
||||
|
||||
if (src)
|
||||
free(ll_src);
|
||||
if (dst)
|
||||
free(ll_dst);
|
||||
bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
@ -153,6 +154,66 @@ void se_rsa_acc_ctrl(u32 rs, u32 flags)
|
|||
SE(SE_RSA_KEYTABLE_ACCESS_LOCK_OFFSET) &= ~(1 << rs);
|
||||
}
|
||||
|
||||
// se_rsa_key_set() was derived from Atmosphère's set_rsa_keyslot
|
||||
void se_rsa_key_set(u32 ks, const void *mod, u32 mod_size, const void *exp, u32 exp_size)
|
||||
{
|
||||
u32 *data = (u32 *)mod;
|
||||
for (u32 i = 0; i < mod_size / 4; i++)
|
||||
{
|
||||
SE(SE_RSA_KEYTABLE_ADDR) = RSA_KEY_NUM(ks) | RSA_KEY_TYPE(RSA_KEY_TYPE_MOD) | i;
|
||||
SE(SE_RSA_KEYTABLE_DATA) = byte_swap_32(data[mod_size / 4 - i - 1]);
|
||||
}
|
||||
|
||||
data = (u32 *)exp;
|
||||
for (u32 i = 0; i < exp_size / 4; i++)
|
||||
{
|
||||
SE(SE_RSA_KEYTABLE_ADDR) = RSA_KEY_NUM(ks) | RSA_KEY_TYPE(RSA_KEY_TYPE_EXP) | i;
|
||||
SE(SE_RSA_KEYTABLE_DATA) = byte_swap_32(data[exp_size / 4 - i - 1]);
|
||||
}
|
||||
|
||||
_se_rsa_mod_sizes[ks] = mod_size;
|
||||
_se_rsa_exp_sizes[ks] = exp_size;
|
||||
}
|
||||
|
||||
// se_rsa_key_clear() was derived from Atmosphère's clear_rsa_keyslot
|
||||
void se_rsa_key_clear(u32 ks)
|
||||
{
|
||||
for (u32 i = 0; i < TEGRA_SE_RSA2048_DIGEST_SIZE / 4; i++)
|
||||
{
|
||||
SE(SE_RSA_KEYTABLE_ADDR) = RSA_KEY_NUM(ks) | RSA_KEY_TYPE(RSA_KEY_TYPE_MOD) | i;
|
||||
SE(SE_RSA_KEYTABLE_DATA) = 0;
|
||||
}
|
||||
for (u32 i = 0; i < TEGRA_SE_RSA2048_DIGEST_SIZE / 4; i++)
|
||||
{
|
||||
SE(SE_RSA_KEYTABLE_ADDR) = RSA_KEY_NUM(ks) | RSA_KEY_TYPE(RSA_KEY_TYPE_EXP) | i;
|
||||
SE(SE_RSA_KEYTABLE_DATA) = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// se_rsa_exp_mod() was derived from Atmosphère's se_synchronous_exp_mod and se_get_exp_mod_output
|
||||
int se_rsa_exp_mod(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_size)
|
||||
{
|
||||
int res;
|
||||
u8 stack_buf[TEGRA_SE_RSA2048_DIGEST_SIZE];
|
||||
|
||||
for (u32 i = 0; i < src_size; i++)
|
||||
stack_buf[i] = *((u8 *)src + src_size - i - 1);
|
||||
|
||||
SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_ENC_ALG(ALG_RSA) | SE_CONFIG_DST(DST_RSAREG);
|
||||
SE(SE_RSA_CONFIG) = RSA_KEY_SLOT(ks);
|
||||
SE(SE_RSA_KEY_SIZE_REG_OFFSET) = (_se_rsa_mod_sizes[ks] >> 6) - 1;
|
||||
SE(SE_RSA_EXP_SIZE_REG_OFFSET) = _se_rsa_exp_sizes[ks] >> 2;
|
||||
|
||||
res = _se_execute(OP_START, NULL, 0, stack_buf, src_size);
|
||||
|
||||
// Copy output hash.
|
||||
u32 *dst32 = (u32 *)dst;
|
||||
for (u32 i = 0; i < dst_size / 4; i++)
|
||||
dst32[dst_size / 4 - i - 1] = byte_swap_32(SE(SE_RSA_OUTPUT + (i << 2)));
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void se_key_acc_ctrl(u32 ks, u32 flags)
|
||||
{
|
||||
if (flags & 0x7F)
|
||||
|
@ -227,18 +288,7 @@ int se_aes_crypt_ecb(u32 ks, u32 enc, void *dst, u32 dst_size, const void *src,
|
|||
|
||||
int se_aes_crypt_block_ecb(u32 ks, u32 enc, void *dst, const void *src)
|
||||
{
|
||||
if (enc)
|
||||
{
|
||||
SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_ENC_ALG(ALG_AES_ENC) | SE_CONFIG_DST(DST_MEMORY);
|
||||
SE(SE_CRYPTO_REG_OFFSET) = SE_CRYPTO_KEY_INDEX(ks) | SE_CRYPTO_CORE_SEL(CORE_ENCRYPT);
|
||||
}
|
||||
else
|
||||
{
|
||||
SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_DEC_ALG(ALG_AES_DEC) | SE_CONFIG_DST(DST_MEMORY);
|
||||
SE(SE_CRYPTO_REG_OFFSET) = SE_CRYPTO_KEY_INDEX(ks) | SE_CRYPTO_CORE_SEL(CORE_DECRYPT);
|
||||
}
|
||||
SE(SE_BLOCK_COUNT_REG_OFFSET) = 0;
|
||||
return _se_execute(OP_START, dst, 0x10, src, 0x10);
|
||||
return se_aes_crypt_ecb(ks, enc, dst, 0x10, src, 0x10);
|
||||
}
|
||||
|
||||
int se_aes_crypt_ctr(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_size, void *ctr)
|
||||
|
@ -371,7 +421,7 @@ 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_CONFIG_REG_OFFSET) = SHA_INIT_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;
|
||||
|
@ -391,3 +441,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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -231,8 +231,8 @@
|
|||
#define SE_SPARE_0_REG_OFFSET 0x80c
|
||||
|
||||
#define SE_SHA_CONFIG_REG_OFFSET 0x200
|
||||
#define SHA_DISABLE 0
|
||||
#define SHA_ENABLE 1
|
||||
#define SHA_INIT_DISABLE 0
|
||||
#define SHA_INIT_ENABLE 1
|
||||
|
||||
#define SE_SHA_MSG_LENGTH_REG_OFFSET 0x204
|
||||
#define SE_SHA_MSG_LEFT_REG_OFFSET 0x214
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include "../sec/tsec.h"
|
||||
#include "../sec/tsec_t210.h"
|
||||
#include "../sec/se_t210.h"
|
||||
#include "../soc/bpmp.h"
|
||||
#include "../soc/clock.h"
|
||||
#include "../soc/smmu.h"
|
||||
#include "../soc/t210.h"
|
||||
|
@ -64,8 +65,12 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt)
|
|||
u32 *pdir, *car, *fuse, *pmc, *flowctrl, *se, *mc, *iram, *evec;
|
||||
u32 *pkg11_magic_off;
|
||||
|
||||
bpmp_mmu_disable();
|
||||
bpmp_clk_rate_set(BPMP_CLK_NORMAL);
|
||||
|
||||
// Enable clocks.
|
||||
clock_enable_host1x();
|
||||
usleep(2);
|
||||
clock_enable_tsec();
|
||||
clock_enable_sor_safe();
|
||||
clock_enable_sor0();
|
||||
|
@ -170,7 +175,7 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt)
|
|||
}
|
||||
|
||||
//Execute firmware.
|
||||
HOST1X(0x3300) = 0x34C2E1DA;
|
||||
HOST1X(HOST1X_CH0_SYNC_SYNCPT_160) = 0x34C2E1DA;
|
||||
TSEC(TSEC_STATUS) = 0;
|
||||
TSEC(TSEC_BOOTKEYVER) = 1; // HOS uses key version 1.
|
||||
TSEC(TSEC_BOOTVEC) = 0;
|
||||
|
@ -247,7 +252,7 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt)
|
|||
}
|
||||
|
||||
//Fetch result.
|
||||
HOST1X(0x3300) = 0;
|
||||
HOST1X(HOST1X_CH0_SYNC_SYNCPT_160) = 0;
|
||||
u32 buf[4];
|
||||
buf[0] = SOR1(SOR_NV_PDISP_SOR_DP_HDCP_BKSV_LSB);
|
||||
buf[1] = SOR1(SOR_NV_PDISP_SOR_TMDS_HDCP_BKSV_LSB);
|
||||
|
@ -272,7 +277,8 @@ out:;
|
|||
clock_disable_sor0();
|
||||
clock_disable_sor_safe();
|
||||
clock_disable_tsec();
|
||||
clock_disable_host1x();
|
||||
bpmp_mmu_enable();
|
||||
bpmp_clk_rate_set(BPMP_CLK_SUPER_BOOST);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
|
249
source/soc/bpmp.c
Normal file
249
source/soc/bpmp.c
Normal file
|
@ -0,0 +1,249 @@
|
|||
/*
|
||||
* BPMP-Lite Cache/MMU and Frequency driver for Tegra X1
|
||||
*
|
||||
* Copyright (c) 2019 CTCaer
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "bpmp.h"
|
||||
#include "clock.h"
|
||||
#include "t210.h"
|
||||
#include "../utils/util.h"
|
||||
|
||||
#define BPMP_CACHE_CONFIG 0x0
|
||||
#define CFG_ENABLE (1 << 0)
|
||||
#define CFG_FORCE_WRITE_THROUGH (1 << 3)
|
||||
#define CFG_DISABLE_WRITE_BUFFER (1 << 10)
|
||||
#define CFG_DISABLE_READ_BUFFER (1 << 11)
|
||||
#define CFG_FULL_LINE_DIRTY (1 << 13)
|
||||
#define CFG_TAG_CHK_ABRT_ON_ERR (1 << 14)
|
||||
#define BPMP_CACHE_LOCK 0x4
|
||||
#define BPMP_CACHE_SIZE 0xC
|
||||
#define BPMP_CACHE_LFSR 0x10
|
||||
#define BPMP_CACHE_TAG_STATUS 0x14
|
||||
#define BPMP_CACHE_CLKEN_OVERRIDE 0x18
|
||||
#define BPMP_CACHE_MAINT_ADDR 0x20
|
||||
#define BPMP_CACHE_MAINT_DATA 0x24
|
||||
#define BPMP_CACHE_MAINT_REQ 0x28
|
||||
#define MAINT_REQ_WAY_BITMAP(x) ((x) << 8)
|
||||
|
||||
#define BPMP_CACHE_INT_MASK 0x40
|
||||
#define BPMP_CACHE_INT_CLEAR 0x44
|
||||
#define INT_CLR_MAINT_DONE (1 << 0)
|
||||
|
||||
#define BPMP_CACHE_INT_RAW_EVENT 0x48
|
||||
#define INT_RAW_EVENT_MAINT_DONE (1 << 0)
|
||||
#define BPMP_CACHE_INT_STATUS 0x4C
|
||||
|
||||
#define BPMP_CACHE_RB_CFG 0x80
|
||||
#define BPMP_CACHE_WB_CFG 0x84
|
||||
|
||||
#define BPMP_CACHE_MMU_FALLBACK_ENTRY 0xA0
|
||||
#define BPMP_CACHE_MMU_SHADOW_COPY_MASK 0xA4
|
||||
#define BPMP_CACHE_MMU_CFG 0xAC
|
||||
#define MMU_CFG_SEQ_EN (1 << 1)
|
||||
#define MMU_CFG_TLB_EN (1 << 2)
|
||||
#define MMU_CFG_ABORT_STORE_LAST (1 << 4)
|
||||
#define BPMP_CACHE_MMU_CMD 0xB0
|
||||
#define MMU_CMD_NOP 0
|
||||
#define MMU_CMD_INIT 1
|
||||
#define MMU_CMD_COPY_SHADOW 2
|
||||
#define BPMP_CACHE_MMU_ABORT_STAT 0xB4
|
||||
#define BPMP_CACHE_MMU_ABORT_ADDR 0xB8
|
||||
#define BPMP_CACHE_MMU_ACTIVE_ENTRIES 0xBC
|
||||
|
||||
#define BPMP_MMU_SHADOW_ENTRY_BASE (BPMP_CACHE_BASE + 0x400)
|
||||
#define BPMP_MMU_MAIN_ENTRY_BASE (BPMP_CACHE_BASE + 0x800)
|
||||
#define MMU_ENTRY_ADDR_MASK 0xFFFFFFE0
|
||||
|
||||
#define MMU_EN_CACHED (1 << 0)
|
||||
#define MMU_EN_EXEC (1 << 1)
|
||||
#define MMU_EN_READ (1 << 2)
|
||||
#define MMU_EN_WRITE (1 << 3)
|
||||
|
||||
bpmp_mmu_entry_t mmu_entries[] =
|
||||
{
|
||||
{ 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 }
|
||||
};
|
||||
|
||||
void bpmp_mmu_maintenance(u32 op)
|
||||
{
|
||||
if (!(BPMP_CACHE_CTRL(BPMP_CACHE_CONFIG) & CFG_ENABLE))
|
||||
return;
|
||||
|
||||
BPMP_CACHE_CTRL(BPMP_CACHE_INT_CLEAR) = INT_CLR_MAINT_DONE;
|
||||
|
||||
// This is a blocking operation.
|
||||
BPMP_CACHE_CTRL(BPMP_CACHE_MAINT_REQ) = MAINT_REQ_WAY_BITMAP(0xF) | op;
|
||||
|
||||
while(!(BPMP_CACHE_CTRL(BPMP_CACHE_INT_RAW_EVENT) & INT_RAW_EVENT_MAINT_DONE))
|
||||
;
|
||||
|
||||
BPMP_CACHE_CTRL(BPMP_CACHE_INT_CLEAR) = BPMP_CACHE_CTRL(BPMP_CACHE_INT_RAW_EVENT);
|
||||
}
|
||||
|
||||
void bpmp_mmu_set_entry(int idx, bpmp_mmu_entry_t *entry, bool apply)
|
||||
{
|
||||
if (idx > 31)
|
||||
return;
|
||||
|
||||
volatile bpmp_mmu_entry_t *mmu_entry = (bpmp_mmu_entry_t *)(BPMP_MMU_SHADOW_ENTRY_BASE + sizeof(bpmp_mmu_entry_t) * idx);
|
||||
|
||||
if (entry->enable)
|
||||
{
|
||||
mmu_entry->min_addr = entry->min_addr & MMU_ENTRY_ADDR_MASK;
|
||||
mmu_entry->max_addr = entry->max_addr & MMU_ENTRY_ADDR_MASK;
|
||||
mmu_entry->attr = entry->attr;
|
||||
|
||||
BPMP_CACHE_CTRL(BPMP_CACHE_MMU_SHADOW_COPY_MASK) |= (1 << idx);
|
||||
|
||||
if (apply)
|
||||
BPMP_CACHE_CTRL(BPMP_CACHE_MMU_CMD) = MMU_CMD_COPY_SHADOW;
|
||||
}
|
||||
}
|
||||
|
||||
void bpmp_mmu_enable()
|
||||
{
|
||||
if (BPMP_CACHE_CTRL(BPMP_CACHE_CONFIG) & CFG_ENABLE)
|
||||
return;
|
||||
|
||||
// Init BPMP MMU.
|
||||
BPMP_CACHE_CTRL(BPMP_CACHE_MMU_CMD) = MMU_CMD_INIT;
|
||||
BPMP_CACHE_CTRL(BPMP_CACHE_MMU_FALLBACK_ENTRY) = MMU_EN_READ | MMU_EN_WRITE | MMU_EN_EXEC; // RWX for non-defined regions.
|
||||
BPMP_CACHE_CTRL(BPMP_CACHE_MMU_CFG) = MMU_CFG_SEQ_EN | MMU_CFG_TLB_EN | MMU_CFG_ABORT_STORE_LAST;
|
||||
|
||||
// Init BPMP MMU entries.
|
||||
BPMP_CACHE_CTRL(BPMP_CACHE_MMU_SHADOW_COPY_MASK) = 0;
|
||||
for (u32 idx = 0; idx < (sizeof(mmu_entries) / sizeof(bpmp_mmu_entry_t)); idx++)
|
||||
bpmp_mmu_set_entry(idx, &mmu_entries[idx], false);
|
||||
|
||||
BPMP_CACHE_CTRL(BPMP_CACHE_MMU_CMD) = MMU_CMD_COPY_SHADOW;
|
||||
|
||||
// Invalidate cache.
|
||||
bpmp_mmu_maintenance(BPMP_MMU_MAINT_INVALID_WAY);
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
void bpmp_mmu_disable()
|
||||
{
|
||||
if (!(BPMP_CACHE_CTRL(BPMP_CACHE_CONFIG) & CFG_ENABLE))
|
||||
return;
|
||||
|
||||
// Clean and invalidate cache.
|
||||
bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY);
|
||||
|
||||
// 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.
|
||||
};
|
||||
|
||||
bpmp_freq_t bpmp_clock_set = BPMP_CLK_NORMAL;
|
||||
|
||||
void bpmp_clk_rate_set(bpmp_freq_t fid)
|
||||
{
|
||||
if (fid > (BPMP_CLK_MAX - 1))
|
||||
fid = BPMP_CLK_MAX - 1;
|
||||
|
||||
if (bpmp_clock_set == fid)
|
||||
return;
|
||||
|
||||
if (fid)
|
||||
{
|
||||
if (bpmp_clock_set)
|
||||
{
|
||||
// Restore to PLLP source during PLLC4 configuration.
|
||||
CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = 0x20003333; // PLLP_OUT.
|
||||
// Wait a bit for clock source change.
|
||||
msleep(10);
|
||||
}
|
||||
|
||||
CLOCK(CLK_RST_CONTROLLER_PLLC4_MISC) = PLLC4_MISC_EN_LCKDET;
|
||||
CLOCK(CLK_RST_CONTROLLER_PLLC4_BASE) = 4 | (pllc4_divn[fid] << 8) | PLL_BASE_ENABLE; // DIVM: 4, DIVP: 1.
|
||||
|
||||
while (!(CLOCK(CLK_RST_CONTROLLER_PLLC4_BASE) & PLLC4_BASE_LOCK))
|
||||
;
|
||||
|
||||
CLOCK(CLK_RST_CONTROLLER_PLLC4_OUT) = (1 << 8) | PLLC4_OUT3_CLKEN; // 1.5 div.
|
||||
CLOCK(CLK_RST_CONTROLLER_PLLC4_OUT) |= PLLC4_OUT3_RSTN_CLR; // Get divider out of reset.
|
||||
|
||||
// Wait a bit for PLLC4 to stabilize.
|
||||
msleep(10);
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_SYSTEM_RATE) = 3; // PCLK = HCLK / 4.
|
||||
CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = 0x20003323; // PLLC4_OUT3.
|
||||
|
||||
bpmp_clock_set = fid;
|
||||
}
|
||||
else
|
||||
{
|
||||
CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = 0x20003333; // PLLP_OUT.
|
||||
|
||||
// Wait a bit for clock source change.
|
||||
msleep(10);
|
||||
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_SYSTEM_RATE) = 2; // PCLK = HCLK / 3.
|
||||
CLOCK(CLK_RST_CONTROLLER_PLLC4_BASE) &= ~PLL_BASE_ENABLE;
|
||||
bpmp_clock_set = BPMP_CLK_NORMAL;
|
||||
}
|
||||
}
|
||||
|
||||
// The following functions halt BPMP to reduce power while sleeping.
|
||||
// They are not as accurate as RTC at big values but they guarantee time+ delay.
|
||||
void bpmp_usleep(u32 us)
|
||||
{
|
||||
u32 delay;
|
||||
|
||||
// Each iteration takes 1us.
|
||||
while (us)
|
||||
{
|
||||
delay = (us > HALT_COP_MAX_CNT) ? HALT_COP_MAX_CNT : us;
|
||||
us -= delay;
|
||||
|
||||
FLOW_CTLR(FLOW_CTLR_HALT_COP_EVENTS) = HALT_COP_WAIT_EVENT | HALT_COP_USEC | delay;
|
||||
}
|
||||
}
|
||||
|
||||
void bpmp_msleep(u32 ms)
|
||||
{
|
||||
u32 delay;
|
||||
|
||||
// Iteration time is variable. ~200 - 1000us.
|
||||
while (ms)
|
||||
{
|
||||
delay = (ms > HALT_COP_MAX_CNT) ? HALT_COP_MAX_CNT : ms;
|
||||
ms -= delay;
|
||||
|
||||
FLOW_CTLR(FLOW_CTLR_HALT_COP_EVENTS) = HALT_COP_WAIT_EVENT | HALT_COP_MSEC | delay;
|
||||
}
|
||||
}
|
||||
|
||||
void bpmp_halt()
|
||||
{
|
||||
FLOW_CTLR(FLOW_CTLR_HALT_COP_EVENTS) = HALT_COP_WAIT_EVENT | HALT_COP_JTAG;
|
||||
}
|
54
source/soc/bpmp.h
Normal file
54
source/soc/bpmp.h
Normal file
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* BPMP-Lite Cache/MMU and Frequency driver for Tegra X1
|
||||
*
|
||||
* Copyright (c) 2019 CTCaer
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _BPMP_H_
|
||||
#define _BPMP_H_
|
||||
|
||||
#include "../utils/types.h"
|
||||
|
||||
#define BPMP_MMU_MAINT_CLEAN_WAY 17
|
||||
#define BPMP_MMU_MAINT_INVALID_WAY 18
|
||||
#define BPMP_MMU_MAINT_CLN_INV_WAY 19
|
||||
|
||||
typedef struct _bpmp_mmu_entry_t
|
||||
{
|
||||
u32 min_addr;
|
||||
u32 max_addr;
|
||||
u32 attr;
|
||||
u32 enable;
|
||||
} bpmp_mmu_entry_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
BPMP_CLK_NORMAL, // 408MHz 0% - 136MHz APB.
|
||||
BPMP_CLK_LOW_BOOST, // 544MHz 33% - 136MHz APB.
|
||||
BPMP_CLK_MID_BOOST, // 576MHz 41% - 144MHz APB.
|
||||
BPMP_CLK_SUPER_BOOST, // 608MHz 49% - 152MHz APB.
|
||||
BPMP_CLK_MAX
|
||||
} bpmp_freq_t;
|
||||
|
||||
void bpmp_mmu_maintenance(u32 op);
|
||||
void bpmp_mmu_set_entry(int idx, bpmp_mmu_entry_t *entry, bool apply);
|
||||
void bpmp_mmu_enable();
|
||||
void bpmp_mmu_disable();
|
||||
void bpmp_clk_rate_set(bpmp_freq_t fid);
|
||||
void bpmp_usleep(u32 us);
|
||||
void bpmp_msleep(u32 ms);
|
||||
void bpmp_halt();
|
||||
|
||||
#endif
|
|
@ -15,6 +15,7 @@
|
|||
*/
|
||||
|
||||
#include "../soc/clock.h"
|
||||
#include "../soc/kfuse.h"
|
||||
#include "../soc/t210.h"
|
||||
#include "../utils/util.h"
|
||||
#include "../storage/sdmmc.h"
|
||||
|
@ -22,57 +23,58 @@
|
|||
/* clock_t: reset, enable, source, index, clk_src, clk_div */
|
||||
|
||||
static const clock_t _clock_uart[] = {
|
||||
/* UART A */ { CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_UARTA, 6, 0, 0 },
|
||||
/* UART B */ { CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_UARTB, 7, 0, 0 },
|
||||
/* UART C */ { CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_RST_CONTROLLER_CLK_SOURCE_UARTC, 0x17, 0, 0 },
|
||||
/* UART D */ { 0 },
|
||||
/* UART E */ { 0 }
|
||||
/* UART A */ { CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_UARTA, 6, 0, 2 },
|
||||
/* UART B */ { CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_UARTB, 7, 0, 2 },
|
||||
/* UART C */ { CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_RST_CONTROLLER_CLK_SOURCE_UARTC, 23, 0, 2 },
|
||||
/* UART D */ { CLK_RST_CONTROLLER_RST_DEVICES_U, CLK_RST_CONTROLLER_CLK_OUT_ENB_U, CLK_RST_CONTROLLER_CLK_SOURCE_UARTD, 1, 0, 2 },
|
||||
/* UART E */ { CLK_RST_CONTROLLER_RST_DEVICES_Y, CLK_RST_CONTROLLER_CLK_OUT_ENB_Y, CLK_RST_CONTROLLER_CLK_SOURCE_UARTAPE, 20, 0, 2 }
|
||||
};
|
||||
|
||||
static const clock_t _clock_i2c[] = {
|
||||
/* I2C1 */ { CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_I2C1, 0xC, 6, 0 },
|
||||
/* 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, 0xF, 6, 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 }
|
||||
};
|
||||
|
||||
static clock_t _clock_se = {
|
||||
CLK_RST_CONTROLLER_RST_DEVICES_V, CLK_RST_CONTROLLER_CLK_OUT_ENB_V, CLK_RST_CONTROLLER_CLK_SOURCE_SE, 0x1F, 0, 0
|
||||
CLK_RST_CONTROLLER_RST_DEVICES_V, CLK_RST_CONTROLLER_CLK_OUT_ENB_V, CLK_RST_CONTROLLER_CLK_SOURCE_SE, 31, 0, 0
|
||||
};
|
||||
static clock_t _clock_unk2 = {
|
||||
CLK_RST_CONTROLLER_RST_DEVICES_V, CLK_RST_CONTROLLER_CLK_OUT_ENB_V, CLK_NO_SOURCE, 0x1E, 0, 0
|
||||
|
||||
static clock_t _clock_tzram = {
|
||||
CLK_RST_CONTROLLER_RST_DEVICES_V, CLK_RST_CONTROLLER_CLK_OUT_ENB_V, CLK_NO_SOURCE, 30, 0, 0
|
||||
};
|
||||
|
||||
static clock_t _clock_host1x = {
|
||||
CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_HOST1X, 0x1C, 4, 3
|
||||
CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_HOST1X, 28, 4, 3
|
||||
};
|
||||
static clock_t _clock_tsec = {
|
||||
CLK_RST_CONTROLLER_RST_DEVICES_U, CLK_RST_CONTROLLER_CLK_OUT_ENB_U, CLK_RST_CONTROLLER_CLK_SOURCE_TSEC, 0x13, 0, 2
|
||||
CLK_RST_CONTROLLER_RST_DEVICES_U, CLK_RST_CONTROLLER_CLK_OUT_ENB_U, CLK_RST_CONTROLLER_CLK_SOURCE_TSEC, 19, 0, 2
|
||||
};
|
||||
static clock_t _clock_sor_safe = {
|
||||
CLK_RST_CONTROLLER_RST_DEVICES_Y, CLK_RST_CONTROLLER_CLK_OUT_ENB_Y, CLK_NO_SOURCE, 0x1E, 0, 0
|
||||
CLK_RST_CONTROLLER_RST_DEVICES_Y, CLK_RST_CONTROLLER_CLK_OUT_ENB_Y, CLK_NO_SOURCE, 30, 0, 0
|
||||
};
|
||||
static clock_t _clock_sor0 = {
|
||||
CLK_RST_CONTROLLER_RST_DEVICES_X, CLK_RST_CONTROLLER_CLK_OUT_ENB_X, CLK_NO_SOURCE, 0x16, 0, 0
|
||||
CLK_RST_CONTROLLER_RST_DEVICES_X, CLK_RST_CONTROLLER_CLK_OUT_ENB_X, CLK_NO_SOURCE, 22, 0, 0
|
||||
};
|
||||
static clock_t _clock_sor1 = {
|
||||
CLK_RST_CONTROLLER_RST_DEVICES_X, CLK_RST_CONTROLLER_CLK_OUT_ENB_X, CLK_RST_CONTROLLER_CLK_SOURCE_SOR1, 0x17, 0, 2
|
||||
CLK_RST_CONTROLLER_RST_DEVICES_X, CLK_RST_CONTROLLER_CLK_OUT_ENB_X, CLK_RST_CONTROLLER_CLK_SOURCE_SOR1, 23, 0, 2
|
||||
};
|
||||
static clock_t _clock_kfuse = {
|
||||
CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_NO_SOURCE, 8, 0, 0
|
||||
};
|
||||
|
||||
static clock_t _clock_cl_dvfs = {
|
||||
CLK_RST_CONTROLLER_RST_DEVICES_W, CLK_RST_CONTROLLER_CLK_OUT_ENB_W, CLK_NO_SOURCE, 0x1B, 0, 0
|
||||
CLK_RST_CONTROLLER_RST_DEVICES_W, CLK_RST_CONTROLLER_CLK_OUT_ENB_W, CLK_NO_SOURCE, 27, 0, 0
|
||||
};
|
||||
static clock_t _clock_coresight = {
|
||||
CLK_RST_CONTROLLER_RST_DEVICES_U, CLK_RST_CONTROLLER_CLK_OUT_ENB_U, CLK_RST_CONTROLLER_CLK_SOURCE_CSITE, 9, 0, 4
|
||||
};
|
||||
|
||||
static clock_t _clock_pwm = {
|
||||
CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_PWM, 0x11, 6, 4
|
||||
CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_PWM, 17, 6, 4 // Freference: 6.2MHz.
|
||||
};
|
||||
|
||||
void clock_enable(const clock_t *clk)
|
||||
|
@ -123,9 +125,9 @@ void clock_enable_se()
|
|||
clock_enable(&_clock_se);
|
||||
}
|
||||
|
||||
void clock_enable_unk2()
|
||||
void clock_enable_tzram()
|
||||
{
|
||||
clock_enable(&_clock_unk2);
|
||||
clock_enable(&_clock_tzram);
|
||||
}
|
||||
|
||||
void clock_enable_host1x()
|
||||
|
@ -187,6 +189,7 @@ void clock_enable_kfuse()
|
|||
usleep(10);
|
||||
CLOCK(CLK_RST_CONTROLLER_RST_DEVICES_H) &= 0xFFFFFEFF;
|
||||
usleep(20);
|
||||
kfuse_wait_ready();
|
||||
}
|
||||
|
||||
void clock_disable_kfuse()
|
||||
|
@ -365,49 +368,49 @@ 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)
|
||||
{
|
||||
u32 divisor = 0;
|
||||
u32 source = PLLP_OUT0;
|
||||
|
||||
// Get IO clock divisor.
|
||||
switch (val)
|
||||
{
|
||||
case 25000:
|
||||
*pout = 24728;
|
||||
divisor = 31;
|
||||
divisor = 31; // 16.5 div.
|
||||
break;
|
||||
case 26000:
|
||||
*pout = 25500;
|
||||
divisor = 30;
|
||||
divisor = 30; // 16 div.
|
||||
break;
|
||||
case 40800:
|
||||
*pout = 40800;
|
||||
divisor = 18;
|
||||
divisor = 18; // 10 div.
|
||||
break;
|
||||
case 50000:
|
||||
*pout = 48000;
|
||||
divisor = 15;
|
||||
divisor = 15; // 8.5 div.
|
||||
break;
|
||||
case 52000:
|
||||
*pout = 51000;
|
||||
divisor = 14;
|
||||
divisor = 14; // 8 div.
|
||||
break;
|
||||
case 100000:
|
||||
*pout = 90667;
|
||||
divisor = 7;
|
||||
divisor = 7; // 4.5 div.
|
||||
break;
|
||||
case 200000:
|
||||
*pout = 163200;
|
||||
divisor = 3;
|
||||
divisor = 3; // 2.5 div.
|
||||
break;
|
||||
case 208000:
|
||||
*pout = 204000;
|
||||
divisor = 2;
|
||||
divisor = 2; // 2 div.
|
||||
break;
|
||||
default:
|
||||
*pout = 24728;
|
||||
divisor = 31;
|
||||
divisor = 31; // 16.5 div.
|
||||
}
|
||||
|
||||
_clock_sdmmc_table[2 * id] = val;
|
||||
|
|
|
@ -41,6 +41,8 @@
|
|||
#define CLK_RST_CONTROLLER_PLLM_MISC2 0x9C
|
||||
#define CLK_RST_CONTROLLER_PLLP_BASE 0xA0
|
||||
#define CLK_RST_CONTROLLER_PLLD_BASE 0xD0
|
||||
#define CLK_RST_CONTROLLER_PLLD_MISC1 0xD8
|
||||
#define CLK_RST_CONTROLLER_PLLD_MISC 0xDC
|
||||
#define CLK_RST_CONTROLLER_PLLX_BASE 0xE0
|
||||
#define CLK_RST_CONTROLLER_PLLX_MISC 0xE4
|
||||
#define CLK_RST_CONTROLLER_PLLE_BASE 0xE8
|
||||
|
@ -50,6 +52,7 @@
|
|||
#define CLK_RST_CONTROLLER_CLK_SOURCE_PWM 0x110
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_I2C1 0x124
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_I2C5 0x128
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_DISP1 0x138
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_VI 0x148
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC1 0x150
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC2 0x154
|
||||
|
@ -57,11 +60,13 @@
|
|||
#define CLK_RST_CONTROLLER_CLK_SOURCE_UARTA 0x178
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_UARTB 0x17C
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_HOST1X 0x180
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_I2C2 0x198
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_EMC 0x19C
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_UARTC 0x1A0
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_I2C3 0x1B8
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC3 0x1BC
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_UARTD 0x1C0
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_CSITE 0x1D4
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_EMC 0x19C
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_TSEC 0x1F4
|
||||
#define CLK_RST_CONTROLLER_CLK_OUT_ENB_X 0x280
|
||||
#define CLK_RST_CONTROLLER_CLK_ENB_X_SET 0x284
|
||||
|
@ -95,9 +100,12 @@
|
|||
#define CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRC 0x3A0
|
||||
#define CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRD 0x3A4
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_MSELECT 0x3B4
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_I2C4 0x3C4
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_SYS 0x400
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_SOR1 0x410
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_SE 0x42C
|
||||
#define CLK_RST_CONTROLLER_CLK_ENB_V_SET 0x440
|
||||
#define CLK_RST_CONTROLLER_CLK_ENB_V_CLR 0x444
|
||||
#define CLK_RST_CONTROLLER_CLK_ENB_W_SET 0x448
|
||||
#define CLK_RST_CONTROLLER_CLK_ENB_W_CLR 0x44C
|
||||
#define CLK_RST_CONTROLLER_RST_CPUG_CMPLX_SET 0x450
|
||||
|
@ -108,16 +116,30 @@
|
|||
#define CLK_RST_CONTROLLER_PLLX_MISC_3 0x518
|
||||
#define CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRE 0x554
|
||||
#define CLK_RST_CONTROLLER_SPARE_REG0 0x55C
|
||||
#define CLK_RST_CONTROLLER_PLLC4_BASE 0x5A4
|
||||
#define CLK_RST_CONTROLLER_PLLC4_MISC 0x5A8
|
||||
#define CLK_RST_CONTROLLER_PLLC4_OUT 0x5E4
|
||||
#define CLK_RST_CONTROLLER_PLLMB_BASE 0x5E8
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_DSIA_LP 0x620
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_I2C6 0x65C
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_EMC_DLL 0x664
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_UART_FST_MIP_CAL 0x66C
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_UART_FST_MIPI_CAL 0x66C
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC_LEGACY_TM 0x694
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_NVENC 0x6A0
|
||||
#define CLK_RST_CONTROLLER_SE_SUPER_CLK_DIVIDER 0x704
|
||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_UARTAPE 0x710
|
||||
|
||||
#define CLK_NO_SOURCE 0x0
|
||||
|
||||
/*! PLL control and status bits */
|
||||
#define PLL_BASE_ENABLE (1 << 30)
|
||||
|
||||
#define PLLC4_MISC_EN_LCKDET (1 << 30)
|
||||
#define PLLC4_BASE_LOCK (1 << 27)
|
||||
#define PLLC4_BASE_IDDQ (1 << 18)
|
||||
#define PLLC4_OUT3_CLKEN (1 << 1)
|
||||
#define PLLC4_OUT3_RSTN_CLR (1 << 0)
|
||||
|
||||
/*! Generic clock descriptor. */
|
||||
typedef struct _clock_t
|
||||
{
|
||||
|
@ -139,7 +161,7 @@ void clock_enable_uart(u32 idx);
|
|||
void clock_enable_i2c(u32 idx);
|
||||
void clock_disable_i2c(u32 idx);
|
||||
void clock_enable_se();
|
||||
void clock_enable_unk2();
|
||||
void clock_enable_tzram();
|
||||
void clock_enable_host1x();
|
||||
void clock_disable_host1x();
|
||||
void clock_enable_tsec();
|
||||
|
|
|
@ -32,18 +32,21 @@ void _cluster_enable_power()
|
|||
// Enable cores power.
|
||||
// 1-3.x: MAX77621_NFSR_ENABLE.
|
||||
i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_CONTROL1_REG,
|
||||
MAX77621_AD_ENABLE | MAX77621_NFSR_ENABLE | MAX77621_SNS_ENABLE);
|
||||
MAX77621_AD_ENABLE | MAX77621_NFSR_ENABLE | MAX77621_SNS_ENABLE | MAX77621_RAMP_12mV_PER_US);
|
||||
// 1.0.0-3.x: MAX77621_T_JUNCTION_120 | MAX77621_CKKADV_TRIP_DISABLE | MAX77621_INDUCTOR_NOMINAL.
|
||||
i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_CONTROL2_REG,
|
||||
MAX77621_T_JUNCTION_120 | MAX77621_WDTMR_ENABLE | MAX77621_CKKADV_TRIP_75mV_PER_US| MAX77621_INDUCTOR_NOMINAL);
|
||||
i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_VOUT_REG, MAX77621_VOUT_ENABLE | 0x37);
|
||||
i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_VOUT_DVC_REG, MAX77621_VOUT_ENABLE | 0x37);
|
||||
i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_VOUT_REG, MAX77621_VOUT_ENABLE | MAX77621_VOUT_0_95V);
|
||||
i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_VOUT_DVC_REG, MAX77621_VOUT_ENABLE | MAX77621_VOUT_0_95V);
|
||||
}
|
||||
|
||||
int _cluster_pmc_enable_partition(u32 part, u32 toggle, bool enable)
|
||||
int _cluster_pmc_enable_partition(u32 part, int enable)
|
||||
{
|
||||
// Check if the partition has already been turned on.
|
||||
if (enable && PMC(APBDEV_PMC_PWRGATE_STATUS) & part)
|
||||
u32 part_mask = 1 << part;
|
||||
u32 desired_state = enable << part;
|
||||
|
||||
// Check if the partition has the state we want.
|
||||
if ((PMC(APBDEV_PMC_PWRGATE_STATUS) & part_mask) == desired_state)
|
||||
return 1;
|
||||
|
||||
u32 i = 5001;
|
||||
|
@ -55,12 +58,13 @@ int _cluster_pmc_enable_partition(u32 part, u32 toggle, bool enable)
|
|||
return 0;
|
||||
}
|
||||
|
||||
PMC(APBDEV_PMC_PWRGATE_TOGGLE) = toggle | (enable ? 0x100 : 0);
|
||||
// Toggle power gating.
|
||||
PMC(APBDEV_PMC_PWRGATE_TOGGLE) = part | 0x100;
|
||||
|
||||
i = 5001;
|
||||
while (i > 0)
|
||||
{
|
||||
if (PMC(APBDEV_PMC_PWRGATE_STATUS) & part)
|
||||
if ((PMC(APBDEV_PMC_PWRGATE_STATUS) & part_mask) == desired_state)
|
||||
break;
|
||||
usleep(1);
|
||||
i--;
|
||||
|
@ -103,11 +107,11 @@ void cluster_boot_cpu0(u32 entry)
|
|||
CLOCK(CLK_RST_CONTROLLER_CPU_SOFTRST_CTRL2) &= 0xFFFFF000;
|
||||
|
||||
// Enable CPU rail.
|
||||
_cluster_pmc_enable_partition(1, 0, true);
|
||||
_cluster_pmc_enable_partition(0, 1);
|
||||
// Enable cluster 0 non-CPU.
|
||||
_cluster_pmc_enable_partition(0x8000, 15, true);
|
||||
_cluster_pmc_enable_partition(15, 1);
|
||||
// Enable CE0.
|
||||
_cluster_pmc_enable_partition(0x4000, 14, true);
|
||||
_cluster_pmc_enable_partition(14, 1);
|
||||
|
||||
// Request and wait for RAM repair.
|
||||
FLOW_CTLR(FLOW_CTLR_RAM_REPAIR) = 1;
|
||||
|
@ -117,10 +121,10 @@ void cluster_boot_cpu0(u32 entry)
|
|||
EXCP_VEC(EVP_CPU_RESET_VECTOR) = 0;
|
||||
|
||||
// Set reset vector.
|
||||
SB(SB_AA64_RESET_LOW) = entry | 1;
|
||||
SB(SB_AA64_RESET_LOW) = entry | SB_AA64_RST_AARCH64_MODE_EN;
|
||||
SB(SB_AA64_RESET_HIGH) = 0;
|
||||
// Non-secure reset vector write disable.
|
||||
SB(SB_CSR) = 2;
|
||||
SB(SB_CSR) = SB_CSR_NS_RST_VEC_WR_DIS;
|
||||
(void)SB(SB_CSR);
|
||||
|
||||
// Clear MSELECT reset.
|
||||
|
|
|
@ -19,19 +19,6 @@
|
|||
|
||||
#include "../utils/types.h"
|
||||
|
||||
/*! Flow controller registers. */
|
||||
#define FLOW_CTLR_HALT_CPU0_EVENTS 0x0
|
||||
#define FLOW_CTLR_HALT_CPU1_EVENTS 0x14
|
||||
#define FLOW_CTLR_HALT_CPU2_EVENTS 0x1C
|
||||
#define FLOW_CTLR_HALT_CPU3_EVENTS 0x24
|
||||
#define FLOW_CTLR_HALT_COP_EVENTS 0x4
|
||||
#define FLOW_CTLR_CPU0_CSR 0x8
|
||||
#define FLOW_CTLR_CPU1_CSR 0x18
|
||||
#define FLOW_CTLR_CPU2_CSR 0x20
|
||||
#define FLOW_CTLR_CPU3_CSR 0x28
|
||||
#define FLOW_CTLR_RAM_REPAIR 0x40
|
||||
#define FLOW_CTLR_BPMP_CLUSTER_CONTROL 0x98
|
||||
|
||||
void cluster_boot_cpu0(u32 entry);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -37,12 +37,31 @@
|
|||
#define FUSE_WRITE_ACCESS_SW 0x30
|
||||
#define FUSE_PWR_GOOD_SW 0x34
|
||||
#define FUSE_SKU_INFO 0x110
|
||||
#define FUSE_CPU_SPEEDO_0_CALIB 0x114
|
||||
#define FUSE_CPU_IDDQ_CALIB 0x118
|
||||
#define FUSE_OPT_FT_REV 0x128
|
||||
#define FUSE_CPU_SPEEDO_1_CALIB 0x12C
|
||||
#define FUSE_CPU_SPEEDO_2_CALIB 0x130
|
||||
#define FUSE_SOC_SPEEDO_0_CALIB 0x134
|
||||
#define FUSE_SOC_SPEEDO_1_CALIB 0x138
|
||||
#define FUSE_SOC_SPEEDO_2_CALIB 0x13C
|
||||
#define FUSE_SOC_IDDQ_CALIB 0x140
|
||||
#define FUSE_OPT_CP_REV 0x190
|
||||
#define FUSE_FIRST_BOOTROM_PATCH_SIZE 0x19c
|
||||
#define FUSE_PRIVATE_KEY0 0x1A4
|
||||
#define FUSE_PRIVATE_KEY1 0x1A8
|
||||
#define FUSE_PRIVATE_KEY2 0x1AC
|
||||
#define FUSE_PRIVATE_KEY3 0x1B0
|
||||
#define FUSE_PRIVATE_KEY4 0x1B4
|
||||
#define FUSE_RESERVED_SW 0x1C0
|
||||
#define FUSE_OPT_VENDOR_CODE 0x200
|
||||
#define FUSE_OPT_FAB_CODE 0x204
|
||||
#define FUSE_OPT_LOT_CODE_0 0x208
|
||||
#define FUSE_OPT_LOT_CODE_1 0x20C
|
||||
#define FUSE_OPT_WAFER_ID 0x210
|
||||
#define FUSE_OPT_X_COORDINATE 0x214
|
||||
#define FUSE_OPT_Y_COORDINATE 0x218
|
||||
#define FUSE_GPU_IDDQ_CALIB 0x228
|
||||
|
||||
/*! Fuse commands. */
|
||||
#define FUSE_READ 0x1
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include <string.h>
|
||||
|
||||
#include "hw_init.h"
|
||||
#include "bpmp.h"
|
||||
#include "clock.h"
|
||||
#include "fuse.h"
|
||||
#include "gpio.h"
|
||||
|
@ -27,6 +28,7 @@
|
|||
#include "t210.h"
|
||||
#include "../gfx/di.h"
|
||||
#include "../mem/mc.h"
|
||||
#include "../mem/minerva.h"
|
||||
#include "../mem/sdram.h"
|
||||
#include "../power/max77620.h"
|
||||
#include "../power/max7762x.h"
|
||||
|
@ -38,22 +40,36 @@
|
|||
extern sdmmc_t sd_sdmmc;
|
||||
extern boot_cfg_t b_cfg;
|
||||
|
||||
/*
|
||||
* CLK_OSC - 38.4 MHz crystal.
|
||||
* CLK_M - 19.2 MHz (osc/2).
|
||||
* CLK_S - 32.768 KHz (from PMIC).
|
||||
* SCLK - 204MHz init (-> 408MHz -> OC).
|
||||
* HCLK - 204MHz init (-> 408MHz -> OC).
|
||||
* PCLK - 68MHz init (-> 136MHz -> OC/4).
|
||||
*/
|
||||
|
||||
void _config_oscillators()
|
||||
{
|
||||
CLOCK(CLK_RST_CONTROLLER_SPARE_REG0) = (CLOCK(CLK_RST_CONTROLLER_SPARE_REG0) & 0xFFFFFFF3) | 4;
|
||||
SYSCTR0(SYSCTR0_CNTFID0) = 19200000;
|
||||
CLOCK(CLK_RST_CONTROLLER_SPARE_REG0) = (CLOCK(CLK_RST_CONTROLLER_SPARE_REG0) & 0xFFFFFFF3) | 4; // Set CLK_M_DIVISOR to 2.
|
||||
SYSCTR0(SYSCTR0_CNTFID0) = 19200000; // Set counter frequency.
|
||||
TMR(TIMERUS_USEC_CFG) = 0x45F; // For 19.2MHz clk_m.
|
||||
CLOCK(CLK_RST_CONTROLLER_OSC_CTRL) = 0x50000071;
|
||||
PMC(APBDEV_PMC_OSC_EDPD_OVER) = (PMC(APBDEV_PMC_OSC_EDPD_OVER) & 0xFFFFFF81) | 0xE;
|
||||
PMC(APBDEV_PMC_OSC_EDPD_OVER) = (PMC(APBDEV_PMC_OSC_EDPD_OVER) & 0xFFBFFFFF) | 0x400000;
|
||||
PMC(APBDEV_PMC_CNTRL2) = (PMC(APBDEV_PMC_CNTRL2) & 0xFFFFEFFF) | 0x1000;
|
||||
PMC(APBDEV_PMC_SCRATCH188) = (PMC(APBDEV_PMC_SCRATCH188) & 0xFCFFFFFF) | 0x2000000;
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_SYSTEM_RATE) = 0x10;
|
||||
CLOCK(CLK_RST_CONTROLLER_PLLMB_BASE) &= 0xBFFFFFFF;
|
||||
CLOCK(CLK_RST_CONTROLLER_OSC_CTRL) = 0x50000071; // Set OSC to 38.4MHz and drive strength.
|
||||
|
||||
PMC(APBDEV_PMC_OSC_EDPD_OVER) = (PMC(APBDEV_PMC_OSC_EDPD_OVER) & 0xFFFFFF81) | 0xE; // Set LP0 OSC drive strength.
|
||||
PMC(APBDEV_PMC_OSC_EDPD_OVER) = (PMC(APBDEV_PMC_OSC_EDPD_OVER) & 0xFFBFFFFF) | PMC_OSC_EDPD_OVER_OSC_CTRL_OVER;
|
||||
PMC(APBDEV_PMC_CNTRL2) = (PMC(APBDEV_PMC_CNTRL2) & 0xFFFFEFFF) | PMC_CNTRL2_HOLD_CKE_LOW_EN;
|
||||
PMC(APBDEV_PMC_SCRATCH188) = (PMC(APBDEV_PMC_SCRATCH188) & 0xFCFFFFFF) | (4 << 23); // LP0 EMC2TMC_CFG_XM2COMP_PU_VREF_SEL_RANGE.
|
||||
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_SYSTEM_RATE) = 0x10; // Set HCLK div to 2 and PCLK div to 1.
|
||||
CLOCK(CLK_RST_CONTROLLER_PLLMB_BASE) &= 0xBFFFFFFF; // PLLMB disable.
|
||||
|
||||
PMC(APBDEV_PMC_TSC_MULT) = (PMC(APBDEV_PMC_TSC_MULT) & 0xFFFF0000) | 0x249F; //0x249F = 19200000 * (16 / 32.768 kHz)
|
||||
CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = 0x20004444;
|
||||
CLOCK(CLK_RST_CONTROLLER_SUPER_SCLK_DIVIDER) = 0x80000000;
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_SYSTEM_RATE) = 2;
|
||||
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SYS) = 0; // Set SCLK div to 1.
|
||||
CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = 0x20004444; // Set clk source to Run and PLLP_OUT2 (204MHz).
|
||||
CLOCK(CLK_RST_CONTROLLER_SUPER_SCLK_DIVIDER) = 0x80000000; // Enable SUPER_SDIV to 1.
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_SYSTEM_RATE) = 2; // Set HCLK div to 1 and PCLK div to 3.
|
||||
}
|
||||
|
||||
void _config_gpios()
|
||||
|
@ -61,11 +77,22 @@ void _config_gpios()
|
|||
PINMUX_AUX(PINMUX_AUX_UART2_TX) = 0;
|
||||
PINMUX_AUX(PINMUX_AUX_UART3_TX) = 0;
|
||||
|
||||
// Set Joy-Con IsAttached direction.
|
||||
PINMUX_AUX(PINMUX_AUX_GPIO_PE6) = PINMUX_INPUT_ENABLE;
|
||||
PINMUX_AUX(PINMUX_AUX_GPIO_PH6) = PINMUX_INPUT_ENABLE;
|
||||
|
||||
// Set pin mode for Joy-Con IsAttached and UARTB/C TX pins.
|
||||
#if !defined (DEBUG_UART_PORT) || DEBUG_UART_PORT != UART_B
|
||||
gpio_config(GPIO_PORT_G, GPIO_PIN_0, GPIO_MODE_GPIO);
|
||||
#endif
|
||||
#if !defined (DEBUG_UART_PORT) || DEBUG_UART_PORT != UART_C
|
||||
gpio_config(GPIO_PORT_D, GPIO_PIN_1, GPIO_MODE_GPIO);
|
||||
#endif
|
||||
// Set Joy-Con IsAttached mode.
|
||||
gpio_config(GPIO_PORT_E, GPIO_PIN_6, GPIO_MODE_GPIO);
|
||||
gpio_config(GPIO_PORT_H, GPIO_PIN_6, GPIO_MODE_GPIO);
|
||||
|
||||
// Enable input logic for Joy-Con IsAttached and UARTB/C TX pins.
|
||||
gpio_output_enable(GPIO_PORT_G, GPIO_PIN_0, GPIO_OUTPUT_DISABLE);
|
||||
gpio_output_enable(GPIO_PORT_D, GPIO_PIN_1, GPIO_OUTPUT_DISABLE);
|
||||
gpio_output_enable(GPIO_PORT_E, GPIO_PIN_6, GPIO_OUTPUT_DISABLE);
|
||||
|
@ -80,13 +107,17 @@ void _config_gpios()
|
|||
gpio_config(GPIO_PORT_X, GPIO_PIN_7, GPIO_MODE_GPIO);
|
||||
gpio_output_enable(GPIO_PORT_X, GPIO_PIN_6, GPIO_OUTPUT_DISABLE);
|
||||
gpio_output_enable(GPIO_PORT_X, GPIO_PIN_7, GPIO_OUTPUT_DISABLE);
|
||||
|
||||
// Configure HOME as inputs.
|
||||
// PINMUX_AUX(PINMUX_AUX_BUTTON_HOME) = PINMUX_PULL_UP | PINMUX_INPUT_ENABLE;
|
||||
// gpio_config(GPIO_PORT_Y, GPIO_PIN_1, GPIO_MODE_GPIO);
|
||||
}
|
||||
|
||||
void _config_pmc_scratch()
|
||||
{
|
||||
PMC(APBDEV_PMC_SCRATCH20) &= 0xFFF3FFFF;
|
||||
PMC(APBDEV_PMC_SCRATCH190) &= 0xFFFFFFFE;
|
||||
PMC(APBDEV_PMC_SECURE_SCRATCH21) |= 0x10;
|
||||
PMC(APBDEV_PMC_SCRATCH20) &= 0xFFF3FFFF; // Unset Debug console from Customer Option.
|
||||
PMC(APBDEV_PMC_SCRATCH190) &= 0xFFFFFFFE; // Unset DATA_DQ_E_IVREF EMC_PMACRO_DATA_PAD_TX_CTRL
|
||||
PMC(APBDEV_PMC_SECURE_SCRATCH21) |= PMC_FUSE_PRIVATEKEYDISABLE_TZ_STICKY_BIT;
|
||||
}
|
||||
|
||||
void _mbist_workaround()
|
||||
|
@ -94,13 +125,18 @@ void _mbist_workaround()
|
|||
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_V) |= (1 << 10); // Enable AHUB clock.
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_Y) |= (1 << 6); // Enable APE clock.
|
||||
|
||||
// Set mux output to SOR1 clock switch.
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SOR1) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SOR1) | 0x8000) & 0xFFFFBFFF;
|
||||
CLOCK(CLK_RST_CONTROLLER_PLLD_BASE) |= 0x40800000u;
|
||||
CLOCK(CLK_RST_CONTROLLER_RST_DEV_Y_CLR) = 0x40;
|
||||
CLOCK(CLK_RST_CONTROLLER_RST_DEV_X_CLR) = 0x40000;
|
||||
CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_CLR) = 0x18000000;
|
||||
// Enabled PLLD and set csi to PLLD for test pattern generation.
|
||||
CLOCK(CLK_RST_CONTROLLER_PLLD_BASE) |= 0x40800000;
|
||||
|
||||
// Clear per-clock resets.
|
||||
CLOCK(CLK_RST_CONTROLLER_RST_DEV_Y_CLR) = 0x40; // Clear reset APE.
|
||||
CLOCK(CLK_RST_CONTROLLER_RST_DEV_X_CLR) = 0x40000; // Clear reset VIC.
|
||||
CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_CLR) = 0x18000000; // Clear reset DISP1, HOST1X.
|
||||
usleep(2);
|
||||
|
||||
// I2S channels to master and disable SLCG.
|
||||
I2S(I2S1_CTRL) |= I2S_CTRL_MASTER_EN;
|
||||
I2S(I2S1_CG) &= ~I2S_CG_SLCG_ENABLE;
|
||||
I2S(I2S2_CTRL) |= I2S_CTRL_MASTER_EN;
|
||||
|
@ -111,30 +147,39 @@ void _mbist_workaround()
|
|||
I2S(I2S4_CG) &= ~I2S_CG_SLCG_ENABLE;
|
||||
I2S(I2S5_CTRL) |= I2S_CTRL_MASTER_EN;
|
||||
I2S(I2S5_CG) &= ~I2S_CG_SLCG_ENABLE;
|
||||
DISPLAY_A(_DIREG(DC_COM_DSC_TOP_CTL)) |= 4;
|
||||
|
||||
DISPLAY_A(_DIREG(DC_COM_DSC_TOP_CTL)) |= 4; // DSC_SLCG_OVERRIDE.
|
||||
VIC(0x8C) = 0xFFFFFFFF;
|
||||
usleep(2);
|
||||
|
||||
CLOCK(CLK_RST_CONTROLLER_RST_DEV_Y_SET) = 0x40;
|
||||
CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = 0x18000000;
|
||||
CLOCK(CLK_RST_CONTROLLER_RST_DEV_X_SET) = 0x40000;
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_H) = 0xC0;
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_L) = 0x80000130;
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_U) = 0x1F00200;
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_V) = 0x80400808;
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_W) = 0x402000FC;
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_X) = 0x23000780;
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_Y) = 0x300;
|
||||
// Set per-clock reset.
|
||||
CLOCK(CLK_RST_CONTROLLER_RST_DEV_Y_SET) = 0x40; // Set reset APE.
|
||||
CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = 0x18000000; // Set reset DISP1, HOST1x.
|
||||
CLOCK(CLK_RST_CONTROLLER_RST_DEV_X_SET) = 0x40000; // Set reset VIC.
|
||||
|
||||
// Enable specific clocks and disable all others.
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_H) = 0xC0; // Enable clock PMC, FUSE.
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_L) = 0x80000130; // Enable clock RTC, TMR, GPIO, BPMP_CACHE.
|
||||
//CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_L) = 0x80400130; // Keep USB data ON.
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_U) = 0x1F00200; // Enable clock CSITE, IRAMA, IRAMB, IRAMC, IRAMD, BPMP_CACHE_RAM.
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_V) = 0x80400808; // Enable clock MSELECT, APB2APE, SPDIF_DOUBLER, SE.
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_W) = 0x402000FC; // Enable clock PCIERX0, PCIERX1, PCIERX2, PCIERX3, PCIERX4, PCIERX5, ENTROPY, MC1.
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_X) = 0x23000780; // Enable clock MC_CAPA, MC_CAPB, MC_CPU, MC_BBC, DBGAPB, HPLL_ADSP, PLLG_REF.
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_Y) = 0x300; // Enable clock MC_CDPA, MC_CCPA.
|
||||
|
||||
// Disable clock gate overrides.
|
||||
CLOCK(CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRA) = 0;
|
||||
CLOCK(CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRB) = 0;
|
||||
CLOCK(CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRC) = 0;
|
||||
CLOCK(CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRD) = 0;
|
||||
CLOCK(CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRE) = 0;
|
||||
CLOCK(CLK_RST_CONTROLLER_PLLD_BASE) &= 0x1F7FFFFF;
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SOR1) &= 0xFFFF3FFF;
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_VI) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_VI) & 0x1FFFFFFF) | 0x80000000;
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_HOST1X) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_HOST1X) & 0x1FFFFFFF) | 0x80000000;
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_NVENC) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_NVENC) & 0x1FFFFFFF) | 0x80000000;
|
||||
|
||||
// Set child clock sources.
|
||||
CLOCK(CLK_RST_CONTROLLER_PLLD_BASE) &= 0x1F7FFFFF; // Disable PLLD and set reference clock and csi clock.
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SOR1) &= 0xFFFF3FFF; // Set SOR1 to automatic muxing of safe clock (24MHz) or SOR1 clk switch.
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_VI) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_VI) & 0x1FFFFFFF) | 0x80000000; // Set clock source to PLLP_OUT.
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_HOST1X) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_HOST1X) & 0x1FFFFFFF) | 0x80000000; // Set clock source to PLLP_OUT.
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_NVENC) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_NVENC) & 0x1FFFFFFF) | 0x80000000; // Set clock source to PLLP_OUT.
|
||||
}
|
||||
|
||||
void _config_se_brom()
|
||||
|
@ -170,13 +215,59 @@ void _config_se_brom()
|
|||
APB_MISC(APB_MISC_PP_STRAPPING_OPT_A) = (APB_MISC(APB_MISC_PP_STRAPPING_OPT_A) & 0xF0) | (7 << 10);
|
||||
}
|
||||
|
||||
void _config_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.
|
||||
|
||||
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_CFG0,
|
||||
(7 << MAX77620_FPS_TIME_PERIOD_SHIFT));
|
||||
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_CFG1,
|
||||
(7 << MAX77620_FPS_TIME_PERIOD_SHIFT) | (1 << MAX77620_FPS_EN_SRC_SHIFT));
|
||||
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_CFG2,
|
||||
(7 << MAX77620_FPS_TIME_PERIOD_SHIFT));
|
||||
max77620_regulator_config_fps(REGULATOR_LDO4);
|
||||
max77620_regulator_config_fps(REGULATOR_LDO8);
|
||||
max77620_regulator_config_fps(REGULATOR_SD0);
|
||||
max77620_regulator_config_fps(REGULATOR_SD1);
|
||||
max77620_regulator_config_fps(REGULATOR_SD3);
|
||||
|
||||
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_GPIO3,
|
||||
(4 << MAX77620_FPS_TIME_PERIOD_SHIFT) | (2 << MAX77620_FPS_PD_PERIOD_SHIFT)); // 3.x+
|
||||
|
||||
// Set vdd_core voltage to 1.125V
|
||||
max77620_regulator_set_voltage(REGULATOR_SD0, 1125000);
|
||||
|
||||
// Fix CPU/GPU after a Linux warmboot.
|
||||
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_GPIO5, 2);
|
||||
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_GPIO6, 2);
|
||||
|
||||
i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_VOUT_REG, MAX77621_VOUT_0_95V); // Disable power.
|
||||
i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_VOUT_DVC_REG, MAX77621_VOUT_ENABLE | MAX77621_VOUT_1_09V); // Enable DVS power.
|
||||
i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_CONTROL1_REG, MAX77621_RAMP_50mV_PER_US);
|
||||
i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_CONTROL2_REG,
|
||||
MAX77621_T_JUNCTION_120 | MAX77621_FT_ENABLE | MAX77621_CKKADV_TRIP_75mV_PER_US_HIST_DIS |
|
||||
MAX77621_CKKADV_TRIP_150mV_PER_US | MAX77621_INDUCTOR_NOMINAL);
|
||||
|
||||
i2c_send_byte(I2C_5, MAX77621_GPU_I2C_ADDR, MAX77621_VOUT_REG, MAX77621_VOUT_0_95V); // Disable power.
|
||||
i2c_send_byte(I2C_5, MAX77621_GPU_I2C_ADDR, MAX77621_VOUT_DVC_REG, MAX77621_VOUT_ENABLE | MAX77621_VOUT_1_09V); // Enable DVS power.
|
||||
i2c_send_byte(I2C_5, MAX77621_GPU_I2C_ADDR, MAX77621_CONTROL1_REG, MAX77621_RAMP_50mV_PER_US);
|
||||
i2c_send_byte(I2C_5, MAX77621_GPU_I2C_ADDR, MAX77621_CONTROL2_REG,
|
||||
MAX77621_T_JUNCTION_120 | MAX77621_FT_ENABLE | MAX77621_CKKADV_TRIP_75mV_PER_US_HIST_DIS |
|
||||
MAX77621_CKKADV_TRIP_150mV_PER_US | MAX77621_INDUCTOR_NOMINAL);
|
||||
|
||||
// Disable low battery shutdown monitor.
|
||||
max77620_low_battery_monitor_config();
|
||||
}
|
||||
|
||||
void config_hw()
|
||||
{
|
||||
// Bootrom stuff we skipped by going through rcm.
|
||||
_config_se_brom();
|
||||
//FUSE(FUSE_PRIVATEKEYDISABLE) = 0x11;
|
||||
SYSREG(AHB_AHB_SPARE_REG) &= 0xFFFFFF9F;
|
||||
PMC(APBDEV_PMC_SCRATCH49) = ((PMC(APBDEV_PMC_SCRATCH49) >> 1) << 1) & 0xFFFFFFFD;
|
||||
SYSREG(AHB_AHB_SPARE_REG) &= 0xFFFFFF9F; // Unset APB2JTAG_OVERRIDE_EN and OBS_OVERRIDE_EN.
|
||||
PMC(APBDEV_PMC_SCRATCH49) = PMC(APBDEV_PMC_SCRATCH49) & 0xFFFFFFFC;
|
||||
|
||||
_mbist_workaround();
|
||||
clock_enable_se();
|
||||
|
@ -197,49 +288,30 @@ void config_hw()
|
|||
clock_enable_i2c(I2C_1);
|
||||
clock_enable_i2c(I2C_5);
|
||||
|
||||
clock_enable_unk2();
|
||||
clock_enable_tzram();
|
||||
|
||||
i2c_init(I2C_1);
|
||||
i2c_init(I2C_5);
|
||||
|
||||
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_CNFGBBC, MAX77620_CNFGBBC_RESISTOR_1K);
|
||||
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_ONOFFCNFG1,
|
||||
(1 << 6) | (3 << MAX77620_ONOFFCNFG1_MRT_SHIFT)); // PWR delay for forced shutdown off.
|
||||
|
||||
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_CFG0,
|
||||
(7 << MAX77620_FPS_TIME_PERIOD_SHIFT));
|
||||
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_CFG1,
|
||||
(7 << MAX77620_FPS_TIME_PERIOD_SHIFT) | (1 << MAX77620_FPS_EN_SRC_SHIFT));
|
||||
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_CFG2,
|
||||
(7 << MAX77620_FPS_TIME_PERIOD_SHIFT));
|
||||
max77620_regulator_config_fps(REGULATOR_LDO4);
|
||||
max77620_regulator_config_fps(REGULATOR_LDO8);
|
||||
max77620_regulator_config_fps(REGULATOR_SD0);
|
||||
max77620_regulator_config_fps(REGULATOR_SD1);
|
||||
max77620_regulator_config_fps(REGULATOR_SD3);
|
||||
|
||||
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_GPIO3,
|
||||
(4 << MAX77620_FPS_TIME_PERIOD_SHIFT) | (2 << MAX77620_FPS_PD_PERIOD_SHIFT)); // 3.x+
|
||||
|
||||
max77620_regulator_set_voltage(REGULATOR_SD0, 1125000);
|
||||
|
||||
// Fix GPU after warmboot for Linux.
|
||||
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_GPIO5, 2);
|
||||
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_GPIO6, 2);
|
||||
|
||||
// Disable low battery shutdown monitor.
|
||||
max77620_low_battery_monitor_config();
|
||||
_config_regulators();
|
||||
|
||||
_config_pmc_scratch(); // Missing from 4.x+
|
||||
|
||||
CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = (CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) & 0xFFFF8888) | 0x3333;
|
||||
CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = 0x20003333; // Set SCLK to PLLP_OUT (408MHz).
|
||||
|
||||
sdram_init();
|
||||
|
||||
bpmp_mmu_enable();
|
||||
mc_enable_ahb_redirect();
|
||||
}
|
||||
|
||||
void reconfig_hw_workaround(bool extra_reconfig, u32 magic)
|
||||
{
|
||||
// Flush and disable MMU.
|
||||
bpmp_mmu_disable();
|
||||
bpmp_clk_rate_set(BPMP_CLK_NORMAL);
|
||||
minerva_change_freq(FREQ_204);
|
||||
|
||||
// Re-enable clocks to Audio Processing Engine as a workaround to hanging.
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_V) |= (1 << 10); // Enable AHUB clock.
|
||||
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_Y) |= (1 << 6); // Enable APE clock.
|
||||
|
|
|
@ -46,7 +46,7 @@ static int _i2c_send_pkt(u32 idx, u32 x, u8 *buf, u32 size)
|
|||
vu32 *base = (vu32 *)i2c_addrs[idx];
|
||||
base[I2C_CMD_ADDR0] = x << 1; //Set x (send mode).
|
||||
base[I2C_CMD_DATA1] = tmp; //Set value.
|
||||
base[I2C_CNFG] = (2 * size - 2) | 0x2800; //Set size and send mode.
|
||||
base[I2C_CNFG] = ((size - 1) << 1) | 0x2800; //Set size and send mode.
|
||||
_i2c_wait(base); //Kick transaction.
|
||||
|
||||
base[I2C_CNFG] = (base[I2C_CNFG] & 0xFFFFFDFF) | 0x200;
|
||||
|
@ -66,7 +66,7 @@ static int _i2c_recv_pkt(u32 idx, u8 *buf, u32 size, u32 x)
|
|||
|
||||
vu32 *base = (vu32 *)i2c_addrs[idx];
|
||||
base[I2C_CMD_ADDR0] = (x << 1) | 1; // Set x (recv mode).
|
||||
base[I2C_CNFG] = (size - 1) << 1 | 0x2840; // Set size and recv mode.
|
||||
base[I2C_CNFG] = ((size - 1) << 1) | 0x2840; // Set size and recv mode.
|
||||
_i2c_wait(base); // Kick transaction.
|
||||
|
||||
base[I2C_CNFG] = (base[I2C_CNFG] & 0xFFFFFDFF) | 0x200;
|
||||
|
|
57
source/soc/kfuse.c
Normal file
57
source/soc/kfuse.c
Normal file
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "../soc/kfuse.h"
|
||||
#include "../soc/clock.h"
|
||||
#include "../soc/t210.h"
|
||||
#include "../utils/util.h"
|
||||
|
||||
int kfuse_read(u32 *buf)
|
||||
{
|
||||
int res = 0;
|
||||
|
||||
clock_enable_kfuse();
|
||||
|
||||
while (!(KFUSE(KFUSE_STATE) & KFUSE_STATE_DONE))
|
||||
;
|
||||
|
||||
if (!(KFUSE(KFUSE_STATE) & KFUSE_STATE_CRCPASS))
|
||||
goto out;
|
||||
|
||||
KFUSE(KFUSE_KEYADDR) = KFUSE_KEYADDR_AUTOINC;
|
||||
for (int i = 0; i < KFUSE_NUM_WORDS; i++)
|
||||
buf[i] = KFUSE(KFUSE_KEYS);
|
||||
|
||||
res = 1;
|
||||
|
||||
out:;
|
||||
clock_disable_kfuse();
|
||||
return res;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
42
source/soc/kfuse.h
Normal file
42
source/soc/kfuse.h
Normal file
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _KFUSE_H_
|
||||
#define _KFUSE_H_
|
||||
|
||||
#include "../utils/types.h"
|
||||
|
||||
#define KFUSE_STATE_SOFTRESET (1 << 31)
|
||||
#define KFUSE_STATE_STOP (1 << 25)
|
||||
#define KFUSE_STATE_RESTART (1 << 24)
|
||||
#define KFUSE_STATE_CRCPASS (1 << 17)
|
||||
#define KFUSE_STATE_DONE (1 << 16)
|
||||
#define KFUSE_STATE_ERRBLOCK_MASK 0x3F00
|
||||
#define KFUSE_STATE_ERRBLOCK_SHIFT 8
|
||||
#define KFUSE_STATE_CURBLOCK_MASK 0x3F
|
||||
|
||||
#define KFUSE_KEYADDR_AUTOINC (1<<16)
|
||||
|
||||
#define KFUSE_STATE 0x80
|
||||
#define KFUSE_KEYADDR 0x88
|
||||
#define KFUSE_KEYS 0x8C
|
||||
|
||||
#define KFUSE_NUM_WORDS 144
|
||||
|
||||
int kfuse_read(u32 *buf);
|
||||
int kfuse_wait_ready();
|
||||
|
||||
#endif
|
|
@ -38,18 +38,37 @@
|
|||
#define PINMUX_AUX_SDMMC3_DAT1 0x28
|
||||
#define PINMUX_AUX_SDMMC3_DAT2 0x2C
|
||||
#define PINMUX_AUX_SDMMC3_DAT3 0x30
|
||||
#define PINMUX_AUX_SATA_LED_ACTIVE 0x4C
|
||||
#define PINMUX_AUX_DMIC3_CLK 0xB4
|
||||
#define PINMUX_AUX_DMIC3_DAT 0xB8
|
||||
#define PINMUX_AUX_CAM_I2C_SCL 0xD4
|
||||
#define PINMUX_AUX_CAM_I2C_SDA 0xD8
|
||||
#define PINMUX_AUX_UART2_TX 0xF4
|
||||
#define PINMUX_AUX_UART3_TX 0x104
|
||||
#define PINMUX_AUX_DAP4_DIN 0x148
|
||||
#define PINMUX_AUX_DAP4_SCLK 0x150
|
||||
#define PINMUX_AUX_GPIO_X1_AUD 0x18C
|
||||
#define PINMUX_AUX_GPIO_X3_AUD 0x190
|
||||
#define PINMUX_AUX_SPDIF_IN 0x1A4
|
||||
#define PINMUX_AUX_USB_VBUS_EN0 0x1A8
|
||||
#define PINMUX_AUX_USB_VBUS_EN1 0x1AC
|
||||
#define PINMUX_AUX_WIFI_EN 0x1B4
|
||||
#define PINMUX_AUX_WIFI_RST 0x1B8
|
||||
#define PINMUX_AUX_AP_WAKE_NFC 0x1CC
|
||||
#define PINMUX_AUX_NFC_EN 0x1D0
|
||||
#define PINMUX_AUX_NFC_INT 0x1D4
|
||||
#define PINMUX_AUX_CAM1_PWDN 0x1EC
|
||||
#define PINMUX_AUX_CAM2_PWDN 0x1F0
|
||||
#define PINMUX_AUX_LCD_BL_PWM 0x1FC
|
||||
#define PINMUX_AUX_LCD_BL_EN 0x200
|
||||
#define PINMUX_AUX_LCD_RST 0x204
|
||||
#define PINMUX_AUX_LCD_GPIO2 0x20C
|
||||
#define PINMUX_AUX_TOUCH_INT 0x220
|
||||
#define PINMUX_AUX_MOTION_INT 0x224
|
||||
#define PINMUX_AUX_BUTTON_HOME 0x240
|
||||
#define PINMUX_AUX_GPIO_PE6 0x248
|
||||
#define PINMUX_AUX_GPIO_PH6 0x250
|
||||
#define PINMUX_AUX_GPIO_PK3 0x260
|
||||
#define PINMUX_AUX_GPIO_PZ1 0x280
|
||||
/*! 0:UART-A, 1:UART-B, 3:UART-C, 3:UART-D */
|
||||
#define PINMUX_AUX_UARTX_TX(x) (0xE4 + 0x10 * (x))
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#define APBDEV_PMC_PWRGATE_TOGGLE 0x30
|
||||
#define APBDEV_PMC_PWRGATE_STATUS 0x38
|
||||
#define APBDEV_PMC_NO_IOPOWER 0x44
|
||||
#define PMC_NO_IOPOWER_SDMMC1_IO_EN (1 << 12)
|
||||
#define APBDEV_PMC_SCRATCH0 0x50
|
||||
#define APBDEV_PMC_SCRATCH1 0x54
|
||||
#define APBDEV_PMC_SCRATCH20 0xA0
|
||||
|
@ -37,6 +38,7 @@
|
|||
#define APBDEV_PMC_SCRATCH33 0x120
|
||||
#define APBDEV_PMC_SCRATCH40 0x13C
|
||||
#define APBDEV_PMC_OSC_EDPD_OVER 0x1A4
|
||||
#define PMC_OSC_EDPD_OVER_OSC_CTRL_OVER 0x400000
|
||||
#define APBDEV_PMC_RST_STATUS 0x1B4
|
||||
#define APBDEV_PMC_IO_DPD_REQ 0x1B8
|
||||
#define APBDEV_PMC_IO_DPD2_REQ 0x1C0
|
||||
|
@ -51,9 +53,11 @@
|
|||
#define APBDEV_PMC_REG_SHORT 0x2CC
|
||||
#define APBDEV_PMC_SEC_DISABLE3 0x2D8
|
||||
#define APBDEV_PMC_SECURE_SCRATCH21 0x334
|
||||
#define PMC_FUSE_PRIVATEKEYDISABLE_TZ_STICKY_BIT 0x10
|
||||
#define APBDEV_PMC_SECURE_SCRATCH32 0x360
|
||||
#define APBDEV_PMC_SECURE_SCRATCH49 0x3A4
|
||||
#define APBDEV_PMC_CNTRL2 0x440
|
||||
#define PMC_CNTRL2_HOLD_CKE_LOW_EN 0x1000
|
||||
#define APBDEV_PMC_IO_DPD3_REQ 0x45C
|
||||
#define APBDEV_PMC_IO_DPD4_REQ 0x464
|
||||
#define APBDEV_PMC_UTMIP_PAD_CFG1 0x4C4
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "../utils/types.h"
|
||||
|
||||
#define BOOTROM_BASE 0x100000
|
||||
#define IRAM_BASE 0x40000000
|
||||
#define HOST1X_BASE 0x50000000
|
||||
#define BPMP_CACHE_BASE 0x50040000
|
||||
#define DISPLAY_A_BASE 0x54200000
|
||||
|
@ -100,15 +101,22 @@
|
|||
#define CL_DVFS(off) _REG(CL_DVFS_BASE, off)
|
||||
#define TEST_REG(off) _REG(0x0, off)
|
||||
|
||||
/* HOST1X registers. */
|
||||
#define HOST1X_CH0_SYNC_BASE 0x2100
|
||||
#define HOST1X_CH0_SYNC_SYNCPT_9 (HOST1X_CH0_SYNC_BASE + 0xFA4)
|
||||
#define HOST1X_CH0_SYNC_SYNCPT_160 (HOST1X_CH0_SYNC_BASE + 0x1200)
|
||||
|
||||
/*! EVP registers. */
|
||||
#define EVP_CPU_RESET_VECTOR 0x100
|
||||
|
||||
/*! Misc registers. */
|
||||
#define APB_MISC_PP_STRAPPING_OPT_A 0x08
|
||||
#define APB_MISC_PP_PINMUX_GLOBAL 0x40
|
||||
#define APB_MISC_GP_HIDREV 0x804
|
||||
#define APB_MISC_GP_LCD_BL_PWM_CFGPADCTRL 0xA34
|
||||
#define APB_MISC_GP_SDMMC1_PAD_CFGPADCTRL 0xA98
|
||||
#define APB_MISC_GP_EMMC4_PAD_CFGPADCTRL 0xAB4
|
||||
#define APB_MISC_GP_EMMC4_PAD_PUPD_CFGPADCTRL 0xABC
|
||||
#define APB_MISC_GP_WIFI_EN_CFGPADCTRL 0xB64
|
||||
#define APB_MISC_GP_WIFI_RST_CFGPADCTRL 0xB68
|
||||
|
||||
|
@ -118,7 +126,10 @@
|
|||
|
||||
/*! Secure boot registers. */
|
||||
#define SB_CSR 0x0
|
||||
#define SB_CSR_NS_RST_VEC_WR_DIS (1 << 1)
|
||||
#define SB_CSR_PIROM_DISABLE (1 << 4)
|
||||
#define SB_AA64_RESET_LOW 0x30
|
||||
#define SB_AA64_RST_AARCH64_MODE_EN (1 << 0)
|
||||
#define SB_AA64_RESET_HIGH 0x34
|
||||
|
||||
/*! SOR registers. */
|
||||
|
@ -182,10 +193,31 @@
|
|||
/*! PWM registers. */
|
||||
#define PWM_CONTROLLER_PWM_CSR_0 0x00
|
||||
#define PWM_CONTROLLER_PWM_CSR_1 0x10
|
||||
#define PWM_CSR_EN (1 << 31)
|
||||
|
||||
/*! Special registers. */
|
||||
#define EMC_SCRATCH0 0x324
|
||||
#define EMC_HEKA_UPD (1 << 30)
|
||||
#define EMC_SEPT_RUN (1 << 31)
|
||||
|
||||
/*! Flow controller registers. */
|
||||
#define FLOW_CTLR_HALT_COP_EVENTS 0x4
|
||||
#define HALT_COP_SEC (1 << 23)
|
||||
#define HALT_COP_MSEC (1 << 24)
|
||||
#define HALT_COP_USEC (1 << 25)
|
||||
#define HALT_COP_JTAG (1 << 28)
|
||||
#define HALT_COP_WAIT_EVENT (1 << 30)
|
||||
#define HALT_COP_WAIT_IRQ (1 << 31)
|
||||
#define HALT_COP_MAX_CNT 0xFF
|
||||
#define FLOW_CTLR_HALT_CPU0_EVENTS 0x0
|
||||
#define FLOW_CTLR_HALT_CPU1_EVENTS 0x14
|
||||
#define FLOW_CTLR_HALT_CPU2_EVENTS 0x1C
|
||||
#define FLOW_CTLR_HALT_CPU3_EVENTS 0x24
|
||||
#define FLOW_CTLR_CPU0_CSR 0x8
|
||||
#define FLOW_CTLR_CPU1_CSR 0x18
|
||||
#define FLOW_CTLR_CPU2_CSR 0x20
|
||||
#define FLOW_CTLR_CPU3_CSR 0x28
|
||||
#define FLOW_CTLR_RAM_REPAIR 0x40
|
||||
#define FLOW_CTLR_BPMP_CLUSTER_CONTROL 0x98
|
||||
|
||||
#endif
|
||||
|
|
266
source/storage/emummc.c
Normal file
266
source/storage/emummc.c
Normal file
|
@ -0,0 +1,266 @@
|
|||
/*
|
||||
* Copyright (C) 2019 CTCaer
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "emummc.h"
|
||||
#include "sdmmc.h"
|
||||
#include "../config/config.h"
|
||||
#include "../config/ini.h"
|
||||
#include "../gfx/gfx.h"
|
||||
#include "../libs/fatfs/ff.h"
|
||||
#include "../mem/heap.h"
|
||||
#include "../utils/list.h"
|
||||
#include "../utils/types.h"
|
||||
|
||||
extern sdmmc_t sd_sdmmc;
|
||||
extern sdmmc_storage_t sd_storage;
|
||||
extern FATFS sd_fs;
|
||||
|
||||
extern hekate_config h_cfg;
|
||||
|
||||
extern bool sd_mount();
|
||||
extern void sd_unmount();
|
||||
|
||||
bool emummc_load_cfg()
|
||||
{
|
||||
sd_mount();
|
||||
emu_cfg.enabled = 0;
|
||||
emu_cfg.path = NULL;
|
||||
emu_cfg.nintendo_path = NULL;
|
||||
emu_cfg.sector = 0;
|
||||
emu_cfg.id = 0;
|
||||
emu_cfg.file_based_part_size = 0;
|
||||
emu_cfg.active_part = 0;
|
||||
emu_cfg.fs_ver = 0;
|
||||
emu_cfg.emummc_file_based_path = (char *)malloc(0x80);
|
||||
|
||||
LIST_INIT(ini_sections);
|
||||
if (ini_parse(&ini_sections, "emuMMC/emummc.ini", false))
|
||||
{
|
||||
LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_sections, link)
|
||||
{
|
||||
if (ini_sec->type == INI_CHOICE)
|
||||
{
|
||||
if (strcmp(ini_sec->name, "emummc"))
|
||||
continue;
|
||||
|
||||
LIST_FOREACH_ENTRY(ini_kv_t, kv, &ini_sec->kvs, link)
|
||||
{
|
||||
if (!strcmp("enabled", kv->key))
|
||||
emu_cfg.enabled = atoi(kv->val);
|
||||
else if (!strcmp("sector", kv->key))
|
||||
emu_cfg.sector = strtol(kv->val, NULL, 16);
|
||||
else if (!strcmp("id", kv->key))
|
||||
emu_cfg.id = strtol(kv->val, NULL, 16);
|
||||
else if (!strcmp("path", kv->key))
|
||||
emu_cfg.path = kv->val;
|
||||
else if (!strcmp("nintendo_path", kv->key))
|
||||
emu_cfg.nintendo_path = kv->val;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int emummc_raw_get_part_off(int part_idx)
|
||||
{
|
||||
switch (part_idx)
|
||||
{
|
||||
case 0:
|
||||
return 2;
|
||||
case 1:
|
||||
return 0;
|
||||
case 2:
|
||||
return 1;
|
||||
}
|
||||
return 2;
|
||||
}
|
||||
|
||||
|
||||
int emummc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc)
|
||||
{
|
||||
FILINFO fno;
|
||||
if (!sdmmc_storage_init_mmc(storage, sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4))
|
||||
{
|
||||
EPRINTF("Failed to init eMMC.");
|
||||
|
||||
goto out;
|
||||
}
|
||||
if (h_cfg.emummc_force_disable)
|
||||
return 1;
|
||||
|
||||
emu_cfg.active_part = 0;
|
||||
if (!sd_mount())
|
||||
goto out;
|
||||
|
||||
if (emu_cfg.enabled && !emu_cfg.sector)
|
||||
{
|
||||
strcpy(emu_cfg.emummc_file_based_path, emu_cfg.path);
|
||||
strcat(emu_cfg.emummc_file_based_path, "/eMMC");
|
||||
|
||||
if (f_stat(emu_cfg.emummc_file_based_path, &fno))
|
||||
{
|
||||
EPRINTF("Failed to open eMMC folder.");
|
||||
goto out;
|
||||
}
|
||||
f_chmod(emu_cfg.emummc_file_based_path, AM_ARC, AM_ARC);
|
||||
|
||||
strcat(emu_cfg.emummc_file_based_path, "/00");
|
||||
if (f_stat(emu_cfg.emummc_file_based_path, &fno))
|
||||
{
|
||||
EPRINTF("Failed to open emuMMC rawnand.");
|
||||
goto out;
|
||||
}
|
||||
emu_cfg.file_based_part_size = fno.fsize >> 9;
|
||||
}
|
||||
return 1;
|
||||
|
||||
out:
|
||||
return 0;
|
||||
}
|
||||
|
||||
int emummc_storage_end(sdmmc_storage_t *storage)
|
||||
{
|
||||
sd_unmount();
|
||||
sdmmc_storage_end(storage);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int emummc_storage_read(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, void *buf)
|
||||
{
|
||||
FIL fp;
|
||||
if (!emu_cfg.enabled || h_cfg.emummc_force_disable)
|
||||
return sdmmc_storage_read(storage, sector, num_sectors, buf);
|
||||
else if (emu_cfg.sector)
|
||||
{
|
||||
sector += emu_cfg.sector;
|
||||
sector += emummc_raw_get_part_off(emu_cfg.active_part) * 0x2000;
|
||||
return sdmmc_storage_read(&sd_storage, sector, num_sectors, buf);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!emu_cfg.active_part)
|
||||
{
|
||||
u32 file_part = sector / emu_cfg.file_based_part_size;
|
||||
sector = sector % emu_cfg.file_based_part_size;
|
||||
if (file_part >= 10)
|
||||
itoa(file_part, emu_cfg.emummc_file_based_path + strlen(emu_cfg.emummc_file_based_path) - 2, 10);
|
||||
else
|
||||
{
|
||||
emu_cfg.emummc_file_based_path[strlen(emu_cfg.emummc_file_based_path) - 2] = '0';
|
||||
itoa(file_part, emu_cfg.emummc_file_based_path + strlen(emu_cfg.emummc_file_based_path) - 1, 10);
|
||||
}
|
||||
}
|
||||
if (f_open(&fp, emu_cfg.emummc_file_based_path, FA_READ))
|
||||
{
|
||||
EPRINTF("Failed to open emuMMC image.");
|
||||
return 0;
|
||||
}
|
||||
f_lseek(&fp, (u64)sector << 9);
|
||||
if (f_read(&fp, buf, (u64)num_sectors << 9, NULL))
|
||||
{
|
||||
EPRINTF("Failed to read emuMMC image.");
|
||||
f_close(&fp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
f_close(&fp);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int emummc_storage_write(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, void *buf)
|
||||
{
|
||||
FIL fp;
|
||||
if (!emu_cfg.enabled || h_cfg.emummc_force_disable)
|
||||
return sdmmc_storage_write(storage, sector, num_sectors, buf);
|
||||
else if (emu_cfg.sector)
|
||||
{
|
||||
sector += emu_cfg.sector;
|
||||
sector += emummc_raw_get_part_off(emu_cfg.active_part) * 0x2000;
|
||||
return sdmmc_storage_write(&sd_storage, sector, num_sectors, buf);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!emu_cfg.active_part)
|
||||
{
|
||||
u32 file_part = sector / emu_cfg.file_based_part_size;
|
||||
sector = sector % emu_cfg.file_based_part_size;
|
||||
if (file_part >= 10)
|
||||
itoa(file_part, emu_cfg.emummc_file_based_path + strlen(emu_cfg.emummc_file_based_path) - 2, 10);
|
||||
else
|
||||
{
|
||||
emu_cfg.emummc_file_based_path[strlen(emu_cfg.emummc_file_based_path) - 2] = '0';
|
||||
itoa(file_part, emu_cfg.emummc_file_based_path + strlen(emu_cfg.emummc_file_based_path) - 1, 10);
|
||||
}
|
||||
}
|
||||
if (f_open(&fp, emu_cfg.emummc_file_based_path, FA_WRITE))
|
||||
{
|
||||
gfx_printf("e5\n");
|
||||
return 0;
|
||||
}
|
||||
f_lseek(&fp, (u64)sector << 9);
|
||||
if (f_write(&fp, buf, (u64)num_sectors << 9, NULL))
|
||||
{
|
||||
gfx_printf("e6\n");
|
||||
f_close(&fp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
f_close(&fp);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
int emummc_storage_set_mmc_partition(sdmmc_storage_t *storage, u32 partition)
|
||||
{
|
||||
emu_cfg.active_part = partition;
|
||||
|
||||
if (!emu_cfg.enabled || h_cfg.emummc_force_disable)
|
||||
sdmmc_storage_set_mmc_partition(storage, partition);
|
||||
else if (emu_cfg.sector)
|
||||
return 1;
|
||||
else
|
||||
{
|
||||
strcpy(emu_cfg.emummc_file_based_path, emu_cfg.path);
|
||||
strcat(emu_cfg.emummc_file_based_path, "/eMMC");
|
||||
|
||||
switch (partition)
|
||||
{
|
||||
case 0:
|
||||
strcat(emu_cfg.emummc_file_based_path, "/00");
|
||||
break;
|
||||
case 1:
|
||||
strcat(emu_cfg.emummc_file_based_path, "/BOOT0");
|
||||
break;
|
||||
case 2:
|
||||
strcat(emu_cfg.emummc_file_based_path, "/BOOT1");
|
||||
break;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
59
source/storage/emummc.h
Normal file
59
source/storage/emummc.h
Normal file
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* Copyright (C) 2019 CTCaer
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef EMUMMC_H
|
||||
#define EMUMMC_H
|
||||
|
||||
#include "sdmmc.h"
|
||||
#include "../utils/types.h"
|
||||
|
||||
typedef enum
|
||||
{
|
||||
EMUMMC_TYPE_NONE = 0,
|
||||
EMUMMC_TYPE_PARTITION = 1,
|
||||
EMUMMC_TYPE_FILES = 2,
|
||||
} emummc_type_t;
|
||||
|
||||
typedef enum {
|
||||
EMUMMC_MMC_NAND = 0,
|
||||
EMUMMC_MMC_SD = 1,
|
||||
EMUMMC_MMC_GC = 2,
|
||||
} emummc_mmc_t;
|
||||
|
||||
typedef struct _emummc_cfg_t
|
||||
{
|
||||
int enabled;
|
||||
u64 sector;
|
||||
u16 id;
|
||||
char *path;
|
||||
char *nintendo_path;
|
||||
// Internal.
|
||||
char *emummc_file_based_path;
|
||||
u32 file_based_part_size;
|
||||
u32 active_part;
|
||||
int fs_ver;
|
||||
} emummc_cfg_t;
|
||||
|
||||
emummc_cfg_t emu_cfg;
|
||||
|
||||
bool emummc_load_cfg();
|
||||
int emummc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc);
|
||||
int emummc_storage_end(sdmmc_storage_t *storage);
|
||||
int emummc_storage_read(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, void *buf);
|
||||
int emummc_storage_write(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, void *buf);
|
||||
int emummc_storage_set_mmc_partition(sdmmc_storage_t *storage, u32 partition);
|
||||
|
||||
#endif
|
|
@ -17,6 +17,7 @@
|
|||
#include <string.h>
|
||||
|
||||
#include "nx_emmc.h"
|
||||
#include "emummc.h"
|
||||
#include "../mem/heap.h"
|
||||
#include "../utils/list.h"
|
||||
|
||||
|
@ -24,7 +25,7 @@ void nx_emmc_gpt_parse(link_t *gpt, sdmmc_storage_t *storage)
|
|||
{
|
||||
u8 *buf = (u8 *)malloc(NX_GPT_NUM_BLOCKS * NX_EMMC_BLOCKSIZE);
|
||||
|
||||
sdmmc_storage_read(storage, NX_GPT_FIRST_LBA, NX_GPT_NUM_BLOCKS, buf);
|
||||
emummc_storage_read(storage, NX_GPT_FIRST_LBA, NX_GPT_NUM_BLOCKS, buf);
|
||||
|
||||
gpt_header_t *hdr = (gpt_header_t *)buf;
|
||||
for (u32 i = 0; i < hdr->num_part_ents; i++)
|
||||
|
@ -36,8 +37,8 @@ void nx_emmc_gpt_parse(link_t *gpt, sdmmc_storage_t *storage)
|
|||
part->attrs = ent->attrs;
|
||||
|
||||
//HACK
|
||||
for (u32 i = 0; i < 36; i++)
|
||||
part->name[i] = ent->name[i];
|
||||
for (u32 j = 0; j < 36; j++)
|
||||
part->name[j] = ent->name[j];
|
||||
part->name[36] = 0;
|
||||
|
||||
list_append(gpt, &part->link);
|
||||
|
@ -65,7 +66,7 @@ int nx_emmc_part_read(sdmmc_storage_t *storage, emmc_part_t *part, u32 sector_of
|
|||
// The last LBA is inclusive.
|
||||
if (part->lba_start + sector_off > part->lba_end)
|
||||
return 0;
|
||||
return sdmmc_storage_read(storage, part->lba_start + sector_off, num_sectors, buf);
|
||||
return emummc_storage_read(storage, part->lba_start + sector_off, num_sectors, buf);
|
||||
}
|
||||
|
||||
int nx_emmc_part_write(sdmmc_storage_t *storage, emmc_part_t *part, u32 sector_off, u32 num_sectors, void *buf)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (C) 2018 CTCaer
|
||||
* Copyright (C) 2018-2019 CTCaer
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
|
@ -26,8 +26,6 @@
|
|||
//#define DPRINTF(...) gfx_printf(__VA_ARGS__)
|
||||
#define DPRINTF(...)
|
||||
|
||||
extern boot_cfg_t b_cfg;
|
||||
|
||||
static inline u32 unstuff_bits(u32 *resp, u32 start, u32 size)
|
||||
{
|
||||
const u32 mask = (size < 32 ? 1 << size : 0) - 1;
|
||||
|
@ -71,6 +69,7 @@ static int _sdmmc_storage_execute_cmd_type1_ex(sdmmc_storage_t *storage, u32 *re
|
|||
if (_sdmmc_storage_check_result(*resp))
|
||||
if (expected_state == 0x10 || R1_CURRENT_STATE(*resp) == expected_state)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -84,6 +83,7 @@ static int _sdmmc_storage_go_idle_state(sdmmc_storage_t *storage)
|
|||
{
|
||||
sdmmc_cmd_t cmd;
|
||||
sdmmc_init_cmd(&cmd, MMC_GO_IDLE_STATE, 0, SDMMC_RSP_TYPE_0, 0);
|
||||
|
||||
return sdmmc_execute_cmd(storage->sdmmc, &cmd, 0, 0);
|
||||
}
|
||||
|
||||
|
@ -93,7 +93,9 @@ static int _sdmmc_storage_get_cid(sdmmc_storage_t *storage, void *buf)
|
|||
sdmmc_init_cmd(&cmd, MMC_ALL_SEND_CID, 0, SDMMC_RSP_TYPE_2, 0);
|
||||
if (!sdmmc_execute_cmd(storage->sdmmc, &cmd, 0, 0))
|
||||
return 0;
|
||||
|
||||
sdmmc_get_rsp(storage->sdmmc, buf, 0x10, SDMMC_RSP_TYPE_2);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -108,7 +110,9 @@ static int _sdmmc_storage_get_csd(sdmmc_storage_t *storage, void *buf)
|
|||
sdmmc_init_cmd(&cmdbuf, MMC_SEND_CSD, storage->rca << 16, SDMMC_RSP_TYPE_2, 0);
|
||||
if (!sdmmc_execute_cmd(storage->sdmmc, &cmdbuf, 0, 0))
|
||||
return 0;
|
||||
|
||||
sdmmc_get_rsp(storage->sdmmc, buf, 0x10, SDMMC_RSP_TYPE_2);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -146,8 +150,10 @@ static int _sdmmc_storage_readwrite_ex(sdmmc_storage_t *storage, u32 *blkcnt_out
|
|||
u32 tmp = 0;
|
||||
sdmmc_stop_transmission(storage->sdmmc, &tmp);
|
||||
_sdmmc_storage_get_status(storage, &tmp, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -155,7 +161,9 @@ int sdmmc_storage_end(sdmmc_storage_t *storage)
|
|||
{
|
||||
if (!_sdmmc_storage_go_idle_state(storage))
|
||||
return 0;
|
||||
|
||||
sdmmc_end(storage->sdmmc);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -177,6 +185,7 @@ static int _sdmmc_storage_readwrite(sdmmc_storage_t *storage, u32 sector, u32 nu
|
|||
|
||||
msleep(100);
|
||||
} while (retries);
|
||||
|
||||
return 0;
|
||||
|
||||
out:;
|
||||
|
@ -185,6 +194,7 @@ out:;
|
|||
num_sectors -= blkcnt;
|
||||
bbuf += 512 * blkcnt;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -235,14 +245,17 @@ static int _mmc_storage_get_op_cond(sdmmc_storage_t *storage, u32 power)
|
|||
u32 cond = 0;
|
||||
if (!_mmc_storage_get_op_cond_inner(storage, &cond, power))
|
||||
break;
|
||||
|
||||
if (cond & MMC_CARD_BUSY)
|
||||
{
|
||||
if (cond & 0x40000000)
|
||||
storage->has_sector_access = 1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
if (get_tmr_ms() > timeout)
|
||||
break;
|
||||
|
||||
usleep(1000);
|
||||
}
|
||||
|
||||
|
@ -372,6 +385,7 @@ static int _mmc_storage_switch_buswidth(sdmmc_storage_t *storage, u32 bus_width)
|
|||
if (_sdmmc_storage_check_status(storage))
|
||||
{
|
||||
sdmmc_set_bus_width(storage->sdmmc, bus_width);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -382,14 +396,19 @@ static int _mmc_storage_enable_HS(sdmmc_storage_t *storage, int check)
|
|||
{
|
||||
if (!_mmc_storage_switch(storage, SDMMC_SWITCH(MMC_SWITCH_MODE_WRITE_BYTE, EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS)))
|
||||
return 0;
|
||||
|
||||
if (check && !_sdmmc_storage_check_status(storage))
|
||||
return 0;
|
||||
|
||||
if (!sdmmc_setup_clock(storage->sdmmc, 2))
|
||||
return 0;
|
||||
|
||||
DPRINTF("[MMC] switched to HS\n");
|
||||
storage->csd.busspeed = 52;
|
||||
|
||||
if (check || _sdmmc_storage_check_status(storage))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -397,12 +416,16 @@ static int _mmc_storage_enable_HS200(sdmmc_storage_t *storage)
|
|||
{
|
||||
if (!_mmc_storage_switch(storage, SDMMC_SWITCH(MMC_SWITCH_MODE_WRITE_BYTE, EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS200)))
|
||||
return 0;
|
||||
|
||||
if (!sdmmc_setup_clock(storage->sdmmc, 3))
|
||||
return 0;
|
||||
|
||||
if (!sdmmc_config_tuning(storage->sdmmc, 3, MMC_SEND_TUNING_BLOCK_HS200))
|
||||
return 0;
|
||||
|
||||
DPRINTF("[MMC] switched to HS200\n");
|
||||
storage->csd.busspeed = 200;
|
||||
|
||||
return _sdmmc_storage_check_status(storage);
|
||||
}
|
||||
|
||||
|
@ -410,17 +433,24 @@ static int _mmc_storage_enable_HS400(sdmmc_storage_t *storage)
|
|||
{
|
||||
if (!_mmc_storage_enable_HS200(storage))
|
||||
return 0;
|
||||
|
||||
sdmmc_get_venclkctl(storage->sdmmc);
|
||||
|
||||
if (!_mmc_storage_enable_HS(storage, 0))
|
||||
return 0;
|
||||
|
||||
if (!_mmc_storage_switch(storage, SDMMC_SWITCH(MMC_SWITCH_MODE_WRITE_BYTE, EXT_CSD_BUS_WIDTH, EXT_CSD_DDR_BUS_WIDTH_8)))
|
||||
return 0;
|
||||
|
||||
if (!_mmc_storage_switch(storage, SDMMC_SWITCH(MMC_SWITCH_MODE_WRITE_BYTE, EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS400)))
|
||||
return 0;
|
||||
|
||||
if (!sdmmc_setup_clock(storage->sdmmc, 4))
|
||||
return 0;
|
||||
|
||||
DPRINTF("[MMC] switched to HS400\n");
|
||||
storage->csd.busspeed = 400;
|
||||
|
||||
return _sdmmc_storage_check_status(storage);
|
||||
}
|
||||
|
||||
|
@ -432,8 +462,7 @@ static int _mmc_storage_enable_highspeed(sdmmc_storage_t *storage, u32 card_type
|
|||
goto out;
|
||||
|
||||
if (sdmmc_get_bus_width(storage->sdmmc) == SDMMC_BUS_WIDTH_8 &&
|
||||
card_type & EXT_CSD_CARD_TYPE_HS400_1_8V &&
|
||||
type == 4)
|
||||
card_type & EXT_CSD_CARD_TYPE_HS400_1_8V && type == 4)
|
||||
return _mmc_storage_enable_HS400(storage);
|
||||
|
||||
if (sdmmc_get_bus_width(storage->sdmmc) == SDMMC_BUS_WIDTH_8 ||
|
||||
|
@ -445,6 +474,7 @@ static int _mmc_storage_enable_highspeed(sdmmc_storage_t *storage, u32 card_type
|
|||
out:;
|
||||
if (card_type & EXT_CSD_CARD_TYPE_HS_52)
|
||||
return _mmc_storage_enable_HS(storage, 1);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -452,6 +482,7 @@ static int _mmc_storage_enable_bkops(sdmmc_storage_t *storage)
|
|||
{
|
||||
if (!_mmc_storage_switch(storage, SDMMC_SWITCH(MMC_SWITCH_MODE_SET_BITS, EXT_CSD_BKOPS_EN, EXT_CSD_BKOPS_LEVEL_2)))
|
||||
return 0;
|
||||
|
||||
return _sdmmc_storage_check_status(storage);
|
||||
}
|
||||
|
||||
|
@ -549,8 +580,10 @@ int sdmmc_storage_set_mmc_partition(sdmmc_storage_t *storage, u32 partition)
|
|||
{
|
||||
if (!_mmc_storage_switch(storage, SDMMC_SWITCH(MMC_SWITCH_MODE_WRITE_BYTE, EXT_CSD_PART_CONFIG, partition)))
|
||||
return 0;
|
||||
|
||||
if (!_sdmmc_storage_check_status(storage))
|
||||
return 0;
|
||||
|
||||
storage->partition = partition;
|
||||
return 1;
|
||||
}
|
||||
|
@ -564,6 +597,7 @@ static int _sd_storage_execute_app_cmd(sdmmc_storage_t *storage, u32 expected_st
|
|||
u32 tmp;
|
||||
if (!_sdmmc_storage_execute_cmd_type1_ex(storage, &tmp, MMC_APP_CMD, storage->rca << 16, 0, expected_state, mask))
|
||||
return 0;
|
||||
|
||||
return sdmmc_execute_cmd(storage->sdmmc, cmd, req, blkcnt_out);
|
||||
}
|
||||
|
||||
|
@ -571,6 +605,7 @@ static int _sd_storage_execute_app_cmd_type1(sdmmc_storage_t *storage, u32 *resp
|
|||
{
|
||||
if (!_sdmmc_storage_execute_cmd_type1(storage, MMC_APP_CMD, storage->rca << 16, 0, R1_STATE_TRAN))
|
||||
return 0;
|
||||
|
||||
return _sdmmc_storage_execute_cmd_type1_ex(storage, resp, cmd, arg, check_busy, expected_state, 0);
|
||||
}
|
||||
|
||||
|
@ -602,6 +637,7 @@ static int _sd_storage_get_op_cond_once(sdmmc_storage_t *storage, u32 *cond, int
|
|||
sdmmc_init_cmd(&cmdbuf, SD_APP_OP_COND, arg, SDMMC_RSP_TYPE_3, 0);
|
||||
if (!_sd_storage_execute_app_cmd(storage, 0x10, is_version_1 ? 0x400000 : 0, &cmdbuf, 0, 0))
|
||||
return 0;
|
||||
|
||||
return sdmmc_get_rsp(storage->sdmmc, cond, 4, SDMMC_RSP_TYPE_3);
|
||||
}
|
||||
|
||||
|
@ -802,10 +838,12 @@ int _sd_storage_enable_highspeed(sdmmc_storage_t *storage, u32 hs_type, u8 *buf)
|
|||
{
|
||||
if (!_sd_storage_switch(storage, buf, SD_SWITCH_CHECK, 0, hs_type))
|
||||
return 0;
|
||||
DPRINTF("[SD] SD supports switch to (U)HS check\n");
|
||||
|
||||
u32 type_out = buf[16] & 0xF;
|
||||
if (type_out != hs_type)
|
||||
return 0;
|
||||
DPRINTF("[SD] SD supports selected (U)HS mode\n");
|
||||
|
||||
if ((((u16)buf[0] << 8) | buf[1]) < 0x320)
|
||||
{
|
||||
|
@ -834,7 +872,7 @@ int _sd_storage_enable_highspeed_low_volt(sdmmc_storage_t *storage, u32 type, u8
|
|||
u32 hs_type = 0;
|
||||
switch (type)
|
||||
{
|
||||
case 11:
|
||||
case 11: // SDR104.
|
||||
// Fall through if not supported.
|
||||
if (buf[13] & SD_MODE_UHS_SDR104)
|
||||
{
|
||||
|
@ -844,7 +882,7 @@ int _sd_storage_enable_highspeed_low_volt(sdmmc_storage_t *storage, u32 type, u8
|
|||
storage->csd.busspeed = 104;
|
||||
break;
|
||||
}
|
||||
case 10:
|
||||
case 10: // SDR50.
|
||||
if (buf[13] & SD_MODE_UHS_SDR50)
|
||||
{
|
||||
type = 10;
|
||||
|
@ -853,7 +891,7 @@ int _sd_storage_enable_highspeed_low_volt(sdmmc_storage_t *storage, u32 type, u8
|
|||
storage->csd.busspeed = 50;
|
||||
break;
|
||||
}
|
||||
case 8:
|
||||
case 8: // SDR12.
|
||||
if (!(buf[13] & SD_MODE_UHS_SDR12))
|
||||
return 0;
|
||||
type = 8;
|
||||
|
@ -868,10 +906,13 @@ int _sd_storage_enable_highspeed_low_volt(sdmmc_storage_t *storage, u32 type, u8
|
|||
|
||||
if (!_sd_storage_enable_highspeed(storage, hs_type, buf))
|
||||
return 0;
|
||||
DPRINTF("[SD] SD card accepted UHS\n");
|
||||
if (!sdmmc_setup_clock(storage->sdmmc, type))
|
||||
return 0;
|
||||
DPRINTF("[SD] setup clock\n");
|
||||
if (!sdmmc_config_tuning(storage->sdmmc, type, MMC_SEND_TUNING_BLOCK))
|
||||
return 0;
|
||||
DPRINTF("[SD] config tuning\n");
|
||||
return _sdmmc_storage_check_status(storage);
|
||||
}
|
||||
|
||||
|
@ -885,8 +926,10 @@ int _sd_storage_enable_highspeed_high_volt(sdmmc_storage_t *storage, u8 *buf)
|
|||
|
||||
if (!_sd_storage_enable_highspeed(storage, 1, buf))
|
||||
return 0;
|
||||
|
||||
if (!_sdmmc_storage_check_status(storage))
|
||||
return 0;
|
||||
|
||||
return sdmmc_setup_clock(storage->sdmmc, 7);
|
||||
}
|
||||
|
||||
|
@ -1011,14 +1054,19 @@ static void _sd_storage_parse_csd(sdmmc_storage_t *storage)
|
|||
}
|
||||
}
|
||||
|
||||
void sdmmc_storage_init_wait_sd()
|
||||
{
|
||||
u32 sd_poweroff_time = (u32)get_tmr_ms() - sd_power_cycle_time_start;
|
||||
if (sd_poweroff_time < 100)
|
||||
msleep(100 - sd_poweroff_time);
|
||||
}
|
||||
|
||||
int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32 bus_width, u32 type)
|
||||
{
|
||||
int is_version_1 = 0;
|
||||
|
||||
// Some cards (Sandisk U1), do not like a fast power cycle. Wait min 100ms.
|
||||
u32 sd_poweroff_time = (u32)get_tmr_ms() - b_cfg.sd_timeoff;
|
||||
if (id == SDMMC_1 && (sd_poweroff_time < 100))
|
||||
msleep(100 - sd_poweroff_time);
|
||||
sdmmc_storage_init_wait_sd();
|
||||
|
||||
memset(storage, 0, sizeof(sdmmc_storage_t));
|
||||
storage->sdmmc = sdmmc;
|
||||
|
@ -1066,7 +1114,7 @@ int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32
|
|||
storage->sec_cnt = storage->csd.c_size << 10;
|
||||
break;
|
||||
default:
|
||||
DPRINTF("[SD] Unknown CSD structure %d\n", storage->csd.structure);
|
||||
DPRINTF("[SD] unknown CSD structure %d\n", storage->csd.structure);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1123,7 +1171,7 @@ int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32
|
|||
free(buf);
|
||||
return 0;
|
||||
}
|
||||
DPRINTF("[SD] enabled highspeed (low voltage)\n");
|
||||
DPRINTF("[SD] enabled UHS\n");
|
||||
}
|
||||
else if (type != 6 && (storage->scr.sda_vsn & 0xF) != 0)
|
||||
{
|
||||
|
@ -1132,7 +1180,7 @@ int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32
|
|||
free(buf);
|
||||
return 0;
|
||||
}
|
||||
DPRINTF("[SD] enabled highspeed (high voltage)\n");
|
||||
DPRINTF("[SD] enabled HS\n");
|
||||
storage->csd.busspeed = 25;
|
||||
}
|
||||
|
||||
|
|
|
@ -21,6 +21,8 @@
|
|||
#include "../utils/types.h"
|
||||
#include "sdmmc_driver.h"
|
||||
|
||||
u32 sd_power_cycle_time_start;
|
||||
|
||||
typedef struct _mmc_cid
|
||||
{
|
||||
u32 manfid;
|
||||
|
@ -107,6 +109,7 @@ int sdmmc_storage_read(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, vo
|
|||
int sdmmc_storage_write(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, void *buf);
|
||||
int sdmmc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32 bus_width, u32 type);
|
||||
int sdmmc_storage_set_mmc_partition(sdmmc_storage_t *storage, u32 partition);
|
||||
void sdmmc_storage_init_wait_sd();
|
||||
int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32 bus_width, u32 type);
|
||||
int sdmmc_storage_init_gc(sdmmc_storage_t *storage, sdmmc_t *sdmmc);
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include "sdmmc.h"
|
||||
#include "../gfx/gfx.h"
|
||||
#include "../power/max7762x.h"
|
||||
#include "../soc/bpmp.h"
|
||||
#include "../soc/clock.h"
|
||||
#include "../soc/gpio.h"
|
||||
#include "../soc/pinmux.h"
|
||||
|
@ -31,8 +32,6 @@
|
|||
//#define DPRINTF(...) gfx_printf(__VA_ARGS__)
|
||||
#define DPRINTF(...)
|
||||
|
||||
extern boot_cfg_t b_cfg;
|
||||
|
||||
/*! SCMMC controller base addresses. */
|
||||
static const u32 _sdmmc_bases[4] = {
|
||||
0x700B0000,
|
||||
|
@ -123,6 +122,7 @@ static int _sdmmc_config_ven_ceata_clk(sdmmc_t *sdmmc, u32 id)
|
|||
{
|
||||
if (!sdmmc->venclkctl_set)
|
||||
return 0;
|
||||
|
||||
tap_val = sdmmc->venclkctl_tap;
|
||||
}
|
||||
else
|
||||
|
@ -233,7 +233,7 @@ int sdmmc_setup_clock(sdmmc_t *sdmmc, u32 type)
|
|||
sdmmc->regs->hostctl2 |= SDHCI_CTRL_VDD_180;
|
||||
break;
|
||||
case 4:
|
||||
//Non standard
|
||||
// Non standard.
|
||||
sdmmc->regs->hostctl2 = (sdmmc->regs->hostctl2 & SDHCI_CTRL_UHS_MASK) | HS400_BUS_SPEED;
|
||||
sdmmc->regs->hostctl2 |= SDHCI_CTRL_VDD_180;
|
||||
break;
|
||||
|
@ -511,13 +511,17 @@ static int _sdmmc_config_tuning_once(sdmmc_t *sdmmc, u32 cmd)
|
|||
return 0;
|
||||
|
||||
_sdmmc_setup_read_small_block(sdmmc);
|
||||
|
||||
sdmmc->regs->norintstsen |= TEGRA_MMC_NORINTSTSEN_BUFFER_READ_READY;
|
||||
sdmmc->regs->norintsts = sdmmc->regs->norintsts;
|
||||
sdmmc->regs->clkcon &= ~TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE;
|
||||
|
||||
_sdmmc_parse_cmd_48(sdmmc, cmd);
|
||||
_sdmmc_get_clkcon(sdmmc);
|
||||
usleep(1);
|
||||
|
||||
_sdmmc_reset(sdmmc);
|
||||
|
||||
sdmmc->regs->clkcon |= TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE;
|
||||
_sdmmc_get_clkcon(sdmmc);
|
||||
|
||||
|
@ -533,10 +537,13 @@ static int _sdmmc_config_tuning_once(sdmmc_t *sdmmc, u32 cmd)
|
|||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
_sdmmc_reset(sdmmc);
|
||||
|
||||
sdmmc->regs->norintstsen &= 0xFFDF;
|
||||
_sdmmc_get_clkcon(sdmmc);
|
||||
usleep((1000 * 8 + sdmmc->divisor - 1) / sdmmc->divisor);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -563,8 +570,8 @@ int sdmmc_config_tuning(sdmmc_t *sdmmc, u32 type, u32 cmd)
|
|||
return 0;
|
||||
}
|
||||
|
||||
sdmmc->regs->ventunctl0 = (sdmmc->regs->ventunctl0 & 0xFFFF1FFF) | flag;
|
||||
sdmmc->regs->ventunctl0 = (sdmmc->regs->ventunctl0 & 0xFFFFE03F) | 0x40;
|
||||
sdmmc->regs->ventunctl0 = (sdmmc->regs->ventunctl0 & 0xFFFF1FFF) | flag; // Tries.
|
||||
sdmmc->regs->ventunctl0 = (sdmmc->regs->ventunctl0 & 0xFFFFE03F) | 0x40; // Multiplier.
|
||||
sdmmc->regs->ventunctl0 |= 0x20000;
|
||||
sdmmc->regs->hostctl2 |= SDHCI_CTRL_EXEC_TUNING;
|
||||
|
||||
|
@ -577,6 +584,7 @@ int sdmmc_config_tuning(sdmmc_t *sdmmc, u32 type, u32 cmd)
|
|||
|
||||
if (sdmmc->regs->hostctl2 & SDHCI_CTRL_TUNED_CLK)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -746,11 +754,14 @@ static int _sdmmc_stop_transmission_inner(sdmmc_t *sdmmc, u32 *rsp)
|
|||
return 0;
|
||||
|
||||
_sdmmc_enable_interrupts(sdmmc);
|
||||
|
||||
cmd.cmd = MMC_STOP_TRANSMISSION;
|
||||
cmd.arg = 0;
|
||||
cmd.rsp_type = SDMMC_RSP_TYPE_1;
|
||||
cmd.check_busy = 1;
|
||||
|
||||
_sdmmc_parse_cmdbuf(sdmmc, &cmd, false);
|
||||
|
||||
int res = _sdmmc_wait_request(sdmmc);
|
||||
_sdmmc_mask_interrupts(sdmmc);
|
||||
|
||||
|
@ -758,6 +769,7 @@ static int _sdmmc_stop_transmission_inner(sdmmc_t *sdmmc, u32 *rsp)
|
|||
return 0;
|
||||
|
||||
_sdmmc_cache_rsp(sdmmc, rsp, 4, SDMMC_RSP_TYPE_1);
|
||||
|
||||
return _sdmmc_wait_prnsts_type1(sdmmc);
|
||||
}
|
||||
|
||||
|
@ -777,6 +789,7 @@ int sdmmc_stop_transmission(sdmmc_t *sdmmc, u32 *rsp)
|
|||
|
||||
int res = _sdmmc_stop_transmission_inner(sdmmc, rsp);
|
||||
usleep((8000 + sdmmc->divisor - 1) / sdmmc->divisor);
|
||||
|
||||
if (should_disable_sd_clock)
|
||||
sdmmc->regs->clkcon &= ~TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE;
|
||||
|
||||
|
@ -817,7 +830,7 @@ static int _sdmmc_config_dma(sdmmc_t *sdmmc, u32 *blkcnt_out, sdmmc_req_t *req)
|
|||
trnmode |= TEGRA_MMC_TRNMOD_DATA_XFER_DIR_SEL_READ;
|
||||
if (req->is_auto_cmd12)
|
||||
trnmode = (trnmode & 0xFFF3) | TEGRA_MMC_TRNMOD_AUTO_CMD12;
|
||||
|
||||
bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY);
|
||||
sdmmc->regs->trnmod = trnmode;
|
||||
|
||||
return 1;
|
||||
|
@ -841,7 +854,10 @@ static int _sdmmc_update_dma(sdmmc_t *sdmmc)
|
|||
if (res < 0)
|
||||
break;
|
||||
if (intr & TEGRA_MMC_NORINTSTS_XFER_COMPLETE)
|
||||
{
|
||||
bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY);
|
||||
return 1; // Transfer complete.
|
||||
}
|
||||
if (intr & TEGRA_MMC_NORINTSTS_DMA_INTERRUPT)
|
||||
{
|
||||
// Update DMA.
|
||||
|
@ -906,6 +922,7 @@ static int _sdmmc_execute_cmd_inner(sdmmc_t *sdmmc, sdmmc_cmd_t *cmd, sdmmc_req_
|
|||
{
|
||||
if (blkcnt_out)
|
||||
*blkcnt_out = blkcnt;
|
||||
|
||||
if (req->is_auto_cmd12)
|
||||
sdmmc->rsp3 = sdmmc->regs->rspreg3;
|
||||
}
|
||||
|
@ -925,6 +942,8 @@ static int _sdmmc_config_sdmmc1()
|
|||
gpio_config(GPIO_PORT_Z, GPIO_PIN_1, GPIO_MODE_GPIO);
|
||||
gpio_output_enable(GPIO_PORT_Z, GPIO_PIN_1, GPIO_OUTPUT_DISABLE);
|
||||
usleep(100);
|
||||
|
||||
// Check if SD card is inserted.
|
||||
if(!!gpio_read(GPIO_PORT_Z, GPIO_PIN_1))
|
||||
return 0;
|
||||
|
||||
|
@ -938,7 +957,7 @@ static int _sdmmc_config_sdmmc1()
|
|||
*/
|
||||
|
||||
// Configure SDMMC1 pinmux.
|
||||
APB_MISC(APB_MISC_GP_SDMMC1_CLK_LPBK_CONTROL) = 1;
|
||||
APB_MISC(APB_MISC_GP_SDMMC1_CLK_LPBK_CONTROL) = 1; // Enable deep loopback for SDMMC1 CLK pad.
|
||||
PINMUX_AUX(PINMUX_AUX_SDMMC1_CLK) = PINMUX_DRIVE_2X | PINMUX_INPUT_ENABLE | PINMUX_PARKED;
|
||||
PINMUX_AUX(PINMUX_AUX_SDMMC1_CMD) = PINMUX_DRIVE_2X | PINMUX_INPUT_ENABLE | PINMUX_PARKED | PINMUX_PULL_UP;
|
||||
PINMUX_AUX(PINMUX_AUX_SDMMC1_DAT3) = PINMUX_DRIVE_2X | PINMUX_INPUT_ENABLE | PINMUX_PARKED | PINMUX_PULL_UP;
|
||||
|
@ -1009,18 +1028,23 @@ int sdmmc_init(sdmmc_t *sdmmc, u32 id, u32 power, u32 bus_width, u32 type, int n
|
|||
sdmmc->regs->sdmemcmppadctl = (sdmmc->regs->sdmemcmppadctl & 0xF) | 7;
|
||||
if (!_sdmmc_autocal_config_offset(sdmmc, power))
|
||||
return 0;
|
||||
|
||||
_sdmmc_autocal_execute(sdmmc, power);
|
||||
|
||||
if (_sdmmc_enable_internal_clock(sdmmc))
|
||||
{
|
||||
sdmmc_set_bus_width(sdmmc, bus_width);
|
||||
_sdmmc_set_voltage(sdmmc, power);
|
||||
|
||||
if (sdmmc_setup_clock(sdmmc, type))
|
||||
{
|
||||
sdmmc_sd_clock_ctrl(sdmmc, no_sd);
|
||||
_sdmmc_sd_clock_enable(sdmmc);
|
||||
_sdmmc_get_clkcon(sdmmc);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
|
@ -1039,8 +1063,8 @@ void sdmmc_end(sdmmc_t *sdmmc)
|
|||
{
|
||||
gpio_output_enable(GPIO_PORT_E, GPIO_PIN_4, GPIO_OUTPUT_DISABLE);
|
||||
max77620_regulator_enable(REGULATOR_LDO2, 0);
|
||||
b_cfg.sd_timeoff = get_tmr_ms(); // Some sandisc U1 cards need 100ms for a power cycle.
|
||||
msleep(1); // To power cycle, min 1ms without power is needed.
|
||||
sd_power_cycle_time_start = get_tmr_ms(); // Some sandisc U1 cards need 100ms for a power cycle.
|
||||
usleep(1000); // To power cycle, min 1ms without power is needed.
|
||||
}
|
||||
|
||||
_sdmmc_get_clkcon(sdmmc);
|
||||
|
@ -1077,6 +1101,7 @@ int sdmmc_execute_cmd(sdmmc_t *sdmmc, sdmmc_cmd_t *cmd, sdmmc_req_t *req, u32 *b
|
|||
|
||||
int res = _sdmmc_execute_cmd_inner(sdmmc, cmd, req, blkcnt_out);
|
||||
usleep((8000 + sdmmc->divisor - 1) / sdmmc->divisor);
|
||||
|
||||
if (should_disable_sd_clock)
|
||||
sdmmc->regs->clkcon &= ~TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE;
|
||||
|
||||
|
@ -1093,6 +1118,14 @@ int sdmmc_enable_low_voltage(sdmmc_t *sdmmc)
|
|||
|
||||
_sdmmc_get_clkcon(sdmmc);
|
||||
|
||||
// Enable schmitt trigger for better duty cycle and low jitter clock.
|
||||
PINMUX_AUX(PINMUX_AUX_SDMMC1_CLK) |= PINMUX_SCHMT;
|
||||
PINMUX_AUX(PINMUX_AUX_SDMMC1_CMD) |= PINMUX_SCHMT;
|
||||
PINMUX_AUX(PINMUX_AUX_SDMMC1_DAT3) |= PINMUX_SCHMT;
|
||||
PINMUX_AUX(PINMUX_AUX_SDMMC1_DAT2) |= PINMUX_SCHMT;
|
||||
PINMUX_AUX(PINMUX_AUX_SDMMC1_DAT1) |= PINMUX_SCHMT;
|
||||
PINMUX_AUX(PINMUX_AUX_SDMMC1_DAT0) |= PINMUX_SCHMT;
|
||||
|
||||
max77620_regulator_set_voltage(REGULATOR_LDO2, 1800000);
|
||||
PMC(APBDEV_PMC_PWR_DET_VAL) &= ~(1 << 12);
|
||||
|
||||
|
@ -1106,7 +1139,7 @@ int sdmmc_enable_low_voltage(sdmmc_t *sdmmc)
|
|||
{
|
||||
sdmmc->regs->clkcon |= TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE;
|
||||
_sdmmc_get_clkcon(sdmmc);
|
||||
msleep(1);
|
||||
usleep(1000);
|
||||
if ((sdmmc->regs->prnsts & 0xF00000) == 0xF00000)
|
||||
return 1;
|
||||
}
|
||||
|
|
51
source/tegraexplorer/gfx.c
Normal file
51
source/tegraexplorer/gfx.c
Normal file
|
@ -0,0 +1,51 @@
|
|||
#include "../gfx/gfx.h"
|
||||
#include "te.h"
|
||||
#include "../utils/btn.h"
|
||||
#include "gfx.h"
|
||||
|
||||
void clearscreen(){
|
||||
gfx_clear_grey(0x1B);
|
||||
gfx_box(0, 0, 719, 15, COLOR_WHITE);
|
||||
gfx_con_setpos(0, 0);
|
||||
gfx_printf("%k%KTegraexplorer%k%K\n", COLOR_DEFAULT, COLOR_WHITE, COLOR_WHITE, COLOR_DEFAULT);
|
||||
}
|
||||
|
||||
void message(char* message, u32 color){
|
||||
clearscreen();
|
||||
gfx_printf("%k%s%k", color, message, COLOR_DEFAULT);
|
||||
return btn_wait();
|
||||
}
|
||||
|
||||
int makemenu(menu_item menu[], int menuamount){
|
||||
int currentpos = 1, i, res;
|
||||
clearscreen();
|
||||
|
||||
while (1){
|
||||
gfx_con_setpos(0, 31);
|
||||
for (i = 0; i < menuamount; i++){
|
||||
if (menu[i].property < 0) {
|
||||
i--;
|
||||
continue;
|
||||
}
|
||||
if (i == currentpos - 1)
|
||||
gfx_printf("%k%K%s%K\n", COLOR_DEFAULT, COLOR_WHITE, menu[i].name, COLOR_DEFAULT);
|
||||
else
|
||||
gfx_printf("%k%s\n", menu[i].color, menu[i].name);
|
||||
}
|
||||
gfx_printf("\n%k%s", COLOR_WHITE, menuamount);
|
||||
|
||||
res = btn_wait();
|
||||
|
||||
if (res & BTN_VOL_UP)
|
||||
currentpos--;
|
||||
else if (res & BTN_VOL_DOWN)
|
||||
currentpos++;
|
||||
else if (res & BTN_POWER)
|
||||
return menu[currentpos - 1].internal_function;
|
||||
|
||||
if (currentpos > menuamount)
|
||||
currentpos = menuamount;
|
||||
else if (currentpos < 1)
|
||||
currentpos = 1;
|
||||
}
|
||||
}
|
4
source/tegraexplorer/gfx.h
Normal file
4
source/tegraexplorer/gfx.h
Normal file
|
@ -0,0 +1,4 @@
|
|||
#pragma once
|
||||
|
||||
int makemenu(menu_item menu[], int menuamount);
|
||||
void message(char* message, u32 color);
|
77
source/tegraexplorer/te.c
Normal file
77
source/tegraexplorer/te.c
Normal file
|
@ -0,0 +1,77 @@
|
|||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "te.h"
|
||||
#include "gfx.h"
|
||||
#include "../utils/util.h"
|
||||
|
||||
extern bool sd_mount();
|
||||
extern void sd_unmount();
|
||||
|
||||
menu_item mainmenu[MAINMENU_AMOUNT] = {
|
||||
{"[SD:/] SD CARD", COLOR_GREEN, 1, 0},
|
||||
{"[EMMC:/] ?\n", COLOR_GREEN, 2, 0},
|
||||
{"Mount/Unmount SD", COLOR_WHITE, 3, 0},
|
||||
{"Tools\n", COLOR_VIOLET, 4, 0},
|
||||
{"Credits", COLOR_WHITE, 5, 0},
|
||||
{"Exit", COLOR_WHITE, 6, 0}
|
||||
};
|
||||
|
||||
menu_item shutdownmenu[4] = {
|
||||
{"Reboot to RCM", COLOR_VIOLET, 1, 0},
|
||||
{"Reboot normally", COLOR_ORANGE, 2, 0},
|
||||
{"Power off\n", COLOR_BLUE, 3, 0},
|
||||
{"Back", COLOR_WHITE, 4, 0}
|
||||
};
|
||||
|
||||
int calcmenuitems(){
|
||||
int amount = 0, i;
|
||||
|
||||
for (i = 0; i < MAINMENU_AMOUNT; i++)
|
||||
if (mainmenu[i].property >= 0)
|
||||
amount++;
|
||||
|
||||
return amount;
|
||||
}
|
||||
|
||||
void fillmainmenu(){
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAINMENU_AMOUNT; i++){
|
||||
switch (i + 1) {
|
||||
case 1:
|
||||
if (sd_mount)
|
||||
mainmenu[i].property = 1;
|
||||
else
|
||||
mainmenu[i].property = -1;
|
||||
break;
|
||||
case 3:
|
||||
if (sd_mount)
|
||||
mainmenu[i].property = 1;
|
||||
else
|
||||
mainmenu[i].property = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void te_main(){
|
||||
int res;
|
||||
|
||||
while (1){
|
||||
fillmainmenu();
|
||||
res = makemenu(mainmenu, calcmenuitems());
|
||||
|
||||
if (res == 5)
|
||||
message(CREDITS_MESSAGE, COLOR_GREEN);
|
||||
|
||||
if (res == 6){
|
||||
res = makemenu(shutdownmenu, 4);
|
||||
if (res == 1)
|
||||
reboot_rcm();
|
||||
else if (res == 2)
|
||||
reboot_normal();
|
||||
else if (res == 3)
|
||||
power_off();
|
||||
}
|
||||
}
|
||||
}
|
16
source/tegraexplorer/te.h
Normal file
16
source/tegraexplorer/te.h
Normal file
|
@ -0,0 +1,16 @@
|
|||
#pragma once
|
||||
#include "../utils/types.h"
|
||||
|
||||
#define MAINMENU_AMOUNT 6
|
||||
#define CREDITS_MESSAGE "Tegraexplorer, made by:\nSuch Meme, Many Skill\n\nProject based on:\nLockpick_RCM\nHekate\n\nCool people:\nshchmue\ndennthecafebabe\nDax"
|
||||
|
||||
typedef struct _menu_item {
|
||||
char name[50];
|
||||
u32 color;
|
||||
short internal_function;
|
||||
short property;
|
||||
} menu_item;
|
||||
|
||||
menu_item mainmenu[MAINMENU_AMOUNT];
|
||||
|
||||
void te_main();
|
|
@ -29,7 +29,7 @@ u8 btn_read()
|
|||
res |= BTN_VOL_DOWN;
|
||||
if (!gpio_read(GPIO_PORT_X, GPIO_PIN_6))
|
||||
res |= BTN_VOL_UP;
|
||||
if (i2c_recv_byte(4, MAX77620_I2C_ADDR, 0x15) & 0x4)
|
||||
if (i2c_recv_byte(4, MAX77620_I2C_ADDR, MAX77620_REG_ONOFFSTAT) & 0x4)
|
||||
res |= BTN_POWER;
|
||||
return res;
|
||||
}
|
||||
|
|
94
source/utils/dirlist.c
Normal file
94
source/utils/dirlist.c
Normal file
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
* Copyright (c) 2018 CTCaer
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "../libs/fatfs/ff.h"
|
||||
#include "../mem/heap.h"
|
||||
#include "../utils/types.h"
|
||||
|
||||
char *dirlist(const char *directory, const char *pattern, bool includeHiddenFiles)
|
||||
{
|
||||
u8 max_entries = 61;
|
||||
|
||||
int res = 0;
|
||||
u32 i = 0, j = 0, k = 0;
|
||||
DIR dir;
|
||||
FILINFO fno;
|
||||
|
||||
char *dir_entries = (char *)calloc(max_entries, 256);
|
||||
char *temp = (char *)calloc(1, 256);
|
||||
|
||||
if (!pattern && !f_opendir(&dir, directory))
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
res = f_readdir(&dir, &fno);
|
||||
if (res || !fno.fname[0])
|
||||
break;
|
||||
if (!(fno.fattrib & AM_DIR) && (fno.fname[0] != '.') && (includeHiddenFiles || !(fno.fattrib & AM_HID)))
|
||||
{
|
||||
memcpy(dir_entries + (k * 256), fno.fname, strlen(fno.fname) + 1);
|
||||
k++;
|
||||
if (k > (max_entries - 1))
|
||||
break;
|
||||
}
|
||||
}
|
||||
f_closedir(&dir);
|
||||
}
|
||||
else if (pattern && !f_findfirst(&dir, &fno, directory, pattern) && fno.fname[0])
|
||||
{
|
||||
do
|
||||
{
|
||||
if (!(fno.fattrib & AM_DIR) && (fno.fname[0] != '.') && (includeHiddenFiles || !(fno.fattrib & AM_HID)))
|
||||
{
|
||||
memcpy(dir_entries + (k * 256), fno.fname, strlen(fno.fname) + 1);
|
||||
k++;
|
||||
if (k > (max_entries - 1))
|
||||
break;
|
||||
}
|
||||
res = f_findnext(&dir, &fno);
|
||||
} while (fno.fname[0] && !res);
|
||||
f_closedir(&dir);
|
||||
}
|
||||
|
||||
if (!k)
|
||||
{
|
||||
free(temp);
|
||||
free(dir_entries);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Reorder ini files by ASCII ordering.
|
||||
for (i = 0; i < k - 1 ; i++)
|
||||
{
|
||||
for (j = i + 1; j < k; j++)
|
||||
{
|
||||
if (strcmp(&dir_entries[i * 256], &dir_entries[j * 256]) > 0)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
free(temp);
|
||||
|
||||
return dir_entries;
|
||||
}
|
19
source/utils/dirlist.h
Normal file
19
source/utils/dirlist.h
Normal file
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
* Copyright (c) 2018 CTCaer
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "../utils/types.h"
|
||||
|
||||
char *dirlist(const char *directory, const char *pattern, bool includeHiddenFiles);
|
|
@ -14,7 +14,7 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "types.h"
|
||||
#include "sprintf.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
|
@ -104,8 +104,9 @@ u32 sprintf(char *buffer, const char *fmt, ...) {
|
|||
goto out;
|
||||
default:
|
||||
_putc(buffer + count, '%');
|
||||
count++;
|
||||
_putc(buffer + count, *fmt);
|
||||
count += 2;
|
||||
count++;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
#ifndef _SPRINTF_H_
|
||||
#define _SPRINTF_H_
|
||||
|
||||
#include "types.h"
|
||||
|
||||
u32 sprintf(char *buffer, const char *fmt, ...);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -35,7 +35,8 @@
|
|||
#define KB_FIRMWARE_VERSION_620 6
|
||||
#define KB_FIRMWARE_VERSION_700 7
|
||||
#define KB_FIRMWARE_VERSION_810 8
|
||||
#define KB_FIRMWARE_VERSION_MAX KB_FIRMWARE_VERSION_810
|
||||
#define KB_FIRMWARE_VERSION_900 9
|
||||
#define KB_FIRMWARE_VERSION_MAX KB_FIRMWARE_VERSION_900
|
||||
|
||||
#define HOS_PKG11_MAGIC 0x31314B50
|
||||
|
||||
|
@ -45,8 +46,8 @@
|
|||
#define COLOR_GREEN 0xFF40FF00
|
||||
#define COLOR_BLUE 0xFF00DDFF
|
||||
#define COLOR_VIOLET 0xFF8040FF
|
||||
#define COLOR_DEFAULT 0xFF1B1B1B
|
||||
#define COLOR_WHITE 0xFFFFFFFF
|
||||
#define COLOR_DEFAULT 0xFF1B1B1B
|
||||
|
||||
typedef signed char s8;
|
||||
typedef short s16;
|
||||
|
@ -69,6 +70,8 @@ typedef volatile unsigned char vu8;
|
|||
typedef volatile unsigned short vu16;
|
||||
typedef volatile unsigned int vu32;
|
||||
|
||||
static const u32 colors[6] = {COLOR_RED, COLOR_ORANGE, COLOR_YELLOW, COLOR_GREEN, COLOR_BLUE, COLOR_VIOLET};
|
||||
|
||||
typedef int bool;
|
||||
#define true 1
|
||||
#define false 0
|
||||
|
@ -77,14 +80,22 @@ typedef int bool;
|
|||
#define BOOT_CFG_FROM_LAUNCH (1 << 1)
|
||||
#define BOOT_CFG_SEPT_RUN (1 << 7)
|
||||
|
||||
#define EXTRA_CFG_DUMP_EMUMMC (1 << 0)
|
||||
|
||||
typedef struct __attribute__((__packed__)) _boot_cfg_t
|
||||
{
|
||||
u8 boot_cfg;
|
||||
u8 autoboot;
|
||||
u8 autoboot_list;
|
||||
u8 extra_cfg;
|
||||
u32 sd_timeoff;
|
||||
u8 rsvd[124];
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
char id[8];
|
||||
};
|
||||
u8 xt_str[0x80];
|
||||
};
|
||||
} boot_cfg_t;
|
||||
|
||||
typedef struct __attribute__((__packed__)) _reloc_meta_t
|
||||
|
|
|
@ -19,10 +19,13 @@
|
|||
#include "../gfx/di.h"
|
||||
#include "../power/max77620.h"
|
||||
#include "../rtc/max77620-rtc.h"
|
||||
#include "../soc/bpmp.h"
|
||||
#include "../soc/i2c.h"
|
||||
#include "../soc/pmc.h"
|
||||
#include "../soc/t210.h"
|
||||
|
||||
#define USE_RTC_TIMER
|
||||
|
||||
extern void sd_unmount();
|
||||
|
||||
u32 get_tmr_s()
|
||||
|
@ -34,7 +37,7 @@ u32 get_tmr_ms()
|
|||
{
|
||||
// The registers must be read with the following order:
|
||||
// RTC_MILLI_SECONDS (0x10) -> RTC_SHADOW_SECONDS (0xC)
|
||||
return (RTC(APBDEV_RTC_MILLI_SECONDS) | (RTC(APBDEV_RTC_SHADOW_SECONDS) << 10));
|
||||
return (RTC(APBDEV_RTC_MILLI_SECONDS) + (RTC(APBDEV_RTC_SHADOW_SECONDS) * 1000));
|
||||
}
|
||||
|
||||
u32 get_tmr_us()
|
||||
|
@ -42,19 +45,32 @@ u32 get_tmr_us()
|
|||
return TMR(TIMERUS_CNTR_1US); //TIMERUS_CNTR_1US
|
||||
}
|
||||
|
||||
void msleep(u32 milliseconds)
|
||||
void msleep(u32 ms)
|
||||
{
|
||||
u32 start = RTC(APBDEV_RTC_MILLI_SECONDS) | (RTC(APBDEV_RTC_SHADOW_SECONDS) << 10);
|
||||
while (((RTC(APBDEV_RTC_MILLI_SECONDS) | (RTC(APBDEV_RTC_SHADOW_SECONDS) << 10)) - start) <= milliseconds)
|
||||
#ifdef USE_RTC_TIMER
|
||||
u32 start = RTC(APBDEV_RTC_MILLI_SECONDS) + (RTC(APBDEV_RTC_SHADOW_SECONDS) * 1000);
|
||||
// Casting to u32 is important!
|
||||
while (((u32)(RTC(APBDEV_RTC_MILLI_SECONDS) + (RTC(APBDEV_RTC_SHADOW_SECONDS) * 1000)) - start) <= ms)
|
||||
;
|
||||
#else
|
||||
bpmp_msleep(ms);
|
||||
#endif
|
||||
}
|
||||
|
||||
void usleep(u32 microseconds)
|
||||
void usleep(u32 us)
|
||||
{
|
||||
#ifdef USE_RTC_TIMER
|
||||
u32 start = TMR(TIMERUS_CNTR_1US);
|
||||
// Casting to u32 is important!
|
||||
while ((u32)(TMR(TIMERUS_CNTR_1US) - start) <= microseconds)
|
||||
|
||||
// Check if timer is at upper limits and use BPMP sleep so it doesn't wake up immediately.
|
||||
if ((start + us) < start)
|
||||
bpmp_usleep(us);
|
||||
else
|
||||
while ((u32)(TMR(TIMERUS_CNTR_1US) - start) <= us) // Casting to u32 is important!
|
||||
;
|
||||
#else
|
||||
bpmp_usleep(us);
|
||||
#endif
|
||||
}
|
||||
|
||||
void exec_cfg(u32 *base, const cfg_op_t *ops, u32 num_ops)
|
||||
|
@ -72,12 +88,15 @@ void panic(u32 val)
|
|||
TMR(TIMER_TMR9_TMR_PTV) = TIMER_EN | TIMER_PER_EN;
|
||||
TMR(TIMER_WDT4_CONFIG) = TIMER_SRC(9) | TIMER_PER(1) | TIMER_PMCRESET_EN;
|
||||
TMR(TIMER_WDT4_COMMAND) = TIMER_START_CNT;
|
||||
while (1)
|
||||
;
|
||||
|
||||
while (true)
|
||||
usleep(1);
|
||||
}
|
||||
|
||||
void reboot_normal()
|
||||
{
|
||||
bpmp_mmu_disable();
|
||||
|
||||
sd_unmount();
|
||||
display_end();
|
||||
|
||||
|
@ -86,6 +105,8 @@ void reboot_normal()
|
|||
|
||||
void reboot_rcm()
|
||||
{
|
||||
bpmp_mmu_disable();
|
||||
|
||||
sd_unmount();
|
||||
display_end();
|
||||
|
||||
|
@ -93,16 +114,19 @@ void reboot_rcm()
|
|||
PMC(APBDEV_PMC_CNTRL) |= PMC_CNTRL_MAIN_RST;
|
||||
|
||||
while (true)
|
||||
usleep(1);
|
||||
bpmp_halt();
|
||||
}
|
||||
|
||||
void power_off()
|
||||
{
|
||||
sd_unmount();
|
||||
display_end();
|
||||
|
||||
// Stop the alarm, in case we injected and powered off too fast.
|
||||
max77620_rtc_stop_alarm();
|
||||
|
||||
//TODO: we should probably make sure all regulators are powered off properly.
|
||||
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_ONOFFCNFG1, MAX77620_ONOFFCNFG1_PWR_OFF);
|
||||
|
||||
while (true)
|
||||
bpmp_halt();
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#define _UTIL_H_
|
||||
|
||||
#include "types.h"
|
||||
#include "../mem/minerva.h"
|
||||
|
||||
#define byte_swap_32(num) (((num >> 24) & 0xff) | ((num << 8) & 0xff0000) | \
|
||||
((num >> 8 )& 0xff00) | ((num << 24) & 0xff000000))
|
||||
|
@ -29,11 +30,22 @@ typedef struct _cfg_op_t
|
|||
u32 val;
|
||||
} cfg_op_t;
|
||||
|
||||
typedef struct _nyx_storage_t
|
||||
{
|
||||
u32 version;
|
||||
u32 cfg;
|
||||
u8 irama[0x8000];
|
||||
u8 hekate[0x30000];
|
||||
u8 rsvd[0x800000];
|
||||
mtc_config_t mtc_cfg;
|
||||
emc_table_t mtc_table;
|
||||
} nyx_storage_t;
|
||||
|
||||
u32 get_tmr_us();
|
||||
u32 get_tmr_ms();
|
||||
u32 get_tmr_s();
|
||||
void usleep(u32 ticks);
|
||||
void msleep(u32 milliseconds);
|
||||
void usleep(u32 us);
|
||||
void msleep(u32 ms);
|
||||
void panic(u32 val);
|
||||
void reboot_normal();
|
||||
void reboot_rcm();
|
||||
|
|
Loading…
Reference in a new issue