Compare commits

..

50 Commits
v4.5 ... v4.9.1

Author SHA1 Message Date
Kostas Missos
be09b68532 Bump version to v4.9 2019-03-09 00:12:08 +02:00
Kostas Missos
50eff41351 [eMMC Tools] Support for partial restore
Co-Authored-By: emvym3two <emvym3two@users.noreply.github.com>
2019-03-09 00:09:36 +02:00
Kostas Missos
4b78198f33 Update readme.md for the new features 2019-03-08 22:19:25 +02:00
Kostas Missos
dfb5640bfe Performance fixes 2019-03-08 22:18:54 +02:00
Kostas Missos
f139f9c56f [FSS0] Add Fusee secondary storage parser
Using "fss0={sd path}" allows you to parse kips, exosphere and warmboot from a fusee secondary binary.

Exosphere and warmboot are overridable if these entries are defined after that.

Additionally any extra kip can be loaded as before via
kip1={sd path}/* for many
or
kip1={sd path} for a sigle one

Warning: Don't double load core kips like loader, pm, sm and ams_mitm. The result will be a hang.
2019-03-08 01:14:43 +02:00
Kostas Missos
4f4df9ccd1 [Auto boot] Change order of invoking sept
This is important, otherwise it can break tools like memloader.

Until a semi-usb init solution is found, hekate will show bootlogo and allow you to go to menu.
If >= 7.0.0 after that, it will run sept and then show logo again without a wait. For as long as rebuilding the boot process takes.
2019-03-08 00:35:43 +02:00
Kostas Missos
bafc6f4a1d [Backup & Restore] Performance changes
- Use always aligned buffers to up the speed for DMA usage. For verification, backup and restore.
- Rework verification a little bit and make default Sparse mode.

Sparse mode protects from fake sd cards, bad sectors and frequent I/O corruption. Aka, ~100% of cases.
2019-03-08 00:30:56 +02:00
Kostas Missos
b1110caed1 [Reloc patcher] Use structs and name more consts 2019-03-08 00:23:19 +02:00
Kostas Missos
e7f72b711a [Utils] btn_wait_timeout
- Allow btn_wait_timeout to be triggered immediately
- Make power options global
2019-03-08 00:22:15 +02:00
Kostas Missos
0ddc1c71a8 Bugfixes and hardcoded naming
- Make debugmode for exosphere mandatory
- Support dev RSA modulus for warmboot
- Fix a critical bug where it allowed free() to be used on a non-heap address.
- Better the makefile
2019-03-08 00:19:04 +02:00
Kostas Missos
4e7c39d6a0 [Logos] Optimize logos and save ~7KB
Additionally stop unneeded frees of menu logo to increase redrwaing performance.
2019-03-08 00:08:39 +02:00
Kostas Missos
72a81e7c2a [gfx] Make gfx context and macros global 2019-03-08 00:02:37 +02:00
Kostas Missos
2e9a89aa20 [Versioning] Better and smarter for update and sept
- Still compatible with old hekate.
- Allows for hotfix control
- Sept is now copied from actual running payload, negating the need to check update.bin
- If a foreign payload is found in sept then it is renamed and hekate copies itself. After sept run, it renames it back and continues with boot.
2019-03-07 23:53:58 +02:00
Kostas Missos
ca68818efe [Boot cfg] Proper usage of storage and structs 2019-03-07 23:41:07 +02:00
Kostas Missos
3b9bf65071 Bump version to v4.8 2019-02-24 03:09:07 +02:00
Kostas Missos
50d4cbbda1 [sept] Auto update sept payload via update.bin
This will check if payload.bin is the same version with update.bin
2019-02-24 03:04:28 +02:00
Kostas Missos
f911fab9f2 [7.0.0-7.0.1] Add full support via Atmosphere's sept 2019-02-24 03:03:17 +02:00
Kostas Missos
aae7689bf5 [7.0.0] Initial support 2019-02-24 02:58:15 +02:00
Kostas Missos
7d908c9ac5 [hos] Support new mailbox and refactor a little bit 2019-02-24 02:54:32 +02:00
Kostas Missos
2fb37db707 [Boot Config] Add HOS reboot to config
This storage allows you to reboot from HOS to the selected ini boot entry.

In the future it will be used for far more.
2019-02-24 02:43:13 +02:00
Kostas Missos
c8052e5b50 [exosphere] Support for new exo config 2019-02-24 02:34:04 +02:00
Kostas Missos
de830df7e7 Add automatic NOGC based on fuses burnt
Auto NoGC:
0: Force disable, 1: Auto (checks fuses and fw version)

And also remove customlogo. It's redudunt.
2019-02-24 01:06:24 +02:00
Kostas Missos
04907e2823 Bug fixes and refactoring
- Info tools
- Tools
- Tsec
- Many more
2019-02-24 00:59:33 +02:00
Kostas Missos
4f5fcf9fbd [config + ini] Refactor and fix bugs 2019-02-24 00:35:24 +02:00
Kostas Missos
ec890c7c97 [PMIC] Refactoring 2019-02-16 01:23:14 +02:00
Kostas Missos
4f2bbbf101 Fix GPU on Linux when booting from warmboot 2019-02-12 00:46:06 +02:00
Kostas Missos
b677d6cad3 Add max77620-rtc driver & disable alarm on shut off 2019-02-12 00:45:27 +02:00
Kostas Missos
b3f8961e45 Fix sleep with 6.X.X secmon when debug mode is on 2019-02-12 00:42:22 +02:00
Kostas Missos
2f37811aba Normalize brom patches & add sd autocalib fallback 2019-02-12 00:40:40 +02:00
Kostas Missos
5cd596e53c Add SVC generic patches
First patch allows same process on svcControlCodeMemory
2019-02-12 00:36:24 +02:00
Kostas Missos
4ae42c3a9d Small fixes and whitespace
Additionally make info functions smaller and show available fuses.
2019-02-12 00:34:35 +02:00
Kostas Missos
e105634b0d Proper warmboot exploit impl and documentation
Side effect:
Fixed a bug where the dumped patched bootrom had the warmboot exploit patch

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

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

A proposed usage is by using the first option and then the 2nd.
2018-12-16 16:57:49 +02:00
Kostas Missos
5ed875ce90 Make tsec checks faster and cover unluckiest cases
+ changes for readability
2018-12-16 16:55:56 +02:00
Kostas Missos
30d3c76655 Bugfixes 2018-12-16 16:52:38 +02:00
Kostas Missos
949a034500 Merge pull request #166 from balika011/warmboot
Add warmboot patches for efuse checks
2018-12-16 16:23:09 +02:00
balika011
b2893d7fb6 Add warmboot patches for efuse checks
Fixes sleep on downgrade
2018-12-16 15:21:17 +01:00
Kostas Missos
9a3fdd944e Merge pull request #165 from balika011/overclock
Fine-tune dram configs for OC
2018-12-16 16:17:51 +02:00
balika011
8b8f3c564c Fine-tune dram configs
Helps overclocking
2018-12-16 14:51:16 +01:00
Kostas Missos
cd1bb96241 Merge pull request #164 from balika011/ipatches_fix
Fix ipatch printing
2018-12-16 14:54:43 +02:00
balika011
8b59ddf3a8 Fix ipatch printing 2018-12-16 12:35:48 +01:00
Kostas Missos
09bfed9146 Merge pull request #162 from balika011/ipatches_fix
Fix ipatches backup on dumping
2018-12-15 21:45:26 +02:00
Kostas Missos
cbe75d7769 Merge pull request #158 from hyln9/master
Fix debug uart
2018-12-15 21:44:03 +02:00
balika011
dad380344f Fix ipatches backup on dumping 2018-12-15 17:04:14 +01:00
Yule Hou
71b0975730 Fix debug uart 2018-12-08 12:38:59 +08:00
64 changed files with 2907 additions and 2391 deletions

128
Makefile
View File

@@ -4,98 +4,106 @@ endif
include $(DEVKITARM)/base_rules
TARGET := hekate
################################################################################
IPL_LOAD_ADDR := 0x40008000
IPL_MAGIC := 0x43544349 #"ICTC"
BLVERSION_MAJOR := 4
BLVERSION_MINOR := 5
BUILD := build
OUTPUT := output
BLVERSION_MINOR := 9
BLVERSION_HOTFX := 0
BL_RESERVED := 0
################################################################################
TARGET := hekate
BUILDDIR := build
OUTPUTDIR := output
SOURCEDIR = bootloader
VPATH = $(dir $(wildcard ./$(SOURCEDIR)/*/)) $(dir $(wildcard ./$(SOURCEDIR)/*/*/))
OBJS = $(addprefix $(BUILD)/$(TARGET)/, \
# Main and graphics.
OBJS = $(addprefix $(BUILDDIR)/$(TARGET)/, \
start.o \
main.o \
fe_emmc_tools.o \
fe_info.o \
fe_tools.o \
config.o \
btn.o \
clock.o \
cluster.o \
fuse.o \
gpio.o \
heap.o \
hos.o \
hos_config.o \
secmon_exo.o \
i2c.o \
kfuse.o \
bq24193.o \
max7762x.o \
max17050.o \
mc.o \
nx_emmc.o \
sdmmc.o \
sdmmc_driver.o \
sdram.o \
tui.o \
util.o \
di.o \
gfx.o \
pinmux.o \
pkg1.o \
pkg2.o \
se.o \
tsec.o \
uart.o \
hw_init.o \
dirlist.o \
ini.o \
ianos.o \
smmu.o \
main.o heap.o \
gfx.o tui.o \
fe_emmc_tools.o fe_info.o fe_tools.o \
)
OBJS += $(addprefix $(BUILD)/$(TARGET)/, \
# Hardware.
OBJS += $(addprefix $(BUILDDIR)/$(TARGET)/, \
clock.o cluster.o di.o gpio.o i2c.o mc.o sdram.o pinmux.o se.o smmu.o tsec.o uart.o \
fuse.o kfuse.o \
sdmmc.o sdmmc_driver.o \
bq24193.o max17050.o max7762x.o max77620-rtc.o \
hw_init.o \
)
# Utilities.
OBJS += $(addprefix $(BUILDDIR)/$(TARGET)/, \
btn.o dirlist.o ianos.o util.o \
config.o ini.o \
)
# Horizon.
OBJS += $(addprefix $(BUILDDIR)/$(TARGET)/, \
nx_emmc.o \
hos.o hos_config.o pkg1.o pkg2.o fss.o secmon_exo.o sept.o \
)
# Libraries.
OBJS += $(addprefix $(BUILDDIR)/$(TARGET)/, \
lz.o blz.o \
diskio.o ff.o ffunicode.o ffsystem.o \
elfload.o elfreloc_arm.o \
)
################################################################################
CUSTOMDEFINES := -DIPL_LOAD_ADDR=$(IPL_LOAD_ADDR) -DBL_MAGIC=$(IPL_MAGIC)
CUSTOMDEFINES += -DBL_VER_MJ=$(BLVERSION_MAJOR) -DBL_VER_MN=$(BLVERSION_MINOR) -DBL_VER_HF=$(BLVERSION_HOTFX) -DBL_RESERVED=$(BL_RESERVED)
CUSTOMDEFINES += -DMENU_LOGO_ENABLE
# 0: UART_A, 1: UART_B.
#CUSTOMDEFINES += -DDEBUG_UART_PORT=0
#CUSTOMDEFINES += -DDEBUG
ARCH := -march=armv4t -mtune=arm7tdmi -mthumb -mthumb-interwork
CUSTOMDEFINES := -DBLVERSIONMJ=$(BLVERSION_MAJOR) -DBLVERSIONMN=$(BLVERSION_MINOR)
CUSTOMDEFINES += -DMENU_LOGO_ENABLE #-DDEBUG
CFLAGS = $(ARCH) -O2 -nostdlib -ffunction-sections -fdata-sections -fomit-frame-pointer -fno-inline -std=gnu11 -Wall $(CUSTOMDEFINES)
LDFLAGS = $(ARCH) -nostartfiles -lgcc -Wl,--nmagic,--gc-sections
LDFLAGS = $(ARCH) -nostartfiles -lgcc -Wl,--nmagic,--gc-sections -Xlinker --defsym=IPL_LOAD_ADDR=$(IPL_LOAD_ADDR)
MODULEDIRS := $(wildcard modules/*)
################################################################################
.PHONY: all clean $(MODULEDIRS)
all: $(TARGET).bin
@echo -n "Payload size is "
@wc -c < $(OUTPUT)/$(TARGET).bin
@wc -c < $(OUTPUTDIR)/$(TARGET).bin
@echo "Max size is 126296 Bytes."
clean:
@rm -rf $(OBJS)
@rm -rf $(BUILD)
@rm -rf $(OUTPUT)
@rm -rf $(BUILDDIR)
@rm -rf $(OUTPUTDIR)
$(MODULEDIRS):
$(MAKE) -C $@ $(MAKECMDGOALS)
$(TARGET).bin: $(BUILD)/$(TARGET)/$(TARGET).elf $(MODULEDIRS)
$(OBJCOPY) -S -O binary $< $(OUTPUT)/$@
@printf ICTC$(BLVERSION_MAJOR)$(BLVERSION_MINOR) >> $(OUTPUT)/$@
$(TARGET).bin: $(BUILDDIR)/$(TARGET)/$(TARGET).elf $(MODULEDIRS)
$(OBJCOPY) -S -O binary $< $(OUTPUTDIR)/$@
@printf ICTC$(BLVERSION_MAJOR)$(BLVERSION_MINOR) >> $(OUTPUTDIR)/$@
$(BUILD)/$(TARGET)/$(TARGET).elf: $(OBJS)
$(BUILDDIR)/$(TARGET)/$(TARGET).elf: $(OBJS)
$(CC) $(LDFLAGS) -T $(SOURCEDIR)/link.ld $^ -o $@
$(BUILD)/$(TARGET)/%.o: %.c
$(BUILDDIR)/$(TARGET)/%.o: %.c
$(CC) $(CFLAGS) -c $< -o $@
$(BUILD)/$(TARGET)/%.o: %.S
@mkdir -p "$(BUILD)"
@mkdir -p "$(BUILD)/$(TARGET)"
@mkdir -p "$(OUTPUT)"
$(BUILDDIR)/$(TARGET)/%.o: %.S
@mkdir -p "$(BUILDDIR)"
@mkdir -p "$(BUILDDIR)/$(TARGET)"
@mkdir -p "$(OUTPUTDIR)"
$(CC) $(CFLAGS) -c $< -o $@

View File

@@ -20,6 +20,8 @@ Custom Nintendo Switch bootloader, firmware patcher, and more.
| bootloader/payloads/ | For payloads. 'Payloads...' menu. Autoboot only supported by including them into an ini. All CFW bootloaders, tools, Linux payloads are supported. |
| bootloader/libtools/ | Future reserved |
**Note**: Sept files for booting 7.0.0 and up are expected at /sept folder at root of sd card.
## Bootloader configuration
@@ -29,15 +31,15 @@ The bootloader can be configured via 'bootloader/hekate_ipl.ini' (if it is prese
There are four possible type of entries. "**[ ]**": Boot entry, "**{ }**": Caption, "**#**": Comment, "*newline*": .ini cosmetic newline.
### Configuration keys/values when boot entry is **config**:
### Global Configuration keys/values when boot entry is **config**:
| Config option | Description |
| ------------------ | ---------------------------------------------------------- |
| autoboot=0 | 0: Disable, #: Boot entry number to auto boot. |
| bootwait=3 | 0: Disable (It also disables bootlogo. Having **VOL-** pressed since injection goes to menu.), #: Time to wait for **VOL-** to enter menu. |
| customlogo=0 | 0: Use default hekate bootlogo, 1: Use bootlogo.bmp. |
| verification=2 | 0: Disable Backup/Restore verification, 1: Sparse (block based, fast and not 100% reliable), 2: Full (sha256 based, slow and 100% reliable). |
| autohosoff=1 | 0: Disable, 1: If woke up from HOS via an RTC alarm, shows logo, then powers off completely, 2: No logo, immediately powers off.|
| autonogc=1 | 0: Disable, 1: Automatically applies nogc patch if unburnt fuses found and a >= 4.0.0 HOS is booted. |
| backlight=100 | Screen backlight level. 0-255. |
@@ -51,12 +53,33 @@ There are four possible type of entries. "**[ ]**": Boot entry, "**{ }**": Capti
| kernel={SD path} | Replaces the kernel binary |
| kip1={SD path} | Replaces/Adds kernel initial process. Multiple can be set. |
| kip1={SD folder}/* | Loads every .kip/.kip1 inside a folder. Compatible with single kip1 keys. |
| kip1patch=patchname| Enables a kip1 patch. Specify with multiple lines and/or as CSV. Implemented patches right now are nosigchk,nogc |
| fss0={SD path} | Takes a fusee-secondary binary and extracts all needed parts from it. |
| kip1patch=patchname| Enables a kip1 patch. Specify with multiple lines and/or as CSV. Current available patches nosigchk. |
| fullsvcperm=1 | Disables SVC verification (full services permission) |
| debugmode=1 | Enables Debug mode |
| debugmode=1 | Enables Debug mode. Obsolete when used with exosphere as secmon. |
| atmosphere=1 | Enables Atmosphère patching |
| payload={SD path} | Payload launching. Tools, Linux, CFW bootloaders, etc. |
**Note1**: When using the wildcard (`/*`) with `kip1` you can still use the normal `kip1` after that to load extra signle kips.
**Note2**: When using FSS0 it parses exosphere, warmboot and all core kips. You can override the first 2 by using `secmon`/`warmboot` after defining `fss0`.
You can define `kip1` to load an extra kip or many via the wildcard (`/*`) usage.
**Warning**: Never define core kips when using `fss0` and make sure that the folder (when using `/*`), does not include them.
### Payload storage:
Hekate now has a new storage in the binary that helps it configure it outside of BPMP enviroment:
| Offset / Name | Description |
| -------------------- | ----------------------------------------------------------------- |
| '0x94' boot_cfg | bit0: Force AutoBoot, bit1: Show launch log, bit2: sept run. |
| '0x98' autoboot | If `Force AutoBoot`: 0: Force go to menu, else boot that entry. |
| '0x9C' autoboot_list | If `Force AutoBoot` and `autoboot` then it boots from ini folder. |
| '0xA0' extra_cfg | Reserved. |
| '0xA4' rsvd[128] | Reserved. |
You can find a template [Here](./res/hekate_ipl_template.ini)

View File

@@ -1,5 +1,5 @@
/*
* 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,
@@ -17,20 +17,15 @@
#include <string.h>
#include <stdlib.h>
#include "../utils/btn.h"
#include "config.h"
#include "../libs/fatfs/ff.h"
#include "ini.h"
#include "../utils/list.h"
#include "../gfx/tui.h"
#include "../utils/util.h"
#include "../gfx/gfx.h"
extern gfx_ctxt_t gfx_ctxt;
extern gfx_con_t gfx_con;
//TODO: Create more macros (info, header, debug, etc) with different colors and utilize them for consistency.
#define EPRINTF(text) gfx_printf(&gfx_con, "%k"text"%k\n", 0xFFFF0000, 0xFFCCCCCC)
#define EPRINTFARGS(text, args...) gfx_printf(&gfx_con, "%k"text"%k\n", 0xFFFF0000, args, 0xFFCCCCCC)
#include "../gfx/tui.h"
#include "../libs/fatfs/ff.h"
#include "../soc/t210.h"
#include "../utils/btn.h"
#include "../utils/list.h"
#include "../utils/util.h"
extern hekate_config h_cfg;
extern int sd_mount();
@@ -41,13 +36,14 @@ void set_default_configuration()
h_cfg.autoboot = 0;
h_cfg.autoboot_list = 0;
h_cfg.bootwait = 3;
h_cfg.customlogo = 0;
h_cfg.verification = 2;
h_cfg.verification = 1;
h_cfg.se_keygen_done = 0;
h_cfg.sbar_time_keeping = 0;
h_cfg.backlight = 100;
h_cfg.autohosoff = 1;
h_cfg.autohosoff = 0;
h_cfg.errors = 0;
h_cfg.autonogc = 1;
h_cfg.sept_run = EMC(EMC_SCRATCH0) & EMC_SEPT_RUN;
}
int create_config_entry()
@@ -93,9 +89,6 @@ int create_config_entry()
f_puts("\nbootwait=", &fp);
itoa(h_cfg.bootwait, lbuf, 10);
f_puts(lbuf, &fp);
f_puts("\ncustomlogo=", &fp);
itoa(h_cfg.customlogo, lbuf, 10);
f_puts(lbuf, &fp);
f_puts("\nverification=", &fp);
itoa(h_cfg.verification, lbuf, 10);
f_puts(lbuf, &fp);
@@ -105,6 +98,9 @@ int create_config_entry()
f_puts("\nautohosoff=", &fp);
itoa(h_cfg.autohosoff, lbuf, 10);
f_puts(lbuf, &fp);
f_puts("\nautonogc=", &fp);
itoa(h_cfg.autonogc, lbuf, 10);
f_puts(lbuf, &fp);
f_puts("\n", &fp);
if (mainIniFound)
@@ -156,7 +152,19 @@ int create_config_entry()
return 0;
}
void _config_autoboot_list()
static void _save_config()
{
gfx_clear_grey(&gfx_ctxt, 0x1B);
gfx_con_setpos(&gfx_con, 0, 0);
if (!create_config_entry())
gfx_puts(&gfx_con, "\nConfiguration was saved!\n");
else
EPRINTF("\nConfiguration saving failed!");
gfx_puts(&gfx_con, "\nPress any key...");
}
static void _config_autoboot_list(void *ent)
{
gfx_clear_grey(&gfx_ctxt, 0x1B);
gfx_con_setpos(&gfx_con, 0, 0);
@@ -216,28 +224,23 @@ void _config_autoboot_list()
}
memset(&ments[i], 0, sizeof(ment_t));
menu_t menu = {ments, "Select a list entry to auto boot", 0, 0};
menu_t menu = {ments, "Select an entry to auto boot", 0, 0};
temp_autoboot = (u32 *)tui_do_menu(&gfx_con, &menu);
if (temp_autoboot != NULL)
{
gfx_clear_grey(&gfx_ctxt, 0x1B);
gfx_con_setpos(&gfx_con, 0, 0);
h_cfg.autoboot = *(u32 *)temp_autoboot;
h_cfg.autoboot_list = 1;
// Save choice to ini file.
if (!create_config_entry())
gfx_puts(&gfx_con, "\nConfiguration was saved!\n");
else
EPRINTF("\nConfiguration saving failed!");
gfx_puts(&gfx_con, "\nPress any key...");
_save_config();
ment_t *tmp = (ment_t *)ent;
tmp->data = NULL;
}
else
goto out2;
}
else
{
EPRINTF("Could not open 'bootloader/hekate_ipl.ini'.\nMake sure it exists in SD Card!.");
EPRINTF("Could not open 'bootloader/hekate_ipl.ini'.\nMake sure it exists!.");
goto out;
}
}
@@ -251,9 +254,6 @@ out2:;
ini_free(&ini_sections);
sd_unmount();
if (temp_autoboot == NULL)
return;
}
void config_autoboot()
@@ -291,13 +291,13 @@ void config_autoboot()
ments[2].caption = " Disable";
ments[2].data = &boot_values[0];
ments[3].type = MENT_HANDLER;
ments[3].type = MENT_HDLR_RE;
if (h_cfg.autoboot_list)
ments[3].caption = "*More configs...";
else
ments[3].caption = " More configs...";
ments[3].handler = _config_autoboot_list;
ments[3].data = NULL;
ments[3].data = (void *)0xCAFE;
ments[4].type = MENT_CHGLINE;
@@ -344,24 +344,16 @@ void config_autoboot()
temp_autoboot = (u32 *)tui_do_menu(&gfx_con, &menu);
if (temp_autoboot != NULL)
{
gfx_clear_grey(&gfx_ctxt, 0x1B);
gfx_con_setpos(&gfx_con, 0, 0);
h_cfg.autoboot = *(u32 *)temp_autoboot;
h_cfg.autoboot_list = 0;
// Save choice to ini file.
if (!create_config_entry())
gfx_puts(&gfx_con, "\nConfiguration was saved!\n");
else
EPRINTF("\nConfiguration saving failed!");
gfx_puts(&gfx_con, "\nPress any key...");
_save_config();
}
else
goto out2;
}
else
{
EPRINTF("Could not open 'bootloader/hekate_ipl.ini'.\nMake sure it exists in SD Card!.");
EPRINTF("Could not open 'bootloader/hekate_ipl.ini'.\nMake sure it exists!.");
goto out;
}
}
@@ -427,16 +419,8 @@ void config_bootdelay()
u32 *temp_bootwait = (u32 *)tui_do_menu(&gfx_con, &menu);
if (temp_bootwait != NULL)
{
gfx_clear_grey(&gfx_ctxt, 0x1B);
gfx_con_setpos(&gfx_con, 0, 0);
h_cfg.bootwait = *(u32 *)temp_bootwait;
// Save choice to ini file.
if (!create_config_entry())
gfx_puts(&gfx_con, "\nConfiguration was saved!\n");
else
EPRINTF("\nConfiguration saving failed!");
gfx_puts(&gfx_con, "\nPress any key...");
_save_config();
}
free(ments);
@@ -448,64 +432,6 @@ void config_bootdelay()
btn_wait();
}
void config_customlogo()
{
gfx_clear_grey(&gfx_ctxt, 0x1B);
gfx_con_setpos(&gfx_con, 0, 0);
ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * 5);
u32 *cb_values = (u32 *)malloc(sizeof(u32) * 2);
for (u32 j = 0; j < 2; j++)
{
cb_values[j] = j;
ments[j + 2].type = MENT_DATA;
ments[j + 2].data = &cb_values[j];
}
ments[0].type = MENT_BACK;
ments[0].caption = "Back";
ments[1].type = MENT_CHGLINE;
if (h_cfg.customlogo)
{
ments[2].caption = " Disable";
ments[3].caption = "*Enable";
}
else
{
ments[2].caption = "*Disable";
ments[3].caption = " Enable";
}
memset(&ments[4], 0, sizeof(ment_t));
menu_t menu = {ments, "Custom bootlogo", 0, 0};
u32 *temp_customlogo = (u32 *)tui_do_menu(&gfx_con, &menu);
if (temp_customlogo != NULL)
{
gfx_clear_grey(&gfx_ctxt, 0x1B);
gfx_con_setpos(&gfx_con, 0, 0);
h_cfg.customlogo = *(u32 *)temp_customlogo;
// Save choice to ini file.
if (!create_config_entry())
gfx_puts(&gfx_con, "\nConfiguration was saved!\n");
else
EPRINTF("\nConfiguration saving failed!");
gfx_puts(&gfx_con, "\nPress any key...");
}
free(ments);
free(cb_values);
if (temp_customlogo == NULL)
return;
btn_wait();
}
void config_verification()
{
gfx_clear_grey(&gfx_ctxt, 0x1B);
@@ -527,22 +453,17 @@ void config_verification()
ments[1].type = MENT_CHGLINE;
memcpy(vr_text, " Disable (Fastest)", 19);
memcpy(vr_text + 64, " Sparse (Fast - Not reliable)", 32);
memcpy(vr_text + 128, " Full (Slow - 100% reliable)", 32);
memcpy(vr_text, " Disable (Fastest - Unsafe)", 28);
memcpy(vr_text + 64, " Sparse (Fast - Safe)", 23);
memcpy(vr_text + 128, " Full (Slow - Safe)", 23);
for (u32 i = 0; i < 3; i++)
{
if (h_cfg.verification != i)
{
vr_text[64 * i] = ' ';
ments[2 + i].caption = vr_text + (i * 64);
}
else
{
vr_text[64 * i] = '*';
ments[2 + i].caption = vr_text + (i * 64);
}
ments[2 + i].caption = vr_text + (i * 64);
}
memset(&ments[5], 0, sizeof(ment_t));
@@ -551,16 +472,8 @@ void config_verification()
u32 *temp_verification = (u32 *)tui_do_menu(&gfx_con, &menu);
if (temp_verification != NULL)
{
gfx_clear_grey(&gfx_ctxt, 0x1B);
gfx_con_setpos(&gfx_con, 0, 0);
h_cfg.verification = *(u32 *)temp_verification;
// Save choice to ini file.
if (!create_config_entry())
gfx_puts(&gfx_con, "\nConfiguration was saved!\n");
else
EPRINTF("\nConfiguration saving failed!");
gfx_puts(&gfx_con, "\nPress any key...");
_save_config();
}
free(ments);
@@ -604,7 +517,6 @@ void config_backlight()
bri_text[i * 32 + 1] = i + '0';
memcpy(bri_text + i * 32 + 2, "0%", 3);
}
else
memcpy(bri_text + i * 32 + 1, "100%", 5);
@@ -619,16 +531,8 @@ void config_backlight()
u32 *temp_backlight = (u32 *)tui_do_menu(&gfx_con, &menu);
if (temp_backlight != NULL)
{
gfx_clear_grey(&gfx_ctxt, 0x1B);
gfx_con_setpos(&gfx_con, 0, 0);
h_cfg.backlight = (*(u32 *)temp_backlight) * 2;
//Save choice to ini file.
if (!create_config_entry())
gfx_puts(&gfx_con, "\nConfiguration was saved!\n");
else
EPRINTF("\nConfiguration saving failed!");
gfx_puts(&gfx_con, "\nPress any key...");
_save_config();
}
free(ments);
@@ -685,16 +589,8 @@ void config_auto_hos_poweroff()
u32 *temp_autohosoff = (u32 *)tui_do_menu(&gfx_con, &menu);
if (temp_autohosoff != NULL)
{
gfx_clear_grey(&gfx_ctxt, 0x1B);
gfx_con_setpos(&gfx_con, 0, 0);
h_cfg.autohosoff = *(u32 *)temp_autohosoff;
// Save choice to ini file.
if (!create_config_entry())
gfx_puts(&gfx_con, "\nConfiguration was saved!\n");
else
EPRINTF("\nConfiguration saving failed!");
gfx_puts(&gfx_con, "\nPress any key...");
_save_config();
}
free(ments);
@@ -704,3 +600,52 @@ void config_auto_hos_poweroff()
return;
btn_wait();
}
void config_nogc()
{
gfx_clear_grey(&gfx_ctxt, 0x1B);
gfx_con_setpos(&gfx_con, 0, 0);
ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * 5);
u32 *cb_values = (u32 *)malloc(sizeof(u32) * 2);
for (u32 j = 0; j < 2; j++)
{
cb_values[j] = j;
ments[j + 2].type = MENT_DATA;
ments[j + 2].data = &cb_values[j];
}
ments[0].type = MENT_BACK;
ments[0].caption = "Back";
ments[1].type = MENT_CHGLINE;
if (h_cfg.autonogc)
{
ments[2].caption = " Disable";
ments[3].caption = "*Auto";
}
else
{
ments[2].caption = "*Disable";
ments[3].caption = " Auto";
}
memset(&ments[4], 0, sizeof(ment_t));
menu_t menu = {ments, "No Gamecard", 0, 0};
u32 *temp_nogc = (u32 *)tui_do_menu(&gfx_con, &menu);
if (temp_nogc != NULL)
{
h_cfg.autonogc = *(u32 *)temp_nogc;
_save_config();
}
free(ments);
free(cb_values);
if (temp_nogc == NULL)
return;
btn_wait();
}

View File

@@ -1,5 +1,5 @@
/*
* 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,
@@ -25,14 +25,15 @@ typedef struct _hekate_config
u32 autoboot;
u32 autoboot_list;
u32 bootwait;
u32 customlogo;
u32 verification;
u32 backlight;
u32 autohosoff;
u32 errors;
u32 autonogc;
// Global temporary config.
int se_keygen_done;
u32 sbar_time_keeping;
u32 errors;
int sept_run;
} hekate_config;
typedef enum
@@ -44,9 +45,9 @@ void set_default_configuration();
int create_config_entry();
void config_autoboot();
void config_bootdelay();
void config_customlogo();
void config_verification();
void config_backlight();
void config_auto_hos_poweroff();
void config_nogc();
#endif /* _CONFIG_H_ */

View File

@@ -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,
@@ -24,11 +24,39 @@
static char *_strdup(char *str)
{
if (!str)
return NULL;
char *res = (char *)malloc(strlen(str) + 1);
strcpy(res, str);
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;
@@ -43,6 +71,7 @@ int ini_parse(link_t *dst, char *ini_path, bool is_dir)
memcpy(filename, ini_path, pathlen + 1);
// Get all ini filenames.
if (is_dir)
{
filelist = dirlist(filename, "*.ini", false);
@@ -57,6 +86,7 @@ int ini_parse(link_t *dst, char *ini_path, bool is_dir)
do
{
// Copy ini filename in path string.
if (is_dir)
{
if (filelist[k * 256])
@@ -68,6 +98,7 @@ int ini_parse(link_t *dst, char *ini_path, bool is_dir)
break;
}
// Open ini.
if (f_open(&fp, filename, FA_READ) != FR_OK)
{
free(filelist);
@@ -84,80 +115,36 @@ int ini_parse(link_t *dst, char *ini_path, bool is_dir)
lblen = strlen(lbuf);
// Remove trailing newline.
if (lbuf[lblen - 1] == '\n')
if (lbuf[lblen - 1] == '\n' || lbuf[lblen - 1] == '\r')
lbuf[lblen - 1] = 0;
if (lblen > 2 && lbuf[0] == '[') // Create new section.
{
if (csec)
{
list_append(dst, &csec->link);
csec = NULL;
}
_find_section_name(lbuf, lblen, ']');
u32 i;
for (i = 0; i < lblen && lbuf[i] != '\n' && lbuf[i] != ']'; i++)
;
lbuf[i] = 0;
csec = (ini_sec_t *)malloc(sizeof(ini_sec_t));
csec->name = _strdup(&lbuf[1]);
csec->type = INI_CHOICE;
csec = _ini_create_section(dst, csec, &lbuf[1], INI_CHOICE);
list_init(&csec->kvs);
}
else if (lblen > 2 && lbuf[0] == '{') //Create new caption.
{
if (csec)
{
list_append(dst, &csec->link);
csec = NULL;
}
_find_section_name(lbuf, lblen, '}');
u32 i;
for (i = 0; i < lblen && lbuf[i] != '\n' && lbuf[i] != '}'; i++)
;
lbuf[i] = 0;
csec = (ini_sec_t *)malloc(sizeof(ini_sec_t));
csec->name = _strdup(&lbuf[1]);
csec->type = INI_CAPTION;
csec = _ini_create_section(dst, csec, &lbuf[1], INI_CAPTION);
csec->color = 0xFF0AB9E6;
}
else if (lblen > 2 && lbuf[0] == '#') //Create empty lines and comments.
{
if (csec)
{
list_append(dst, &csec->link);
csec = NULL;
}
_find_section_name(lbuf, lblen, '\0');
u32 i;
for (i = 0; i < lblen && lbuf[i] != '\n'; i++)
;
lbuf[i] = 0;
csec = (ini_sec_t *)malloc(sizeof(ini_sec_t));
csec->name = _strdup(&lbuf[1]);
csec->type = INI_COMMENT;
csec = _ini_create_section(dst, csec, &lbuf[1], INI_COMMENT);
}
else if (lblen < 2)
{
if (csec)
{
list_append(dst, &csec->link);
csec = NULL;
}
csec = (ini_sec_t *)malloc(sizeof(ini_sec_t));
csec->name = NULL;
csec->type = INI_NEWLINE;
csec = _ini_create_section(dst, csec, NULL, INI_NEWLINE);
}
else if (csec && csec->type == INI_CHOICE) //Extract key/value.
{
u32 i;
for (i = 0; i < lblen && lbuf[i] != '\n' && lbuf[i] != '='; i++)
;
lbuf[i] = 0;
u32 i = _find_section_name(lbuf, lblen, '=');
ini_kv_t *kv = (ini_kv_t *)malloc(sizeof(ini_kv_t));
kv->key = _strdup(&lbuf[0]);
@@ -169,8 +156,11 @@ int ini_parse(link_t *dst, char *ini_path, bool is_dir)
f_close(&fp);
if (csec)
{
list_append(dst, &csec->link);
if (is_dir)
csec = NULL;
}
} while (is_dir);
free(filename);

View File

@@ -31,29 +31,27 @@
#include "../utils/btn.h"
#include "../utils/util.h"
#define EMMC_BUF_ALIGNED 0xB5000000
#define SDXC_BUF_ALIGNED 0xB6000000
#define MIXD_BUF_ALIGNED 0xB7000000
extern sdmmc_t sd_sdmmc;
extern sdmmc_storage_t sd_storage;
extern FATFS sd_fs;
extern hekate_config h_cfg;
extern gfx_ctxt_t gfx_ctxt;
extern gfx_con_t gfx_con;
extern bool sd_mount();
extern void sd_unmount();
extern void emmcsn_path_impl(char *path, char *sub_dir, char *filename, sdmmc_storage_t *storage);
//TODO: Create more macros (info, header, debug, etc) with different colors and utilize them for consistency.
#define EPRINTF(text) gfx_printf(&gfx_con, "%k"text"%k\n", 0xFFFF0000, 0xFFCCCCCC)
#define EPRINTFARGS(text, args...) gfx_printf(&gfx_con, "%k"text"%k\n", 0xFFFF0000, args, 0xFFCCCCCC)
#define WPRINTF(text) gfx_printf(&gfx_con, "%k"text"%k\n", 0xFFFFDD00, 0xFFCCCCCC)
#define WPRINTFARGS(text, args...) gfx_printf(&gfx_con, "%k"text"%k\n", 0xFFFFDD00, args, 0xFFCCCCCC)
int _dump_emmc_verify(sdmmc_storage_t *storage, u32 lba_curr, char *outFilename, emmc_part_t *part)
static int _dump_emmc_verify(sdmmc_storage_t *storage, u32 lba_curr, char *outFilename, emmc_part_t *part)
{
FIL fp;
u8 sparseShouldVerify = 0;
u32 btn = 0;
u32 prevPct = 200;
int res = 0;
u32 sdFileSector = 0;
u8 hashEm[0x20];
u8 hashSd[0x20];
@@ -62,14 +60,10 @@ int _dump_emmc_verify(sdmmc_storage_t *storage, u32 lba_curr, char *outFilename,
{
u32 totalSectorsVer = (u32)((u64)f_size(&fp) >> (u64)9);
u32 numSectorsPerIter = 0;
if (totalSectorsVer > 0x200000)
numSectorsPerIter = 8192; //4MB Cache
else
numSectorsPerIter = 512; //256KB Cache
const u32 NUM_SECTORS_PER_ITER = 8192; // 4MB Cache.
u8 *bufEm = (u8 *)calloc(numSectorsPerIter, NX_EMMC_BLOCKSIZE);
u8 *bufSd = (u8 *)calloc(numSectorsPerIter, NX_EMMC_BLOCKSIZE);
u8 *bufEm = (u8 *)EMMC_BUF_ALIGNED;
u8 *bufSd = (u8 *)SDXC_BUF_ALIGNED;
u32 pct = (u64)((u64)(lba_curr - part->lba_start) * 100u) / (u64)(part->lba_end - part->lba_start);
tui_pbar(&gfx_con, 0, gfx_con.y, pct, 0xFF96FF00, 0xFF155500);
@@ -77,53 +71,49 @@ int _dump_emmc_verify(sdmmc_storage_t *storage, u32 lba_curr, char *outFilename,
u32 num = 0;
while (totalSectorsVer > 0)
{
num = MIN(totalSectorsVer, numSectorsPerIter);
if (!sdmmc_storage_read(storage, lba_curr, num, bufEm))
num = MIN(totalSectorsVer, NUM_SECTORS_PER_ITER);
// Check every time or every 4.
// Every 4 protects from fake sd, sector corruption and frequent I/O corruption.
// Full provides all that, plus protection from extremely rare I/O corruption.
if ((h_cfg.verification & 2) || !(sparseShouldVerify % 4))
{
gfx_con.fntsz = 16;
EPRINTFARGS("\nFailed to read %d blocks (@LBA %08X),\nfrom eMMC!\n\nVerification failed..\n",
num, lba_curr);
if (!sdmmc_storage_read(storage, lba_curr, num, bufEm))
{
gfx_con.fntsz = 16;
EPRINTFARGS("\nFailed to read %d blocks (@LBA %08X),\nfrom eMMC!\n\nVerification failed..\n",
num, lba_curr);
f_close(&fp);
return 1;
}
f_lseek(&fp, sdFileSector);
if (f_read(&fp, bufSd, num << 9, NULL))
{
gfx_con.fntsz = 16;
EPRINTFARGS("\nFailed to read %d blocks (@LBA %08X),\nfrom sd card!\n\nVerification failed..\n", num, lba_curr);
f_close(&fp);
return 1;
}
free(bufEm);
free(bufSd);
f_close(&fp);
return 1;
}
if (f_read(&fp, bufSd, num << 9, NULL))
{
gfx_con.fntsz = 16;
EPRINTFARGS("\nFailed to read %d blocks (@LBA %08X),\nfrom sd card!\n\nVerification failed..\n", num, lba_curr);
free(bufEm);
free(bufSd);
f_close(&fp);
return 1;
}
switch (h_cfg.verification)
{
case 1:
res = memcmp32sparse((u32 *)bufEm, (u32 *)bufSd, num << 9);
break;
case 2:
default:
se_calc_sha256(&hashEm, bufEm, num << 9);
se_calc_sha256(&hashSd, bufSd, num << 9);
se_calc_sha256(hashEm, bufEm, num << 9);
se_calc_sha256(hashSd, bufSd, num << 9);
res = memcmp(hashEm, hashSd, 0x10);
break;
}
if (res)
{
gfx_con.fntsz = 16;
EPRINTFARGS("\nSD card and eMMC data (@LBA %08X),\ndo not match!\n\nVerification failed..\n", lba_curr);
free(bufEm);
free(bufSd);
f_close(&fp);
return 1;
if (res)
{
gfx_con.fntsz = 16;
EPRINTFARGS("\nSD and eMMC data (@LBA %08X),\ndo not match!\n\nVerification failed..\n", lba_curr);
f_close(&fp);
return 1;
}
}
sparseShouldVerify++;
sdFileSector += NUM_SECTORS_PER_ITER << 9;
pct = (u64)((u64)(lba_curr - part->lba_start) * 100u) / (u64)(part->lba_end - part->lba_start);
if (pct != prevPct)
{
@@ -138,19 +128,15 @@ int _dump_emmc_verify(sdmmc_storage_t *storage, u32 lba_curr, char *outFilename,
if ((btn & BTN_VOL_DOWN) && (btn & BTN_VOL_UP))
{
gfx_con.fntsz = 16;
WPRINTF("\n\nThe verification was cancelled!");
WPRINTF("\n\nVerification was cancelled!");
EPRINTF("\nPress any key...\n");
msleep(1500);
msleep(1000);
free(bufEm);
free(bufSd);
f_close(&fp);
return 0;
}
}
free(bufEm);
free(bufSd);
f_close(&fp);
tui_pbar(&gfx_con, 0, gfx_con.y, pct, 0xFFCCCCCC, 0xFF555555);
@@ -165,7 +151,18 @@ int _dump_emmc_verify(sdmmc_storage_t *storage, u32 lba_curr, char *outFilename,
}
}
int _dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t *part)
void _update_filename(char *outFilename, u32 sdPathLen, u32 numSplitParts, u32 currPartIdx)
{
if (numSplitParts >= 10 && currPartIdx < 10)
{
outFilename[sdPathLen] = '0';
itoa(currPartIdx, &outFilename[sdPathLen + 1], 10);
}
else
itoa(currPartIdx, &outFilename[sdPathLen], 10);
}
static int _dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t *part)
{
static const u32 FAT32_FILESIZE_LIMIT = 0xFFFFFFFF;
static const u32 SECTORS_TO_MIB_COEFF = 11;
@@ -195,7 +192,7 @@ int _dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t *part)
if ((sd_storage.csd.capacity >> (20 - sd_storage.csd.read_blkbits)) <= 8192)
multipartSplitSize = (1u << 30);
// Maximum parts fitting the free space available.
maxSplitParts = (sd_fs.free_clst * sd_fs.csize) / (multipartSplitSize / 512);
maxSplitParts = (sd_fs.free_clst * sd_fs.csize) / (multipartSplitSize / NX_EMMC_BLOCKSIZE);
// Check if the USER partition or the RAW eMMC fits the sd card free space.
if (totalSectors > (sd_fs.free_clst * sd_fs.csize))
@@ -246,28 +243,8 @@ int _dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t *part)
outFilename[sdPathLen++] = '.';
if (!partialDumpInProgress)
{
outFilename[sdPathLen] = '0';
if (numSplitParts >= 10)
{
outFilename[sdPathLen + 1] = '0';
outFilename[sdPathLen + 2] = 0;
}
else
outFilename[sdPathLen + 1] = 0;
}
// Continue from where we left, if Partial Backup in progress.
else
{
if (numSplitParts >= 10 && currPartIdx < 10)
{
outFilename[sdPathLen] = '0';
itoa(currPartIdx, &outFilename[sdPathLen + 1], 10);
}
else
itoa(currPartIdx, &outFilename[sdPathLen], 10);
}
_update_filename(outFilename, sdPathLen, numSplitParts, partialDumpInProgress ? currPartIdx : 0);
}
FIL fp;
@@ -276,7 +253,7 @@ int _dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t *part)
{
f_close(&fp);
gfx_con.fntsz = 16;
WPRINTF("An existing backup has been detected!");
WPRINTF("Press POWER to Continue.\nPress VOL to go to the menu.\n");
msleep(500);
@@ -297,12 +274,9 @@ int _dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t *part)
return 0;
}
u32 numSectorsPerIter = 0;
if (totalSectors > 0x200000)
numSectorsPerIter = 8192;
else
numSectorsPerIter = 512;
u8 *buf = (u8 *)calloc(numSectorsPerIter, NX_EMMC_BLOCKSIZE);
const u32 NUM_SECTORS_PER_ITER = 8192;
u8 *buf = (u8 *)MIXD_BUF_ALIGNED;
u32 lba_curr = part->lba_start;
u32 lbaStartPart = part->lba_start;
@@ -341,18 +315,11 @@ int _dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t *part)
{
EPRINTF("\nPress any key and try again...\n");
free(buf);
return 0;
}
}
if (numSplitParts >= 10 && currPartIdx < 10)
{
outFilename[sdPathLen] = '0';
itoa(currPartIdx, &outFilename[sdPathLen + 1], 10);
}
else
itoa(currPartIdx, &outFilename[sdPathLen], 10);
_update_filename(outFilename, sdPathLen, numSplitParts, currPartIdx);
// Always create partial.idx before next part, in case a fatal error occurs.
if (isSmallSdCard)
@@ -368,7 +335,6 @@ int _dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t *part)
gfx_con.fntsz = 16;
EPRINTF("\nError creating partial.idx file.\n");
free(buf);
return 0;
}
@@ -382,7 +348,6 @@ int _dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t *part)
4. Select the SAME option again to continue.\n");
gfx_con.fntsz = 16;
free(buf);
return 1;
}
}
@@ -397,7 +362,6 @@ int _dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t *part)
gfx_con.fntsz = 16;
EPRINTFARGS("Error (%d) creating file %s.\n", res, outFilename);
free(buf);
return 0;
}
bytesWritten = 0;
@@ -408,7 +372,7 @@ int _dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t *part)
}
retryCount = 0;
num = MIN(totalSectors, numSectorsPerIter);
num = MIN(totalSectors, NUM_SECTORS_PER_ITER);
while (!sdmmc_storage_read(storage, lba_curr, num, buf))
{
EPRINTFARGS("Error reading %d blocks @ LBA %08X,\nfrom eMMC (try %d), retrying...",
@@ -422,7 +386,6 @@ int _dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t *part)
num, lba_curr);
EPRINTF("\nPress any key and try again...\n");
free(buf);
f_close(&fp);
f_unlink(outFilename);
@@ -436,7 +399,6 @@ int _dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t *part)
EPRINTFARGS("\nFatal error (%d) when writing to SD Card", res);
EPRINTF("\nPress any key and try again...\n");
free(buf);
f_close(&fp);
f_unlink(outFilename);
@@ -468,7 +430,6 @@ int _dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t *part)
EPRINTF("\nPress any key...\n");
msleep(1500);
free(buf);
f_close(&fp);
f_unlink(outFilename);
@@ -478,7 +439,6 @@ int _dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t *part)
tui_pbar(&gfx_con, 0, gfx_con.y, 100, 0xFFCCCCCC, 0xFF555555);
// Backup operation ended successfully.
free(buf);
f_close(&fp);
if (h_cfg.verification)
@@ -635,30 +595,90 @@ void dump_emmc_user() { _dump_emmc_selected(PART_USER); }
void dump_emmc_boot() { _dump_emmc_selected(PART_BOOT); }
void dump_emmc_rawnand() { _dump_emmc_selected(PART_RAW); }
int _restore_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t *part)
static int _restore_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t *part, bool allow_multi_part)
{
static const u32 SECTORS_TO_MIB_COEFF = 11;
u32 totalSectors = part->lba_end - part->lba_start + 1;
u32 currPartIdx = 0;
u32 numSplitParts = 0;
u32 lbaStartPart = part->lba_start;
int res = 0;
char *outFilename = sd_path;
u32 sdPathLen = strlen(sd_path);
u64 fileSize = 0;
u64 totalCheckFileSize = 0;
gfx_con.fntsz = 8;
FIL fp;
FILINFO fno;
gfx_printf(&gfx_con, "\nFilename: %s\n", outFilename);
bool use_multipart = false;
if (allow_multi_part)
{
// Check to see if there is a combined file and if so then use that.
if (f_stat(outFilename, &fno))
{
// If not, check if there are partial files and the total size matches.
gfx_printf(&gfx_con, "\nFile not found, checking for part files.\n");
// Store console pos, so we dont take too much room.
gfx_con_getpos(&gfx_con, &gfx_con.savedx, &gfx_con.savedy);
outFilename[sdPathLen++] = '.';
// Stat total size of the part files.
while ((u32)((u64)totalCheckFileSize >> (u64)9) != totalSectors)
{
_update_filename(outFilename, sdPathLen, 99, numSplitParts);
gfx_con_setpos(&gfx_con, gfx_con.savedx, gfx_con.savedy);
gfx_printf(&gfx_con, "\nFilename: %s\n", outFilename);
if (f_stat(outFilename, &fno))
{
WPRINTFARGS("Error (%d) file not found '%s'. Aborting...\n", res, outFilename);
return 0;
}
else
totalCheckFileSize += (u64)fno.fsize;
numSplitParts++;
}
gfx_printf(&gfx_con, "\n%X sectors total.\n", (u32)((u64)totalCheckFileSize >> (u64)9));
if ((u32)((u64)totalCheckFileSize >> (u64)9) != totalSectors)
{
gfx_con.fntsz = 16;
EPRINTF("Size of SD Card split backups does not match,\neMMC's selected part size.\n");
return 0;
}
else
{
use_multipart = true;
_update_filename(outFilename, sdPathLen, numSplitParts, 0);
}
}
}
gfx_con_setpos(&gfx_con, gfx_con.savedx, gfx_con.savedy);
res = f_open(&fp, outFilename, FA_READ);
if (res)
{
WPRINTFARGS("Error (%d) while opening backup. Continuing...\n", res);
if (res != FR_NO_FILE)
EPRINTFARGS("Error (%d) while opening backup. Continuing...\n", res);
else
WPRINTFARGS("Error (%d) file not found. Continuing...\n", res);
gfx_con.fntsz = 16;
return 0;
}
//TODO: Should we keep this check?
else if (((u32)((u64)f_size(&fp) >> (u64)9)) != totalSectors)
else if (!use_multipart && (((u32)((u64)f_size(&fp) >> (u64)9)) != totalSectors)) // Check total restore size vs emmc size.
{
gfx_con.fntsz = 16;
EPRINTF("Size of the SD Card backup does not match,\neMMC's selected part size.\n");
@@ -667,15 +687,15 @@ int _restore_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t *par
return 0;
}
else
gfx_printf(&gfx_con, "\nTotal restore size: %d MiB.\n\n", ((u32)((u64)f_size(&fp) >> (u64)9)) >> SECTORS_TO_MIB_COEFF);
{
fileSize = (u64)f_size(&fp);
gfx_printf(&gfx_con, "\nTotal restore size: %d MiB.\n\n",
((u32)((use_multipart ? ((u64)totalCheckFileSize >> (u64)9) : fileSize) >> (u64)9)) >> SECTORS_TO_MIB_COEFF);
}
u32 numSectorsPerIter = 0;
if (totalSectors > 0x200000)
numSectorsPerIter = 8192; //4MB Cache
else
numSectorsPerIter = 512; //256KB Cache
const u32 NUM_SECTORS_PER_ITER = 8192; // 4MB Cache.
u8 *buf = (u8 *)calloc(numSectorsPerIter, NX_EMMC_BLOCKSIZE);
u8 *buf = (u8 *)MIXD_BUF_ALIGNED;
u32 lba_curr = part->lba_start;
u32 bytesWritten = 0;
@@ -684,10 +704,53 @@ int _restore_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t *par
u32 num = 0;
u32 pct = 0;
gfx_con_getpos(&gfx_con, &gfx_con.savedx, &gfx_con.savedy);
while (totalSectors > 0)
{
// If we have more than one part, check the size for the split parts and make sure that the bytes written is not more than that.
if (numSplitParts != 0 && bytesWritten >= fileSize)
{
// If we have more bytes written then close the file pointer and increase the part index we are using
f_close(&fp);
memset(&fp, 0, sizeof(fp));
currPartIdx++;
if (h_cfg.verification)
{
// Verify part.
if (_dump_emmc_verify(storage, lbaStartPart, outFilename, part))
{
EPRINTF("\nPress any key and try again...\n");
return 0;
}
}
_update_filename(outFilename, sdPathLen, numSplitParts, currPartIdx);
// Read from next part.
gfx_con_setpos(&gfx_con, gfx_con.savedx, gfx_con.savedy);
gfx_printf(&gfx_con, "Filename: %s\n\n", outFilename);
lbaStartPart = lba_curr;
// Try to open the next file part
res = f_open(&fp, outFilename, FA_READ);
if (res)
{
gfx_con.fntsz = 16;
EPRINTFARGS("Error (%d) opening file %s.\n", res, outFilename);
return 0;
}
fileSize = (u64)f_size(&fp);
bytesWritten = 0;
}
retryCount = 0;
num = MIN(totalSectors, numSectorsPerIter);
num = MIN(totalSectors, NUM_SECTORS_PER_ITER);
res = f_read(&fp, buf, NX_EMMC_BLOCKSIZE * num, NULL);
if (res)
@@ -696,7 +759,6 @@ int _restore_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t *par
EPRINTFARGS("\nFatal error (%d) when reading from SD Card", res);
EPRINTF("\nYour device may be in an inoperative state!\n\nPress any key and try again now...\n");
free(buf);
f_close(&fp);
return 0;
}
@@ -713,7 +775,6 @@ int _restore_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t *par
num, lba_curr);
EPRINTF("\nYour device may be in an inoperative state!\n\nPress any key and try again...\n");
free(buf);
f_close(&fp);
return 0;
}
@@ -732,7 +793,6 @@ int _restore_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t *par
tui_pbar(&gfx_con, 0, gfx_con.y, 100, 0xFFCCCCCC, 0xFF555555);
// Restore operation ended successfully.
free(buf);
f_close(&fp);
if (h_cfg.verification)
@@ -762,7 +822,7 @@ static void _restore_emmc_selected(emmcPartType_t restoreType)
tui_sbar(&gfx_con, true);
gfx_con_setpos(&gfx_con, 0, 0);
gfx_printf(&gfx_con, "%kThis is a dangerous operation\nand may render your device inoperative!\n\n", 0xFFFFDD00);
gfx_printf(&gfx_con, "%kThis may render your device inoperative!\n\n", 0xFFFFDD00);
gfx_printf(&gfx_con, "Are you really sure?\n\n%k", 0xFFCCCCCC);
if ((restoreType & PART_BOOT) || (restoreType & PART_GP_ALL))
{
@@ -774,13 +834,13 @@ static void _restore_emmc_selected(emmcPartType_t restoreType)
}
gfx_con_getpos(&gfx_con, &gfx_con.savedx, &gfx_con.savedy);
u8 value = 10;
while (value > 0)
u8 failsafe_wait = 10;
while (failsafe_wait > 0)
{
gfx_con_setpos(&gfx_con, gfx_con.savedx, gfx_con.savedy);
gfx_printf(&gfx_con, "%kWait... (%ds) %k", 0xFF888888, value, 0xFFCCCCCC);
gfx_printf(&gfx_con, "%kWait... (%ds) %k", 0xFF888888, failsafe_wait, 0xFFCCCCCC);
msleep(1000);
value--;
failsafe_wait--;
}
gfx_con_setpos(&gfx_con, gfx_con.savedx, gfx_con.savedy);
@@ -825,7 +885,7 @@ static void _restore_emmc_selected(emmcPartType_t restoreType)
sdmmc_storage_set_mmc_partition(&storage, i + 1);
emmcsn_path_impl(sdPath, "/restore", bootPart.name, &storage);
res = _restore_emmc_part(sdPath, &storage, &bootPart);
res = _restore_emmc_part(sdPath, &storage, &bootPart, false);
}
}
@@ -841,7 +901,7 @@ static void _restore_emmc_selected(emmcPartType_t restoreType)
part->name, part->lba_start, part->lba_end, 0xFFCCCCCC);
emmcsn_path_impl(sdPath, "/restore/partitions/", part->name, &storage);
res = _restore_emmc_part(sdPath, &storage, part);
res = _restore_emmc_part(sdPath, &storage, part, false);
}
nx_emmc_gpt_free(&gpt);
}
@@ -861,7 +921,7 @@ static void _restore_emmc_selected(emmcPartType_t restoreType)
rawPart.name, rawPart.lba_start, rawPart.lba_end, 0xFFCCCCCC);
emmcsn_path_impl(sdPath, "/restore", rawPart.name, &storage);
res = _restore_emmc_part(sdPath, &storage, &rawPart);
res = _restore_emmc_part(sdPath, &storage, &rawPart, true);
}
}

View File

@@ -1,6 +1,6 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (c) 2018 CTCaer
* Copyright (c) 2018-2019 CTCaer
* Copyright (c) 2018 balika011
*
* This program is free software; you can redistribute it and/or modify it
@@ -38,8 +38,6 @@
#include "../utils/btn.h"
#include "../utils/util.h"
extern gfx_ctxt_t gfx_ctxt;
extern gfx_con_t gfx_con;
extern sdmmc_storage_t sd_storage;
extern FATFS sd_fs;
@@ -48,12 +46,6 @@ extern void sd_unmount();
extern int sd_save_to_file(void *buf, u32 size, const char *filename);
extern void emmcsn_path_impl(char *path, char *sub_dir, char *filename, sdmmc_storage_t *storage);
//TODO: Create more macros (info, header, debug, etc) with different colors and utilize them for consistency.
#define EPRINTF(text) gfx_printf(&gfx_con, "%k"text"%k\n", 0xFFFF0000, 0xFFCCCCCC)
#define EPRINTFARGS(text, args...) gfx_printf(&gfx_con, "%k"text"%k\n", 0xFFFF0000, args, 0xFFCCCCCC)
#define WPRINTF(text) gfx_printf(&gfx_con, "%k"text"%k\n", 0xFFFFDD00, 0xFFCCCCCC)
#define WPRINTFARGS(text, args...) gfx_printf(&gfx_con, "%k"text"%k\n", 0xFFFFDD00, args, 0xFFCCCCCC)
void print_fuseinfo()
{
gfx_clear_partial_grey(&gfx_ctxt, 0x1B, 0, 1256);
@@ -77,7 +69,7 @@ void print_fuseinfo()
break;
}
gfx_printf(&gfx_con, "Sdram ID: %d\n", (fuse_read_odm(4) >> 3) & 0x1F);
gfx_printf(&gfx_con, "Burnt fuses: %d\n", burntFuses);
gfx_printf(&gfx_con, "Burnt fuses: %d / 64\n", burntFuses);
gfx_printf(&gfx_con, "Secure key: %08X%08X%08X%08X\n\n\n",
byte_swap_32(FUSE(FUSE_PRIVATE_KEY0)), byte_swap_32(FUSE(FUSE_PRIVATE_KEY1)),
byte_swap_32(FUSE(FUSE_PRIVATE_KEY2)), byte_swap_32(FUSE(FUSE_PRIVATE_KEY3)));
@@ -85,7 +77,7 @@ void print_fuseinfo()
gfx_printf(&gfx_con, "%k(Unlocked) fuse cache:\n\n%k", 0xFF00DDFF, 0xFFCCCCCC);
gfx_hexdump(&gfx_con, 0x7000F900, (u8 *)0x7000F900, 0x2FC);
gfx_puts(&gfx_con, "Press POWER to dump them to SD Card.\nPress VOL to go to the menu.\n");
gfx_puts(&gfx_con, "\nPress POWER to dump them to SD Card.\nPress VOL to go to the menu.\n");
u32 btn = btn_wait();
if (btn & BTN_POWER)
@@ -349,7 +341,6 @@ void print_tsec_key()
gfx_con_setpos(&gfx_con, 0, 0);
u32 retries = 0;
u32 key_ver_max = 3;
tsec_ctxt_t tsec_ctxt;
sdmmc_storage_t storage;
@@ -365,85 +356,70 @@ void print_tsec_key()
const pkg1_id_t *pkg1_id = pkg1_identify(pkg1);
if (!pkg1_id)
{
EPRINTFARGS("Unknown package1 version for reading\nTSEC firmware (= '%s').",
(char *)pkg1 + 0x10);
EPRINTF("Unknown pkg1 version for reading\nTSEC firmware.");
goto out_wait;
}
u8 keys[0x10 * 3];
u8 keys[0x10 * 2];
memset(keys, 0x00, 0x20);
tsec_ctxt.size = 0xF00;
tsec_ctxt.fw = (u8 *)pkg1 + pkg1_id->tsec_off;
tsec_ctxt.pkg1 = pkg1;
tsec_ctxt.pkg11_off = pkg1_id->pkg11_off;
tsec_ctxt.secmon_base = pkg1_id->secmon_base;
if (pkg1_id->kb >= KB_FIRMWARE_VERSION_620)
{
if (pkg1_id->kb <= KB_FIRMWARE_VERSION_600)
tsec_ctxt.size = 0xF00;
else if (pkg1_id->kb == KB_FIRMWARE_VERSION_620)
tsec_ctxt.size = 0x2900;
else
{
tsec_ctxt.size = 0x3000;
// Exit after TSEC key generation.
*((vu16 *)((u32)tsec_ctxt.fw + 0x2DB5)) = 0x02F8;
}
if (pkg1_id->kb == KB_FIRMWARE_VERSION_620)
{
u8 *tsec_paged = (u8 *)page_alloc(3);
memcpy(tsec_paged, (void *)tsec_ctxt.fw, tsec_ctxt.size);
tsec_ctxt.fw = tsec_paged;
key_ver_max = 1;
}
for (u32 i = 1; i <= key_ver_max; i++)
int res = 0;
while (tsec_query(keys, pkg1_id->kb, &tsec_ctxt) < 0)
{
tsec_ctxt.key_ver = i;
int res = 0;
memset(keys, 0x00, 0x20);
while (tsec_query(keys + ((i - 1) * 0x10), pkg1_id->kb, &tsec_ctxt) < 0)
retries++;
if (retries > 3)
{
if (pkg1_id->kb <= KB_FIRMWARE_VERSION_600)
memset(keys + ((i - 1) * 0x10), 0x00, 0x10);
else
memset(keys, 0x00, 0x30);
retries++;
if (retries > 3)
{
res = -1;
break;
}
res = -1;
break;
}
if (pkg1_id->kb <= KB_FIRMWARE_VERSION_600)
{
gfx_printf(&gfx_con, "%kTSEC key %d: %k", 0xFF00DDFF, i, 0xFFCCCCCC);
if (res >= 0)
{
for (u32 j = 0; j < 0x10; j++)
gfx_printf(&gfx_con, "%02X", keys[((i - 1) * 0x10) + j]);
}
else
EPRINTFARGS("ERROR %X", res);
gfx_putc(&gfx_con, '\n');
}
else
{
gfx_printf(&gfx_con, "%kTSEC key: %k", 0xFF00DDFF, 0xFFCCCCCC);
if (res >= 0)
{
for (u32 j = 0; j < 0x10; j++)
gfx_printf(&gfx_con, "%02X", keys[j]);
gfx_putc(&gfx_con, '\n');
gfx_printf(&gfx_con, "%kTSEC root: %k", 0xFF00DDFF, 0xFFCCCCCC);
for (u32 j = 0; j < 0x10; j++)
gfx_printf(&gfx_con, "%02X", keys[0x10 + j]);
}
else
EPRINTFARGS("ERROR %X", res);
gfx_putc(&gfx_con, '\n');
}
}
gfx_puts(&gfx_con, "\nPress POWER to dump them to SD Card.\nPress VOL to go to the menu.\n");
gfx_printf(&gfx_con, "%kTSEC key: %k", 0xFF00DDFF, 0xFFCCCCCC);
if (res >= 0)
{
for (u32 j = 0; j < 0x10; j++)
gfx_printf(&gfx_con, "%02X", keys[j]);
if (pkg1_id->kb == KB_FIRMWARE_VERSION_620)
{
gfx_printf(&gfx_con, "\n%kTSEC root: %k", 0xFF00DDFF, 0xFFCCCCCC);
for (u32 j = 0; j < 0x10; j++)
gfx_printf(&gfx_con, "%02X", keys[0x10 + j]);
}
}
else
EPRINTFARGS("ERROR %X\n", res);
gfx_puts(&gfx_con, "\n\nPress POWER to dump them to SD Card.\nPress VOL to go to the menu.\n");
u32 btn = btn_wait();
if (btn & BTN_POWER)
@@ -452,7 +428,7 @@ void print_tsec_key()
{
char path[64];
emmcsn_path_impl(path, "/dumps", "tsec_keys.bin", NULL);
if (!sd_save_to_file(keys, 0x10 * 3, path))
if (!sd_save_to_file(keys, 0x10 * 2, path))
gfx_puts(&gfx_con, "\nDone!\n");
sd_unmount();
}
@@ -637,11 +613,11 @@ void _ipatch_process(u32 offset, u32 value)
u8 lo = value & 0xff;
switch (value >> 8)
{
case 0xdf:
gfx_printf(&gfx_con, " svc #0x%02x", lo);
break;
case 0x20:
gfx_printf(&gfx_con, " movs r0, #0x%02x", lo);
gfx_printf(&gfx_con, " MOVS R0, #0x%02X", lo);
break;
case 0xDF:
gfx_printf(&gfx_con, " SVC #0x%02X", lo);
break;
}
gfx_puts(&gfx_con, "\n");
@@ -657,7 +633,7 @@ void bootrom_ipatches_info()
u32 res = fuse_read_ipatch(_ipatch_process);
if (res != 0)
EPRINTFARGS("Failed to read ipatches. Error: %d", res);
gfx_puts(&gfx_con, "\nPress POWER to dump them to SD Card.\nPress VOL to go to the menu.\n");
u32 btn = btn_wait();
@@ -688,15 +664,15 @@ void bootrom_ipatches_info()
if (!sd_save_to_file((u8 *)BOOTROM_BASE, BOOTROM_SIZE, path))
gfx_puts(&gfx_con, "\nbootrom_patched.bin saved!\n");
u8 ipatch_backup[13];
memcpy(ipatch_backup, (void *) IPATCH_BASE, 13);
memset((void*)IPATCH_BASE, 0, 13);
u32 ipatch_backup[14];
memcpy(ipatch_backup, (void *)IPATCH_BASE, sizeof(ipatch_backup));
memset((void*)IPATCH_BASE, 0, sizeof(ipatch_backup));
emmcsn_path_impl(path, "/dumps", "bootrom_unpatched.bin", NULL);
if (!sd_save_to_file((u8 *)BOOTROM_BASE, BOOTROM_SIZE, path))
gfx_puts(&gfx_con, "\nbootrom_unpatched.bin saved!\n");
memcpy((void*)IPATCH_BASE, ipatch_backup, 13);
memcpy((void*)IPATCH_BASE, ipatch_backup, sizeof(ipatch_backup));
sd_unmount();
}

View File

@@ -1,6 +1,6 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (c) 2018 CTCaer
* Copyright (c) 2018-2019 CTCaer
* Copyright (c) 2018 Reisyukaku
*
* This program is free software; you can redistribute it and/or modify it
@@ -26,6 +26,7 @@
#include "../hos/hos.h"
#include "../hos/pkg1.h"
#include "../hos/pkg2.h"
#include "../hos/sept.h"
#include "../libs/fatfs/ff.h"
#include "../mem/heap.h"
#include "../power/max7762x.h"
@@ -35,20 +36,14 @@
#include "../utils/btn.h"
#include "../utils/util.h"
extern boot_cfg_t b_cfg;
extern hekate_config h_cfg;
extern gfx_ctxt_t gfx_ctxt;
extern gfx_con_t gfx_con;
extern sdmmc_storage_t sd_storage;
extern bool sd_mount();
extern void sd_unmount();
extern int sd_save_to_file(void *buf, u32 size, const char *filename);
extern void emmcsn_path_impl(char *path, char *sub_dir, char *filename, sdmmc_storage_t *storage);
//TODO: Create more macros (info, header, debug, etc) with different colors and utilize them for consistency.
#define EPRINTF(text) gfx_printf(&gfx_con, "%k"text"%k\n", 0xFFFF0000, 0xFFCCCCCC)
#define EPRINTFARGS(text, args...) gfx_printf(&gfx_con, "%k"text"%k\n", 0xFFFF0000, args, 0xFFCCCCCC)
void dump_packages12()
{
if (!sd_mount())
@@ -82,20 +77,34 @@ void dump_packages12()
if (!pkg1_id)
{
gfx_con.fntsz = 8;
EPRINTFARGS("Unknown package1 version for reading\nTSEC firmware (= '%s').", (char *)pkg1 + 0x10);
EPRINTF("Unknown pkg1 version for reading\nTSEC firmware.");
goto out_free;
}
kb = pkg1_id->kb;
if (!h_cfg.se_keygen_done || kb >= KB_FIRMWARE_VERSION_620)
if (!h_cfg.se_keygen_done || kb == KB_FIRMWARE_VERSION_620)
{
tsec_ctxt.key_ver = 1;
tsec_ctxt.fw = (void *)pkg1 + pkg1_id->tsec_off;
tsec_ctxt.pkg1 = (void *)pkg1;
tsec_ctxt.pkg11_off = pkg1_id->pkg11_off;
tsec_ctxt.secmon_base = pkg1_id->secmon_base;
if (kb >= KB_FIRMWARE_VERSION_700 && !h_cfg.sept_run)
{
b_cfg.autoboot = 0;
b_cfg.autoboot_list = 0;
gfx_printf(&gfx_con, "sept will run to get the keys.\nThen rerun this option.");
btn_wait();
if (!reboot_to_sept((u8 *)tsec_ctxt.fw))
{
gfx_printf(&gfx_con, "Failed to run sept\n");
goto out_free;
}
}
// Read keyblob.
u8 *keyblob = (u8 *)calloc(NX_EMMC_BLOCKSIZE, 1);
sdmmc_storage_read(&storage, 0x180000 / NX_EMMC_BLOCKSIZE + kb, 1, keyblob);
@@ -110,41 +119,45 @@ void dump_packages12()
if (kb <= KB_FIRMWARE_VERSION_600)
pkg1_decrypt(pkg1_id, pkg1);
pkg1_unpack(warmboot, secmon, loader, pkg1_id, pkg1);
// Display info.
gfx_printf(&gfx_con, "%kNX Bootloader size: %k0x%05X\n\n", 0xFFC7EA46, 0xFFCCCCCC, hdr->ldr_size);
gfx_printf(&gfx_con, "%kSecure monitor addr: %k0x%05X\n", 0xFFC7EA46, 0xFFCCCCCC, pkg1_id->secmon_base);
gfx_printf(&gfx_con, "%kSecure monitor size: %k0x%05X\n\n", 0xFFC7EA46, 0xFFCCCCCC, hdr->sm_size);
gfx_printf(&gfx_con, "%kWarmboot addr: %k0x%05X\n", 0xFFC7EA46, 0xFFCCCCCC, pkg1_id->warmboot_base);
gfx_printf(&gfx_con, "%kWarmboot size: %k0x%05X\n\n", 0xFFC7EA46, 0xFFCCCCCC, hdr->wb_size);
char path[64];
// Dump package1.1.
emmcsn_path_impl(path, "/pkg1", "pkg1_decr.bin", &storage);
if (sd_save_to_file(pkg1, 0x40000, path))
goto out_free;
gfx_puts(&gfx_con, "\nFull package1 dumped to pkg1_decr.bin\n");
// Dump nxbootloader.
emmcsn_path_impl(path, "/pkg1", "nxloader.bin", &storage);
if (sd_save_to_file(loader, hdr->ldr_size, path))
goto out_free;
gfx_puts(&gfx_con, "NX Bootloader dumped to nxloader.bin\n");
if (kb <= KB_FIRMWARE_VERSION_620)
{
pkg1_unpack(warmboot, secmon, loader, pkg1_id, pkg1);
// Display info.
gfx_printf(&gfx_con, "%kNX Bootloader size: %k0x%05X\n\n", 0xFFC7EA46, 0xFFCCCCCC, hdr->ldr_size);
gfx_printf(&gfx_con, "%kSecure monitor addr: %k0x%05X\n", 0xFFC7EA46, 0xFFCCCCCC, pkg1_id->secmon_base);
gfx_printf(&gfx_con, "%kSecure monitor size: %k0x%05X\n\n", 0xFFC7EA46, 0xFFCCCCCC, hdr->sm_size);
gfx_printf(&gfx_con, "%kWarmboot addr: %k0x%05X\n", 0xFFC7EA46, 0xFFCCCCCC, pkg1_id->warmboot_base);
gfx_printf(&gfx_con, "%kWarmboot size: %k0x%05X\n\n", 0xFFC7EA46, 0xFFCCCCCC, hdr->wb_size);
// Dump secmon.
emmcsn_path_impl(path, "/pkg1", "secmon.bin", &storage);
if (sd_save_to_file(secmon, hdr->sm_size, path))
goto out_free;
gfx_puts(&gfx_con, "Secure Monitor dumped to secmon.bin\n");
// Dump warmboot.
emmcsn_path_impl(path, "/pkg1", "warmboot.bin", &storage);
if (sd_save_to_file(warmboot, hdr->wb_size, path))
goto out_free;
gfx_puts(&gfx_con, "Warmboot dumped to warmboot.bin\n\n\n");
// Dump package1.1.
emmcsn_path_impl(path, "/pkg1", "pkg1_decr.bin", &storage);
if (sd_save_to_file(pkg1, 0x40000, path))
goto out_free;
gfx_puts(&gfx_con, "\npkg1 dumped to pkg1_decr.bin\n");
// Dump nxbootloader.
emmcsn_path_impl(path, "/pkg1", "nxloader.bin", &storage);
if (sd_save_to_file(loader, hdr->ldr_size, path))
goto out_free;
gfx_puts(&gfx_con, "NX Bootloader dumped to nxloader.bin\n");
// Dump secmon.
emmcsn_path_impl(path, "/pkg1", "secmon.bin", &storage);
if (sd_save_to_file(secmon, hdr->sm_size, path))
goto out_free;
gfx_puts(&gfx_con, "Secure Monitor dumped to secmon.bin\n");
// Dump warmboot.
emmcsn_path_impl(path, "/pkg1", "warmboot.bin", &storage);
if (sd_save_to_file(warmboot, hdr->wb_size, path))
goto out_free;
gfx_puts(&gfx_con, "Warmboot dumped to warmboot.bin\n\n\n");
}
// Dump package2.1.
sdmmc_storage_set_mmc_partition(&storage, 0);
@@ -180,7 +193,7 @@ void dump_packages12()
emmcsn_path_impl(path, "/pkg2", "pkg2_decr.bin", &storage);
if (sd_save_to_file(pkg2, pkg2_hdr->sec_size[PKG2_SEC_KERNEL] + pkg2_hdr->sec_size[PKG2_SEC_INI1], path))
goto out;
gfx_puts(&gfx_con, "\nFull package2 dumped to pkg2_decr.bin\n");
gfx_puts(&gfx_con, "\npkg2 dumped to pkg2_decr.bin\n");
// Dump kernel.
emmcsn_path_impl(path, "/pkg2", "kernel.bin", &storage);
@@ -193,7 +206,7 @@ void dump_packages12()
if (sd_save_to_file(pkg2_hdr->data + pkg2_hdr->sec_size[PKG2_SEC_KERNEL],
pkg2_hdr->sec_size[PKG2_SEC_INI1], path))
goto out;
gfx_puts(&gfx_con, "INI1 kip1 package dumped to ini1.bin\n");
gfx_puts(&gfx_con, "INI1 dumped to ini1.bin\n");
gfx_puts(&gfx_con, "\nDone. Press any key...\n");
@@ -322,6 +335,7 @@ void menu_autorcm()
ments[4].handler = _disable_autorcm;
}
ments[4].type = MENT_HDLR_RE;
ments[4].data = NULL;
memset(&ments[5], 0, sizeof(ment_t));
menu_t menu = {ments, "This corrupts your BOOT0!", 0, 0};
@@ -329,7 +343,7 @@ void menu_autorcm()
tui_do_menu(&gfx_con, &menu);
}
int _fix_attributes(char *path, u32 *total, u32 is_root, u32 check_first_run)
int _fix_attributes(char *path, u32 *total, u32 hos_folder, u32 check_first_run)
{
FRESULT res;
DIR dir;
@@ -369,8 +383,8 @@ int _fix_attributes(char *path, u32 *total, u32 is_root, u32 check_first_run)
if (res != FR_OK || fno.fname[0] == 0)
break;
// Skip official Nintendo dir.
if (is_root && !strcmp(fno.fname, "Nintendo"))
// Skip official Nintendo dir if started from root.
if (!hos_folder && !strcmp(fno.fname, "Nintendo"))
continue;
// Set new directory or file.
@@ -380,15 +394,21 @@ int _fix_attributes(char *path, u32 *total, u32 is_root, u32 check_first_run)
// Check if archive bit is set.
if (fno.fattrib & AM_ARC)
{
*(u32 *)total = *(u32 *)total + 1;
*total = *total + 1;
f_chmod(path, 0, AM_ARC);
}
// Is it a directory?
if (fno.fattrib & AM_DIR)
{
// Set archive bit to NCA folders.
if (hos_folder && !strcmp(fno.fname + strlen(fno.fname) - 4, ".nca"))
{
*total = *total + 1;
f_chmod(path, AM_ARC, AM_ARC);
}
// Enter the directory.
res = _fix_attributes(path, total, 0, 0);
res = _fix_attributes(path, total, hos_folder, 0);
if (res != FR_OK)
break;
}
@@ -405,7 +425,7 @@ void _fix_sd_attr(u32 type)
gfx_con_setpos(&gfx_con, 0, 0);
char path[256];
char label[14];
char label[16];
u32 total = 0;
if (sd_mount())
@@ -418,21 +438,21 @@ void _fix_sd_attr(u32 type)
break;
case 1:
default:
memcpy(path, "/switch", 8);
memcpy(label, "switch folder", 14);
memcpy(path, "/Nintendo", 10);
memcpy(label, "Nintendo folder", 16);
break;
}
gfx_printf(&gfx_con, "Traversing all %s files!\nThis may take some time, please wait...\n\n", label);
_fix_attributes(path, &total, !type, type);
gfx_printf(&gfx_con, "Traversing all %s files!\nThis may take some time...\n\n", label);
_fix_attributes(path, &total, type, type);
gfx_printf(&gfx_con, "%kTotal archive bits cleared: %d!%k\n\nDone! Press any key...", 0xFF96FF00, total, 0xFFCCCCCC);
sd_unmount();
}
btn_wait();
}
void fix_sd_all_attr() { _fix_sd_attr(0); }
void fix_sd_switch_attr() { _fix_sd_attr(1); }
void fix_sd_all_attr() { _fix_sd_attr(0); }
void fix_sd_nin_attr() { _fix_sd_attr(1); }
void fix_battery_desync()
{
@@ -546,8 +566,10 @@ void fix_battery_desync()
}*/
/*
//#include "../modules/hekate_libsys_minerva/mtc.h"
//mtc_config_t mtc_cfg;
#include "../../modules/hekate_libsys_minerva/mtc.h"
#include "../ianos/ianos.h"
#include "../soc/fuse.h"
#include "../soc/clock.h"
void minerva()
{
@@ -575,6 +597,9 @@ void minerva()
break;
}
// Change DRAM voltage.
//i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_SD1, 42); //40 = (1000 * 1100 - 600000) / 12500 -> 1.1V
mtc_cfg.rate_from = mtc_cfg.mtc_table[curr_ram_idx].rate_khz;
mtc_cfg.rate_to = 800000;
mtc_cfg.train_mode = OP_TRAIN_SWITCH;
@@ -583,7 +608,7 @@ void minerva()
// Thefollowing frequency needs periodic training every 100ms.
//msleep(200);
//mtc_cfg.rate_to = 1600000;
//gfx_printf(&gfx_con, "Training and switching %7d -> %7d\n\n", mtc_cfg.current_emc_table->rate_khz, 1600000);
//ianos_loader(false, "bootloader/sys/libsys_minerva.bso", DRAM_LIB, (void *)&mtc_cfg);

View File

@@ -20,8 +20,9 @@
void dump_packages12();
void fix_sd_all_attr();
void fix_sd_switch_attr();
void fix_sd_nin_attr();
void fix_battery_desync();
void menu_autorcm();
//void minerva();
#endif

View File

@@ -1,6 +1,6 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (C) 2018 CTCaer
* Copyright (c) 2018 CTCaer
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@@ -23,6 +23,7 @@
#include "../soc/i2c.h"
#include "../soc/pmc.h"
#include "../power/max77620.h"
#include "../power/max7762x.h"
#include "../soc/gpio.h"
#include "../soc/pinmux.h"
#include "../soc/clock.h"
@@ -42,8 +43,8 @@ static void _display_dsi_wait(u32 timeout, u32 off, u32 mask)
void display_init()
{
// Power on.
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_LDO0_CFG, 0xD0); // Configure to 1.2V.
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_GPIO7, 0x09);
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;

View File

@@ -238,6 +238,10 @@
#define DC_WINBUF_ADDR_H_OFFSET 0x806
#define DC_WINBUF_ADDR_V_OFFSET 0x808
#define DC_WINBUF_SURFACE_KIND 0x80B
#define PITCH (0 << 0)
#define TILED (1 << 0)
#define BLOCK (2 << 0)
#define BLOCK_HEIGHT(x) (((x) & 0x7) << 4)
/*! Display serial interface registers. */
#define _DSIREG(reg) ((reg) * 4)

View File

@@ -21,6 +21,11 @@
#include "../../common/common_gfx.h"
#define EPRINTF(text) gfx_printf(&gfx_con, "%k"text"%k\n", 0xFFFF0000, 0xFFCCCCCC)
#define EPRINTFARGS(text, args...) gfx_printf(&gfx_con, "%k"text"%k\n", 0xFFFF0000, args, 0xFFCCCCCC)
#define WPRINTF(text) gfx_printf(&gfx_con, "%k"text"%k\n", 0xFFFFDD00, 0xFFCCCCCC)
#define WPRINTFARGS(text, args...) gfx_printf(&gfx_con, "%k"text"%k\n", 0xFFFFDD00, args, 0xFFCCCCCC)
void gfx_init_ctxt(gfx_ctxt_t *ctxt, u32 *fb, u32 width, u32 height, u32 stride);
void gfx_clear_grey(gfx_ctxt_t *ctxt, u8 color);
void gfx_clear_partial_grey(gfx_ctxt_t *ctxt, u8 color, u32 pos_x, u32 height);
@@ -43,4 +48,8 @@ void gfx_set_rect_rgb(gfx_ctxt_t *ctxt, const u8 *buf, u32 size_x, u32 size_y, u
void gfx_set_rect_argb(gfx_ctxt_t *ctxt, const u32 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y);
void gfx_render_bmp_argb(gfx_ctxt_t *ctxt, const u32 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y);
// Global gfx console and context.
gfx_ctxt_t gfx_ctxt;
gfx_con_t gfx_con;
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -15,13 +15,12 @@
* 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"
#include "../config/config.h"
#include "di.h"
#ifdef MENU_LOGO_ENABLE
extern u8 *Kc_MENU_LOGO;
@@ -206,8 +205,10 @@ void *tui_do_menu(gfx_con_t *con, menu_t *menu)
return NULL;
break;
case MENT_HDLR_RE:
ent->handler(ent->data);
return NULL;
ent->handler(ent);
if (!ent->data)
return NULL;
break;
default:
break;
}

127
bootloader/hos/fss.c Normal file
View File

@@ -0,0 +1,127 @@
/*
* Atmosphère Fusée Secondary Storage parser.
*
* 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 "fss.h"
#include "hos.h"
#include "../libs/fatfs/ff.h"
#include "../mem/heap.h"
#include "../gfx/gfx.h"
#define DPRINTF(...)
#define FSS0_MAGIC 0x30535346
#define CNT_TYPE_FSP 0
#define CNT_TYPE_EXO 1
#define CNT_TYPE_WBT 2
#define CNT_TYPE_RBT 3
#define CNT_TYPE_SP1 4
#define CNT_TYPE_SP2 5
#define CNT_TYPE_KIP 6
#define CNT_TYPE_BMP 7
typedef struct _fss_t
{
u32 magic;
u32 size;
u32 crt0_off;
u32 cnt_off;
u32 cnt_count;
u32 hos_ver;
u32 version;
u32 git_rev;
} fss_t;
typedef struct _fss_content_t
{
u32 offset;
u32 size;
u32 type;
u32 rsvd1;
char name[0x10];
} fss_content_t;
int parse_fss(launch_ctxt_t *ctxt, const char *value)
{
FIL fp;
if (f_open(&fp, value, FA_READ) != FR_OK)
return 0;
void *fss = malloc(f_size(&fp));
// Read header.
f_read(&fp, fss, 0x400, NULL);
u32 fss_entry = *(u32 *)(fss + 4);
fss_t *fss_meta = (fss_t *)(fss + fss_entry);
if (fss_meta->magic == FSS0_MAGIC)
{
gfx_printf(&gfx_con, "Found FSS0, Atmosphere %d.%d.%d-%08x\n"
"Max HOS supported: %d.%d.%d\n"
"Unpacking and loading components.. ",
fss_meta->version >> 24, (fss_meta->version >> 16) & 0xFF, (fss_meta->version >> 8) & 0xFF, fss_meta->git_rev,
fss_meta->hos_ver >> 24, (fss_meta->hos_ver >> 16) & 0xFF, (fss_meta->hos_ver >> 8) & 0xFF);
fss_content_t *curr_fss_cnt = (fss_content_t *)(fss + fss_meta->cnt_off);
void *content;
for (int i = 0; i < fss_meta->cnt_count; i++)
{
content = (void *)(fss + curr_fss_cnt[i].offset);
if ((curr_fss_cnt[i].offset + curr_fss_cnt[i].size) > fss_meta->size)
continue;
// Load content to launch context.
switch (curr_fss_cnt[i].type)
{
case CNT_TYPE_KIP:;
merge_kip_t *mkip1 = (merge_kip_t *)malloc(sizeof(merge_kip_t));
mkip1->kip1 = content;
list_append(&ctxt->kip1_list, &mkip1->link);
DPRINTF("Loaded %s.kip1 from FSS0 (size %08X)\n", curr_fss_cnt[i].name, curr_fss_cnt[i].size);
break;
case CNT_TYPE_EXO:
ctxt->secmon_size = curr_fss_cnt[i].size;
ctxt->secmon = content;
break;
case CNT_TYPE_WBT:
ctxt->warmboot_size = curr_fss_cnt[i].size;
ctxt->warmboot = content;
break;
default:
continue;
// TODO: add more types?
// case CNT_TYPE_SP1:
// case CNT_TYPE_SP2:
}
f_lseek(&fp, curr_fss_cnt[i].offset);
f_read(&fp, content, curr_fss_cnt[i].size, NULL);
}
gfx_printf(&gfx_con, "Done!\n");
f_close(&fp);
return 1;
}
f_close(&fp);
free(fss);
return 0;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018 naehrwert
* 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,
@@ -14,21 +14,11 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* TODO: the placement of the relocator is a bit fragile atm, maybe we
* should include it in start.S and copy it to some known good
* place in IRAM instead. Basically we want it as far back atm
* as it might be overwritten during relocation.
*/
#ifndef _FSS_H_
#define _FSS_H_
.section .text.reloc
.arm
#include "hos.h"
.globl _reloc_ipl
.type _reloc_ipl, %function
_reloc_ipl:
LDMIA R0!, {R4-R7}
STMIA R1!, {R4-R7}
SUBS R2, #0x10
BNE _reloc_ipl
BX R3
int parse_fss(launch_ctxt_t *ctxt, const char *value);
#endif

View File

@@ -2,7 +2,7 @@
* Copyright (c) 2018 naehrwert
* Copyright (c) 2018 st4rk
* Copyright (c) 2018 Ced2911
* Copyright (c) 2018 CTCaer
* Copyright (c) 2018-2019 CTCaer
* Copyright (c) 2018 balika011
*
* This program is free software; you can redistribute it and/or modify it
@@ -22,6 +22,7 @@
#include "hos.h"
#include "hos_config.h"
#include "sept.h"
#include "secmon_exo.h"
#include "../config/config.h"
#include "../gfx/di.h"
@@ -38,10 +39,7 @@
#include "../storage/nx_emmc.h"
#include "../storage/sdmmc.h"
#include "../utils/util.h"
#include "../gfx/gfx.h"
extern gfx_ctxt_t gfx_ctxt;
extern gfx_con_t gfx_con;
extern hekate_config h_cfg;
@@ -50,6 +48,20 @@ extern void sd_unmount();
//#define DPRINTF(...) gfx_printf(&gfx_con, __VA_ARGS__)
#define DPRINTF(...)
#define PKG2_LOAD_ADDR 0xA9800000
// Secmon mailbox.
#define SECMON_MB_ADDR 0x40002EF8
#define SECMON7_MB_ADDR 0x400000F8
typedef struct _secmon_mailbox_t
{
// < 4.0.0 Signals - 0: Not ready, 1: BCT ready, 2: DRAM and pkg2 ready, 3: Continue boot.
// >= 4.0.0 Signals - 0: Not ready, 1: BCT ready, 2: DRAM ready, 4: pkg2 ready and continue boot.
u32 in;
// Non-zero: Secmon ready.
u32 out;
} secmon_mailbox_t;
static const u8 keyblob_keyseeds[][0x10] = {
{ 0xDF, 0x20, 0x6F, 0x59, 0x44, 0x54, 0xEF, 0xDC, 0x70, 0x74, 0x48, 0x3B, 0x0D, 0xED, 0x9F, 0xD3 }, //1.0.0
{ 0x0C, 0x25, 0x61, 0x5D, 0x68, 0x4C, 0xEB, 0x42, 0x1C, 0x23, 0x79, 0xEA, 0x82, 0x25, 0x12, 0xAC }, //3.0.0
@@ -68,7 +80,7 @@ static const u8 master_keyseed_retail[0x10] =
static const u8 console_keyseed[0x10] =
{ 0x4F, 0x02, 0x5F, 0x0E, 0xB6, 0x6D, 0x11, 0x0E, 0xDC, 0x32, 0x7D, 0x41, 0x86, 0xC2, 0xF4, 0x78 };
static const u8 key8_keyseed[] =
static const u8 package2_keyseed[] =
{ 0xFB, 0x8B, 0x6A, 0x9C, 0x79, 0x00, 0xC8, 0x49, 0xEF, 0xD2, 0x4D, 0x85, 0x4D, 0x30, 0xA0, 0xC7 };
static const u8 master_keyseed_4xx_5xx_610[0x10] =
@@ -96,7 +108,7 @@ static void _se_lock(bool lock_se)
SE(SE_SECURITY_0) &= 0xFFFFFFFB; // Make access lock regs secure only.
}
memset((void *)IPATCH_BASE, 0, 13);
memset((void *)IPATCH_BASE, 0, 14 * sizeof(u32));
SB(SB_CSR) = 0x10; // Protected IROM enable.
// This is useful for documenting the bits in the SE config registers, so we can keep it around.
@@ -129,9 +141,7 @@ void _pmc_scratch_lock(u32 kb)
PMC(APBDEV_PMC_SEC_DISABLE7) = 0xFFFFFFFF;
PMC(APBDEV_PMC_SEC_DISABLE8) = 0xFFAAFFFF;
break;
case KB_FIRMWARE_VERSION_400:
case KB_FIRMWARE_VERSION_500:
case KB_FIRMWARE_VERSION_600:
default:
PMC(APBDEV_PMC_SEC_DISABLE2) |= 0x3FCFFFF;
PMC(APBDEV_PMC_SEC_DISABLE4) |= 0x3F3FFFFF;
PMC(APBDEV_PMC_SEC_DISABLE5) = 0xFFFFFFFF;
@@ -165,30 +175,44 @@ int keygen(u8 *keyblob, u32 kb, tsec_ctxt_t *tsec_ctxt)
u8 tmp[0x20];
u32 retries = 0;
tsec_ctxt->size = 0xF00;
if (kb > KB_FIRMWARE_VERSION_MAX)
return 0;
// Get TSEC key.
if (kb >= KB_FIRMWARE_VERSION_620)
{
if (kb <= KB_FIRMWARE_VERSION_600)
tsec_ctxt->size = 0xF00;
else if (kb == KB_FIRMWARE_VERSION_620)
tsec_ctxt->size = 0x2900;
else
tsec_ctxt->size = 0x3000;
// Prepare smmu tsec page for 6.2.0.
if (kb == KB_FIRMWARE_VERSION_620)
{
u8 *tsec_paged = (u8 *)page_alloc(3);
memcpy(tsec_paged, (void *)tsec_ctxt->fw, tsec_ctxt->size);
tsec_ctxt->fw = tsec_paged;
}
while (tsec_query(tmp, kb, tsec_ctxt) < 0)
// Get TSEC key.
if (kb <= KB_FIRMWARE_VERSION_620)
{
memset(tmp, 0x00, 0x20);
retries++;
while (tsec_query(tmp, kb, tsec_ctxt) < 0)
{
memset(tmp, 0x00, 0x20);
retries++;
if (retries > 3)
return 0;
// We rely on racing conditions, make sure we cover even the unluckiest cases.
if (retries > 15)
{
EPRINTF("\nFailed to get TSEC keys. Please try again.\n");
return 0;
}
}
}
if (kb >= KB_FIRMWARE_VERSION_620)
if (kb >= KB_FIRMWARE_VERSION_700)
se_aes_unwrap_key(8, 12, package2_keyseed);
else if (kb == KB_FIRMWARE_VERSION_620)
{
// Set TSEC key.
se_aes_key_set(12, tmp, 0x10);
@@ -199,7 +223,7 @@ int keygen(u8 *keyblob, u32 kb, tsec_ctxt_t *tsec_ctxt)
se_aes_key_set(8, tmp + 0x10, 0x10);
se_aes_unwrap_key(8, 8, master_keyseed_620);
se_aes_unwrap_key(8, 8, master_keyseed_retail);
se_aes_unwrap_key(8, 8, key8_keyseed);
se_aes_unwrap_key(8, 8, package2_keyseed);
}
else
{
@@ -260,7 +284,7 @@ int keygen(u8 *keyblob, u32 kb, tsec_ctxt_t *tsec_ctxt)
// Package2 key.
se_key_acc_ctrl(8, 0x15);
se_aes_unwrap_key(8, 12, key8_keyseed);
se_aes_unwrap_key(8, 12, package2_keyseed);
}
return 1;
@@ -281,10 +305,10 @@ static int _read_emmc_pkg1(launch_ctxt_t *ctxt)
ctxt->pkg1_id = pkg1_identify(ctxt->pkg1);
if (!ctxt->pkg1_id)
{
gfx_printf(&gfx_con, "%kUnknown package1,\nVersion (= '%s').%k\n", 0xFFFF0000, (char *)ctxt->pkg1 + 0x10, 0xFFCCCCCC);
EPRINTF("Unknown pkg1 version.");
goto out;
}
gfx_printf(&gfx_con, "Identified package1 ('%s'),\nKeyblob version %d\n\n", (char *)(ctxt->pkg1 + 0x10), ctxt->pkg1_id->kb);
gfx_printf(&gfx_con, "Identified pkg1 and Keyblob %d\n\n", ctxt->pkg1_id->kb);
// Read the correct keyblob.
ctxt->keyblob = (u8 *)calloc(NX_EMMC_BLOCKSIZE, 1);
@@ -358,8 +382,10 @@ int hos_launch(ini_sec_t *cfg)
{
launch_ctxt_t ctxt;
tsec_ctxt_t tsec_ctxt;
volatile secmon_mailbox_t *secmon_mb;
memset(&ctxt, 0, sizeof(launch_ctxt_t));
memset(&tsec_ctxt, 0, sizeof(tsec_ctxt_t));
list_init(&ctxt.kip1_list);
if (!gfx_con.mute)
@@ -367,7 +393,7 @@ int hos_launch(ini_sec_t *cfg)
gfx_con_setpos(&gfx_con, 0, 0);
// Try to parse config if present.
if (cfg && !_parse_boot_config(&ctxt, cfg))
if (cfg && !parse_boot_config(&ctxt, cfg))
return 0;
gfx_printf(&gfx_con, "Initializing...\n\n");
@@ -376,17 +402,26 @@ int hos_launch(ini_sec_t *cfg)
if (!_read_emmc_pkg1(&ctxt))
return 0;
gfx_printf(&gfx_con, "Loaded package1 and keyblob\n");
// Check if fuses lower than 4.0.0 and if yes apply NO Gamecard patch.
if (h_cfg.autonogc && !(fuse_read_odm(7) & ~0xF) && ctxt.pkg1_id->kb >= KB_FIRMWARE_VERSION_400)
config_kip1patch(&ctxt, "nogc");
gfx_printf(&gfx_con, "Loaded pkg1 & keyblob\n");
// Generate keys.
if (!h_cfg.se_keygen_done || ctxt.pkg1_id->kb >= KB_FIRMWARE_VERSION_620)
if (!h_cfg.se_keygen_done || ctxt.pkg1_id->kb == KB_FIRMWARE_VERSION_620)
{
tsec_ctxt.key_ver = 1;
tsec_ctxt.fw = (u8 *)ctxt.pkg1 + ctxt.pkg1_id->tsec_off;
tsec_ctxt.pkg1 = ctxt.pkg1;
tsec_ctxt.pkg11_off = ctxt.pkg1_id->pkg11_off;
tsec_ctxt.secmon_base = ctxt.pkg1_id->secmon_base;
if (ctxt.pkg1_id->kb >= KB_FIRMWARE_VERSION_700 && !h_cfg.sept_run)
{
gfx_printf(&gfx_con, "Failed to run sept\n");
return 0;
}
if (!keygen(ctxt.keyblob, ctxt.pkg1_id->kb, &tsec_ctxt))
return 0;
DPRINTF("Generated keys\n");
@@ -400,14 +435,34 @@ int hos_launch(ini_sec_t *cfg)
if (ctxt.pkg1_id->kb <= KB_FIRMWARE_VERSION_600)
pkg1_decrypt(ctxt.pkg1_id, ctxt.pkg1);
pkg1_unpack((void *)ctxt.pkg1_id->warmboot_base, (void *)ctxt.pkg1_id->secmon_base, NULL, ctxt.pkg1_id, ctxt.pkg1);
gfx_printf(&gfx_con, "Decrypted and unpacked package1\n");
if (ctxt.pkg1_id->kb <= KB_FIRMWARE_VERSION_620)
{
pkg1_unpack((void *)ctxt.pkg1_id->warmboot_base, (void *)ctxt.pkg1_id->secmon_base, NULL, ctxt.pkg1_id, ctxt.pkg1);
gfx_printf(&gfx_con, "Decrypted & unpacked pkg1\n");
}
else
{
EPRINTF("No mandatory secmon or warmboot provided!");
return 0;
}
}
// Replace 'warmboot.bin' if requested.
if (ctxt.warmboot)
memcpy((void *)ctxt.pkg1_id->warmboot_base, ctxt.warmboot, ctxt.warmboot_size);
else
{
if (ctxt.pkg1_id->kb >= KB_FIRMWARE_VERSION_700)
{
EPRINTF("No warmboot provided!");
return 0;
}
// Else we patch it to allow downgrading.
patch_t *warmboot_patchset = ctxt.pkg1_id->warmboot_patchset;
gfx_printf(&gfx_con, "%kPatching Warmboot%k\n", 0xFFFFBA00, 0xFFCCCCCC);
for (u32 i = 0; warmboot_patchset[i].off != 0xFFFFFFFF; i++)
*(vu32 *)(ctxt.pkg1_id->warmboot_base + warmboot_patchset[i].off) = warmboot_patchset[i].val;
}
// Set warmboot address in PMC if required.
if (ctxt.pkg1_id->set_warmboot)
PMC(APBDEV_PMC_SCRATCH1) = ctxt.pkg1_id->warmboot_base;
@@ -415,7 +470,7 @@ int hos_launch(ini_sec_t *cfg)
// Replace 'SecureMonitor' if requested.
if (ctxt.secmon)
memcpy((void *)ctxt.pkg1_id->secmon_base, ctxt.secmon, ctxt.secmon_size);
else
else if (ctxt.pkg1_id->secmon_patchset)
{
// Else we patch it to allow for an unsigned package2 and patched kernel.
patch_t *secmon_patchset = ctxt.pkg1_id->secmon_patchset;
@@ -424,17 +479,22 @@ int hos_launch(ini_sec_t *cfg)
*(vu32 *)(ctxt.pkg1_id->secmon_base + secmon_patchset[i].off) = secmon_patchset[i].val;
}
gfx_printf(&gfx_con, "Loaded warmboot.bin and secmon\n");
gfx_printf(&gfx_con, "Loaded warmboot and secmon\n");
// Read package2.
u8 *bootConfigBuf = _read_emmc_pkg2(&ctxt);
if (!bootConfigBuf)
return 0;
gfx_printf(&gfx_con, "Read package2\n");
gfx_printf(&gfx_con, "Read pkg2\n");
// Decrypt package2 and parse KIP1 blobs in INI1 section.
pkg2_hdr_t *pkg2_hdr = pkg2_decrypt(ctxt.pkg2);
if (!pkg2_hdr)
{
gfx_printf(&gfx_con, "Pkg2 decryption failed!\n");
return 0;
}
LIST_INIT(kip1_info);
pkg2_parse_kips(&kip1_info, pkg2_hdr);
@@ -470,13 +530,15 @@ int hos_launch(ini_sec_t *cfg)
for (u32 j = 0; j < kernel_patchset[i].val; j++)
*(vu32 *)(ctxt.kernel + kernel_patchset[i].off + (j << 2)) = temp[j];
}
else if (kernel_patchset[i].id < SVC_VERIFY_DS)
*(vu32 *)(ctxt.kernel + kernel_patchset[i].off) = kernel_patchset[i].val;
}
}
}
}
// Merge extra KIP1s into loaded ones.
gfx_printf(&gfx_con, "%kPatching kernel initial processes%k\n", 0xFFFFBA00, 0xFFCCCCCC);
gfx_printf(&gfx_con, "%kPatching kips%k\n", 0xFFFFBA00, 0xFFCCCCCC);
LIST_FOREACH_ENTRY(merge_kip_t, mki, &ctxt.kip1_list, link)
pkg2_merge_kip(&kip1_info, (pkg2_kip1_t *)mki->kip1);
@@ -484,18 +546,17 @@ int hos_launch(ini_sec_t *cfg)
const char* unappliedPatch = pkg2_patch_kips(&kip1_info, ctxt.kip1_patches);
if (unappliedPatch != NULL)
{
gfx_printf(&gfx_con, "%kREQUESTED PATCH '%s' NOT APPLIED!%k\n", 0xFFFF0000, unappliedPatch, 0xFFCCCCCC);
EPRINTFARGS("Failed to apply '%s'!", unappliedPatch);
sd_unmount(); // Just exiting is not enough until pkg2_patch_kips stops modifying the string passed into it.
while(1) {} // MUST stop here, because if user requests 'nogc' but it's not applied, their GC controller gets updated!
_free_launch_components(&ctxt);
return 0; // MUST stop here, because if user requests 'nogc' but it's not applied, their GC controller gets updated!
}
// Rebuild and encrypt package2.
pkg2_build_encrypt((void *)0xA9800000, ctxt.kernel, ctxt.kernel_size, &kip1_info);
pkg2_build_encrypt((void *)PKG2_LOAD_ADDR, ctxt.kernel, ctxt.kernel_size, &kip1_info);
gfx_printf(&gfx_con, "Rebuilt and loaded package2\n");
// Unmount SD card.
sd_unmount();
gfx_printf(&gfx_con, "Rebuilt & loaded pkg2\n");
gfx_printf(&gfx_con, "\n%kBooting...%k\n", 0xFF96FF00, 0xFFCCCCCC);
@@ -526,7 +587,7 @@ int hos_launch(ini_sec_t *cfg)
case KB_FIRMWARE_VERSION_600:
se_key_acc_ctrl(12, 0xFF);
se_key_acc_ctrl(15, 0xFF);
case KB_FIRMWARE_VERSION_620:
default:
bootStateDramPkg2 = 2;
bootStatePkg2Continue = 4;
break;
@@ -549,7 +610,10 @@ int hos_launch(ini_sec_t *cfg)
// Config Exosphère if booting full Atmosphère.
if (ctxt.atmosphere && ctxt.secmon)
config_exosphere(ctxt.pkg1_id->id, ctxt.pkg1_id->kb, ctxt.debugmode);
config_exosphere(ctxt.pkg1_id->id, ctxt.pkg1_id->kb, (void *)ctxt.pkg1_id->warmboot_base, ctxt.pkg1);
// Unmount SD card.
sd_unmount();
// Finalize MC carveout.
if (ctxt.pkg1_id->kb <= KB_FIRMWARE_VERSION_301)
@@ -562,39 +626,42 @@ int hos_launch(ini_sec_t *cfg)
if (ctxt.pkg1_id->kb >= KB_FIRMWARE_VERSION_620)
_sysctr0_reset();
// < 4.0.0 pkg1.1 locks PMC scratches.
//_pmc_scratch_lock(ctxt.pkg1_id->kb);
// Set secmon mailbox address.
if (ctxt.pkg1_id->kb >= KB_FIRMWARE_VERSION_700)
secmon_mb = (secmon_mailbox_t *)SECMON7_MB_ADDR;
else
secmon_mb = (secmon_mailbox_t *)SECMON_MB_ADDR;
// Start from DRAM ready signal and reset outgoing value.
secmon_mb->in = bootStateDramPkg2;
secmon_mb->out = 0;
// Free allocated memory.
ini_free_section(cfg);
_free_launch_components(&ctxt);
// < 4.0.0 pkg1.1 locks PMC scratches.
//_pmc_scratch_lock(ctxt.pkg1_id->kb);
// < 4.0.0 Signals - 0: Not ready, 1: BCT ready, 2: DRAM and pkg2 ready, 3: Continue boot.
// >= 4.0.0 Signals - 0: Not ready, 1: BCT ready, 2: DRAM ready, 4: pkg2 ready and continue boot.
vu32 *mb_in = (vu32 *)0x40002EF8;
// Non-zero: Secmon ready.
vu32 *mb_out = (vu32 *)0x40002EFC;
// Start from DRAM ready signal.
*mb_in = bootStateDramPkg2;
*mb_out = 0;
// Disable display. This must be executed before secmon to provide support for all fw versions.
display_end();
// Clear EMC_SCRATCH0.
EMC(EMC_SCRATCH0) = 0;
// Wait for secmon to get ready.
if (smmu_is_used())
smmu_exit();
else
cluster_boot_cpu0(ctxt.pkg1_id->secmon_base);
while (!*mb_out)
while (!secmon_mb->out)
usleep(1); // This only works when in IRAM or with a trained DRAM.
// Signal pkg2 ready and continue boot.
*mb_in = bootStatePkg2Continue;
secmon_mb->in = bootStatePkg2Continue;
// Halt ourselves in waitevent state and resume if there's JTAG activity.
while (1)
while (true)
FLOW_CTLR(FLOW_CTLR_HALT_COP_EVENTS) = 0x50000000;
return 0;

View File

@@ -30,7 +30,10 @@
#define KB_FIRMWARE_VERSION_500 4
#define KB_FIRMWARE_VERSION_600 5
#define KB_FIRMWARE_VERSION_620 6
#define KB_FIRMWARE_VERSION_MAX KB_FIRMWARE_VERSION_620
#define KB_FIRMWARE_VERSION_700 7
#define KB_FIRMWARE_VERSION_MAX KB_FIRMWARE_VERSION_700
#define HOS_PKG11_MAGIC 0x31314B50
typedef struct _launch_ctxt_t
{

View File

@@ -1,6 +1,6 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (c) 2018 CTCaer
* Copyright (c) 2018-2019 CTCaer
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@@ -19,12 +19,12 @@
#include "hos.h"
#include "hos_config.h"
#include "fss.h"
#include "../libs/fatfs/ff.h"
#include "../mem/heap.h"
#include "../utils/dirlist.h"
#include "../gfx/gfx.h"
extern gfx_con_t gfx_con;
//#define DPRINTF(...) gfx_printf(&gfx_con, __VA_ARGS__)
#define DPRINTF(...)
@@ -126,6 +126,36 @@ static int _config_kip1(launch_ctxt_t *ctxt, const char *value)
return 1;
}
int config_kip1patch(launch_ctxt_t *ctxt, const char *value)
{
if (value == NULL)
return 0;
int valueLen = strlen(value);
if (!valueLen)
return 0;
if (ctxt->kip1_patches == NULL)
{
ctxt->kip1_patches = malloc(valueLen + 1);
memcpy(ctxt->kip1_patches, value, valueLen);
ctxt->kip1_patches[valueLen] = 0;
}
else
{
char *oldAlloc = ctxt->kip1_patches;
int oldSize = strlen(oldAlloc);
ctxt->kip1_patches = malloc(oldSize + 1 + valueLen + 1);
memcpy(ctxt->kip1_patches, oldAlloc, oldSize);
free(oldAlloc);
oldAlloc = NULL;
ctxt->kip1_patches[oldSize++] = ',';
memcpy(&ctxt->kip1_patches[oldSize], value, valueLen);
ctxt->kip1_patches[oldSize + valueLen] = 0;
}
return 1;
}
static int _config_svcperm(launch_ctxt_t *ctxt, const char *value)
{
if (*value == '1')
@@ -156,34 +186,9 @@ static int _config_atmosphere(launch_ctxt_t *ctxt, const char *value)
return 1;
}
static int _config_kip1patch(launch_ctxt_t *ctxt, const char *value)
static int _config_fss(launch_ctxt_t *ctxt, const char *value)
{
if (value == NULL)
return 0;
int valueLen = strlen(value);
if (!valueLen)
return 0;
if (ctxt->kip1_patches == NULL)
{
ctxt->kip1_patches = malloc(valueLen + 1);
memcpy(ctxt->kip1_patches, value, valueLen);
ctxt->kip1_patches[valueLen] = 0;
}
else
{
char *oldAlloc = ctxt->kip1_patches;
int oldSize = strlen(oldAlloc);
ctxt->kip1_patches = malloc(oldSize + 1 + valueLen + 1);
memcpy(ctxt->kip1_patches, oldAlloc, oldSize);
free(oldAlloc);
oldAlloc = NULL;
ctxt->kip1_patches[oldSize++] = ',';
memcpy(&ctxt->kip1_patches[oldSize], value, valueLen);
ctxt->kip1_patches[oldSize + valueLen] = 0;
}
return 1;
return parse_fss(ctxt, value);
}
typedef struct _cfg_handler_t
@@ -197,14 +202,15 @@ static const cfg_handler_t _config_handlers[] = {
{ "secmon", _config_secmon },
{ "kernel", _config_kernel },
{ "kip1", _config_kip1 },
{ "kip1patch", _config_kip1patch },
{ "kip1patch", config_kip1patch },
{ "fullsvcperm", _config_svcperm },
{ "debugmode", _config_debugmode },
{ "atmosphere", _config_atmosphere },
{ "fss0", _config_fss },
{ NULL, NULL },
};
int _parse_boot_config(launch_ctxt_t *ctxt, ini_sec_t *cfg)
int parse_boot_config(launch_ctxt_t *ctxt, ini_sec_t *cfg)
{
LIST_FOREACH_ENTRY(ini_kv_t, kv, &cfg->kvs, link)
{

View File

@@ -19,7 +19,8 @@
#include "hos.h"
int _parse_boot_config(launch_ctxt_t *ctxt, ini_sec_t *cfg);
int parse_boot_config(launch_ctxt_t *ctxt, ini_sec_t *cfg);
int config_kip1patch(launch_ctxt_t *ctxt, const char *value);
#endif

View File

@@ -1,7 +1,7 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (c) 2018 st4rk
* Copyright (c) 2018 CTCaer
* Copyright (c) 2018-2019 CTCaer
* Copyright (c) 2018 balika011
*
* This program is free software; you can redistribute it and/or modify it
@@ -20,8 +20,11 @@
#include <string.h>
#include "pkg1.h"
#include "../utils/aarch64_util.h"
#include "../gfx/gfx.h"
#include "../sec/se.h"
#include "../utils/aarch64_util.h"
#define _NOPv7() 0xE320F000
#define SM_100_ADR 0x4002B020
PATCHSET_DEF(_secmon_1_patchset,
@@ -66,10 +69,18 @@ PATCHSET_DEF(_secmon_5_patchset,
PATCHSET_DEF(_secmon_6_patchset,
// Patch package2 decryption and signature/hash checks.
{ 0xDC8 + 0x820, _NOP() }, //package2 structure.
{ 0xDC8 + 0x82C, _NOP() }, //Version.
{ 0xDC8 + 0xE90, _NOP() }, //Header signature.
{ 0xDC8 + 0x112C, _NOP() } //Sections SHA2.
{ 0xDC8 + 0x820, _NOP() }, //package2 structure.
{ 0xDC8 + 0x82C, _NOP() }, //Version.
{ 0xDC8 + 0xE90, _NOP() }, //Header signature.
{ 0xDC8 + 0x112C, _NOP() }, //Sections SHA2.
// Fix sleep mode for debug.
{ 0x1A68 + 0x3854, 0x94000E45 }, //gpio_config_for_uart.
{ 0x1A68 + 0x3858, 0x97FFFC0F }, //clkrst_reboot_uarta.
{ 0x1A68 + 0x385C, 0x52A00021 }, //MOV W1, #0x10000 ; baudrate.
{ 0x1A68 + 0x3860, 0x2A1F03E0 }, //MOV W0, WZR ; uart_port -> A.
{ 0x1A68 + 0x3864, 0x72984001 }, //MOVK W1, #0xC200 ; baudrate.
{ 0x1A68 + 0x3868, 0x94000C8C }, //uart_configure.
{ 0x1A68 + 0x3A6C, _NOP() } // warmboot UARTA cfg.
);
PATCHSET_DEF(_secmon_620_patchset,
@@ -77,9 +88,36 @@ PATCHSET_DEF(_secmon_620_patchset,
{ 0xDC8 + 0x604, _NOP() }, //package2 structure.
{ 0xDC8 + 0x610, _NOP() }, //Version.
{ 0xDC8 + 0xC74, _NOP() }, //Header signature.
{ 0xDC8 + 0xF10, _NOP() } //Sections SHA2.
{ 0xDC8 + 0xF10, _NOP() }, //Sections SHA2.
// Fix sleep mode for debug.
{ 0x2AC8 + 0x3854, 0x94000F42 }, //gpio_config_for_uart.
{ 0x2AC8 + 0x3858, 0x97FFFC0F }, //clkrst_reboot_uarta.
{ 0x2AC8 + 0x385C, 0x52A00021 }, //MOV W1, #0x10000 ; baudrate.
{ 0x2AC8 + 0x3860, 0x2A1F03E0 }, //MOV W0, WZR ; uart_port -> A.
{ 0x2AC8 + 0x3864, 0x72984001 }, //MOVK W1, #0xC200 ; baudrate.
{ 0x2AC8 + 0x3868, 0x94000D89 }, //uart_configure.
{ 0x2AC8 + 0x3A6C, _NOP() } // warmboot UARTA cfg.
);
PATCHSET_DEF(_warmboot_1_patchset,
{ 0x4DC, _NOPv7() } // Fuse check.
);
PATCHSET_DEF(_warmboot_2_patchset,
{ 0x4DC, _NOPv7() } // Fuse check.
);
PATCHSET_DEF(_warmboot_3_patchset,
{ 0x4DC, _NOPv7() }, // Fuse check.
{ 0x4F0, _NOPv7() } // Segment id check.
);
PATCHSET_DEF(_warmboot_4_patchset,
{ 0x544, _NOPv7() }, // Fuse check.
{ 0x558, _NOPv7() } // Segment id check.
);
/*
* package1.1 header: <wb, ldr, sm>
* package1.1 layout:
@@ -91,23 +129,30 @@ PATCHSET_DEF(_secmon_620_patchset,
* 5.0: {ldr, sm, wb} { 1, 2, 0 }
* 6.0: {ldr, sm, wb} { 1, 2, 0 }
* 6.2: {ldr, sm, wb} { 1, 2, 0 }
* 7.0: {ldr, sm, wb} { 1, 2, 0 }
*/
static const pkg1_id_t _pkg1_ids[] = {
{ "20161121183008", 0, 0x1900, 0x3FE0, { 2, 1, 0 }, SM_100_ADR, 0x8000D000, true, _secmon_1_patchset }, //1.0.0 (Patched relocator)
{ "20170210155124", 0, 0x1900, 0x3FE0, { 0, 1, 2 }, 0x4002D000, 0x8000D000, true, _secmon_2_patchset }, //2.0.0 - 2.3.0
{ "20170519101410", 1, 0x1A00, 0x3FE0, { 0, 1, 2 }, 0x4002D000, 0x8000D000, true, _secmon_3_patchset }, //3.0.0
{ "20170710161758", 2, 0x1A00, 0x3FE0, { 0, 1, 2 }, 0x4002D000, 0x8000D000, true, _secmon_3_patchset }, //3.0.1 - 3.0.2
{ "20170921172629", 3, 0x1800, 0x3FE0, { 1, 2, 0 }, 0x4002B000, 0x4003B000, false, _secmon_4_patchset }, //4.0.0 - 4.1.0
{ "20180220163747", 4, 0x1900, 0x3FE0, { 1, 2, 0 }, 0x4002B000, 0x4003B000, false, _secmon_5_patchset }, //5.0.0 - 5.1.0
{ "20180802162753", 5, 0x1900, 0x3FE0, { 1, 2, 0 }, 0x4002B000, 0x4003D800, false, _secmon_6_patchset }, //6.0.0 - 6.1.0
{ "20181107105733", 6, 0x0E00, 0x6FE0, { 1, 2, 0 }, 0x4002B000, 0x4003D800, false, _secmon_620_patchset }, //6.2.0
{ "20161121183008", 0, 0x1900, 0x3FE0, { 2, 1, 0 }, SM_100_ADR, 0x8000D000, true, _secmon_1_patchset, _warmboot_1_patchset }, //1.0.0 (Patched relocator)
{ "20170210155124", 0, 0x1900, 0x3FE0, { 0, 1, 2 }, 0x4002D000, 0x8000D000, true, _secmon_2_patchset, _warmboot_2_patchset }, //2.0.0 - 2.3.0
{ "20170519101410", 1, 0x1A00, 0x3FE0, { 0, 1, 2 }, 0x4002D000, 0x8000D000, true, _secmon_3_patchset, _warmboot_3_patchset }, //3.0.0
{ "20170710161758", 2, 0x1A00, 0x3FE0, { 0, 1, 2 }, 0x4002D000, 0x8000D000, true, _secmon_3_patchset, _warmboot_3_patchset }, //3.0.1 - 3.0.2
{ "20170921172629", 3, 0x1800, 0x3FE0, { 1, 2, 0 }, 0x4002B000, 0x4003B000, false, _secmon_4_patchset, _warmboot_4_patchset }, //4.0.0 - 4.1.0
{ "20180220163747", 4, 0x1900, 0x3FE0, { 1, 2, 0 }, 0x4002B000, 0x4003B000, false, _secmon_5_patchset, _warmboot_4_patchset }, //5.0.0 - 5.1.0
{ "20180802162753", 5, 0x1900, 0x3FE0, { 1, 2, 0 }, 0x4002B000, 0x4003D800, false, _secmon_6_patchset, _warmboot_4_patchset }, //6.0.0 - 6.1.0
{ "20181107105733", 6, 0x0E00, 0x6FE0, { 1, 2, 0 }, 0x4002B000, 0x4003D800, false, _secmon_620_patchset, _warmboot_4_patchset }, //6.2.0
{ "20181218175730", 7, 0x0F00, 0x6FE0, { 1, 2, 0 }, 0x40030000, 0x4003E000, false, NULL, _warmboot_4_patchset }, //7.0.0
{ "20190208150037", 7, 0x0F00, 0x6FE0, { 1, 2, 0 }, 0x40030000, 0x4003E000, false, NULL, _warmboot_4_patchset }, //7.0.1
{ NULL } //End.
};
const pkg1_id_t *pkg1_identify(u8 *pkg1)
{
char build_date[15];
memcpy(build_date, (char *)(pkg1 + 0x10), 14);
build_date[14] = 0;
gfx_printf(&gfx_con, "Found pkg1 ('%s').\n\n", build_date);
for (u32 i = 0; _pkg1_ids[i].id; i++)
if (!memcmp(pkg1 + 0x10, _pkg1_ids[i].id, 12))
return &_pkg1_ids[i];

View File

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

View File

@@ -1,6 +1,6 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (c) 2018 CTCaer
* Copyright (c) 2018-2019 CTCaer
* Copyright (c) 2018 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
@@ -26,8 +26,6 @@
#include "../gfx/gfx.h"
extern gfx_con_t gfx_con;
/*#include "util.h"
#define DPRINTF(...) gfx_printf(&gfx_con, __VA_ARGS__)
#define DEBUG_PRINTING*/
@@ -44,6 +42,7 @@ extern gfx_con_t gfx_con;
#define FREE_CODE_OFF_1ST_400 0x52890
#define FREE_CODE_OFF_1ST_500 0x5C020
#define FREE_CODE_OFF_1ST_600 0x5EE00
#define FREE_CODE_OFF_1ST_700 0x5FEC0
#define ID_SND_OFF_100 0x23CC0
#define ID_SND_OFF_200 0x3F134
@@ -52,6 +51,7 @@ extern gfx_con_t gfx_con;
#define ID_SND_OFF_400 0x2AF64
#define ID_SND_OFF_500 0x2AD34
#define ID_SND_OFF_600 0x2BB8C
#define ID_SND_OFF_700 0x2D044
#define ID_RCV_OFF_100 0x219F0
#define ID_RCV_OFF_200 0x3D1A8
@@ -60,13 +60,14 @@ extern gfx_con_t gfx_con;
#define ID_RCV_OFF_400 0x28F6C
#define ID_RCV_OFF_500 0x28DAC
#define ID_RCV_OFF_600 0x29B6C
#define ID_RCV_OFF_700 0x2B23C
static u32 PRC_ID_SND_100[] =
{
0xA9BF2FEA, 0x2A0E03EB, 0xD37EF56B, 0xF86B6B8B, 0x92FFFFE9, 0x8A090168, 0xD2FFFFE9, 0x8A09016B,
0xD2FFFFC9, 0xEB09017F, 0x54000040, 0xF9412948, 0xA8C12FEA
};
#define FREE_CODE_OFF_2ND_100 (FREE_CODE_OFF_1ST_100 + sizeof(PRC_ID_SND_100) + 4)
#define FREE_CODE_OFF_2ND_100 (FREE_CODE_OFF_1ST_100 + sizeof(PRC_ID_SND_100) + sizeof(u32))
static u32 PRC_ID_RCV_100[] =
{
0xA9BF2FEA, 0x2A1C03EA, 0xD37EF54A, 0xF86A69AA, 0x92FFFFE9, 0x8A090148, 0xD2FFFFE9, 0x8A09014A,
@@ -78,7 +79,7 @@ static u32 PRC_ID_SND_200[] =
0xA9BF2FEA, 0x2A1803EB, 0xD37EF56B, 0xF86B6B8B, 0x92FFFFE9, 0x8A090168, 0xD2FFFFE9, 0x8A09016B,
0xD2FFFFC9, 0xEB09017F, 0x54000040, 0xF9413148, 0xA8C12FEA
};
#define FREE_CODE_OFF_2ND_200 (FREE_CODE_OFF_1ST_200 + sizeof(PRC_ID_SND_200) + 4)
#define FREE_CODE_OFF_2ND_200 (FREE_CODE_OFF_1ST_200 + sizeof(PRC_ID_SND_200) + sizeof(u32))
static u32 PRC_ID_RCV_200[] =
{
0xA9BF2FEA, 0x2A0F03EA, 0xD37EF54A, 0xF9405FEB, 0xF86A696A, 0xF9407BEB, 0x92FFFFE9, 0x8A090148,
@@ -90,7 +91,7 @@ static u32 PRC_ID_SND_300[] =
0xA9BF2FEA, 0x2A1803EB, 0xD37EF56B, 0xF86B6B8B, 0x92FFFFE9, 0x8A090168, 0xD2FFFFE9, 0x8A09016B,
0xD2FFFFC9, 0xEB09017F, 0x54000040, 0xF9415548, 0xA8C12FEA
};
#define FREE_CODE_OFF_2ND_300 (FREE_CODE_OFF_1ST_300 + sizeof(PRC_ID_SND_300) + 4)
#define FREE_CODE_OFF_2ND_300 (FREE_CODE_OFF_1ST_300 + sizeof(PRC_ID_SND_300) + sizeof(u32))
static u32 PRC_ID_RCV_300[] =
{
0xA9BF2FEA, 0x2A0F03EA, 0xD37EF54A, 0xF9405FEB, 0xF86A696A, 0xF9407BEB, 0x92FFFFE9, 0x8A090148,
@@ -102,7 +103,7 @@ static u32 PRC_ID_SND_302[] =
0xA9BF2FEA, 0x2A1803EB, 0xD37EF56B, 0xF86B6B8B, 0x92FFFFE9, 0x8A090168, 0xD2FFFFE9, 0x8A09016B,
0xD2FFFFC9, 0xEB09017F, 0x54000040, 0xF9415548, 0xA8C12FEA
};
#define FREE_CODE_OFF_2ND_302 (FREE_CODE_OFF_1ST_302 + sizeof(PRC_ID_SND_302) + 4)
#define FREE_CODE_OFF_2ND_302 (FREE_CODE_OFF_1ST_302 + sizeof(PRC_ID_SND_302) + sizeof(u32))
static u32 PRC_ID_RCV_302[] =
{
0xA9BF2FEA, 0x2A0F03EA, 0xD37EF54A, 0xF9405FEB, 0xF86A696A, 0xF9407BEB, 0x92FFFFE9, 0x8A090148,
@@ -114,7 +115,7 @@ static u32 PRC_ID_SND_400[] =
0x2A1703EA, 0xD37EF54A, 0xF86A6B8A, 0x92FFFFE9, 0x8A090148, 0xD2FFFFE9, 0x8A09014A, 0xD2FFFFC9,
0xEB09015F, 0x54000060, 0xF94053EA, 0xF9415948, 0xF94053EA
};
#define FREE_CODE_OFF_2ND_400 (FREE_CODE_OFF_1ST_400 + sizeof(PRC_ID_SND_400) + 4)
#define FREE_CODE_OFF_2ND_400 (FREE_CODE_OFF_1ST_400 + sizeof(PRC_ID_SND_400) + sizeof(u32))
static u32 PRC_ID_RCV_400[] =
{
0xF9403BED, 0x2A0E03EA, 0xD37EF54A, 0xF86A69AA, 0x92FFFFE9, 0x8A090148, 0xD2FFFFE9, 0x8A09014A,
@@ -126,7 +127,7 @@ static u32 PRC_ID_SND_500[] =
0x2A1703EA, 0xD37EF54A, 0xF86A6B6A, 0x92FFFFE9, 0x8A090148, 0xD2FFFFE9, 0x8A09014A, 0xD2FFFFC9,
0xEB09015F, 0x54000060, 0xF94043EA, 0xF9415948, 0xF94043EA
};
#define FREE_CODE_OFF_2ND_500 (FREE_CODE_OFF_1ST_500 + sizeof(PRC_ID_SND_500) + 4)
#define FREE_CODE_OFF_2ND_500 (FREE_CODE_OFF_1ST_500 + sizeof(PRC_ID_SND_500) + sizeof(u32))
static u32 PRC_ID_RCV_500[] =
{
0xF9403BED, 0x2A1503EA, 0xD37EF54A, 0xF86A69AA, 0x92FFFFE9, 0x8A090148, 0xD2FFFFE9, 0x8A09014A,
@@ -139,7 +140,7 @@ static u32 PRC_ID_SND_600[] =
0x8A09014A, 0xD2FFFFC9, 0xEB09015F, 0x54000100, 0xA9BF27E8, 0xF9400308, 0xF9401D08, 0xAA1803E0,
0xD63F0100, 0xA8C127E8, 0xAA0003E8, 0xA8C12FEA, 0xAA0803E0
};
#define FREE_CODE_OFF_2ND_600 (FREE_CODE_OFF_1ST_600 + sizeof(PRC_ID_SND_600) + 4)
#define FREE_CODE_OFF_2ND_600 (FREE_CODE_OFF_1ST_600 + sizeof(PRC_ID_SND_600) + sizeof(u32))
static u32 PRC_ID_RCV_600[] =
{
0xA9BF2FEA, 0xF94043EB, 0x2A1503EA, 0xD37EF54A, 0xF86A696A, 0x92FFFFE9, 0x8A090148, 0xD2FFFFE9,
@@ -147,6 +148,20 @@ static u32 PRC_ID_RCV_600[] =
0xD63F0100, 0xA8C127E8, 0xAA0003E8, 0xA8C12FEA, 0xAA0803E0
};
static u32 PRC_ID_SND_700[] =
{
0xA9BF2FEA, 0xF9403BEB, 0x2A1903EA, 0xD37EF54A, 0xF86A696A, 0x92FFFFE9, 0x8A090148, 0xD2FFFFE9,
0x8A09014A, 0xD2FFFFC9, 0xEB09015F, 0x54000100, 0xA9BF27E8, 0xF94002A8, 0xF9401D08, 0xAA1503E0,
0xD63F0100, 0xA8C127E8, 0xAA0003E8, 0xA8C12FEA, 0xAA0803E0
};
#define FREE_CODE_OFF_2ND_700 (FREE_CODE_OFF_1ST_700 + sizeof(PRC_ID_SND_700) + sizeof(u32))
static u32 PRC_ID_RCV_700[] =
{
0xA9BF2FEA, 0xF9404FEB, 0x2A1603EA, 0xD37EF54A, 0xF86A696A, 0x92FFFFE9, 0x8A090148, 0xD2FFFFE9,
0x8A09014A, 0xD2FFFFC9, 0xEB09015F, 0x54000100, 0xA9BF27E8, 0xF9400368, 0xF9401D08, 0xAA1B03E0,
0xD63F0100, 0xA8C127E8, 0xAA0003E8, 0xA8C12FEA, 0xAA0803E0
};
// Include kernel patches here, so we can utilize pkg1 id
KERNEL_PATCHSET_DEF(_kernel_1_patchset,
{ SVC_VERIFY_DS, 0x3764C, _NOP(), NULL }, // Disable SVC verifications
@@ -155,11 +170,11 @@ KERNEL_PATCHSET_DEF(_kernel_1_patchset,
{ ATM_GEN_PATCH, ID_SND_OFF_100, _B(ID_SND_OFF_100, FREE_CODE_OFF_1ST_100), NULL}, // Send process id branch.
{ ATM_ARR_PATCH, FREE_CODE_OFF_1ST_100, sizeof(PRC_ID_SND_100) >> 2, PRC_ID_SND_100}, // Send process id code.
{ ATM_GEN_PATCH, FREE_CODE_OFF_1ST_100 + sizeof(PRC_ID_SND_100), // Branch back and skip 1 instruction.
_B(FREE_CODE_OFF_1ST_100 + sizeof(PRC_ID_SND_100), ID_SND_OFF_100 + 4), NULL},
_B(FREE_CODE_OFF_1ST_100 + sizeof(PRC_ID_SND_100), ID_SND_OFF_100 + sizeof(u32)), NULL},
{ ATM_GEN_PATCH, ID_RCV_OFF_100, _B(ID_RCV_OFF_100, FREE_CODE_OFF_2ND_100), NULL}, // Receive process id branch.
{ ATM_ARR_PATCH, FREE_CODE_OFF_2ND_100, sizeof(PRC_ID_RCV_100) >> 2, PRC_ID_RCV_100}, // Receive process id code.
{ ATM_GEN_PATCH, FREE_CODE_OFF_2ND_100 + sizeof(PRC_ID_RCV_100), // Branch back and skip 1 instruction.
_B(FREE_CODE_OFF_2ND_100 + sizeof(PRC_ID_RCV_100), ID_RCV_OFF_100 + 4), NULL}
_B(FREE_CODE_OFF_2ND_100 + sizeof(PRC_ID_RCV_100), ID_RCV_OFF_100 + sizeof(u32)), NULL}
);
KERNEL_PATCHSET_DEF(_kernel_2_patchset,
@@ -169,11 +184,11 @@ KERNEL_PATCHSET_DEF(_kernel_2_patchset,
{ ATM_GEN_PATCH, ID_SND_OFF_200, _B(ID_SND_OFF_200, FREE_CODE_OFF_1ST_200), NULL}, // Send process id branch.
{ ATM_ARR_PATCH, FREE_CODE_OFF_1ST_200, sizeof(PRC_ID_SND_200) >> 2, PRC_ID_SND_200}, // Send process id code.
{ ATM_GEN_PATCH, FREE_CODE_OFF_1ST_200 + sizeof(PRC_ID_SND_200), // Branch back and skip 1 instruction.
_B(FREE_CODE_OFF_1ST_200 + sizeof(PRC_ID_SND_200), ID_SND_OFF_200 + 4), NULL},
_B(FREE_CODE_OFF_1ST_200 + sizeof(PRC_ID_SND_200), ID_SND_OFF_200 + sizeof(u32)), NULL},
{ ATM_GEN_PATCH, ID_RCV_OFF_200, _B(ID_RCV_OFF_200, FREE_CODE_OFF_2ND_200), NULL}, // Receive process id branch.
{ ATM_ARR_PATCH, FREE_CODE_OFF_2ND_200, sizeof(PRC_ID_RCV_200) >> 2, PRC_ID_RCV_200}, // Receive process id code.
{ ATM_GEN_PATCH, FREE_CODE_OFF_2ND_200 + sizeof(PRC_ID_RCV_200), // Branch back and skip 1 instruction.
_B(FREE_CODE_OFF_2ND_200 + sizeof(PRC_ID_RCV_200), ID_RCV_OFF_200 + 4), NULL}
_B(FREE_CODE_OFF_2ND_200 + sizeof(PRC_ID_RCV_200), ID_RCV_OFF_200 + sizeof(u32)), NULL}
);
KERNEL_PATCHSET_DEF(_kernel_3_patchset,
@@ -183,11 +198,11 @@ KERNEL_PATCHSET_DEF(_kernel_3_patchset,
{ ATM_GEN_PATCH, ID_SND_OFF_300, _B(ID_SND_OFF_300, FREE_CODE_OFF_1ST_300), NULL}, // Send process id branch.
{ ATM_ARR_PATCH, FREE_CODE_OFF_1ST_300, sizeof(PRC_ID_SND_300) >> 2, PRC_ID_SND_300}, // Send process id code.
{ ATM_GEN_PATCH, FREE_CODE_OFF_1ST_300 + sizeof(PRC_ID_SND_300), // Branch back and skip 1 instruction.
_B(FREE_CODE_OFF_1ST_300 + sizeof(PRC_ID_SND_300), ID_SND_OFF_300 + 4), NULL},
_B(FREE_CODE_OFF_1ST_300 + sizeof(PRC_ID_SND_300), ID_SND_OFF_300 + sizeof(u32)), NULL},
{ ATM_GEN_PATCH, ID_RCV_OFF_300, _B(ID_RCV_OFF_300, FREE_CODE_OFF_2ND_300), NULL}, // Receive process id branch.
{ ATM_ARR_PATCH, FREE_CODE_OFF_2ND_300, sizeof(PRC_ID_RCV_300) >> 2, PRC_ID_RCV_300}, // Receive process id code.
{ ATM_GEN_PATCH, FREE_CODE_OFF_2ND_300 + sizeof(PRC_ID_RCV_300), // Branch back and skip 1 instruction.
_B(FREE_CODE_OFF_2ND_300 + sizeof(PRC_ID_RCV_300), ID_RCV_OFF_300 + 4), NULL}
_B(FREE_CODE_OFF_2ND_300 + sizeof(PRC_ID_RCV_300), ID_RCV_OFF_300 + sizeof(u32)), NULL}
);
KERNEL_PATCHSET_DEF(_kernel_302_patchset,
@@ -197,11 +212,11 @@ KERNEL_PATCHSET_DEF(_kernel_302_patchset,
{ ATM_GEN_PATCH, ID_SND_OFF_302, _B(ID_SND_OFF_302, FREE_CODE_OFF_1ST_302), NULL}, // Send process id branch.
{ ATM_ARR_PATCH, FREE_CODE_OFF_1ST_302, sizeof(PRC_ID_SND_302) >> 2, PRC_ID_SND_302}, // Send process id code.
{ ATM_GEN_PATCH, FREE_CODE_OFF_1ST_302 + sizeof(PRC_ID_SND_302), // Branch back and skip 1 instruction.
_B(FREE_CODE_OFF_1ST_302 + sizeof(PRC_ID_SND_302), ID_SND_OFF_302 + 4), NULL},
_B(FREE_CODE_OFF_1ST_302 + sizeof(PRC_ID_SND_302), ID_SND_OFF_302 + sizeof(u32)), NULL},
{ ATM_GEN_PATCH, ID_RCV_OFF_302, _B(ID_RCV_OFF_302, FREE_CODE_OFF_2ND_302), NULL}, // Receive process id branch.
{ ATM_ARR_PATCH, FREE_CODE_OFF_2ND_302, sizeof(PRC_ID_RCV_302) >> 2, PRC_ID_RCV_302}, // Receive process id code.
{ ATM_GEN_PATCH, FREE_CODE_OFF_2ND_302 + sizeof(PRC_ID_RCV_302), // Branch back and skip 1 instruction.
_B(FREE_CODE_OFF_2ND_302 + sizeof(PRC_ID_RCV_302), ID_RCV_OFF_302 + 4), NULL}
_B(FREE_CODE_OFF_2ND_302 + sizeof(PRC_ID_RCV_302), ID_RCV_OFF_302 + sizeof(u32)), NULL}
);
KERNEL_PATCHSET_DEF(_kernel_4_patchset,
@@ -211,39 +226,56 @@ KERNEL_PATCHSET_DEF(_kernel_4_patchset,
{ ATM_GEN_PATCH, ID_SND_OFF_400, _B(ID_SND_OFF_400, FREE_CODE_OFF_1ST_400), NULL}, // Send process id branch.
{ ATM_ARR_PATCH, FREE_CODE_OFF_1ST_400, sizeof(PRC_ID_SND_400) >> 2, PRC_ID_SND_400}, // Send process id code.
{ ATM_GEN_PATCH, FREE_CODE_OFF_1ST_400 + sizeof(PRC_ID_SND_400), // Branch back and skip 2 instructions.
_B(FREE_CODE_OFF_1ST_400 + sizeof(PRC_ID_SND_400), ID_SND_OFF_400 + 8), NULL},
_B(FREE_CODE_OFF_1ST_400 + sizeof(PRC_ID_SND_400), ID_SND_OFF_400 + sizeof(u32) * 2), NULL},
{ ATM_GEN_PATCH, ID_RCV_OFF_400, _B(ID_RCV_OFF_400, FREE_CODE_OFF_2ND_400), NULL}, // Receive process id branch.
{ ATM_ARR_PATCH, FREE_CODE_OFF_2ND_400, sizeof(PRC_ID_RCV_400) >> 2, PRC_ID_RCV_400}, // Receive process id code.
{ ATM_GEN_PATCH, FREE_CODE_OFF_2ND_400 + sizeof(PRC_ID_RCV_400), // Branch back and skip 1 instruction.
_B(FREE_CODE_OFF_2ND_400 + sizeof(PRC_ID_RCV_400), ID_RCV_OFF_400 + 4), NULL}
_B(FREE_CODE_OFF_2ND_400 + sizeof(PRC_ID_RCV_400), ID_RCV_OFF_400 + sizeof(u32)), NULL}
);
KERNEL_PATCHSET_DEF(_kernel_5_patchset,
{ SVC_GENERIC, 0x38C2C, _NOP(), NULL }, // Allow same process on svcControlCodeMemory.
{ SVC_VERIFY_DS, 0x45E6C, _NOP(), NULL }, // Disable SVC verifications
{ DEBUG_MODE_EN, 0x5513C, _MOVZX(8, 1, 0), NULL }, // Enable Debug Patch
// Atmosphère kernel patches.
{ ATM_GEN_PATCH, ID_SND_OFF_500, _B(ID_SND_OFF_500, FREE_CODE_OFF_1ST_500), NULL}, // Send process id branch.
{ ATM_ARR_PATCH, FREE_CODE_OFF_1ST_500, sizeof(PRC_ID_SND_500) >> 2, PRC_ID_SND_500}, // Send process id code.
{ ATM_GEN_PATCH, FREE_CODE_OFF_1ST_500 + sizeof(PRC_ID_SND_500), // Branch back and skip 2 instructions.
_B(FREE_CODE_OFF_1ST_500 + sizeof(PRC_ID_SND_500), ID_SND_OFF_500 + 8), NULL},
_B(FREE_CODE_OFF_1ST_500 + sizeof(PRC_ID_SND_500), ID_SND_OFF_500 + sizeof(u32) * 2), NULL},
{ ATM_GEN_PATCH, ID_RCV_OFF_500, _B(ID_RCV_OFF_500, FREE_CODE_OFF_2ND_500), NULL}, // Receive process id branch.
{ ATM_ARR_PATCH, FREE_CODE_OFF_2ND_500, sizeof(PRC_ID_RCV_500) >> 2, PRC_ID_RCV_500}, // Receive process id code.
{ ATM_GEN_PATCH, FREE_CODE_OFF_2ND_500 + sizeof(PRC_ID_RCV_500), // Branch back and skip 2 instructions.
_B(FREE_CODE_OFF_2ND_500 + sizeof(PRC_ID_RCV_500), ID_RCV_OFF_500 + 8), NULL}
_B(FREE_CODE_OFF_2ND_500 + sizeof(PRC_ID_RCV_500), ID_RCV_OFF_500 + sizeof(u32) * 2), NULL}
);
KERNEL_PATCHSET_DEF(_kernel_6_patchset,
{ SVC_GENERIC, 0x3A8CC, _NOP(), NULL }, // Allow same process on svcControlCodeMemory.
{ SVC_VERIFY_DS, 0x47EA0, _NOP(), NULL }, // Disable SVC verifications
{ DEBUG_MODE_EN, 0x57548, _MOVZX(8, 1, 0), NULL }, // Enable Debug Patch
// Atmosphère kernel patches.
{ ATM_GEN_PATCH, ID_SND_OFF_600, _B(ID_SND_OFF_600, FREE_CODE_OFF_1ST_600), NULL}, // Send process id branch.
{ ATM_ARR_PATCH, FREE_CODE_OFF_1ST_600, sizeof(PRC_ID_SND_600) >> 2, PRC_ID_SND_600}, // Send process id code.
{ ATM_GEN_PATCH, FREE_CODE_OFF_1ST_600 + sizeof(PRC_ID_SND_600), // Branch back and skip 4 instructions.
_B(FREE_CODE_OFF_1ST_600 + sizeof(PRC_ID_SND_600), ID_SND_OFF_600 + 0x10), NULL},
_B(FREE_CODE_OFF_1ST_600 + sizeof(PRC_ID_SND_600), ID_SND_OFF_600 + sizeof(u32) * 4), NULL},
{ ATM_GEN_PATCH, ID_RCV_OFF_600, _B(ID_RCV_OFF_600, FREE_CODE_OFF_2ND_600), NULL}, // Receive process id branch.
{ ATM_ARR_PATCH, FREE_CODE_OFF_2ND_600, sizeof(PRC_ID_RCV_600) >> 2, PRC_ID_RCV_600}, // Receive process id code.
{ ATM_GEN_PATCH, FREE_CODE_OFF_2ND_600 + sizeof(PRC_ID_RCV_600), // Branch back and skip 4 instructions.
_B(FREE_CODE_OFF_2ND_600 + sizeof(PRC_ID_RCV_600), ID_RCV_OFF_600 + 0x10), NULL}
_B(FREE_CODE_OFF_2ND_600 + sizeof(PRC_ID_RCV_600), ID_RCV_OFF_600 + sizeof(u32) * 4), NULL}
);
KERNEL_PATCHSET_DEF(_kernel_7_patchset,
{ SVC_GENERIC, 0x3C6E0, _NOP(), NULL }, // Allow same process on svcControlCodeMemory.
{ SVC_VERIFY_DS, 0x49E5C, _NOP(), NULL }, // Disable SVC verifications
{ DEBUG_MODE_EN, 0x581B0, _MOVZX(8, 1, 0), NULL }, // Enable Debug Patch
// Atmosphère kernel patches.
{ ATM_GEN_PATCH, ID_SND_OFF_700, _B(ID_SND_OFF_700, FREE_CODE_OFF_1ST_700), NULL}, // Send process id branch.
{ ATM_ARR_PATCH, FREE_CODE_OFF_1ST_700, sizeof(PRC_ID_SND_700) >> 2, PRC_ID_SND_700}, // Send process id code.
{ ATM_GEN_PATCH, FREE_CODE_OFF_1ST_700 + sizeof(PRC_ID_SND_700), // Branch back and skip 4 instructions.
_B(FREE_CODE_OFF_1ST_700 + sizeof(PRC_ID_SND_700), ID_SND_OFF_700 + sizeof(u32) * 4), NULL},
{ ATM_GEN_PATCH, ID_RCV_OFF_700, _B(ID_RCV_OFF_700, FREE_CODE_OFF_2ND_700), NULL}, // Receive process id branch.
{ ATM_ARR_PATCH, FREE_CODE_OFF_2ND_700, sizeof(PRC_ID_RCV_700) >> 2, PRC_ID_RCV_700}, // Receive process id code.
{ ATM_GEN_PATCH, FREE_CODE_OFF_2ND_700 + sizeof(PRC_ID_RCV_700), // Branch back and skip 4 instructions.
_B(FREE_CODE_OFF_2ND_700 + sizeof(PRC_ID_RCV_700), ID_RCV_OFF_700 + sizeof(u32) * 4), NULL}
);
static const pkg2_kernel_id_t _pkg2_kernel_ids[] =
@@ -255,6 +287,7 @@ static const pkg2_kernel_id_t _pkg2_kernel_ids[] =
{ 0x485d0157, _kernel_4_patchset }, //4.0.0 - 4.1.0
{ 0xf3c363f2, _kernel_5_patchset }, //5.0.0 - 5.1.0
{ 0x64ce1a44, _kernel_6_patchset }, //6.0.0 - 6.2.0
{ 0x908175e1, _kernel_7_patchset }, //7.0.0
{ 0, 0 } //End.
};
@@ -275,195 +308,238 @@ enum kip_offset_section
#define GET_KIP_PATCH_OFFSET(x) (x & KIP_PATCH_OFFSET_MASK)
#define KPS(x) ((u32)(x) << KIP_PATCH_SECTION_SHIFT)
static kip1_patch_t _fs_nosigchk_100[] =
static kip1_patch_t _fs_nosigchk_100[] =
{
{ KPS(KIP_TEXT) | 0x194A0, 4, "\xBA\x09\x00\x94", "\xE0\x03\x1F\x2A" },
{ KPS(KIP_TEXT) | 0x3A79C, 4, "\xE0\x06\x00\x36", "\x1F\x20\x03\xD5" },
{ 0, 0, NULL, NULL }
};
static kip1_patchset_t _fs_patches_100[] =
static kip1_patchset_t _fs_patches_100[] =
{
{ "nosigchk", _fs_nosigchk_100 },
{ "nogc", NULL },
{ NULL, NULL }
};
static kip1_patch_t _fs_nosigchk_200[] =
static kip1_patch_t _fs_nosigchk_200[] =
{
{ KPS(KIP_TEXT) | 0x15DF4, 4, "\xBC\x0A\x00\x94", "\xE0\x03\x1F\x2A" },
{ KPS(KIP_TEXT) | 0x3F720, 4, "\x00\x06\x00\x36", "\x1F\x20\x03\xD5" },
{ 0, 0, NULL, NULL }
};
static kip1_patchset_t _fs_patches_200[] =
static kip1_patchset_t _fs_patches_200[] =
{
{ "nosigchk", _fs_nosigchk_200 },
{ "nogc", NULL },
{ NULL, NULL }
};
static kip1_patch_t _fs_nosigchk_210[] =
static kip1_patch_t _fs_nosigchk_210[] =
{
{ KPS(KIP_TEXT) | 0x15F64, 4, "\xDF\x0A\x00\x94", "\xE0\x03\x1F\x2A" },
{ KPS(KIP_TEXT) | 0x3FAF8, 4, "\x00\x06\x00\x36", "\x1F\x20\x03\xD5" },
{ 0, 0, NULL, NULL }
};
static kip1_patchset_t _fs_patches_210[] =
static kip1_patchset_t _fs_patches_210[] =
{
{ "nosigchk", _fs_nosigchk_210 },
{ "nogc", NULL },
{ NULL, NULL }
};
static kip1_patch_t _fs_nosigchk_300[] =
static kip1_patch_t _fs_nosigchk_300[] =
{
{ KPS(KIP_TEXT) | 0x18E24, 4, "\x52\x0C\x00\x94", "\xE0\x03\x1F\x2A" },
{ KPS(KIP_TEXT) | 0x49EC8, 4, "\x40\x04\x00\x36", "\x1F\x20\x03\xD5" },
{ 0, 0, NULL, NULL }
};
static kip1_patchset_t _fs_patches_300[] =
static kip1_patchset_t _fs_patches_300[] =
{
{ "nosigchk", _fs_nosigchk_300 },
{ "nogc", NULL },
{ NULL, NULL }
};
static kip1_patch_t _fs_nosigchk_30x[] =
static kip1_patch_t _fs_nosigchk_30x[] =
{
{ KPS(KIP_TEXT) | 0x18E90, 4, "\x52\x0C\x00\x94", "\xE0\x03\x1F\x2A" },
{ KPS(KIP_TEXT) | 0x49F34, 4, "\xE0\x03\x00\x36", "\x1F\x20\x03\xD5" },
{ 0, 0, NULL, NULL }
};
static kip1_patchset_t _fs_patches_30x[] =
static kip1_patchset_t _fs_patches_30x[] =
{
{ "nosigchk", _fs_nosigchk_30x },
{ "nogc", NULL },
{ NULL, NULL }
};
static kip1_patch_t _fs_nosigchk_4xx[] =
static kip1_patch_t _fs_nosigchk_4xx[] =
{
{ KPS(KIP_TEXT) | 0x1C4FC, 4, "\x3C\x2F\x00\x94", "\xE0\x03\x1F\x2A" },
{ KPS(KIP_TEXT) | 0x57934, 4, "\xE0\x02\x00\x36", "\x1F\x20\x03\xD5" },
{ 0, 0, NULL, NULL }
};
static kip1_patch_t _fs_nogc_40x[] =
static kip1_patch_t _fs_nogc_40x[] =
{
{ KPS(KIP_TEXT) | 0xA3458, 4, "\x14\x40\x80\x72", "\x14\x80\x80\x72" },
{ KPS(KIP_TEXT) | 0xAAB44, 8, "\xF4\x4F\xBE\xA9\xFD\x7B\x01\xA9", "\xE0\x03\x1F\x2A\xC0\x03\x5F\xD6" },
{ 0, 0, NULL, NULL }
};
static kip1_patchset_t _fs_patches_40x[] =
static kip1_patchset_t _fs_patches_40x[] =
{
{ "nosigchk", _fs_nosigchk_4xx },
{ "nogc", _fs_nogc_40x },
{ NULL, NULL }
};
static kip1_patch_t _fs_nogc_410[] =
static kip1_patch_t _fs_nogc_410[] =
{
{ KPS(KIP_TEXT) | 0xA34BC, 4, "\x14\x40\x80\x72", "\x14\x80\x80\x72" },
{ KPS(KIP_TEXT) | 0xAABA8, 8, "\xF4\x4F\xBE\xA9\xFD\x7B\x01\xA9", "\xE0\x03\x1F\x2A\xC0\x03\x5F\xD6" },
{ 0, 0, NULL, NULL }
};
static kip1_patchset_t _fs_patches_410[] =
static kip1_patchset_t _fs_patches_410[] =
{
{ "nosigchk", _fs_nosigchk_4xx },
{ "nogc", _fs_nogc_410 },
{ NULL, NULL }
};
static kip1_patch_t _fs_nosigchk_50x[] =
static kip1_patch_t _fs_nosigchk_50x[] =
{
{ KPS(KIP_TEXT) | 0x22DDC, 4, "\x7D\x3E\x00\x94", "\xE0\x03\x1F\x2A" },
{ KPS(KIP_TEXT) | 0x7D490, 4, "\x40\x03\x00\x36", "\x1F\x20\x03\xD5" },
{ 0, 0, NULL, NULL }
};
static kip1_patch_t _fs_nogc_50x[] =
static kip1_patch_t _fs_nogc_50x[] =
{
{ KPS(KIP_TEXT) | 0xCF3C4, 4, "\x14\x40\x80\x52", "\x14\x80\x80\x52" },
{ KPS(KIP_TEXT) | 0xD73A0, 8, "\xF4\x4F\xBE\xA9\xFD\x7B\x01\xA9", "\xE0\x03\x1F\x2A\xC0\x03\x5F\xD6" },
{ 0, 0, NULL, NULL }
};
static kip1_patchset_t _fs_patches_50x[] =
static kip1_patchset_t _fs_patches_50x[] =
{
{ "nosigchk", _fs_nosigchk_50x },
{ "nogc", _fs_nogc_50x },
{ NULL, NULL }
};
static kip1_patch_t _fs_nosigchk_510[] =
static kip1_patch_t _fs_nosigchk_510[] =
{
{ KPS(KIP_TEXT) | 0x22E0C, 4, "\x85\x3E\x00\x94", "\xE0\x03\x1F\x2A" },
{ KPS(KIP_TEXT) | 0x7D860, 4, "\x40\x03\x00\x36", "\x1F\x20\x03\xD5" },
{ 0, 0, NULL, NULL }
};
static kip1_patch_t _fs_nogc_510[] =
static kip1_patch_t _fs_nogc_510[] =
{
{ KPS(KIP_TEXT) | 0xCF794, 4, "\x14\x40\x80\x52", "\x14\x80\x80\x52" },
{ KPS(KIP_TEXT) | 0xD7770, 8, "\xF4\x4F\xBE\xA9\xFD\x7B\x01\xA9", "\xE0\x03\x1F\x2A\xC0\x03\x5F\xD6" },
{ 0, 0, NULL, NULL }
};
static kip1_patchset_t _fs_patches_510[] =
static kip1_patchset_t _fs_patches_510[] =
{
{ "nosigchk", _fs_nosigchk_510 },
{ "nogc", _fs_nogc_510 },
{ NULL, NULL }
};
static kip1_patch_t _fs_nosigchk_600[] =
static kip1_patch_t _fs_nosigchk_600[] =
{
{ KPS(KIP_TEXT) | 0x712A8, 4, "\x8E\x3E\x00\x94", "\xE0\x03\x1F\x2A" },
{ KPS(KIP_TEXT) | 0xEB08C, 4, "\xC0\x03\x00\x36", "\x1F\x20\x03\xD5" },
{ 0, 0, NULL, NULL }
};
static kip1_patch_t _fs_nosigchk_600_exfat[] =
static kip1_patch_t _fs_nosigchk_600_exfat[] =
{
{ KPS(KIP_TEXT) | 0x7C9A8, 4, "\x8E\x3E\x00\x94", "\xE0\x03\x1F\x2A" },
{ KPS(KIP_TEXT) | 0xF678C, 4, "\xC0\x03\x00\x36", "\x1F\x20\x03\xD5" },
{ 0, 0, NULL, NULL }
};
static kip1_patch_t _fs_nogc_600[] =
static kip1_patch_t _fs_nogc_600[] =
{
{ KPS(KIP_TEXT) | 0x12CC20, 8, "\xF4\x4F\xBE\xA9\xFD\x7B\x01\xA9", "\xE0\x03\x1F\x2A\xC0\x03\x5F\xD6" },
{ KPS(KIP_TEXT) | 0x1538F4, 4, "\x14\x40\x80\x52", "\x14\x80\x80\x52" },
{ 0, 0, NULL, NULL }
};
static kip1_patch_t _fs_nogc_600_exfat[] =
static kip1_patch_t _fs_nogc_600_exfat[] =
{
{ KPS(KIP_TEXT) | 0x138320, 8, "\xF4\x4F\xBE\xA9\xFD\x7B\x01\xA9", "\xE0\x03\x1F\x2A\xC0\x03\x5F\xD6" },
{ KPS(KIP_TEXT) | 0x15EFF4, 4, "\x14\x40\x80\x52", "\x14\x80\x80\x52" },
{ 0, 0, NULL, NULL }
};
static kip1_patchset_t _fs_patches_600[] =
static kip1_patchset_t _fs_patches_600[] =
{
{ "nosigchk", _fs_nosigchk_600 },
{ "nogc", _fs_nogc_600 },
{ NULL, NULL }
};
static kip1_patchset_t _fs_patches_600_exfat[] =
static kip1_patchset_t _fs_patches_600_exfat[] =
{
{ "nosigchk", _fs_nosigchk_600_exfat },
{ "nogc", _fs_nogc_600_exfat },
{ NULL, NULL }
};
static kip1_patch_t _fs_nosigchk_700[] =
{
{ KPS(KIP_TEXT) | 0x74A2C, 4, "\x31\x43\x00\x94", "\xE0\x03\x1F\x2A" },
{ KPS(KIP_TEXT) | 0xF25E4, 4, "\xC0\x03\x00\x36", "\x1F\x20\x03\xD5" },
{ 0, 0, NULL, NULL }
};
static kip1_patch_t _fs_nosigchk_700_exfat[] =
{
{ KPS(KIP_TEXT) | 0x7FFDC, 4, "\x31\x43\x00\x94", "\xE0\x03\x1F\x2A" },
{ KPS(KIP_TEXT) | 0xFDB94, 4, "\xC0\x03\x00\x36", "\x1F\x20\x03\xD5" },
{ 0, 0, NULL, NULL }
};
static kip1_patch_t _fs_nogc_700[] =
{
{ KPS(KIP_TEXT) | 0x134160, 8, "\xF4\x4F\xBE\xA9\xFD\x7B\x01\xA9", "\xE0\x03\x1F\x2A\xC0\x03\x5F\xD6" },
{ KPS(KIP_TEXT) | 0x15BF04, 4, "\x14\x40\x80\x52", "\x14\x80\x80\x52" },
{ 0, 0, NULL, NULL }
};
static kip1_patch_t _fs_nogc_700_exfat[] =
{
{ KPS(KIP_TEXT) | 0x13F710, 8, "\xF4\x4F\xBE\xA9\xFD\x7B\x01\xA9", "\xE0\x03\x1F\x2A\xC0\x03\x5F\xD6" },
{ KPS(KIP_TEXT) | 0x1674B4, 4, "\x14\x40\x80\x52", "\x14\x80\x80\x52" },
{ 0, 0, NULL, NULL }
};
static kip1_patchset_t _fs_patches_700[] =
{
{ "nosigchk", _fs_nosigchk_700 },
{ "nogc", _fs_nogc_700 },
{ NULL, NULL }
};
static kip1_patchset_t _fs_patches_700_exfat[] =
{
{ "nosigchk", _fs_nosigchk_700_exfat },
{ "nogc", _fs_nogc_700_exfat },
{ NULL, NULL }
};
// SHA256 hashes.
static kip1_id_t _kip_ids[] =
{
{ "FS", "\xde\x9f\xdd\xa4\x08\x5d\xd5\xfe\x68\xdc\xb2\x0b\x41\x09\x5b\xb4", _fs_patches_100 }, // FS 1.0.0
@@ -487,7 +563,9 @@ static kip1_id_t _kip_ids[] =
{ "FS", "\x1b\x82\xcb\x22\x18\x67\xcb\x52\xc4\x4a\x86\x9e\xa9\x1a\x1a\xdd", _fs_patches_600 }, // FS 6.0.0-4.0
{ "FS", "\x96\x6a\xdd\x3d\x20\xb6\x27\x13\x2c\x5a\x8d\xa4\x9a\xc9\xd8\xdd", _fs_patches_600_exfat }, // FS 6.0.0-4.0 exfat
{ "FS", "\x3a\x57\x4d\x43\x61\x86\x19\x1d\x17\x88\xeb\x2c\x0f\x07\x6b\x11", _fs_patches_600 }, // FS 6.0.0-5.0
{ "FS", "\x33\x05\x53\xf6\xb5\xfb\x55\xc4\xc2\xd7\xb7\x36\x24\x02\x76\xb3", _fs_patches_600_exfat } // FS 6.0.0-5.0 exfat
{ "FS", "\x33\x05\x53\xf6\xb5\xfb\x55\xc4\xc2\xd7\xb7\x36\x24\x02\x76\xb3", _fs_patches_600_exfat }, // FS 6.0.0-5.0 exfat
{ "FS", "\x2A\xDB\xE9\x7E\x9B\x5F\x41\x77\x9E\xC9\x5F\xFE\x26\x99\xC9\x33", _fs_patches_700 }, // FS 7.0.0
{ "FS", "\x2C\xCE\x65\x9C\xEC\x53\x6A\x8E\x4D\x91\xF3\xBE\x4B\x74\xBE\xD3", _fs_patches_700_exfat } // FS 7.0.0 exfat
};
const pkg2_kernel_id_t *pkg2_identify(u32 id)
@@ -571,7 +649,7 @@ int pkg2_decompress_kip(pkg2_kip1_info_t* ki, u32 sectsToDecomp)
memcpy(&hdr, ki->kip1, sizeof(hdr));
unsigned int newKipSize = sizeof(hdr);
for (u32 sectIdx=0; sectIdx<KIP1_NUM_SECTIONS; sectIdx++)
for (u32 sectIdx = 0; sectIdx < KIP1_NUM_SECTIONS; sectIdx++)
{
u32 sectCompBit = 1u << sectIdx;
// For compressed, cant get actual decompressed size without doing it, so use safe "output size".
@@ -584,7 +662,7 @@ int pkg2_decompress_kip(pkg2_kip1_info_t* ki, u32 sectsToDecomp)
pkg2_kip1_t* newKip = malloc(newKipSize);
unsigned char* dstDataPtr = newKip->data;
const unsigned char* srcDataPtr = ki->kip1->data;
for (u32 sectIdx=0; sectIdx<KIP1_NUM_SECTIONS; sectIdx++)
for (u32 sectIdx = 0; sectIdx < KIP1_NUM_SECTIONS; sectIdx++)
{
u32 sectCompBit = 1u << sectIdx;
// Easy copy path for uncompressed or ones we dont want to uncompress.
@@ -638,7 +716,7 @@ const char* pkg2_patch_kips(link_t *info, char* patchNames)
static const u32 MAX_NUM_PATCHES_REQUESTED = sizeof(u32)*8;
char* patches[MAX_NUM_PATCHES_REQUESTED];
u32 numPatches=1;
u32 numPatches = 1;
patches[0] = patchNames;
{
for (char* p = patchNames; *p != 0; p++)
@@ -646,7 +724,7 @@ const char* pkg2_patch_kips(link_t *info, char* patchNames)
if (*p == ',')
{
*p = 0;
patches[numPatches++] = p+1;
patches[numPatches++] = p + 1;
if (numPatches >= MAX_NUM_PATCHES_REQUESTED)
return "too_many_patches";
}
@@ -656,10 +734,10 @@ const char* pkg2_patch_kips(link_t *info, char* patchNames)
}
u32 patchesApplied = 0; // Bitset over patches.
for (u32 i=0; i<numPatches; i++)
for (u32 i = 0; i < numPatches; i++)
{
// Eliminate leading spaces.
for (const char* p=patches[i]; *p!=0; p++)
for (const char* p = patches[i]; *p != 0; p++)
{
if (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n')
patches[i]++;
@@ -671,7 +749,7 @@ const char* pkg2_patch_kips(link_t *info, char* patchNames)
continue;
// Eliminate trailing spaces.
for (int chIdx=valueLen-1; chIdx>=0; chIdx--)
for (int chIdx=valueLen - 1; chIdx >= 0; chIdx--)
{
const char* p = patches[i] + chIdx;
if (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n')
@@ -684,11 +762,11 @@ const char* pkg2_patch_kips(link_t *info, char* patchNames)
DPRINTF("Requested patch: '%s'\n", patches[i]);
}
u32 shaBuf[32/sizeof(u32)];
u32 shaBuf[32 / sizeof(u32)];
LIST_FOREACH_ENTRY(pkg2_kip1_info_t, ki, info, link)
{
shaBuf[0] = 0; // sha256 for this kip not yet calculated.
for (u32 currKipIdx=0; currKipIdx<(sizeof(_kip_ids)/sizeof(_kip_ids[0])); currKipIdx++)
for (u32 currKipIdx = 0; currKipIdx < (sizeof(_kip_ids) / sizeof(_kip_ids[0])); currKipIdx++)
{
if (strncmp((const char*)ki->kip1->name, _kip_ids[currKipIdx].name, sizeof(ki->kip1->name)) != 0)
continue;
@@ -697,7 +775,7 @@ const char* pkg2_patch_kips(link_t *info, char* patchNames)
kip1_patchset_t* currPatchset = _kip_ids[currKipIdx].patchset;
while (currPatchset != NULL && currPatchset->name != NULL)
{
for (u32 i=0; i<numPatches; i++)
for (u32 i = 0; i < numPatches; i++)
{
if (strcmp(currPatchset->name, patches[i]) != 0)
{
@@ -728,7 +806,7 @@ const char* pkg2_patch_kips(link_t *info, char* patchNames)
{
if (currPatchset->patches != NULL)
{
for (u32 currEnabIdx=0; currEnabIdx<numPatches; currEnabIdx++)
for (u32 currEnabIdx = 0; currEnabIdx < numPatches; currEnabIdx++)
{
if (strcmp(currPatchset->name, patches[currEnabIdx]))
continue;
@@ -752,13 +830,13 @@ const char* pkg2_patch_kips(link_t *info, char* patchNames)
if (!se_calc_sha256(shaBuf, ki->kip1, ki->size))
memset(shaBuf, 0, sizeof(shaBuf));
DPRINTF("%dms %s KIP1 size %d hash %08X\n", (postDecompTime-preDecompTime)/1000, ki->kip1->name, (int)ki->size, __builtin_bswap32(shaBuf[0]));
DPRINTF("%dms %s KIP1 size %d hash %08X\n", (postDecompTime-preDecompTime) / 1000, ki->kip1->name, (int)ki->size, __builtin_bswap32(shaBuf[0]));
#endif
currPatchset = _kip_ids[currKipIdx].patchset;
while (currPatchset != NULL && currPatchset->name != NULL)
{
for (u32 currEnabIdx=0; currEnabIdx<numPatches; currEnabIdx++)
for (u32 currEnabIdx = 0; currEnabIdx < numPatches; currEnabIdx++)
{
if (strcmp(currPatchset->name, patches[currEnabIdx]))
continue;
@@ -772,7 +850,7 @@ const char* pkg2_patch_kips(link_t *info, char* patchNames)
}
unsigned char* kipSectData = ki->kip1->data;
for (u32 currSectIdx=0; currSectIdx<KIP1_NUM_SECTIONS; currSectIdx++)
for (u32 currSectIdx = 0; currSectIdx < KIP1_NUM_SECTIONS; currSectIdx++)
{
if (bitsAffected & (1u << currSectIdx))
{
@@ -806,7 +884,7 @@ const char* pkg2_patch_kips(link_t *info, char* patchNames)
}
}
for (u32 i=0; i<numPatches; i++)
for (u32 i = 0; i < numPatches; i++)
{
if ((patchesApplied & (1u << i)) == 0)
return patches[i];
@@ -899,4 +977,3 @@ DPRINTF("INI1 encrypted\n");
memset(hdr->ctr, 0 , 0x10);
*(u32 *)hdr->ctr = 0x100 + sizeof(pkg2_hdr_t) + kernel_size + ini1_size;
}

View File

@@ -44,8 +44,10 @@ typedef struct _kernel_patch_t
enum
{
// Generic instruction patches
SVC_VERIFY_DS = 0x10, // 0x0-0xF are RESERVED.
// Always applied.
SVC_GENERIC = 0,
// Generic instruction patches.
SVC_VERIFY_DS = 0x10,
DEBUG_MODE_EN,
ATM_GEN_PATCH,
// >4 bytes patches. Value is a pointer of a u32 array.
@@ -115,16 +117,16 @@ typedef struct _pkg2_kernel_id_t
typedef struct _kip1_patch_t
{
u32 offset; //section+offset of patch to apply
u32 length; //in bytes, 0 means last patch
const char* srcData; //that must match
const char* dstData; //that it gets replaced by
u32 offset; // section+offset of patch to apply.
u32 length; // In bytes, 0 means last patch.
const char* srcData; // That must match.
const char* dstData; // That it gets replaced by.
} kip1_patch_t;
typedef struct _kip1_patchset_t
{
const char* name; //NULL means end
kip1_patch_t* patches; //NULL means not necessary
const char* name; // NULL means end.
kip1_patch_t* patches; // NULL means not necessary.
} kip1_patchset_t;
typedef struct _kip1_id_t

View File

@@ -1,5 +1,5 @@
/*
* 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,
@@ -17,25 +17,44 @@
#include <string.h>
#include "hos.h"
#include "../mem/heap.h"
#include "../soc/fuse.h"
#include "../storage/sdmmc.h"
#include "../utils/types.h"
// Exosphère mailbox defines.
#define EXO_MAGIC_ADDR 0x40002E40
#define EXO_MAGIC_VAL 0x31434258
#define EXO_FWNO_ADDR 0x40002E44
#define EXO_FLAGS_ADDR 0x40002E48
#define EXO_FLAG_620_KGN (1 << 0)
#define EXO_FLAG_DBG_PRIV (1 << 1)
#define EXO_FLAG_DBG_USER (1 << 2)
typedef struct _exo_cfg_t
{
vu32 magic;
vu32 fwno;
vu32 flags;
vu32 rsvd;
} exo_cfg_t;
void config_exosphere(const char *id, u32 kb, bool debug)
typedef struct _atm_meta_t
{
uint32_t magic;
uint32_t fwno;
} wb_cfg_t;
#define ATM_WB_HEADER_OFF 0x244
#define ATM_WB_MAGIC 0x30544257
// Exosphère mailbox defines.
#define EXO_CFG_DEPR_ADDR 0x40002E40 // Deprecated.
#define EXO_CFG_ADDR 0x8000F000
#define EXO_MAGIC_DEPR_VAL 0x31434258
#define EXO_MAGIC_VAL 0x304F5845
#define EXO_FLAG_620_KGN (1 << 0)
#define EXO_FLAG_DBG_PRIV (1 << 1)
#define EXO_FLAG_DBG_USER (1 << 2)
void config_exosphere(const char *id, u32 kb, void *warmboot, void *pkg1)
{
u32 exoFwNo = 0;
u32 exoFlags = 0;
vu32 *mb_exo_magic = (vu32 *)EXO_MAGIC_ADDR;
vu32 *mb_exo_fw_no = (vu32 *)EXO_FWNO_ADDR;
vu32 *mb_exo_flags = (vu32 *)EXO_FLAGS_ADDR;
volatile exo_cfg_t *exo_cfg_depr = (exo_cfg_t *)EXO_CFG_DEPR_ADDR;
volatile exo_cfg_t *exo_cfg = (exo_cfg_t *)EXO_CFG_ADDR;
switch (kb)
{
@@ -53,14 +72,46 @@ void config_exosphere(const char *id, u32 kb, bool debug)
break;
}
if (kb >= KB_FIRMWARE_VERSION_620)
if (kb == KB_FIRMWARE_VERSION_620)
exoFlags |= EXO_FLAG_620_KGN;
if (debug)
exoFlags |= EXO_FLAG_DBG_PRIV | EXO_FLAG_DBG_USER;
// To avoid problems, make private debug mode always on.
exoFlags |= EXO_FLAG_DBG_PRIV;
// Set mailbox values.
*mb_exo_magic = EXO_MAGIC_VAL;
*mb_exo_fw_no = exoFwNo;
*mb_exo_flags = exoFlags;
exo_cfg_depr->magic = EXO_MAGIC_VAL;
exo_cfg->magic = EXO_MAGIC_VAL;
exo_cfg_depr->fwno = exoFwNo;
exo_cfg->fwno = exoFwNo;
exo_cfg_depr->flags = exoFlags;
exo_cfg->flags = exoFlags;
// If warmboot is lp0fw, add in RSA modulus.
volatile wb_cfg_t *wb_cfg = (wb_cfg_t *)(warmboot + ATM_WB_HEADER_OFF);
if (wb_cfg->magic == ATM_WB_MAGIC)
{
wb_cfg->fwno = exoFwNo;
sdmmc_storage_t storage;
sdmmc_t sdmmc;
// Set warmboot binary rsa modulus.
u8 *rsa_mod = (u8 *)malloc(512);
sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4);
sdmmc_storage_set_mmc_partition(&storage, 1);
sdmmc_storage_read(&storage, 1, 1, rsa_mod);
sdmmc_storage_end(&storage);
// Patch AutoRCM out.
if ((fuse_read_odm(4) & 3) != 3)
rsa_mod[0x10] = 0xF7;
else
rsa_mod[0x10] = 0x37;
memcpy(warmboot + 0x10, rsa_mod + 0x10, 0x100);
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2018 CTCaer
* Copyright (C) 2018-2019 CTCaer
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@@ -19,6 +19,6 @@
#include "../utils/types.h"
void config_exosphere(const char *id, u32 kb, bool debug);
void config_exosphere(const char *id, u32 kb, void *warmboot, void *pkg1);
#endif

206
bootloader/hos/sept.c Normal file
View File

@@ -0,0 +1,206 @@
/*
* 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 "hos.h"
#include "sept.h"
#include "../config/config.h"
#include "../gfx/di.h"
#include "../ianos/ianos.h"
#include "../libs/fatfs/ff.h"
#include "../mem/heap.h"
#include "../soc/pmc.h"
#include "../soc/t210.h"
#include "../storage/nx_emmc.h"
#include "../storage/sdmmc.h"
#include "../utils/btn.h"
#include "../utils/types.h"
#include "../gfx/gfx.h"
#define RELOC_META_OFF 0x7C
#define PATCHED_RELOC_SZ 0x94
#define WB_RST_ADDR 0x40010ED0
#define WB_RST_SIZE 0x30
u8 warmboot_reboot[] = {
0x14, 0x00, 0x9F, 0xE5, // LDR R0, =0x7000E450
0x01, 0x10, 0xB0, 0xE3, // MOVS R1, #1
0x00, 0x10, 0x80, 0xE5, // STR R1, [R0]
0x0C, 0x00, 0x9F, 0xE5, // LDR R0, =0x7000E400
0x10, 0x10, 0xB0, 0xE3, // MOVS R1, #0x10
0x00, 0x10, 0x80, 0xE5, // STR R1, [R0]
0xFE, 0xFF, 0xFF, 0xEA, // LOOP
0x50, 0xE4, 0x00, 0x70, // #0x7000E450
0x00, 0xE4, 0x00, 0x70 // #0x7000E400
};
#define SEPT_PRI_ADDR 0x4003F000
#define SEPT_PK1T_ADDR 0xC0400000
#define SEPT_TCSZ_ADDR (SEPT_PK1T_ADDR - 0x4)
#define SEPT_STG1_ADDR (SEPT_PK1T_ADDR + 0x2E100)
#define SEPT_STG2_ADDR (SEPT_PK1T_ADDR + 0x60E0)
#define SEPT_PKG_SZ (0x2F100 + WB_RST_SIZE)
extern boot_cfg_t b_cfg;
extern hekate_config h_cfg;
extern const volatile ipl_ver_meta_t ipl_ver;
extern void *sd_file_read(char *path);
extern void sd_mount();
extern void sd_unmount();
extern bool is_ipl_updated(void *buf);
extern void reloc_patcher(u32 payload_dst, u32 payload_src, u32 payload_size);
void check_sept()
{
// Check if non-hekate payload is used for sept and restore it.
if (h_cfg.sept_run && !f_stat("sept/payload.bak", NULL))
{
f_unlink("sept/payload.bin");
f_rename("sept/payload.bak", "sept/payload.bin");
return;
}
u8 *pkg1 = (u8 *)calloc(1, 0x40000);
sdmmc_storage_t storage;
sdmmc_t sdmmc;
if (!sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4))
{
EPRINTF("Failed to init eMMC.");
goto out_free;
}
sdmmc_storage_set_mmc_partition(&storage, 1);
// Read package1.
sdmmc_storage_read(&storage, 0x100000 / NX_EMMC_BLOCKSIZE, 0x40000 / NX_EMMC_BLOCKSIZE, pkg1);
const pkg1_id_t *pkg1_id = pkg1_identify(pkg1);
if (!pkg1_id)
{
gfx_con.fntsz = 16;
EPRINTF("Unknown pkg1 version.");
goto out_free;
}
if (pkg1_id->kb >= KB_FIRMWARE_VERSION_700 && !h_cfg.sept_run)
{
sdmmc_storage_end(&storage);
reboot_to_sept((u8 *)pkg1 + pkg1_id->tsec_off);
}
out_free:
free(pkg1);
sdmmc_storage_end(&storage);
}
int reboot_to_sept(const u8 *tsec_fw)
{
FIL fp;
// Copy warmboot reboot code and TSEC fw.
memcpy((u8 *)(SEPT_PK1T_ADDR - WB_RST_SIZE), (u8 *)warmboot_reboot, sizeof(warmboot_reboot));
memcpy((void *)SEPT_PK1T_ADDR, tsec_fw, 0x3000);
*(vu32 *)SEPT_TCSZ_ADDR = 0x3000;
// Copy sept-primary.
if (f_open(&fp, "sept/sept-primary.bin", FA_READ))
goto error;
if (f_read(&fp, (u8 *)SEPT_STG1_ADDR, f_size(&fp), NULL))
{
f_close(&fp);
goto error;
}
f_close(&fp);
// Copy sept-secondary.
if (f_open(&fp, "sept/sept-secondary.enc", FA_READ))
goto error;
if (f_read(&fp, (u8 *)SEPT_STG2_ADDR, f_size(&fp), NULL))
{
f_close(&fp);
goto error;
}
f_close(&fp);
b_cfg.boot_cfg |= (BOOT_CFG_AUTOBOOT_EN | BOOT_CFG_SEPT_RUN);
bool update_sept_payload = true;
if (!f_open(&fp, "sept/payload.bin", FA_READ | FA_WRITE))
{
ipl_ver_meta_t tmp_ver;
f_lseek(&fp, PATCHED_RELOC_SZ + sizeof(boot_cfg_t));
f_read(&fp, &tmp_ver, sizeof(ipl_ver_meta_t), NULL);
if (tmp_ver.magic == ipl_ver.magic)
{
if (tmp_ver.version == ipl_ver.version)
{
// Save auto boot config to sept payload, if any.
boot_cfg_t *tmp_cfg = malloc(sizeof(boot_cfg_t));
memcpy(tmp_cfg, &b_cfg, sizeof(boot_cfg_t));
f_lseek(&fp, PATCHED_RELOC_SZ);
f_write(&fp, tmp_cfg, sizeof(boot_cfg_t), NULL);
f_close(&fp);
update_sept_payload = false;
}
}
else
f_rename("sept/payload.bin", "sept/payload.bak"); // Backup foreign payload.
f_close(&fp);
}
if (update_sept_payload)
{
volatile reloc_meta_t *reloc = (reloc_meta_t *)(IPL_LOAD_ADDR + RELOC_META_OFF);
f_open(&fp, "sept/payload.bin", FA_WRITE | FA_CREATE_ALWAYS);
f_write(&fp, (u8 *)reloc->start, reloc->end - reloc->start, NULL);
f_close(&fp);
}
sd_unmount();
u32 pk1t_sept = SEPT_PK1T_ADDR - (ALIGN(PATCHED_RELOC_SZ, 0x10) + WB_RST_SIZE);
void (*sept)() = (void *)pk1t_sept;
reloc_patcher(WB_RST_ADDR, pk1t_sept, SEPT_PKG_SZ);
// Patch SDRAM init to perform an SVC immediately after second write.
PMC(APBDEV_PMC_SCRATCH45) = 0x2E38DFFF;
PMC(APBDEV_PMC_SCRATCH46) = 0x6001DC28;
// Set SVC handler to jump to sept-primary in IRAM.
PMC(APBDEV_PMC_SCRATCH33) = SEPT_PRI_ADDR;
PMC(APBDEV_PMC_SCRATCH40) = 0x6000F208;
display_end();
(*sept)();
error:
EPRINTF("Failed to run sept\n");
display_backlight_brightness(h_cfg.backlight, 1000);
btn_wait();
return 0;
}

25
bootloader/hos/sept.h Normal file
View File

@@ -0,0 +1,25 @@
/*
* 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 _SEPT_H_
#define _SEPT_H_
#include "../utils/types.h"
void check_sept();
int reboot_to_sept(const u8 *tsec_fw);
#endif

View File

@@ -27,8 +27,6 @@
#define IRAM_LIB_ADDR 0x4002B000
#define DRAM_LIB_ADDR 0xE0000000
extern gfx_ctxt_t gfx_ctxt;
extern gfx_con_t gfx_con;
extern heap_t _heap;
extern void *sd_file_read(char *path);
@@ -84,7 +82,7 @@ void ianos_print_error(int errorno)
gfx_printf(&gfx_con, "Error loading ELF!\n");
break;
case 5:
gfx_printf(&gfx_con, "Error relcating ELF!\n");
gfx_printf(&gfx_con, "Error relocating ELF!\n");
break;
}
}

View File

@@ -26,7 +26,6 @@
#ifdef DEBUG
#include "../../gfx/gfx.h"
extern gfx_con_t gfx_con;
#define EL_DEBUG(format, ...) \
gfx_printf(&gfx_con, format __VA_OPT__(, ) __VA_ARGS__)
#else

View File

@@ -11,6 +11,8 @@
#include "diskio.h" /* FatFs lower layer API */
#include "../../storage/sdmmc.h"
#define SDMMC_UPPER_BUFFER 0xB8000000
extern sdmmc_storage_t sd_storage;
DSTATUS disk_status (
@@ -36,7 +38,7 @@ DRESULT disk_read (
{
if ((u32)buff >= 0x90000000)
return sdmmc_storage_read(&sd_storage, sector, count, buff) ? RES_OK : RES_ERROR;
u8 *buf = (u8 *)0x98000000; //TODO: define this somewhere.
u8 *buf = (u8 *)SDMMC_UPPER_BUFFER; //TODO: define this somewhere.
if (sdmmc_storage_read(&sd_storage, sector, count, buf))
{
memcpy(buff, buf, 512 * count);
@@ -54,7 +56,7 @@ DRESULT disk_write (
{
if ((u32)buff >= 0x90000000)
return sdmmc_storage_write(&sd_storage, sector, count, (void *)buff) ? RES_OK : RES_ERROR;
u8 *buf = (u8 *)0x98000000; //TODO: define this somewhere.
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;

View File

@@ -23,10 +23,8 @@
#include "ff.h" /* Declarations of FatFs API */
#include "diskio.h" /* Declarations of device I/O functions */
#include "../../gfx/gfx.h"
extern gfx_ctxt_t gfx_ctxt;
extern gfx_con_t gfx_con;
#define EFSPRINTF(text, ...) print_error(); gfx_printf(&gfx_con, "%k"text"%k\n", 0xFFFFFF00, 0xFFFFFFFF);
//#define EFSPRINTF(...)

View File

@@ -1,9 +1,12 @@
ENTRY(_start)
SECTIONS {
PROVIDE(__ipl_start = 0x40008000);
PROVIDE(__ipl_start = IPL_LOAD_ADDR);
. = __ipl_start;
.text : {
*(.text._start);
*(._boot_cfg);
*(._ipl_version);
*(.text*);
}
.data : {

View File

@@ -1,7 +1,7 @@
/*
* 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,
@@ -25,15 +25,16 @@
#include "gfx/logos.h"
#include "gfx/tui.h"
#include "hos/hos.h"
#include "hos/sept.h"
#include "ianos/ianos.h"
#include "libs/compr/blz.h"
#include "libs/fatfs/ff.h"
#include "mem/heap.h"
#include "mem/sdram.h"
#include "power/max77620.h"
#include "rtc/max77620-rtc.h"
#include "soc/hw_init.h"
#include "soc/i2c.h"
#include "soc/pmc.h"
#include "soc/t210.h"
#include "soc/uart.h"
#include "storage/sdmmc.h"
@@ -46,16 +47,6 @@
#include "frontend/fe_tools.h"
#include "frontend/fe_info.h"
//TODO: ugly.
gfx_ctxt_t gfx_ctxt;
gfx_con_t gfx_con;
//TODO: Create more macros (info, header, debug, etc) with different colors and utilize them for consistency.
#define EPRINTF(text) gfx_printf(&gfx_con, "%k"text"%k\n", 0xFFFF0000, 0xFFCCCCCC)
#define EPRINTFARGS(text, args...) gfx_printf(&gfx_con, "%k"text"%k\n", 0xFFFF0000, args, 0xFFCCCCCC)
#define WPRINTF(text) gfx_printf(&gfx_con, "%k"text"%k\n", 0xFFFFDD00, 0xFFCCCCCC)
#define WPRINTFARGS(text, args...) gfx_printf(&gfx_con, "%k"text"%k\n", 0xFFFFDD00, args, 0xFFCCCCCC)
//TODO: ugly.
sdmmc_t sd_sdmmc;
sdmmc_storage_t sd_storage;
@@ -67,6 +58,13 @@ u8 *Kc_MENU_LOGO;
#endif //MENU_LOGO_ENABLE
hekate_config h_cfg;
boot_cfg_t __attribute__((section ("._boot_cfg"))) b_cfg;
const volatile ipl_ver_meta_t __attribute__((section ("._ipl_version"))) ipl_ver = {
.magic = BL_MAGIC,
.version = (BL_VER_MJ + '0') | ((BL_VER_MN + '0') << 8) | ((BL_VER_HF + '0') << 16),
.rsvd0 = 0,
.rsvd1 = 0
};
bool sd_mount()
{
@@ -117,10 +115,12 @@ void *sd_file_read(char *path)
u8 *ptr = buf;
while (size > 0)
{
u32 rsize = MIN(size, 512 * 512);
u32 rsize = MIN(size, 512 * 8192);
if (f_read(&fp, ptr, rsize, NULL) != FR_OK)
{
free(buf);
f_close(&fp);
return NULL;
}
@@ -190,52 +190,6 @@ void emmcsn_path_impl(char *path, char *sub_dir, char *filename, sdmmc_storage_t
sdmmc_storage_end(&storage2);
}
void panic(u32 val)
{
// Set panic code.
PMC(APBDEV_PMC_SCRATCH200) = val;
//PMC(APBDEV_PMC_CRYPTO_OP) = 1; // Disable SE.
TMR(TIMER_WDT4_UNLOCK_PATTERN) = TIMER_MAGIC_PTRN;
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)
;
}
void reboot_normal()
{
sd_unmount();
#ifdef MENU_LOGO_ENABLE
free(Kc_MENU_LOGO);
#endif //MENU_LOGO_ENABLE
display_end();
panic(0x21); // Bypass fuse programming in package1.
}
void reboot_rcm()
{
sd_unmount();
#ifdef MENU_LOGO_ENABLE
free(Kc_MENU_LOGO);
#endif //MENU_LOGO_ENABLE
display_end();
PMC(APBDEV_PMC_SCRATCH0) = 2; // Reboot into rcm.
PMC(APBDEV_PMC_CNTRL) |= PMC_CNTRL_MAIN_RST;
while (true)
usleep(1);
}
void power_off()
{
sd_unmount();
#ifdef MENU_LOGO_ENABLE
free(Kc_MENU_LOGO);
#endif //MENU_LOGO_ENABLE
//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);
}
void check_power_off_from_hos()
{
// Power off on AutoRCM wakeup from HOS shutdown. For modchips/dongles.
@@ -243,6 +197,10 @@ void check_power_off_from_hos()
if (hosWakeup & MAX77620_IRQ_TOP_RTC_MASK)
{
sd_unmount();
// Stop the alarm, in case we injected too fast.
max77620_rtc_stop_alarm();
if (h_cfg.autohosoff == 1)
{
gfx_clear_grey(&gfx_ctxt, 0x1B);
@@ -252,7 +210,7 @@ void check_power_off_from_hos()
display_backlight_brightness(10, 5000);
display_backlight_brightness(100, 25000);
usleep(600000);
msleep(600);
display_backlight_brightness(0, 20000);
}
power_off();
@@ -260,41 +218,53 @@ void check_power_off_from_hos()
}
// This is a safe and unused DRAM region for our payloads.
#define IPL_LOAD_ADDR 0x40008000
#define EXT_PAYLOAD_ADDR 0xC03C0000
#define PATCHED_RELOC_SZ 0x94
#define RCM_PAYLOAD_ADDR (EXT_PAYLOAD_ADDR + ALIGN(PATCHED_RELOC_SZ, 0x10))
#define PAYLOAD_ENTRY 0x40010000
#define CBFS_SDRAM_EN_ADDR 0x4003e000
#define COREBOOT_ADDR (0xD0000000 - 0x100000)
#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 (*ext_payload_ptr)() = (void *)EXT_PAYLOAD_ADDR;
void reloc_patcher(u32 payload_size)
void reloc_patcher(u32 payload_dst, u32 payload_src, u32 payload_size)
{
static const u32 START_OFF = 0x7C;
static const u32 PAYLOAD_END_OFF = 0x84;
static const u32 IPL_START_OFF = 0x88;
memcpy((u8 *)payload_src, (u8 *)IPL_LOAD_ADDR, PATCHED_RELOC_SZ);
memcpy((u8 *)EXT_PAYLOAD_ADDR, (u8 *)IPL_LOAD_ADDR, PATCHED_RELOC_SZ);
volatile reloc_meta_t *relocator = (reloc_meta_t *)(payload_src + RELOC_META_OFF);
*(vu32 *)(EXT_PAYLOAD_ADDR + START_OFF) = PAYLOAD_ENTRY - ALIGN(PATCHED_RELOC_SZ, 0x10);
*(vu32 *)(EXT_PAYLOAD_ADDR + PAYLOAD_END_OFF) = PAYLOAD_ENTRY + payload_size;
*(vu32 *)(EXT_PAYLOAD_ADDR + IPL_START_OFF) = PAYLOAD_ENTRY;
relocator->start = payload_dst - ALIGN(PATCHED_RELOC_SZ, 0x10);
relocator->stack = PATCHED_RELOC_STACK;
relocator->end = payload_dst + payload_size;
relocator->ep = payload_dst;
if (payload_size == 0x7000)
{
memcpy((u8 *)(EXT_PAYLOAD_ADDR + ALIGN(PATCHED_RELOC_SZ, 0x10)), (u8 *)COREBOOT_ADDR, 0x7000); //Bootblock
*(vu32 *)CBFS_SDRAM_EN_ADDR = 0x4452414D;
memcpy((u8 *)(payload_src + ALIGN(PATCHED_RELOC_SZ, 0x10)), (u8 *)COREBOOT_ADDR, 0x7000); //Bootblock
*(vu32 *)CBFS_DRAM_EN_ADDR = CBFS_DRAM_MAGIC;
}
}
#define BOOTLOADER_UPDATED_MAGIC 0x424f4f54 // "BOOT".
#define BOOTLOADER_UPDATED_MAGIC_ADDR 0x4003E000
bool is_ipl_updated(void *buf)
{
ipl_ver_meta_t *update_ft = (ipl_ver_meta_t *)(buf + PATCHED_RELOC_SZ + sizeof(boot_cfg_t));
if (update_ft->magic == ipl_ver.magic)
{
if (byte_swap_32(update_ft->version) <= byte_swap_32(ipl_ver.version))
return true;
return false;
}
else
return true;
}
int launch_payload(char *path, bool update)
{
gfx_clear_grey(&gfx_ctxt, 0x1B);
if (!update)
gfx_clear_grey(&gfx_ctxt, 0x1B);
gfx_con_setpos(&gfx_con, 0, 0);
if (!path)
return 1;
@@ -328,54 +298,39 @@ int launch_payload(char *path, bool update)
}
f_close(&fp);
if (!update)
{
free(path);
path = NULL;
}
free(path);
if (update && is_ipl_updated(buf))
return 1;
if (update)
{
u8 *update_ft = calloc(1, 6);
memcpy(update_ft, buf + size - 6, 6);
update_ft[4] -= '0';
update_ft[5] -= '0';
if (*(u32 *)update_ft == 0x43544349)
{
if (update_ft[4] < BLVERSIONMJ || (update_ft[4] == BLVERSIONMJ && update_ft[5] <= BLVERSIONMN))
{
free(update_ft);
return 1;
}
*(vu32 *)BOOTLOADER_UPDATED_MAGIC_ADDR = BOOTLOADER_UPDATED_MAGIC;
}
else
{
free(update_ft);
return 1;
}
free(update_ft);
}
sd_unmount();
if (size < 0x30000)
{
if (!update)
reloc_patcher(ALIGN(size, 0x10));
if (update)
memcpy((u8 *)(RCM_PAYLOAD_ADDR + PATCHED_RELOC_SZ), &b_cfg, sizeof(boot_cfg_t)); // Transfer boot cfg.
else
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(0x7000);
if (*(vu32 *)CBFS_SDRAM_EN_ADDR != 0x4452414D)
return 1;
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;
// Launch our payload.
(*ext_payload_ptr)();
if (!update)
(*ext_payload_ptr)();
else
{
EMC(EMC_SCRATCH0) |= EMC_HEKA_UPD;
(*update_ptr)();
}
}
return 1;
@@ -383,22 +338,12 @@ int launch_payload(char *path, bool update)
void auto_launch_update()
{
FIL fp;
if (*(vu32 *)BOOTLOADER_UPDATED_MAGIC_ADDR == BOOTLOADER_UPDATED_MAGIC)
*(vu32 *)BOOTLOADER_UPDATED_MAGIC_ADDR = 0;
else
if (EMC(EMC_SCRATCH0) & EMC_HEKA_UPD)
EMC(EMC_SCRATCH0) &= ~EMC_HEKA_UPD;
else if (sd_mount())
{
if (sd_mount())
{
if (f_open(&fp, "bootloader/update.bin", FA_READ))
return;
else
{
f_close(&fp);
launch_payload("bootloader/update.bin", true);
}
}
if (!f_stat("bootloader/update.bin", NULL))
launch_payload("bootloader/update.bin", true);
}
}
@@ -421,7 +366,7 @@ void launch_tools(u8 type)
if (!type)
memcpy(dir, "bootloader/payloads", 20);
else
memcpy(dir, "bootloader/libtools", 20);
memcpy(dir, "bootloader/modules", 19);
filelist = dirlist(dir, NULL, false);
@@ -466,7 +411,7 @@ void launch_tools(u8 type)
}
}
else
EPRINTF("No payloads or libraries found.");
EPRINTF("No payloads or modules found.");
free(ments);
free(filelist);
@@ -480,9 +425,6 @@ void launch_tools(u8 type)
if (file_sec)
{
#ifdef MENU_LOGO_ENABLE
free(Kc_MENU_LOGO);
#endif //MENU_LOGO_ENABLE
memcpy(dir + strlen(dir), "/", 2);
memcpy(dir + strlen(dir), file_sec, strlen(file_sec) + 1);
@@ -496,10 +438,6 @@ void launch_tools(u8 type)
}
else
ianos_loader(true, dir, DRAM_LIB, NULL);
#ifdef MENU_LOGO_ENABLE
Kc_MENU_LOGO = (u8 *)malloc(0x6000);
blz_uncompress_srcdest(Kc_MENU_LOGO_blz, SZ_MENU_LOGO_BLZ, Kc_MENU_LOGO, SZ_MENU_LOGO);
#endif //MENU_LOGO_ENABLE
}
out:
@@ -510,13 +448,14 @@ out:
}
void launch_tools_payload() { launch_tools(0); }
void launch_tools_library() { launch_tools(1); }
void launch_tools_module() { launch_tools(1); }
void ini_list_launcher()
{
u8 max_entries = 61;
char *payload_path = NULL;
ini_sec_t *cfg_tmp = NULL;
ini_sec_t *cfg_sec = NULL;
LIST_INIT(ini_list_sections);
@@ -555,7 +494,35 @@ void ini_list_launcher()
menu_t menu = {
ments, "Launch ini configurations", 0, 0
};
cfg_sec = ini_clone_section((ini_sec_t *)tui_do_menu(&gfx_con, &menu));
cfg_tmp = (ini_sec_t *)tui_do_menu(&gfx_con, &menu);
if (cfg_tmp)
{
u32 non_cfg = 1;
for (int j = 2; j < i; j++)
{
if (ments[j].type != INI_CHOICE)
non_cfg++;
if (ments[j].data == cfg_tmp)
{
b_cfg.boot_cfg = BOOT_CFG_FROM_LAUNCH;
b_cfg.autoboot = j - non_cfg;
b_cfg.autoboot_list = 1;
break;
}
}
}
payload_path = ini_check_payload_section(cfg_tmp);
if (cfg_tmp && !payload_path)
check_sept();
cfg_sec = ini_clone_section(cfg_tmp);
if (!cfg_sec)
{
free(ments);
@@ -565,23 +532,17 @@ void ini_list_launcher()
}
}
else
EPRINTF("No ini configurations found.");
EPRINTF("No extra configs found.");
free(ments);
ini_free(&ini_list_sections);
}
else
EPRINTF("Could not find any ini\nin bootloader/ini folder!");
EPRINTF("Could not find any ini\nin bootloader/ini!");
}
if (!cfg_sec)
goto out;
#ifdef MENU_LOGO_ENABLE
free(Kc_MENU_LOGO);
#endif //MENU_LOGO_ENABLE
payload_path = ini_check_payload_section(cfg_sec);
if (payload_path)
{
ini_free_section(cfg_sec);
@@ -597,11 +558,6 @@ void ini_list_launcher()
btn_wait();
}
#ifdef MENU_LOGO_ENABLE
Kc_MENU_LOGO = (u8 *)malloc(0x6000);
blz_uncompress_srcdest(Kc_MENU_LOGO_blz, SZ_MENU_LOGO_BLZ, Kc_MENU_LOGO, SZ_MENU_LOGO);
#endif //MENU_LOGO_ENABLE
out:
ini_free_section(cfg_sec);
@@ -613,6 +569,7 @@ void launch_firmware()
u8 max_entries = 61;
char *payload_path = NULL;
ini_sec_t *cfg_tmp = NULL;
ini_sec_t *cfg_sec = NULL;
LIST_INIT(ini_sections);
@@ -657,7 +614,7 @@ void launch_firmware()
if (i < 6)
{
ments[i].type = MENT_CAPTION;
ments[i].caption = "No main configurations found...";
ments[i].caption = "No main configs found...";
ments[i].color = 0xFFFFDD00;
i++;
}
@@ -665,7 +622,33 @@ void launch_firmware()
menu_t menu = {
ments, "Launch configurations", 0, 0
};
cfg_sec = ini_clone_section((ini_sec_t *)tui_do_menu(&gfx_con, &menu));
cfg_tmp = (ini_sec_t *)tui_do_menu(&gfx_con, &menu);
if (cfg_tmp)
{
u8 non_cfg = 4;
for (int j = 5; j < i; j++)
{
if (ments[j].type != INI_CHOICE)
non_cfg++;
if (ments[j].data == cfg_tmp)
{
b_cfg.boot_cfg = BOOT_CFG_FROM_LAUNCH;
b_cfg.autoboot = j - non_cfg;
b_cfg.autoboot_list = 0;
break;
}
}
}
payload_path = ini_check_payload_section(cfg_tmp);
if (cfg_tmp && !payload_path)
check_sept();
cfg_sec = ini_clone_section(cfg_tmp);
if (!cfg_sec)
{
free(ments);
@@ -678,7 +661,7 @@ void launch_firmware()
ini_free(&ini_sections);
}
else
EPRINTF("Could not open 'bootloader/hekate_ipl.ini'.\nMake sure it exists in SD Card!");
EPRINTF("Could not open 'bootloader/hekate_ipl.ini'.\nMake sure it exists!");
}
if (!cfg_sec)
@@ -690,11 +673,6 @@ void launch_firmware()
if (!(btn & BTN_POWER))
goto out;
}
#ifdef MENU_LOGO_ENABLE
free(Kc_MENU_LOGO);
#endif //MENU_LOGO_ENABLE
payload_path = ini_check_payload_section(cfg_sec);
if (payload_path)
{
@@ -708,11 +686,6 @@ void launch_firmware()
else if (!hos_launch(cfg_sec))
EPRINTF("Failed to launch firmware.");
#ifdef MENU_LOGO_ENABLE
Kc_MENU_LOGO = (u8 *)malloc(0x6000);
blz_uncompress_srcdest(Kc_MENU_LOGO_blz, SZ_MENU_LOGO_BLZ, Kc_MENU_LOGO, SZ_MENU_LOGO);
#endif //MENU_LOGO_ENABLE
out:
ini_free_section(cfg_sec);
sd_unmount();
@@ -722,11 +695,12 @@ out:
void auto_launch_firmware()
{
auto_launch_update();
if (!h_cfg.sept_run)
auto_launch_update();
u8 *BOOTLOGO = NULL;
char *payload_path = NULL;
FIL fp;
u32 btn = 0;
struct _bmp_data
{
@@ -742,18 +716,17 @@ void auto_launch_firmware()
bool bootlogoFound = false;
char *bootlogoCustomEntry = NULL;
if (!(b_cfg.boot_cfg & BOOT_CFG_FROM_LAUNCH))
gfx_con.mute = true;
ini_sec_t *cfg_sec = NULL;
LIST_INIT(ini_sections);
LIST_INIT(ini_list_sections);
gfx_con.mute = true;
if (sd_mount())
{
if (f_open(&fp, "bootloader/hekate_ipl.ini", FA_READ))
if (f_stat("bootloader/hekate_ipl.ini", NULL))
create_config_entry();
else
f_close(&fp);
if (ini_parse(&ini_sections, "bootloader/hekate_ipl.ini", false))
{
@@ -777,16 +750,29 @@ void auto_launch_firmware()
h_cfg.autoboot_list = atoi(kv->val);
else if (!strcmp("bootwait", kv->key))
h_cfg.bootwait = atoi(kv->val);
else if (!strcmp("customlogo", kv->key))
h_cfg.customlogo = atoi(kv->val);
else if (!strcmp("verification", kv->key))
h_cfg.verification = atoi(kv->val);
else if (!strcmp("backlight", kv->key))
h_cfg.backlight = atoi(kv->val);
else if (!strcmp("autohosoff", kv->key))
h_cfg.autohosoff = atoi(kv->val);
else if (!strcmp("autonogc", kv->key))
h_cfg.autonogc = atoi(kv->val);
}
boot_entry_id++;
// Override autoboot, otherwise save it for a possbile sept run.
if (b_cfg.boot_cfg & BOOT_CFG_AUTOBOOT_EN)
{
h_cfg.autoboot = b_cfg.autoboot;
h_cfg.autoboot_list = b_cfg.autoboot_list;
}
else
{
b_cfg.autoboot = h_cfg.autoboot;
b_cfg.autoboot_list = h_cfg.autoboot_list;
}
continue;
}
@@ -797,7 +783,6 @@ void auto_launch_firmware()
{
if (!strcmp("logopath", kv->key))
bootlogoCustomEntry = kv->val;
gfx_printf(&gfx_con, "\n%s=%s\n\n", kv->key, kv->val);
}
break;
}
@@ -805,12 +790,11 @@ void auto_launch_firmware()
}
}
if (h_cfg.autohosoff)
if (h_cfg.autohosoff && !(b_cfg.boot_cfg & BOOT_CFG_AUTOBOOT_EN))
check_power_off_from_hos();
if (h_cfg.autoboot_list)
{
ini_free(&ini_sections);
ini_free_section(cfg_sec);
boot_entry_id = 1;
bootlogoCustomEntry = NULL;
@@ -831,7 +815,6 @@ void auto_launch_firmware()
{
if (!strcmp("logopath", kv->key))
bootlogoCustomEntry = kv->val;
gfx_printf(&gfx_con, "\n%s=%s\n\n", kv->key, kv->val);
}
break;
}
@@ -860,19 +843,16 @@ void auto_launch_firmware()
else
goto out;
if (h_cfg.customlogo)
u8 *bitmap = NULL;
if (!(b_cfg.boot_cfg & BOOT_CFG_FROM_LAUNCH) && h_cfg.bootwait)
{
u8 *bitmap = NULL;
if (bootlogoCustomEntry != NULL) // Check if user set custom logo path at the boot entry.
{
if (bootlogoCustomEntry) // Check if user set custom logo path at the boot entry.
bitmap = (u8 *)sd_file_read(bootlogoCustomEntry);
if (bitmap == NULL) // Custom entry bootlogo not found, trying default custom one.
bitmap = (u8 *)sd_file_read("bootloader/bootlogo.bmp");
}
else // User has not set a custom logo path.
if (!bitmap) // Custom entry bootlogo not found, trying default custom one.
bitmap = (u8 *)sd_file_read("bootloader/bootlogo.bmp");
if (bitmap != NULL)
if (bitmap)
{
// Get values manually to avoid unaligned access.
bmpData.size = bitmap[2] | bitmap[3] << 8 |
@@ -886,7 +866,7 @@ void auto_launch_firmware()
// Sanity check.
if (bitmap[0] == 'B' &&
bitmap[1] == 'M' &&
bitmap[28] == 32 && //
bitmap[28] == 32 && // Only 32 bit BMPs allowed.
bmpData.size_x <= 720 &&
bmpData.size_y <= 1280)
{
@@ -909,38 +889,40 @@ void auto_launch_firmware()
else
free(bitmap);
}
// Render boot logo.
if (bootlogoFound)
{
gfx_render_bmp_argb(&gfx_ctxt, (u32 *)BOOTLOGO, bmpData.size_x, bmpData.size_y,
bmpData.pos_x, bmpData.pos_y);
}
else
{
gfx_clear_grey(&gfx_ctxt, 0x1B);
BOOTLOGO = (void *)malloc(0x4000);
blz_uncompress_srcdest(BOOTLOGO_BLZ, SZ_BOOTLOGO_BLZ, BOOTLOGO, SZ_BOOTLOGO);
gfx_set_rect_grey(&gfx_ctxt, BOOTLOGO, X_BOOTLOGO, Y_BOOTLOGO, 326, 544);
}
free(BOOTLOGO);
}
// Render boot logo.
if (bootlogoFound)
{
gfx_render_bmp_argb(&gfx_ctxt, (u32 *)BOOTLOGO, bmpData.size_x, bmpData.size_y,
bmpData.pos_x, bmpData.pos_y);
}
else
{
gfx_clear_grey(&gfx_ctxt, 0x1B);
BOOTLOGO = (void *)malloc(0x4000);
blz_uncompress_srcdest(BOOTLOGO_BLZ, SZ_BOOTLOGO_BLZ, BOOTLOGO, SZ_BOOTLOGO);
gfx_set_rect_grey(&gfx_ctxt, BOOTLOGO, X_BOOTLOGO, Y_BOOTLOGO, 326, 544);
}
free(BOOTLOGO);
display_backlight_brightness(h_cfg.backlight, 1000);
// Wait before booting. If VOL- is pressed go into bootloader menu.
u32 btn = btn_wait_timeout(h_cfg.bootwait * 1000, BTN_VOL_DOWN);
if (btn & BTN_VOL_DOWN)
goto out;
ini_free(&ini_sections);
if (h_cfg.autoboot_list)
ini_free(&ini_list_sections);
#ifdef MENU_LOGO_ENABLE
free(Kc_MENU_LOGO);
#endif //MENU_LOGO_ENABLE
if (h_cfg.sept_run)
display_backlight_brightness(h_cfg.backlight, 0);
else if (h_cfg.bootwait)
display_backlight_brightness(h_cfg.backlight, 1000);
// Wait before booting. If VOL- is pressed go into bootloader menu.
if (!h_cfg.sept_run)
{
btn = btn_wait_timeout(h_cfg.bootwait * 1000, BTN_VOL_DOWN);
if (btn & BTN_VOL_DOWN)
goto out;
}
payload_path = ini_check_payload_section(cfg_sec);
@@ -951,15 +933,12 @@ void auto_launch_firmware()
free(payload_path);
}
else
{
check_sept();
hos_launch(cfg_sec);
#ifdef MENU_LOGO_ENABLE
Kc_MENU_LOGO = (u8 *)malloc(ALIGN(SZ_MENU_LOGO, 0x10));
blz_uncompress_srcdest(Kc_MENU_LOGO_blz, SZ_MENU_LOGO_BLZ, Kc_MENU_LOGO, SZ_MENU_LOGO);
#endif //MENU_LOGO_ENABLE
}
out:
gfx_clear_grey(&gfx_ctxt, 0x1B);
ini_free(&ini_sections);
if (h_cfg.autoboot_list)
ini_free(&ini_list_sections);
@@ -967,13 +946,15 @@ out:
sd_unmount();
gfx_con.mute = false;
b_cfg.boot_cfg &= ~(BOOT_CFG_AUTOBOOT_EN | BOOT_CFG_FROM_LAUNCH);
}
void about()
{
static const char credits[] =
"\nhekate (C) 2018 naehrwert, st4rk\n\n"
"CTCaer mod (C) 2018 CTCaer\n"
"\nhekate (c) 2018 naehrwert, st4rk\n\n"
"CTCaer mod (c) 2018 CTCaer\n"
" ___________________________________________\n\n"
"Thanks to: %kderrek, nedwill, plutoo,\n"
" shuffle2, smea, thexyz, yellows8%k\n"
@@ -983,14 +964,14 @@ void about()
" ___________________________________________\n\n"
"Open source and free packages used:\n\n"
" - FatFs R0.13b,\n"
" Copyright (C) 2018, ChaN\n\n"
" Copyright (c) 2018, ChaN\n\n"
" - bcl-1.2.0,\n"
" Copyright (C) 2003-2006, Marcus Geelnard\n\n"
" Copyright (c) 2003-2006, Marcus Geelnard\n\n"
" - Atmosphere (SE sha256, prc id patches),\n"
" Copyright (C) 2018, Atmosphere-NX\n\n"
" Copyright (c) 2018, Atmosphere-NX\n\n"
" - elfload,\n"
" Copyright (C) 2014, Owen Shepherd\n"
" Copyright (C) 2018, M4xw\n"
" Copyright (c) 2014, Owen Shepherd\n"
" Copyright (c) 2018, M4xw\n"
" ___________________________________________\n\n";
static const char octopus[] =
" %k___\n"
@@ -1027,7 +1008,7 @@ ment_t ment_options[] = {
MDEF_CHGLINE(),
MDEF_HANDLER("Auto boot", config_autoboot),
MDEF_HANDLER("Boot time delay", config_bootdelay),
MDEF_HANDLER("Custom boot logo", config_customlogo),
MDEF_HANDLER("Auto NoGC", config_nogc),
MDEF_HANDLER("Auto HOS power off", config_auto_hos_poweroff),
MDEF_HANDLER("Backlight", config_backlight),
MDEF_END()
@@ -1065,7 +1046,7 @@ ment_t ment_restore[] = {
MDEF_CHGLINE(),
MDEF_CAPTION("------ Full --------", 0xFF0AB9E6),
MDEF_HANDLER("Restore eMMC BOOT0/1", restore_emmc_boot),
MDEF_HANDLER("Restore eMMC RAW GPP (exFAT only)", restore_emmc_rawnand),
MDEF_HANDLER("Restore eMMC RAW GPP", restore_emmc_rawnand),
MDEF_CHGLINE(),
MDEF_CAPTION("-- GPP Partitions --", 0xFF0AB9E6),
MDEF_HANDLER("Restore GPP partitions", restore_emmc_gpp_parts),
@@ -1106,8 +1087,8 @@ ment_t ment_tools[] = {
MDEF_CAPTION("-------- Misc --------", 0xFF0AB9E6),
MDEF_HANDLER("Dump package1/2", dump_packages12),
MDEF_HANDLER("Fix battery de-sync", fix_battery_desync),
MDEF_HANDLER("Unset archive bit (switch folder)", fix_sd_switch_attr),
MDEF_HANDLER("Unset archive bit (all sd files)", fix_sd_all_attr),
MDEF_HANDLER("Fix archive bit (except Nintendo)", fix_sd_all_attr),
MDEF_HANDLER("Fix archive bit (Nintendo only)", fix_sd_nin_attr),
//MDEF_HANDLER("Fix fuel gauge configuration", fix_fuel_gauge_configuration),
//MDEF_HANDLER("Reset all battery cfg", reset_pmic_fuel_gauge_charger_config),
//MDEF_HANDLER("Minerva", minerva), // Uncomment for testing Minerva Training Cell
@@ -1138,31 +1119,36 @@ ment_t ment_top[] = {
};
menu_t menu_top = {
ment_top,
"hekate - CTCaer mod v4.5", 0, 0
"hekate - CTCaer mod v4.9", 0, 0
};
#define IPL_STACK_TOP 0x90010000
#define IPL_HEAP_START 0x90020000
#define IPL_HEAP_END 0xB5000000
extern void pivot_stack(u32 stack_top);
void ipl_main()
{
// Skip config if we just updated the bootloader.
if (*(vu32 *)BOOTLOADER_UPDATED_MAGIC_ADDR != BOOTLOADER_UPDATED_MAGIC)
config_hw();
// Do initial HW configuration. This is compatible with consecutive reruns without a reset.
config_hw();
//Pivot the stack so we have enough space.
pivot_stack(0x90010000);
pivot_stack(IPL_STACK_TOP);
//Tegra/Horizon configuration goes to 0x80000000+, package2 goes to 0xA9800000, we place our heap in between.
heap_init(0x90020000);
heap_init(IPL_HEAP_START);
//uart_send(UART_C, (u8 *)0x40000000, 0x10000);
//uart_wait_idle(UART_C, UART_TX_IDLE);
#ifdef DEBUG_UART_PORT
uart_send(DEBUG_UART_PORT, (u8 *)"Hekate: Hello!\r\n", 16);
uart_wait_idle(DEBUG_UART_PORT, UART_TX_IDLE);
#endif
// Set bootloader's default configuration.
set_default_configuration();
// Save sdram lp0 config.
if (ianos_loader(true, "bootloader/sys/libsys_lp0.bso", DRAM_LIB, (void *)sdram_get_params()))
if (ianos_loader(true, "bootloader/sys/libsys_lp0.bso", DRAM_LIB, (void *)sdram_get_params_patched()))
h_cfg.errors |= ERR_LIBSYS_LP0;
display_init();
@@ -1171,9 +1157,9 @@ void ipl_main()
gfx_init_ctxt(&gfx_ctxt, fb, 720, 1280, 720);
#ifdef MENU_LOGO_ENABLE
Kc_MENU_LOGO = (u8 *)malloc(0x6000);
Kc_MENU_LOGO = (u8 *)malloc(ALIGN(SZ_MENU_LOGO, 0x1000));
blz_uncompress_srcdest(Kc_MENU_LOGO_blz, SZ_MENU_LOGO_BLZ, Kc_MENU_LOGO, SZ_MENU_LOGO);
#endif //MENU_LOGO_ENABLE
#endif
gfx_con_init(&gfx_con, &gfx_ctxt);

View File

@@ -124,6 +124,6 @@ void *calloc(u32 num, u32 size)
void free(void *buf)
{
if ((buf != NULL) || ((u32)buf > (_heap.start - 1)))
if ((u32)buf >= _heap.start)
_heap_free(&_heap, (u32)buf);
}

View File

@@ -1,5 +1,7 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (c) 2018 balika011
* 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,
@@ -18,11 +20,12 @@
#include "../soc/t210.h"
#include "mc.h"
#include "emc.h"
#include "sdram_param_t210.h"
#include "../soc/pmc.h"
#include "../utils/util.h"
#include "../soc/fuse.h"
#include "../power/max77620.h"
#include "../mem/sdram_param_t210.h"
#include "../power/max7762x.h"
#include "../soc/clock.h"
#define CONFIG_SDRAM_COMPRESS_CFG
@@ -388,9 +391,9 @@ break_nosleep:
EMC(EMC_ACPD_CONTROL) = params->emc_acpd_control;
EMC(EMC_TXDSRVTTGEN) = params->emc_txdsrvttgen;
EMC(EMC_CFG) = (params->emc_cfg & 0xE) | 0x3C00000;
if (params->boot_rom_patch_control & 0x80000000)
if (params->boot_rom_patch_control & (1 << 31))
{
*(vu32 *)(4 * (params->boot_rom_patch_control + 0x1C000000)) = params->boot_rom_patch_data;
*(vu32 *)(APB_MISC_BASE + params->boot_rom_patch_control * 4) = params->boot_rom_patch_data;
MC(MC_TIMING_CONTROL) = 1;
}
PMC(APBDEV_PMC_IO_DPD3_REQ) = ((4 * params->emc_pmc_scratch1 >> 2) + 0x40000000) & 0xCFFF0000;
@@ -489,26 +492,54 @@ break_nosleep:
MC(MC_EMEM_CFG_ACCESS_CTRL) = 1; //Disable write access to a bunch of EMC registers.
}
const void *sdram_get_params()
sdram_params_t *sdram_get_params()
{
//TODO: sdram_id should be in [0, 7].
#ifdef CONFIG_SDRAM_COMPRESS_CFG
u8 *buf = (u8 *)0x40030000;
LZ_Uncompress(_dram_cfg_lz, buf, sizeof(_dram_cfg_lz));
return (const void *)&buf[sizeof(sdram_params_t) * _get_sdram_id()];
return (sdram_params_t *)&buf[sizeof(sdram_params_t) * _get_sdram_id()];
#else
return _dram_cfgs[_get_sdram_id()];
#endif
}
/*
* Function: sdram_get_params_patched
*
* This code implements a warmboot exploit. Warmboot, that is actually so hot, it burns Nvidia once again.
* If the boot_rom_patch_control's MSB is set, it uses it as an index to
* APB_MISC_BASE (u32 array) and sets it to the value of boot_rom_patch_data.
* (The MSB falls out when it gets multiplied by sizeof(u32)).
* Because the bootrom does not do any boundary checks, it lets us write anywhere and anything.
* Ipatch hardware let us apply 12 changes to the bootrom and can be changed any time.
* The first patch is not needed any more when the exploit is triggered, so we overwrite that.
* 0x10459E is the address where it returns an error when the signature is not valid.
* We change that to MOV R0, #0, so we pass the check.
*
* Note: The modulus in the header must match and validated.
*/
sdram_params_t *sdram_get_params_patched()
{
#define IPATCH_CONFIG(addr, data) (((addr - 0x100000) / 2) << 16 | (data & 0xffff))
sdram_params_t *sdram_params = sdram_get_params();
// Disable Warmboot signature check.
sdram_params->boot_rom_patch_control = (1 << 31) | (((IPATCH_BASE + 4) - APB_MISC_BASE) / 4);
sdram_params->boot_rom_patch_data = IPATCH_CONFIG(0x10459E, 0x2000);
return sdram_params;
}
void sdram_init()
{
//TODO: sdram_id should be in [0,4].
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);
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_SD1, 40); //40 = (1000 * 1100 - 600000) / 12500 -> 1.1V
max77620_regulator_set_voltage(REGULATOR_SD1, 1100000);
PMC(APBDEV_PMC_VDDP_SEL) = params->pmc_vddp_sel;
usleep(params->pmc_vddp_sel_wait);

View File

@@ -17,8 +17,11 @@
#ifndef _SDRAM_H_
#define _SDRAM_H_
#include "sdram_param_t210.h"
void sdram_init();
const void *sdram_get_params();
sdram_params_t *sdram_get_params();
sdram_params_t *sdram_get_params_patched();
void sdram_lp0_save_params(const void *params);
#endif

View File

@@ -1,8 +1,8 @@
/*
* Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved.
* Copyright 2014 Google Inc.
* Copyright (C) 2018 naehrwert
* Copyright (C) 2018 CTCaer
* 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,

View File

@@ -148,7 +148,7 @@ int bq24193_get_property(enum BQ24193_reg_prop prop, int *value)
void bq24193_fake_battery_removal()
{
u8 value;
u8 value;
// Disable watchdog to keep BATFET disabled.
value = i2c_recv_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_ChrgTermTimer);

View File

@@ -2,6 +2,7 @@
* Defining registers address and its bit definitions of MAX77620 and MAX20024
*
* Copyright (C) 2016 NVIDIA CORPORATION. All rights reserved.
* Copyright (c) 2019 CTCaer
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@@ -14,275 +15,277 @@
#define MAX77620_I2C_ADDR 0x3C
/* GLOBAL, PMIC, GPIO, FPS, ONOFFC, CID Registers */
#define MAX77620_REG_CNFGGLBL1 0x00
#define MAX77620_REG_CNFGGLBL2 0x01
#define MAX77620_REG_CNFGGLBL3 0x02
#define MAX77620_REG_CNFG1_32K 0x03
#define MAX77620_REG_CNFGBBC 0x04
#define MAX77620_REG_IRQTOP 0x05
#define MAX77620_REG_INTLBT 0x06
#define MAX77620_REG_IRQSD 0x07
#define MAX77620_REG_IRQ_LVL2_L0_7 0x08
#define MAX77620_REG_IRQ_LVL2_L8 0x09
#define MAX77620_REG_IRQ_LVL2_GPIO 0x0A
#define MAX77620_REG_ONOFFIRQ 0x0B
#define MAX77620_REG_NVERC 0x0C
#define MAX77620_REG_IRQTOPM 0x0D
#define MAX77620_REG_INTENLBT 0x0E
#define MAX77620_REG_IRQMASKSD 0x0F
#define MAX77620_REG_IRQ_MSK_L0_7 0x10
#define MAX77620_REG_IRQ_MSK_L8 0x11
#define MAX77620_REG_ONOFFIRQM 0x12
#define MAX77620_REG_STATLBT 0x13
#define MAX77620_REG_STATSD 0x14
#define MAX77620_REG_ONOFFSTAT 0x15
#define MAX77620_REG_CNFGGLBL1 0x00
#define MAX77620_CNFGGLBL1_LBDAC_EN (1 << 7)
#define MAX77620_CNFGGLBL1_MPPLD (1 << 6)
#define MAX77620_CNFGGLBL1_LBHYST ((1 << 5) | (1 << 4))
#define MAX77620_CNFGGLBL1_LBHYST_N (1 << 4)
#define MAX77620_CNFGGLBL1_LBDAC 0x0E
#define MAX77620_CNFGGLBL1_LBDAC_N (1 << 1)
#define MAX77620_CNFGGLBL1_LBRSTEN (1 << 0)
#define MAX77620_REG_CNFGGLBL2 0x01
#define MAX77620_REG_CNFGGLBL3 0x02
#define MAX77620_WDTC_MASK 0x3
#define MAX77620_WDTOFFC (1 << 4)
#define MAX77620_WDTSLPC (1 << 3)
#define MAX77620_WDTEN (1 << 2)
#define MAX77620_TWD_MASK 0x3
#define MAX77620_TWD_2s 0x0
#define MAX77620_TWD_16s 0x1
#define MAX77620_TWD_64s 0x2
#define MAX77620_TWD_128s 0x3
#define MAX77620_REG_CNFG1_32K 0x03
#define MAX77620_CNFG1_32K_OUT0_EN (1 << 2)
#define MAX77620_REG_CNFGBBC 0x04
#define MAX77620_CNFGBBC_ENABLE (1 << 0)
#define MAX77620_CNFGBBC_CURRENT_MASK 0x06
#define MAX77620_CNFGBBC_CURRENT_SHIFT 1
#define MAX77620_CNFGBBC_VOLTAGE_MASK 0x18
#define MAX77620_CNFGBBC_VOLTAGE_SHIFT 3
#define MAX77620_CNFGBBC_LOW_CURRENT_DISABLE (1 << 5)
#define MAX77620_CNFGBBC_RESISTOR_MASK 0xC0
#define MAX77620_CNFGBBC_RESISTOR_SHIFT 6
#define MAX77620_CNFGBBC_RESISTOR_100 (0 << MAX77620_CNFGBBC_RESISTOR_SHIFT)
#define MAX77620_CNFGBBC_RESISTOR_1K (1 << MAX77620_CNFGBBC_RESISTOR_SHIFT)
#define MAX77620_CNFGBBC_RESISTOR_3K (2 << MAX77620_CNFGBBC_RESISTOR_SHIFT)
#define MAX77620_CNFGBBC_RESISTOR_6K (3 << MAX77620_CNFGBBC_RESISTOR_SHIFT)
#define MAX77620_REG_IRQTOP 0x05
#define MAX77620_IRQ_TOP_GLBL_MASK (1 << 7)
#define MAX77620_IRQ_TOP_SD_MASK (1 << 6)
#define MAX77620_IRQ_TOP_LDO_MASK (1 << 5)
#define MAX77620_IRQ_TOP_GPIO_MASK (1 << 4)
#define MAX77620_IRQ_TOP_RTC_MASK (1 << 3)
#define MAX77620_IRQ_TOP_32K_MASK (1 << 2)
#define MAX77620_IRQ_TOP_ONOFF_MASK (1 << 1)
#define MAX77620_REG_INTLBT 0x06
#define MAX77620_REG_IRQTOPM 0x0D
#define MAX77620_IRQ_LBM_MASK (1 << 3)
#define MAX77620_IRQ_TJALRM1_MASK (1 << 2)
#define MAX77620_IRQ_TJALRM2_MASK (1 << 1)
#define MAX77620_REG_IRQSD 0x07
#define MAX77620_REG_IRQ_LVL2_L0_7 0x08
#define MAX77620_REG_IRQ_LVL2_L8 0x09
#define MAX77620_REG_IRQ_LVL2_GPIO 0x0A
#define MAX77620_REG_ONOFFIRQ 0x0B
#define MAX77620_REG_NVERC 0x0C
#define MAX77620_REG_INTENLBT 0x0E
#define MAX77620_GLBLM_MASK (1 << 0)
#define MAX77620_REG_IRQMASKSD 0x0F
#define MAX77620_REG_IRQ_MSK_L0_7 0x10
#define MAX77620_REG_IRQ_MSK_L8 0x11
#define MAX77620_REG_ONOFFIRQM 0x12
#define MAX77620_REG_STATLBT 0x13
#define MAX77620_REG_STATSD 0x14
#define MAX77620_REG_ONOFFSTAT 0x15
/* SD and LDO Registers */
#define MAX77620_REG_SD0 0x16
#define MAX77620_REG_SD1 0x17
#define MAX77620_REG_SD2 0x18
#define MAX77620_REG_SD3 0x19
#define MAX77620_REG_SD4 0x1A
#define MAX77620_REG_DVSSD0 0x1B
#define MAX77620_REG_DVSSD1 0x1C
#define MAX77620_REG_SD0_CFG 0x1D
#define MAX77620_REG_SD1_CFG 0x1E
#define MAX77620_REG_SD2_CFG 0x1F
#define MAX77620_REG_SD3_CFG 0x20
#define MAX77620_REG_SD4_CFG 0x21
#define MAX77620_REG_SD_CFG2 0x22
#define MAX77620_REG_LDO0_CFG 0x23
#define MAX77620_REG_LDO0_CFG2 0x24
#define MAX77620_REG_LDO1_CFG 0x25
#define MAX77620_REG_LDO1_CFG2 0x26
#define MAX77620_REG_LDO2_CFG 0x27
#define MAX77620_REG_LDO2_CFG2 0x28
#define MAX77620_REG_LDO3_CFG 0x29
#define MAX77620_REG_LDO3_CFG2 0x2A
#define MAX77620_REG_LDO4_CFG 0x2B
#define MAX77620_REG_LDO4_CFG2 0x2C
#define MAX77620_REG_LDO5_CFG 0x2D
#define MAX77620_REG_LDO5_CFG2 0x2E
#define MAX77620_REG_LDO6_CFG 0x2F
#define MAX77620_REG_LDO6_CFG2 0x30
#define MAX77620_REG_LDO7_CFG 0x31
#define MAX77620_REG_LDO7_CFG2 0x32
#define MAX77620_REG_LDO8_CFG 0x33
#define MAX77620_REG_LDO8_CFG2 0x34
#define MAX77620_REG_LDO_CFG3 0x35
#define MAX77620_REG_SD0 0x16
#define MAX77620_REG_SD1 0x17
#define MAX77620_REG_SD2 0x18
#define MAX77620_REG_SD3 0x19
#define MAX77620_REG_SD4 0x1A
#define MAX77620_SDX_VOLT_MASK 0xFF
#define MAX77620_SD0_VOLT_MASK 0x3F
#define MAX77620_SD1_VOLT_MASK 0x7F
#define MAX77620_LDO_VOLT_MASK 0x3F
#define MAX77620_REG_DVSSD0 0x1B
#define MAX77620_REG_DVSSD1 0x1C
#define MAX77620_REG_SD0_CFG 0x1D
#define MAX77620_REG_SD1_CFG 0x1E
#define MAX77620_REG_SD2_CFG 0x1F
#define MAX77620_REG_SD3_CFG 0x20
#define MAX77620_REG_SD4_CFG 0x21
#define MAX77620_REG_SD_CFG2 0x22
#define MAX77620_REG_LDO0_CFG 0x23
#define MAX77620_REG_LDO0_CFG2 0x24
#define MAX77620_REG_LDO1_CFG 0x25
#define MAX77620_REG_LDO1_CFG2 0x26
#define MAX77620_REG_LDO2_CFG 0x27
#define MAX77620_REG_LDO2_CFG2 0x28
#define MAX77620_REG_LDO3_CFG 0x29
#define MAX77620_REG_LDO3_CFG2 0x2A
#define MAX77620_REG_LDO4_CFG 0x2B
#define MAX77620_REG_LDO4_CFG2 0x2C
#define MAX77620_REG_LDO5_CFG 0x2D
#define MAX77620_REG_LDO5_CFG2 0x2E
#define MAX77620_REG_LDO6_CFG 0x2F
#define MAX77620_REG_LDO6_CFG2 0x30
#define MAX77620_REG_LDO7_CFG 0x31
#define MAX77620_REG_LDO7_CFG2 0x32
#define MAX77620_REG_LDO8_CFG 0x33
#define MAX77620_REG_LDO8_CFG2 0x34
#define MAX77620_LDO_POWER_MODE_MASK 0xC0
#define MAX77620_LDO_POWER_MODE_SHIFT 6
#define MAX77620_POWER_MODE_NORMAL 3
#define MAX77620_POWER_MODE_LPM 2
#define MAX77620_POWER_MODE_GLPM 1
#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_ENABLE (1 << 1)
#define MAX77620_LDO_CFG2_SS_MASK (1 << 0)
#define MAX77620_LDO_CFG2_SS_FAST (1 << 0)
#define MAX77620_LDO_CFG2_SS_SLOW 0
#define MAX77620_LDO_SLEW_RATE_MASK 0x1
#define MAX77620_REG_LDO_CFG3 0x35
#define MAX77620_TRACK4_MASK (1 << 5)
#define MAX77620_TRACK4_SHIFT 5
/* LDO Configuration 3 */
#define MAX77620_TRACK4_MASK (1 << 5)
#define MAX77620_TRACK4_SHIFT 5
#define MAX77620_LDO_SLEW_RATE_MASK 0x1
/* Voltage */
#define MAX77620_SDX_VOLT_MASK 0xFF
#define MAX77620_SD0_VOLT_MASK 0x3F
#define MAX77620_SD1_VOLT_MASK 0x7F
#define MAX77620_LDO_VOLT_MASK 0x3F
#define MAX77620_REG_GPIO0 0x36
#define MAX77620_REG_GPIO1 0x37
#define MAX77620_REG_GPIO2 0x38
#define MAX77620_REG_GPIO3 0x39
#define MAX77620_REG_GPIO4 0x3A
#define MAX77620_REG_GPIO5 0x3B
#define MAX77620_REG_GPIO6 0x3C
#define MAX77620_REG_GPIO7 0x3D
#define MAX77620_REG_PUE_GPIO 0x3E
#define MAX77620_REG_PDE_GPIO 0x3F
#define MAX77620_REG_AME_GPIO 0x40
#define MAX77620_REG_GPIO0 0x36
#define MAX77620_REG_GPIO1 0x37
#define MAX77620_REG_GPIO2 0x38
#define MAX77620_REG_GPIO3 0x39
#define MAX77620_REG_GPIO4 0x3A
#define MAX77620_REG_GPIO5 0x3B
#define MAX77620_REG_GPIO6 0x3C
#define MAX77620_REG_GPIO7 0x3D
#define MAX77620_REG_PUE_GPIO 0x3E
#define MAX77620_REG_PDE_GPIO 0x3F
#define MAX77620_REG_AME_GPIO 0x40
#define MAX77620_REG_ONOFFCNFG1 0x41
#define MAX77620_REG_ONOFFCNFG2 0x42
#define MAX77620_REG_ONOFFCNFG1 0x41
#define MAX77620_ONOFFCNFG1_SFT_RST (1 << 7)
#define MAX77620_ONOFFCNFG1_MRT_MASK 0x38
#define MAX77620_ONOFFCNFG1_MRT_SHIFT 0x3
#define MAX77620_ONOFFCNFG1_SLPEN (1 << 2)
#define MAX77620_ONOFFCNFG1_PWR_OFF (1 << 1)
#define MAX20024_ONOFFCNFG1_CLRSE 0x18
#define MAX77620_REG_ONOFFCNFG2 0x42
#define MAX77620_ONOFFCNFG2_SFT_RST_WK (1 << 7)
#define MAX77620_ONOFFCNFG2_WD_RST_WK (1 << 6)
#define MAX77620_ONOFFCNFG2_SLP_LPM_MSK (1 << 5)
#define MAX77620_ONOFFCNFG2_WK_ALARM1 (1 << 2)
#define MAX77620_ONOFFCNFG2_WK_EN0 (1 << 0)
/* FPS Registers */
#define MAX77620_REG_FPS_CFG0 0x43
#define MAX77620_REG_FPS_CFG1 0x44
#define MAX77620_REG_FPS_CFG2 0x45
#define MAX77620_REG_FPS_LDO0 0x46
#define MAX77620_REG_FPS_LDO1 0x47
#define MAX77620_REG_FPS_LDO2 0x48
#define MAX77620_REG_FPS_LDO3 0x49
#define MAX77620_REG_FPS_LDO4 0x4A
#define MAX77620_REG_FPS_LDO5 0x4B
#define MAX77620_REG_FPS_LDO6 0x4C
#define MAX77620_REG_FPS_LDO7 0x4D
#define MAX77620_REG_FPS_LDO8 0x4E
#define MAX77620_REG_FPS_SD0 0x4F
#define MAX77620_REG_FPS_SD1 0x50
#define MAX77620_REG_FPS_SD2 0x51
#define MAX77620_REG_FPS_SD3 0x52
#define MAX77620_REG_FPS_SD4 0x53
#define MAX77620_REG_FPS_NONE 0
#define MAX77620_FPS_SRC_MASK 0xC0
#define MAX77620_FPS_SRC_SHIFT 6
#define MAX77620_FPS_PU_PERIOD_MASK 0x38
#define MAX77620_FPS_PU_PERIOD_SHIFT 3
#define MAX77620_FPS_PD_PERIOD_MASK 0x07
#define MAX77620_FPS_PD_PERIOD_SHIFT 0
#define MAX77620_FPS_TIME_PERIOD_MASK 0x38
#define MAX77620_FPS_TIME_PERIOD_SHIFT 3
#define MAX77620_FPS_EN_SRC_MASK 0x06
#define MAX77620_FPS_EN_SRC_SHIFT 1
#define MAX77620_FPS_ENFPS_SW_MASK 0x01
#define MAX77620_FPS_ENFPS_SW 0x01
#define MAX77620_REG_FPS_CFG0 0x43
#define MAX77620_REG_FPS_CFG1 0x44
#define MAX77620_REG_FPS_CFG2 0x45
#define MAX77620_REG_FPS_LDO0 0x46
#define MAX77620_REG_FPS_LDO1 0x47
#define MAX77620_REG_FPS_LDO2 0x48
#define MAX77620_REG_FPS_LDO3 0x49
#define MAX77620_REG_FPS_LDO4 0x4A
#define MAX77620_REG_FPS_LDO5 0x4B
#define MAX77620_REG_FPS_LDO6 0x4C
#define MAX77620_REG_FPS_LDO7 0x4D
#define MAX77620_REG_FPS_LDO8 0x4E
#define MAX77620_REG_FPS_SD0 0x4F
#define MAX77620_REG_FPS_SD1 0x50
#define MAX77620_REG_FPS_SD2 0x51
#define MAX77620_REG_FPS_SD3 0x52
#define MAX77620_REG_FPS_SD4 0x53
#define MAX77620_REG_FPS_NONE 0
#define MAX77620_FPS_SRC_MASK 0xC0
#define MAX77620_FPS_SRC_SHIFT 6
#define MAX77620_FPS_PU_PERIOD_MASK 0x38
#define MAX77620_FPS_PU_PERIOD_SHIFT 3
#define MAX77620_FPS_PD_PERIOD_MASK 0x07
#define MAX77620_FPS_PD_PERIOD_SHIFT 0
/* Minimum and maximum FPS period time (in microseconds) are
* different for MAX77620 and Max20024.
*/
#define MAX77620_FPS_PERIOD_MIN_US 40
#define MAX20024_FPS_PERIOD_MIN_US 20
#define MAX77620_FPS_COUNT 3
#define MAX77620_FPS_PERIOD_MAX_US 2560
#define MAX20024_FPS_PERIOD_MAX_US 5120
#define MAX77620_FPS_PERIOD_MIN_US 40
#define MAX20024_FPS_PERIOD_MIN_US 20
#define MAX77620_REG_FPS_GPIO1 0x54
#define MAX77620_REG_FPS_GPIO2 0x55
#define MAX77620_REG_FPS_GPIO3 0x56
#define MAX77620_REG_FPS_RSO 0x57
#define MAX77620_REG_CID0 0x58
#define MAX77620_REG_CID1 0x59
#define MAX77620_REG_CID2 0x5A
#define MAX77620_REG_CID3 0x5B
#define MAX77620_REG_CID4 0x5C
#define MAX77620_REG_CID5 0x5D
#define MAX77620_FPS_PERIOD_MAX_US 2560
#define MAX20024_FPS_PERIOD_MAX_US 5120
#define MAX77620_REG_DVSSD4 0x5E
#define MAX20024_REG_MAX_ADD 0x70
#define MAX77620_REG_FPS_GPIO1 0x54
#define MAX77620_REG_FPS_GPIO2 0x55
#define MAX77620_REG_FPS_GPIO3 0x56
#define MAX77620_FPS_TIME_PERIOD_MASK 0x38
#define MAX77620_FPS_TIME_PERIOD_SHIFT 3
#define MAX77620_FPS_EN_SRC_MASK 0x06
#define MAX77620_FPS_EN_SRC_SHIFT 1
#define MAX77620_FPS_ENFPS_SW_MASK 0x01
#define MAX77620_FPS_ENFPS_SW 0x01
#define MAX77620_CID_DIDM_MASK 0xF0
#define MAX77620_CID_DIDM_SHIFT 4
#define MAX77620_REG_FPS_RSO 0x57
#define MAX77620_REG_CID0 0x58
#define MAX77620_REG_CID1 0x59
#define MAX77620_REG_CID2 0x5A
#define MAX77620_REG_CID3 0x5B
#define MAX77620_REG_CID4 0x5C
#define MAX77620_REG_CID5 0x5D
#define MAX77620_REG_DVSSD4 0x5E
#define MAX20024_REG_MAX_ADD 0x70
#define MAX77620_CID_DIDM_MASK 0xF0
#define MAX77620_CID_DIDM_SHIFT 4
/* CNCG2SD */
#define MAX77620_SD_CNF2_ROVS_EN_SD1 (1 << 1)
#define MAX77620_SD_CNF2_ROVS_EN_SD0 (1 << 2)
#define MAX77620_SD_CNF2_ROVS_EN_SD1 (1 << 1)
#define MAX77620_SD_CNF2_ROVS_EN_SD0 (1 << 2)
/* Device Identification Metal */
#define MAX77620_CID5_DIDM(n) (((n) >> 4) & 0xF)
#define MAX77620_CID5_DIDM(n) (((n) >> 4) & 0xF)
/* Device Indentification OTP */
#define MAX77620_CID5_DIDO(n) ((n) & 0xF)
#define MAX77620_CID5_DIDO(n) ((n) & 0xF)
/* SD CNFG1 */
#define MAX77620_SD_SR_MASK 0xC0
#define MAX77620_SD_SR_SHIFT 6
#define MAX77620_SD_POWER_MODE_MASK 0x30
#define MAX77620_SD_POWER_MODE_SHIFT 4
#define MAX77620_SD_CFG1_ADE_MASK (1 << 3)
#define MAX77620_SD_CFG1_ADE_DISABLE 0
#define MAX77620_SD_CFG1_ADE_ENABLE (1 << 3)
#define MAX77620_SD_FPWM_MASK 0x04
#define MAX77620_SD_FPWM_SHIFT 2
#define MAX77620_SD_FSRADE_MASK 0x01
#define MAX77620_SD_FSRADE_SHIFT 0
#define MAX77620_SD_CFG1_FPWM_SD_MASK (1 << 2)
#define MAX77620_SD_CFG1_FPWM_SD_SKIP 0
#define MAX77620_SD_CFG1_FPWM_SD_FPWM (1 << 2)
#define MAX20024_SD_CFG1_MPOK_MASK (1 << 1)
#define MAX77620_SD_CFG1_FSRADE_SD_MASK (1 << 0)
#define MAX77620_SD_CFG1_FSRADE_SD_DISABLE 0
#define MAX77620_SD_CFG1_FSRADE_SD_ENABLE (1 << 0)
#define MAX77620_SD_SR_MASK 0xC0
#define MAX77620_SD_SR_SHIFT 6
#define MAX77620_SD_POWER_MODE_MASK 0x30
#define MAX77620_SD_POWER_MODE_SHIFT 4
#define MAX77620_SD_CFG1_ADE_MASK (1 << 3)
#define MAX77620_SD_CFG1_ADE_DISABLE 0
#define MAX77620_SD_CFG1_ADE_ENABLE (1 << 3)
#define MAX77620_SD_FPWM_MASK 0x04
#define MAX77620_SD_FPWM_SHIFT 2
#define MAX77620_SD_FSRADE_MASK 0x01
#define MAX77620_SD_FSRADE_SHIFT 0
#define MAX77620_SD_CFG1_FPWM_SD_MASK (1 << 2)
#define MAX77620_SD_CFG1_FPWM_SD_SKIP 0
#define MAX77620_SD_CFG1_FPWM_SD_FPWM (1 << 2)
#define MAX20024_SD_CFG1_MPOK_MASK (1 << 1)
#define MAX77620_SD_CFG1_FSRADE_SD_MASK (1 << 0)
#define MAX77620_SD_CFG1_FSRADE_SD_DISABLE 0
#define MAX77620_SD_CFG1_FSRADE_SD_ENABLE (1 << 0)
/* LDO_CNFG2 */
#define MAX77620_LDO_POWER_MODE_MASK 0xC0
#define MAX77620_LDO_POWER_MODE_SHIFT 6
#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_ENABLE (1 << 1)
#define MAX77620_LDO_CFG2_SS_MASK (1 << 0)
#define MAX77620_LDO_CFG2_SS_FAST (1 << 0)
#define MAX77620_LDO_CFG2_SS_SLOW 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_TOP_GLBL_MASK (1 << 7)
#define MAX77620_IRQ_TOP_SD_MASK (1 << 6)
#define MAX77620_IRQ_TOP_LDO_MASK (1 << 5)
#define MAX77620_IRQ_TOP_GPIO_MASK (1 << 4)
#define MAX77620_IRQ_TOP_RTC_MASK (1 << 3)
#define MAX77620_IRQ_TOP_32K_MASK (1 << 2)
#define MAX77620_IRQ_TOP_ONOFF_MASK (1 << 1)
#define MAX77620_IRQ_LBM_MASK (1 << 3)
#define MAX77620_IRQ_TJALRM1_MASK (1 << 2)
#define MAX77620_IRQ_TJALRM2_MASK (1 << 1)
#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)
#define MAX77620_IRQ_LVL2_GPIO_EDGE3 (1 << 3)
#define MAX77620_IRQ_LVL2_GPIO_EDGE4 (1 << 4)
#define MAX77620_IRQ_LVL2_GPIO_EDGE5 (1 << 5)
#define MAX77620_IRQ_LVL2_GPIO_EDGE6 (1 << 6)
#define MAX77620_IRQ_LVL2_GPIO_EDGE7 (1 << 7)
#define MAX77620_CNFG1_32K_OUT0_EN (1 << 2)
#define MAX77620_ONOFFCNFG1_SFT_RST (1 << 7)
#define MAX77620_ONOFFCNFG1_MRT_MASK 0x38
#define MAX77620_ONOFFCNFG1_MRT_SHIFT 0x3
#define MAX77620_ONOFFCNFG1_SLPEN (1 << 2)
#define MAX77620_ONOFFCNFG1_PWR_OFF (1 << 1)
#define MAX20024_ONOFFCNFG1_CLRSE 0x18
#define MAX77620_ONOFFCNFG2_SFT_RST_WK (1 << 7)
#define MAX77620_ONOFFCNFG2_WD_RST_WK (1 << 6)
#define MAX77620_ONOFFCNFG2_SLP_LPM_MSK (1 << 5)
#define MAX77620_ONOFFCNFG2_WK_ALARM1 (1 << 2)
#define MAX77620_ONOFFCNFG2_WK_EN0 (1 << 0)
#define MAX77620_GLBLM_MASK (1 << 0)
#define MAX77620_WDTC_MASK 0x3
#define MAX77620_WDTOFFC (1 << 4)
#define MAX77620_WDTSLPC (1 << 3)
#define MAX77620_WDTEN (1 << 2)
#define MAX77620_TWD_MASK 0x3
#define MAX77620_TWD_2s 0x0
#define MAX77620_TWD_16s 0x1
#define MAX77620_TWD_64s 0x2
#define MAX77620_TWD_128s 0x3
#define MAX77620_CNFGGLBL1_LBDAC_EN (1 << 7)
#define MAX77620_CNFGGLBL1_MPPLD (1 << 6)
#define MAX77620_CNFGGLBL1_LBHYST ((1 << 5) | (1 << 4))
#define MAX77620_CNFGGLBL1_LBHYST_N (1 << 4)
#define MAX77620_CNFGGLBL1_LBDAC 0x0E
#define MAX77620_CNFGGLBL1_LBDAC_N (1 << 1)
#define MAX77620_CNFGGLBL1_LBRSTEN (1 << 0)
/* CNFG BBC registers */
#define MAX77620_CNFGBBC_ENABLE (1 << 0)
#define MAX77620_CNFGBBC_CURRENT_MASK 0x06
#define MAX77620_CNFGBBC_CURRENT_SHIFT 1
#define MAX77620_CNFGBBC_VOLTAGE_MASK 0x18
#define MAX77620_CNFGBBC_VOLTAGE_SHIFT 3
#define MAX77620_CNFGBBC_LOW_CURRENT_DISABLE (1 << 5)
#define MAX77620_CNFGBBC_RESISTOR_MASK 0xC0
#define MAX77620_CNFGBBC_RESISTOR_SHIFT 6
#define MAX77620_FPS_COUNT 3
#define MAX77620_IRQ_LVL2_GPIO_EDGE0 (1 << 0)
#define MAX77620_IRQ_LVL2_GPIO_EDGE1 (1 << 1)
#define MAX77620_IRQ_LVL2_GPIO_EDGE2 (1 << 2)
#define MAX77620_IRQ_LVL2_GPIO_EDGE3 (1 << 3)
#define MAX77620_IRQ_LVL2_GPIO_EDGE4 (1 << 4)
#define MAX77620_IRQ_LVL2_GPIO_EDGE5 (1 << 5)
#define MAX77620_IRQ_LVL2_GPIO_EDGE6 (1 << 6)
#define MAX77620_IRQ_LVL2_GPIO_EDGE7 (1 << 7)
/* Interrupts */
enum {

View File

@@ -1,5 +1,6 @@
/*
* Copyright (c) 2018 naehrwert
* 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,
@@ -27,12 +28,15 @@ typedef struct _max77620_regulator_t
u8 type;
const char *name;
u8 reg_sd;
u32 mv_step;
u32 mv_min;
u32 mv_default;
u32 mv_max;
u8 volt_addr;
u8 cfg_addr;
u8 volt_mask;
u8 enable_mask;
u8 enable_shift;
@@ -45,19 +49,19 @@ typedef struct _max77620_regulator_t
} max77620_regulator_t;
static const max77620_regulator_t _pmic_regulators[] = {
{ REGULATOR_SD, "sd0", 0x16, 12500, 600000, 625000, 1400000, MAX77620_REG_SD0, MAX77620_REG_SD0_CFG, 0x3F, 0x30, 4, 0x80, 0x4F, 1, 7, 1 },
{ REGULATOR_SD, "sd1", 0x17, 12500, 600000, 1125000, 1125000, MAX77620_REG_SD1, MAX77620_REG_SD1_CFG, 0x3F, 0x30, 4, 0x40, 0x50, 0, 1, 5 },
{ REGULATOR_SD, "sd2", 0x18, 12500, 600000, 1325000, 1350000, MAX77620_REG_SD2, MAX77620_REG_SD2_CFG, 0xFF, 0x30, 4, 0x20, 0x51, 1, 5, 2 },
{ REGULATOR_SD, "sd3", 0x19, 12500, 600000, 1800000, 1800000, MAX77620_REG_SD3, MAX77620_REG_SD3_CFG, 0xFF, 0x30, 4, 0x10, 0x52, 0, 3, 3 },
{ REGULATOR_LDO, "ldo0", 0x00, 25000, 800000, 1200000, 1200000, MAX77620_REG_LDO0_CFG, MAX77620_REG_LDO0_CFG2, 0x3F, 0xC0, 6, 0x00, 0x46, 3, 7, 0 },
{ REGULATOR_LDO, "ldo1", 0x00, 25000, 800000, 1050000, 1050000, MAX77620_REG_LDO1_CFG, MAX77620_REG_LDO1_CFG2, 0x3F, 0xC0, 6, 0x00, 0x47, 3, 7, 0 },
{ REGULATOR_LDO, "ldo2", 0x00, 50000, 800000, 1800000, 3300000, MAX77620_REG_LDO2_CFG, MAX77620_REG_LDO2_CFG2, 0x3F, 0xC0, 6, 0x00, 0x48, 3, 7, 0 },
{ REGULATOR_LDO, "ldo3", 0x00, 50000, 800000, 3100000, 3100000, MAX77620_REG_LDO3_CFG, MAX77620_REG_LDO3_CFG2, 0x3F, 0xC0, 6, 0x00, 0x49, 3, 7, 0 },
{ REGULATOR_LDO, "ldo4", 0x00, 12500, 800000, 850000, 850000, MAX77620_REG_LDO4_CFG, MAX77620_REG_LDO4_CFG2, 0x3F, 0xC0, 6, 0x00, 0x4A, 0, 7, 1 },
{ REGULATOR_LDO, "ldo5", 0x00, 50000, 800000, 1800000, 1800000, MAX77620_REG_LDO5_CFG, MAX77620_REG_LDO5_CFG2, 0x3F, 0xC0, 6, 0x00, 0x4B, 3, 7, 0 },
{ REGULATOR_LDO, "ldo6", 0x00, 50000, 800000, 2900000, 2900000, MAX77620_REG_LDO6_CFG, MAX77620_REG_LDO6_CFG2, 0x3F, 0xC0, 6, 0x00, 0x4C, 3, 7, 0 },
{ REGULATOR_LDO, "ldo7", 0x00, 50000, 800000, 1050000, 1050000, MAX77620_REG_LDO7_CFG, MAX77620_REG_LDO7_CFG2, 0x3F, 0xC0, 6, 0x00, 0x4D, 1, 4, 3 },
{ REGULATOR_LDO, "ldo8", 0x00, 50000, 800000, 1050000, 1050000, MAX77620_REG_LDO8_CFG, MAX77620_REG_LDO8_CFG2, 0x3F, 0xC0, 6, 0x00, 0x4E, 3, 7, 0 }
{ REGULATOR_SD, "sd0", 0x16, 12500, 600000, 625000, 1400000, MAX77620_REG_SD0, MAX77620_REG_SD0_CFG, MAX77620_SD0_VOLT_MASK, MAX77620_SD_POWER_MODE_MASK, MAX77620_SD_POWER_MODE_SHIFT, 0x80, MAX77620_REG_FPS_SD0, 1, 7, 1 },
{ REGULATOR_SD, "sd1", 0x17, 12500, 600000, 1125000, 1125000, MAX77620_REG_SD1, MAX77620_REG_SD1_CFG, MAX77620_SD1_VOLT_MASK, MAX77620_SD_POWER_MODE_MASK, MAX77620_SD_POWER_MODE_SHIFT, 0x40, MAX77620_REG_FPS_SD1, 0, 1, 5 },
{ REGULATOR_SD, "sd2", 0x18, 12500, 600000, 1325000, 1350000, MAX77620_REG_SD2, MAX77620_REG_SD2_CFG, MAX77620_SDX_VOLT_MASK, MAX77620_SD_POWER_MODE_MASK, MAX77620_SD_POWER_MODE_SHIFT, 0x20, MAX77620_REG_FPS_SD2, 1, 5, 2 },
{ REGULATOR_SD, "sd3", 0x19, 12500, 600000, 1800000, 1800000, MAX77620_REG_SD3, MAX77620_REG_SD3_CFG, MAX77620_SDX_VOLT_MASK, MAX77620_SD_POWER_MODE_MASK, MAX77620_SD_POWER_MODE_SHIFT, 0x10, MAX77620_REG_FPS_SD3, 0, 3, 3 },
{ REGULATOR_LDO, "ldo0", 0x00, 25000, 800000, 1200000, 1200000, MAX77620_REG_LDO0_CFG, MAX77620_REG_LDO0_CFG2, MAX77620_LDO_VOLT_MASK, MAX77620_LDO_POWER_MODE_MASK, MAX77620_LDO_POWER_MODE_SHIFT, 0x00, MAX77620_REG_FPS_LDO0, 3, 7, 0 },
{ REGULATOR_LDO, "ldo1", 0x00, 25000, 800000, 1050000, 1050000, MAX77620_REG_LDO1_CFG, MAX77620_REG_LDO1_CFG2, MAX77620_LDO_VOLT_MASK, MAX77620_LDO_POWER_MODE_MASK, MAX77620_LDO_POWER_MODE_SHIFT, 0x00, MAX77620_REG_FPS_LDO1, 3, 7, 0 },
{ REGULATOR_LDO, "ldo2", 0x00, 50000, 800000, 1800000, 3300000, MAX77620_REG_LDO2_CFG, MAX77620_REG_LDO2_CFG2, MAX77620_LDO_VOLT_MASK, MAX77620_LDO_POWER_MODE_MASK, MAX77620_LDO_POWER_MODE_SHIFT, 0x00, MAX77620_REG_FPS_LDO2, 3, 7, 0 },
{ REGULATOR_LDO, "ldo3", 0x00, 50000, 800000, 3100000, 3100000, MAX77620_REG_LDO3_CFG, MAX77620_REG_LDO3_CFG2, MAX77620_LDO_VOLT_MASK, MAX77620_LDO_POWER_MODE_MASK, MAX77620_LDO_POWER_MODE_SHIFT, 0x00, MAX77620_REG_FPS_LDO3, 3, 7, 0 },
{ REGULATOR_LDO, "ldo4", 0x00, 12500, 800000, 850000, 850000, MAX77620_REG_LDO4_CFG, MAX77620_REG_LDO4_CFG2, MAX77620_LDO_VOLT_MASK, MAX77620_LDO_POWER_MODE_MASK, MAX77620_LDO_POWER_MODE_SHIFT, 0x00, MAX77620_REG_FPS_LDO4, 0, 7, 1 },
{ REGULATOR_LDO, "ldo5", 0x00, 50000, 800000, 1800000, 1800000, MAX77620_REG_LDO5_CFG, MAX77620_REG_LDO5_CFG2, MAX77620_LDO_VOLT_MASK, MAX77620_LDO_POWER_MODE_MASK, MAX77620_LDO_POWER_MODE_SHIFT, 0x00, MAX77620_REG_FPS_LDO5, 3, 7, 0 },
{ REGULATOR_LDO, "ldo6", 0x00, 50000, 800000, 2900000, 2900000, MAX77620_REG_LDO6_CFG, MAX77620_REG_LDO6_CFG2, MAX77620_LDO_VOLT_MASK, MAX77620_LDO_POWER_MODE_MASK, MAX77620_LDO_POWER_MODE_SHIFT, 0x00, MAX77620_REG_FPS_LDO6, 3, 7, 0 },
{ REGULATOR_LDO, "ldo7", 0x00, 50000, 800000, 1050000, 1050000, MAX77620_REG_LDO7_CFG, MAX77620_REG_LDO7_CFG2, MAX77620_LDO_VOLT_MASK, MAX77620_LDO_POWER_MODE_MASK, MAX77620_LDO_POWER_MODE_SHIFT, 0x00, MAX77620_REG_FPS_LDO7, 1, 4, 3 },
{ REGULATOR_LDO, "ldo8", 0x00, 50000, 800000, 1050000, 1050000, MAX77620_REG_LDO8_CFG, MAX77620_REG_LDO8_CFG2, MAX77620_LDO_VOLT_MASK, MAX77620_LDO_POWER_MODE_MASK, MAX77620_LDO_POWER_MODE_SHIFT, 0x00, MAX77620_REG_FPS_LDO8, 3, 7, 0 }
};
int max77620_regulator_get_status(u32 id)
@@ -79,7 +83,8 @@ int max77620_regulator_config_fps(u32 id)
const max77620_regulator_t *reg = &_pmic_regulators[id];
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, reg->fps_addr, (reg->fps_src << 6) | (reg->pu_period << 3) | (reg->pd_period));
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, reg->fps_addr,
(reg->fps_src << MAX77620_FPS_SRC_SHIFT) | (reg->pu_period << MAX77620_FPS_PU_PERIOD_SHIFT) | (reg->pd_period));
return 1;
}
@@ -91,7 +96,7 @@ int max77620_regulator_set_voltage(u32 id, u32 mv)
const max77620_regulator_t *reg = &_pmic_regulators[id];
if (mv < reg->mv_default || mv > reg->mv_max)
if (mv < reg->mv_min || mv > reg->mv_max)
return 0;
u32 mult = (mv + reg->mv_step - 1 - reg->mv_min) / reg->mv_step;
@@ -113,7 +118,7 @@ int max77620_regulator_enable(u32 id, int enable)
u32 addr = reg->type == REGULATOR_SD ? reg->cfg_addr : reg->volt_addr;
u8 val = i2c_recv_byte(I2C_5, MAX77620_I2C_ADDR, addr);
if (enable)
val = (val & ~reg->enable_mask) | ((3 << reg->enable_shift) & reg->enable_mask);
val = (val & ~reg->enable_mask) | ((MAX77620_POWER_MODE_NORMAL << reg->enable_shift) & reg->enable_mask);
else
val &= ~reg->enable_mask;
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, addr, val);
@@ -122,6 +127,24 @@ int max77620_regulator_enable(u32 id, int enable)
return 1;
}
int max77620_regulator_set_volt_and_flags(u32 id, u32 mv, u8 flags)
{
if (id > REGULATOR_MAX)
return 0;
const max77620_regulator_t *reg = &_pmic_regulators[id];
if (mv < reg->mv_min || mv > reg->mv_max)
return 0;
u32 mult = (mv + reg->mv_step - 1 - reg->mv_min) / reg->mv_step;
u8 val = ((flags << reg->enable_shift) & ~reg->volt_mask) | (mult & reg->volt_mask);
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, reg->volt_addr, val);
usleep(1000);
return 1;
}
void max77620_config_default()
{
for (u32 i = 1; i <= REGULATOR_MAX; i++)

View File

@@ -1,5 +1,6 @@
/*
* Copyright (c) 2018 naehrwert
* 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,
@@ -30,10 +31,10 @@
* ldo0 | Display Panel | 25000 | 800000 | 1200000 | 1200000 | 1.2V (pkg1.1)
* ldo1 | XUSB, PCIE | 25000 | 800000 | 1050000 | 1050000 | 1.05V (pcv)
* ldo2 | SDMMC1 | 50000 | 800000 | 1800000 | 3300000 |
* ldo3 | | 50000 | 800000 | 3100000 | 3100000 |
* ldo3 | GC ASIC | 50000 | 800000 | 3100000 | 3100000 | 3.1V (pcv)
* ldo4 | RTC | 12500 | 800000 | 850000 | 850000 |
* ldo5 | | 50000 | 800000 | 1800000 | 1800000 |
* ldo6 | | 50000 | 800000 | 2900000 | 2900000 |
* ldo5 | GC ASIC | 50000 | 800000 | 1800000 | 1800000 | 1.8V (pcv)
* ldo6 | Touch, ALS | 50000 | 800000 | 2900000 | 2900000 | 2.9V
* ldo7 | XUSB | 50000 | 800000 | 1050000 | 1050000 |
* ldo8 | XUSB, DC | 50000 | 800000 | 1050000 | 1050000 |
*/
@@ -108,6 +109,7 @@ int max77620_regulator_get_status(u32 id);
int max77620_regulator_config_fps(u32 id);
int max77620_regulator_set_voltage(u32 id, u32 mv);
int max77620_regulator_enable(u32 id, int enable);
int max77620_regulator_set_volt_and_flags(u32 id, u32 mv, u8 flags);
void max77620_config_default();
void max77620_low_battery_monitor_config();

View File

@@ -0,0 +1,77 @@
/*
* PMIC Real Time Clock driver for Nintendo Switch's MAX77620-RTC
*
* 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 "max77620-rtc.h"
#include "../soc/i2c.h"
#include "../utils/util.h"
void max77620_rtc_get_time(rtc_time_t *time)
{
u8 val = 0;
// Update RTC regs from RTC clock.
i2c_send_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_UPDATE0_REG, MAX77620_RTC_READ_UPDATE);
// Get control reg config.
val = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_CONTROL_REG);
// TODO: Check for binary format also?
// Get time.
time->sec = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_SEC_REG) & 0x7F;
time->min = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_MIN_REG) & 0x7F;
time->hour = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_HOUR_REG) & 0x1F;
if (!(val & MAX77620_RTC_24H) && time->hour & MAX77620_RTC_HOUR_PM_MASK)
time->hour = (time->hour & 0xF) + 12;
// Get day of week. 1: Monday to 7: Sunday.
time->weekday = 0;
val = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_WEEKDAY_REG);
for (int i = 0; i < 8; i++)
{
time->weekday++;
if (val & 1)
break;
val >>= 1;
}
// Get date.
time->date = 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;
}
void max77620_rtc_stop_alarm()
{
u8 val = 0;
// Update RTC regs from RTC clock.
i2c_send_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_UPDATE0_REG, MAX77620_RTC_READ_UPDATE);
// Stop alarm for both ALARM1 and ALARM2. Horizon uses ALARM2.
for (int i = 0; i < (MAX77620_RTC_NR_TIME_REGS * 2); i++)
{
val = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_ALARM1_SEC_REG + i);
val &= ~MAX77620_RTC_ALARM_EN_MASK;
i2c_send_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_ALARM1_SEC_REG + i, val);
}
// Update RTC clock from RTC regs.
i2c_send_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_UPDATE0_REG, MAX77620_RTC_WRITE_UPDATE);
}

View File

@@ -0,0 +1,75 @@
/*
* PMIC Real Time Clock driver for Nintendo Switch's MAX77620-RTC
*
* 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 _MFD_MAX77620_RTC_H_
#define _MFD_MAX77620_RTC_H_
#include "../utils/types.h"
#define MAX77620_RTC_I2C_ADDR 0x68
#define MAX77620_RTC_NR_TIME_REGS 7
#define MAX77620_RTC_CONTROLM_REG 0x02
#define MAX77620_RTC_CONTROL_REG 0x03
#define MAX77620_RTC_BIN_FORMAT (1 << 0)
#define MAX77620_RTC_24H (1 << 1)
#define MAX77620_RTC_UPDATE0_REG 0x04
#define MAX77620_RTC_WRITE_UPDATE (1 << 0)
#define MAX77620_RTC_READ_UPDATE (1 << 4)
#define MAX77620_RTC_SEC_REG 0x07
#define MAX77620_RTC_MIN_REG 0x08
#define MAX77620_RTC_HOUR_REG 0x09
#define MAX77620_RTC_HOUR_PM_MASK (1 << 6)
#define MAX77620_RTC_WEEKDAY_REG 0x0A
#define MAX77620_RTC_MONTH_REG 0x0B
#define MAX77620_RTC_YEAR_REG 0x0C
#define MAX77620_RTC_DATE_REG 0x0D
#define MAX77620_ALARM1_SEC_REG 0x0E
#define MAX77620_ALARM1_MIN_REG 0x0F
#define MAX77620_ALARM1_HOUR_REG 0x10
#define MAX77620_ALARM1_WEEKDAY_REG 0x11
#define MAX77620_ALARM1_MONTH_REG 0x12
#define MAX77620_ALARM1_YEAR_REG 0x13
#define MAX77620_ALARM1_DATE_REG 0x14
#define MAX77620_ALARM2_SEC_REG 0x15
#define MAX77620_ALARM2_MIN_REG 0x16
#define MAX77620_ALARM2_HOUR_REG 0x17
#define MAX77620_ALARM2_WEEKDAY_REG 0x18
#define MAX77620_ALARM2_MONTH_REG 0x19
#define MAX77620_ALARM2_YEAR_REG 0x1A
#define MAX77620_ALARM2_DATE_REG 0x1B
#define MAX77620_RTC_ALARM_EN_MASK (1 << 7)
typedef struct _rtc_time_t {
u8 weekday;
u8 sec;
u8 min;
u8 hour;
u8 date;
u8 month;
u16 year;
} rtc_time_t;
void max77620_rtc_get_time(rtc_time_t *time);
void max77620_rtc_stop_alarm();
#endif /* _MFD_MAX77620_RTC_H_ */

View File

@@ -270,15 +270,15 @@ int se_calc_sha256(void *dst, const void *src, u32 src_size)
int res;
// Setup config for SHA256, size = BITS(src_size).
SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_ENC_MODE(MODE_SHA256) | SE_CONFIG_ENC_ALG(ALG_SHA) | SE_CONFIG_DST(DST_HASHREG);
SE(SE_SHA_CONFIG_REG_OFFSET) = 1;
SE(SE_SHA_CONFIG_REG_OFFSET) = SHA_ENABLE;
SE(SE_SHA_MSG_LENGTH_REG_OFFSET) = (u32)(src_size << 3);
SE(0x208) = 0;
SE(0x20C) = 0;
SE(0x210) = 0;
SE(SE_SHA_MSG_LENGTH_REG_OFFSET + 4 * 1) = 0;
SE(SE_SHA_MSG_LENGTH_REG_OFFSET + 4 * 2) = 0;
SE(SE_SHA_MSG_LENGTH_REG_OFFSET + 4 * 3) = 0;
SE(SE_SHA_MSG_LEFT_REG_OFFSET) = (u32)(src_size << 3);
SE(0x218) = 0;
SE(0x21C) = 0;
SE(0x220) = 0;
SE(SE_SHA_MSG_LEFT_REG_OFFSET + 4 * 1) = 0;
SE(SE_SHA_MSG_LEFT_REG_OFFSET + 4 * 2) = 0;
SE(SE_SHA_MSG_LEFT_REG_OFFSET + 4 * 3) = 0;
// Trigger the operation.
res = _se_execute(OP_START, NULL, 0, src, src_size);

View File

@@ -1,6 +1,6 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (c) 2018 CTCaer
* Copyright (c) 2018-2019 CTCaer
* Copyright (c) 2018 balika011
*
* This program is free software; you can redistribute it and/or modify it
@@ -29,8 +29,7 @@
#include "../utils/util.h"
#include "../hos/hos.h"
/* #include "../gfx/gfx.h"
extern gfx_con_t gfx_con; */
// #include "../gfx/gfx.h"
static int _tsec_dma_wait_idle()
{
@@ -64,6 +63,7 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt)
int res = 0;
u8 *fwbuf = NULL;
u32 *pdir, *car, *fuse, *pmc, *flowctrl, *se, *mc, *iram, *evec;
u32 *pkg11_magic_off;
//Enable clocks.
clock_enable_host1x();
@@ -96,15 +96,15 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt)
}
//Load firmware or emulate memio environment for newer TSEC fw.
if (kb <= KB_FIRMWARE_VERSION_600)
if (kb == KB_FIRMWARE_VERSION_620)
TSEC(TSEC_DMATRFBASE) = (u32)tsec_ctxt->fw >> 8;
else
{
fwbuf = (u8 *)malloc(0x2000);
u8 *fwbuf_aligned = (u8 *)ALIGN((u32)fwbuf + 0x1000, 0x100);
fwbuf = (u8 *)malloc(0x4000);
u8 *fwbuf_aligned = (u8 *)ALIGN((u32)fwbuf, 0x100);
memcpy(fwbuf_aligned, tsec_ctxt->fw, tsec_ctxt->size);
TSEC(TSEC_DMATRFBASE) = (u32)fwbuf_aligned >> 8;
}
else
TSEC(TSEC_DMATRFBASE) = (u32)tsec_ctxt->fw >> 8;
for (u32 addr = 0; addr < tsec_ctxt->size; addr += 0x100)
{
@@ -115,7 +115,7 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt)
}
}
if (kb >= KB_FIRMWARE_VERSION_620)
if (kb == KB_FIRMWARE_VERSION_620)
{
// Init SMMU translation for TSEC.
pdir = smmu_init_for_tsec();
@@ -161,6 +161,8 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt)
// IRAM
iram = page_alloc(0x30);
memcpy(iram, tsec_ctxt->pkg1, 0x30000);
// PKG1.1 magic offset.
pkg11_magic_off = (u32 *)(iram + ((tsec_ctxt->pkg11_off + 0x20) / 4));
smmu_map(pdir, 0x40010000, (u32)iram, 0x30, _READABLE | _WRITABLE | _NONSECURE);
// Exception vectors
@@ -171,11 +173,60 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt)
//Execute firmware.
HOST1X(0x3300) = 0x34C2E1DA;
TSEC(TSEC_STATUS) = 0;
TSEC(TSEC_BOOTKEYVER) = tsec_ctxt->key_ver;
TSEC(TSEC_BOOTKEYVER) = 1; // HOS uses key version 1.
TSEC(TSEC_BOOTVEC) = 0;
TSEC(TSEC_CPUCTL) = TSEC_CPUCTL_STARTCPU;
if (kb <= KB_FIRMWARE_VERSION_600)
if (kb == KB_FIRMWARE_VERSION_620)
{
u32 start = get_tmr_us();
u32 k = se[SE_KEYTABLE_DATA0_REG_OFFSET / 4];
u32 key[16] = {0};
u32 kidx = 0;
while (*pkg11_magic_off != HOS_PKG11_MAGIC)
{
smmu_flush_all();
if (k == se[SE_KEYTABLE_DATA0_REG_OFFSET / 4])
continue;
k = se[SE_KEYTABLE_DATA0_REG_OFFSET / 4];
key[kidx++] = k;
// Failsafe.
if ((u32)get_tmr_us() - start > 125000)
break;
}
if (kidx != 8)
{
res = -6;
smmu_deinit_for_tsec();
goto out;
}
// Give some extra time to make sure PKG1.1 is decrypted.
msleep(50);
memcpy(tsec_keys, &key, 0x20);
memcpy(tsec_ctxt->pkg1, iram, 0x30000);
smmu_deinit_for_tsec();
// for (int i = 0; i < kidx; i++)
// gfx_printf(&gfx_con, "key %08X\n", key[i]);
// gfx_printf(&gfx_con, "cpuctl (%08X) mbox (%08X)\n", TSEC(TSEC_CPUCTL), TSEC(TSEC_STATUS));
// u32 errst = MC(MC_ERR_STATUS);
// gfx_printf(&gfx_con, " MC %08X %08X %08X\n", MC(MC_INTSTATUS), errst, MC(MC_ERR_ADR));
// gfx_printf(&gfx_con, " type: %02X\n", errst >> 28);
// gfx_printf(&gfx_con, " smmu: %02X\n", (errst >> 25) & 3);
// gfx_printf(&gfx_con, " dir: %s\n", (errst >> 16) & 1 ? "W" : "R");
// gfx_printf(&gfx_con, " cid: %02x\n", errst & 0xFF);
}
else
{
if (!_tsec_dma_wait_idle())
{
@@ -209,51 +260,6 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt)
memcpy(tsec_keys, &buf, 0x10);
}
else
{
u32 start = get_tmr_us();
u32 k = se[SE_KEYTABLE_DATA0_REG_OFFSET / 4];
u32 key[16] = {0};
u32 kidx = 0;
while (memcmp((u8 *)(iram + ((tsec_ctxt->pkg11_off + 0x20) / 4)), "PK11", 4))
{
smmu_flush_all();
if (k == se[SE_KEYTABLE_DATA0_REG_OFFSET / 4])
continue;
k = se[SE_KEYTABLE_DATA0_REG_OFFSET / 4];
key[kidx++] = k;
// Failsafe.
if ((u32)get_tmr_us() - start > 500000)
break;
}
if (kidx != 8)
{
res = -6;
smmu_deinit_for_tsec();
goto out;
}
memcpy(tsec_keys, &key, 0x20);
memcpy(tsec_ctxt->pkg1, iram, 0x30000);
smmu_deinit_for_tsec();
// for (int i = 0; i < kidx; i++)
// gfx_printf(&gfx_con, "key %08X\n", key[i]);
// gfx_printf(&gfx_con, "cpuctl (%08X) mbox (%08X)\n", TSEC(TSEC_CPUCTL), TSEC(TSEC_STATUS));
// u32 errst = MC(MC_ERR_STATUS);
// gfx_printf(&gfx_con, " MC %08X %08X %08X\n", MC(MC_INTSTATUS), errst, MC(MC_ERR_ADR));
// gfx_printf(&gfx_con, " type: %02X\n", errst >> 28);
// gfx_printf(&gfx_con, " smmu: %02X\n", (errst >> 25) & 3);
// gfx_printf(&gfx_con, " dir: %s\n", (errst >> 16) & 1 ? "W" : "R");
// gfx_printf(&gfx_con, " cid: %02x\n", errst & 0xFF);
}
out_free:;
free(fwbuf);

View File

@@ -22,7 +22,6 @@
typedef struct _tsec_ctxt_t
{
u32 key_ver;
void *fw;
u32 size;
void *pkg1;

View File

@@ -22,11 +22,11 @@
/* 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, 0 },
/* UART B */ { CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_UARTB, 7, 0, 0 },
/* UART C */ { CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_RST_CONTROLLER_CLK_SOURCE_UARTC, 0x17, 0, 0 },
/* UART D */ { 0 },
/* UART E */ { 0 }
};
static const clock_t _clock_i2c[] = {

View File

@@ -25,8 +25,8 @@
void _cluster_enable_power()
{
u8 tmp = i2c_recv_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_AME_GPIO);
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_AME_GPIO, tmp & 0xDF);
u8 tmp = i2c_recv_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_AME_GPIO); // Get current pinmuxing
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_AME_GPIO, tmp & ~(1 << 5)); // Disable GPIO5 pinmuxing.
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_GPIO5, MAX77620_CNFG_GPIO_DRV_PUSHPULL | MAX77620_CNFG_GPIO_OUTPUT_VAL_HIGH);
// Enable cores power.

View File

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

View File

@@ -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,
@@ -37,6 +37,7 @@
#include "../utils/util.h"
extern sdmmc_t sd_sdmmc;
extern boot_cfg_t b_cfg;
void _config_oscillators()
{
@@ -64,8 +65,12 @@ void _config_gpios()
PINMUX_AUX(PINMUX_AUX_GPIO_PE6) = PINMUX_INPUT_ENABLE;
PINMUX_AUX(PINMUX_AUX_GPIO_PH6) = PINMUX_INPUT_ENABLE;
#if !defined (DEBUG_UART_PORT) || DEBUG_UART_PORT != UART_B
gpio_config(GPIO_PORT_G, GPIO_PIN_0, GPIO_MODE_GPIO);
#endif
#if !defined (DEBUG_UART_PORT) || DEBUG_UART_PORT != UART_C
gpio_config(GPIO_PORT_D, GPIO_PIN_1, GPIO_MODE_GPIO);
#endif
gpio_config(GPIO_PORT_E, GPIO_PIN_6, GPIO_MODE_GPIO);
gpio_config(GPIO_PORT_H, GPIO_PIN_6, GPIO_MODE_GPIO);
gpio_output_enable(GPIO_PORT_G, GPIO_PIN_0, GPIO_OUTPUT_DISABLE);
@@ -93,6 +98,9 @@ void _config_pmc_scratch()
void _mbist_workaround()
{
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_V) |= (1 << 10); // Enable AHUB clock.
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_Y) |= (1 << 6); // Enable APE clock.
CLOCK(CLK_RST_CONTROLLER_CLK_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;
@@ -138,27 +146,31 @@ void _mbist_workaround()
void _config_se_brom()
{
// Bootrom part we skipped.
u32 sbk[4] = {
FUSE(FUSE_PRIVATE_KEY0),
FUSE(FUSE_PRIVATE_KEY1),
FUSE(FUSE_PRIVATE_KEY2),
FUSE(FUSE_PRIVATE_KEY3)
};
// Set SBK to slot 14.
se_aes_key_set(14, sbk, 0x10);
// Skip SBK/SSK if sept was run.
if (!(b_cfg.boot_cfg & BOOT_CFG_SEPT_RUN))
{
// Bootrom part we skipped.
u32 sbk[4] = {
FUSE(FUSE_PRIVATE_KEY0),
FUSE(FUSE_PRIVATE_KEY1),
FUSE(FUSE_PRIVATE_KEY2),
FUSE(FUSE_PRIVATE_KEY3)
};
// Set SBK to slot 14.
se_aes_key_set(14, sbk, 0x10);
// Lock SBK from being read.
SE(SE_KEY_TABLE_ACCESS_REG_OFFSET + 14 * 4) = 0x7E;
// Lock SBK from being read.
SE(SE_KEY_TABLE_ACCESS_REG_OFFSET + 14 * 4) = 0x7E;
// Lock SSK (although it's not set and unused anyways).
SE(SE_KEY_TABLE_ACCESS_REG_OFFSET + 15 * 4) = 0x7E;
}
// This memset needs to happen here, else TZRAM will behave weirdly later on.
memset((void *)TZRAM_BASE, 0, 0x10000);
PMC(APBDEV_PMC_CRYPTO_OP) = 0;
PMC(APBDEV_PMC_CRYPTO_OP) = PMC_CRYPTO_OP_SE_ENABLE;
SE(SE_INT_STATUS_REG_OFFSET) = 0x1F;
// Lock SSK (although it's not set and unused anyways).
SE(SE_KEY_TABLE_ACCESS_REG_OFFSET + 15 * 4) = 0x7E;
// Clear the boot reason to avoid problems later
PMC(APBDEV_PMC_SCRATCH200) = 0x0;
PMC(APBDEV_PMC_RST_STATUS) = 0x0;
@@ -187,8 +199,10 @@ void config_hw()
APB_MISC(APB_MISC_PP_PINMUX_GLOBAL) = 0;
_config_gpios();
//clock_enable_uart(UART_C);
//uart_init(UART_C, 115200);
#ifdef DEBUG_UART_PORT
clock_enable_uart(DEBUG_UART_PORT);
uart_init(DEBUG_UART_PORT, 115200);
#endif
clock_enable_cl_dvfs();
@@ -200,21 +214,30 @@ void config_hw()
i2c_init(I2C_1);
i2c_init(I2C_5);
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_CNFGBBC, 0x40);
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_ONOFFCNFG1, 0x78);
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, 0x38);
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_CFG1, 0x3A);
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_CFG2, 0x38);
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_LDO4, 0xF);
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_LDO8, 0xC7);
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_SD0, 0x4F);
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_SD1, 0x29);
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_SD3, 0x1B);
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_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, 0x22); // 3.x+
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+
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_SD0, 42); //42 = (1125000uV - 600000) / 12500 -> 1.125V
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);
_config_pmc_scratch(); // Missing from 4.x+
@@ -255,4 +278,4 @@ void reconfig_hw_workaround(bool extra_reconfig, u32 magic)
msleep(200);
}
}
}

View File

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

View File

@@ -32,12 +32,18 @@
#define PMC_PWR_DET_SDMMC1_IO_EN (1 << 12)
#define APBDEV_PMC_DDR_PWR 0xE8
#define APBDEV_PMC_CRYPTO_OP 0xF4
#define PMC_CRYPTO_OP_SE_ENABLE 0
#define PMC_CRYPTO_OP_SE_DISABLE 1
#define APBDEV_PMC_SCRATCH33 0x120
#define APBDEV_PMC_SCRATCH40 0x13C
#define APBDEV_PMC_OSC_EDPD_OVER 0x1A4
#define APBDEV_PMC_RST_STATUS 0x1B4
#define APBDEV_PMC_IO_DPD_REQ 0x1B8
#define APBDEV_PMC_IO_DPD2_REQ 0x1C0
#define APBDEV_PMC_VDDP_SEL 0x1CC
#define APBDEV_PMC_DDR_CFG 0x1D0
#define APBDEV_PMC_SCRATCH45 0x234
#define APBDEV_PMC_SCRATCH46 0x238
#define APBDEV_PMC_SCRATCH49 0x244
#define APBDEV_PMC_TSC_MULT 0x2B4
#define APBDEV_PMC_SEC_DISABLE2 0x2C4

View File

@@ -94,7 +94,7 @@ void smmu_enable()
cluster_boot_cpu0((u32)smmu_payload);
smmu_used = true;
msleep(100);
msleep(150);
smmu_flush_all();
}

View File

@@ -107,6 +107,8 @@
#define APB_MISC_PP_STRAPPING_OPT_A 0x08
#define APB_MISC_PP_PINMUX_GLOBAL 0x40
#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_WIFI_EN_CFGPADCTRL 0xB64
#define APB_MISC_GP_WIFI_RST_CFGPADCTRL 0xB68
@@ -177,4 +179,9 @@
#define I2S_CG_SLCG_ENABLE (1 << 0)
#define I2S_CTRL_MASTER_EN (1 << 10)
/*! Special registers. */
#define EMC_SCRATCH0 0x324
#define EMC_HEKA_UPD (1 << 30)
#define EMC_SEPT_RUN (1 << 31)
#endif

View File

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

View File

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

View File

@@ -19,13 +19,11 @@
#include "sdmmc.h"
#include "mmc.h"
#include "sd.h"
#include "../utils/util.h"
#include "../gfx/gfx.h"
#include "../mem/heap.h"
#include "../utils/util.h"
/*#include "gfx.h"
extern gfx_ctxt_t gfx_ctxt;
extern gfx_con_t gfx_con;
#define DPRINTF(...) gfx_printf(&gfx_con, __VA_ARGS__)*/
//#define DPRINTF(...) gfx_printf(&gfx_con, __VA_ARGS__)
#define DPRINTF(...)
static inline u32 unstuff_bits(u32 *resp, u32 start, u32 size)

View File

@@ -17,20 +17,18 @@
#include <string.h>
#include "sdmmc.h"
#include "../utils/util.h"
#include "../soc/clock.h"
#include "mmc.h"
#include "sdmmc.h"
#include "../gfx/gfx.h"
#include "../power/max7762x.h"
#include "../soc/t210.h"
#include "../soc/pmc.h"
#include "../soc/pinmux.h"
#include "../soc/clock.h"
#include "../soc/gpio.h"
#include "../soc/pinmux.h"
#include "../soc/pmc.h"
#include "../soc/t210.h"
#include "../utils/util.h"
/*#include "gfx.h"
extern gfx_ctxt_t gfx_ctxt;
extern gfx_con_t gfx_con;
#define DPRINTF(...) gfx_printf(&gfx_con, __VA_ARGS__)*/
//#define DPRINTF(...) gfx_printf(&gfx_con, __VA_ARGS__)
#define DPRINTF(...)
/*! SCMMC controller base addresses. */
@@ -143,8 +141,20 @@ static int _sdmmc_get_clkcon(sdmmc_t *sdmmc)
static void _sdmmc_pad_config_fallback(sdmmc_t *sdmmc, u32 power)
{
_sdmmc_get_clkcon(sdmmc);
if (sdmmc->id == SDMMC_4)
*(vu32 *)0x70000AB4 = ((*(vu32 *)0x70000AB4) & 0x3FFC) | 0x1040;
switch (sdmmc->id)
{
case SDMMC_1:
if (power == SDMMC_POWER_OFF)
break;
if (power == SDMMC_POWER_1_8)
APB_MISC(APB_MISC_GP_SDMMC1_PAD_CFGPADCTRL) = 0x304; // Up: 3, Dn: 4.
else if (power == SDMMC_POWER_3_3)
APB_MISC(APB_MISC_GP_SDMMC1_PAD_CFGPADCTRL) = 0x808; // Up: 8, Dn: 8.
break;
case SDMMC_4:
APB_MISC(APB_MISC_GP_EMMC4_PAD_CFGPADCTRL) = (APB_MISC(APB_MISC_GP_EMMC4_PAD_CFGPADCTRL) & 0x3FFC) | 0x1040;
break;
}
//TODO: load standard values for other controllers, can depend on power.
}

View File

@@ -22,9 +22,9 @@
#include "util.h"
#include "../power/max77620.h"
u32 btn_read()
u8 btn_read()
{
u32 res = 0;
u8 res = 0;
if (!gpio_read(GPIO_PORT_X, GPIO_PIN_7))
res |= BTN_VOL_DOWN;
if (!gpio_read(GPIO_PORT_X, GPIO_PIN_6))
@@ -34,9 +34,9 @@ u32 btn_read()
return res;
}
u32 btn_wait()
u8 btn_wait()
{
u32 res = 0, btn = btn_read();
u8 res = 0, btn = btn_read();
bool pwr = false;
//Power button down, raise a filter.
@@ -59,16 +59,18 @@ u32 btn_wait()
return res;
}
u32 btn_wait_timeout(u32 time_ms, u32 mask)
u8 btn_wait_timeout(u32 time_ms, u8 mask)
{
u32 timeout = get_tmr_ms() + time_ms;
u32 res = btn_read() & mask;
u8 res = btn_read() & mask;
do
while (get_tmr_ms() < timeout)
{
if (!(res & mask))
if (res == mask)
break;
else
res = btn_read() & mask;
} while (get_tmr_ms() < timeout);
};
return res;
}

View File

@@ -20,12 +20,12 @@
#include "types.h"
#define BTN_POWER 0x1
#define BTN_VOL_DOWN 0x2
#define BTN_VOL_UP 0x4
#define BTN_POWER (1 << 0)
#define BTN_VOL_DOWN (1 << 1)
#define BTN_VOL_UP (1 << 2)
u32 btn_read();
u32 btn_wait();
u32 btn_wait_timeout(u32 time_ms, u32 mask);
u8 btn_read();
u8 btn_wait();
u8 btn_wait_timeout(u32 time_ms, u8 mask);
#endif

View File

@@ -51,4 +51,37 @@ typedef int bool;
#define true 1
#define false 0
#define BOOT_CFG_AUTOBOOT_EN (1 << 0)
#define BOOT_CFG_FROM_LAUNCH (1 << 1)
#define BOOT_CFG_SEPT_RUN (1 << 7)
#define EXTRA_CFG_KEYS (1 << 0)
#define EXTRA_CFG_PAYLOAD (1 << 1)
#define EXTRA_CFG_MODULE (1 << 2)
typedef struct __attribute__((__packed__)) _boot_cfg_t
{
u8 boot_cfg;
u8 autoboot;
u8 autoboot_list;
u8 extra_cfg;
u8 rsvd[128];
} boot_cfg_t;
typedef struct __attribute__((__packed__)) _ipl_ver_meta_t
{
u32 magic;
u32 version;
u16 rsvd0;
u16 rsvd1;
} ipl_ver_meta_t;
typedef struct __attribute__((__packed__)) _reloc_meta_t
{
u32 start;
u32 stack;
u32 end;
u32 ep;
} reloc_meta_t;
#endif

View File

@@ -16,8 +16,15 @@
*/
#include "util.h"
#include "../gfx/di.h"
#include "../power/max77620.h"
#include "../rtc/max77620-rtc.h"
#include "../soc/i2c.h"
#include "../soc/pmc.h"
#include "../soc/t210.h"
extern void sd_unmount();
u32 get_tmr_s()
{
return RTC(APBDEV_RTC_SECONDS);
@@ -26,7 +33,7 @@ u32 get_tmr_s()
u32 get_tmr_ms()
{
// The registers must be read with the following order:
// -> RTC_MILLI_SECONDS (0x10) -> RTC_SHADOW_SECONDS (0xC)
// RTC_MILLI_SECONDS (0x10) -> RTC_SHADOW_SECONDS (0xC)
return (RTC(APBDEV_RTC_MILLI_SECONDS) | (RTC(APBDEV_RTC_SHADOW_SECONDS) << 10));
}
@@ -56,6 +63,50 @@ void exec_cfg(u32 *base, const cfg_op_t *ops, u32 num_ops)
base[ops[i].off] = ops[i].val;
}
void panic(u32 val)
{
// Set panic code.
PMC(APBDEV_PMC_SCRATCH200) = val;
//PMC(APBDEV_PMC_CRYPTO_OP) = PMC_CRYPTO_OP_SE_DISABLE;
TMR(TIMER_WDT4_UNLOCK_PATTERN) = TIMER_MAGIC_PTRN;
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)
;
}
void reboot_normal()
{
sd_unmount();
display_end();
panic(0x21); // Bypass fuse programming in package1.
}
void reboot_rcm()
{
sd_unmount();
display_end();
PMC(APBDEV_PMC_SCRATCH0) = 2; // Reboot into rcm.
PMC(APBDEV_PMC_CNTRL) |= PMC_CNTRL_MAIN_RST;
while (true)
usleep(1);
}
void power_off()
{
sd_unmount();
// 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);
}
#define CRC32C_POLY 0x82F63B78
u32 crc32c(const void *buf, u32 len)
{
@@ -69,31 +120,3 @@ u32 crc32c(const void *buf, u32 len)
}
return ~crc;
}
u32 memcmp32sparse(const u32 *buf1, const u32 *buf2, u32 len)
{
u32 len32 = len / 4;
if (!(len32 % 32))
{
while (len32)
{
len32 -= 32;
if(buf1[len32] != buf2[len32])
return 1;
}
}
else
{
while (len32)
{
len32 -= 32;
if(buf1[len32] != buf2[len32])
return 1;
if (len32 < 32)
return 0;
}
}
return 0;
}

View File

@@ -20,8 +20,8 @@
#include "types.h"
#define byte_swap_32(num) ((num >> 24) & 0xff) | ((num << 8) & 0xff0000) | \
((num >> 8 )& 0xff00) | ((num << 24) & 0xff000000)
#define byte_swap_32(num) (((num >> 24) & 0xff) | ((num << 8) & 0xff0000) | \
((num >> 8 )& 0xff00) | ((num << 24) & 0xff000000))
typedef struct _cfg_op_t
{
@@ -34,11 +34,11 @@ u32 get_tmr_ms();
u32 get_tmr_s();
void usleep(u32 ticks);
void msleep(u32 milliseconds);
void panic(u32 val);
void reboot_normal();
void reboot_rcm();
void power_off();
void exec_cfg(u32 *base, const cfg_op_t *ops, u32 num_ops);
u32 crc32c(const void *buf, u32 len);
/* This is a faster implementation of memcmp that checks two u32 values */
/* every 128 Bytes block. Intented only for Backup and Restore */
u32 memcmp32sparse(const u32 *buf1, const u32 *buf2, u32 len);
#endif