Compare commits
34 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3f7238cb10 | ||
|
|
1e8a6358ad | ||
|
|
c412d996fd | ||
|
|
f2086fe054 | ||
|
|
3f9d6574fb | ||
|
|
e996acff66 | ||
|
|
e274d3ef37 | ||
|
|
8663eb1a6e | ||
|
|
938da08e14 | ||
|
|
0468bd9483 | ||
|
|
c077c75b8d | ||
|
|
24f7977fa6 | ||
|
|
6699fda8c9 | ||
|
|
06e4158b93 | ||
|
|
b82d8aaba9 | ||
|
|
6829572556 | ||
|
|
11d8021435 | ||
|
|
493b074a9e | ||
|
|
befd912a88 | ||
|
|
c96ae0148e | ||
|
|
63a9c856fc | ||
|
|
31fde233e1 | ||
|
|
f9bf8923b1 | ||
|
|
ee40dcd76f | ||
|
|
c60ee15449 | ||
|
|
876d94c338 | ||
|
|
7c37b7497b | ||
|
|
dfcba5e6d4 | ||
|
|
a0cf3bbed8 | ||
|
|
1c503d59b5 | ||
|
|
0bf7df0426 | ||
|
|
2c46ec9638 | ||
|
|
ef0c8e0aac | ||
|
|
1a5801ee0f |
3
Makefile
3
Makefile
@@ -61,7 +61,8 @@ dist: all
|
||||
cp fusee/fusee-secondary/fusee-secondary.bin atmosphere-$(AMSVER)/sept/payload.bin
|
||||
cp sept/sept-primary/sept-primary.bin atmosphere-$(AMSVER)/sept/sept-primary.bin
|
||||
cp sept/sept-secondary/sept-secondary.bin atmosphere-$(AMSVER)/sept/sept-secondary.bin
|
||||
cp sept/sept-secondary/sept-secondary.enc atmosphere-$(AMSVER)/sept/sept-secondary.enc
|
||||
cp sept/sept-secondary/sept-secondary_00.enc atmosphere-$(AMSVER)/sept/sept-secondary_00.enc
|
||||
cp sept/sept-secondary/sept-secondary_01.enc atmosphere-$(AMSVER)/sept/sept-secondary_01.enc
|
||||
cp common/defaults/BCT.ini atmosphere-$(AMSVER)/atmosphere/BCT.ini
|
||||
cp common/defaults/loader.ini atmosphere-$(AMSVER)/atmosphere/loader.ini
|
||||
cp common/defaults/system_settings.ini atmosphere-$(AMSVER)/atmosphere/system_settings.ini
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -13,7 +13,7 @@
|
||||
* 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 ATMOSPHERE_TARGET_FIRMWARE_H
|
||||
#define ATMOSPHERE_TARGET_FIRMWARE_H
|
||||
|
||||
@@ -26,11 +26,12 @@
|
||||
#define ATMOSPHERE_TARGET_FIRMWARE_620 7
|
||||
#define ATMOSPHERE_TARGET_FIRMWARE_700 8
|
||||
#define ATMOSPHERE_TARGET_FIRMWARE_800 9
|
||||
#define ATMOSPHERE_TARGET_FIRMWARE_810 10
|
||||
|
||||
#define ATMOSPHERE_TARGET_FIRMWARE_CURRENT ATMOSPHERE_TARGET_FIRMWARE_800
|
||||
#define ATMOSPHERE_TARGET_FIRMWARE_CURRENT ATMOSPHERE_TARGET_FIRMWARE_810
|
||||
|
||||
#define ATMOSPHERE_TARGET_FIRMWARE_MIN ATMOSPHERE_TARGET_FIRMWARE_100
|
||||
#define ATMOSPHERE_TARGET_FIRMWARE_MAX ATMOSPHERE_TARGET_FIRMWARE_800
|
||||
#define ATMOSPHERE_TARGET_FIRMWARE_MAX ATMOSPHERE_TARGET_FIRMWARE_810
|
||||
|
||||
/* TODO: What should this be, for release? */
|
||||
#define ATMOSPHERE_TARGET_FIRMWARE_DEFAULT_FOR_DEBUG ATMOSPHERE_TARGET_FIRMWARE_CURRENT
|
||||
|
||||
@@ -13,16 +13,16 @@
|
||||
* 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 ATMOSPHERE_VERSION_H
|
||||
#define ATMOSPHERE_VERSION_H
|
||||
|
||||
#define ATMOSPHERE_RELEASE_VERSION_MAJOR 0
|
||||
#define ATMOSPHERE_RELEASE_VERSION_MINOR 9
|
||||
#define ATMOSPHERE_RELEASE_VERSION_MICRO 0
|
||||
#define ATMOSPHERE_RELEASE_VERSION_MICRO 1
|
||||
|
||||
#define ATMOSPHERE_SUPPORTED_HOS_VERSION_MAJOR 8
|
||||
#define ATMOSPHERE_SUPPORTED_HOS_VERSION_MINOR 0
|
||||
#define ATMOSPHERE_SUPPORTED_HOS_VERSION_MICRO 1
|
||||
#define ATMOSPHERE_SUPPORTED_HOS_VERSION_MINOR 1
|
||||
#define ATMOSPHERE_SUPPORTED_HOS_VERSION_MICRO 0
|
||||
|
||||
#endif
|
||||
@@ -1,4 +1,8 @@
|
||||
# Changelog
|
||||
## 0.9.1
|
||||
+ Support was added for 8.1.0.
|
||||
+ Please note, emummc is still considered **beta/experimental** -- this is not the inevitable bugfix update for it, although some number of bugs have been fixed. :)
|
||||
+ General system stability improvements to enhance the user's experience.
|
||||
## 0.9.0
|
||||
+ Creport output was improved significantly.
|
||||
+ Thread names are now dumped on crash in addition to 0x100 of TLS from each thread.
|
||||
@@ -133,7 +137,7 @@
|
||||
+ This should greatly simplify the update process in the future, for users who do not launch Atmosphère using fusee.
|
||||
+ Support for cheat codes was added.
|
||||
+ These are handled by a new `dmnt` sysmodule, which will also reimplement Nintendo's Debug Monitor in the future.
|
||||
+ Cheat codes can be enabled/disabled at application launch via a per-title key combination.
|
||||
+ Cheat codes can be enabled/disabled at application launch via a per-title key combination.
|
||||
+ For details, please see the [cheat loading documentation](https://github.com/Atmosphere-NX/Atmosphere/blob/master/docs/cheats.md#cheat-loating-process).
|
||||
+ Cheat codes are fully backwards compatible with the pre-existing format, although a number of bugs have been fixed and some new features have been added.
|
||||
+ For details, please see [the compatibility documentation](https://github.com/Atmosphere-NX/Atmosphere/blob/master/docs/cheats.md#cheat-code-compatibility).
|
||||
@@ -206,7 +210,7 @@
|
||||
+ This should prevent running FS without `nogc` patches after updating to an unsupported system version.
|
||||
+ An extension was added to `exosphere` allowing userland applications to cause the system to reboot into RCM:
|
||||
+ This is done by calling smcSetConfig(id=65001, value=<nonzero>); user homebrew can use splSetConfig for this.
|
||||
+ On fatal error, the user can now choose to perform a standard reboot via the power button, or a reboot into RCM via either volume button.
|
||||
+ On fatal error, the user can now choose to perform a standard reboot via the power button, or a reboot into RCM via either volume button.
|
||||
+ A custom message was added to `fatal` for when an Atmosphère API version mismatch is detected (2495-1623).
|
||||
+ General system stability improvements to enhance the user's experience.
|
||||
## 0.8.0
|
||||
@@ -249,7 +253,7 @@
|
||||
+ Instead of only checking one of the crashing thread's PC/LR for code region presence, creport now checks both + every address in the stacktrace. This is also now done for every thread.
|
||||
+ This matches the improvement Nintendo added to official creport in 6.1.0.
|
||||
+ The code region detection heuristic was further improved by checking whether an address points to .rodata or .rwdata, instead of just .text.
|
||||
+ This means that a crash appears in a loaded NRO (or otherwise discontiguous) code region, creport will be able to detect all active code regions, and not just that one.
|
||||
+ This means that a crash appears in a loaded NRO (or otherwise discontiguous) code region, creport will be able to detect all active code regions, and not just that one.
|
||||
## 0.7.4
|
||||
+ [libstratosphere](https://github.com/Atmosphere-NX/libstratosphere) has been completely refactored/rewritten, and split into its own, separate submodule.
|
||||
+ While this is mostly "under the hood" for end-users, the refactor is faster (improving both boot-time and runtime performance), more accurate (many of the internal IPC structures are now bug-for-bug compatible with Nintendo's implementations), and significantly more stable (it fixes a large number of bugs present in the old library).
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
[subrepo]
|
||||
remote = https://github.com/m4xw/emuMMC
|
||||
branch = develop
|
||||
commit = e72e8f1c8fb7ad8fe7cdedc3784729ea8e11f927
|
||||
parent = 87a1aa17a7693ef39ffea91ad0fa1b530f278bb0
|
||||
commit = e7799388e8d3de17fd178ffe310be2e81ef46d6f
|
||||
parent = f2086fe05492cb523b60fa10e4425c4ea59521b3
|
||||
method = rebase
|
||||
cmdver = 0.4.0
|
||||
|
||||
@@ -17,7 +17,7 @@ else
|
||||
EMUMMCDIR ?= $(CURDIR)/../
|
||||
endif
|
||||
|
||||
include $(EMUMMCDIR)/nx/switch_rules
|
||||
include $(DEVKITPRO)/libnx/switch_rules
|
||||
|
||||
ARCH := -march=armv8-a -mtune=cortex-a57 -mtp=soft -fPIE
|
||||
|
||||
@@ -31,7 +31,7 @@ CFLAGS += $(INCLUDE) -D__SWITCH__
|
||||
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++17
|
||||
|
||||
ASFLAGS := -g $(ARCH)
|
||||
LDFLAGS = -specs=$(EMUMMCDIR)/nx/switch.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map)
|
||||
LDFLAGS = -specs=$(DEVKITPRO)/libnx/switch.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map)
|
||||
|
||||
ifneq ($(BUILD),$(notdir $(CURDIR)))
|
||||
|
||||
|
||||
@@ -1,229 +0,0 @@
|
||||
OUTPUT_ARCH(aarch64)
|
||||
ENTRY(_start)
|
||||
|
||||
PHDRS
|
||||
{
|
||||
code PT_LOAD FLAGS(5) /* Read | Execute */;
|
||||
rodata PT_LOAD FLAGS(4) /* Read */;
|
||||
data PT_LOAD FLAGS(6) /* Read | Write */;
|
||||
dyn PT_DYNAMIC;
|
||||
}
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
/* =========== CODE section =========== */
|
||||
PROVIDE(__start__ = 0x0);
|
||||
. = __start__;
|
||||
__code_start = . ;
|
||||
|
||||
/*.trampoline :
|
||||
{
|
||||
KEEP (*(.trampoline))
|
||||
. = ALIGN(8);
|
||||
} :code
|
||||
|
||||
.emuMMC_ctx :
|
||||
{
|
||||
KEEP (*(.emuMMC_ctx))
|
||||
. = ALIGN(8);
|
||||
} :code */
|
||||
|
||||
.crt0 :
|
||||
{
|
||||
KEEP (*(.crt0))
|
||||
. = ALIGN(8);
|
||||
} :code
|
||||
|
||||
.init :
|
||||
{
|
||||
KEEP( *(.init) )
|
||||
. = ALIGN(8);
|
||||
} :code
|
||||
|
||||
.plt :
|
||||
{
|
||||
*(.plt)
|
||||
*(.iplt)
|
||||
. = ALIGN(8);
|
||||
} :code
|
||||
|
||||
.text :
|
||||
{
|
||||
*(.text.unlikely .text.*_unlikely .text.unlikely.*)
|
||||
*(.text.exit .text.exit.*)
|
||||
*(.text.startup .text.startup.*)
|
||||
*(.text.hot .text.hot.*)
|
||||
*(.text .stub .text.* .gnu.linkonce.t.*)
|
||||
. = ALIGN(8);
|
||||
} :code
|
||||
|
||||
.fini :
|
||||
{
|
||||
KEEP( *(.fini) )
|
||||
. = ALIGN(8);
|
||||
} :code
|
||||
|
||||
/* =========== RODATA section =========== */
|
||||
. = ALIGN(0x1000);
|
||||
__rodata_start = . ;
|
||||
|
||||
.nx-module-name : { KEEP (*(.nx-module-name)) } :rodata
|
||||
|
||||
.rodata :
|
||||
{
|
||||
*(.rodata .rodata.* .gnu.linkonce.r.*)
|
||||
. = ALIGN(8);
|
||||
} :rodata
|
||||
|
||||
.eh_frame_hdr : { __eh_frame_hdr_start = .; *(.eh_frame_hdr) *(.eh_frame_entry .eh_frame_entry.*) __eh_frame_hdr_end = .; } :rodata
|
||||
.eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) *(.eh_frame.*) } :rodata
|
||||
.gcc_except_table : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) } :rodata
|
||||
.gnu_extab : ONLY_IF_RO { *(.gnu_extab*) } : rodata
|
||||
|
||||
.dynamic : { *(.dynamic) } :rodata :dyn
|
||||
.dynsym : { *(.dynsym) } :rodata
|
||||
.dynstr : { *(.dynstr) } :rodata
|
||||
.rela.dyn : { *(.rela.*) } :rodata
|
||||
.interp : { *(.interp) } :rodata
|
||||
.hash : { *(.hash) } :rodata
|
||||
.gnu.hash : { *(.gnu.hash) } :rodata
|
||||
.gnu.version : { *(.gnu.version) } :rodata
|
||||
.gnu.version_d : { *(.gnu.version_d) } :rodata
|
||||
.gnu.version_r : { *(.gnu.version_r) } :rodata
|
||||
.note.gnu.build-id : { *(.note.gnu.build-id) } :rodata
|
||||
|
||||
/* =========== DATA section =========== */
|
||||
. = ALIGN(0x1000);
|
||||
__data_start = . ;
|
||||
|
||||
.eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) *(.eh_frame.*) } :data
|
||||
.gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) } :data
|
||||
.gnu_extab : ONLY_IF_RW { *(.gnu_extab*) } : data
|
||||
.exception_ranges : ONLY_IF_RW { *(.exception_ranges .exception_ranges*) } :data
|
||||
|
||||
.tdata ALIGN(8) :
|
||||
{
|
||||
__tdata_lma = .;
|
||||
*(.tdata .tdata.* .gnu.linkonce.td.*)
|
||||
. = ALIGN(8);
|
||||
__tdata_lma_end = .;
|
||||
} :data
|
||||
|
||||
.tbss ALIGN(8) :
|
||||
{
|
||||
*(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon)
|
||||
. = ALIGN(8);
|
||||
} :data
|
||||
|
||||
.preinit_array ALIGN(8) :
|
||||
{
|
||||
PROVIDE (__preinit_array_start = .);
|
||||
KEEP (*(.preinit_array))
|
||||
PROVIDE (__preinit_array_end = .);
|
||||
} :data
|
||||
|
||||
.init_array ALIGN(8) :
|
||||
{
|
||||
PROVIDE (__init_array_start = .);
|
||||
KEEP (*(SORT(.init_array.*)))
|
||||
KEEP (*(.init_array))
|
||||
PROVIDE (__init_array_end = .);
|
||||
} :data
|
||||
|
||||
.fini_array ALIGN(8) :
|
||||
{
|
||||
PROVIDE (__fini_array_start = .);
|
||||
KEEP (*(.fini_array))
|
||||
KEEP (*(SORT(.fini_array.*)))
|
||||
PROVIDE (__fini_array_end = .);
|
||||
} :data
|
||||
|
||||
.ctors ALIGN(8) :
|
||||
{
|
||||
KEEP (*crtbegin.o(.ctors)) /* MUST be first -- GCC requires it */
|
||||
KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors))
|
||||
KEEP (*(SORT(.ctors.*)))
|
||||
KEEP (*(.ctors))
|
||||
} :data
|
||||
|
||||
.dtors ALIGN(8) :
|
||||
{
|
||||
KEEP (*crtbegin.o(.dtors))
|
||||
KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors))
|
||||
KEEP (*(SORT(.dtors.*)))
|
||||
KEEP (*(.dtors))
|
||||
} :data
|
||||
|
||||
__got_start__ = .;
|
||||
|
||||
.got : { *(.got) *(.igot) } :data
|
||||
.got.plt : { *(.got.plt) *(.igot.plt) } :data
|
||||
|
||||
__got_end__ = .;
|
||||
|
||||
.data ALIGN(8) :
|
||||
{
|
||||
*(.data .data.* .gnu.linkonce.d.*)
|
||||
SORT(CONSTRUCTORS)
|
||||
} :data
|
||||
|
||||
__bss_start__ = .;
|
||||
.bss ALIGN(8) :
|
||||
{
|
||||
*(.dynbss)
|
||||
*(.bss .bss.* .gnu.linkonce.b.*)
|
||||
*(COMMON)
|
||||
. = ALIGN(8);
|
||||
|
||||
/* Reserve space for the TLS segment of the main thread */
|
||||
__tls_start = .;
|
||||
. += + SIZEOF(.tdata) + SIZEOF(.tbss);
|
||||
__tls_end = .;
|
||||
} : data
|
||||
__bss_end__ = .;
|
||||
|
||||
. = ALIGN(0x1000);
|
||||
__end__ = ABSOLUTE(.) ;
|
||||
|
||||
PROVIDE(__injected_size__ = (__end__ - __start__));
|
||||
|
||||
/* ==================
|
||||
==== Metadata ====
|
||||
================== */
|
||||
|
||||
/* Discard sections that difficult post-processing */
|
||||
/DISCARD/ : { *(.group .comment .note) }
|
||||
|
||||
/* Stabs debugging sections. */
|
||||
.stab 0 : { *(.stab) }
|
||||
.stabstr 0 : { *(.stabstr) }
|
||||
.stab.excl 0 : { *(.stab.excl) }
|
||||
.stab.exclstr 0 : { *(.stab.exclstr) }
|
||||
.stab.index 0 : { *(.stab.index) }
|
||||
.stab.indexstr 0 : { *(.stab.indexstr) }
|
||||
|
||||
/* DWARF debug sections.
|
||||
Symbols in the DWARF debugging sections are relative to the beginning
|
||||
of the section so we begin them at 0. */
|
||||
|
||||
/* DWARF 1 */
|
||||
.debug 0 : { *(.debug) }
|
||||
.line 0 : { *(.line) }
|
||||
|
||||
/* GNU DWARF 1 extensions */
|
||||
.debug_srcinfo 0 : { *(.debug_srcinfo) }
|
||||
.debug_sfnames 0 : { *(.debug_sfnames) }
|
||||
|
||||
/* DWARF 1.1 and DWARF 2 */
|
||||
.debug_aranges 0 : { *(.debug_aranges) }
|
||||
.debug_pubnames 0 : { *(.debug_pubnames) }
|
||||
|
||||
/* DWARF 2 */
|
||||
.debug_info 0 : { *(.debug_info) }
|
||||
.debug_abbrev 0 : { *(.debug_abbrev) }
|
||||
.debug_line 0 : { *(.debug_line) }
|
||||
.debug_frame 0 : { *(.debug_frame) }
|
||||
.debug_str 0 : { *(.debug_str) }
|
||||
.debug_loc 0 : { *(.debug_loc) }
|
||||
.debug_macinfo 0 : { *(.debug_macinfo) }
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
%rename link old_link
|
||||
|
||||
*link:
|
||||
%(old_link) -T %:getenv(PWD /nx/switch.ld) -pie --gc-sections -z text -z nodynamic-undefined-weak --build-id=sha1 --nx-module-name
|
||||
|
||||
*startfile:
|
||||
crti%O%s crtbegin%O%s
|
||||
|
||||
@@ -1,81 +0,0 @@
|
||||
ifeq ($(strip $(DEVKITPRO)),)
|
||||
$(error "Please set DEVKITPRO in your environment. export DEVKITPRO=<path to>devkitPro)
|
||||
endif
|
||||
|
||||
include $(DEVKITPRO)/devkitA64/base_rules
|
||||
|
||||
PORTLIBS := $(PORTLIBS_PATH)/switch
|
||||
PATH := $(PORTLIBS)/bin:$(PATH)
|
||||
|
||||
LIBNX ?= $(DEVKITPRO)/libnx
|
||||
|
||||
ifeq ($(strip $(APP_TITLE)),)
|
||||
APP_TITLE := $(notdir $(OUTPUT))
|
||||
endif
|
||||
|
||||
ifeq ($(strip $(APP_AUTHOR)),)
|
||||
APP_AUTHOR := Unspecified Author
|
||||
endif
|
||||
|
||||
ifeq ($(strip $(APP_VERSION)),)
|
||||
APP_VERSION := 1.0.0
|
||||
endif
|
||||
|
||||
ifeq ($(strip $(APP_ICON)),)
|
||||
APP_ICON := $(LIBNX)/default_icon.jpg
|
||||
endif
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
%.nacp: $(MAKEFILE_LIST)
|
||||
@nacptool --create "$(APP_TITLE)" "$(APP_AUTHOR)" "$(APP_VERSION)" $@ $(NACPFLAGS)
|
||||
@echo built ... $(notdir $@)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
%.npdm: $(APP_JSON)
|
||||
@npdmtool $< $@
|
||||
@echo built ... $(notdir $@)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
define make_pfs0
|
||||
@mkdir -p exefs
|
||||
@[ $(BUILD_EXEFS_SRC) ] && [ -d $(BUILD_EXEFS_SRC) ] && cp -R $(BUILD_EXEFS_SRC)/* exefs || echo > /dev/null
|
||||
@cp $*.nso exefs/main
|
||||
@[ $(APP_JSON) ] && cp $*.npdm exefs/main.npdm || echo > /dev/null
|
||||
@build_pfs0 exefs $@
|
||||
@echo built ... $(notdir $@)
|
||||
endef
|
||||
|
||||
ifeq ($(strip $(APP_JSON)),)
|
||||
%.pfs0: %.nso
|
||||
else
|
||||
%.pfs0: %.nso %.npdm
|
||||
endif
|
||||
$(make_pfs0)
|
||||
|
||||
ifeq ($(strip $(APP_JSON)),)
|
||||
%.nsp: %.nso
|
||||
else
|
||||
%.nsp: %.nso %.npdm
|
||||
endif
|
||||
$(make_pfs0)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
%.nso: %.elf
|
||||
@elf2nso $< $@
|
||||
@echo built ... $(notdir $@)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
%.nro: %.elf
|
||||
@elf2nro $< $@ $(NROFLAGS)
|
||||
@echo built ... $(notdir $@)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
%.kip: %.elf
|
||||
@elf2kip $< $(APP_JSON) $@
|
||||
@echo built ... $(notdir $@)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
%.elf:
|
||||
@echo linking $(notdir $@)
|
||||
@$(LD) $(LDFLAGS) $(OFILES) $(LIBPATHS) $(LIBS) -o $@
|
||||
@$(NM) -CSn $@ > $(notdir $*.lst)
|
||||
@@ -39,6 +39,8 @@
|
||||
#include "offsets/700_exfat.h"
|
||||
#include "offsets/800.h"
|
||||
#include "offsets/800_exfat.h"
|
||||
#include "offsets/810.h"
|
||||
#include "offsets/810_exfat.h"
|
||||
#include "../utils/fatal.h"
|
||||
|
||||
#define GET_OFFSET_STRUCT_NAME(vers) g_offsets##vers
|
||||
@@ -88,6 +90,8 @@ DEFINE_OFFSET_STRUCT(_700);
|
||||
DEFINE_OFFSET_STRUCT(_700_EXFAT);
|
||||
DEFINE_OFFSET_STRUCT(_800);
|
||||
DEFINE_OFFSET_STRUCT(_800_EXFAT);
|
||||
DEFINE_OFFSET_STRUCT(_810);
|
||||
DEFINE_OFFSET_STRUCT(_810_EXFAT);
|
||||
|
||||
const fs_offsets_t *get_fs_offsets(enum FS_VER version) {
|
||||
switch (version) {
|
||||
@@ -137,6 +141,10 @@ const fs_offsets_t *get_fs_offsets(enum FS_VER version) {
|
||||
return &(GET_OFFSET_STRUCT_NAME(_800));
|
||||
case FS_VER_8_0_0_EXFAT:
|
||||
return &(GET_OFFSET_STRUCT_NAME(_800_EXFAT));
|
||||
case FS_VER_8_1_0:
|
||||
return &(GET_OFFSET_STRUCT_NAME(_810));
|
||||
case FS_VER_8_1_0_EXFAT:
|
||||
return &(GET_OFFSET_STRUCT_NAME(_810_EXFAT));
|
||||
default:
|
||||
fatal_abort(Fatal_UnknownVersion);
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
typedef struct {
|
||||
int opcode_reg;
|
||||
uint32_t adrp_offset;
|
||||
uint32_t add_rel_offset;
|
||||
} fs_offsets_nintendo_path_t;
|
||||
|
||||
typedef struct {
|
||||
|
||||
@@ -20,7 +20,8 @@
|
||||
|
||||
#include "../utils/types.h"
|
||||
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
char *device_addr_buffer;
|
||||
uint64_t device_addr_buffer_size;
|
||||
char *device_addr_buffer_masked;
|
||||
@@ -28,7 +29,8 @@ typedef struct {
|
||||
|
||||
_Static_assert(__alignof(sdmmc_dma_buffer_t) == 8, "sdmmc_dma_buffer_t definition");
|
||||
|
||||
typedef struct sdmmc_accessor_vt {
|
||||
typedef struct sdmmc_accessor_vt
|
||||
{
|
||||
void *ctor;
|
||||
void *dtor;
|
||||
void *map_device_addr_space;
|
||||
@@ -39,14 +41,18 @@ typedef struct sdmmc_accessor_vt {
|
||||
// More not included because we don't use it.
|
||||
} sdmmc_accessor_vt_t;
|
||||
|
||||
typedef struct {
|
||||
_Static_assert(__alignof(sdmmc_accessor_vt_t) == 8, "sdmmc_accessor_vt_t definition");
|
||||
|
||||
typedef struct
|
||||
{
|
||||
void *vtab;
|
||||
t210_sdmmc_t *io_map;
|
||||
sdmmc_dma_buffer_t dmaBuffers[3];
|
||||
// More not included because we don't use it.
|
||||
} mmc_obj_t;
|
||||
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
sdmmc_accessor_vt_t *vtab;
|
||||
mmc_obj_t *parent;
|
||||
// More not included because we don't use it.
|
||||
|
||||
@@ -56,6 +56,9 @@ enum FS_VER
|
||||
FS_VER_8_0_0,
|
||||
FS_VER_8_0_0_EXFAT,
|
||||
|
||||
FS_VER_8_1_0,
|
||||
FS_VER_8_1_0_EXFAT,
|
||||
|
||||
FS_VER_MAX,
|
||||
};
|
||||
|
||||
|
||||
@@ -47,11 +47,11 @@
|
||||
// Nintendo Paths
|
||||
#define FS_OFFSET_100_NINTENDO_PATHS \
|
||||
{ \
|
||||
{.opcode_reg = 9, .adrp_offset = 0x00032C58}, \
|
||||
{.opcode_reg = 8, .adrp_offset = 0x00032C60}, \
|
||||
{.opcode_reg = 9, .adrp_offset = 0x00032F3C}, \
|
||||
{.opcode_reg = 8, .adrp_offset = 0x00032F44}, \
|
||||
{.opcode_reg = 0, .adrp_offset = 0}, \
|
||||
{.opcode_reg = 9, .adrp_offset = 0x00032C58, .add_rel_offset = 4}, \
|
||||
{.opcode_reg = 8, .adrp_offset = 0x00032C60, .add_rel_offset = 4}, \
|
||||
{.opcode_reg = 9, .adrp_offset = 0x00032F3C, .add_rel_offset = 4}, \
|
||||
{.opcode_reg = 8, .adrp_offset = 0x00032F44, .add_rel_offset = 4}, \
|
||||
{.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \
|
||||
}
|
||||
|
||||
#endif // __FS_100_H__
|
||||
|
||||
@@ -47,10 +47,10 @@
|
||||
// Nintendo Paths
|
||||
#define FS_OFFSET_200_NINTENDO_PATHS \
|
||||
{ \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x00033F08}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x00035084}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x0003537C}, \
|
||||
{.opcode_reg = 0, .adrp_offset = 0}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x00033F08, .add_rel_offset = 0x00000004}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x00035084, .add_rel_offset = 0x0000000C}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x0003537C, .add_rel_offset = 0x0000000C}, \
|
||||
{.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \
|
||||
}
|
||||
|
||||
#endif // __FS_200_H__
|
||||
|
||||
@@ -47,10 +47,10 @@
|
||||
// Nintendo Paths
|
||||
#define FS_OFFSET_200_EXFAT_NINTENDO_PATHS \
|
||||
{ \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x00033F08}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x00035084}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x0003537C}, \
|
||||
{.opcode_reg = 0, .adrp_offset = 0}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x00033F08, .add_rel_offset = 0x00000004}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x00035084, .add_rel_offset = 0x0000000C}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x0003537C, .add_rel_offset = 0x0000000C}, \
|
||||
{.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \
|
||||
}
|
||||
|
||||
#endif // __FS_200_EXFAT_H__
|
||||
|
||||
@@ -47,10 +47,10 @@
|
||||
// Nintendo Paths
|
||||
#define FS_OFFSET_210_NINTENDO_PATHS \
|
||||
{ \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x000342E0}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x0003545C}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x00035754}, \
|
||||
{.opcode_reg = 0, .adrp_offset = 0}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x000342E0, .add_rel_offset = 0x00000004}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x0003545C, .add_rel_offset = 0x0000000C}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x00035754, .add_rel_offset = 0x0000000C}, \
|
||||
{.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \
|
||||
}
|
||||
|
||||
#endif // __FS_210_H__
|
||||
|
||||
@@ -47,10 +47,10 @@
|
||||
// Nintendo Paths
|
||||
#define FS_OFFSET_210_EXFAT_NINTENDO_PATHS \
|
||||
{ \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x000342E0}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x0003545C}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x00035754}, \
|
||||
{.opcode_reg = 0, .adrp_offset = 0}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x000342E0, .add_rel_offset = 0x00000004}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x0003545C, .add_rel_offset = 0x0000000C}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x00035754, .add_rel_offset = 0x0000000C}, \
|
||||
{.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \
|
||||
}
|
||||
|
||||
#endif // __FS_210_EXFAT_H__
|
||||
|
||||
@@ -47,10 +47,10 @@
|
||||
// Nintendo Paths
|
||||
#define FS_OFFSET_300_NINTENDO_PATHS \
|
||||
{ \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x000391F4}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x0003A480}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x0003A778}, \
|
||||
{.opcode_reg = 0, .adrp_offset = 0}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x000391F4, .add_rel_offset = 0x00000004}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x0003A480, .add_rel_offset = 0x0000000C}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x0003A778, .add_rel_offset = 0x0000000C}, \
|
||||
{.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \
|
||||
}
|
||||
|
||||
#endif // __FS_300_H__
|
||||
|
||||
@@ -47,10 +47,10 @@
|
||||
// Nintendo Paths
|
||||
#define FS_OFFSET_300_EXFAT_NINTENDO_PATHS \
|
||||
{ \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x000391F4}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x0003A480}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x0003A778}, \
|
||||
{.opcode_reg = 0, .adrp_offset = 0}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x000391F4, .add_rel_offset = 0x00000004}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x0003A480, .add_rel_offset = 0x0000000C}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x0003A778, .add_rel_offset = 0x0000000C}, \
|
||||
{.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \
|
||||
}
|
||||
|
||||
#endif // __FS_300_EXFAT_H__
|
||||
|
||||
@@ -47,10 +47,10 @@
|
||||
// Nintendo Paths
|
||||
#define FS_OFFSET_301_NINTENDO_PATHS \
|
||||
{ \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x00039260}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x0003A4EC}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x0003A7E4}, \
|
||||
{.opcode_reg = 0, .adrp_offset = 0}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x00039260, .add_rel_offset = 0x00000004}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x0003A4EC, .add_rel_offset = 0x0000000C}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x0003A7E4, .add_rel_offset = 0x0000000C}, \
|
||||
{.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \
|
||||
}
|
||||
|
||||
#endif // __FS_301_H__
|
||||
|
||||
@@ -47,10 +47,10 @@
|
||||
// Nintendo Paths
|
||||
#define FS_OFFSET_301_EXFAT_NINTENDO_PATHS \
|
||||
{ \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x00039260}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x0003A4EC}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x0003A7E4}, \
|
||||
{.opcode_reg = 0, .adrp_offset = 0}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x00039260, .add_rel_offset = 0x00000004}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x0003A4EC, .add_rel_offset = 0x0000000C}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x0003A7E4, .add_rel_offset = 0x0000000C}, \
|
||||
{.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \
|
||||
}
|
||||
|
||||
#endif // __FS_301_EXFAT_H__
|
||||
|
||||
@@ -47,10 +47,10 @@
|
||||
// Nintendo Paths
|
||||
#define FS_OFFSET_400_NINTENDO_PATHS \
|
||||
{ \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x0002023C}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x00021BE8}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x00021EC4}, \
|
||||
{.opcode_reg = 0, .adrp_offset = 0}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x0002023C, .add_rel_offset = 0x00000004}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x00021BE8, .add_rel_offset = 0x0000000C}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x00021EC4, .add_rel_offset = 0x0000000C}, \
|
||||
{.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \
|
||||
}
|
||||
|
||||
#endif // __FS_400_H__
|
||||
|
||||
@@ -47,10 +47,10 @@
|
||||
// Nintendo Paths
|
||||
#define FS_OFFSET_400_EXFAT_NINTENDO_PATHS \
|
||||
{ \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x0002023C}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x00021BE8}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x00021EC4}, \
|
||||
{.opcode_reg = 0, .adrp_offset = 0}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x0002023C, .add_rel_offset = 0x00000004}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x00021BE8, .add_rel_offset = 0x0000000C}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x00021EC4, .add_rel_offset = 0x0000000C}, \
|
||||
{.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \
|
||||
}
|
||||
|
||||
#endif // __FS_400_EXFAT_H__
|
||||
|
||||
@@ -47,10 +47,10 @@
|
||||
// Nintendo Paths
|
||||
#define FS_OFFSET_410_NINTENDO_PATHS \
|
||||
{ \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x0002023C}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x00021BE8}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x00021EC4}, \
|
||||
{.opcode_reg = 0, .adrp_offset = 0}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x0002023C, .add_rel_offset = 0x00000004}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x00021BE8, .add_rel_offset = 0x0000000C}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x00021EC4, .add_rel_offset = 0x0000000C}, \
|
||||
{.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \
|
||||
}
|
||||
|
||||
#endif // __FS_410_H__
|
||||
|
||||
@@ -47,10 +47,10 @@
|
||||
// Nintendo Paths
|
||||
#define FS_OFFSET_410_EXFAT_NINTENDO_PATHS \
|
||||
{ \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x0002023C}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x00021BE8}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x00021EC4}, \
|
||||
{.opcode_reg = 0, .adrp_offset = 0}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x0002023C, .add_rel_offset = 4}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x00021BE8, .add_rel_offset = 12}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x00021EC4, .add_rel_offset = 12}, \
|
||||
{.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \
|
||||
}
|
||||
|
||||
#endif // __FS_410_EXFAT_H__
|
||||
|
||||
@@ -47,10 +47,10 @@
|
||||
// Nintendo Paths
|
||||
#define FS_OFFSET_500_NINTENDO_PATHS \
|
||||
{ \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x00028980}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x0002ACE4}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x0002B220}, \
|
||||
{.opcode_reg = 0, .adrp_offset = 0}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x00028980, .add_rel_offset = 4}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x0002ACE4, .add_rel_offset = 4}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x0002B220, .add_rel_offset = 4}, \
|
||||
{.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \
|
||||
}
|
||||
|
||||
#endif // __FS_500_H__
|
||||
|
||||
@@ -47,10 +47,10 @@
|
||||
// Nintendo Paths
|
||||
#define FS_OFFSET_500_EXFAT_NINTENDO_PATHS \
|
||||
{ \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x00028980}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x0002ACE4}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x0002B220}, \
|
||||
{.opcode_reg = 0, .adrp_offset = 0}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x00028980, .add_rel_offset = 4}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x0002ACE4, .add_rel_offset = 4}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x0002B220, .add_rel_offset = 4}, \
|
||||
{.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \
|
||||
}
|
||||
|
||||
#endif // __FS_500_EXFAT_H__
|
||||
|
||||
@@ -47,10 +47,10 @@
|
||||
// Nintendo Paths
|
||||
#define FS_OFFSET_510_NINTENDO_PATHS \
|
||||
{ \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x000289B0}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x0002AD14}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x0002B250}, \
|
||||
{.opcode_reg = 0, .adrp_offset = 0}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x000289B0, .add_rel_offset = 4}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x0002AD14, .add_rel_offset = 4}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x0002B250, .add_rel_offset = 4}, \
|
||||
{.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \
|
||||
}
|
||||
|
||||
#endif // __FS_510_H__
|
||||
|
||||
@@ -47,10 +47,10 @@
|
||||
// Nintendo Paths
|
||||
#define FS_OFFSET_510_EXFAT_NINTENDO_PATHS \
|
||||
{ \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x000289B0}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x0002AD14}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x0002B250}, \
|
||||
{.opcode_reg = 0, .adrp_offset = 0}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x000289B0, .add_rel_offset = 4}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x0002AD14, .add_rel_offset = 4}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x0002B250, .add_rel_offset = 4}, \
|
||||
{.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \
|
||||
}
|
||||
|
||||
#endif // __FS_510_EXFAT_H__
|
||||
|
||||
@@ -47,11 +47,11 @@
|
||||
// Nintendo Paths
|
||||
#define FS_OFFSET_600_NINTENDO_PATHS \
|
||||
{ \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x000790DC}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x0007A924}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x0007AB18}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x0007AEF4}, \
|
||||
{.opcode_reg = 0, .adrp_offset = 0} \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x000790DC, .add_rel_offset = 4}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x0007A924, .add_rel_offset = 4}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x0007AB18, .add_rel_offset = 4}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x0007AEF4, .add_rel_offset = 4}, \
|
||||
{.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0} \
|
||||
}
|
||||
|
||||
#endif // __FS_600_H__
|
||||
|
||||
@@ -47,11 +47,11 @@
|
||||
// Nintendo Paths
|
||||
#define FS_OFFSET_600_EXFAT_NINTENDO_PATHS \
|
||||
{ \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x000847DC}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x00086024}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x00086218}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x000865F4}, \
|
||||
{.opcode_reg = 0, .adrp_offset = 0} \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x000847DC, .add_rel_offset = 4}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x00086024, .add_rel_offset = 4}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x00086218, .add_rel_offset = 4}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x000865F4, .add_rel_offset = 4}, \
|
||||
{.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0} \
|
||||
}
|
||||
|
||||
#endif // __FS_600_EXFAT_H__
|
||||
|
||||
@@ -47,12 +47,12 @@
|
||||
// Nintendo Paths
|
||||
#define FS_OFFSET_700_NINTENDO_PATHS \
|
||||
{ \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x0007DA90}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x0007F344}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x0007F538}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x0007F914}, \
|
||||
{.opcode_reg = 4, .adrp_offset = 0x0007FAD8}, \
|
||||
{.opcode_reg = 0, .adrp_offset = 0}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x0007DA90, .add_rel_offset = 4}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x0007F344, .add_rel_offset = 4}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x0007F538, .add_rel_offset = 4}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x0007F914, .add_rel_offset = 4}, \
|
||||
{.opcode_reg = 4, .adrp_offset = 0x0007FAD8, .add_rel_offset = 4}, \
|
||||
{.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \
|
||||
}
|
||||
|
||||
#endif // __FS_700_H__
|
||||
|
||||
@@ -47,12 +47,12 @@
|
||||
// Nintendo Paths
|
||||
#define FS_OFFSET_700_EXFAT_NINTENDO_PATHS \
|
||||
{ \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x00089040}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x0008A8F4}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x0008AAE8}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x0008AEC4}, \
|
||||
{.opcode_reg = 4, .adrp_offset = 0x0008B088}, \
|
||||
{.opcode_reg = 0, .adrp_offset = 0}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x00089040, .add_rel_offset = 4}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x0008A8F4, .add_rel_offset = 4}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x0008AAE8, .add_rel_offset = 4}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x0008AEC4, .add_rel_offset = 4}, \
|
||||
{.opcode_reg = 4, .adrp_offset = 0x0008B088, .add_rel_offset = 4}, \
|
||||
{.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \
|
||||
}
|
||||
|
||||
#endif // __FS_700_EXFAT_H__
|
||||
|
||||
@@ -47,12 +47,12 @@
|
||||
// Nintendo Paths
|
||||
#define FS_OFFSET_800_NINTENDO_PATHS \
|
||||
{ \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x0007F5F0}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x00081084}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x00081278}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x00081654}, \
|
||||
{.opcode_reg = 4, .adrp_offset = 0x00081818}, \
|
||||
{.opcode_reg = 0, .adrp_offset = 0} \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x0007F5F0, .add_rel_offset = 4}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x00081084, .add_rel_offset = 4}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x00081278, .add_rel_offset = 4}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x00081654, .add_rel_offset = 4}, \
|
||||
{.opcode_reg = 4, .adrp_offset = 0x00081818, .add_rel_offset = 4}, \
|
||||
{.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0} \
|
||||
}
|
||||
|
||||
#endif // __FS_800_H__
|
||||
|
||||
@@ -47,12 +47,12 @@
|
||||
// Nintendo Paths
|
||||
#define FS_OFFSET_800_EXFAT_NINTENDO_PATHS \
|
||||
{ \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x0008ABA0}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x0008C634}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x0008C828}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x0008CC04}, \
|
||||
{.opcode_reg = 4, .adrp_offset = 0x0008CDC8}, \
|
||||
{.opcode_reg = 0, .adrp_offset = 0} \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x0008ABA0, .add_rel_offset = 4}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x0008C634, .add_rel_offset = 4}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x0008C828, .add_rel_offset = 4}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x0008CC04, .add_rel_offset = 4}, \
|
||||
{.opcode_reg = 4, .adrp_offset = 0x0008CDC8, .add_rel_offset = 4}, \
|
||||
{.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0} \
|
||||
}
|
||||
|
||||
#endif // __FS_800_EXFAT_H__
|
||||
|
||||
58
emummc/source/FS/offsets/810.h
Normal file
58
emummc/source/FS/offsets/810.h
Normal file
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (c) 2019 m4xw <m4x@m4xw.net>
|
||||
* Copyright (c) 2019 Atmosphere-NX
|
||||
*
|
||||
* 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 __FS_810_H__
|
||||
#define __FS_810_H__
|
||||
|
||||
// Accessor vtable getters
|
||||
#define FS_OFFSET_810_SDMMC_ACCESSOR_GC 0x15EA20
|
||||
#define FS_OFFSET_810_SDMMC_ACCESSOR_SD 0x15E790
|
||||
#define FS_OFFSET_810_SDMMC_ACCESSOR_NAND 0x15AC80
|
||||
|
||||
// Hooks
|
||||
#define FS_OFFSET_810_SDMMC_WRAPPER_READ 0x152A80
|
||||
#define FS_OFFSET_810_SDMMC_WRAPPER_WRITE 0x152B60
|
||||
#define FS_OFFSET_810_RTLD 0x5B4
|
||||
#define FS_OFFSET_810_RTLD_DESTINATION 0x9C
|
||||
|
||||
#define FS_OFFSET_810_CLKRST_SET_MIN_V_CLK_RATE 0x16F370
|
||||
|
||||
// Misc funcs
|
||||
#define FS_OFFSET_810_LOCK_MUTEX 0x14B6D0
|
||||
#define FS_OFFSET_810_UNLOCK_MUTEX 0x14B720
|
||||
|
||||
// Misc Data
|
||||
#define FS_OFFSET_810_SD_MUTEX 0xF1A3E8
|
||||
#define FS_OFFSET_810_NAND_MUTEX 0xF15BE8
|
||||
#define FS_OFFSET_810_ACTIVE_PARTITION 0xF15C28
|
||||
#define FS_OFFSET_810_SDMMC_DAS_HANDLE 0xE167C0
|
||||
|
||||
// NOPs
|
||||
#define FS_OFFSET_810_SHUTDOWN_SD 0xBAF6C
|
||||
#define FS_OFFSET_810_SD_DAS_INIT 0x87D58
|
||||
|
||||
// Nintendo Paths
|
||||
#define FS_OFFSET_810_NINTENDO_PATHS \
|
||||
{ \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x0007F5F0, .add_rel_offset = 4}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x00081084, .add_rel_offset = 4}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x00081278, .add_rel_offset = 4}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x00081654, .add_rel_offset = 4}, \
|
||||
{.opcode_reg = 4, .adrp_offset = 0x00081818, .add_rel_offset = 4}, \
|
||||
{.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0} \
|
||||
}
|
||||
|
||||
#endif // __FS_810_H__
|
||||
58
emummc/source/FS/offsets/810_exfat.h
Normal file
58
emummc/source/FS/offsets/810_exfat.h
Normal file
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (c) 2019 m4xw <m4x@m4xw.net>
|
||||
* Copyright (c) 2019 Atmosphere-NX
|
||||
*
|
||||
* 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 __FS_810_EXFAT_H__
|
||||
#define __FS_810_EXFAT_H__
|
||||
|
||||
// Accessor vtable getters
|
||||
#define FS_OFFSET_810_EXFAT_SDMMC_ACCESSOR_GC 0x169FD0
|
||||
#define FS_OFFSET_810_EXFAT_SDMMC_ACCESSOR_SD 0x169D40
|
||||
#define FS_OFFSET_810_EXFAT_SDMMC_ACCESSOR_NAND 0x166230
|
||||
|
||||
// Hooks
|
||||
#define FS_OFFSET_810_EXFAT_SDMMC_WRAPPER_READ 0x15E030
|
||||
#define FS_OFFSET_810_EXFAT_SDMMC_WRAPPER_WRITE 0x15E110
|
||||
#define FS_OFFSET_810_EXFAT_RTLD 0x5B4
|
||||
#define FS_OFFSET_810_EXFAT_RTLD_DESTINATION 0x9C
|
||||
|
||||
#define FS_OFFSET_810_EXFAT_CLKRST_SET_MIN_V_CLK_RATE 0x17A920
|
||||
|
||||
// Misc funcs
|
||||
#define FS_OFFSET_810_EXFAT_LOCK_MUTEX 0x156C80
|
||||
#define FS_OFFSET_810_EXFAT_UNLOCK_MUTEX 0x156CD0
|
||||
|
||||
// Misc Data
|
||||
#define FS_OFFSET_810_EXFAT_SD_MUTEX 0xFFE3E8
|
||||
#define FS_OFFSET_810_EXFAT_NAND_MUTEX 0xFF9BE8
|
||||
#define FS_OFFSET_810_EXFAT_ACTIVE_PARTITION 0xFF9C28
|
||||
#define FS_OFFSET_810_EXFAT_SDMMC_DAS_HANDLE 0xEFAA20
|
||||
|
||||
// NOPs
|
||||
#define FS_OFFSET_810_EXFAT_SHUTDOWN_SD 0xC651C
|
||||
#define FS_OFFSET_810_EXFAT_SD_DAS_INIT 0x93308
|
||||
|
||||
// Nintendo Paths
|
||||
#define FS_OFFSET_810_EXFAT_NINTENDO_PATHS \
|
||||
{ \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x0008ABA0, .add_rel_offset = 4}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x0008C634, .add_rel_offset = 4}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x0008C828, .add_rel_offset = 4}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x0008CC04, .add_rel_offset = 4}, \
|
||||
{.opcode_reg = 4, .adrp_offset = 0x0008CDC8, .add_rel_offset = 4}, \
|
||||
{.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0} \
|
||||
}
|
||||
|
||||
#endif // __FS_810_EXFAT_H__
|
||||
@@ -23,9 +23,13 @@
|
||||
#include "sd.h"
|
||||
#include "../utils/types.h"
|
||||
#include "../utils/util.h"
|
||||
#include "../utils/fatal.h"
|
||||
|
||||
#define DPRINTF(...) //fprintf(stdout, __VA_ARGS__)
|
||||
|
||||
sdmmc_accessor_t *_current_accessor = NULL;
|
||||
bool sdmmc_memcpy_buf = false;
|
||||
|
||||
static inline u32 unstuff_bits(u32 *resp, u32 start, u32 size)
|
||||
{
|
||||
const u32 mask = (size < 32 ? 1 << size : 0) - 1;
|
||||
@@ -41,6 +45,80 @@ static inline u32 unstuff_bits(u32 *resp, u32 start, u32 size)
|
||||
* Common functions for SD and MMC.
|
||||
*/
|
||||
|
||||
// FS DMA calculations.
|
||||
intptr_t sdmmc_calculate_dma_addr(sdmmc_accessor_t *_this, void *buf, unsigned int num_sectors)
|
||||
{
|
||||
int dma_buf_idx = 0;
|
||||
char *_buf = (char *)buf;
|
||||
char *actual_buf_start = _buf;
|
||||
char *actual_buf_end = &_buf[512 * num_sectors];
|
||||
char *dma_buffer_start = _this->parent->dmaBuffers[FS_SDMMC_EMMC].device_addr_buffer;
|
||||
|
||||
if (dma_buffer_start <= _buf && actual_buf_end <= &dma_buffer_start[_this->parent->dmaBuffers[FS_SDMMC_EMMC].device_addr_buffer_size])
|
||||
{
|
||||
dma_buf_idx = FS_SDMMC_EMMC;
|
||||
}
|
||||
else
|
||||
{
|
||||
dma_buffer_start = _this->parent->dmaBuffers[FS_SDMMC_SD].device_addr_buffer;
|
||||
if (dma_buffer_start <= actual_buf_start && actual_buf_end <= &dma_buffer_start[_this->parent->dmaBuffers[FS_SDMMC_SD].device_addr_buffer_size])
|
||||
{
|
||||
dma_buf_idx = FS_SDMMC_SD;
|
||||
}
|
||||
else
|
||||
{
|
||||
dma_buffer_start = _this->parent->dmaBuffers[FS_SDMMC_GC].device_addr_buffer;
|
||||
if (dma_buffer_start <= actual_buf_start && actual_buf_end <= &dma_buffer_start[_this->parent->dmaBuffers[FS_SDMMC_GC].device_addr_buffer_size])
|
||||
{
|
||||
dma_buf_idx = FS_SDMMC_GC;
|
||||
}
|
||||
else
|
||||
{
|
||||
// If buffer is on a random heap
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sdmmc_memcpy_buf = false;
|
||||
|
||||
intptr_t admaaddr = (intptr_t)&_this->parent->dmaBuffers[dma_buf_idx].device_addr_buffer_masked[actual_buf_start - dma_buffer_start];
|
||||
return admaaddr;
|
||||
}
|
||||
|
||||
int sdmmc_get_fitting_dma_index(sdmmc_accessor_t *_this, unsigned int num_sectors)
|
||||
{
|
||||
int dma_buf_idx = 0;
|
||||
int blkSize = num_sectors * 512;
|
||||
|
||||
if (_this->parent->dmaBuffers[FS_SDMMC_EMMC].device_addr_buffer_size >= blkSize)
|
||||
{
|
||||
dma_buf_idx = FS_SDMMC_EMMC;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_this->parent->dmaBuffers[FS_SDMMC_SD].device_addr_buffer_size >= blkSize)
|
||||
{
|
||||
dma_buf_idx = FS_SDMMC_SD;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_this->parent->dmaBuffers[FS_SDMMC_GC].device_addr_buffer_size >= blkSize)
|
||||
{
|
||||
dma_buf_idx = FS_SDMMC_GC;
|
||||
}
|
||||
else
|
||||
{
|
||||
// If buffer is on a random heap
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sdmmc_memcpy_buf = true;
|
||||
return dma_buf_idx;
|
||||
}
|
||||
|
||||
static int _sdmmc_storage_check_result(u32 res)
|
||||
{
|
||||
//Error mask:
|
||||
@@ -129,9 +207,11 @@ static int _sdmmc_storage_check_status(sdmmc_storage_t *storage)
|
||||
static int _sdmmc_storage_readwrite_ex(sdmmc_storage_t *storage, u32 *blkcnt_out, u32 sector, u32 num_sectors, void *buf, u32 is_write)
|
||||
{
|
||||
sdmmc_cmd_t cmdbuf;
|
||||
sdmmc_req_t reqbuf;
|
||||
u32 tmp = 0;
|
||||
|
||||
sdmmc_init_cmd(&cmdbuf, is_write ? MMC_WRITE_MULTIPLE_BLOCK : MMC_READ_MULTIPLE_BLOCK, sector, SDMMC_RSP_TYPE_1, 0);
|
||||
|
||||
sdmmc_req_t reqbuf;
|
||||
reqbuf.buf = buf;
|
||||
reqbuf.num_sectors = num_sectors;
|
||||
reqbuf.blksize = 512;
|
||||
@@ -140,12 +220,12 @@ static int _sdmmc_storage_readwrite_ex(sdmmc_storage_t *storage, u32 *blkcnt_out
|
||||
reqbuf.is_auto_cmd12 = 1;
|
||||
|
||||
if (!sdmmc_execute_cmd(storage->sdmmc, &cmdbuf, &reqbuf, blkcnt_out))
|
||||
{
|
||||
u32 tmp = 0;
|
||||
{
|
||||
sdmmc_stop_transmission(storage->sdmmc, &tmp);
|
||||
_sdmmc_storage_get_status(storage, &tmp, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#define _SDMMC_H_
|
||||
|
||||
#include "../utils/types.h"
|
||||
#include "../FS/FS.h"
|
||||
#include "sdmmc_driver.h"
|
||||
|
||||
typedef struct _mmc_cid
|
||||
@@ -102,6 +103,9 @@ typedef struct _sdmmc_storage_t
|
||||
sd_ssr_t ssr;
|
||||
} sdmmc_storage_t;
|
||||
|
||||
extern sdmmc_accessor_t *_current_accessor;
|
||||
extern bool sdmmc_memcpy_buf;
|
||||
|
||||
int sdmmc_storage_end(sdmmc_storage_t *storage);
|
||||
int sdmmc_storage_read(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, void *buf);
|
||||
int sdmmc_storage_write(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, void *buf);
|
||||
@@ -109,5 +113,7 @@ int sdmmc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32
|
||||
int sdmmc_storage_set_mmc_partition(sdmmc_storage_t *storage, u32 partition);
|
||||
int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32 bus_width, u32 type);
|
||||
int sdmmc_storage_init_gc(sdmmc_storage_t *storage, sdmmc_t *sdmmc);
|
||||
intptr_t sdmmc_calculate_dma_addr(sdmmc_accessor_t *_this, void *buf, unsigned int num_sectors);
|
||||
int sdmmc_get_fitting_dma_index(sdmmc_accessor_t *_this, unsigned int num_sectors);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include "../soc/pmc.h"
|
||||
#include "../soc/pinmux.h"
|
||||
#include "../soc/gpio.h"
|
||||
#include "../utils/fatal.h"
|
||||
|
||||
#define DPRINTF(...)
|
||||
|
||||
@@ -640,6 +641,23 @@ static int _sdmmc_autocal_config_offset(sdmmc_t *sdmmc, u32 power)
|
||||
|
||||
static void _sdmmc_autocal_execute(sdmmc_t *sdmmc, u32 power)
|
||||
{
|
||||
if(sdmmc->id == SDMMC_1)
|
||||
{
|
||||
static int last_power = SDMMC_POWER_3_3;
|
||||
if(power == SDMMC_POWER_1_8 && last_power == SDMMC_POWER_3_3)
|
||||
{
|
||||
last_power = power = SDMMC_POWER_1_8;
|
||||
if (!_sdmmc_autocal_config_offset(sdmmc, power))
|
||||
return;
|
||||
}
|
||||
else if(power == SDMMC_POWER_3_3 && last_power == SDMMC_POWER_1_8)
|
||||
{
|
||||
last_power = power = SDMMC_POWER_3_3;
|
||||
if (!_sdmmc_autocal_config_offset(sdmmc, power))
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
bool should_enable_sd_clock = false;
|
||||
if (sdmmc->regs->clkcon & TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE)
|
||||
{
|
||||
@@ -788,7 +806,15 @@ static int _sdmmc_config_dma(sdmmc_t *sdmmc, u32 *blkcnt_out, sdmmc_req_t *req)
|
||||
u32 blkcnt = req->num_sectors;
|
||||
if (blkcnt >= 0xFFFF)
|
||||
blkcnt = 0xFFFF;
|
||||
u64 admaaddr = sdmmc->dma_addr_fs;
|
||||
|
||||
u64 admaaddr = (u64)sdmmc_calculate_dma_addr(_current_accessor, req->buf, blkcnt);
|
||||
if (!admaaddr)
|
||||
{
|
||||
// buf is on a heap
|
||||
int dma_idx = sdmmc_get_fitting_dma_index(_current_accessor, blkcnt);
|
||||
admaaddr = (u64)&_current_accessor->parent->dmaBuffers[dma_idx].device_addr_buffer_masked[0];
|
||||
sdmmc->last_dma_idx = dma_idx;
|
||||
}
|
||||
|
||||
//Check alignment.
|
||||
if (admaaddr & 7)
|
||||
@@ -870,7 +896,22 @@ static int _sdmmc_execute_cmd_inner(sdmmc_t *sdmmc, sdmmc_cmd_t *cmd, sdmmc_req_
|
||||
if (req)
|
||||
{
|
||||
_sdmmc_config_dma(sdmmc, &blkcnt, req);
|
||||
armDCacheFlush(req->buf, req->blksize * blkcnt);
|
||||
if(!sdmmc_memcpy_buf)
|
||||
{
|
||||
// Flush from/to phys
|
||||
armDCacheFlush(req->buf, req->blksize * blkcnt);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(req->is_write)
|
||||
{
|
||||
void* dma_addr = &_current_accessor->parent->dmaBuffers[sdmmc->last_dma_idx].device_addr_buffer[0];
|
||||
memcpy(dma_addr, req->buf, req->blksize * blkcnt);
|
||||
|
||||
// Flush to phys
|
||||
armDCacheFlush(dma_addr, req->blksize * blkcnt);
|
||||
}
|
||||
}
|
||||
|
||||
_sdmmc_enable_interrupts(sdmmc);
|
||||
is_data_present = true;
|
||||
@@ -892,8 +933,15 @@ static int _sdmmc_execute_cmd_inner(sdmmc_t *sdmmc, sdmmc_cmd_t *cmd, sdmmc_req_
|
||||
{
|
||||
sdmmc->expected_rsp_type = cmd->rsp_type;
|
||||
_sdmmc_cache_rsp(sdmmc, sdmmc->rsp, 0x10, cmd->rsp_type);
|
||||
|
||||
/*if(sdmmc->rsp[0] & 0xFDF9A080)
|
||||
{
|
||||
res = 0;
|
||||
sdmmc->rsp[0] = 0; // Reset error
|
||||
}*/
|
||||
}
|
||||
if (req)
|
||||
|
||||
if (res && req)
|
||||
_sdmmc_update_dma(sdmmc);
|
||||
}
|
||||
|
||||
@@ -903,7 +951,22 @@ static int _sdmmc_execute_cmd_inner(sdmmc_t *sdmmc, sdmmc_cmd_t *cmd, sdmmc_req_
|
||||
{
|
||||
if (req)
|
||||
{
|
||||
armDCacheFlush(req->buf, req->blksize * blkcnt);
|
||||
if(!req->is_write)
|
||||
{
|
||||
if(!sdmmc_memcpy_buf)
|
||||
{
|
||||
// Flush from phys
|
||||
armDCacheFlush(req->buf, req->blksize * blkcnt);
|
||||
}
|
||||
else
|
||||
{
|
||||
void* dma_addr = &_current_accessor->parent->dmaBuffers[sdmmc->last_dma_idx].device_addr_buffer[0];
|
||||
// Flush from phys
|
||||
armDCacheFlush(dma_addr, req->blksize * blkcnt);
|
||||
// Copy to buffer
|
||||
memcpy(req->buf, dma_addr, req->blksize * blkcnt);
|
||||
}
|
||||
}
|
||||
|
||||
if (blkcnt_out)
|
||||
*blkcnt_out = blkcnt;
|
||||
|
||||
@@ -83,7 +83,7 @@ typedef struct _sdmmc_t
|
||||
int venclkctl_set;
|
||||
u32 venclkctl_tap;
|
||||
u32 expected_rsp_type;
|
||||
u64 dma_addr_fs;
|
||||
u64 last_dma_idx;
|
||||
u64 dma_addr_next;
|
||||
u32 rsp[4];
|
||||
u32 rsp3;
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "emummc.h"
|
||||
#include "emummc_ctx.h"
|
||||
|
||||
static bool sdmmc_first_init = false;
|
||||
static bool storageMMCinitialized = false;
|
||||
static bool storageSDinitialized = false;
|
||||
|
||||
@@ -68,15 +69,25 @@ static void _sdmmc_ensure_device_attached(void)
|
||||
|
||||
static void _sdmmc_ensure_initialized(void)
|
||||
{
|
||||
// The boot sysmodule will eventually kill power to SD. Detect this, and reinitialize when it happens.
|
||||
static bool init_done = false;
|
||||
if (!init_done)
|
||||
|
||||
// First Initial init
|
||||
if (!sdmmc_first_init)
|
||||
{
|
||||
if (gpio_read(GPIO_PORT_E, GPIO_PIN_4) == 0)
|
||||
sdmmc_initialize();
|
||||
sdmmc_first_init = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// The boot sysmodule will eventually kill power to SD. Detect this, and reinitialize when it happens.
|
||||
if (!init_done)
|
||||
{
|
||||
sdmmc_finalize();
|
||||
sdmmc_initialize();
|
||||
init_done = true;
|
||||
if (gpio_read(GPIO_PORT_E, GPIO_PIN_4) == 0)
|
||||
{
|
||||
sdmmc_finalize();
|
||||
sdmmc_initialize();
|
||||
init_done = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -128,7 +139,7 @@ static void _file_based_emmc_initialize(void)
|
||||
memset(&f_emu, 0, sizeof(file_based_ctxt));
|
||||
|
||||
memcpy(path, (void *)emuMMC_ctx.storagePath, sizeof(emuMMC_ctx.storagePath));
|
||||
strcat(path, "/eMMC");
|
||||
strcat(path, "/eMMC/");
|
||||
int path_len = strlen(path);
|
||||
|
||||
// Open BOOT0 physical partition.
|
||||
@@ -188,23 +199,33 @@ bool sdmmc_initialize(void)
|
||||
|
||||
if (!storageSDinitialized)
|
||||
{
|
||||
if (sdmmc_storage_init_sd(&sd_storage, &sd_sdmmc, SDMMC_1, SDMMC_BUS_WIDTH_4, 11))
|
||||
int retries = 5;
|
||||
while (retries)
|
||||
{
|
||||
storageSDinitialized = true;
|
||||
|
||||
// File based emummc.
|
||||
if ((emuMMC_ctx.EMMC_Type == emuMMC_SD_File) && !fat_mounted)
|
||||
if (sdmmc_storage_init_sd(&sd_storage, &sd_sdmmc, SDMMC_1, SDMMC_BUS_WIDTH_4, 11))
|
||||
{
|
||||
f_emu.sd_fs = (FATFS *)malloc(sizeof(FATFS));
|
||||
if (f_mount(f_emu.sd_fs, "", 1) != FR_OK)
|
||||
fatal_abort(Fatal_InitSD);
|
||||
else
|
||||
fat_mounted = true;
|
||||
storageSDinitialized = true;
|
||||
|
||||
_file_based_emmc_initialize();
|
||||
// File based emummc.
|
||||
if ((emuMMC_ctx.EMMC_Type == emuMMC_SD_File) && !fat_mounted)
|
||||
{
|
||||
f_emu.sd_fs = (FATFS *)malloc(sizeof(FATFS));
|
||||
if (f_mount(f_emu.sd_fs, "", 1) != FR_OK)
|
||||
fatal_abort(Fatal_InitSD);
|
||||
else
|
||||
fat_mounted = true;
|
||||
|
||||
_file_based_emmc_initialize();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
retries--;
|
||||
msleep(100);
|
||||
}
|
||||
else
|
||||
|
||||
if (!storageSDinitialized)
|
||||
{
|
||||
fatal_abort(Fatal_InitSD);
|
||||
}
|
||||
@@ -213,38 +234,6 @@ bool sdmmc_initialize(void)
|
||||
return storageMMCinitialized && storageSDinitialized;
|
||||
}
|
||||
|
||||
// FS DMA calculations.
|
||||
intptr_t sdmmc_calculate_dma_addr(sdmmc_accessor_t *_this, void *buf, unsigned int num_sectors)
|
||||
{
|
||||
int dma_buf_idx = 0;
|
||||
char *_buf = (char *)buf;
|
||||
char *actual_buf_start = _buf;
|
||||
char *actual_buf_end = &_buf[512 * num_sectors];
|
||||
char *dma_buffer_start = _this->parent->dmaBuffers[FS_SDMMC_EMMC].device_addr_buffer;
|
||||
|
||||
if (dma_buffer_start <= _buf && actual_buf_end <= &dma_buffer_start[_this->parent->dmaBuffers[FS_SDMMC_EMMC].device_addr_buffer_size])
|
||||
{
|
||||
dma_buf_idx = FS_SDMMC_EMMC;
|
||||
}
|
||||
else
|
||||
{
|
||||
dma_buffer_start = _this->parent->dmaBuffers[FS_SDMMC_SD].device_addr_buffer;
|
||||
if (dma_buffer_start <= actual_buf_start && actual_buf_end <= &dma_buffer_start[_this->parent->dmaBuffers[FS_SDMMC_SD].device_addr_buffer_size])
|
||||
{
|
||||
dma_buf_idx = FS_SDMMC_SD;
|
||||
}
|
||||
else
|
||||
{
|
||||
dma_buffer_start = _this->parent->dmaBuffers[FS_SDMMC_GC].device_addr_buffer;
|
||||
dma_buf_idx = FS_SDMMC_GC;
|
||||
}
|
||||
}
|
||||
|
||||
intptr_t admaaddr = (intptr_t)&_this->parent->dmaBuffers[dma_buf_idx].device_addr_buffer_masked[actual_buf_start - dma_buffer_start];
|
||||
|
||||
return admaaddr;
|
||||
}
|
||||
|
||||
sdmmc_accessor_t *sdmmc_accessor_get(int mmc_id)
|
||||
{
|
||||
sdmmc_accessor_t *_this;
|
||||
@@ -354,6 +343,8 @@ uint64_t sdmmc_wrapper_read(void *buf, uint64_t bufSize, int mmc_id, unsigned in
|
||||
if (mmc_id == FS_SDMMC_EMMC || mmc_id == FS_SDMMC_SD)
|
||||
{
|
||||
mutex_lock_handler(mmc_id);
|
||||
// Assign FS accessor to the SDMMC driver
|
||||
_current_accessor = _this;
|
||||
// Make sure we're attached to the device address space.
|
||||
_sdmmc_ensure_device_attached();
|
||||
// Make sure we're still initialized if boot killed sd card power.
|
||||
@@ -362,8 +353,6 @@ uint64_t sdmmc_wrapper_read(void *buf, uint64_t bufSize, int mmc_id, unsigned in
|
||||
|
||||
if (mmc_id == FS_SDMMC_EMMC)
|
||||
{
|
||||
sd_storage.sdmmc->dma_addr_fs = (u64)sdmmc_calculate_dma_addr(_this, buf, num_sectors);
|
||||
|
||||
// Call hekates driver.
|
||||
if (emummc_read_write_inner(buf, sector, num_sectors, false))
|
||||
{
|
||||
@@ -377,8 +366,6 @@ uint64_t sdmmc_wrapper_read(void *buf, uint64_t bufSize, int mmc_id, unsigned in
|
||||
|
||||
if (mmc_id == FS_SDMMC_SD)
|
||||
{
|
||||
sd_storage.sdmmc->dma_addr_fs = (u64)sdmmc_calculate_dma_addr(_this, buf, num_sectors);
|
||||
|
||||
// Call hekates driver.
|
||||
if (sdmmc_storage_read(&sd_storage, sector, num_sectors, buf))
|
||||
{
|
||||
@@ -410,8 +397,7 @@ uint64_t sdmmc_wrapper_write(int mmc_id, unsigned int sector, unsigned int num_s
|
||||
if (mmc_id == FS_SDMMC_EMMC)
|
||||
{
|
||||
mutex_lock_handler(mmc_id);
|
||||
|
||||
sd_storage.sdmmc->dma_addr_fs = (u64)sdmmc_calculate_dma_addr(_this, buf, num_sectors);
|
||||
_current_accessor = _this;
|
||||
|
||||
// Call hekates driver.
|
||||
if (emummc_read_write_inner(buf, sector, num_sectors, true))
|
||||
@@ -427,9 +413,9 @@ uint64_t sdmmc_wrapper_write(int mmc_id, unsigned int sector, unsigned int num_s
|
||||
if (mmc_id == FS_SDMMC_SD)
|
||||
{
|
||||
mutex_lock_handler(mmc_id);
|
||||
_current_accessor = _this;
|
||||
|
||||
sector += 0;
|
||||
sd_storage.sdmmc->dma_addr_fs = (u64)sdmmc_calculate_dma_addr(_this, buf, num_sectors);
|
||||
|
||||
// Call hekates driver.
|
||||
if (sdmmc_storage_write(&sd_storage, sector, num_sectors, buf))
|
||||
|
||||
@@ -50,8 +50,6 @@ sdmmc_accessor_t *sdmmc_accessor_get(int mmc_id);
|
||||
void mutex_lock_handler(int mmc_id);
|
||||
void mutex_unlock_handler(int mmc_id);
|
||||
|
||||
intptr_t sdmmc_calculate_dma_addr(sdmmc_accessor_t *_this, void *buf, unsigned int num_sectors);
|
||||
|
||||
uint64_t sdmmc_wrapper_read(void *buf, uint64_t bufSize, int mmc_id, unsigned int sector, unsigned int num_sectors);
|
||||
uint64_t sdmmc_wrapper_write(int mmc_id, unsigned int sector, unsigned int num_sectors, void *buf, uint64_t bufSize);
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ uintptr_t text_base;
|
||||
char inner_heap[INNER_HEAP_SIZE];
|
||||
size_t inner_heap_size = INNER_HEAP_SIZE;
|
||||
extern char _start;
|
||||
extern char __injected_size__;
|
||||
extern char __argdata__;
|
||||
|
||||
// Nintendo Path
|
||||
// TODO
|
||||
@@ -53,7 +53,7 @@ static char nintendo_path_contents_100[0x100] = "/Nintendo/Contents";
|
||||
static const fs_offsets_t *fs_offsets;
|
||||
|
||||
// Defined by linkerscript
|
||||
#define INJECTED_SIZE ((uintptr_t)&__injected_size__ - (uintptr_t)&_start)
|
||||
#define INJECTED_SIZE ((uintptr_t)&__argdata__ - (uintptr_t)&_start)
|
||||
#define INJECT_OFFSET(type, offset) (type)(text_base + INJECTED_SIZE + offset)
|
||||
|
||||
#define GENERATE_ADD(register, register_target, value) (0x91000000 | value << 10 | register << 5 | register_target)
|
||||
@@ -154,15 +154,14 @@ void write_nop(uintptr_t source)
|
||||
smcWriteAddress32((void *)source, GENERATE_NOP());
|
||||
}
|
||||
|
||||
void write_adrp_add(int reg, uintptr_t pc, intptr_t destination)
|
||||
void write_adrp_add(int reg, uintptr_t pc, uintptr_t add_rel_offset, intptr_t destination)
|
||||
{
|
||||
uintptr_t add_opcode_location = pc + sizeof(uint32_t);
|
||||
uintptr_t add_opcode_location = pc + add_rel_offset;
|
||||
|
||||
intptr_t offset = (destination & 0xFFFFF000) - (pc & 0xFFFFF000);
|
||||
uint32_t opcode_adrp = GENERATE_ADRP(reg, offset);
|
||||
uint32_t opcode_add = GENERATE_ADD(reg, reg, (destination & 0x00000FFF));
|
||||
|
||||
// TODO: use 64 write?
|
||||
smcWriteAddress32((void *)pc, opcode_adrp);
|
||||
smcWriteAddress32((void *)add_opcode_location, opcode_add);
|
||||
}
|
||||
@@ -268,7 +267,7 @@ void setup_nintendo_paths(void)
|
||||
{
|
||||
intptr_t nintendo_path_location = (intptr_t)&nintendo_path;
|
||||
uintptr_t fs_adrp_opcode_location = INJECT_OFFSET(uintptr_t, fs_offsets->nintendo_paths[i].adrp_offset);
|
||||
write_adrp_add(fs_offsets->nintendo_paths[i].opcode_reg, fs_adrp_opcode_location, nintendo_path_location);
|
||||
write_adrp_add(fs_offsets->nintendo_paths[i].opcode_reg, fs_adrp_opcode_location, fs_offsets->nintendo_paths[i].add_rel_offset, nintendo_path_location);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -281,8 +280,8 @@ void setup_nintendo_paths(void)
|
||||
intptr_t album_path_location = nintendo_album_path_location + path_len - 6; // "/Album"
|
||||
uintptr_t fs_n_adrp_opcode_location = INJECT_OFFSET(uintptr_t, fs_offsets->nintendo_paths[0].adrp_offset);
|
||||
uintptr_t fs_adrp_opcode_location = INJECT_OFFSET(uintptr_t, fs_offsets->nintendo_paths[1].adrp_offset);
|
||||
write_adrp_add(fs_offsets->nintendo_paths[0].opcode_reg, fs_n_adrp_opcode_location, nintendo_album_path_location);
|
||||
write_adrp_add(fs_offsets->nintendo_paths[1].opcode_reg, fs_adrp_opcode_location, album_path_location);
|
||||
write_adrp_add(fs_offsets->nintendo_paths[0].opcode_reg, fs_n_adrp_opcode_location, fs_offsets->nintendo_paths[0].add_rel_offset, nintendo_album_path_location);
|
||||
write_adrp_add(fs_offsets->nintendo_paths[1].opcode_reg, fs_adrp_opcode_location, fs_offsets->nintendo_paths[1].add_rel_offset, album_path_location);
|
||||
}
|
||||
// Do contents path
|
||||
{
|
||||
@@ -291,8 +290,8 @@ void setup_nintendo_paths(void)
|
||||
intptr_t contents_path_location = nintendo_contents_path_location + path_len - 9; // "/Contents"
|
||||
uintptr_t fs_n_adrp_opcode_location = INJECT_OFFSET(uintptr_t, fs_offsets->nintendo_paths[2].adrp_offset);
|
||||
uintptr_t fs_adrp_opcode_location = INJECT_OFFSET(uintptr_t, fs_offsets->nintendo_paths[3].adrp_offset);
|
||||
write_adrp_add(fs_offsets->nintendo_paths[2].opcode_reg, fs_n_adrp_opcode_location, nintendo_contents_path_location);
|
||||
write_adrp_add(fs_offsets->nintendo_paths[3].opcode_reg, fs_adrp_opcode_location, contents_path_location);
|
||||
write_adrp_add(fs_offsets->nintendo_paths[2].opcode_reg, fs_n_adrp_opcode_location, fs_offsets->nintendo_paths[2].add_rel_offset, nintendo_contents_path_location);
|
||||
write_adrp_add(fs_offsets->nintendo_paths[3].opcode_reg, fs_adrp_opcode_location, fs_offsets->nintendo_paths[3].add_rel_offset, contents_path_location);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -317,6 +316,4 @@ void __init()
|
||||
populate_function_pointers();
|
||||
write_nops();
|
||||
setup_nintendo_paths();
|
||||
|
||||
sdmmc_initialize();
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -78,7 +78,7 @@ startup:
|
||||
|
||||
MOV W0, #0xFFFF8001
|
||||
ADR X1, __data_start
|
||||
ADR X2, __end__
|
||||
ADR X2, __argdata__
|
||||
SUB X2, X2, X1
|
||||
MOV X3, #3
|
||||
SVC 0x73
|
||||
@@ -127,5 +127,5 @@ bss_loop:
|
||||
MOV X30, X27
|
||||
|
||||
# FS main
|
||||
ADR X16, __injected_size__
|
||||
ADRP X16, __argdata__
|
||||
BR X16
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
ParseClipboard()
|
||||
|
||||
Func FormatLineData($sLineData)
|
||||
Func FormatLineData($sLineData, $sLineDataAdd)
|
||||
Local $lineData = StringReplace($sLineData, @TAB, " ")
|
||||
Local $lineDataADRP, $lineDataADD
|
||||
Local $isADRP = false
|
||||
$lineData = StringReplace($lineData, "Up o sub_71000" , "0x")
|
||||
$isADRP = StringInStr($lineData, "ADRP")
|
||||
@@ -13,24 +14,39 @@ Func FormatLineData($sLineData)
|
||||
|
||||
$lineDataAddr = StringReplace($lineDataAddr, "0x" , "")
|
||||
$lineDataAddition = StringReplace($lineDataAddition, "0x" , "")
|
||||
$addrADRP = Dec($lineDataAddr) + Dec($lineDataAddition)
|
||||
|
||||
If $isADRP Then
|
||||
$lineData = "0x" & Hex(Dec($lineDataAddr) + Dec($lineDataAddition))
|
||||
Else
|
||||
Return ""
|
||||
EndIf
|
||||
$lineDataADRP = "0x" & Hex($addrADRP)
|
||||
|
||||
Return "{.opcode_reg = " & $targetRegister & ", .adrp_offset = " & $lineData & "}, \" & @LF
|
||||
Local $lineDataADD = StringReplace($sLineDataAdd, @TAB, " ")
|
||||
Local $isADD = false
|
||||
$lineDataADD = StringReplace($lineDataADD, "Up o sub_71000" , "0x")
|
||||
$isADD = StringInStr($lineData, "ADD")
|
||||
|
||||
$lineDataADD = StringSplit($lineDataADD, " ")[1]
|
||||
$lineDataAddAddr = StringSplit($lineDataADD, "+")[1]
|
||||
$lineDataAddAddition = StringSplit($lineDataADD, "+")[2]
|
||||
|
||||
$lineDataAddAddr = StringReplace($lineDataAddAddr, "0x" , "")
|
||||
$lineDataAddAddition = StringReplace($lineDataAddAddition, "0x" , "")
|
||||
$addrADD = Dec($lineDataAddAddr) + Dec($lineDataAddAddition)
|
||||
$addrADD = $addrADD - $addrADRP
|
||||
$lineDataADD = "0x" & Hex($addrADD)
|
||||
|
||||
Return @TAB & "{.opcode_reg = " & $targetRegister & ", .adrp_offset = " & $lineDataADRP & ", .add_rel_offset = " & $lineDataADD & "}, \" & @LF
|
||||
EndFunc
|
||||
|
||||
Func ParseClipboard()
|
||||
Local $sData = ClipGet()
|
||||
Local $oData = ""
|
||||
Local $sLineData = StringSplit(StringReplace($sData, @CRLF, @LF), @LF)
|
||||
For $i = 2 to UBound($sLineData) - 2
|
||||
Local $lineData = FormatLineData($sLineData[$i])
|
||||
For $i = 2 to UBound($sLineData) - 2 Step 2
|
||||
Local $lineData = FormatLineData($sLineData[$i], $sLineData[$i+1])
|
||||
;ConsoleWrite($lineData)
|
||||
$oData = $oData & $lineData
|
||||
Next
|
||||
|
||||
$oData = "{ \" & @LF & $oData & @TAB & "{.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \" & @LF & "}" & @LF
|
||||
;ConsoleWrite($oData)
|
||||
ClipPut($oData)
|
||||
EndFunc
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
* 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 <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
@@ -34,13 +34,13 @@ unsigned int exosphere_load_config(void) {
|
||||
generic_panic();
|
||||
}
|
||||
g_has_loaded_config = true;
|
||||
|
||||
|
||||
const unsigned int magic = MAILBOX_EXOSPHERE_CONFIG.magic;
|
||||
|
||||
|
||||
if (magic == MAGIC_EXOSPHERE_CONFIG) {
|
||||
g_exosphere_cfg = MAILBOX_EXOSPHERE_CONFIG;
|
||||
}
|
||||
|
||||
|
||||
return g_exosphere_cfg.target_firmware;
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ unsigned int exosphere_get_target_firmware(void) {
|
||||
if (!g_has_loaded_config) {
|
||||
generic_panic();
|
||||
}
|
||||
|
||||
|
||||
return g_exosphere_cfg.target_firmware;
|
||||
}
|
||||
|
||||
@@ -56,15 +56,15 @@ unsigned int exosphere_should_perform_620_keygen(void) {
|
||||
if (!g_has_loaded_config) {
|
||||
generic_panic();
|
||||
}
|
||||
|
||||
return g_exosphere_cfg.target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_620 && EXOSPHERE_CHECK_FLAG(EXOSPHERE_FLAG_PERFORM_620_KEYGEN);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned int exosphere_should_override_debugmode_priv(void) {
|
||||
if (!g_has_loaded_config) {
|
||||
generic_panic();
|
||||
}
|
||||
|
||||
|
||||
return EXOSPHERE_CHECK_FLAG(EXOSPHERE_FLAG_IS_DEBUGMODE_PRIV);
|
||||
}
|
||||
|
||||
@@ -72,7 +72,7 @@ unsigned int exosphere_should_override_debugmode_user(void) {
|
||||
if (!g_has_loaded_config) {
|
||||
generic_panic();
|
||||
}
|
||||
|
||||
|
||||
return EXOSPHERE_CHECK_FLAG(EXOSPHERE_FLAG_IS_DEBUGMODE_USER);
|
||||
}
|
||||
|
||||
@@ -80,7 +80,7 @@ unsigned int exosphere_should_disable_usermode_exception_handlers(void) {
|
||||
if (!g_has_loaded_config) {
|
||||
generic_panic();
|
||||
}
|
||||
|
||||
|
||||
return EXOSPHERE_CHECK_FLAG(EXOSPHERE_FLAG_DISABLE_USERMODE_EXCEPTION_HANDLERS);
|
||||
}
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
* 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 EXOSPHERE_EXOSPHERE_CONFIG_H
|
||||
#define EXOSPHERE_EXOSPHERE_CONFIG_H
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
/* Exosphere config in DRAM shares physical/virtual mapping. */
|
||||
#define MAILBOX_EXOSPHERE_CONFIG_PHYS MAILBOX_EXOSPHERE_CONFIG
|
||||
|
||||
#define EXOSPHERE_FLAG_PERFORM_620_KEYGEN (1 << 0u)
|
||||
#define EXOSPHERE_FLAG_PERFORM_620_KEYGEN_DEPRECATED (1 << 0u)
|
||||
#define EXOSPHERE_FLAG_IS_DEBUGMODE_PRIV (1 << 1u)
|
||||
#define EXOSPHERE_FLAG_IS_DEBUGMODE_USER (1 << 2u)
|
||||
#define EXOSPHERE_FLAG_DISABLE_USERMODE_EXCEPTION_HANDLERS (1 << 3u)
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
* 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 <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
@@ -42,6 +42,7 @@ static const uint8_t mkey_vectors_dev[MASTERKEY_REVISION_MAX][0x10] =
|
||||
{0x78, 0xD5, 0xF1, 0x20, 0x3D, 0x16, 0xE9, 0x30, 0x32, 0x27, 0x34, 0x6F, 0xCF, 0xE0, 0x27, 0xDC}, /* Master key 04 encrypted with Master key 05. */
|
||||
{0x6F, 0xD2, 0x84, 0x1D, 0x05, 0xEC, 0x40, 0x94, 0x5F, 0x18, 0xB3, 0x81, 0x09, 0x98, 0x8D, 0x4E}, /* Master key 05 encrypted with Master key 06. */
|
||||
{0x37, 0xAF, 0xAB, 0x35, 0x79, 0x09, 0xD9, 0x48, 0x29, 0xD2, 0xDB, 0xA5, 0xA5, 0xF5, 0x30, 0x19}, /* Master key 06 encrypted with Master key 07. */
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* TODO: Master key 07 encrypted with Master key 08. */
|
||||
};
|
||||
|
||||
/* Retail unit keys. */
|
||||
@@ -55,6 +56,7 @@ static const uint8_t mkey_vectors[MASTERKEY_REVISION_MAX][0x10] =
|
||||
{0xEB, 0xF5, 0x6F, 0x83, 0x61, 0x9E, 0xF8, 0xFA, 0xE0, 0x87, 0xD7, 0xA1, 0x4E, 0x25, 0x36, 0xEE}, /* Master key 04 encrypted with Master key 05. */
|
||||
{0x1E, 0x1E, 0x22, 0xC0, 0x5A, 0x33, 0x3C, 0xB9, 0x0B, 0xA9, 0x03, 0x04, 0xBA, 0xDB, 0x07, 0x57}, /* Master key 05 encrypted with Master key 06. */
|
||||
{0xA4, 0xD4, 0x52, 0x6F, 0xD1, 0xE4, 0x36, 0xAA, 0x9F, 0xCB, 0x61, 0x27, 0x1C, 0x67, 0x65, 0x1F}, /* Master key 06 encrypted with Master key 07. */
|
||||
{0xEA, 0x60, 0xB3, 0xEA, 0xCE, 0x8F, 0x24, 0x46, 0x7D, 0x33, 0x9C, 0xD1, 0xBC, 0x24, 0x98, 0x29}, /* Master key 07 encrypted with Master key 08. */
|
||||
};
|
||||
|
||||
bool check_mkey_revision(unsigned int revision, bool is_retail) {
|
||||
@@ -83,7 +85,7 @@ void mkey_detect_revision(void) {
|
||||
if (g_determined_mkey_revision) {
|
||||
generic_panic();
|
||||
}
|
||||
|
||||
|
||||
for (unsigned int rev = 0; rev < MASTERKEY_REVISION_MAX; rev++) {
|
||||
if (check_mkey_revision(rev, configitem_is_retail())) {
|
||||
g_determined_mkey_revision = true;
|
||||
@@ -91,7 +93,7 @@ void mkey_detect_revision(void) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* We must have determined the master key, or we're not running on a Switch. */
|
||||
if (!g_determined_mkey_revision) {
|
||||
/* Panic in bright red. */
|
||||
@@ -125,7 +127,6 @@ unsigned int mkey_get_keyslot(unsigned int revision) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void set_old_devkey(unsigned int revision, const uint8_t *key) {
|
||||
if (revision < MASTERKEY_REVISION_400_410 || MASTERKEY_REVISION_MAX <= revision) {
|
||||
generic_panic();
|
||||
@@ -135,23 +136,17 @@ void set_old_devkey(unsigned int revision, const uint8_t *key) {
|
||||
}
|
||||
|
||||
unsigned int devkey_get_keyslot(unsigned int revision) {
|
||||
if (!g_determined_mkey_revision || revision >= MASTERKEY_REVISION_MAX) {
|
||||
if (!g_determined_mkey_revision || revision > g_mkey_revision) {
|
||||
generic_panic();
|
||||
}
|
||||
|
||||
if (revision > g_mkey_revision) {
|
||||
generic_panic();
|
||||
}
|
||||
|
||||
if (revision >= 1) {
|
||||
if (revision == MASTERKEY_REVISION_MAX) {
|
||||
return KEYSLOT_SWITCH_DEVICEKEY;
|
||||
} else {
|
||||
/* Load into a temp keyslot. */
|
||||
set_aes_keyslot(KEYSLOT_SWITCH_TEMPKEY, g_old_devicekeys[revision - MASTERKEY_REVISION_400_410], 0x10);
|
||||
return KEYSLOT_SWITCH_TEMPKEY;
|
||||
}
|
||||
} else {
|
||||
if (revision < MASTERKEY_REVISION_400_410) {
|
||||
return KEYSLOT_SWITCH_4XOLDDEVICEKEY;
|
||||
} else if (revision < g_mkey_revision) {
|
||||
/* Load into a temp keyslot. */
|
||||
set_aes_keyslot(KEYSLOT_SWITCH_TEMPKEY, g_old_devicekeys[revision - MASTERKEY_REVISION_400_410], 0x10);
|
||||
return KEYSLOT_SWITCH_TEMPKEY;
|
||||
} else {
|
||||
return KEYSLOT_SWITCH_DEVICEKEY;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,14 +13,14 @@
|
||||
* 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 EXOSPHERE_MASTERKEY_H
|
||||
#define EXOSPHERE_MASTERKEY_H
|
||||
|
||||
/* This is glue code to enable master key support across versions. */
|
||||
|
||||
/* TODO: Update to 0x9 on release of new master key. */
|
||||
#define MASTERKEY_REVISION_MAX 0x8
|
||||
/* TODO: Update to 0xA on release of new master key. */
|
||||
#define MASTERKEY_REVISION_MAX 0x9
|
||||
|
||||
#define MASTERKEY_REVISION_100_230 0x00
|
||||
#define MASTERKEY_REVISION_300 0x01
|
||||
@@ -29,7 +29,8 @@
|
||||
#define MASTERKEY_REVISION_500_510 0x04
|
||||
#define MASTERKEY_REVISION_600_610 0x05
|
||||
#define MASTERKEY_REVISION_620 0x06
|
||||
#define MASTERKEY_REVISION_700_CURRENT 0x07
|
||||
#define MASTERKEY_REVISION_700_800 0x07
|
||||
#define MASTERKEY_REVISION_810_CURRENT 0x08
|
||||
|
||||
#define MASTERKEY_NUM_NEW_DEVICE_KEYS (MASTERKEY_REVISION_MAX - MASTERKEY_REVISION_400_410)
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
* 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 <stdint.h>
|
||||
|
||||
#include "memory_map.h"
|
||||
@@ -28,7 +28,7 @@ typedef struct {
|
||||
static saved_carveout_info_t g_saved_carveouts[2] = {
|
||||
{0x80060000ull, KERNEL_CARVEOUT_SIZE_MAX},
|
||||
{0x00000000ull, 0x00000000ull}
|
||||
};
|
||||
};
|
||||
|
||||
volatile security_carveout_t *get_carveout_by_id(unsigned int carveout) {
|
||||
if (CARVEOUT_ID_MIN <= carveout && carveout <= CARVEOUT_ID_MAX) {
|
||||
@@ -130,7 +130,7 @@ void configure_kernel_carveout(unsigned int carveout_id, uint64_t address, uint6
|
||||
if (carveout_id != 4 && carveout_id != 5) {
|
||||
generic_panic();
|
||||
}
|
||||
|
||||
|
||||
g_saved_carveouts[carveout_id-4].address = address;
|
||||
g_saved_carveouts[carveout_id-4].size = size;
|
||||
|
||||
@@ -140,8 +140,12 @@ void configure_kernel_carveout(unsigned int carveout_id, uint64_t address, uint6
|
||||
carveout->size_big_pages = (uint32_t)(size >> 17);
|
||||
carveout->client_access_0 = (BIT(CSR_PTCR) | BIT(CSR_DISPLAY0A) | BIT(CSR_DISPLAY0AB) | BIT(CSR_DISPLAY0B) | BIT(CSR_DISPLAY0BB) | BIT(CSR_DISPLAY0C) | BIT(CSR_DISPLAY0CB) | BIT(CSR_AFIR) | BIT(CSR_DISPLAYHC) | BIT(CSR_DISPLAYHCB) | BIT(CSR_HDAR) | BIT(CSR_HOST1XDMAR) | BIT(CSR_HOST1XR) | BIT(CSR_NVENCSRD) | BIT(CSR_PPCSAHBDMAR) | BIT(CSR_PPCSAHBSLVR));
|
||||
carveout->client_access_1 = (BIT(CSR_MPCORER) | BIT(CSW_NVENCSWR) | BIT(CSW_AFIW) | BIT(CSW_HDAW) | BIT(CSW_HOST1XW) | BIT(CSW_MPCOREW) | BIT(CSW_PPCSAHBDMAW) | BIT(CSW_PPCSAHBSLVW));
|
||||
if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_800) {
|
||||
carveout->client_access_2 = (BIT(CSR_XUSB_HOSTR) | BIT(CSW_XUSB_HOSTW) | BIT(CSR_XUSB_DEVR) | BIT(CSW_XUSB_DEVW));
|
||||
if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_810) {
|
||||
carveout->client_access_2 = (BIT(CSR_XUSB_HOSTR) | BIT(CSW_XUSB_HOSTW) | BIT(CSR_XUSB_DEVR) | BIT(CSW_XUSB_DEVW));
|
||||
carveout->client_access_3 = (BIT(CSR_SDMMCRA) | BIT(CSR_SDMMCRAA) | BIT(CSR_SDMMCRAB) | BIT(CSW_SDMMCWA) | BIT(CSW_SDMMCWAA) | BIT(CSW_SDMMCWAB) | BIT(CSR_VICSRD) | BIT(CSW_VICSWR) | BIT(CSR_DISPLAYD) | BIT(CSR_APER) | BIT(CSW_APEW) | BIT(CSR_NVJPGSRD) | BIT(CSW_NVJPGSWR));
|
||||
carveout->client_access_4 = (BIT(CSR_SESRD) | BIT(CSW_SESWR));
|
||||
} else if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_800) {
|
||||
carveout->client_access_2 = (BIT(CSR_XUSB_HOSTR) | BIT(CSW_XUSB_HOSTW) | BIT(CSR_XUSB_DEVR) | BIT(CSW_XUSB_DEVW));
|
||||
carveout->client_access_3 = (BIT(CSR_SDMMCRA) | BIT(CSR_SDMMCRAA) | BIT(CSR_SDMMCRAB) | BIT(CSW_SDMMCWA) | BIT(CSW_SDMMCWAA) | BIT(CSW_SDMMCWAB) | BIT(CSR_VICSRD) | BIT(CSW_VICSWR) | BIT(CSR_DISPLAYD) | BIT(CSR_NVDECSRD) | BIT(CSW_NVDECSWR) | BIT(CSR_APER) | BIT(CSW_APEW) | BIT(CSR_NVJPGSRD) | BIT(CSW_NVJPGSWR));
|
||||
carveout->client_access_4 = (BIT(CSR_SESRD) | BIT(CSW_SESWR) | BIT(CSR_TSECSRDB) | BIT(CSW_TSECSWRB));
|
||||
} else {
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
* 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 "utils.h"
|
||||
@@ -43,6 +43,7 @@ static const uint8_t new_device_key_sources[MASTERKEY_NUM_NEW_DEVICE_KEYS][0x10]
|
||||
{0x70, 0x08, 0x1B, 0x97, 0x44, 0x64, 0xF8, 0x91, 0x54, 0x9D, 0xC6, 0x84, 0x8F, 0x1A, 0xB2, 0xE4}, /* 6.x New Device Key Source. */
|
||||
{0x8E, 0x09, 0x1F, 0x7A, 0xBB, 0xCA, 0x6A, 0xFB, 0xB8, 0x9B, 0xD5, 0xC1, 0x25, 0x9C, 0xA9, 0x17}, /* 6.2.0 New Device Key Source. */
|
||||
{0x8F, 0x77, 0x5A, 0x96, 0xB0, 0x94, 0xFD, 0x8D, 0x28, 0xE4, 0x19, 0xC8, 0x16, 0x1C, 0xDB, 0x3D}, /* 7.0.0 New Device Key Source. */
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* TODO: 8.1.0 New Device Key Source to be added on next change-of-keys. */
|
||||
};
|
||||
|
||||
static const uint8_t new_device_keygen_sources[MASTERKEY_NUM_NEW_DEVICE_KEYS][0x10] = {
|
||||
@@ -51,6 +52,7 @@ static const uint8_t new_device_keygen_sources[MASTERKEY_NUM_NEW_DEVICE_KEYS][0x
|
||||
{0x99, 0xFA, 0x98, 0xBD, 0x15, 0x1C, 0x72, 0xFD, 0x7D, 0x9A, 0xD5, 0x41, 0x00, 0xFD, 0xB2, 0xEF}, /* 6.x New Device Keygen Source. */
|
||||
{0x81, 0x3C, 0x6C, 0xBF, 0x5D, 0x21, 0xDE, 0x77, 0x20, 0xD9, 0x6C, 0xE3, 0x22, 0x06, 0xAE, 0xBB}, /* 6.2.0 New Device Keygen Source. */
|
||||
{0x86, 0x61, 0xB0, 0x16, 0xFA, 0x7A, 0x9A, 0xEA, 0xF6, 0xF5, 0xBE, 0x1A, 0x13, 0x5B, 0x6D, 0x9E}, /* 7.0.0 New Device Keygen Source. */
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* TODO: 8.1.0 New Device Key Source to be added on next change-of-keys. */
|
||||
};
|
||||
|
||||
static const uint8_t new_device_keygen_sources_dev[MASTERKEY_NUM_NEW_DEVICE_KEYS][0x10] = {
|
||||
@@ -58,45 +60,28 @@ static const uint8_t new_device_keygen_sources_dev[MASTERKEY_NUM_NEW_DEVICE_KEYS
|
||||
{0x59, 0x2D, 0x20, 0x69, 0x33, 0xB5, 0x17, 0xBA, 0xCF, 0xB1, 0x4E, 0xFD, 0xE4, 0xC2, 0x7B, 0xA8}, /* 5.x New Device Keygen Source. */
|
||||
{0xF6, 0xD8, 0x59, 0x63, 0x8F, 0x47, 0xCB, 0x4A, 0xD8, 0x74, 0x05, 0x7F, 0x88, 0x92, 0x33, 0xA5}, /* 6.x New Device Keygen Source. */
|
||||
{0x20, 0xAB, 0xF2, 0x0F, 0x05, 0xE3, 0xDE, 0x2E, 0xA1, 0xFB, 0x37, 0x5E, 0x8B, 0x22, 0x1A, 0x38}, /* 6.2.0 New Device Keygen Source. */
|
||||
{0x60, 0xAE, 0x56, 0x68, 0x11, 0xE2, 0x0C, 0x99, 0xDE, 0x05, 0xAE, 0x68, 0x78, 0x85, 0x04, 0xAE}, /* 6.2.0 New Device Keygen Source. */
|
||||
};
|
||||
|
||||
static const uint8_t new_master_kek_sources[MASTERKEY_REVISION_700_CURRENT - MASTERKEY_REVISION_600_610][0x10] = {
|
||||
{0x37, 0x4B, 0x77, 0x29, 0x59, 0xB4, 0x04, 0x30, 0x81, 0xF6, 0xE5, 0x8C, 0x6D, 0x36, 0x17, 0x9A}, /* 6.2.0 Master Kek Source. */
|
||||
{0x9A, 0x3E, 0xA9, 0xAB, 0xFD, 0x56, 0x46, 0x1C, 0x9B, 0xF6, 0x48, 0x7F, 0x5C, 0xFA, 0x09, 0x5C}, /* 7.0.0 Master Kek Source. */
|
||||
};
|
||||
|
||||
static const uint8_t keyblob_key_seed_00[0x10] = {
|
||||
0xDF, 0x20, 0x6F, 0x59, 0x44, 0x54, 0xEF, 0xDC, 0x70, 0x74, 0x48, 0x3B, 0x0D, 0xED, 0x9F, 0xD3
|
||||
};
|
||||
|
||||
static const uint8_t devicekey_seed[0x10] = {
|
||||
0x4F, 0x02, 0x5F, 0x0E, 0xB6, 0x6D, 0x11, 0x0E, 0xDC, 0x32, 0x7D, 0x41, 0x86, 0xC2, 0xF4, 0x78
|
||||
};
|
||||
|
||||
static const uint8_t devicekey_4x_seed[0x10] = {
|
||||
0x0C, 0x91, 0x09, 0xDB, 0x93, 0x93, 0x07, 0x81, 0x07, 0x3C, 0xC4, 0x16, 0x22, 0x7C, 0x6C, 0x28
|
||||
};
|
||||
|
||||
static const uint8_t masterkey_seed[0x10] = {
|
||||
0xD8, 0xA2, 0x41, 0x0A, 0xC6, 0xC5, 0x90, 0x01, 0xC6, 0x1D, 0x6A, 0x26, 0x7C, 0x51, 0x3F, 0x3C
|
||||
};
|
||||
|
||||
static const uint8_t devicekek_4x_seed[0x10] = {
|
||||
0x2D, 0xC1, 0xF4, 0x8D, 0xF3, 0x5B, 0x69, 0x33, 0x42, 0x10, 0xAC, 0x65, 0xDA, 0x90, 0x46, 0x66
|
||||
{0x60, 0xAE, 0x56, 0x68, 0x11, 0xE2, 0x0C, 0x99, 0xDE, 0x05, 0xAE, 0x68, 0x78, 0x85, 0x04, 0xAE}, /* 7.0.0 New Device Keygen Source. */
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* TODO: 8.1.0 New Device Key Source to be added on next change-of-keys. */
|
||||
};
|
||||
|
||||
static void derive_new_device_keys(unsigned int keygen_keyslot) {
|
||||
uint8_t work_buffer[0x10];
|
||||
bool is_retail = configitem_is_retail();
|
||||
for (unsigned int revision = 0; revision < MASTERKEY_NUM_NEW_DEVICE_KEYS; revision++) {
|
||||
const unsigned int relative_revision = revision + MASTERKEY_REVISION_400_410;
|
||||
|
||||
se_aes_ecb_decrypt_block(keygen_keyslot, work_buffer, 0x10, new_device_key_sources[revision], 0x10);
|
||||
decrypt_data_into_keyslot(KEYSLOT_SWITCH_TEMPKEY, mkey_get_keyslot(0), is_retail ? new_device_keygen_sources[revision] : new_device_keygen_sources_dev[revision], 0x10);
|
||||
if (revision < MASTERKEY_NUM_NEW_DEVICE_KEYS - 1) {
|
||||
se_aes_ecb_decrypt_block(KEYSLOT_SWITCH_TEMPKEY, work_buffer, 0x10, work_buffer, 0x10);
|
||||
set_old_devkey(revision + MASTERKEY_REVISION_400_410, work_buffer);
|
||||
if (relative_revision > mkey_get_revision()) {
|
||||
break;
|
||||
} else if (relative_revision == mkey_get_revision()) {
|
||||
/* On 7.0.0, sept will have derived this key for us already. */
|
||||
if (exosphere_get_target_firmware() < ATMOSPHERE_TARGET_FIRMWARE_700) {
|
||||
decrypt_data_into_keyslot(KEYSLOT_SWITCH_DEVICEKEY, KEYSLOT_SWITCH_TEMPKEY, work_buffer, 0x10);
|
||||
}
|
||||
} else {
|
||||
decrypt_data_into_keyslot(KEYSLOT_SWITCH_DEVICEKEY, KEYSLOT_SWITCH_TEMPKEY, work_buffer, 0x10);
|
||||
se_aes_ecb_decrypt_block(KEYSLOT_SWITCH_TEMPKEY, work_buffer, 0x10, work_buffer, 0x10);
|
||||
set_old_devkey(relative_revision, work_buffer);
|
||||
}
|
||||
}
|
||||
set_aes_keyslot_flags(KEYSLOT_SWITCH_DEVICEKEY, 0xFF);
|
||||
@@ -118,7 +103,8 @@ static void setup_se(void) {
|
||||
se->_0x0 &= 0xFFFEFFFF; /* Clear bit 16. */
|
||||
(void)(se->FLAGS_REG);
|
||||
__dsb_sy();
|
||||
|
||||
|
||||
/* NOTE: On 8.1.0+, Nintendo does not make keyslots 0-5 unreadable. */
|
||||
se->_0x4 = 0;
|
||||
se->AES_KEY_READ_DISABLE_REG = 0;
|
||||
se->RSA_KEY_READ_DISABLE_REG = 0;
|
||||
@@ -136,33 +122,6 @@ static void setup_se(void) {
|
||||
for (unsigned int i = 0; i < KEYSLOT_RSA_MAX; i++) {
|
||||
set_rsa_keyslot_flags(i, 0x41);
|
||||
}
|
||||
|
||||
if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_620 && exosphere_should_perform_620_keygen()) {
|
||||
unsigned int master_kek_source_ind;
|
||||
switch (exosphere_get_target_firmware()) {
|
||||
case ATMOSPHERE_TARGET_FIRMWARE_620:
|
||||
master_kek_source_ind = MASTERKEY_REVISION_620 - MASTERKEY_REVISION_620;
|
||||
break;
|
||||
case ATMOSPHERE_TARGET_FIRMWARE_700:
|
||||
case ATMOSPHERE_TARGET_FIRMWARE_800:
|
||||
master_kek_source_ind = MASTERKEY_REVISION_700_CURRENT - MASTERKEY_REVISION_620;
|
||||
break;
|
||||
default:
|
||||
generic_panic();
|
||||
break;
|
||||
}
|
||||
/* Start by generating device keys. */
|
||||
se_aes_ecb_decrypt_block(KEYSLOT_SWITCH_6XTSECKEY, work_buffer, 0x10, keyblob_key_seed_00, 0x10);
|
||||
decrypt_data_into_keyslot(KEYSLOT_SWITCH_4XOLDDEVICEKEY, KEYSLOT_SWITCH_6XSBK, work_buffer, 0x10);
|
||||
decrypt_data_into_keyslot(KEYSLOT_SWITCH_4XNEWCONSOLEKEYGENKEY, KEYSLOT_SWITCH_4XOLDDEVICEKEY, devicekey_4x_seed, 0x10);
|
||||
decrypt_data_into_keyslot(KEYSLOT_SWITCH_4XOLDDEVICEKEY, KEYSLOT_SWITCH_4XOLDDEVICEKEY, devicekey_seed, 0x10);
|
||||
|
||||
/* Next, generate the master kek, and from there master key/device kek. We use different keyslots than Nintendo, here. */
|
||||
decrypt_data_into_keyslot(KEYSLOT_SWITCH_6XTSECROOTKEY, KEYSLOT_SWITCH_6XTSECROOTKEY, new_master_kek_sources[master_kek_source_ind], 0x10);
|
||||
decrypt_data_into_keyslot(KEYSLOT_SWITCH_MASTERKEY, KEYSLOT_SWITCH_6XTSECROOTKEY, masterkey_seed, 0x10);
|
||||
decrypt_data_into_keyslot(KEYSLOT_SWITCH_5XNEWDEVICEKEYGENKEY, KEYSLOT_SWITCH_6XTSECROOTKEY, devicekek_4x_seed, 0x10);
|
||||
clear_aes_keyslot(KEYSLOT_SWITCH_6XTSECROOTKEY);
|
||||
}
|
||||
|
||||
/* Detect Master Key revision. */
|
||||
mkey_detect_revision();
|
||||
@@ -181,6 +140,7 @@ static void setup_se(void) {
|
||||
case ATMOSPHERE_TARGET_FIRMWARE_620:
|
||||
case ATMOSPHERE_TARGET_FIRMWARE_700:
|
||||
case ATMOSPHERE_TARGET_FIRMWARE_800:
|
||||
case ATMOSPHERE_TARGET_FIRMWARE_810:
|
||||
derive_new_device_keys(KEYSLOT_SWITCH_5XNEWDEVICEKEYGENKEY);
|
||||
break;
|
||||
}
|
||||
@@ -198,7 +158,7 @@ static void setup_se(void) {
|
||||
set_aes_keyslot_flags(KEYSLOT_SWITCH_SESSIONKEY, 0xFF);
|
||||
|
||||
/* Generate test vector for our keys. */
|
||||
se_generate_stored_vector();
|
||||
se_generate_stored_vector();
|
||||
}
|
||||
|
||||
static void setup_boot_config(void) {
|
||||
@@ -287,7 +247,7 @@ static bool validate_package2_metadata(package2_meta_t *metadata) {
|
||||
if (metadata->magic != MAGIC_PK21) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Package2 size, version number is stored XORed in header CTR. */
|
||||
/* Nintendo, what the fuck? */
|
||||
@@ -370,7 +330,7 @@ static bool validate_package2_metadata(package2_meta_t *metadata) {
|
||||
|
||||
/* Perform version checks. */
|
||||
/* We will be compatible with all package2s released before current, but not newer ones. */
|
||||
if (metadata->version_max >= PACKAGE2_MINVER_THEORETICAL && metadata->version_min < PACKAGE2_MAXVER_700_CURRENT) {
|
||||
if (metadata->version_max >= PACKAGE2_MINVER_THEORETICAL && metadata->version_min < PACKAGE2_MAXVER_810_CURRENT) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -495,21 +455,22 @@ static void copy_warmboot_bin_to_dram() {
|
||||
break;
|
||||
case ATMOSPHERE_TARGET_FIRMWARE_700:
|
||||
case ATMOSPHERE_TARGET_FIRMWARE_800:
|
||||
case ATMOSPHERE_TARGET_FIRMWARE_810:
|
||||
warmboot_src = (uint8_t *)0x4003E000;
|
||||
break;
|
||||
}
|
||||
uint8_t *warmboot_dst = (uint8_t *)0x8000D000;
|
||||
const size_t warmboot_size = 0x2000;
|
||||
|
||||
|
||||
/* Flush cache, to ensure warmboot is where we need it to be. */
|
||||
flush_dcache_range(warmboot_src, warmboot_src + warmboot_size);
|
||||
__dsb_sy();
|
||||
|
||||
|
||||
/* Copy warmboot. */
|
||||
for (size_t i = 0; i < warmboot_size; i += sizeof(uint32_t)) {
|
||||
write32le(warmboot_dst, i, read32le(warmboot_src, i));
|
||||
}
|
||||
|
||||
|
||||
/* Flush cache, to ensure warmboot is where we need it to be. */
|
||||
flush_dcache_range(warmboot_dst, warmboot_dst + warmboot_size);
|
||||
__dsb_sy();
|
||||
@@ -544,12 +505,12 @@ void load_package2(coldboot_crt0_reloc_list_t *reloc_list) {
|
||||
|
||||
/* Setup the Security Engine. */
|
||||
setup_se();
|
||||
|
||||
|
||||
/* Perform initial PMC register writes, if relevant. */
|
||||
if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_400) {
|
||||
MAKE_REG32(PMC_BASE + 0x054) = 0x8000D000;
|
||||
MAKE_REG32(PMC_BASE + 0x0A0) &= 0xFFF3FFFF;
|
||||
MAKE_REG32(PMC_BASE + 0x818) &= 0xFFFFFFFE;
|
||||
MAKE_REG32(PMC_BASE + 0x054) = 0x8000D000;
|
||||
MAKE_REG32(PMC_BASE + 0x0A0) &= 0xFFF3FFFF;
|
||||
MAKE_REG32(PMC_BASE + 0x818) &= 0xFFFFFFFE;
|
||||
MAKE_REG32(PMC_BASE + 0x334) |= 0x10;
|
||||
switch (exosphere_get_target_firmware()) {
|
||||
case ATMOSPHERE_TARGET_FIRMWARE_400:
|
||||
@@ -568,6 +529,9 @@ void load_package2(coldboot_crt0_reloc_list_t *reloc_list) {
|
||||
case ATMOSPHERE_TARGET_FIRMWARE_800:
|
||||
MAKE_REG32(PMC_BASE + 0x360) = 0x129;
|
||||
break;
|
||||
case ATMOSPHERE_TARGET_FIRMWARE_810:
|
||||
MAKE_REG32(PMC_BASE + 0x360) = 0x14A;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -585,7 +549,7 @@ void load_package2(coldboot_crt0_reloc_list_t *reloc_list) {
|
||||
|
||||
/* memclear the initial copy of Exosphere running in IRAM (relocated to TZRAM by earlier code). */
|
||||
/* memset((void *)reloc_list->reloc_base, 0, reloc_list->loaded_bin_size); */
|
||||
|
||||
|
||||
/* Let NX Bootloader know that we're running. */
|
||||
MAILBOX_NX_BOOTLOADER_IS_SECMON_AWAKE(exosphere_get_target_firmware()) = 1;
|
||||
|
||||
@@ -597,7 +561,7 @@ void load_package2(coldboot_crt0_reloc_list_t *reloc_list) {
|
||||
|
||||
/* Load Boot Config into global. */
|
||||
setup_boot_config();
|
||||
|
||||
|
||||
/* Set sysctr0 registers based on bootconfig. */
|
||||
if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_400) {
|
||||
uint64_t sysctr0_val = bootconfig_get_value_for_sysctr0();
|
||||
@@ -620,7 +584,7 @@ void load_package2(coldboot_crt0_reloc_list_t *reloc_list) {
|
||||
|
||||
/* Make PMC (2.x+), MC (4.x+) registers secure-only */
|
||||
secure_additional_devices();
|
||||
|
||||
|
||||
/* Remove the identity mapping for iRAM-C+D & TZRAM */
|
||||
/* For our crt0 to work, this doesn't actually unmap TZRAM */
|
||||
identity_unmap_iram_cd_tzram();
|
||||
@@ -630,7 +594,7 @@ void load_package2(coldboot_crt0_reloc_list_t *reloc_list) {
|
||||
flush_dcache_range((uint8_t *)NX_BOOTLOADER_PACKAGE2_LOAD_ADDRESS, (uint8_t *)NX_BOOTLOADER_PACKAGE2_LOAD_ADDRESS + sizeof(header));
|
||||
memcpy(&header, NX_BOOTLOADER_PACKAGE2_LOAD_ADDRESS, sizeof(header));
|
||||
flush_dcache_range((uint8_t *)&header, (uint8_t *)&header + sizeof(header));
|
||||
|
||||
|
||||
/* Perform signature checks. */
|
||||
/* Special exosphere patching enable: All-zeroes signature + decrypted header implies unsigned and decrypted package2. */
|
||||
if (header.signature[0] == 0 && memcmp(header.signature, header.signature + 1, sizeof(header.signature) - 1) == 0 && header.metadata.magic == MAGIC_PK21) {
|
||||
@@ -641,7 +605,7 @@ void load_package2(coldboot_crt0_reloc_list_t *reloc_list) {
|
||||
|
||||
/* Decrypt header, get key revision required. */
|
||||
uint32_t package2_mkey_rev = decrypt_and_validate_header(&header);
|
||||
|
||||
|
||||
/* Copy hash, if necessary. */
|
||||
if (bootconfig_is_recovery_boot()) {
|
||||
bootconfig_set_package2_hash_for_recovery(NX_BOOTLOADER_PACKAGE2_LOAD_ADDRESS, get_package2_size(&header.metadata));
|
||||
@@ -649,7 +613,7 @@ void load_package2(coldboot_crt0_reloc_list_t *reloc_list) {
|
||||
|
||||
/* Load Package2 Sections. */
|
||||
load_package2_sections(&header.metadata, package2_mkey_rev);
|
||||
|
||||
|
||||
/* Clean up cache. */
|
||||
flush_dcache_all();
|
||||
invalidate_icache_all(); /* non-broadcasting */
|
||||
@@ -660,7 +624,7 @@ void load_package2(coldboot_crt0_reloc_list_t *reloc_list) {
|
||||
/* Remove the DRAM identity mapping. */
|
||||
if (0) {
|
||||
identity_unmap_dram();
|
||||
}
|
||||
}
|
||||
|
||||
/* Synchronize with NX BOOTLOADER. */
|
||||
if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_400) {
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
* 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 EXOSPHERE_PACKAGE2_H
|
||||
#define EXOSPHERE_PACKAGE2_H
|
||||
|
||||
@@ -70,7 +70,8 @@ static inline uintptr_t get_nx_bootloader_mailbox_base(unsigned int targetfw) {
|
||||
#define PACKAGE2_MAXVER_500_510 0x7
|
||||
#define PACKAGE2_MAXVER_600_610 0x8
|
||||
#define PACKAGE2_MAXVER_620 0x9
|
||||
#define PACKAGE2_MAXVER_700_CURRENT 0xA
|
||||
#define PACKAGE2_MAXVER_700_800 0xA
|
||||
#define PACKAGE2_MAXVER_810_CURRENT 0xB
|
||||
|
||||
#define PACKAGE2_MINVER_100 0x3
|
||||
#define PACKAGE2_MINVER_200 0x4
|
||||
@@ -80,7 +81,8 @@ static inline uintptr_t get_nx_bootloader_mailbox_base(unsigned int targetfw) {
|
||||
#define PACKAGE2_MINVER_500_510 0x8
|
||||
#define PACKAGE2_MINVER_600_610 0x9
|
||||
#define PACKAGE2_MINVER_620 0xA
|
||||
#define PACKAGE2_MINVER_700_CURRENT 0xB
|
||||
#define PACKAGE2_MINVER_700_800 0xB
|
||||
#define PACKAGE2_MINVER_810_CURRENT 0xC
|
||||
|
||||
typedef struct {
|
||||
union {
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
* 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 <stdatomic.h>
|
||||
#include <stdint.h>
|
||||
|
||||
@@ -185,6 +185,7 @@ void set_version_specific_smcs(void) {
|
||||
case ATMOSPHERE_TARGET_FIRMWARE_620:
|
||||
case ATMOSPHERE_TARGET_FIRMWARE_700:
|
||||
case ATMOSPHERE_TARGET_FIRMWARE_800:
|
||||
case ATMOSPHERE_TARGET_FIRMWARE_810:
|
||||
/* No more LoadSecureExpModKey. */
|
||||
g_smc_user_table[0xE].handler = NULL;
|
||||
g_smc_user_table[0xC].id = 0xC300D60C;
|
||||
@@ -256,7 +257,7 @@ void call_smc_handler(uint32_t handler_id, smc_args_t *args) {
|
||||
unsigned char smc_id, call_range;
|
||||
unsigned int result;
|
||||
unsigned int (*smc_handler)(smc_args_t *args);
|
||||
|
||||
|
||||
/* Validate top-level handler. */
|
||||
if (handler_id >= SMC_HANDLER_COUNT) {
|
||||
generic_panic();
|
||||
@@ -288,17 +289,17 @@ void call_smc_handler(uint32_t handler_id, smc_args_t *args) {
|
||||
if ((smc_handler = g_smc_tables[handler_id].handlers[smc_id].handler) == NULL) {
|
||||
generic_panic();
|
||||
}
|
||||
|
||||
|
||||
bool is_aes_kek = handler_id == SMC_HANDLER_USER && args->X[0] == 0xC3000007;
|
||||
|
||||
#if DEBUG_LOG_SMCS
|
||||
uint64_t num;
|
||||
#if DEBUG_LOG_SMCS
|
||||
uint64_t num;
|
||||
if (handler_id == SMC_HANDLER_USER) {
|
||||
num = atomic_fetch_add(&num_smcs_called, 1);
|
||||
*(volatile smc_args_t *)(get_iram_address_for_debug() + 0x100 + ((0x80 * num) & 0x3FFF)) = *args;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/* Call function. */
|
||||
if (exosphere_get_target_firmware() < ATMOSPHERE_TARGET_FIRMWARE_800 ||
|
||||
(g_smc_tables[handler_id].handlers[smc_id].blacklist_mask & g_smc_blacklist_mask) == 0) {
|
||||
@@ -307,15 +308,15 @@ void call_smc_handler(uint32_t handler_id, smc_args_t *args) {
|
||||
/* Call not allowed due to current boot conditions. */
|
||||
args->X[0] = 6;
|
||||
}
|
||||
|
||||
#if DEBUG_LOG_SMCS
|
||||
|
||||
#if DEBUG_LOG_SMCS
|
||||
if (handler_id == SMC_HANDLER_USER) {
|
||||
*(volatile smc_args_t *)(get_iram_address_for_debug() + 0x100 + ((0x80 * num + 0x40) & 0x3FFF)) = *args;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#if DEBUG_PANIC_ON_FAILURE
|
||||
if (args->X[0] && (!is_aes_kek || args->X[3] <= ATMOSPHERE_TARGET_FIRMWARE_DEFAULT_FOR_DEBUG))
|
||||
if (args->X[0] && (!is_aes_kek || args->X[3] <= ATMOSPHERE_TARGET_FIRMWARE_DEFAULT_FOR_DEBUG))
|
||||
{
|
||||
MAKE_REG32(get_iram_address_for_debug() + 0x4FF0) = handler_id;
|
||||
MAKE_REG32(get_iram_address_for_debug() + 0x4FF4) = smc_id;
|
||||
@@ -695,14 +696,14 @@ uint32_t smc_configure_carveout(smc_args_t *args) {
|
||||
if (size > KERNEL_CARVEOUT_SIZE_MAX) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
|
||||
/* Ensure validity of carveout index. */
|
||||
if (carveout_id > 1) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
/* Configuration is one-shot, and cannot be done multiple times. */
|
||||
if (exosphere_get_target_firmware() < ATMOSPHERE_TARGET_FIRMWARE_300) {
|
||||
if (exosphere_get_target_firmware() < ATMOSPHERE_TARGET_FIRMWARE_300) {
|
||||
if (g_configured_carveouts[carveout_id]) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
* 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 <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
@@ -52,6 +52,7 @@ static bool is_user_keyslot_valid(unsigned int keyslot) {
|
||||
case ATMOSPHERE_TARGET_FIRMWARE_620:
|
||||
case ATMOSPHERE_TARGET_FIRMWARE_700:
|
||||
case ATMOSPHERE_TARGET_FIRMWARE_800:
|
||||
case ATMOSPHERE_TARGET_FIRMWARE_810:
|
||||
default:
|
||||
return keyslot <= 5;
|
||||
}
|
||||
@@ -165,7 +166,7 @@ uint32_t user_generate_aes_kek(smc_args_t *args) {
|
||||
bool is_personalized = (int)(packed_options & 1);
|
||||
|
||||
bool is_recovery_boot = configitem_is_recovery_boot();
|
||||
|
||||
|
||||
/* 5.0.0+ Bounds checking. */
|
||||
if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_500) {
|
||||
if (is_personalized) {
|
||||
@@ -295,7 +296,7 @@ uint32_t crypt_aes_done_handler(void) {
|
||||
uint32_t user_crypt_aes(smc_args_t *args) {
|
||||
uint32_t keyslot = args->X[1] & 3;
|
||||
uint32_t mode = (args->X[1] >> 4) & 3;
|
||||
|
||||
|
||||
if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_600) {
|
||||
keyslot = args->X[1] & 7;
|
||||
}
|
||||
@@ -791,7 +792,7 @@ uint32_t user_encrypt_rsa_key_for_import(smc_args_t *args) {
|
||||
|
||||
if (usecase > CRYPTOUSECASE_RSAIMPORT) {
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
if (usecase == 0) {
|
||||
if (size < 0x31 || size > 0x240) {
|
||||
return 2;
|
||||
@@ -823,7 +824,7 @@ uint32_t user_encrypt_rsa_key_for_import(smc_args_t *args) {
|
||||
|
||||
if (secure_copy_to_user(&page_ref, user_address, user_data, size) == 0) {
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -854,7 +855,7 @@ uint32_t user_decrypt_or_import_rsa_key(smc_args_t *args) {
|
||||
|
||||
if (usecase > CRYPTOUSECASE_RSAIMPORT) {
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
if (usecase == 0) {
|
||||
if (size < 0x31 || size > 0x240) {
|
||||
return 2;
|
||||
@@ -881,7 +882,7 @@ uint32_t user_decrypt_or_import_rsa_key(smc_args_t *args) {
|
||||
case 0:
|
||||
if (secure_copy_to_user(&page_ref, user_address, user_data, size) == 0) {
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
case 1:
|
||||
exponent_id = 1;
|
||||
|
||||
@@ -99,7 +99,7 @@ SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
|
||||
KIPFILES := loader.kip pm.kip sm.kip ams_mitm.kip spl.kip boot.kip
|
||||
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) fusee-primary.bin \
|
||||
exosphere.bin lp0fw.bin rebootstub.bin thermosphere.bin splash_screen.bmp \
|
||||
sept-primary.bin sept-secondary.enc emummc.kip \
|
||||
sept-primary.bin sept-secondary_00.enc sept-secondary_01.enc emummc.kip \
|
||||
$(KIPFILES)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
@@ -198,22 +198,27 @@ fusee_primary.bin.o fusee_primary_bin.h: fusee-primary.bin
|
||||
#---------------------------------------------------------------------------------
|
||||
@echo $(notdir $<)
|
||||
@$(_bin2o)
|
||||
|
||||
|
||||
sept_primary.bin.o sept_primary_bin.h: sept-primary.bin
|
||||
#---------------------------------------------------------------------------------
|
||||
@echo $(notdir $<)
|
||||
@$(_bin2o)
|
||||
|
||||
sept_secondary.enc.o sept_secondary_enc.h: sept-secondary.enc
|
||||
|
||||
sept_secondary_00.enc.o sept_secondary_00.h: sept-secondary_00.enc
|
||||
#---------------------------------------------------------------------------------
|
||||
@echo $(notdir $<)
|
||||
@$(_bin2o)
|
||||
|
||||
|
||||
sept_secondary_01.enc.o sept_secondary_01_enc.h: sept-secondary_01.enc
|
||||
#---------------------------------------------------------------------------------
|
||||
@echo $(notdir $<)
|
||||
@$(_bin2o)
|
||||
|
||||
%.bin.o %_bin.h: %.bin
|
||||
#---------------------------------------------------------------------------------
|
||||
@echo $(notdir $<)
|
||||
@$(bin2o)
|
||||
|
||||
|
||||
%.bmp.o %_bmp.h: %.bmp
|
||||
#---------------------------------------------------------------------------------
|
||||
@echo $(notdir $<)
|
||||
|
||||
@@ -55,7 +55,7 @@ SECTIONS
|
||||
. = ALIGN(32);
|
||||
PROVIDE (__chainloader_end__ = ABSOLUTE(.));
|
||||
} >low_iram :NONE
|
||||
|
||||
|
||||
.nxboot_loadable :
|
||||
{
|
||||
. = ALIGN(32);
|
||||
@@ -157,7 +157,7 @@ SECTIONS
|
||||
CONSTRUCTORS
|
||||
. = ALIGN(32);
|
||||
} >main
|
||||
|
||||
|
||||
__data_end__ = ABSOLUTE(.);
|
||||
PROVIDE (__total_size__ = (__data_end__ - __start__));
|
||||
|
||||
@@ -236,8 +236,10 @@ SECTIONS
|
||||
PROVIDE(__rebootstub_bin_size__ = rebootstub_bin_end - rebootstub_bin);
|
||||
PROVIDE(__sept_primary_bin_start__ = sept_primary_bin - __start__);
|
||||
PROVIDE(__sept_primary_bin_size__ = sept_primary_bin_end - sept_primary_bin);
|
||||
PROVIDE(__sept_secondary_enc_start__ = sept_secondary_enc - __start__);
|
||||
PROVIDE(__sept_secondary_enc_size__ = sept_secondary_enc_end - sept_secondary_enc);
|
||||
PROVIDE(__sept_secondary_00_enc_start__ = sept_secondary_00_enc - __start__);
|
||||
PROVIDE(__sept_secondary_00_enc_size__ = sept_secondary_00_enc_end - sept_secondary_00_enc);
|
||||
PROVIDE(__sept_secondary_01_enc_start__ = sept_secondary_01_enc - __start__);
|
||||
PROVIDE(__sept_secondary_01_enc_size__ = sept_secondary_01_enc_end - sept_secondary_01_enc);
|
||||
PROVIDE(__sm_kip_start__ = sm_kip - __start__);
|
||||
PROVIDE(__sm_kip_size__ = sm_kip_end - sm_kip);
|
||||
PROVIDE(__spl_kip_start__ = spl_kip - __start__);
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
* 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 EXOSPHERE_EMUMMC_CONFIG_H
|
||||
#define EXOSPHERE_EMUMMC_CONFIG_H
|
||||
|
||||
@@ -73,6 +73,9 @@ typedef enum {
|
||||
FS_VER_8_0_0,
|
||||
FS_VER_8_0_0_EXFAT,
|
||||
|
||||
FS_VER_8_1_0,
|
||||
FS_VER_8_1_0_EXFAT,
|
||||
|
||||
FS_VER_MAX,
|
||||
} emummc_fs_ver_t;
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
* 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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
@@ -46,7 +46,7 @@ static bool should_ignore_default_patch(const char *patch_dir) {
|
||||
if (!g_enable_nogc_patches && strcmp(patch_dir, NOGC_PATCH_DIR) == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -64,7 +64,7 @@ static bool has_patch(const char *dir, const char *subdir, const void *hash, siz
|
||||
if (cur_len >= sizeof(path)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
FILE *f = fopen(path, "rb");
|
||||
if (f != NULL) {
|
||||
fclose(f);
|
||||
@@ -77,7 +77,7 @@ static bool has_needed_default_kip_patches(uint64_t title_id, const void *hash,
|
||||
if (title_id == 0x0100000000000000ULL && g_enable_nogc_patches) {
|
||||
return has_patch("atmosphere/kip_patches", NOGC_PATCH_DIR, hash, hash_size);
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -90,7 +90,7 @@ static void apply_ips_patch(uint8_t *mem, size_t mem_size, size_t prot_size, boo
|
||||
} else if (!is_ips32 && memcmp(buffer, IPS_TAIL, 3) == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
/* Offset of patch. */
|
||||
uint32_t patch_offset;
|
||||
if (is_ips32) {
|
||||
@@ -98,27 +98,27 @@ static void apply_ips_patch(uint8_t *mem, size_t mem_size, size_t prot_size, boo
|
||||
} else {
|
||||
patch_offset = (buffer[0] << 16) | (buffer[1] << 8) | (buffer[2]);
|
||||
}
|
||||
|
||||
|
||||
/* Size of patch. */
|
||||
if (fread(buffer, 2, 1, f_ips) != 1) {
|
||||
break;
|
||||
}
|
||||
uint32_t patch_size = (buffer[0] << 8) | (buffer[1]);
|
||||
|
||||
|
||||
/* Check for RLE encoding. */
|
||||
if (patch_size == 0) {
|
||||
/* Size of RLE. */
|
||||
if (fread(buffer, 2, 1, f_ips) != 1) {
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
uint32_t rle_size = (buffer[0] << 8) | (buffer[1]);
|
||||
|
||||
|
||||
/* Value for RLE. */
|
||||
if (fread(buffer, 1, 1, f_ips) != 1) {
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
if (patch_offset < prot_size) {
|
||||
if (patch_offset + rle_size > prot_size) {
|
||||
uint32_t diff = prot_size - patch_offset;
|
||||
@@ -187,7 +187,7 @@ static bool name_matches_hash(const char *name, size_t name_len, const void *has
|
||||
hash_from_name[id_ofs] |= hex_nybble_to_u8(name[name_ofs++]) << 4;
|
||||
hash_from_name[id_ofs] |= hex_nybble_to_u8(name[name_ofs++]);
|
||||
}
|
||||
|
||||
|
||||
return memcmp(hash, hash_from_name, hash_size) == 0;
|
||||
|
||||
}
|
||||
@@ -204,11 +204,11 @@ static bool has_ips_patches(const char *dir, const void *hash, size_t hash_size)
|
||||
if (strcmp(pdir_ent->d_name, ".") == 0 || strcmp(pdir_ent->d_name, "..") == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
if (should_ignore_default_patch(pdir_ent->d_name)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
snprintf(path, sizeof(path) - 1, "%s/%s", dir, pdir_ent->d_name);
|
||||
DIR *patch_dir = opendir(path);
|
||||
struct dirent *ent;
|
||||
@@ -218,7 +218,7 @@ static bool has_ips_patches(const char *dir, const void *hash, size_t hash_size)
|
||||
if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
size_t name_len = strlen(ent->d_name);
|
||||
if ((4 < name_len && name_len <= 0x44) && ((name_len & 1) == 0) && strcmp(ent->d_name + name_len - 4, ".ips") == 0 && name_matches_hash(ent->d_name, name_len, hash, hash_size)) {
|
||||
snprintf(path, sizeof(path) - 1, "%s/%s/%s", dir, pdir_ent->d_name, ent->d_name);
|
||||
@@ -254,11 +254,11 @@ static void apply_ips_patches(const char *dir, void *mem, size_t mem_size, size_
|
||||
if (strcmp(pdir_ent->d_name, ".") == 0 || strcmp(pdir_ent->d_name, "..") == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
if (should_ignore_default_patch(pdir_ent->d_name)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
snprintf(path, sizeof(path) - 1, "%s/%s", dir, pdir_ent->d_name);
|
||||
DIR *patch_dir = opendir(path);
|
||||
struct dirent *ent;
|
||||
@@ -268,7 +268,7 @@ static void apply_ips_patches(const char *dir, void *mem, size_t mem_size, size_
|
||||
if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
size_t name_len = strlen(ent->d_name);
|
||||
if ((4 < name_len && name_len <= 0x44) && ((name_len & 1) == 0) && strcmp(ent->d_name + name_len - 4, ".ips") == 0 && name_matches_hash(ent->d_name, name_len, hash, hash_size)) {
|
||||
snprintf(path, sizeof(path) - 1, "%s/%s/%s", dir, pdir_ent->d_name, ent->d_name);
|
||||
@@ -291,7 +291,7 @@ static void apply_ips_patches(const char *dir, void *mem, size_t mem_size, size_
|
||||
}
|
||||
closedir(patches_dir);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void apply_kernel_ips_patches(void *kernel, size_t kernel_size) {
|
||||
uint8_t hash[0x20];
|
||||
@@ -304,16 +304,16 @@ static void kip1_blz_uncompress(void *hdr_end) {
|
||||
uint32_t addl_size = ((u8_hdr_end[-4]) << 0) | ((u8_hdr_end[-3]) << 8) | ((u8_hdr_end[-2]) << 16) | ((u8_hdr_end[-1]) << 24);
|
||||
uint32_t header_size = ((u8_hdr_end[-8]) << 0) | ((u8_hdr_end[-7]) << 8) | ((u8_hdr_end[-6]) << 16) | ((u8_hdr_end[-5]) << 24);
|
||||
uint32_t cmp_and_hdr_size = ((u8_hdr_end[-12]) << 0) | ((u8_hdr_end[-11]) << 8) | ((u8_hdr_end[-10]) << 16) | ((u8_hdr_end[-9]) << 24);
|
||||
|
||||
|
||||
unsigned char *cmp_start = (unsigned char *)(((uintptr_t)hdr_end) - cmp_and_hdr_size);
|
||||
uint32_t cmp_ofs = cmp_and_hdr_size - header_size;
|
||||
uint32_t out_ofs = cmp_and_hdr_size + addl_size;
|
||||
|
||||
|
||||
while (out_ofs) {
|
||||
unsigned char control = cmp_start[--cmp_ofs];
|
||||
for (unsigned int i = 0; i < 8; i++) {
|
||||
if (control & 0x80) {
|
||||
if (cmp_ofs < 2) {
|
||||
if (cmp_ofs < 2) {
|
||||
fatal_error("KIP1 decompression out of bounds!\n");
|
||||
}
|
||||
cmp_ofs -= 2;
|
||||
@@ -325,7 +325,7 @@ static void kip1_blz_uncompress(void *hdr_end) {
|
||||
seg_size = out_ofs;
|
||||
}
|
||||
out_ofs -= seg_size;
|
||||
|
||||
|
||||
for (unsigned int j = 0; j < seg_size; j++) {
|
||||
cmp_start[out_ofs + j] = cmp_start[out_ofs + j + seg_ofs];
|
||||
}
|
||||
@@ -350,15 +350,15 @@ kip1_header_t *kip1_uncompress(kip1_header_t *kip, size_t *size) {
|
||||
new_header.section_headers[i].compressed_size = new_header.section_headers[i].out_size;
|
||||
}
|
||||
new_header.flags &= 0xF8;
|
||||
|
||||
|
||||
*size = kip1_get_size_from_header(&new_header);
|
||||
|
||||
|
||||
unsigned char *new_kip = calloc(1, *size);
|
||||
if (new_kip == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
*((kip1_header_t *)new_kip) = new_header;
|
||||
|
||||
|
||||
size_t new_offset = 0x100;
|
||||
size_t old_offset = 0x100;
|
||||
for (unsigned int i = 0; i < 3; i++) {
|
||||
@@ -369,7 +369,7 @@ kip1_header_t *kip1_uncompress(kip1_header_t *kip, size_t *size) {
|
||||
new_offset += kip->section_headers[i].out_size;
|
||||
old_offset += kip->section_headers[i].compressed_size;
|
||||
}
|
||||
|
||||
|
||||
return (kip1_header_t *)new_kip;
|
||||
}
|
||||
|
||||
@@ -408,12 +408,15 @@ static const uint8_t g_fs_hashes[FS_VER_MAX][0x8] = {
|
||||
|
||||
"\xB2\xF5\x17\x6B\x35\x48\x36\x4D", /* FS_VER_8_0_0 */
|
||||
"\xDB\xD9\x41\xC0\xC5\x3C\x52\xCC", /* FS_VER_8_0_0_EXFAT */
|
||||
|
||||
"\x6B\x09\xB6\x7B\x29\xC0\x20\x24", /* FS_VER_8_1_0 */
|
||||
"\xB4\xCA\xE1\xF2\x49\x65\xD9\x2E", /* FS_VER_8_1_0_EXFAT */
|
||||
};
|
||||
|
||||
kip1_header_t *apply_kip_ips_patches(kip1_header_t *kip, size_t kip_size, emummc_fs_ver_t *out_fs_ver) {
|
||||
uint8_t hash[0x20];
|
||||
se_calculate_sha256(hash, kip, kip_size);
|
||||
|
||||
|
||||
if (kip->title_id == FS_TITLE_ID) {
|
||||
bool found = false;
|
||||
for (size_t i = 0; i < FS_VER_MAX; i++) {
|
||||
@@ -426,24 +429,24 @@ kip1_header_t *apply_kip_ips_patches(kip1_header_t *kip, size_t kip_size, emummc
|
||||
fatal_error("[NXBOOT]: Failed to identify FS version...");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!has_needed_default_kip_patches(kip->title_id, hash, sizeof(hash))) {
|
||||
fatal_error("[NXBOOT]: Missing default patch for KIP %08x%08x...\n", (uint32_t)(kip->title_id >> 32), (uint32_t)kip->title_id);
|
||||
}
|
||||
|
||||
|
||||
if (!has_ips_patches("atmosphere/kip_patches", hash, sizeof(hash))) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
print(SCREEN_LOG_LEVEL_MANDATORY, "[NXBOOT]: Patching KIP %08x%08x...\n", (uint32_t)(kip->title_id >> 32), (uint32_t)kip->title_id);
|
||||
|
||||
|
||||
|
||||
|
||||
size_t uncompressed_kip_size;
|
||||
kip1_header_t *uncompressed_kip = kip1_uncompress(kip, &uncompressed_kip_size);
|
||||
if (uncompressed_kip == NULL) {
|
||||
if (uncompressed_kip == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
apply_ips_patches("atmosphere/kip_patches", uncompressed_kip, uncompressed_kip_size, 0x100, hash, sizeof(hash));
|
||||
return uncompressed_kip;
|
||||
}
|
||||
|
||||
@@ -54,7 +54,8 @@ static const uint8_t AL16 masterkey_4x_seed[0x10] = {
|
||||
0x2D, 0xC1, 0xF4, 0x8D, 0xF3, 0x5B, 0x69, 0x33, 0x42, 0x10, 0xAC, 0x65, 0xDA, 0x90, 0x46, 0x66
|
||||
};
|
||||
|
||||
static const uint8_t AL16 new_master_kek_seeds[MASTERKEY_REVISION_700_CURRENT - MASTERKEY_REVISION_600_610][0x10] = {
|
||||
/* TODO: Bother adding 8.1.0 here? We'll never call into here... */
|
||||
static const uint8_t AL16 new_master_kek_seeds[MASTERKEY_REVISION_700_800 - MASTERKEY_REVISION_600_610][0x10] = {
|
||||
{0x37, 0x4B, 0x77, 0x29, 0x59, 0xB4, 0x04, 0x30, 0x81, 0xF6, 0xE5, 0x8C, 0x6D, 0x36, 0x17, 0x9A}, /* MasterKek seed 06. */
|
||||
{0x9A, 0x3E, 0xA9, 0xAB, 0xFD, 0x56, 0x46, 0x1C, 0x9B, 0xF6, 0x48, 0x7F, 0x5C, 0xFA, 0x09, 0x5C}, /* MasterKek seed 07. */
|
||||
};
|
||||
@@ -93,17 +94,17 @@ static int decrypt_keyblob(const nx_keyblob_t *keyblobs, uint32_t revision, uint
|
||||
if (get_keyblob(&keyblob, revision, keyblobs, available_revision) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
se_aes_ecb_decrypt_block(0xD, work_buffer, 0x10, keyblob_seeds[revision], 0x10);
|
||||
decrypt_data_into_keyslot(keyslot, 0xE, work_buffer, 0x10);
|
||||
decrypt_data_into_keyslot(0xB, keyslot, keyblob_mac_seed, 0x10);
|
||||
|
||||
|
||||
/* Validate keyblob. */
|
||||
se_compute_aes_128_cmac(0xB, work_buffer, 0x10, keyblob.mac + sizeof(keyblob.mac), sizeof(keyblob) - sizeof(keyblob.mac));
|
||||
if (safe_memcmp(keyblob.mac, work_buffer, 0x10)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/* Decrypt keyblob. */
|
||||
se_aes_ctr_crypt(keyslot, &g_dec_keyblobs[revision], sizeof(g_dec_keyblobs[revision]), keyblob.data, sizeof(keyblob.data), keyblob.ctr, sizeof(keyblob.ctr));
|
||||
return 0;
|
||||
@@ -113,7 +114,7 @@ int load_package1_key(uint32_t revision) {
|
||||
if (revision > MASTERKEY_REVISION_600_610) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
set_aes_keyslot(0xB, g_dec_keyblobs[revision].package1_key, 0x10);
|
||||
return 0;
|
||||
}
|
||||
@@ -122,17 +123,17 @@ int load_package1_key(uint32_t revision) {
|
||||
int derive_nx_keydata(uint32_t target_firmware, const nx_keyblob_t *keyblobs, uint32_t available_revision, const void *tsec_key, void *tsec_root_keys, unsigned int *out_keygen_type) {
|
||||
uint8_t AL16 work_buffer[0x10];
|
||||
uint8_t AL16 zeroes[0x10] = {0};
|
||||
|
||||
|
||||
/* Initialize keygen type. */
|
||||
*out_keygen_type = 0;
|
||||
|
||||
/* TODO: Set keyslot flags properly in preparation of derivation. */
|
||||
set_aes_keyslot_flags(0xE, 0x15);
|
||||
set_aes_keyslot_flags(0xD, 0x15);
|
||||
|
||||
|
||||
/* Set the TSEC key. */
|
||||
set_aes_keyslot(0xD, tsec_key, 0x10);
|
||||
|
||||
|
||||
/* Decrypt all keyblobs, setting keyslot 0xF correctly. */
|
||||
for (unsigned int rev = 0; rev <= MASTERKEY_REVISION_600_610; rev++) {
|
||||
int ret = decrypt_keyblob(keyblobs, rev, available_revision);
|
||||
@@ -150,13 +151,16 @@ int derive_nx_keydata(uint32_t target_firmware, const nx_keyblob_t *keyblobs, ui
|
||||
break;
|
||||
case ATMOSPHERE_TARGET_FIRMWARE_700:
|
||||
case ATMOSPHERE_TARGET_FIRMWARE_800:
|
||||
desired_keyblob = MASTERKEY_REVISION_700_CURRENT;
|
||||
desired_keyblob = MASTERKEY_REVISION_700_800;
|
||||
break;
|
||||
case ATMOSPHERE_TARGET_FIRMWARE_810:
|
||||
desired_keyblob = MASTERKEY_REVISION_810_CURRENT;
|
||||
break;
|
||||
default:
|
||||
fatal_error("Unknown target firmware: %02x!", target_firmware);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
/* Try emulation result. */
|
||||
for (unsigned int rev = MASTERKEY_REVISION_620; rev < MASTERKEY_REVISION_MAX; rev++) {
|
||||
void *tsec_root_key = (void *)((uintptr_t)tsec_root_keys + 0x10 * (rev - MASTERKEY_REVISION_620));
|
||||
@@ -167,7 +171,7 @@ int derive_nx_keydata(uint32_t target_firmware, const nx_keyblob_t *keyblobs, ui
|
||||
memcpy(g_dec_keyblobs[rev].master_kek, work_buffer, 0x10);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (memcmp(g_dec_keyblobs[desired_keyblob].master_kek, zeroes, 0x10) == 0) {
|
||||
/* Try reading the keys from a file. */
|
||||
const char *keyfile = fuse_get_retail_type() != 0 ? "atmosphere/prod.keys" : "atmosphere/dev.keys";
|
||||
@@ -188,13 +192,13 @@ int derive_nx_keydata(uint32_t target_firmware, const nx_keyblob_t *keyblobs, ui
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
if (memcmp(g_dec_keyblobs[available_revision].master_kek, zeroes, 0x10) == 0) {
|
||||
fatal_error("Error: failed to derive master_kek_%02x!", available_revision);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Clear the SBK. */
|
||||
clear_aes_keyslot(0xE);
|
||||
|
||||
@@ -225,6 +229,7 @@ int derive_nx_keydata(uint32_t target_firmware, const nx_keyblob_t *keyblobs, ui
|
||||
case ATMOSPHERE_TARGET_FIRMWARE_620:
|
||||
case ATMOSPHERE_TARGET_FIRMWARE_700:
|
||||
case ATMOSPHERE_TARGET_FIRMWARE_800:
|
||||
case ATMOSPHERE_TARGET_FIRMWARE_810:
|
||||
decrypt_data_into_keyslot(0xA, 0xF, devicekey_4x_seed, 0x10);
|
||||
decrypt_data_into_keyslot(0xF, 0xF, devicekey_seed, 0x10);
|
||||
decrypt_data_into_keyslot(0xE, 0xC, masterkey_4x_seed, 0x10);
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
* 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 <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
@@ -39,6 +39,7 @@ static const uint8_t mkey_vectors_dev[MASTERKEY_REVISION_MAX][0x10] =
|
||||
{0x78, 0xD5, 0xF1, 0x20, 0x3D, 0x16, 0xE9, 0x30, 0x32, 0x27, 0x34, 0x6F, 0xCF, 0xE0, 0x27, 0xDC}, /* Master key 04 encrypted with Master key 05. */
|
||||
{0x6F, 0xD2, 0x84, 0x1D, 0x05, 0xEC, 0x40, 0x94, 0x5F, 0x18, 0xB3, 0x81, 0x09, 0x98, 0x8D, 0x4E}, /* Master key 05 encrypted with Master key 06. */
|
||||
{0x37, 0xAF, 0xAB, 0x35, 0x79, 0x09, 0xD9, 0x48, 0x29, 0xD2, 0xDB, 0xA5, 0xA5, 0xF5, 0x30, 0x19}, /* Master key 06 encrypted with Master key 07. */
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* TODO: Master key 07 encrypted with Master key 08. */
|
||||
};
|
||||
|
||||
/* Retail unit keys. */
|
||||
@@ -52,6 +53,7 @@ static const uint8_t mkey_vectors[MASTERKEY_REVISION_MAX][0x10] =
|
||||
{0xEB, 0xF5, 0x6F, 0x83, 0x61, 0x9E, 0xF8, 0xFA, 0xE0, 0x87, 0xD7, 0xA1, 0x4E, 0x25, 0x36, 0xEE}, /* Master key 04 encrypted with Master key 05. */
|
||||
{0x1E, 0x1E, 0x22, 0xC0, 0x5A, 0x33, 0x3C, 0xB9, 0x0B, 0xA9, 0x03, 0x04, 0xBA, 0xDB, 0x07, 0x57}, /* Master key 05 encrypted with Master key 06. */
|
||||
{0xA4, 0xD4, 0x52, 0x6F, 0xD1, 0xE4, 0x36, 0xAA, 0x9F, 0xCB, 0x61, 0x27, 0x1C, 0x67, 0x65, 0x1F}, /* Master key 06 encrypted with Master key 07. */
|
||||
{0xEA, 0x60, 0xB3, 0xEA, 0xCE, 0x8F, 0x24, 0x46, 0x7D, 0x33, 0x9C, 0xD1, 0xBC, 0x24, 0x98, 0x29}, /* Master key 07 encrypted with Master key 08. */
|
||||
};
|
||||
|
||||
static bool check_mkey_revision(unsigned int revision, bool is_retail) {
|
||||
@@ -80,7 +82,7 @@ int mkey_detect_revision(bool is_retail) {
|
||||
if (g_determined_mkey_revision) {
|
||||
generic_panic();
|
||||
}
|
||||
|
||||
|
||||
for (unsigned int rev = 0; rev < MASTERKEY_REVISION_MAX; rev++) {
|
||||
if (check_mkey_revision(rev, is_retail)) {
|
||||
g_determined_mkey_revision = true;
|
||||
@@ -88,7 +90,7 @@ int mkey_detect_revision(bool is_retail) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* We must have determined the master key, or we're not running on a Switch. */
|
||||
if (!g_determined_mkey_revision) {
|
||||
return -1;
|
||||
|
||||
@@ -13,14 +13,14 @@
|
||||
* 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 FUSEE_MASTERKEY_H
|
||||
#define FUSEE_MASTERKEY_H
|
||||
|
||||
/* This is glue code to enable master key support across versions. */
|
||||
|
||||
/* TODO: Update to 0x8 on release of new master key. */
|
||||
#define MASTERKEY_REVISION_MAX 0x8
|
||||
/* TODO: Update to 0xA on release of new master key. */
|
||||
#define MASTERKEY_REVISION_MAX 0x9
|
||||
|
||||
#define MASTERKEY_REVISION_100_230 0x00
|
||||
#define MASTERKEY_REVISION_300 0x01
|
||||
@@ -29,7 +29,8 @@
|
||||
#define MASTERKEY_REVISION_500_510 0x04
|
||||
#define MASTERKEY_REVISION_600_610 0x05
|
||||
#define MASTERKEY_REVISION_620 0x06
|
||||
#define MASTERKEY_REVISION_700_CURRENT 0x07
|
||||
#define MASTERKEY_REVISION_700_800 0x07
|
||||
#define MASTERKEY_REVISION_810_CURRENT 0x08
|
||||
|
||||
#define MASTERKEY_NUM_NEW_DEVICE_KEYS (MASTERKEY_REVISION_MAX - MASTERKEY_REVISION_400_410)
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
* 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 <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
@@ -53,7 +53,8 @@
|
||||
#define u8 uint8_t
|
||||
#define u32 uint32_t
|
||||
#include "exosphere_bin.h"
|
||||
#include "sept_secondary_enc.h"
|
||||
#include "sept_secondary_00_enc.h"
|
||||
#include "sept_secondary_01_enc.h"
|
||||
#include "lp0fw_bin.h"
|
||||
#include "emummc_kip.h"
|
||||
#include "lib/log.h"
|
||||
@@ -207,8 +208,15 @@ static uint32_t nxboot_get_target_firmware(const void *package1loader) {
|
||||
}
|
||||
case 0x0F: /* 7.0.0 - 7.0.1 */
|
||||
return ATMOSPHERE_TARGET_FIRMWARE_700;
|
||||
case 0x10: /* 8.0.0 */
|
||||
return ATMOSPHERE_TARGET_FIRMWARE_800;
|
||||
case 0x10: { /* 8.0.0 - 8.1.0 */
|
||||
if (memcmp(package1loader_header->build_timestamp, "20190314", 8) == 0) {
|
||||
return ATMOSPHERE_TARGET_FIRMWARE_800;
|
||||
} else if (memcmp(package1loader_header->build_timestamp, "20190531", 8) == 0) {
|
||||
return ATMOSPHERE_TARGET_FIRMWARE_810;
|
||||
} else {
|
||||
fatal_error("[NXBOOT] Unable to identify package1!\n");
|
||||
}
|
||||
}
|
||||
default:
|
||||
fatal_error("[NXBOOT] Unable to identify package1!\n");
|
||||
}
|
||||
@@ -216,7 +224,7 @@ static uint32_t nxboot_get_target_firmware(const void *package1loader) {
|
||||
|
||||
static bool nxboot_configure_emummc(exo_emummc_config_t *exo_emummc_config) {
|
||||
emummc_config_t emummc_cfg = {.enabled = false, .id = 0, .sector = -1, .path = "", .nintendo_path = ""};
|
||||
|
||||
|
||||
char *emummc_ini = calloc(1, 0x10000);
|
||||
if (!read_from_file(emummc_ini, 0xFFFF, "emummc/emummc.ini")) {
|
||||
free(emummc_ini);
|
||||
@@ -237,12 +245,12 @@ static bool nxboot_configure_emummc(exo_emummc_config_t *exo_emummc_config) {
|
||||
exo_emummc_config->base_cfg.fs_version = FS_VER_1_0_0; /* Will be filled out later. */
|
||||
strncpy(exo_emummc_config->emu_dir_path, emummc_cfg.nintendo_path, sizeof(exo_emummc_config->emu_dir_path));
|
||||
exo_emummc_config->emu_dir_path[sizeof(exo_emummc_config->emu_dir_path) - 1] = '\0';
|
||||
|
||||
|
||||
if (emummc_cfg.enabled) {
|
||||
if (emummc_cfg.sector >= 0) {
|
||||
if (emummc_cfg.sector != -1) {
|
||||
exo_emummc_config->base_cfg.type = EMUMMC_TYPE_PARTITION;
|
||||
exo_emummc_config->partition_cfg.start_sector = emummc_cfg.sector;
|
||||
|
||||
|
||||
/* Mount emulated NAND from SD card partition. */
|
||||
if (nxfs_mount_emummc_partition(emummc_cfg.sector) < 0) {
|
||||
fatal_error("[NXBOOT] Failed to mount EmuMMC from SD card partition!\n");
|
||||
@@ -254,37 +262,40 @@ static bool nxboot_configure_emummc(exo_emummc_config_t *exo_emummc_config) {
|
||||
|
||||
int num_parts = 0;
|
||||
uint64_t part_limit = 0;
|
||||
char emummc_path[0x300 + 1] = {0};
|
||||
char emummc_path[0x100 + 1] = {0};
|
||||
char emummc_boot0_path[0x300 + 1] = {0};
|
||||
char emummc_boot1_path[0x300 + 1] = {0};
|
||||
char emummc_rawnand_path[0x300 + 1] = {0};
|
||||
|
||||
|
||||
/* Prepare base folder path. */
|
||||
snprintf(emummc_path, sizeof(emummc_path) - 1, "sdmc:/%s/%s", emummc_cfg.path, "eMMC");
|
||||
|
||||
snprintf(emummc_path, sizeof(emummc_path) - 1, "%s/%s", emummc_cfg.path, "eMMC");
|
||||
|
||||
/* Check if eMMC folder is present. */
|
||||
if (!is_valid_folder(emummc_path)) {
|
||||
fatal_error("[NXBOOT] Failed to find EmuMMC eMMC folder!\n");
|
||||
}
|
||||
|
||||
|
||||
/* Prepare expected file paths. */
|
||||
snprintf(emummc_boot0_path, sizeof(emummc_boot0_path) - 1, "sdmc:/%s/%s", emummc_path, "boot0");
|
||||
snprintf(emummc_boot1_path, sizeof(emummc_boot1_path) - 1, "sdmc:/%s/%s", emummc_path, "boot1");
|
||||
|
||||
snprintf(emummc_boot0_path, sizeof(emummc_boot0_path) - 1, "%s/%s", emummc_path, "boot0");
|
||||
snprintf(emummc_boot1_path, sizeof(emummc_boot1_path) - 1, "%s/%s", emummc_path, "boot1");
|
||||
|
||||
/* Check if boot0 and boot1 image files are present. */
|
||||
if (!is_valid_file(emummc_boot0_path) || !is_valid_file(emummc_boot1_path)) {
|
||||
fatal_error("[NXBOOT] Failed to find EmuMMC boot0/boot1 image files!\n");
|
||||
}
|
||||
|
||||
|
||||
/* Find raw image files (single or multi part). */
|
||||
for (int i = 0; i < 64; i++) {
|
||||
snprintf(emummc_rawnand_path, sizeof(emummc_rawnand_path) - 1, "sdmc:/%s/%02d", emummc_path, i);
|
||||
snprintf(emummc_rawnand_path, sizeof(emummc_rawnand_path) - 1, "%s/%02d", emummc_path, i);
|
||||
if (is_valid_file(emummc_rawnand_path)) {
|
||||
if (i == 0) {
|
||||
/* The size of the first file should tell us the part limit. */
|
||||
part_limit = get_file_size(emummc_rawnand_path);
|
||||
}
|
||||
num_parts++;
|
||||
} else {
|
||||
/* No more image files. */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -292,7 +303,7 @@ static bool nxboot_configure_emummc(exo_emummc_config_t *exo_emummc_config) {
|
||||
if ((num_parts == 0) || (part_limit == 0)) {
|
||||
fatal_error("[NXBOOT] Failed to find EmuMMC raw image files!\n");
|
||||
}
|
||||
|
||||
|
||||
/* Mount emulated NAND from files. */
|
||||
if (nxfs_mount_emummc_file(emummc_path, num_parts, part_limit) < 0) {
|
||||
fatal_error("[NXBOOT] Failed to mount EmuMMC from files!\n");
|
||||
@@ -301,7 +312,7 @@ static bool nxboot_configure_emummc(exo_emummc_config_t *exo_emummc_config) {
|
||||
fatal_error("[NXBOOT] Invalid EmuMMC setting!\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return emummc_cfg.enabled;
|
||||
}
|
||||
|
||||
@@ -334,7 +345,7 @@ static void nxboot_configure_stratosphere(uint32_t target_firmware) {
|
||||
if (ini_parse_string(get_loader_ctx()->bct0, stratosphere_ini_handler, &strat_cfg) < 0) {
|
||||
fatal_error("[NXBOOT] Failed to parse BCT.ini!\n");
|
||||
}
|
||||
|
||||
|
||||
/* Enable NOGC patches if the user requested it, or if the user is booting into 4.0.0+ with 3.0.2- fuses. */
|
||||
if (strat_cfg.has_nogc_config) {
|
||||
if (strat_cfg.enable_nogc) {
|
||||
@@ -350,7 +361,7 @@ static void nxboot_configure_stratosphere(uint32_t target_firmware) {
|
||||
|
||||
static void nxboot_set_bootreason(void *bootreason_base) {
|
||||
boot_reason_t boot_reason = {0};
|
||||
FILE *boot0;
|
||||
FILE *boot0;
|
||||
nvboot_config_table *bct;
|
||||
nv_bootloader_info *bootloader_info;
|
||||
|
||||
@@ -359,7 +370,7 @@ static void nxboot_set_bootreason(void *bootreason_base) {
|
||||
if (bct == NULL) {
|
||||
fatal_error("[NXBOOT] Out of memory!\n");
|
||||
}
|
||||
|
||||
|
||||
/* Open boot0. */
|
||||
boot0 = fopen("boot0:/", "rb");
|
||||
if (boot0 == NULL) {
|
||||
@@ -370,25 +381,25 @@ static void nxboot_set_bootreason(void *bootreason_base) {
|
||||
if (fread(bct, sizeof(nvboot_config_table), 1, boot0) == 0) {
|
||||
fatal_error("[NXBOOT] Failed to read the BCT!\n");
|
||||
}
|
||||
|
||||
|
||||
/* Close boot0. */
|
||||
fclose(boot0);
|
||||
|
||||
|
||||
/* Populate bootloader parameters. */
|
||||
bootloader_info = &bct->bootloader[0];
|
||||
boot_reason.bootloader_version = bootloader_info->version;
|
||||
boot_reason.bootloader_start_block = bootloader_info->start_blk;
|
||||
boot_reason.bootloader_start_page = bootloader_info->start_page;
|
||||
boot_reason.bootloader_attribute = bootloader_info->attribute;
|
||||
|
||||
|
||||
uint8_t power_key_intr = 0;
|
||||
uint8_t rtc_intr = 0;
|
||||
i2c_query(I2C_5, MAX77620_PWR_I2C_ADDR, MAX77620_REG_ONOFFIRQ, &power_key_intr, 1);
|
||||
i2c_query(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_REG_RTCINT, &rtc_intr, 1);
|
||||
|
||||
|
||||
/* Set PMIC value. */
|
||||
boot_reason.boot_reason_value = ((rtc_intr << 0x08) | power_key_intr);
|
||||
|
||||
|
||||
/* TODO: Find out what these mean. */
|
||||
if (power_key_intr & 0x80)
|
||||
boot_reason.boot_reason_state = 0x01;
|
||||
@@ -398,10 +409,10 @@ static void nxboot_set_bootreason(void *bootreason_base) {
|
||||
boot_reason.boot_reason_state = 0x03;
|
||||
else if (rtc_intr & 0x04)
|
||||
boot_reason.boot_reason_state = 0x04;
|
||||
|
||||
|
||||
/* Set in memory. */
|
||||
memcpy(bootreason_base, &boot_reason, sizeof(boot_reason));
|
||||
|
||||
|
||||
/* Clean up. */
|
||||
free(bct);
|
||||
}
|
||||
@@ -411,13 +422,13 @@ static void nxboot_move_bootconfig() {
|
||||
void *bootconfig;
|
||||
uint32_t bootconfig_addr;
|
||||
uint32_t bootconfig_size;
|
||||
|
||||
|
||||
/* Allocate memory for reading BootConfig. */
|
||||
bootconfig = memalign(0x1000, 0x4000);
|
||||
if (bootconfig == NULL) {
|
||||
fatal_error("[NXBOOT] Out of memory!\n");
|
||||
}
|
||||
|
||||
|
||||
/* Get BootConfig from the Package2 partition. */
|
||||
bcfile = fopen("bcpkg21:/", "rb");
|
||||
if (bcfile == NULL) {
|
||||
@@ -428,15 +439,15 @@ static void nxboot_move_bootconfig() {
|
||||
fatal_error("[NXBOOT] Failed to read BootConfig!\n");
|
||||
}
|
||||
fclose(bcfile);
|
||||
|
||||
|
||||
/* Select the actual BootConfig size and destination address. */
|
||||
bootconfig_addr = (MAILBOX_EXOSPHERE_CONFIGURATION->target_firmware < ATMOSPHERE_TARGET_FIRMWARE_600) ? 0x4003D000 : 0x4003F800;
|
||||
bootconfig_size = (MAILBOX_EXOSPHERE_CONFIGURATION->target_firmware < ATMOSPHERE_TARGET_FIRMWARE_400) ? 0x3000 : 0x1000;
|
||||
|
||||
|
||||
/* Copy the BootConfig into IRAM. */
|
||||
memset((void *)bootconfig_addr, 0, bootconfig_size);
|
||||
memcpy((void *)bootconfig_addr, bootconfig, bootconfig_size);
|
||||
|
||||
|
||||
/* Clean up. */
|
||||
free(bootconfig);
|
||||
}
|
||||
@@ -456,6 +467,8 @@ uint32_t nxboot_main(void) {
|
||||
size_t package2_size;
|
||||
void *tsec_fw;
|
||||
size_t tsec_fw_size;
|
||||
const void *sept_secondary_enc = NULL;
|
||||
size_t sept_secondary_enc_size = 0;
|
||||
void *warmboot_fw;
|
||||
size_t warmboot_fw_size;
|
||||
void *warmboot_memaddr;
|
||||
@@ -467,7 +480,7 @@ uint32_t nxboot_main(void) {
|
||||
FILE *boot0, *pk2file;
|
||||
void *exosphere_memaddr;
|
||||
exo_emummc_config_t exo_emummc_cfg;
|
||||
|
||||
|
||||
/* Configure emummc or mount the real NAND. */
|
||||
if (!nxboot_configure_emummc(&exo_emummc_cfg)) {
|
||||
emummc = NULL;
|
||||
@@ -539,7 +552,7 @@ uint32_t nxboot_main(void) {
|
||||
fatal_error("[NXBOOT] Failed to read Package2!\n");
|
||||
}
|
||||
fclose(pk2file);
|
||||
|
||||
|
||||
/* Read and parse boot0. */
|
||||
print(SCREEN_LOG_LEVEL_INFO, "[NXBOOT] Reading boot0...\n");
|
||||
boot0 = fopen("boot0:/", "rb");
|
||||
@@ -547,7 +560,7 @@ uint32_t nxboot_main(void) {
|
||||
fatal_error("[NXBOOT] Couldn't parse boot0: %s!\n", strerror(errno));
|
||||
}
|
||||
fclose(boot0);
|
||||
|
||||
|
||||
/* Find the system's target firmware. */
|
||||
uint32_t target_firmware = nxboot_get_target_firmware(package1loader);
|
||||
if (!target_firmware)
|
||||
@@ -558,26 +571,42 @@ uint32_t nxboot_main(void) {
|
||||
/* Read the TSEC firmware from a file, otherwise from PK1L. */
|
||||
if (loader_ctx->tsecfw_path[0] != '\0') {
|
||||
tsec_fw_size = get_file_size(loader_ctx->tsecfw_path);
|
||||
if ((tsec_fw_size != 0) && (tsec_fw_size != 0xF00 && tsec_fw_size != 0x2900 && tsec_fw_size != 0x3000)) {
|
||||
if ((tsec_fw_size != 0) && (tsec_fw_size != 0xF00 && tsec_fw_size != 0x2900 && tsec_fw_size != 0x3000 && tsec_fw_size != 0x3300)) {
|
||||
fatal_error("[NXBOOT] TSEC firmware from %s has a wrong size!\n", loader_ctx->tsecfw_path);
|
||||
} else if (tsec_fw_size == 0) {
|
||||
fatal_error("[NXBOOT] Could not read the TSEC firmware from %s!\n", loader_ctx->tsecfw_path);
|
||||
}
|
||||
|
||||
|
||||
/* Allocate memory for the TSEC firmware. */
|
||||
tsec_fw = memalign(0x100, tsec_fw_size);
|
||||
|
||||
|
||||
if (tsec_fw == NULL) {
|
||||
fatal_error("[NXBOOT] Out of memory!\n");
|
||||
}
|
||||
if (read_from_file(tsec_fw, tsec_fw_size, loader_ctx->tsecfw_path) != tsec_fw_size) {
|
||||
fatal_error("[NXBOOT] Could not read the TSEC firmware from %s!\n", loader_ctx->tsecfw_path);
|
||||
}
|
||||
|
||||
if (tsec_fw_size == 0x3000) {
|
||||
sept_secondary_enc = sept_secondary_00_enc;
|
||||
sept_secondary_enc_size = sept_secondary_00_enc_size;
|
||||
} else if (tsec_fw_size == 0x3300) {
|
||||
sept_secondary_enc = sept_secondary_01_enc;
|
||||
sept_secondary_enc_size = sept_secondary_01_enc_size;
|
||||
} else {
|
||||
fatal_error("[NXBOOT] Unable to identify sept revision to run.");
|
||||
}
|
||||
} else {
|
||||
if (!package1_get_tsec_fw(&tsec_fw, package1loader, package1loader_size)) {
|
||||
fatal_error("[NXBOOT] Failed to read the TSEC firmware from Package1loader!\n");
|
||||
}
|
||||
if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_700) {
|
||||
if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_810) {
|
||||
sept_secondary_enc = sept_secondary_01_enc;
|
||||
sept_secondary_enc_size = sept_secondary_01_enc_size;
|
||||
tsec_fw_size = 0x3300;
|
||||
} else if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_700) {
|
||||
sept_secondary_enc = sept_secondary_00_enc;
|
||||
sept_secondary_enc_size = sept_secondary_00_enc_size;
|
||||
tsec_fw_size = 0x3000;
|
||||
} else if (target_firmware == ATMOSPHERE_TARGET_FIRMWARE_620) {
|
||||
tsec_fw_size = 0x2900;
|
||||
@@ -603,10 +632,10 @@ uint32_t nxboot_main(void) {
|
||||
get_and_clear_has_run_sept();
|
||||
} else if (target_firmware == ATMOSPHERE_TARGET_FIRMWARE_620) {
|
||||
uint8_t tsec_keys[0x20] = {0};
|
||||
|
||||
|
||||
/* Emulate the TSEC payload on 6.2.0+. */
|
||||
smmu_emulate_tsec((void *)tsec_keys, package1loader, package1loader_size, package1loader);
|
||||
|
||||
|
||||
/* Copy back the keys. */
|
||||
memcpy((void *)tsec_key, (void *)tsec_keys, 0x10);
|
||||
memcpy((void *)tsec_root_keys, (void *)tsec_keys + 0x10, 0x10);
|
||||
@@ -616,11 +645,11 @@ uint32_t nxboot_main(void) {
|
||||
fatal_error("[NXBOOT] Failed to get TSEC key!\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//fatal_error("Ran sept!");
|
||||
/* Display splash screen. */
|
||||
display_splash_screen_bmp(loader_ctx->custom_splash_path, (void *)0xC0000000);
|
||||
|
||||
|
||||
/* Derive keydata. If on 7.0.0+, sept has already derived keys for us. */
|
||||
unsigned int keygen_type = 0;
|
||||
if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_700) {
|
||||
@@ -662,27 +691,27 @@ uint32_t nxboot_main(void) {
|
||||
if (warmboot_fw == NULL) {
|
||||
fatal_error("[NXBOOT] Out of memory!\n");
|
||||
}
|
||||
|
||||
|
||||
memcpy(warmboot_fw, lp0fw_bin, warmboot_fw_size);
|
||||
|
||||
|
||||
if (warmboot_fw_size == 0) {
|
||||
fatal_error("[NXBOOT] Could not read the warmboot firmware from Package1!\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Patch warmboot firmware for atmosphere. */
|
||||
if (warmboot_fw != NULL && warmboot_fw_size >= sizeof(warmboot_ams_header_t)) {
|
||||
warmboot_ams_header_t *ams_header = (warmboot_ams_header_t *)warmboot_fw;
|
||||
if (ams_header->ams_metadata.magic == WARMBOOT_MAGIC) {
|
||||
/* Set target firmware */
|
||||
ams_header->ams_metadata.target_firmware = target_firmware;
|
||||
|
||||
|
||||
/* Set RSA modulus */
|
||||
const uint8_t *pkc_modulus = fuse_get_retail_type() != 0 ? retail_pkc_modulus : dev_pkc_modulus;
|
||||
memcpy(ams_header->rsa_modulus, pkc_modulus, sizeof(ams_header->rsa_modulus));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Select the right address for the warmboot firmware. */
|
||||
if (MAILBOX_EXOSPHERE_CONFIGURATION->target_firmware < ATMOSPHERE_TARGET_FIRMWARE_400) {
|
||||
@@ -705,7 +734,7 @@ uint32_t nxboot_main(void) {
|
||||
}
|
||||
|
||||
print(SCREEN_LOG_LEVEL_INFO, "[NXBOOT] Rebuilding package2...\n");
|
||||
|
||||
|
||||
/* Parse stratosphere config. */
|
||||
nxboot_configure_stratosphere(MAILBOX_EXOSPHERE_CONFIGURATION->target_firmware);
|
||||
|
||||
@@ -767,10 +796,10 @@ uint32_t nxboot_main(void) {
|
||||
free(package2);
|
||||
|
||||
print(SCREEN_LOG_LEVEL_INFO, "[NXBOOT] Powering on the CCPLEX...\n");
|
||||
|
||||
|
||||
/* Unmount everything. */
|
||||
nxfs_end();
|
||||
|
||||
|
||||
/* Return the memory address for booting CPU0. */
|
||||
return (uint32_t)exosphere_memaddr;
|
||||
}
|
||||
|
||||
@@ -190,7 +190,7 @@ static int emummc_partition_read(device_partition_t *devpart, void *dst, uint64_
|
||||
/* Read partition data using our backing file. */
|
||||
int rc = 0;
|
||||
FILE *emummc_file = fopen(devpart->emu_file_path, "rb");
|
||||
fseek(emummc_file, sector * devpart->sector_size, SEEK_CUR);
|
||||
fseek(emummc_file, (devpart->start_sector + sector) * devpart->sector_size, SEEK_CUR);
|
||||
rc = (fread(dst, devpart->sector_size, num_sectors, emummc_file) > 0) ? 0 : -1;
|
||||
fclose(emummc_file);
|
||||
return rc;
|
||||
@@ -205,7 +205,7 @@ static int emummc_partition_write(device_partition_t *devpart, const void *src,
|
||||
/* Write partition data using our backing file. */
|
||||
int rc = 0;
|
||||
FILE *emummc_file = fopen(devpart->emu_file_path, "wb");
|
||||
fseek(emummc_file, sector * devpart->sector_size, SEEK_CUR);
|
||||
fseek(emummc_file, (devpart->start_sector + sector) * devpart->sector_size, SEEK_CUR);
|
||||
rc = (fwrite(src, devpart->sector_size, num_sectors, emummc_file) > 0) ? 0 : -1;
|
||||
fclose(emummc_file);
|
||||
return rc;
|
||||
@@ -691,7 +691,7 @@ int nxfs_mount_emummc_file(const char *emummc_path, int num_parts, uint64_t part
|
||||
model.emu_use_file = true;
|
||||
|
||||
/* Prepare boot0 file path. */
|
||||
snprintf(emummc_boot0_path, sizeof(emummc_boot0_path) - 1, "sdmc:/%s/%s", emummc_path, "boot0");
|
||||
snprintf(emummc_boot0_path, sizeof(emummc_boot0_path) - 1, "%s/%s", emummc_path, "boot0");
|
||||
|
||||
/* Mount emulated boot0 device. */
|
||||
rc = emudev_mount_device("boot0", &model, emummc_boot0_path);
|
||||
@@ -716,7 +716,7 @@ int nxfs_mount_emummc_file(const char *emummc_path, int num_parts, uint64_t part
|
||||
model.emu_use_file = true;
|
||||
|
||||
/* Prepare boot1 file path. */
|
||||
snprintf(emummc_boot1_path, sizeof(emummc_boot1_path) - 1, "sdmc:/%s/%s", emummc_path, "boot1");
|
||||
snprintf(emummc_boot1_path, sizeof(emummc_boot1_path) - 1, "%s/%s", emummc_path, "boot1");
|
||||
|
||||
/* Mount emulated boot1 device. */
|
||||
rc = emudev_mount_device("boot1", &model, emummc_boot1_path);
|
||||
@@ -726,7 +726,13 @@ int nxfs_mount_emummc_file(const char *emummc_path, int num_parts, uint64_t part
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Don't register emulated boot1 for now. */
|
||||
/* Register emulated boot1 device. */
|
||||
rc = emudev_register_device("boot1");
|
||||
|
||||
/* Failed to register boot1 device. */
|
||||
if (rc == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Setup a template for raw NAND. */
|
||||
model = g_emummc_devpart_template;
|
||||
@@ -735,7 +741,7 @@ int nxfs_mount_emummc_file(const char *emummc_path, int num_parts, uint64_t part
|
||||
model.emu_use_file = true;
|
||||
|
||||
/* Prepare single raw NAND file path. */
|
||||
snprintf(emummc_rawnand_path, sizeof(emummc_rawnand_path) - 1, "sdmc:/%s/%02d", emummc_path, 0);
|
||||
snprintf(emummc_rawnand_path, sizeof(emummc_rawnand_path) - 1, "%s/%02d", emummc_path, 0);
|
||||
|
||||
/* Mount emulated raw NAND device from single or multiple parts. */
|
||||
if (!is_exfat) {
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
* 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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <atmosphere.h>
|
||||
@@ -66,7 +66,7 @@ void package2_rebuild_and_copy(package2_header_t *package2, uint32_t target_firm
|
||||
if (thermosphere_size != 0 && package2->metadata.section_sizes[PACKAGE2_SECTION_UNUSED] != 0) {
|
||||
fatal_error(u8"Error: Package2 has no unused section for Thermosphère!\n");
|
||||
}
|
||||
|
||||
|
||||
/* Load Kernel from SD, if possible. */
|
||||
{
|
||||
size_t sd_kernel_size = get_file_size("atmosphere/kernel.bin");
|
||||
@@ -88,13 +88,13 @@ void package2_rebuild_and_copy(package2_header_t *package2, uint32_t target_firm
|
||||
|
||||
/* Perform any patches we want to the NX kernel. */
|
||||
package2_patch_kernel(kernel, kernel_size, is_sd_kernel, (void *)&orig_ini1);
|
||||
|
||||
|
||||
/* Ensure we know where embedded INI is if present, and we don't if not. */
|
||||
if ((target_firmware < ATMOSPHERE_TARGET_FIRMWARE_800 && orig_ini1 != NULL) ||
|
||||
if ((target_firmware < ATMOSPHERE_TARGET_FIRMWARE_800 && orig_ini1 != NULL) ||
|
||||
(target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_800 && orig_ini1 == NULL)) {
|
||||
fatal_error("Error: inappropriate kernel embedded ini context");
|
||||
}
|
||||
|
||||
|
||||
print(SCREEN_LOG_LEVEL_DEBUG, "Rebuilding the INI1 section...\n");
|
||||
if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_800) {
|
||||
package2_get_src_section((void *)&orig_ini1, package2, PACKAGE2_SECTION_INI1);
|
||||
@@ -232,7 +232,7 @@ static bool package2_validate_metadata(package2_meta_t *metadata, uint8_t data[]
|
||||
|
||||
/* Perform version checks. */
|
||||
/* We will be compatible with all package2s released before current, but not newer ones. */
|
||||
if (metadata->version_max >= PACKAGE2_MINVER_THEORETICAL && metadata->version_min < PACKAGE2_MAXVER_700_CURRENT) {
|
||||
if (metadata->version_max >= PACKAGE2_MINVER_THEORETICAL && metadata->version_min < PACKAGE2_MAXVER_810_CURRENT) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
* 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 FUSEE_PACKAGE2_H
|
||||
#define FUSEE_PACKAGE2_H
|
||||
|
||||
@@ -36,7 +36,8 @@
|
||||
#define PACKAGE2_MAXVER_500_510 0x7
|
||||
#define PACKAGE2_MAXVER_600_610 0x8
|
||||
#define PACKAGE2_MAXVER_620 0x9
|
||||
#define PACKAGE2_MAXVER_700_CURRENT 0xA
|
||||
#define PACKAGE2_MAXVER_700_800 0xA
|
||||
#define PACKAGE2_MAXVER_810_CURRENT 0xB
|
||||
|
||||
#define PACKAGE2_MINVER_100 0x3
|
||||
#define PACKAGE2_MINVER_200 0x4
|
||||
@@ -46,7 +47,8 @@
|
||||
#define PACKAGE2_MINVER_500_510 0x8
|
||||
#define PACKAGE2_MINVER_600_610 0x9
|
||||
#define PACKAGE2_MINVER_620 0xA
|
||||
#define PACKAGE2_MINVER_700_CURRENT 0xB
|
||||
#define PACKAGE2_MINVER_700_800 0xB
|
||||
#define PACKAGE2_MINVER_810_CURRENT 0xC
|
||||
|
||||
#define NX_BOOTLOADER_PACKAGE2_LOAD_ADDRESS ((void *)(0xA9800000ull))
|
||||
|
||||
@@ -79,7 +81,7 @@ typedef struct {
|
||||
/* Package2 can be encrypted or unencrypted for these functions: */
|
||||
|
||||
static inline size_t package2_meta_get_size(const package2_meta_t *metadata) {
|
||||
return metadata->ctr_dwords[0] ^ metadata->ctr_dwords[2] ^ metadata->ctr_dwords[3];
|
||||
return metadata->ctr_dwords[0] ^ metadata->ctr_dwords[2] ^ metadata->ctr_dwords[3];
|
||||
}
|
||||
|
||||
static inline uint8_t package2_meta_get_header_version(const package2_meta_t *metadata) {
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <atmosphere/version.h>
|
||||
|
||||
|
||||
.macro CLEAR_GPR_REG_ITER
|
||||
mov r\@, #0
|
||||
.endm
|
||||
@@ -27,7 +27,7 @@
|
||||
.type _start, %function
|
||||
_start:
|
||||
b _crt0
|
||||
|
||||
|
||||
.word (_metadata - _start)
|
||||
|
||||
_crt0:
|
||||
@@ -67,7 +67,7 @@ _crt0:
|
||||
ldr r0, [r0]
|
||||
ldr r1, [r1]
|
||||
b main
|
||||
|
||||
|
||||
/* Fusee-secondary header. */
|
||||
.align 5
|
||||
_metadata:
|
||||
@@ -168,12 +168,20 @@ _content_headers:
|
||||
.asciz "sept_primary"
|
||||
.align 5
|
||||
|
||||
/* sept_secondary content header */
|
||||
.word __sept_secondary_enc_start__
|
||||
.word __sept_secondary_enc_size__
|
||||
/* sept_secondary 00 content header */
|
||||
.word __sept_secondary_00_enc_start__
|
||||
.word __sept_secondary_00_enc_size__
|
||||
.word CONTENT_TYPE_SP2
|
||||
.word 0xCCCCCCCC
|
||||
.asciz "sept_secondary"
|
||||
.asciz "sept_secondary_00"
|
||||
.align 5
|
||||
|
||||
/* sept_secondary 01 content header */
|
||||
.word __sept_secondary_01_enc_start__
|
||||
.word __sept_secondary_01_enc_size__
|
||||
.word CONTENT_TYPE_SP2
|
||||
.word 0xCCCCCCCC
|
||||
.asciz "sept_secondary_01"
|
||||
.align 5
|
||||
|
||||
/* sm content header */
|
||||
|
||||
@@ -1,7 +1,20 @@
|
||||
HOVI_ENC_KEY_PRD = bytearray.fromhex('00000000000000000000000000000000')
|
||||
HOVI_ENC_KEY_DEV = bytearray.fromhex('00000000000000000000000000000000')
|
||||
HOVI_SIG_KEY_PRD = bytearray.fromhex('00000000000000000000000000000000')
|
||||
HOVI_SIG_KEY_DEV = bytearray.fromhex('00000000000000000000000000000000')
|
||||
HOVI_KEK_KEY_PRD = bytearray.fromhex('00000000000000000000000000000000')
|
||||
HOVI_KEK_KEY_DEV = bytearray.fromhex('00000000000000000000000000000000')
|
||||
IV = bytearray.fromhex('00000000000000000000000000000000')
|
||||
NUM_KEYS = 2
|
||||
|
||||
HOVI_ENC_KEY_PRD = [
|
||||
bytearray.fromhex('00000000000000000000000000000000'),
|
||||
bytearray.fromhex('00000000000000000000000000000000'),
|
||||
]
|
||||
|
||||
HOVI_SIG_KEY_PRD = [
|
||||
bytearray.fromhex('00000000000000000000000000000000'),
|
||||
bytearray.fromhex('00000000000000000000000000000000'),
|
||||
]
|
||||
|
||||
IV = [
|
||||
bytearray.fromhex('00000000000000000000000000000000'),
|
||||
bytearray.fromhex('00000000000000000000000000000000'),
|
||||
]
|
||||
|
||||
assert len(HOVI_ENC_KEY_PRD) == NUM_KEYS
|
||||
assert len(HOVI_SIG_KEY_PRD) == NUM_KEYS
|
||||
assert len(IV) == NUM_KEYS
|
||||
@@ -77,14 +77,15 @@ export TOPDIR := $(CURDIR)
|
||||
|
||||
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
|
||||
$(foreach dir,$(DATA),$(CURDIR)/$(dir)) \
|
||||
$(AMS)/exosphere/rebootstub
|
||||
$(AMS)/exosphere/rebootstub \
|
||||
$(TOPDIR)/key_derivation
|
||||
|
||||
export DEPSDIR := $(CURDIR)/$(BUILD)
|
||||
|
||||
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
|
||||
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
|
||||
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
|
||||
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) rebootstub.bin
|
||||
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) rebootstub.bin key_derivation.bin
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# use CXX for linking C++ projects, CC for standard C
|
||||
@@ -111,33 +112,38 @@ export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
|
||||
|
||||
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
|
||||
|
||||
.PHONY: $(BUILD) clean all check_rebootstub
|
||||
.PHONY: $(BUILD) clean all check_rebootstub check_key_derivation
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
all: check_rebootstub $(BUILD)
|
||||
all: check_rebootstub check_key_derivation $(BUILD)
|
||||
|
||||
check_rebootstub:
|
||||
@$(MAKE) -C $(AMS)/exosphere/rebootstub all
|
||||
|
||||
$(BUILD):
|
||||
ifeq ($(strip $(SEPT_ENC_PATH)),)
|
||||
check_key_derivation:
|
||||
@$(MAKE) -C key_derivation
|
||||
|
||||
$(BUILD): check_rebootstub check_key_derivation
|
||||
ifeq ($(strip $(SEPT_00_ENC_PATH)),)
|
||||
@[ -d $@ ] || mkdir -p $@
|
||||
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
|
||||
else
|
||||
@touch $(TOPDIR)/$(TARGET).bin
|
||||
@cp $(SEPT_ENC_PATH) $(TOPDIR)/$(TARGET).enc
|
||||
@cp $(SEPT_00_ENC_PATH) $(TOPDIR)/$(TARGET)_00.enc
|
||||
@cp $(SEPT_01_ENC_PATH) $(TOPDIR)/$(TARGET)_01.enc
|
||||
endif
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
clean:
|
||||
@echo clean ...
|
||||
@$(MAKE) -C $(AMS)/exosphere/rebootstub clean
|
||||
@rm -fr $(BUILD) $(TARGET).bin $(TARGET).enc $(TARGET).elf
|
||||
@$(MAKE) -C key_derivation clean
|
||||
@rm -fr $(BUILD) $(TARGET).bin $(TARGET)_*.enc $(TARGET).elf
|
||||
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
else
|
||||
.PHONY: all
|
||||
.PHONY: all $(OUTPUT).bin
|
||||
|
||||
DEPENDS := $(OFILES:.o=.d)
|
||||
|
||||
|
||||
154
sept/sept-secondary/key_derivation/Makefile
Normal file
154
sept/sept-secondary/key_derivation/Makefile
Normal file
@@ -0,0 +1,154 @@
|
||||
#---------------------------------------------------------------------------------
|
||||
.SUFFIXES:
|
||||
#---------------------------------------------------------------------------------
|
||||
|
||||
ifeq ($(strip $(DEVKITPRO)),)
|
||||
$(error "Please set DEVKITPRO in your environment. export DEVKITPRO=<path to>/devkitpro")
|
||||
endif
|
||||
|
||||
TOPDIR ?= $(CURDIR)
|
||||
include $(DEVKITPRO)/devkitA64/base_rules
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# TARGET is the name of the output
|
||||
# BUILD is the directory where object files & intermediate files will be placed
|
||||
# SOURCES is a list of directories containing source code
|
||||
# DATA is a list of directories containing data files
|
||||
# INCLUDES is a list of directories containing header files
|
||||
#---------------------------------------------------------------------------------
|
||||
TARGET := $(notdir $(CURDIR))
|
||||
BUILD := build
|
||||
SOURCES := src
|
||||
DATA := data
|
||||
INCLUDES := include
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# options for code generation
|
||||
#---------------------------------------------------------------------------------
|
||||
ARCH := -march=armv8-a -mtune=cortex-a57 -mgeneral-regs-only #<- important
|
||||
|
||||
CFLAGS := \
|
||||
-g \
|
||||
-Os \
|
||||
-ffunction-sections \
|
||||
-fdata-sections \
|
||||
-fomit-frame-pointer \
|
||||
-fno-inline \
|
||||
-std=gnu11 \
|
||||
-Werror \
|
||||
-Wall \
|
||||
$(ARCH) $(DEFINES)
|
||||
|
||||
CFLAGS += $(INCLUDE)
|
||||
|
||||
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++11
|
||||
|
||||
ASFLAGS := -g $(ARCH)
|
||||
LDFLAGS = -specs=$(TOPDIR)/linker.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map)
|
||||
|
||||
LIBS :=
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# list of directories containing libraries, this must be the top level containing
|
||||
# include and lib
|
||||
#---------------------------------------------------------------------------------
|
||||
LIBDIRS :=
|
||||
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# no real need to edit anything past this point unless you need to add additional
|
||||
# rules for different file extensions
|
||||
#---------------------------------------------------------------------------------
|
||||
ifneq ($(BUILD),$(notdir $(CURDIR)))
|
||||
#---------------------------------------------------------------------------------
|
||||
|
||||
export OUTPUT := $(CURDIR)/$(TARGET)
|
||||
export TOPDIR := $(CURDIR)
|
||||
|
||||
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
|
||||
$(foreach dir,$(DATA),$(CURDIR)/$(dir))
|
||||
|
||||
export DEPSDIR := $(CURDIR)/$(BUILD)
|
||||
|
||||
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
|
||||
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
|
||||
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
|
||||
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# use CXX for linking C++ projects, CC for standard C
|
||||
#---------------------------------------------------------------------------------
|
||||
ifeq ($(strip $(CPPFILES)),)
|
||||
#---------------------------------------------------------------------------------
|
||||
export LD := $(CC)
|
||||
#---------------------------------------------------------------------------------
|
||||
else
|
||||
#---------------------------------------------------------------------------------
|
||||
export LD := $(CXX)
|
||||
#---------------------------------------------------------------------------------
|
||||
endif
|
||||
#---------------------------------------------------------------------------------
|
||||
|
||||
export OFILES_BIN := $(addsuffix .o,$(BINFILES))
|
||||
export OFILES_SRC := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
|
||||
export OFILES := $(OFILES_BIN) $(OFILES_SRC)
|
||||
export HFILES_BIN := $(addsuffix .h,$(subst .,_,$(BINFILES)))
|
||||
|
||||
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
|
||||
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
|
||||
-I$(CURDIR)/$(BUILD)
|
||||
|
||||
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
|
||||
|
||||
.PHONY: $(BUILD) clean all
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
all: $(BUILD)
|
||||
|
||||
$(BUILD):
|
||||
@[ -d $@ ] || mkdir -p $@
|
||||
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
clean:
|
||||
@echo clean ...
|
||||
@rm -fr $(BUILD) $(TARGET).bin $(TARGET).elf
|
||||
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
else
|
||||
.PHONY: all
|
||||
|
||||
DEPENDS := $(OFILES:.o=.d)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# main targets
|
||||
#---------------------------------------------------------------------------------
|
||||
all : $(OUTPUT).bin
|
||||
|
||||
$(OUTPUT).bin : $(OUTPUT).elf
|
||||
$(OBJCOPY) -S -O binary $< $@
|
||||
@echo built ... $(notdir $@)
|
||||
|
||||
$(OUTPUT).elf : $(OFILES)
|
||||
|
||||
%.elf: $(OFILES)
|
||||
@echo linking $(notdir $@)
|
||||
@$(LD) $(LDFLAGS) $(OFILES) $(LIBPATHS) $(LIBS) -o $@
|
||||
@$(NM) -CSn $@ > $(notdir $*.lst)
|
||||
|
||||
$(OFILES_SRC) : $(HFILES_BIN)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# you need a rule like this for each extension you use as binary data
|
||||
#---------------------------------------------------------------------------------
|
||||
%.bin.o : %.bin
|
||||
#---------------------------------------------------------------------------------
|
||||
@echo $(notdir $<)
|
||||
@$(bin2o)
|
||||
|
||||
-include $(DEPENDS)
|
||||
|
||||
#---------------------------------------------------------------------------------------
|
||||
endif
|
||||
#---------------------------------------------------------------------------------------
|
||||
17
sept/sept-secondary/key_derivation/linker.ld
Normal file
17
sept/sept-secondary/key_derivation/linker.ld
Normal file
@@ -0,0 +1,17 @@
|
||||
OUTPUT_ARCH(aarch64)
|
||||
|
||||
ENTRY(_start)
|
||||
SECTIONS
|
||||
{
|
||||
. = 0x4003D000;
|
||||
|
||||
__start__ = ABSOLUTE(.);
|
||||
|
||||
.text : ALIGN(4) { *(.text.start) *(.text*); . = ALIGN(4); }
|
||||
.rodata : ALIGN(4) { *(.rodata*); . = ALIGN(4); }
|
||||
.bss : ALIGN(8) { __bss_start__ = .; *(.bss* COMMON); . = ALIGN(8); __bss_end__ = .; }
|
||||
|
||||
. = ALIGN(4);
|
||||
|
||||
__end__ = ABSOLUTE(.);
|
||||
}
|
||||
7
sept/sept-secondary/key_derivation/linker.specs
Normal file
7
sept/sept-secondary/key_derivation/linker.specs
Normal file
@@ -0,0 +1,7 @@
|
||||
%rename link old_link
|
||||
|
||||
*link:
|
||||
%(old_link) -T %:getenv(TOPDIR /linker.ld) --nmagic --gc-sections
|
||||
|
||||
*startfile:
|
||||
crti%O%s crtbegin%O%s
|
||||
142
sept/sept-secondary/key_derivation/src/key_derivation.c
Normal file
142
sept/sept-secondary/key_derivation/src/key_derivation.c
Normal file
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2019 Atmosphère-NX
|
||||
*
|
||||
* 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 "pmc.h"
|
||||
#include "se.h"
|
||||
#include "utils.h"
|
||||
|
||||
#define AL16 __attribute__((aligned(16)))
|
||||
|
||||
#define DERIVATION_ID_MAX 2
|
||||
|
||||
static const uint8_t AL16 keyblob_seed_00[0x10] = {
|
||||
0xDF, 0x20, 0x6F, 0x59, 0x44, 0x54, 0xEF, 0xDC, 0x70, 0x74, 0x48, 0x3B, 0x0D, 0xED, 0x9F, 0xD3
|
||||
};
|
||||
|
||||
static const uint8_t AL16 masterkey_seed[0x10] = {
|
||||
0xD8, 0xA2, 0x41, 0x0A, 0xC6, 0xC5, 0x90, 0x01, 0xC6, 0x1D, 0x6A, 0x26, 0x7C, 0x51, 0x3F, 0x3C
|
||||
};
|
||||
|
||||
static const uint8_t AL16 devicekey_seed[0x10] = {
|
||||
0x4F, 0x02, 0x5F, 0x0E, 0xB6, 0x6D, 0x11, 0x0E, 0xDC, 0x32, 0x7D, 0x41, 0x86, 0xC2, 0xF4, 0x78
|
||||
};
|
||||
|
||||
static const uint8_t AL16 devicekey_4x_seed[0x10] = {
|
||||
0x0C, 0x91, 0x09, 0xDB, 0x93, 0x93, 0x07, 0x81, 0x07, 0x3C, 0xC4, 0x16, 0x22, 0x7C, 0x6C, 0x28
|
||||
};
|
||||
|
||||
static const uint8_t AL16 masterkey_4x_seed[0x10] = {
|
||||
0x2D, 0xC1, 0xF4, 0x8D, 0xF3, 0x5B, 0x69, 0x33, 0x42, 0x10, 0xAC, 0x65, 0xDA, 0x90, 0x46, 0x66
|
||||
};
|
||||
|
||||
static const uint8_t AL16 zeroes[0x10] = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
static const uint8_t AL16 master_kek_seeds[DERIVATION_ID_MAX][0x10] = {
|
||||
{0x9A, 0x3E, 0xA9, 0xAB, 0xFD, 0x56, 0x46, 0x1C, 0x9B, 0xF6, 0x48, 0x7F, 0x5C, 0xFA, 0x09, 0x5C},
|
||||
{0xDE, 0xDC, 0xE3, 0x39, 0x30, 0x88, 0x16, 0xF8, 0xAE, 0x97, 0xAD, 0xEC, 0x64, 0x2D, 0x41, 0x41},
|
||||
};
|
||||
|
||||
static const uint8_t AL16 master_devkey_seeds[DERIVATION_ID_MAX][0x10] = {
|
||||
{0x8F, 0x77, 0x5A, 0x96, 0xB0, 0x94, 0xFD, 0x8D, 0x28, 0xE4, 0x19, 0xC8, 0x16, 0x1C, 0xDB, 0x3D},
|
||||
{0x67, 0x62, 0xD4, 0x8E, 0x55, 0xCF, 0xFF, 0x41, 0x31, 0x15, 0x3B, 0x24, 0x0C, 0x7C, 0x07, 0xAE},
|
||||
};
|
||||
|
||||
static const uint8_t AL16 master_devkey_vectors[DERIVATION_ID_MAX][0x10] = {
|
||||
{0xD8, 0xD3, 0x67, 0x4F, 0xF3, 0xA2, 0xA4, 0x4E, 0xE4, 0x04, 0x37, 0xC2, 0xD9, 0xCF, 0x41, 0x6F},
|
||||
{0x72, 0xD0, 0xAD, 0xEB, 0xE1, 0xF6, 0x35, 0x90, 0xB4, 0x43, 0xCC, 0x4B, 0xC4, 0xDC, 0x88, 0x0A},
|
||||
};
|
||||
|
||||
void derive_keys(void) {
|
||||
/* Set mailbox. */
|
||||
volatile uint32_t *mailbox = (volatile uint32_t *)0x4003FF00;
|
||||
const uint32_t derivation_id = *((volatile uint32_t *)0x4003E800);
|
||||
|
||||
if (derivation_id < DERIVATION_ID_MAX) {
|
||||
uint8_t *enc_se_state = (uint8_t *)0x4003E000;
|
||||
|
||||
uint32_t AL16 work_buffer[4];
|
||||
|
||||
/* Derive Keyblob Key 00. */
|
||||
se_aes_ecb_decrypt_block(0xC, work_buffer, 0x10, keyblob_seed_00, 0x10);
|
||||
decrypt_data_into_keyslot(0xF, 0xE, work_buffer, 0x10);
|
||||
|
||||
/* Derive master kek. */
|
||||
decrypt_data_into_keyslot(0xE, 0xD, master_kek_seeds[derivation_id], 0x10);
|
||||
|
||||
/* Clear the copy of the root key inside the SE. */
|
||||
clear_aes_keyslot(0xD);
|
||||
|
||||
/* Derive master key, device master key. */
|
||||
decrypt_data_into_keyslot(0xC, 0xE, masterkey_seed, 0x10);
|
||||
decrypt_data_into_keyslot(0xE, 0xE, masterkey_4x_seed, 0x10);
|
||||
clear_aes_keyslot(0xD);
|
||||
|
||||
/* Derive device keys. */
|
||||
decrypt_data_into_keyslot(0xA, 0xF, devicekey_4x_seed, 0x10);
|
||||
decrypt_data_into_keyslot(0xF, 0xF, devicekey_seed, 0x10);
|
||||
clear_aes_keyslot(0xD);
|
||||
|
||||
/* Derive firmware specific device key. */
|
||||
se_aes_ecb_decrypt_block(0xA, work_buffer, 0x10, master_devkey_seeds[derivation_id], 0x10);
|
||||
decrypt_data_into_keyslot(0xE, 0xE, work_buffer, 0x10);
|
||||
clear_aes_keyslot(0xD);
|
||||
|
||||
/* Test against a vector. */
|
||||
for (size_t i = 0; i < 4; i++) {
|
||||
work_buffer[i] = 0;
|
||||
}
|
||||
if (memcmp(work_buffer, zeroes, 0x10) != 0) {
|
||||
clear_aes_keyslot(0xE);
|
||||
clear_aes_keyslot(0xD);
|
||||
clear_aes_keyslot(0xC);
|
||||
clear_aes_keyslot(0xA);
|
||||
clear_aes_keyslot(0xF);
|
||||
generic_panic();
|
||||
}
|
||||
|
||||
se_aes_ecb_decrypt_block(0xE, work_buffer, 0x10, master_devkey_vectors[derivation_id], 0x10);
|
||||
|
||||
if (memcmp(work_buffer, zeroes, 0x10) == 0) {
|
||||
clear_aes_keyslot(0xE);
|
||||
clear_aes_keyslot(0xD);
|
||||
clear_aes_keyslot(0xC);
|
||||
clear_aes_keyslot(0xA);
|
||||
clear_aes_keyslot(0xF);
|
||||
generic_panic();
|
||||
}
|
||||
|
||||
/* Clear work buffer. */
|
||||
for (size_t i = 0; i < 4; i++) {
|
||||
work_buffer[i] = 0xCCCCCCCC;
|
||||
}
|
||||
|
||||
/* Save context for real. */
|
||||
se_set_in_context_save_mode(true);
|
||||
se_save_context(KEYSLOT_SWITCH_SRKGENKEY, KEYSLOT_SWITCH_RNGKEY, enc_se_state);
|
||||
se_set_in_context_save_mode(false);
|
||||
}
|
||||
|
||||
/* Clear all keyslots. */
|
||||
for (size_t i = 0; i < 0x10; i++) {
|
||||
clear_aes_keyslot(i);
|
||||
}
|
||||
|
||||
*mailbox = 7;
|
||||
while (1) { /* Wait for sept to handle the rest. */ }
|
||||
}
|
||||
26
sept/sept-secondary/key_derivation/src/key_derivation.h
Normal file
26
sept/sept-secondary/key_derivation/src/key_derivation.h
Normal file
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2019 Atmosphère-NX
|
||||
*
|
||||
* 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_KEYDERIVATION_H
|
||||
#define SEPT_KEYDERIVATION_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
void derive_keys(void);
|
||||
|
||||
#endif
|
||||
626
sept/sept-secondary/key_derivation/src/pmc.h
Normal file
626
sept/sept-secondary/key_derivation/src/pmc.h
Normal file
@@ -0,0 +1,626 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2019 Atmosphère-NX
|
||||
*
|
||||
* 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 FUSEE_PMC_H
|
||||
#define FUSEE_PMC_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define PMC_BASE 0x7000E400
|
||||
#define MAKE_PMC_REG(n) MAKE_REG32(PMC_BASE + n)
|
||||
|
||||
#define PMC_CONTROL_SDMMC1 (1 << 12)
|
||||
#define PMC_CONTROL_SDMMC3 (1 << 13)
|
||||
#define PMC_CONTROL_SDMMC4 (1 << 14)
|
||||
|
||||
#define APBDEV_PMC_CONTROL MAKE_PMC_REG(0x00)
|
||||
#define APBDEV_PM_0 MAKE_PMC_REG(0x14)
|
||||
#define APBDEV_PMC_DPD_ENABLE_0 MAKE_PMC_REG(0x24)
|
||||
#define APBDEV_PMC_PWRGATE_TOGGLE_0 MAKE_PMC_REG(0x30)
|
||||
#define APBDEV_PMC_PWRGATE_STATUS_0 MAKE_PMC_REG(0x38)
|
||||
#define APBDEV_PMC_NO_IOPOWER_0 MAKE_PMC_REG(0x44)
|
||||
#define APBDEV_PMC_SCRATCH0_0 MAKE_PMC_REG(0x50)
|
||||
#define APBDEV_PMC_SCRATCH1_0 MAKE_PMC_REG(0x54)
|
||||
#define APBDEV_PMC_SCRATCH20_0 MAKE_PMC_REG(0xA0)
|
||||
#define APBDEV_PMC_PWR_DET_VAL_0 MAKE_PMC_REG(0xE4)
|
||||
#define APBDEV_PMC_DDR_PWR_0 MAKE_PMC_REG(0xE8)
|
||||
#define APBDEV_PMC_CRYPTO_OP_0 MAKE_PMC_REG(0xF4)
|
||||
#define APBDEV_PMC_WAKE2_STATUS_0 MAKE_PMC_REG(0x168)
|
||||
#define APBDEV_PMC_OSC_EDPD_OVER_0 MAKE_PMC_REG(0x1A4)
|
||||
#define APBDEV_PMC_RST_STATUS_0 MAKE_PMC_REG(0x1B4)
|
||||
#define APBDEV_PMC_IO_DPD_REQ_0 MAKE_PMC_REG(0x1B8)
|
||||
#define APBDEV_PMC_IO_DPD2_REQ_0 MAKE_PMC_REG(0x1C0)
|
||||
#define APBDEV_PMC_VDDP_SEL_0 MAKE_PMC_REG(0x1CC)
|
||||
#define APBDEV_PMC_SCRATCH49_0 MAKE_PMC_REG(0x244)
|
||||
#define APBDEV_PMC_TSC_MULT_0 MAKE_PMC_REG(0x2B4)
|
||||
#define APBDEV_PMC_REG_SHORT_0 MAKE_PMC_REG(0x2CC)
|
||||
#define APBDEV_PMC_WEAK_BIAS_0 MAKE_PMC_REG(0x2C8)
|
||||
#define APBDEV_PMC_SECURE_SCRATCH21_0 MAKE_PMC_REG(0x334)
|
||||
#define APBDEV_PMC_SECURE_SCRATCH32_0 MAKE_PMC_REG(0x360)
|
||||
#define APBDEV_PMC_SECURE_SCRATCH49_0 MAKE_PMC_REG(0x3A4)
|
||||
#define APBDEV_PMC_CNTRL2_0 MAKE_PMC_REG(0x440)
|
||||
#define APBDEV_PMC_IO_DPD4_REQ_0 MAKE_PMC_REG(0x464)
|
||||
#define APBDEV_PMC_UTMIP_PAD_CFG1_0 MAKE_PMC_REG(0x4C4)
|
||||
#define APBDEV_PMC_UTMIP_PAD_CFG3_0 MAKE_PMC_REG(0x4CC)
|
||||
#define APBDEV_PMC_DDR_CNTRL_0 MAKE_PMC_REG(0x4E4)
|
||||
#define APBDEV_PMC_SCRATCH43_0 MAKE_PMC_REG(0x22C)
|
||||
#define APBDEV_PMC_SCRATCH188_0 MAKE_PMC_REG(0x810)
|
||||
#define APBDEV_PMC_SCRATCH190_0 MAKE_PMC_REG(0x818)
|
||||
#define APBDEV_PMC_SCRATCH200_0 MAKE_PMC_REG(0x840)
|
||||
|
||||
#define APBDEV_PMC_SCRATCH45_0 MAKE_PMC_REG(0x234)
|
||||
#define APBDEV_PMC_SCRATCH46_0 MAKE_PMC_REG(0x238)
|
||||
#define APBDEV_PMC_SCRATCH33_0 MAKE_PMC_REG(0x120)
|
||||
#define APBDEV_PMC_SCRATCH40_0 MAKE_PMC_REG(0x13C)
|
||||
|
||||
typedef struct {
|
||||
uint32_t cntrl;
|
||||
uint32_t sec_disable;
|
||||
uint32_t pmc_swrst;
|
||||
uint32_t wake_mask;
|
||||
uint32_t wake_lvl;
|
||||
uint32_t wake_status;
|
||||
uint32_t sw_wake_status;
|
||||
uint32_t dpd_pads_oride;
|
||||
uint32_t dpd_sample;
|
||||
uint32_t dpd_enable;
|
||||
uint32_t pwrgate_timer_off;
|
||||
uint32_t clamp_status;
|
||||
uint32_t pwrgate_toggle;
|
||||
uint32_t remove_clamping;
|
||||
uint32_t pwrgate_status;
|
||||
uint32_t pwrgood_timer;
|
||||
uint32_t blink_timer;
|
||||
uint32_t no_iopower;
|
||||
uint32_t pwr_det;
|
||||
uint32_t pwr_det_latch;
|
||||
uint32_t scratch0;
|
||||
uint32_t scratch1;
|
||||
uint32_t scratch2;
|
||||
uint32_t scratch3;
|
||||
uint32_t scratch4;
|
||||
uint32_t scratch5;
|
||||
uint32_t scratch6;
|
||||
uint32_t scratch7;
|
||||
uint32_t scratch8;
|
||||
uint32_t scratch9;
|
||||
uint32_t scratch10;
|
||||
uint32_t scratch11;
|
||||
uint32_t scratch12;
|
||||
uint32_t scratch13;
|
||||
uint32_t scratch14;
|
||||
uint32_t scratch15;
|
||||
uint32_t scratch16;
|
||||
uint32_t scratch17;
|
||||
uint32_t scratch18;
|
||||
uint32_t scratch19;
|
||||
uint32_t scratch20;
|
||||
uint32_t scratch21;
|
||||
uint32_t scratch22;
|
||||
uint32_t scratch23;
|
||||
uint32_t secure_scratch0;
|
||||
uint32_t secure_scratch1;
|
||||
uint32_t secure_scratch2;
|
||||
uint32_t secure_scratch3;
|
||||
uint32_t secure_scratch4;
|
||||
uint32_t secure_scratch5;
|
||||
uint32_t cpupwrgood_timer;
|
||||
uint32_t cpupwroff_timer;
|
||||
uint32_t pg_mask;
|
||||
uint32_t pg_mask_1;
|
||||
uint32_t auto_wake_lvl;
|
||||
uint32_t auto_wake_lvl_mask;
|
||||
uint32_t wake_delay;
|
||||
uint32_t pwr_det_val;
|
||||
uint32_t ddr_pwr;
|
||||
uint32_t usb_debounce_del;
|
||||
uint32_t usb_ao;
|
||||
uint32_t crypto_op;
|
||||
uint32_t pllp_wb0_override;
|
||||
uint32_t scratch24;
|
||||
uint32_t scratch25;
|
||||
uint32_t scratch26;
|
||||
uint32_t scratch27;
|
||||
uint32_t scratch28;
|
||||
uint32_t scratch29;
|
||||
uint32_t scratch30;
|
||||
uint32_t scratch31;
|
||||
uint32_t scratch32;
|
||||
uint32_t scratch33;
|
||||
uint32_t scratch34;
|
||||
uint32_t scratch35;
|
||||
uint32_t scratch36;
|
||||
uint32_t scratch37;
|
||||
uint32_t scratch38;
|
||||
uint32_t scratch39;
|
||||
uint32_t scratch40;
|
||||
uint32_t scratch41;
|
||||
uint32_t scratch42;
|
||||
uint32_t bo_mirror0;
|
||||
uint32_t bo_mirror1;
|
||||
uint32_t bo_mirror2;
|
||||
uint32_t sys_33v_en;
|
||||
uint32_t bo_mirror_access;
|
||||
uint32_t gate;
|
||||
uint32_t wake2_mask;
|
||||
uint32_t wake2_lvl;
|
||||
uint32_t wake2_stat;
|
||||
uint32_t sw_wake2_stat;
|
||||
uint32_t auto_wake2_lvl_mask;
|
||||
uint32_t pg_mask2;
|
||||
uint32_t pg_mask_ce1;
|
||||
uint32_t pg_mask_ce2;
|
||||
uint32_t pg_mask_ce3;
|
||||
uint32_t pwrgate_timer_ce0;
|
||||
uint32_t pwrgate_timer_ce1;
|
||||
uint32_t pwrgate_timer_ce2;
|
||||
uint32_t pwrgate_timer_ce3;
|
||||
uint32_t pwrgate_timer_ce4;
|
||||
uint32_t pwrgate_timer_ce5;
|
||||
uint32_t pwrgate_timer_ce6;
|
||||
uint32_t pcx_edpd_cntrl;
|
||||
uint32_t osc_edpd_over;
|
||||
uint32_t clk_out_cntrl;
|
||||
uint32_t sata_pwrgate;
|
||||
uint32_t sensor_ctrl;
|
||||
uint32_t reset_status;
|
||||
uint32_t io_dpd_req;
|
||||
uint32_t io_dpd_stat;
|
||||
uint32_t io_dpd2_req;
|
||||
uint32_t io_dpd2_stat;
|
||||
uint32_t sel_dpd_tim;
|
||||
uint32_t vddp_sel;
|
||||
uint32_t ddr_cfg;
|
||||
uint32_t e_no_vttgen;
|
||||
uint32_t _reserved0;
|
||||
uint32_t pllm_wb0_ovrride_frq;
|
||||
uint32_t test_pwrgate;
|
||||
uint32_t pwrgate_timer_mult;
|
||||
uint32_t dsi_sel_dpd;
|
||||
uint32_t utmip_uhsic_triggers;
|
||||
uint32_t utmip_uhsic_saved_st;
|
||||
uint32_t utmip_pad_cfg;
|
||||
uint32_t utmip_term_pad_cfg;
|
||||
uint32_t utmip_uhsic_sleep_cfg;
|
||||
uint32_t utmip_uhsic_sleepwalk_cfg;
|
||||
uint32_t utmip_sleepwalk_p[3];
|
||||
uint32_t uhsic_sleepwalk_p0;
|
||||
uint32_t utmip_uhsic_status;
|
||||
uint32_t utmip_uhsic_fake;
|
||||
uint32_t bo_mirror3[2];
|
||||
uint32_t secure_scratch6;
|
||||
uint32_t secure_scratch7;
|
||||
uint32_t scratch43;
|
||||
uint32_t scratch44;
|
||||
uint32_t scratch45;
|
||||
uint32_t scratch46;
|
||||
uint32_t scratch47;
|
||||
uint32_t scratch48;
|
||||
uint32_t scratch49;
|
||||
uint32_t scratch50;
|
||||
uint32_t scratch51;
|
||||
uint32_t scratch52;
|
||||
uint32_t scratch53;
|
||||
uint32_t scratch54;
|
||||
uint32_t scratch55;
|
||||
uint32_t scratch0_eco;
|
||||
uint32_t por_dpd_ctrl;
|
||||
uint32_t scratch2_eco;
|
||||
uint32_t utmip_uhsic_line_wakeup;
|
||||
uint32_t utmip_bias_master_cntrl;
|
||||
uint32_t utmip_master_config;
|
||||
uint32_t td_pwrgate_inter_part_timer;
|
||||
uint32_t utmip_uhsic2_triggers;
|
||||
uint32_t utmip_uhsic2_saved_state;
|
||||
uint32_t utmip_uhsic2_sleep_cfg;
|
||||
uint32_t utmip_uhsic2_sleepwalk_cfg;
|
||||
uint32_t uhsic2_sleepwalk_p1;
|
||||
uint32_t utmip_uhsic2_status;
|
||||
uint32_t utmip_uhsic2_fake;
|
||||
uint32_t utmip_uhsic2_line_wakeup;
|
||||
uint32_t utmip_master2_config;
|
||||
uint32_t utmip_uhsic_rpd_cfg;
|
||||
uint32_t pg_mask_ce0;
|
||||
uint32_t pg_mask3[2];
|
||||
uint32_t pllm_wb0_override2;
|
||||
uint32_t tsc_mult;
|
||||
uint32_t cpu_vsense_override;
|
||||
uint32_t glb_amap_cfg;
|
||||
uint32_t sticky_bits;
|
||||
uint32_t sec_disable2;
|
||||
uint32_t weak_bias;
|
||||
uint32_t reg_short;
|
||||
uint32_t pg_mask_andor;
|
||||
uint32_t _reserved1[11];
|
||||
uint32_t secure_scratch8;
|
||||
uint32_t secure_scratch9;
|
||||
uint32_t secure_scratch10;
|
||||
uint32_t secure_scratch11;
|
||||
uint32_t secure_scratch12;
|
||||
uint32_t secure_scratch13;
|
||||
uint32_t secure_scratch14;
|
||||
uint32_t secure_scratch15;
|
||||
uint32_t secure_scratch16;
|
||||
uint32_t secure_scratch17;
|
||||
uint32_t secure_scratch18;
|
||||
uint32_t secure_scratch19;
|
||||
uint32_t secure_scratch20;
|
||||
uint32_t secure_scratch21;
|
||||
uint32_t secure_scratch22;
|
||||
uint32_t secure_scratch23;
|
||||
uint32_t secure_scratch24;
|
||||
uint32_t secure_scratch25;
|
||||
uint32_t secure_scratch26;
|
||||
uint32_t secure_scratch27;
|
||||
uint32_t secure_scratch28;
|
||||
uint32_t secure_scratch29;
|
||||
uint32_t secure_scratch30;
|
||||
uint32_t secure_scratch31;
|
||||
uint32_t secure_scratch32;
|
||||
uint32_t secure_scratch33;
|
||||
uint32_t secure_scratch34;
|
||||
uint32_t secure_scratch35;
|
||||
uint32_t secure_scratch36;
|
||||
uint32_t secure_scratch37;
|
||||
uint32_t secure_scratch38;
|
||||
uint32_t secure_scratch39;
|
||||
uint32_t secure_scratch40;
|
||||
uint32_t secure_scratch41;
|
||||
uint32_t secure_scratch42;
|
||||
uint32_t secure_scratch43;
|
||||
uint32_t secure_scratch44;
|
||||
uint32_t secure_scratch45;
|
||||
uint32_t secure_scratch46;
|
||||
uint32_t secure_scratch47;
|
||||
uint32_t secure_scratch48;
|
||||
uint32_t secure_scratch49;
|
||||
uint32_t secure_scratch50;
|
||||
uint32_t secure_scratch51;
|
||||
uint32_t secure_scratch52;
|
||||
uint32_t secure_scratch53;
|
||||
uint32_t secure_scratch54;
|
||||
uint32_t secure_scratch55;
|
||||
uint32_t secure_scratch56;
|
||||
uint32_t secure_scratch57;
|
||||
uint32_t secure_scratch58;
|
||||
uint32_t secure_scratch59;
|
||||
uint32_t secure_scratch60;
|
||||
uint32_t secure_scratch61;
|
||||
uint32_t secure_scratch62;
|
||||
uint32_t secure_scratch63;
|
||||
uint32_t secure_scratch64;
|
||||
uint32_t secure_scratch65;
|
||||
uint32_t secure_scratch66;
|
||||
uint32_t secure_scratch67;
|
||||
uint32_t secure_scratch68;
|
||||
uint32_t secure_scratch69;
|
||||
uint32_t secure_scratch70;
|
||||
uint32_t secure_scratch71;
|
||||
uint32_t secure_scratch72;
|
||||
uint32_t secure_scratch73;
|
||||
uint32_t secure_scratch74;
|
||||
uint32_t secure_scratch75;
|
||||
uint32_t secure_scratch76;
|
||||
uint32_t secure_scratch77;
|
||||
uint32_t secure_scratch78;
|
||||
uint32_t secure_scratch79;
|
||||
uint32_t _reserved2[8];
|
||||
uint32_t cntrl2;
|
||||
uint32_t _reserved3[2];
|
||||
uint32_t event_counter;
|
||||
uint32_t fuse_control;
|
||||
uint32_t scratch1_eco;
|
||||
uint32_t _reserved4;
|
||||
uint32_t io_dpd3_req;
|
||||
uint32_t io_dpd3_status;
|
||||
uint32_t io_dpd4_req;
|
||||
uint32_t io_dpd4_status;
|
||||
uint32_t _reserved5[30];
|
||||
uint32_t ddr_cntrl;
|
||||
uint32_t _reserved6[70];
|
||||
uint32_t scratch56;
|
||||
uint32_t scratch57;
|
||||
uint32_t scratch58;
|
||||
uint32_t scratch59;
|
||||
uint32_t scratch60;
|
||||
uint32_t scratch61;
|
||||
uint32_t scratch62;
|
||||
uint32_t scratch63;
|
||||
uint32_t scratch64;
|
||||
uint32_t scratch65;
|
||||
uint32_t scratch66;
|
||||
uint32_t scratch67;
|
||||
uint32_t scratch68;
|
||||
uint32_t scratch69;
|
||||
uint32_t scratch70;
|
||||
uint32_t scratch71;
|
||||
uint32_t scratch72;
|
||||
uint32_t scratch73;
|
||||
uint32_t scratch74;
|
||||
uint32_t scratch75;
|
||||
uint32_t scratch76;
|
||||
uint32_t scratch77;
|
||||
uint32_t scratch78;
|
||||
uint32_t scratch79;
|
||||
uint32_t scratch80;
|
||||
uint32_t scratch81;
|
||||
uint32_t scratch82;
|
||||
uint32_t scratch83;
|
||||
uint32_t scratch84;
|
||||
uint32_t scratch85;
|
||||
uint32_t scratch86;
|
||||
uint32_t scratch87;
|
||||
uint32_t scratch88;
|
||||
uint32_t scratch89;
|
||||
uint32_t scratch90;
|
||||
uint32_t scratch91;
|
||||
uint32_t scratch92;
|
||||
uint32_t scratch93;
|
||||
uint32_t scratch94;
|
||||
uint32_t scratch95;
|
||||
uint32_t scratch96;
|
||||
uint32_t scratch97;
|
||||
uint32_t scratch98;
|
||||
uint32_t scratch99;
|
||||
uint32_t scratch100;
|
||||
uint32_t scratch101;
|
||||
uint32_t scratch102;
|
||||
uint32_t scratch103;
|
||||
uint32_t scratch104;
|
||||
uint32_t scratch105;
|
||||
uint32_t scratch106;
|
||||
uint32_t scratch107;
|
||||
uint32_t scratch108;
|
||||
uint32_t scratch109;
|
||||
uint32_t scratch110;
|
||||
uint32_t scratch111;
|
||||
uint32_t scratch112;
|
||||
uint32_t scratch113;
|
||||
uint32_t scratch114;
|
||||
uint32_t scratch115;
|
||||
uint32_t scratch116;
|
||||
uint32_t scratch117;
|
||||
uint32_t scratch118;
|
||||
uint32_t scratch119;
|
||||
uint32_t scratch120;
|
||||
uint32_t scratch121;
|
||||
uint32_t scratch122;
|
||||
uint32_t scratch123;
|
||||
uint32_t scratch124;
|
||||
uint32_t scratch125;
|
||||
uint32_t scratch126;
|
||||
uint32_t scratch127;
|
||||
uint32_t scratch128;
|
||||
uint32_t scratch129;
|
||||
uint32_t scratch130;
|
||||
uint32_t scratch131;
|
||||
uint32_t scratch132;
|
||||
uint32_t scratch133;
|
||||
uint32_t scratch134;
|
||||
uint32_t scratch135;
|
||||
uint32_t scratch136;
|
||||
uint32_t scratch137;
|
||||
uint32_t scratch138;
|
||||
uint32_t scratch139;
|
||||
uint32_t scratch140;
|
||||
uint32_t scratch141;
|
||||
uint32_t scratch142;
|
||||
uint32_t scratch143;
|
||||
uint32_t scratch144;
|
||||
uint32_t scratch145;
|
||||
uint32_t scratch146;
|
||||
uint32_t scratch147;
|
||||
uint32_t scratch148;
|
||||
uint32_t scratch149;
|
||||
uint32_t scratch150;
|
||||
uint32_t scratch151;
|
||||
uint32_t scratch152;
|
||||
uint32_t scratch153;
|
||||
uint32_t scratch154;
|
||||
uint32_t scratch155;
|
||||
uint32_t scratch156;
|
||||
uint32_t scratch157;
|
||||
uint32_t scratch158;
|
||||
uint32_t scratch159;
|
||||
uint32_t scratch160;
|
||||
uint32_t scratch161;
|
||||
uint32_t scratch162;
|
||||
uint32_t scratch163;
|
||||
uint32_t scratch164;
|
||||
uint32_t scratch165;
|
||||
uint32_t scratch166;
|
||||
uint32_t scratch167;
|
||||
uint32_t scratch168;
|
||||
uint32_t scratch169;
|
||||
uint32_t scratch170;
|
||||
uint32_t scratch171;
|
||||
uint32_t scratch172;
|
||||
uint32_t scratch173;
|
||||
uint32_t scratch174;
|
||||
uint32_t scratch175;
|
||||
uint32_t scratch176;
|
||||
uint32_t scratch177;
|
||||
uint32_t scratch178;
|
||||
uint32_t scratch179;
|
||||
uint32_t scratch180;
|
||||
uint32_t scratch181;
|
||||
uint32_t scratch182;
|
||||
uint32_t scratch183;
|
||||
uint32_t scratch184;
|
||||
uint32_t scratch185;
|
||||
uint32_t scratch186;
|
||||
uint32_t scratch187;
|
||||
uint32_t scratch188;
|
||||
uint32_t scratch189;
|
||||
uint32_t scratch190;
|
||||
uint32_t scratch191;
|
||||
uint32_t scratch192;
|
||||
uint32_t scratch193;
|
||||
uint32_t scratch194;
|
||||
uint32_t scratch195;
|
||||
uint32_t scratch196;
|
||||
uint32_t scratch197;
|
||||
uint32_t scratch198;
|
||||
uint32_t scratch199;
|
||||
uint32_t scratch200;
|
||||
uint32_t scratch201;
|
||||
uint32_t scratch202;
|
||||
uint32_t scratch203;
|
||||
uint32_t scratch204;
|
||||
uint32_t scratch205;
|
||||
uint32_t scratch206;
|
||||
uint32_t scratch207;
|
||||
uint32_t scratch208;
|
||||
uint32_t scratch209;
|
||||
uint32_t scratch210;
|
||||
uint32_t scratch211;
|
||||
uint32_t scratch212;
|
||||
uint32_t scratch213;
|
||||
uint32_t scratch214;
|
||||
uint32_t scratch215;
|
||||
uint32_t scratch216;
|
||||
uint32_t scratch217;
|
||||
uint32_t scratch218;
|
||||
uint32_t scratch219;
|
||||
uint32_t scratch220;
|
||||
uint32_t scratch221;
|
||||
uint32_t scratch222;
|
||||
uint32_t scratch223;
|
||||
uint32_t scratch224;
|
||||
uint32_t scratch225;
|
||||
uint32_t scratch226;
|
||||
uint32_t scratch227;
|
||||
uint32_t scratch228;
|
||||
uint32_t scratch229;
|
||||
uint32_t scratch230;
|
||||
uint32_t scratch231;
|
||||
uint32_t scratch232;
|
||||
uint32_t scratch233;
|
||||
uint32_t scratch234;
|
||||
uint32_t scratch235;
|
||||
uint32_t scratch236;
|
||||
uint32_t scratch237;
|
||||
uint32_t scratch238;
|
||||
uint32_t scratch239;
|
||||
uint32_t scratch240;
|
||||
uint32_t scratch241;
|
||||
uint32_t scratch242;
|
||||
uint32_t scratch243;
|
||||
uint32_t scratch244;
|
||||
uint32_t scratch245;
|
||||
uint32_t scratch246;
|
||||
uint32_t scratch247;
|
||||
uint32_t scratch248;
|
||||
uint32_t scratch249;
|
||||
uint32_t scratch250;
|
||||
uint32_t scratch251;
|
||||
uint32_t scratch252;
|
||||
uint32_t scratch253;
|
||||
uint32_t scratch254;
|
||||
uint32_t scratch255;
|
||||
uint32_t scratch256;
|
||||
uint32_t scratch257;
|
||||
uint32_t scratch258;
|
||||
uint32_t scratch259;
|
||||
uint32_t scratch260;
|
||||
uint32_t scratch261;
|
||||
uint32_t scratch262;
|
||||
uint32_t scratch263;
|
||||
uint32_t scratch264;
|
||||
uint32_t scratch265;
|
||||
uint32_t scratch266;
|
||||
uint32_t scratch267;
|
||||
uint32_t scratch268;
|
||||
uint32_t scratch269;
|
||||
uint32_t scratch270;
|
||||
uint32_t scratch271;
|
||||
uint32_t scratch272;
|
||||
uint32_t scratch273;
|
||||
uint32_t scratch274;
|
||||
uint32_t scratch275;
|
||||
uint32_t scratch276;
|
||||
uint32_t scratch277;
|
||||
uint32_t scratch278;
|
||||
uint32_t scratch279;
|
||||
uint32_t scratch280;
|
||||
uint32_t scratch281;
|
||||
uint32_t scratch282;
|
||||
uint32_t scratch283;
|
||||
uint32_t scratch284;
|
||||
uint32_t scratch285;
|
||||
uint32_t scratch286;
|
||||
uint32_t scratch287;
|
||||
uint32_t scratch288;
|
||||
uint32_t scratch289;
|
||||
uint32_t scratch290;
|
||||
uint32_t scratch291;
|
||||
uint32_t scratch292;
|
||||
uint32_t scratch293;
|
||||
uint32_t scratch294;
|
||||
uint32_t scratch295;
|
||||
uint32_t scratch296;
|
||||
uint32_t scratch297;
|
||||
uint32_t scratch298;
|
||||
uint32_t scratch299;
|
||||
uint32_t _reserved7[50];
|
||||
uint32_t secure_scratch80;
|
||||
uint32_t secure_scratch81;
|
||||
uint32_t secure_scratch82;
|
||||
uint32_t secure_scratch83;
|
||||
uint32_t secure_scratch84;
|
||||
uint32_t secure_scratch85;
|
||||
uint32_t secure_scratch86;
|
||||
uint32_t secure_scratch87;
|
||||
uint32_t secure_scratch88;
|
||||
uint32_t secure_scratch89;
|
||||
uint32_t secure_scratch90;
|
||||
uint32_t secure_scratch91;
|
||||
uint32_t secure_scratch92;
|
||||
uint32_t secure_scratch93;
|
||||
uint32_t secure_scratch94;
|
||||
uint32_t secure_scratch95;
|
||||
uint32_t secure_scratch96;
|
||||
uint32_t secure_scratch97;
|
||||
uint32_t secure_scratch98;
|
||||
uint32_t secure_scratch99;
|
||||
uint32_t secure_scratch100;
|
||||
uint32_t secure_scratch101;
|
||||
uint32_t secure_scratch102;
|
||||
uint32_t secure_scratch103;
|
||||
uint32_t secure_scratch104;
|
||||
uint32_t secure_scratch105;
|
||||
uint32_t secure_scratch106;
|
||||
uint32_t secure_scratch107;
|
||||
uint32_t secure_scratch108;
|
||||
uint32_t secure_scratch109;
|
||||
uint32_t secure_scratch110;
|
||||
uint32_t secure_scratch111;
|
||||
uint32_t secure_scratch112;
|
||||
uint32_t secure_scratch113;
|
||||
uint32_t secure_scratch114;
|
||||
uint32_t secure_scratch115;
|
||||
uint32_t secure_scratch116;
|
||||
uint32_t secure_scratch117;
|
||||
uint32_t secure_scratch118;
|
||||
uint32_t secure_scratch119;
|
||||
} tegra_pmc_t;
|
||||
|
||||
static inline volatile tegra_pmc_t *pmc_get_regs(void)
|
||||
{
|
||||
return (volatile tegra_pmc_t *)PMC_BASE;
|
||||
}
|
||||
|
||||
#endif
|
||||
757
sept/sept-secondary/key_derivation/src/se.c
Normal file
757
sept/sept-secondary/key_derivation/src/se.c
Normal file
@@ -0,0 +1,757 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2019 Atmosphère-NX
|
||||
*
|
||||
* 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 "utils.h"
|
||||
#include "se.h"
|
||||
|
||||
void trigger_se_blocking_op(unsigned int op, void *dst, size_t dst_size, const void *src, size_t src_size);
|
||||
|
||||
/* Globals for driver. */
|
||||
static unsigned int g_se_modulus_sizes[KEYSLOT_RSA_MAX];
|
||||
static unsigned int g_se_exp_sizes[KEYSLOT_RSA_MAX];
|
||||
|
||||
/* Initialize a SE linked list. */
|
||||
void NOINLINE ll_init(volatile se_ll_t *ll, void *buffer, size_t size) {
|
||||
ll->num_entries = 0; /* 1 Entry. */
|
||||
|
||||
if (buffer != NULL) {
|
||||
ll->addr_info.address = (uint32_t) get_physical_address(buffer);
|
||||
ll->addr_info.size = (uint32_t) size;
|
||||
} else {
|
||||
ll->addr_info.address = 0;
|
||||
ll->addr_info.size = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void se_check_error_status_reg(void) {
|
||||
if (se_get_regs()->ERR_STATUS_REG) {
|
||||
generic_panic();
|
||||
}
|
||||
}
|
||||
|
||||
void se_check_for_error(void) {
|
||||
volatile tegra_se_t *se = se_get_regs();
|
||||
if (se->INT_STATUS_REG & 0x10000 || se->FLAGS_REG & 3 || se->ERR_STATUS_REG) {
|
||||
generic_panic();
|
||||
}
|
||||
}
|
||||
|
||||
void se_verify_flags_cleared(void) {
|
||||
if (se_get_regs()->FLAGS_REG & 3) {
|
||||
generic_panic();
|
||||
}
|
||||
}
|
||||
|
||||
/* Set the flags for an AES keyslot. */
|
||||
void set_aes_keyslot_flags(unsigned int keyslot, unsigned int flags) {
|
||||
volatile tegra_se_t *se = se_get_regs();
|
||||
|
||||
if (keyslot >= KEYSLOT_AES_MAX) {
|
||||
generic_panic();
|
||||
}
|
||||
|
||||
/* Misc flags. */
|
||||
if (flags & ~0x80) {
|
||||
se->AES_KEYSLOT_FLAGS[keyslot] = ~flags;
|
||||
}
|
||||
|
||||
/* Disable keyslot reads. */
|
||||
if (flags & 0x80) {
|
||||
se->AES_KEY_READ_DISABLE_REG &= ~(1 << keyslot);
|
||||
}
|
||||
}
|
||||
|
||||
/* Set the flags for an RSA keyslot. */
|
||||
void set_rsa_keyslot_flags(unsigned int keyslot, unsigned int flags) {
|
||||
volatile tegra_se_t *se = se_get_regs();
|
||||
|
||||
if (keyslot >= KEYSLOT_RSA_MAX) {
|
||||
generic_panic();
|
||||
}
|
||||
|
||||
/* Misc flags. */
|
||||
if (flags & ~0x80) {
|
||||
/* TODO: Why are flags assigned this way? */
|
||||
se->RSA_KEYSLOT_FLAGS[keyslot] = (((flags >> 4) & 4) | (flags & 3)) ^ 7;
|
||||
}
|
||||
|
||||
/* Disable keyslot reads. */
|
||||
if (flags & 0x80) {
|
||||
se->RSA_KEY_READ_DISABLE_REG &= ~(1 << keyslot);
|
||||
}
|
||||
}
|
||||
|
||||
void clear_aes_keyslot(unsigned int keyslot) {
|
||||
volatile tegra_se_t *se = se_get_regs();
|
||||
|
||||
if (keyslot >= KEYSLOT_AES_MAX) {
|
||||
generic_panic();
|
||||
}
|
||||
|
||||
/* Zero out the whole keyslot and IV. */
|
||||
for (unsigned int i = 0; i < 0x10; i++) {
|
||||
se->AES_KEYTABLE_ADDR = (keyslot << 4) | i;
|
||||
se->AES_KEYTABLE_DATA = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void clear_rsa_keyslot(unsigned int keyslot) {
|
||||
volatile tegra_se_t *se = se_get_regs();
|
||||
|
||||
if (keyslot >= KEYSLOT_RSA_MAX) {
|
||||
generic_panic();
|
||||
}
|
||||
|
||||
/* Zero out the whole keyslot. */
|
||||
for (unsigned int i = 0; i < 0x40; i++) {
|
||||
/* Select Keyslot Modulus[i] */
|
||||
se->RSA_KEYTABLE_ADDR = (keyslot << 7) | i | 0x40;
|
||||
se->RSA_KEYTABLE_DATA = 0;
|
||||
}
|
||||
for (unsigned int i = 0; i < 0x40; i++) {
|
||||
/* Select Keyslot Expontent[i] */
|
||||
se->RSA_KEYTABLE_ADDR = (keyslot << 7) | i;
|
||||
se->RSA_KEYTABLE_DATA = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void set_aes_keyslot(unsigned int keyslot, const void *key, size_t key_size) {
|
||||
volatile tegra_se_t *se = se_get_regs();
|
||||
|
||||
if (keyslot >= KEYSLOT_AES_MAX || key_size > KEYSIZE_AES_MAX) {
|
||||
generic_panic();
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < (key_size >> 2); i++) {
|
||||
se->AES_KEYTABLE_ADDR = (keyslot << 4) | i;
|
||||
se->AES_KEYTABLE_DATA = read32le(key, 4 * i);
|
||||
}
|
||||
}
|
||||
|
||||
void set_rsa_keyslot(unsigned int keyslot, const void *modulus, size_t modulus_size, const void *exponent, size_t exp_size) {
|
||||
volatile tegra_se_t *se = se_get_regs();
|
||||
|
||||
if (keyslot >= KEYSLOT_RSA_MAX || modulus_size > KEYSIZE_RSA_MAX || exp_size > KEYSIZE_RSA_MAX) {
|
||||
generic_panic();
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < (modulus_size >> 2); i++) {
|
||||
se->RSA_KEYTABLE_ADDR = (keyslot << 7) | 0x40 | i;
|
||||
se->RSA_KEYTABLE_DATA = read32be(modulus, (4 * (modulus_size >> 2)) - (4 * i) - 4);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < (exp_size >> 2); i++) {
|
||||
se->RSA_KEYTABLE_ADDR = (keyslot << 7) | i;
|
||||
se->RSA_KEYTABLE_DATA = read32be(exponent, (4 * (exp_size >> 2)) - (4 * i) - 4);
|
||||
}
|
||||
|
||||
g_se_modulus_sizes[keyslot] = modulus_size;
|
||||
g_se_exp_sizes[keyslot] = exp_size;
|
||||
}
|
||||
|
||||
void set_aes_keyslot_iv(unsigned int keyslot, const void *iv, size_t iv_size) {
|
||||
volatile tegra_se_t *se = se_get_regs();
|
||||
|
||||
if (keyslot >= KEYSLOT_AES_MAX || iv_size > 0x10) {
|
||||
generic_panic();
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < (iv_size >> 2); i++) {
|
||||
se->AES_KEYTABLE_ADDR = (keyslot << 4) | 8 | i;
|
||||
se->AES_KEYTABLE_DATA = read32le(iv, 4 * i);
|
||||
}
|
||||
}
|
||||
|
||||
void clear_aes_keyslot_iv(unsigned int keyslot) {
|
||||
volatile tegra_se_t *se = se_get_regs();
|
||||
|
||||
if (keyslot >= KEYSLOT_AES_MAX) {
|
||||
generic_panic();
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < (0x10 >> 2); i++) {
|
||||
se->AES_KEYTABLE_ADDR = (keyslot << 4) | 8 | i;
|
||||
se->AES_KEYTABLE_DATA = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void set_se_ctr(const void *ctr) {
|
||||
for (unsigned int i = 0; i < 4; i++) {
|
||||
se_get_regs()->CRYPTO_CTR_REG[i] = read32le(ctr, i * 4);
|
||||
}
|
||||
}
|
||||
|
||||
void decrypt_data_into_keyslot(unsigned int keyslot_dst, unsigned int keyslot_src, const void *wrapped_key, size_t wrapped_key_size) {
|
||||
volatile tegra_se_t *se = se_get_regs();
|
||||
|
||||
if (keyslot_dst >= KEYSLOT_AES_MAX || keyslot_src >= KEYSLOT_AES_MAX || wrapped_key_size > KEYSIZE_AES_MAX) {
|
||||
generic_panic();
|
||||
}
|
||||
|
||||
/* Write config, validate. */
|
||||
se->CONFIG_REG = (ALG_AES_DEC | DST_KEYTAB);
|
||||
if (se->CONFIG_REG != (ALG_AES_DEC | DST_KEYTAB)) {
|
||||
generic_panic();
|
||||
}
|
||||
se->CRYPTO_REG = keyslot_src << 24;
|
||||
if (se->CRYPTO_REG != (keyslot_src << 24)) {
|
||||
generic_panic();
|
||||
}
|
||||
se->BLOCK_COUNT_REG = 0;
|
||||
if (se->BLOCK_COUNT_REG != 0) {
|
||||
generic_panic();
|
||||
}
|
||||
se->CRYPTO_KEYTABLE_DST_REG = keyslot_dst << 8;
|
||||
if (se->CRYPTO_KEYTABLE_DST_REG != (keyslot_dst << 8)) {
|
||||
generic_panic();
|
||||
}
|
||||
|
||||
/* Clear address context. */
|
||||
se->IN_LL_ADDR_REG = 0;
|
||||
se->OUT_LL_ADDR_REG = 0;
|
||||
if (se->IN_LL_ADDR_REG != 0 || se->OUT_LL_ADDR_REG != 0) {
|
||||
generic_panic();
|
||||
}
|
||||
|
||||
trigger_se_blocking_op(OP_START, NULL, 0, wrapped_key, wrapped_key_size);
|
||||
|
||||
/* Validate address context. */
|
||||
if (se->IN_LL_ADDR_REG == 0 || se->OUT_LL_ADDR_REG == 0) {
|
||||
generic_panic();
|
||||
}
|
||||
}
|
||||
|
||||
void se_synchronous_exp_mod(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size) {
|
||||
volatile tegra_se_t *se = se_get_regs();
|
||||
uint8_t ALIGN(16) stack_buf[KEYSIZE_RSA_MAX];
|
||||
|
||||
if (keyslot >= KEYSLOT_RSA_MAX || src_size > KEYSIZE_RSA_MAX || dst_size > KEYSIZE_RSA_MAX) {
|
||||
generic_panic();
|
||||
}
|
||||
|
||||
/* Endian swap the input. */
|
||||
for (size_t i = 0; i < src_size; i++) {
|
||||
stack_buf[i] = *((uint8_t *)src + src_size - i - 1);
|
||||
}
|
||||
|
||||
se->CONFIG_REG = (ALG_RSA | DST_RSAREG);
|
||||
se->RSA_CONFIG = keyslot << 24;
|
||||
se->RSA_KEY_SIZE_REG = (g_se_modulus_sizes[keyslot] >> 6) - 1;
|
||||
se->RSA_EXP_SIZE_REG = g_se_exp_sizes[keyslot] >> 2;
|
||||
|
||||
trigger_se_blocking_op(OP_START, NULL, 0, stack_buf, src_size);
|
||||
se_get_exp_mod_output(dst, dst_size);
|
||||
}
|
||||
|
||||
void se_get_exp_mod_output(void *buf, size_t size) {
|
||||
size_t num_dwords = (size >> 2);
|
||||
|
||||
if (num_dwords < 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t *p_out = ((uint32_t *)buf) + num_dwords - 1;
|
||||
uint32_t offset = 0;
|
||||
|
||||
/* Copy endian swapped output. */
|
||||
while (num_dwords) {
|
||||
*p_out = read32be(se_get_regs()->RSA_OUTPUT, offset);
|
||||
offset += 4;
|
||||
p_out--;
|
||||
num_dwords--;
|
||||
}
|
||||
}
|
||||
|
||||
bool se_rsa2048_pss_verify(const void *signature, size_t signature_size, const void *modulus, size_t modulus_size, const void *data, size_t data_size) {
|
||||
uint8_t message[RSA_2048_BYTES];
|
||||
uint8_t h_buf[0x24];
|
||||
|
||||
/* Hardcode RSA with keyslot 0. */
|
||||
const uint8_t public_exponent[4] = {0x00, 0x01, 0x00, 0x01};
|
||||
set_rsa_keyslot(0, modulus, modulus_size, public_exponent, sizeof(public_exponent));
|
||||
se_synchronous_exp_mod(0, message, sizeof(message), signature, signature_size);
|
||||
|
||||
/* Validate sanity byte. */
|
||||
if (message[RSA_2048_BYTES - 1] != 0xBC) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Copy Salt into MGF1 Hash Buffer. */
|
||||
memset(h_buf, 0, sizeof(h_buf));
|
||||
memcpy(h_buf, message + RSA_2048_BYTES - 0x20 - 0x1, 0x20);
|
||||
|
||||
/* Decrypt maskedDB (via inline MGF1). */
|
||||
uint8_t seed = 0;
|
||||
uint8_t mgf1_buf[0x20];
|
||||
for (unsigned int ofs = 0; ofs < RSA_2048_BYTES - 0x20 - 1; ofs += 0x20) {
|
||||
h_buf[sizeof(h_buf) - 1] = seed++;
|
||||
se_calculate_sha256(mgf1_buf, h_buf, sizeof(h_buf));
|
||||
for (unsigned int i = ofs; i < ofs + 0x20 && i < RSA_2048_BYTES - 0x20 - 1; i++) {
|
||||
message[i] ^= mgf1_buf[i - ofs];
|
||||
}
|
||||
}
|
||||
|
||||
/* Constant lmask for rsa-2048-pss. */
|
||||
message[0] &= 0x7F;
|
||||
|
||||
/* Validate DB is of the form 0000...0001. */
|
||||
for (unsigned int i = 0; i < RSA_2048_BYTES - 0x20 - 0x20 - 1 - 1; i++) {
|
||||
if (message[i] != 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (message[RSA_2048_BYTES - 0x20 - 0x20 - 1 - 1] != 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Check hash correctness. */
|
||||
uint8_t validate_buf[8 + 0x20 + 0x20];
|
||||
uint8_t validate_hash[0x20];
|
||||
|
||||
memset(validate_buf, 0, sizeof(validate_buf));
|
||||
se_calculate_sha256(&validate_buf[8], data, data_size);
|
||||
memcpy(&validate_buf[0x28], &message[RSA_2048_BYTES - 0x20 - 0x20 - 1], 0x20);
|
||||
se_calculate_sha256(validate_hash, validate_buf, sizeof(validate_buf));
|
||||
return memcmp(h_buf, validate_hash, 0x20) == 0;
|
||||
}
|
||||
|
||||
void trigger_se_blocking_op(unsigned int op, void *dst, size_t dst_size, const void *src, size_t src_size) {
|
||||
volatile tegra_se_t *se = se_get_regs();
|
||||
se_ll_t in_ll;
|
||||
se_ll_t out_ll;
|
||||
|
||||
ll_init(&in_ll, (void *)src, src_size);
|
||||
ll_init(&out_ll, dst, dst_size);
|
||||
|
||||
/* Set the LLs. */
|
||||
se->IN_LL_ADDR_REG = (uint32_t) get_physical_address(&in_ll);
|
||||
se->OUT_LL_ADDR_REG = (uint32_t) get_physical_address(&out_ll);
|
||||
|
||||
/* Set registers for operation. */
|
||||
se->ERR_STATUS_REG = se->ERR_STATUS_REG;
|
||||
se->INT_STATUS_REG = se->INT_STATUS_REG;
|
||||
|
||||
if (se->IN_LL_ADDR_REG != (uint32_t) get_physical_address(&in_ll) || se->OUT_LL_ADDR_REG != (uint32_t) get_physical_address(&out_ll) || (se->INT_STATUS_REG & 0x10) || (se->FLAGS_REG & 0x3)) {
|
||||
generic_panic();
|
||||
}
|
||||
|
||||
se->OPERATION_REG = op;
|
||||
|
||||
while (!(se->INT_STATUS_REG & 0x10)) { /* Wait a while */ }
|
||||
se_check_for_error();
|
||||
}
|
||||
|
||||
/* Secure AES Functionality. */
|
||||
void se_perform_aes_block_operation(void *dst, size_t dst_size, const void *src, size_t src_size) {
|
||||
uint8_t block[0x10] = {0};
|
||||
|
||||
if (src_size > sizeof(block) || dst_size > sizeof(block)) {
|
||||
generic_panic();
|
||||
}
|
||||
|
||||
/* Load src data into block. */
|
||||
if (src_size != 0) {
|
||||
memcpy(block, src, src_size);
|
||||
}
|
||||
|
||||
/* Trigger AES operation. */
|
||||
se_get_regs()->BLOCK_COUNT_REG = 0;
|
||||
trigger_se_blocking_op(OP_START, block, sizeof(block), block, sizeof(block));
|
||||
|
||||
/* Copy output data into dst. */
|
||||
if (dst_size != 0) {
|
||||
memcpy(dst, block, dst_size);
|
||||
}
|
||||
}
|
||||
|
||||
void se_aes_ctr_crypt(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size, const void *ctr, size_t ctr_size) {
|
||||
volatile tegra_se_t *se = se_get_regs();
|
||||
|
||||
if (keyslot >= KEYSLOT_AES_MAX || ctr_size != 0x10) {
|
||||
generic_panic();
|
||||
}
|
||||
unsigned int num_blocks = src_size >> 4;
|
||||
|
||||
/* Unknown what this write does, but official code writes it for CTR mode. */
|
||||
se->SPARE_0 = 1;
|
||||
se->CONFIG_REG = (ALG_AES_ENC | DST_MEMORY);
|
||||
se->CRYPTO_REG = (keyslot << 24) | 0x91E;
|
||||
set_se_ctr(ctr);
|
||||
|
||||
/* Handle any aligned blocks. */
|
||||
size_t aligned_size = (size_t)num_blocks << 4;
|
||||
if (aligned_size) {
|
||||
se->BLOCK_COUNT_REG = num_blocks - 1;
|
||||
trigger_se_blocking_op(OP_START, dst, dst_size, src, aligned_size);
|
||||
}
|
||||
|
||||
/* Handle final, unaligned block. */
|
||||
if (aligned_size < dst_size && aligned_size < src_size) {
|
||||
size_t last_block_size = dst_size - aligned_size;
|
||||
if (src_size < dst_size) {
|
||||
last_block_size = src_size - aligned_size;
|
||||
}
|
||||
se_perform_aes_block_operation(dst + aligned_size, last_block_size, (uint8_t *)src + aligned_size, src_size - aligned_size);
|
||||
}
|
||||
}
|
||||
|
||||
void se_aes_ecb_encrypt_block(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size, unsigned int config_high) {
|
||||
volatile tegra_se_t *se = se_get_regs();
|
||||
|
||||
if (keyslot >= KEYSLOT_AES_MAX || dst_size != 0x10 || src_size != 0x10) {
|
||||
generic_panic();
|
||||
}
|
||||
|
||||
/* Set configuration high (256-bit vs 128-bit) based on parameter. */
|
||||
se->CONFIG_REG = (ALG_AES_ENC | DST_MEMORY) | (config_high << 16);
|
||||
se->CRYPTO_REG = keyslot << 24 | 0x100;
|
||||
se_perform_aes_block_operation(dst, 0x10, src, 0x10);
|
||||
}
|
||||
|
||||
void se_aes_128_ecb_encrypt_block(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size) {
|
||||
se_aes_ecb_encrypt_block(keyslot, dst, dst_size, src, src_size, 0);
|
||||
}
|
||||
|
||||
void se_aes_256_ecb_encrypt_block(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size) {
|
||||
se_aes_ecb_encrypt_block(keyslot, dst, dst_size, src, src_size, 0x202);
|
||||
}
|
||||
|
||||
void se_aes_ecb_decrypt_block(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size) {
|
||||
volatile tegra_se_t *se = se_get_regs();
|
||||
|
||||
if (keyslot >= KEYSLOT_AES_MAX || dst_size != 0x10 || src_size != 0x10) {
|
||||
generic_panic();
|
||||
}
|
||||
|
||||
se->CONFIG_REG = (ALG_AES_DEC | DST_MEMORY);
|
||||
se->CRYPTO_REG = keyslot << 24;
|
||||
se_perform_aes_block_operation(dst, 0x10, src, 0x10);
|
||||
}
|
||||
|
||||
void shift_left_xor_rb(uint8_t *key) {
|
||||
uint8_t prev_high_bit = 0;
|
||||
for (unsigned int i = 0; i < 0x10; i++) {
|
||||
uint8_t cur_byte = key[0xF - i];
|
||||
key[0xF - i] = (cur_byte << 1) | (prev_high_bit);
|
||||
prev_high_bit = cur_byte >> 7;
|
||||
}
|
||||
if (prev_high_bit) {
|
||||
key[0xF] ^= 0x87;
|
||||
}
|
||||
}
|
||||
|
||||
void shift_left_xor_rb_le(uint8_t *key) {
|
||||
uint8_t prev_high_bit = 0;
|
||||
for (unsigned int i = 0; i < 0x10; i++) {
|
||||
uint8_t cur_byte = key[i];
|
||||
key[i] = (cur_byte << 1) | (prev_high_bit);
|
||||
prev_high_bit = cur_byte >> 7;
|
||||
}
|
||||
if (prev_high_bit) {
|
||||
key[0x0] ^= 0x87;
|
||||
}
|
||||
}
|
||||
|
||||
void se_compute_aes_cmac(unsigned int keyslot, void *cmac, size_t cmac_size, const void *data, size_t data_size, unsigned int config_high) {
|
||||
volatile tegra_se_t *se = se_get_regs();
|
||||
|
||||
if (keyslot >= KEYSLOT_AES_MAX) {
|
||||
generic_panic();
|
||||
}
|
||||
|
||||
/* Generate the derived key, to be XOR'd with final output block. */
|
||||
uint8_t ALIGN(16) derived_key[0x10] = {0};
|
||||
se_aes_ecb_encrypt_block(keyslot, derived_key, sizeof(derived_key), derived_key, sizeof(derived_key), config_high);
|
||||
shift_left_xor_rb(derived_key);
|
||||
if (data_size & 0xF) {
|
||||
shift_left_xor_rb(derived_key);
|
||||
}
|
||||
|
||||
se->CONFIG_REG = (ALG_AES_ENC | DST_HASHREG) | (config_high << 16);
|
||||
se->CRYPTO_REG = (keyslot << 24) | (0x145);
|
||||
clear_aes_keyslot_iv(keyslot);
|
||||
|
||||
unsigned int num_blocks = (data_size + 0xF) >> 4;
|
||||
/* Handle aligned blocks. */
|
||||
if (num_blocks > 1) {
|
||||
se->BLOCK_COUNT_REG = num_blocks - 2;
|
||||
trigger_se_blocking_op(OP_START, NULL, 0, data, data_size);
|
||||
se->CRYPTO_REG |= 0x80;
|
||||
}
|
||||
|
||||
/* Create final block. */
|
||||
uint8_t ALIGN(16) last_block[0x10] = {0};
|
||||
if (data_size & 0xF) {
|
||||
memcpy(last_block, data + (data_size & ~0xF), data_size & 0xF);
|
||||
last_block[data_size & 0xF] = 0x80; /* Last block = data || 100...0 */
|
||||
} else if (data_size >= 0x10) {
|
||||
memcpy(last_block, data + data_size - 0x10, 0x10);
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < 0x10; i++) {
|
||||
last_block[i] ^= derived_key[i];
|
||||
}
|
||||
|
||||
/* Perform last operation. */
|
||||
se->BLOCK_COUNT_REG = 0;
|
||||
trigger_se_blocking_op(OP_START, NULL, 0, last_block, sizeof(last_block));
|
||||
|
||||
/* Copy output CMAC. */
|
||||
for (unsigned int i = 0; i < (cmac_size >> 2); i++) {
|
||||
((uint32_t *)cmac)[i] = read32le(se->HASH_RESULT_REG, i << 2);
|
||||
}
|
||||
}
|
||||
|
||||
void se_compute_aes_128_cmac(unsigned int keyslot, void *cmac, size_t cmac_size, const void *data, size_t data_size) {
|
||||
se_compute_aes_cmac(keyslot, cmac, cmac_size, data, data_size, 0);
|
||||
}
|
||||
void se_compute_aes_256_cmac(unsigned int keyslot, void *cmac, size_t cmac_size, const void *data, size_t data_size) {
|
||||
se_compute_aes_cmac(keyslot, cmac, cmac_size, data, data_size, 0x202);
|
||||
}
|
||||
|
||||
void se_aes_256_cbc_encrypt(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size, const void *iv) {
|
||||
volatile tegra_se_t *se = se_get_regs();
|
||||
|
||||
if (keyslot >= KEYSLOT_AES_MAX || src_size < 0x10) {
|
||||
generic_panic();
|
||||
}
|
||||
|
||||
se->CONFIG_REG = (ALG_AES_ENC | DST_MEMORY) | (0x202 << 16);
|
||||
se->CRYPTO_REG = (keyslot << 24) | 0x144;
|
||||
set_aes_keyslot_iv(keyslot, iv, 0x10);
|
||||
se->BLOCK_COUNT_REG = (src_size >> 4) - 1;
|
||||
trigger_se_blocking_op(OP_START, dst, dst_size, src, src_size);
|
||||
}
|
||||
|
||||
void se_aes_128_cbc_decrypt(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size) {
|
||||
volatile tegra_se_t *se = se_get_regs();
|
||||
|
||||
if (keyslot >= KEYSLOT_AES_MAX || src_size < 0x10) {
|
||||
generic_panic();
|
||||
}
|
||||
|
||||
se->CONFIG_REG = (ALG_AES_DEC | DST_MEMORY) | (0x000 << 16);
|
||||
se->CRYPTO_REG = (keyslot << 24) | 0x66;
|
||||
clear_aes_keyslot_iv(keyslot);
|
||||
se->BLOCK_COUNT_REG = (src_size >> 4) - 1;
|
||||
trigger_se_blocking_op(OP_START, dst, dst_size, src, src_size);
|
||||
}
|
||||
|
||||
/* SHA256 Implementation. */
|
||||
void se_calculate_sha256(void *dst, const void *src, size_t src_size) {
|
||||
volatile tegra_se_t *se = se_get_regs();
|
||||
|
||||
/* Setup config for SHA256, size = BITS(src_size) */
|
||||
se->CONFIG_REG = (ENCMODE_SHA256 | ALG_SHA | DST_HASHREG);
|
||||
se->SHA_CONFIG_REG = 1;
|
||||
se->SHA_MSG_LENGTH_REG = (uint32_t)(src_size << 3);
|
||||
se->_0x208 = 0;
|
||||
se->_0x20C = 0;
|
||||
se->_0x210 = 0;
|
||||
se->SHA_MSG_LEFT_REG = (uint32_t)(src_size << 3);
|
||||
se->_0x218 = 0;
|
||||
se->_0x21C = 0;
|
||||
se->_0x220 = 0;
|
||||
|
||||
/* Trigger the operation. */
|
||||
trigger_se_blocking_op(OP_START, NULL, 0, src, src_size);
|
||||
|
||||
/* Copy output hash. */
|
||||
for (unsigned int i = 0; i < (0x20 >> 2); i++) {
|
||||
((uint32_t *)dst)[i] = read32be(se->HASH_RESULT_REG, i << 2);
|
||||
}
|
||||
}
|
||||
|
||||
/* RNG API */
|
||||
void se_initialize_rng(unsigned int keyslot) {
|
||||
volatile tegra_se_t *se = se_get_regs();
|
||||
|
||||
if (keyslot >= KEYSLOT_AES_MAX) {
|
||||
generic_panic();
|
||||
}
|
||||
|
||||
/* To initialize the RNG, we'll perform an RNG operation into an output buffer. */
|
||||
/* This will be discarded, when done. */
|
||||
uint8_t ALIGN(16) output_buf[0x10];
|
||||
|
||||
se->RNG_SRC_CONFIG_REG = 3; /* Entropy enable + Entropy lock enable */
|
||||
se->RNG_RESEED_INTERVAL_REG = 70001;
|
||||
se->CONFIG_REG = (ALG_RNG | DST_MEMORY);
|
||||
se->CRYPTO_REG = (keyslot << 24) | 0x108;
|
||||
se->RNG_CONFIG_REG = 5;
|
||||
se->BLOCK_COUNT_REG = 0;
|
||||
trigger_se_blocking_op(OP_START, output_buf, 0x10, NULL, 0);
|
||||
}
|
||||
|
||||
void se_generate_random(unsigned int keyslot, void *dst, size_t size) {
|
||||
volatile tegra_se_t *se = se_get_regs();
|
||||
|
||||
if (keyslot >= KEYSLOT_AES_MAX) {
|
||||
generic_panic();
|
||||
}
|
||||
|
||||
uint32_t num_blocks = size >> 4;
|
||||
size_t aligned_size = num_blocks << 4;
|
||||
se->CONFIG_REG = (ALG_RNG | DST_MEMORY);
|
||||
se->CRYPTO_REG = (keyslot << 24) | 0x108;
|
||||
se->RNG_CONFIG_REG = 4;
|
||||
|
||||
if (num_blocks >= 1) {
|
||||
se->BLOCK_COUNT_REG = num_blocks - 1;
|
||||
trigger_se_blocking_op(OP_START, dst, aligned_size, NULL, 0);
|
||||
}
|
||||
if (size > aligned_size) {
|
||||
se_perform_aes_block_operation(dst + aligned_size, size - aligned_size, NULL, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void se_generate_random_key(unsigned int dst_keyslot, unsigned int rng_keyslot) {
|
||||
volatile tegra_se_t *se = se_get_regs();
|
||||
|
||||
if (dst_keyslot >= KEYSLOT_AES_MAX || rng_keyslot >= KEYSLOT_AES_MAX) {
|
||||
generic_panic();
|
||||
}
|
||||
|
||||
/* Setup Config. */
|
||||
se->CONFIG_REG = (ALG_RNG | DST_KEYTAB);
|
||||
se->CRYPTO_REG = (rng_keyslot << 24) | 0x108;
|
||||
se->RNG_CONFIG_REG = 4;
|
||||
se->BLOCK_COUNT_REG = 0;
|
||||
|
||||
/* Generate low part of key. */
|
||||
se->CRYPTO_KEYTABLE_DST_REG = (dst_keyslot << 8);
|
||||
trigger_se_blocking_op(OP_START, NULL, 0, NULL, 0);
|
||||
/* Generate high part of key. */
|
||||
se->CRYPTO_KEYTABLE_DST_REG = (dst_keyslot << 8) | 1;
|
||||
trigger_se_blocking_op(OP_START, NULL, 0, NULL, 0);
|
||||
}
|
||||
|
||||
/* SE context save API. */
|
||||
void se_set_in_context_save_mode(bool is_context_save_mode) {
|
||||
volatile tegra_se_t *se = se_get_regs();
|
||||
|
||||
uint32_t val = se->_0x0;
|
||||
if (is_context_save_mode) {
|
||||
val |= 0x10000;
|
||||
} else {
|
||||
val &= 0xFFFEFFFF;
|
||||
}
|
||||
se->_0x0 = val;
|
||||
/* Perform a useless read from flags reg. */
|
||||
(void)(se->FLAGS_REG);
|
||||
}
|
||||
|
||||
void se_generate_srk(unsigned int srkgen_keyslot) {
|
||||
volatile tegra_se_t *se = se_get_regs();
|
||||
|
||||
se->CONFIG_REG = (ALG_RNG | DST_SRK);
|
||||
se->CRYPTO_REG = (srkgen_keyslot << 24) | 0x108;
|
||||
se->RNG_CONFIG_REG = 6;
|
||||
se->BLOCK_COUNT_REG = 0;
|
||||
trigger_se_blocking_op(OP_START, NULL, 0, NULL, 0);
|
||||
}
|
||||
|
||||
void se_encrypt_with_srk(void *dst, size_t dst_size, const void *src, size_t src_size) {
|
||||
uint8_t output[0x80];
|
||||
uint8_t *aligned_out = (uint8_t *)(((uintptr_t)output + 0x7F) & ~0x3F);
|
||||
if (dst_size > 0x10) {
|
||||
generic_panic();
|
||||
}
|
||||
|
||||
if (dst_size) {
|
||||
trigger_se_blocking_op(OP_CTX_SAVE, aligned_out, dst_size, src, src_size);
|
||||
memcpy(dst, aligned_out, dst_size);
|
||||
} else {
|
||||
trigger_se_blocking_op(OP_CTX_SAVE, aligned_out, 0, src, src_size);
|
||||
}
|
||||
}
|
||||
|
||||
void se_save_context(unsigned int srkgen_keyslot, unsigned int rng_keyslot, void *dst) {
|
||||
volatile tegra_se_t *se = se_get_regs();
|
||||
uint8_t _work_buf[0x80];
|
||||
uint8_t *work_buf = (uint8_t *)(((uintptr_t)_work_buf + 0x7F) & ~0x3F);
|
||||
|
||||
/* Generate the SRK (context save encryption key). */
|
||||
se_generate_random_key(srkgen_keyslot, rng_keyslot);
|
||||
se_generate_srk(srkgen_keyslot);
|
||||
|
||||
se_generate_random(rng_keyslot, work_buf, 0x10);
|
||||
|
||||
/* Save random initial block. */
|
||||
se->CONFIG_REG = (ALG_AES_ENC | DST_MEMORY);
|
||||
se->CONTEXT_SAVE_CONFIG_REG = (CTX_SAVE_SRC_MEM);
|
||||
se->BLOCK_COUNT_REG = 0;
|
||||
se_encrypt_with_srk(dst, 0x10, work_buf, 0x10);
|
||||
|
||||
/* Save Sticky Bits. */
|
||||
for (unsigned int i = 0; i < 0x2; i++) {
|
||||
se->CONTEXT_SAVE_CONFIG_REG = (CTX_SAVE_SRC_STICKY_BITS) | (i << CTX_SAVE_STICKY_BIT_INDEX_SHIFT);
|
||||
se->BLOCK_COUNT_REG = 0;
|
||||
se_encrypt_with_srk(dst + 0x10 + (i * 0x10), 0x10, NULL, 0);
|
||||
}
|
||||
|
||||
/* Save AES Key Table. */
|
||||
for (unsigned int i = 0; i < KEYSLOT_AES_MAX; i++) {
|
||||
se->CONTEXT_SAVE_CONFIG_REG = (CTX_SAVE_SRC_KEYTABLE_AES) | (i << CTX_SAVE_KEY_INDEX_SHIFT) | (CTX_SAVE_KEY_LOW_BITS);
|
||||
se->BLOCK_COUNT_REG = 0;
|
||||
se_encrypt_with_srk(dst + 0x30 + (i * 0x20), 0x10, NULL, 0);
|
||||
se->CONTEXT_SAVE_CONFIG_REG = (CTX_SAVE_SRC_KEYTABLE_AES) | (i << CTX_SAVE_KEY_INDEX_SHIFT) | (CTX_SAVE_KEY_HIGH_BITS);
|
||||
se->BLOCK_COUNT_REG = 0;
|
||||
se_encrypt_with_srk(dst + 0x40 + (i * 0x20), 0x10, NULL, 0);
|
||||
}
|
||||
|
||||
/* Save AES Original IVs. */
|
||||
for (unsigned int i = 0; i < KEYSLOT_AES_MAX; i++) {
|
||||
se->CONTEXT_SAVE_CONFIG_REG = (CTX_SAVE_SRC_KEYTABLE_AES) | (i << CTX_SAVE_KEY_INDEX_SHIFT) | (CTX_SAVE_KEY_ORIGINAL_IV);
|
||||
se->BLOCK_COUNT_REG = 0;
|
||||
se_encrypt_with_srk(dst + 0x230 + (i * 0x10), 0x10, NULL, 0);
|
||||
}
|
||||
|
||||
/* Save AES Updated IVs */
|
||||
for (unsigned int i = 0; i < KEYSLOT_AES_MAX; i++) {
|
||||
se->CONTEXT_SAVE_CONFIG_REG = (CTX_SAVE_SRC_KEYTABLE_AES) | (i << CTX_SAVE_KEY_INDEX_SHIFT) | (CTX_SAVE_KEY_UPDATED_IV);
|
||||
se->BLOCK_COUNT_REG = 0;
|
||||
se_encrypt_with_srk(dst + 0x330 + (i * 0x10), 0x10, NULL, 0);
|
||||
}
|
||||
|
||||
/* Save RSA Keytable. */
|
||||
uint8_t *rsa_ctx_out = (uint8_t *)dst + 0x430;
|
||||
for (unsigned int rsa_key = 0; rsa_key < KEYSLOT_RSA_MAX; rsa_key++) {
|
||||
for (unsigned int mod_exp = 0; mod_exp < 2; mod_exp++) {
|
||||
for (unsigned int sub_block = 0; sub_block < 0x10; sub_block++) {
|
||||
se->CONTEXT_SAVE_CONFIG_REG = (CTX_SAVE_SRC_KEYTABLE_RSA) | ((2 * rsa_key + (1 - mod_exp)) << CTX_SAVE_RSA_KEY_INDEX_SHIFT) | (sub_block << CTX_SAVE_RSA_KEY_BLOCK_INDEX_SHIFT);
|
||||
se->BLOCK_COUNT_REG = 0;
|
||||
se_encrypt_with_srk(rsa_ctx_out, 0x10, NULL, 0);
|
||||
rsa_ctx_out += 0x10;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Save "Known Pattern. " */
|
||||
static const uint8_t context_save_known_pattern[0x10] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f};
|
||||
se->CONTEXT_SAVE_CONFIG_REG = (CTX_SAVE_SRC_MEM);
|
||||
se->BLOCK_COUNT_REG = 0;
|
||||
se_encrypt_with_srk(dst + 0x830, 0x10, context_save_known_pattern, 0x10);
|
||||
|
||||
/* Save SRK into PMC registers. */
|
||||
se->CONTEXT_SAVE_CONFIG_REG = (CTX_SAVE_SRC_SRK);
|
||||
se->BLOCK_COUNT_REG = 0;
|
||||
se_encrypt_with_srk(work_buf, 0, NULL, 0);
|
||||
se->CONFIG_REG = 0;
|
||||
se_encrypt_with_srk(work_buf, 0, NULL, 0);
|
||||
}
|
||||
225
sept/sept-secondary/key_derivation/src/se.h
Normal file
225
sept/sept-secondary/key_derivation/src/se.h
Normal file
@@ -0,0 +1,225 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2019 Atmosphère-NX
|
||||
*
|
||||
* 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 <stdbool.h>
|
||||
|
||||
#ifndef FUSEE_SE_H
|
||||
#define FUSEE_SE_H
|
||||
|
||||
#define SE_BASE 0x70012000
|
||||
#define MAKE_SE_REG(n) MAKE_REG32(SE_BASE + n)
|
||||
|
||||
#define KEYSLOT_SWITCH_LP0TZRAMKEY 0x2
|
||||
#define KEYSLOT_SWITCH_SRKGENKEY 0x8
|
||||
#define KEYSLOT_SWITCH_PACKAGE2KEY 0x8
|
||||
#define KEYSLOT_SWITCH_TEMPKEY 0x9
|
||||
#define KEYSLOT_SWITCH_SESSIONKEY 0xA
|
||||
#define KEYSLOT_SWITCH_RNGKEY 0xB
|
||||
#define KEYSLOT_SWITCH_MASTERKEY 0xC
|
||||
#define KEYSLOT_SWITCH_DEVICEKEY 0xD
|
||||
|
||||
/* This keyslot was added in 4.0.0. */
|
||||
#define KEYSLOT_SWITCH_4XNEWDEVICEKEYGENKEY 0xD
|
||||
#define KEYSLOT_SWITCH_4XNEWCONSOLEKEYGENKEY 0xE
|
||||
#define KEYSLOT_SWITCH_4XOLDDEVICEKEY 0xF
|
||||
|
||||
/* This keyslot was added in 5.0.0. */
|
||||
#define KEYSLOT_SWITCH_5XNEWDEVICEKEYGENKEY 0xA
|
||||
|
||||
#define KEYSLOT_AES_MAX 0x10
|
||||
#define KEYSLOT_RSA_MAX 0x2
|
||||
|
||||
#define KEYSIZE_AES_MAX 0x20
|
||||
#define KEYSIZE_RSA_MAX 0x100
|
||||
|
||||
#define ALG_SHIFT (12)
|
||||
#define ALG_DEC_SHIFT (8)
|
||||
#define ALG_NOP (0 << ALG_SHIFT)
|
||||
#define ALG_AES_ENC (1 << ALG_SHIFT)
|
||||
#define ALG_AES_DEC ((1 << ALG_DEC_SHIFT) | ALG_NOP)
|
||||
#define ALG_RNG (2 << ALG_SHIFT)
|
||||
#define ALG_SHA (3 << ALG_SHIFT)
|
||||
#define ALG_RSA (4 << ALG_SHIFT)
|
||||
|
||||
#define DST_SHIFT (2)
|
||||
#define DST_MEMORY (0 << DST_SHIFT)
|
||||
#define DST_HASHREG (1 << DST_SHIFT)
|
||||
#define DST_KEYTAB (2 << DST_SHIFT)
|
||||
#define DST_SRK (3 << DST_SHIFT)
|
||||
#define DST_RSAREG (4 << DST_SHIFT)
|
||||
|
||||
#define ENCMODE_SHIFT (24)
|
||||
#define DECMODE_SHIFT (16)
|
||||
#define ENCMODE_SHA256 (5 << ENCMODE_SHIFT)
|
||||
|
||||
#define HASH_DISABLE (0x0)
|
||||
#define HASH_ENABLE (0x1)
|
||||
|
||||
#define OP_ABORT 0
|
||||
#define OP_START 1
|
||||
#define OP_RESTART 2
|
||||
#define OP_CTX_SAVE 3
|
||||
#define OP_RESTART_IN 4
|
||||
|
||||
#define CTX_SAVE_SRC_SHIFT 29
|
||||
#define CTX_SAVE_SRC_STICKY_BITS (0 << CTX_SAVE_SRC_SHIFT)
|
||||
#define CTX_SAVE_SRC_KEYTABLE_AES (2 << CTX_SAVE_SRC_SHIFT)
|
||||
#define CTX_SAVE_SRC_KEYTABLE_RSA (1 << CTX_SAVE_SRC_SHIFT)
|
||||
#define CTX_SAVE_SRC_MEM (4 << CTX_SAVE_SRC_SHIFT)
|
||||
#define CTX_SAVE_SRC_SRK (6 << CTX_SAVE_SRC_SHIFT)
|
||||
|
||||
#define CTX_SAVE_KEY_LOW_BITS 0
|
||||
#define CTX_SAVE_KEY_HIGH_BITS 1
|
||||
#define CTX_SAVE_KEY_ORIGINAL_IV 2
|
||||
#define CTX_SAVE_KEY_UPDATED_IV 3
|
||||
|
||||
#define CTX_SAVE_STICKY_BIT_INDEX_SHIFT 24
|
||||
#define CTX_SAVE_KEY_INDEX_SHIFT 8
|
||||
#define CTX_SAVE_RSA_KEY_INDEX_SHIFT 16
|
||||
#define CTX_SAVE_RSA_KEY_BLOCK_INDEX_SHIFT 12
|
||||
|
||||
#define RSA_2048_BYTES 0x100
|
||||
|
||||
typedef struct {
|
||||
uint32_t _0x0;
|
||||
uint32_t _0x4;
|
||||
uint32_t OPERATION_REG;
|
||||
uint32_t INT_ENABLE_REG;
|
||||
uint32_t INT_STATUS_REG;
|
||||
uint32_t CONFIG_REG;
|
||||
uint32_t IN_LL_ADDR_REG;
|
||||
uint32_t _0x1C;
|
||||
uint32_t _0x20;
|
||||
uint32_t OUT_LL_ADDR_REG;
|
||||
uint32_t _0x28;
|
||||
uint32_t _0x2C;
|
||||
uint8_t HASH_RESULT_REG[0x20];
|
||||
uint8_t _0x50[0x20];
|
||||
uint32_t CONTEXT_SAVE_CONFIG_REG;
|
||||
uint8_t _0x74[0x18C];
|
||||
uint32_t SHA_CONFIG_REG;
|
||||
uint32_t SHA_MSG_LENGTH_REG;
|
||||
uint32_t _0x208;
|
||||
uint32_t _0x20C;
|
||||
uint32_t _0x210;
|
||||
uint32_t SHA_MSG_LEFT_REG;
|
||||
uint32_t _0x218;
|
||||
uint32_t _0x21C;
|
||||
uint32_t _0x220;
|
||||
uint32_t _0x224;
|
||||
uint8_t _0x228[0x58];
|
||||
uint32_t AES_KEY_READ_DISABLE_REG;
|
||||
uint32_t AES_KEYSLOT_FLAGS[0x10];
|
||||
uint8_t _0x2C4[0x3C];
|
||||
uint32_t _0x300;
|
||||
uint32_t CRYPTO_REG;
|
||||
uint32_t CRYPTO_CTR_REG[4];
|
||||
uint32_t BLOCK_COUNT_REG;
|
||||
uint32_t AES_KEYTABLE_ADDR;
|
||||
uint32_t AES_KEYTABLE_DATA;
|
||||
uint32_t _0x324;
|
||||
uint32_t _0x328;
|
||||
uint32_t _0x32C;
|
||||
uint32_t CRYPTO_KEYTABLE_DST_REG;
|
||||
uint8_t _0x334[0xC];
|
||||
uint32_t RNG_CONFIG_REG;
|
||||
uint32_t RNG_SRC_CONFIG_REG;
|
||||
uint32_t RNG_RESEED_INTERVAL_REG;
|
||||
uint8_t _0x34C[0xB4];
|
||||
uint32_t RSA_CONFIG;
|
||||
uint32_t RSA_KEY_SIZE_REG;
|
||||
uint32_t RSA_EXP_SIZE_REG;
|
||||
uint32_t RSA_KEY_READ_DISABLE_REG;
|
||||
uint32_t RSA_KEYSLOT_FLAGS[2];
|
||||
uint32_t _0x418;
|
||||
uint32_t _0x41C;
|
||||
uint32_t RSA_KEYTABLE_ADDR;
|
||||
uint32_t RSA_KEYTABLE_DATA;
|
||||
uint8_t RSA_OUTPUT[0x100];
|
||||
uint8_t _0x528[0x2D8];
|
||||
uint32_t FLAGS_REG;
|
||||
uint32_t ERR_STATUS_REG;
|
||||
uint32_t _0x808;
|
||||
uint32_t SPARE_0;
|
||||
uint32_t _0x810;
|
||||
uint32_t _0x814;
|
||||
uint32_t _0x818;
|
||||
uint32_t _0x81C;
|
||||
uint8_t _0x820[0x17E0];
|
||||
} tegra_se_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t address;
|
||||
uint32_t size;
|
||||
} se_addr_info_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t num_entries; /* Set to total entries - 1 */
|
||||
se_addr_info_t addr_info; /* This should really be an array...but for our use case it works. */
|
||||
} se_ll_t;
|
||||
|
||||
static inline volatile tegra_se_t *se_get_regs(void) {
|
||||
return (volatile tegra_se_t *)SE_BASE;
|
||||
}
|
||||
|
||||
void se_check_error_status_reg(void);
|
||||
void se_check_for_error(void);
|
||||
void se_trigger_interrupt(void);
|
||||
|
||||
void se_validate_stored_vector(void);
|
||||
void se_generate_stored_vector(void);
|
||||
|
||||
void se_verify_flags_cleared(void);
|
||||
|
||||
void set_aes_keyslot_flags(unsigned int keyslot, unsigned int flags);
|
||||
void set_rsa_keyslot_flags(unsigned int keyslot, unsigned int flags);
|
||||
void clear_aes_keyslot(unsigned int keyslot);
|
||||
void clear_rsa_keyslot(unsigned int keyslot);
|
||||
|
||||
void set_aes_keyslot(unsigned int keyslot, const void *key, size_t key_size);
|
||||
void decrypt_data_into_keyslot(unsigned int keyslot_dst, unsigned int keyslot_src, const void *wrapped_key, size_t wrapped_key_size);
|
||||
void set_rsa_keyslot(unsigned int keyslot, const void *modulus, size_t modulus_size, const void *exponent, size_t exp_size);
|
||||
void set_aes_keyslot_iv(unsigned int keyslot, const void *iv, size_t iv_size);
|
||||
void set_se_ctr(const void *ctr);
|
||||
|
||||
/* Secure AES API */
|
||||
void se_compute_aes_128_cmac(unsigned int keyslot, void *cmac, size_t cmac_size, const void *data, size_t data_size);
|
||||
void se_compute_aes_256_cmac(unsigned int keyslot, void *cmac, size_t cmac_size, const void *data, size_t data_size);
|
||||
void se_aes_128_ecb_encrypt_block(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size);
|
||||
void se_aes_256_ecb_encrypt_block(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size);
|
||||
void se_aes_ctr_crypt(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size, const void *ctr, size_t ctr_size);
|
||||
void se_aes_ecb_decrypt_block(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size);
|
||||
void se_aes_256_cbc_encrypt(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size, const void *iv);
|
||||
void se_aes_128_cbc_decrypt(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size);
|
||||
|
||||
/* Hash API */
|
||||
void se_calculate_sha256(void *dst, const void *src, size_t src_size);
|
||||
|
||||
/* RSA API */
|
||||
void se_get_exp_mod_output(void *buf, size_t size);
|
||||
void se_synchronous_exp_mod(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size);
|
||||
bool se_rsa2048_pss_verify(const void *signature, size_t signature_size, const void *modulus, size_t modulus_size, const void *data, size_t data_size);
|
||||
|
||||
/* RNG API */
|
||||
void se_initialize_rng(unsigned int keyslot);
|
||||
void se_generate_random(unsigned int keyslot, void *dst, size_t size);
|
||||
|
||||
/* SE context save API. */
|
||||
void se_generate_srk(unsigned int srkgen_keyslot);
|
||||
void se_set_in_context_save_mode(bool is_context_save_mode);
|
||||
void se_generate_random_key(unsigned int dst_keyslot, unsigned int rng_keyslot);
|
||||
void se_save_context(unsigned int srk_keyslot, unsigned int rng_keyslot, void *dst);
|
||||
|
||||
#endif
|
||||
99
sept/sept-secondary/key_derivation/src/start.s
Normal file
99
sept/sept-secondary/key_derivation/src/start.s
Normal file
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2019 Atmosphère-NX
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
/* For some reason GAS doesn't know about it, even with .cpu cortex-a57 */
|
||||
#define cpuactlr_el1 s3_1_c15_c2_0
|
||||
#define cpuectlr_el1 s3_1_c15_c2_1
|
||||
|
||||
.macro RESET_CORE
|
||||
mov x0, #(1 << 63)
|
||||
msr cpuactlr_el1, x0 /* disable regional clock gating */
|
||||
isb
|
||||
mov x0, #3
|
||||
msr rmr_el3, x0
|
||||
isb
|
||||
dsb sy
|
||||
/* Nintendo forgot to copy-paste the branch instruction below. */
|
||||
1:
|
||||
wfi
|
||||
b 1b
|
||||
.endm
|
||||
|
||||
.macro ERRATUM_INVALIDATE_BTB_AT_BOOT
|
||||
/* Nintendo copy-pasted https://github.com/ARM-software/arm-trusted-firmware/blob/master/plat/nvidia/tegra/common/aarch64/tegra_helpers.S#L312 */
|
||||
/*
|
||||
* Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
/* The following comments are mine. */
|
||||
/* mask all interrupts */
|
||||
msr daifset, 0b1111
|
||||
|
||||
/*
|
||||
Enable invalidates of branch target buffer, then flush
|
||||
the entire instruction cache at the local level, and
|
||||
with the reg change, the branch target buffer, then disable
|
||||
invalidates of the branch target buffer again.
|
||||
*/
|
||||
mrs x0, cpuactlr_el1
|
||||
orr x0, x0, #1
|
||||
msr cpuactlr_el1, x0
|
||||
|
||||
dsb sy
|
||||
isb
|
||||
ic iallu
|
||||
dsb sy
|
||||
isb
|
||||
|
||||
mrs x0, cpuactlr_el1
|
||||
bic x0, x0, #1
|
||||
msr cpuactlr_el1, x0
|
||||
|
||||
.rept 7
|
||||
nop /* wait long enough for the write to cpuactlr_el1 to have completed */
|
||||
.endr
|
||||
|
||||
/* if the OS lock is set, disable it and request a warm reset */
|
||||
mrs x0, oslsr_el1
|
||||
ands x0, x0, #2
|
||||
b.eq 2f
|
||||
mov x0, xzr
|
||||
msr oslar_el1, x0
|
||||
|
||||
RESET_CORE
|
||||
|
||||
.rept 65
|
||||
nop /* guard against speculative excecution */
|
||||
.endr
|
||||
|
||||
2:
|
||||
/* set the OS lock */
|
||||
mov x0, #1
|
||||
msr oslar_el1, x0
|
||||
.endm
|
||||
|
||||
|
||||
.section .text.start
|
||||
.align 4
|
||||
.global _start
|
||||
_start:
|
||||
ERRATUM_INVALIDATE_BTB_AT_BOOT
|
||||
msr spsel, #0
|
||||
ldr x0, =__start__
|
||||
mov sp, x0
|
||||
mov fp, #0x0
|
||||
bl derive_keys
|
||||
33
sept/sept-secondary/key_derivation/src/utils.c
Normal file
33
sept/sept-secondary/key_derivation/src/utils.c
Normal file
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2019 Atmosphère-NX
|
||||
*
|
||||
* 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 <stdbool.h>
|
||||
#include <stdarg.h>
|
||||
#include "utils.h"
|
||||
#include "se.h"
|
||||
#include <inttypes.h>
|
||||
|
||||
__attribute__ ((noreturn)) void generic_panic(void) {
|
||||
/* Clear keyslots. */
|
||||
clear_aes_keyslot(0xD);
|
||||
clear_aes_keyslot(0xE);
|
||||
for (size_t i = 0; i < 0x10; i++) {
|
||||
clear_aes_keyslot(i);
|
||||
}
|
||||
clear_aes_keyslot(0xD);
|
||||
clear_aes_keyslot(0xE);
|
||||
while(1) { /* ... */ }
|
||||
}
|
||||
122
sept/sept-secondary/key_derivation/src/utils.h
Normal file
122
sept/sept-secondary/key_derivation/src/utils.h
Normal file
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2019 Atmosphère-NX
|
||||
*
|
||||
* 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 FUSEE_UTILS_H
|
||||
#define FUSEE_UTILS_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#define BIT(n) (1u << (n))
|
||||
#define BITL(n) (1ull << (n))
|
||||
#define MASK(n) (BIT(n) - 1)
|
||||
#define MASKL(n) (BITL(n) - 1)
|
||||
#define MASK2(a,b) (MASK(a) & ~MASK(b))
|
||||
#define MASK2L(a,b) (MASKL(a) & ~MASKL(b))
|
||||
|
||||
#define MAKE_REG32(a) (*(volatile uint32_t *)(a))
|
||||
|
||||
#define ALIGN(m) __attribute__((aligned(m)))
|
||||
#define PACKED __attribute__((packed))
|
||||
|
||||
#define ALINLINE __attribute__((always_inline))
|
||||
#define NOINLINE __attribute__((noinline))
|
||||
|
||||
#define SET_SYSREG(reg, val) do { temp_reg = (val); __asm__ __volatile__ ("msr " #reg ", %0" :: "r"(temp_reg) : "memory"); } while(false)
|
||||
|
||||
static inline uintptr_t get_physical_address(const void *addr) {
|
||||
return (uintptr_t)addr;
|
||||
}
|
||||
|
||||
static inline uint32_t read32le(const volatile void *dword, size_t offset) {
|
||||
uintptr_t addr = (uintptr_t)dword + offset;
|
||||
volatile uint32_t *target = (uint32_t *)addr;
|
||||
return *target;
|
||||
}
|
||||
|
||||
static inline uint32_t read32be(const volatile void *dword, size_t offset) {
|
||||
return __builtin_bswap32(read32le(dword, offset));
|
||||
}
|
||||
|
||||
static inline uint64_t read64le(const volatile void *qword, size_t offset) {
|
||||
uintptr_t addr = (uintptr_t)qword + offset;
|
||||
volatile uint64_t *target = (uint64_t *)addr;
|
||||
return *target;
|
||||
}
|
||||
|
||||
static inline uint64_t read64be(const volatile void *qword, size_t offset) {
|
||||
return __builtin_bswap64(read64le(qword, offset));
|
||||
}
|
||||
|
||||
static inline void write32le(volatile void *dword, size_t offset, uint32_t value) {
|
||||
uintptr_t addr = (uintptr_t)dword + offset;
|
||||
volatile uint32_t *target = (uint32_t *)addr;
|
||||
*target = value;
|
||||
}
|
||||
|
||||
static inline void write32be(volatile void *dword, size_t offset, uint32_t value) {
|
||||
write32le(dword, offset, __builtin_bswap32(value));
|
||||
}
|
||||
|
||||
static inline void write64le(volatile void *qword, size_t offset, uint64_t value) {
|
||||
uintptr_t addr = (uintptr_t)qword + offset;
|
||||
volatile uint64_t *target = (uint64_t *)addr;
|
||||
*target = value;
|
||||
}
|
||||
|
||||
static inline void write64be(volatile void *qword, size_t offset, uint64_t value) {
|
||||
write64le(qword, offset, __builtin_bswap64(value));
|
||||
}
|
||||
|
||||
static inline bool check_32bit_additive_overflow(uint32_t a, uint32_t b) {
|
||||
return __builtin_add_overflow_p(a, b, (uint32_t)0);
|
||||
}
|
||||
|
||||
static inline bool check_32bit_address_loadable(uintptr_t addr) {
|
||||
/* FWIW the bootROM forbids loading anything between 0x40000000 and 0x40010000, using it for itself... */
|
||||
return (addr >= 0x40010000u && addr < 0x40040000u) || addr >= 0x80000000u;
|
||||
}
|
||||
|
||||
static inline bool check_32bit_address_range_loadable(uintptr_t addr, size_t size) {
|
||||
return
|
||||
!__builtin_add_overflow_p(addr, size, (uintptr_t)0) && /* the range doesn't overflow */
|
||||
check_32bit_address_loadable(addr) && check_32bit_address_loadable(addr + size) && /* bounds are valid */
|
||||
!(addr >= 0x40010000u && addr < 0x40040000u && addr + size >= 0x40040000u) /* the range doesn't cross MMIO */
|
||||
;
|
||||
}
|
||||
|
||||
bool overlaps(uint64_t as, uint64_t ae, uint64_t bs, uint64_t be);
|
||||
static inline bool overlaps_a(const void *as, const void *ae, const void *bs, const void *be) {
|
||||
return overlaps((uint64_t)(uintptr_t)as, (uint64_t)(uintptr_t)ae, (uint64_t)(uintptr_t)bs, (uint64_t)(uintptr_t)be);
|
||||
}
|
||||
|
||||
static inline bool check_32bit_address_range_in_program(uintptr_t addr, size_t size) {
|
||||
extern uint8_t __chainloader_start__[], __chainloader_end__[];
|
||||
extern uint8_t __stack_bottom__[], __stack_top__[];
|
||||
extern uint8_t __start__[], __end__[];
|
||||
uint8_t *start = (uint8_t *)addr, *end = start + size;
|
||||
|
||||
return overlaps_a(start, end, __chainloader_start__, __chainloader_end__) ||
|
||||
overlaps_a(start, end, __stack_bottom__, __stack_top__) ||
|
||||
overlaps_a(start, end, (void *)0xC0000000, (void *)0xC03C0000) || /* framebuffer */
|
||||
overlaps_a(start, end, __start__, __end__);
|
||||
}
|
||||
|
||||
__attribute__((noreturn)) void generic_panic(void);
|
||||
|
||||
#endif
|
||||
@@ -20,8 +20,8 @@ MEMORY
|
||||
SECTIONS
|
||||
{
|
||||
PROVIDE(__start__ = 0x40010000);
|
||||
PROVIDE(__stack_top__ = 0x40010000);
|
||||
PROVIDE(__stack_bottom__ = 0x4000C000);
|
||||
PROVIDE(__stack_top__ = 0x4003C000);
|
||||
PROVIDE(__stack_bottom__ = 0x40038000);
|
||||
PROVIDE(__heap_start__ = 0);
|
||||
PROVIDE(__heap_end__ = 0);
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env python
|
||||
import sys
|
||||
import sys, os
|
||||
from struct import pack as pk, unpack as up
|
||||
from Crypto.Cipher import AES
|
||||
from Crypto.Hash import CMAC
|
||||
@@ -41,7 +41,7 @@ def get_last_block_for_desired_mac(key, data, desired_mac):
|
||||
return last_block
|
||||
|
||||
|
||||
def sign_encrypt_code(code, sig_key, enc_key, iv, desired_mac):
|
||||
def sign_encrypt_code(code, sig_key, enc_key, iv, desired_mac, version):
|
||||
# Pad with 0x20 of zeroes.
|
||||
code = code + bytearray(0x20)
|
||||
code_len = len(code)
|
||||
@@ -49,6 +49,9 @@ def sign_encrypt_code(code, sig_key, enc_key, iv, desired_mac):
|
||||
code_len &= ~0xFFF
|
||||
code = code + bytearray(code_len - len(code))
|
||||
|
||||
# Insert version
|
||||
code = code[:8] + pk('<I', version) + code[12:]
|
||||
|
||||
# Add empty trustzone, warmboot segments.
|
||||
code = code + bytearray(0x1FE0 - 0x10)
|
||||
pk11_hdr = b'PK11' + pk('<IIIIIII', 0x1000, 0, 0, code_len - 0x20, 0, 0x1000, 0)
|
||||
@@ -69,8 +72,10 @@ def main(argc, argv):
|
||||
if len(code) & 0xF:
|
||||
code = code + bytearray(0x10 - (len(code) & 0xF))
|
||||
# TODO: Support dev unit crypto
|
||||
with open(argv[2], 'wb') as f:
|
||||
f.write(sign_encrypt_code(code, KEYS.HOVI_SIG_KEY_PRD, KEYS.HOVI_ENC_KEY_PRD, KEYS.IV, b'THANKS_NVIDIA_<3'))
|
||||
fn, fext = os.path.splitext(argv[2])
|
||||
for key in range(KEYS.NUM_KEYS):
|
||||
with open(fn + ('_%02X' % key) + fext, 'wb') as f:
|
||||
f.write(sign_encrypt_code(code, KEYS.HOVI_SIG_KEY_PRD[key], KEYS.HOVI_ENC_KEY_PRD[key], KEYS.IV[key], b'THANKS_NVIDIA_<3', key))
|
||||
return 0
|
||||
|
||||
|
||||
|
||||
178
sept/sept-secondary/src/cluster.c
Normal file
178
sept/sept-secondary/src/cluster.c
Normal file
@@ -0,0 +1,178 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (c) 2018-2019 Atmosphère-NX
|
||||
*
|
||||
* 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 <stdint.h>
|
||||
|
||||
#include "cluster.h"
|
||||
#include "flow.h"
|
||||
#include "sysreg.h"
|
||||
#include "i2c.h"
|
||||
#include "car.h"
|
||||
#include "mc.h"
|
||||
#include "timers.h"
|
||||
#include "pmc.h"
|
||||
#include "max77620.h"
|
||||
|
||||
void _cluster_enable_power()
|
||||
{
|
||||
/* Reboot I2C5. */
|
||||
clkrst_reboot(CARDEVICE_I2C5);
|
||||
i2c_init(I2C_5);
|
||||
|
||||
uint8_t val = 0;
|
||||
i2c_query(I2C_5, MAX77620_PWR_I2C_ADDR, MAX77620_REG_AME_GPIO, &val, 1);
|
||||
|
||||
val &= 0xDF;
|
||||
i2c_send(I2C_5, MAX77620_PWR_I2C_ADDR, MAX77620_REG_AME_GPIO, &val, 1);
|
||||
val = 0x09;
|
||||
i2c_send(I2C_5, MAX77620_PWR_I2C_ADDR, MAX77620_REG_GPIO5, &val, 1);
|
||||
|
||||
/* Enable power. */
|
||||
val = 0x20;
|
||||
i2c_send(I2C_5, MAX77621_CPU_I2C_ADDR, 0x02, &val, 1);
|
||||
val = 0x8D;
|
||||
i2c_send(I2C_5, MAX77621_CPU_I2C_ADDR, 0x03, &val, 1);
|
||||
val = 0xB7;
|
||||
i2c_send(I2C_5, MAX77621_CPU_I2C_ADDR, 0x00, &val, 1);
|
||||
val = 0xB7;
|
||||
i2c_send(I2C_5, MAX77621_CPU_I2C_ADDR, 0x01, &val, 1);
|
||||
}
|
||||
|
||||
int _cluster_pmc_enable_partition(uint32_t part, uint32_t toggle)
|
||||
{
|
||||
volatile tegra_pmc_t *pmc = pmc_get_regs();
|
||||
|
||||
/* Check if the partition has already been turned on. */
|
||||
if (pmc->pwrgate_status & part)
|
||||
return 1;
|
||||
|
||||
uint32_t i = 5001;
|
||||
while (pmc->pwrgate_toggle & 0x100)
|
||||
{
|
||||
udelay(1);
|
||||
i--;
|
||||
if (i < 1)
|
||||
return 0;
|
||||
}
|
||||
|
||||
pmc->pwrgate_toggle = (toggle | 0x100);
|
||||
|
||||
i = 5001;
|
||||
while (i > 0)
|
||||
{
|
||||
if (pmc->pwrgate_status & part)
|
||||
break;
|
||||
|
||||
udelay(1);
|
||||
i--;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void cluster_boot_cpu0(uint32_t entry)
|
||||
{
|
||||
volatile tegra_car_t *car = car_get_regs();
|
||||
|
||||
/* Set ACTIVE_CLUSER to FAST. */
|
||||
FLOW_CTLR_BPMP_CLUSTER_CONTROL_0 &= 0xFFFFFFFE;
|
||||
|
||||
_cluster_enable_power();
|
||||
|
||||
if (!(car->pllx_base & 0x40000000))
|
||||
{
|
||||
car->pllx_misc3 &= 0xFFFFFFF7;
|
||||
udelay(2);
|
||||
car->pllx_base = 0x80404E02;
|
||||
car->pllx_base = 0x404E02;
|
||||
car->pllx_misc = ((car->pllx_misc & 0xFFFBFFFF) | 0x40000);
|
||||
car->pllx_base = 0x40404E02;
|
||||
}
|
||||
|
||||
while (!(car->pllx_base & 0x8000000)) {
|
||||
/* Wait. */
|
||||
}
|
||||
|
||||
/* Configure MSELECT source and enable clock. */
|
||||
car->clk_source_mselect = ((car->clk_source_mselect & 0x1FFFFF00) | 6);
|
||||
car->clk_out_enb_v = ((car->clk_out_enb_v & 0xFFFFFFF7) | 8);
|
||||
|
||||
/* Configure initial CPU clock frequency and enable clock. */
|
||||
car->cclk_brst_pol = 0x20008888;
|
||||
car->super_cclk_div = 0x80000000;
|
||||
car->clk_enb_v_set = 1;
|
||||
|
||||
clkrst_reboot(CARDEVICE_CORESIGHT);
|
||||
|
||||
/* CAR2PMC_CPU_ACK_WIDTH should be set to 0. */
|
||||
car->cpu_softrst_ctrl2 &= 0xFFFFF000;
|
||||
|
||||
/* Enable CPU rail. */
|
||||
_cluster_pmc_enable_partition(1, 0);
|
||||
|
||||
/* Enable cluster 0 non-CPU. */
|
||||
_cluster_pmc_enable_partition(0x8000, 15);
|
||||
|
||||
/* Enable CE0. */
|
||||
_cluster_pmc_enable_partition(0x4000, 14);
|
||||
|
||||
/* Request and wait for RAM repair. */
|
||||
FLOW_CTLR_RAM_REPAIR_0 = 1;
|
||||
while (!(FLOW_CTLR_RAM_REPAIR_0 & 2)) {
|
||||
/* Wait. */
|
||||
}
|
||||
|
||||
MAKE_EXCP_VEC_REG(0x100) = 0;
|
||||
|
||||
/* Check for reset vector lock. */
|
||||
if (SB_CSR_0 & 2) {
|
||||
generic_panic();
|
||||
}
|
||||
|
||||
/* Set reset vector. */
|
||||
SB_AA64_RESET_LOW_0 = (entry | 1);
|
||||
SB_AA64_RESET_HIGH_0 = 0;
|
||||
|
||||
/* Non-secure reset vector write disable. */
|
||||
SB_CSR_0 = 2;
|
||||
(void)SB_CSR_0;
|
||||
|
||||
/* Validate reset vector lock + RESET_LOW/HIGH values. */
|
||||
if (!(SB_CSR_0 & 2)) {
|
||||
generic_panic();
|
||||
}
|
||||
|
||||
/* TODO: Should we even bother taking as a parameter? */
|
||||
if (SB_AA64_RESET_LOW_0 != (0x4003D000 | 1) || SB_AA64_RESET_HIGH_0 != 0) {
|
||||
generic_panic();
|
||||
}
|
||||
|
||||
/* Set CPU_STRICT_TZ_APERTURE_CHECK. */
|
||||
/* NOTE: [4.0.0+] This was added, but it breaks Exosphère. */
|
||||
/* MAKE_MC_REG(MC_TZ_SECURITY_CTRL) = 1; */
|
||||
|
||||
/* Clear MSELECT reset. */
|
||||
car->rst_dev_v &= 0xFFFFFFF7;
|
||||
|
||||
/* Clear NONCPU reset. */
|
||||
car->rst_cpug_cmplx_clr = 0x20000000;
|
||||
|
||||
/* Clear CPU{0,1,2,3} POR and CORE, CX0, L2, and DBG reset.*/
|
||||
/* NOTE: [5.0.0+] This was changed so only CPU0 reset is cleared. */
|
||||
/* car->rst_cpug_cmplx_clr = 0x411F000F; */
|
||||
car->rst_cpug_cmplx_clr = 0x41010001;
|
||||
}
|
||||
23
sept/sept-secondary/src/cluster.h
Normal file
23
sept/sept-secondary/src/cluster.h
Normal file
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (c) 2018-2019 Atmosphère-NX
|
||||
*
|
||||
* 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 FUSEE_CLUSTER_H_
|
||||
#define FUSEE_CLUSTER_H_
|
||||
|
||||
void cluster_boot_cpu0(uint32_t entry);
|
||||
|
||||
#endif
|
||||
@@ -17,64 +17,65 @@
|
||||
#include <stdio.h>
|
||||
#include "key_derivation.h"
|
||||
#include "se.h"
|
||||
#include "cluster.h"
|
||||
#include "timers.h"
|
||||
#include "fuse.h"
|
||||
#include "utils.h"
|
||||
|
||||
#define AL16 ALIGN(16)
|
||||
#define u8 uint8_t
|
||||
#define u32 uint32_t
|
||||
#include "key_derivation_bin.h"
|
||||
#undef u8
|
||||
#undef u32
|
||||
|
||||
static const uint8_t AL16 keyblob_seed_00[0x10] = {
|
||||
0xDF, 0x20, 0x6F, 0x59, 0x44, 0x54, 0xEF, 0xDC, 0x70, 0x74, 0x48, 0x3B, 0x0D, 0xED, 0x9F, 0xD3
|
||||
};
|
||||
|
||||
static const uint8_t AL16 masterkey_seed[0x10] = {
|
||||
0xD8, 0xA2, 0x41, 0x0A, 0xC6, 0xC5, 0x90, 0x01, 0xC6, 0x1D, 0x6A, 0x26, 0x7C, 0x51, 0x3F, 0x3C
|
||||
};
|
||||
void derive_keys(uint32_t version) {
|
||||
/* Clear mailbox. */
|
||||
volatile uint32_t *mailbox = (volatile uint32_t *)0x4003FF00;
|
||||
while (*mailbox != 0) {
|
||||
*mailbox = 0;
|
||||
}
|
||||
|
||||
static const uint8_t AL16 devicekey_seed[0x10] = {
|
||||
0x4F, 0x02, 0x5F, 0x0E, 0xB6, 0x6D, 0x11, 0x0E, 0xDC, 0x32, 0x7D, 0x41, 0x86, 0xC2, 0xF4, 0x78
|
||||
};
|
||||
/* Set derivation id. */
|
||||
*((volatile uint32_t *)0x4003E800) = version;
|
||||
|
||||
static const uint8_t AL16 devicekey_4x_seed[0x10] = {
|
||||
0x0C, 0x91, 0x09, 0xDB, 0x93, 0x93, 0x07, 0x81, 0x07, 0x3C, 0xC4, 0x16, 0x22, 0x7C, 0x6C, 0x28
|
||||
};
|
||||
/* Copy key derivation stub into IRAM high. */
|
||||
for (size_t i = 0; i < key_derivation_bin_size; i += sizeof(uint32_t)) {
|
||||
write32le((void *)0x4003D000, i, read32le(key_derivation_bin, i));
|
||||
}
|
||||
|
||||
static const uint8_t AL16 masterkey_4x_seed[0x10] = {
|
||||
0x2D, 0xC1, 0xF4, 0x8D, 0xF3, 0x5B, 0x69, 0x33, 0x42, 0x10, 0xAC, 0x65, 0xDA, 0x90, 0x46, 0x66
|
||||
};
|
||||
cluster_boot_cpu0(0x4003D000);
|
||||
|
||||
static const uint8_t AL16 new_master_kek_seed_7x[0x10] = {
|
||||
0x9A, 0x3E, 0xA9, 0xAB, 0xFD, 0x56, 0x46, 0x1C, 0x9B, 0xF6, 0x48, 0x7F, 0x5C, 0xFA, 0x09, 0x5C
|
||||
};
|
||||
|
||||
void derive_7x_keys(const void *tsec_key, void *tsec_root_key) {
|
||||
uint8_t AL16 work_buffer[0x10];
|
||||
|
||||
/* Set keyslot flags properly in preparation of derivation. */
|
||||
set_aes_keyslot_flags(0xE, 0x15);
|
||||
set_aes_keyslot_flags(0xD, 0x15);
|
||||
|
||||
/* Set the TSEC key. */
|
||||
set_aes_keyslot(0xD, tsec_key, 0x10);
|
||||
|
||||
/* Derive keyblob key 0. */
|
||||
se_aes_ecb_decrypt_block(0xD, work_buffer, 0x10, keyblob_seed_00, 0x10);
|
||||
decrypt_data_into_keyslot(0xF, 0xE, work_buffer, 0x10);
|
||||
|
||||
/* Clear the SBK. */
|
||||
clear_aes_keyslot(0xE);
|
||||
|
||||
/* Derive the master kek. */
|
||||
set_aes_keyslot(0xC, tsec_root_key, 0x10);
|
||||
decrypt_data_into_keyslot(0xC, 0xC, new_master_kek_seed_7x, 0x10);
|
||||
|
||||
/* Derive keys for exosphere. */
|
||||
decrypt_data_into_keyslot(0xA, 0xF, devicekey_4x_seed, 0x10);
|
||||
decrypt_data_into_keyslot(0xF, 0xF, devicekey_seed, 0x10);
|
||||
decrypt_data_into_keyslot(0xE, 0xC, masterkey_4x_seed, 0x10);
|
||||
decrypt_data_into_keyslot(0xC, 0xC, masterkey_seed, 0x10);
|
||||
|
||||
/* Clear master kek from memory. */
|
||||
for (size_t i = 0; i < sizeof(work_buffer); i++) {
|
||||
work_buffer[i] = 0xCC;
|
||||
while (*mailbox != 7) {
|
||||
/* Wait until keys have been derived. */
|
||||
}
|
||||
}
|
||||
|
||||
void load_keys(const uint8_t *se_state) {
|
||||
/* Clear keyslots up to 0xA. */
|
||||
for (size_t i = 0; i < 0xA; i++) {
|
||||
clear_aes_keyslot(i);
|
||||
}
|
||||
|
||||
/* Copy device keygen key out of state keyslot 0xA into keyslot 0xA. */
|
||||
set_aes_keyslot(0xA, se_state + 0x30 + (0xA * 0x20), 0x10);
|
||||
|
||||
/* Clear keyslot 0xB. */
|
||||
clear_aes_keyslot(0xB);
|
||||
|
||||
/* Copy master key out of state keyslot 0xC into keyslot 0xC. */
|
||||
set_aes_keyslot(0xC, se_state + 0x30 + (0xC * 0x20), 0x10);
|
||||
|
||||
/* Copy firmware device key out of state keyslot 0xE into keyslot 0xD. */
|
||||
set_aes_keyslot(0xD, se_state + 0x30 + (0xE * 0x20), 0x10);
|
||||
|
||||
/* Clear keyslot 0xE. */
|
||||
clear_aes_keyslot(0xE);
|
||||
|
||||
/* Copy device key out of state keyslot 0xF into keyslot 0xF. */
|
||||
set_aes_keyslot(0xF, se_state + 0x30 + (0xF * 0x20), 0x10);
|
||||
|
||||
/* Set keyslot flags properly in preparation for secmon. */
|
||||
set_aes_keyslot_flags(0xE, 0x15);
|
||||
set_aes_keyslot_flags(0xD, 0x15);
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
* 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_KEYDERIVATION_H
|
||||
#define SEPT_KEYDERIVATION_H
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
void derive_7x_keys(const void *tsec_key, void *tsec_root_key);
|
||||
void derive_keys(uint32_t version);
|
||||
void load_keys(const uint8_t *se_state);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#include "utils.h"
|
||||
#include "exception_handlers.h"
|
||||
#include "panic.h"
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "se.h"
|
||||
#include "pmc.h"
|
||||
#include "emc.h"
|
||||
#include "sysreg.h"
|
||||
#include "key_derivation.h"
|
||||
#include "timers.h"
|
||||
#include "fs_utils.h"
|
||||
@@ -39,9 +40,6 @@ extern void (*__program_exit_callback)(int rc);
|
||||
|
||||
static void *g_framebuffer;
|
||||
|
||||
static uint32_t g_tsec_root_key[0x4] = {0};
|
||||
static uint32_t g_tsec_key[0x4] = {0};
|
||||
|
||||
static bool has_rebooted(void) {
|
||||
return MAKE_REG32(0x4003FFFC) == 0xFAFAFAFA;
|
||||
}
|
||||
@@ -51,27 +49,19 @@ static void set_has_rebooted(bool rebooted) {
|
||||
}
|
||||
|
||||
|
||||
static void exfiltrate_keys_and_reboot_if_needed(void) {
|
||||
static void exfiltrate_keys_and_reboot_if_needed(uint32_t version) {
|
||||
volatile tegra_pmc_t *pmc = pmc_get_regs();
|
||||
uint8_t *enc_se_state = (uint8_t *)0x4003E000;
|
||||
uint8_t *dec_se_state = (uint8_t *)0x4003F000;
|
||||
|
||||
|
||||
if (!has_rebooted()) {
|
||||
/* Prepare for a reboot before doing anything else. */
|
||||
prepare_for_reboot_to_self();
|
||||
set_has_rebooted(true);
|
||||
|
||||
/* Save the security engine context. */
|
||||
se_get_regs()->_0x4 = 0x0;
|
||||
se_set_in_context_save_mode(true);
|
||||
se_save_context(KEYSLOT_SWITCH_SRKGENKEY, KEYSLOT_SWITCH_RNGKEY, enc_se_state);
|
||||
se_set_in_context_save_mode(false);
|
||||
|
||||
/* Clear all keyslots. */
|
||||
for (size_t k = 0; k < 0x10; k++) {
|
||||
clear_aes_keyslot(k);
|
||||
}
|
||||
|
||||
|
||||
/* Derive keys. */
|
||||
derive_keys(version);
|
||||
|
||||
reboot_to_self();
|
||||
} else {
|
||||
/* Decrypt the security engine state. */
|
||||
@@ -82,13 +72,10 @@ static void exfiltrate_keys_and_reboot_if_needed(void) {
|
||||
context_key[3] = pmc->secure_scratch7;
|
||||
set_aes_keyslot(0xC, context_key, sizeof(context_key));
|
||||
se_aes_128_cbc_decrypt(0xC, dec_se_state, 0x840, enc_se_state, 0x840);
|
||||
|
||||
/* Copy out tsec key + tsec root key. */
|
||||
for (size_t i = 0; i < 0x10; i += 4) {
|
||||
g_tsec_key[i/4] = MAKE_REG32((uintptr_t)(dec_se_state) + 0x1B0 + i);
|
||||
g_tsec_root_key[i/4] = MAKE_REG32((uintptr_t)(dec_se_state) + 0x1D0 + i);
|
||||
}
|
||||
|
||||
|
||||
/* Load keys in from decrypted state. */
|
||||
load_keys(dec_se_state);
|
||||
|
||||
/* Clear the security engine state. */
|
||||
for (size_t i = 0; i < 0x840; i += 4) {
|
||||
MAKE_REG32((uintptr_t)(enc_se_state) + i) = 0xCCCCCCCC;
|
||||
@@ -101,11 +88,6 @@ static void exfiltrate_keys_and_reboot_if_needed(void) {
|
||||
pmc->secure_scratch5 = 0xCCCCCCCC;
|
||||
pmc->secure_scratch6 = 0xCCCCCCCC;
|
||||
pmc->secure_scratch7 = 0xCCCCCCCC;
|
||||
|
||||
/* Clear all keyslots except for SBK/SSK. */
|
||||
for (size_t k = 0; k < 0xE; k++) {
|
||||
clear_aes_keyslot(k);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,9 +97,6 @@ static void setup_env(void) {
|
||||
/* Initialize hardware. */
|
||||
nx_hwinit();
|
||||
|
||||
/* Check for panics. */
|
||||
check_and_display_panic();
|
||||
|
||||
/* Zero-fill the framebuffer and register it as printk provider. */
|
||||
video_init(g_framebuffer);
|
||||
|
||||
@@ -126,7 +105,7 @@ static void setup_env(void) {
|
||||
|
||||
/* Set the framebuffer. */
|
||||
display_init_framebuffer(g_framebuffer);
|
||||
|
||||
|
||||
/* Draw splash. */
|
||||
draw_splash((volatile uint32_t *)g_framebuffer);
|
||||
|
||||
@@ -136,7 +115,7 @@ static void setup_env(void) {
|
||||
|
||||
/* Set up the exception handlers. */
|
||||
setup_exception_handlers();
|
||||
|
||||
|
||||
/* Mount the SD card. */
|
||||
mount_sd();
|
||||
}
|
||||
@@ -154,33 +133,29 @@ static void exit_callback(int rc) {
|
||||
relocate_and_chainload();
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
int sept_main(uint32_t version) {
|
||||
const char *stage2_path;
|
||||
stage2_args_t *stage2_args;
|
||||
uint32_t stage2_version = 0;
|
||||
ScreenLogLevel log_level = SCREEN_LOG_LEVEL_NONE;
|
||||
|
||||
|
||||
/* Validate that we can safely boot the CCPLEX. */
|
||||
if (SB_CSR_0 & 2) {
|
||||
generic_panic();
|
||||
}
|
||||
|
||||
/* Extract keys from the security engine, which TSEC FW locked down. */
|
||||
exfiltrate_keys_and_reboot_if_needed();
|
||||
|
||||
exfiltrate_keys_and_reboot_if_needed(version);
|
||||
|
||||
/* Override the global logging level. */
|
||||
log_set_log_level(log_level);
|
||||
|
||||
|
||||
/* Initialize the display, console, etc. */
|
||||
setup_env();
|
||||
|
||||
/* Derive keys. */
|
||||
derive_7x_keys(g_tsec_key, g_tsec_root_key);
|
||||
|
||||
/* Cleanup keys in memory. */
|
||||
for (size_t i = 0; i < 0x10; i += 4) {
|
||||
g_tsec_root_key[i/4] = 0xCCCCCCCC;
|
||||
g_tsec_key[i/4] = 0xCCCCCCCC;
|
||||
}
|
||||
|
||||
|
||||
/* Mark EMC scratch to say that sept has run. */
|
||||
MAKE_EMC_REG(EMC_SCRATCH0) |= 0x80000000;
|
||||
|
||||
|
||||
/* Load the loader payload into DRAM. */
|
||||
load_stage2();
|
||||
|
||||
@@ -194,10 +169,10 @@ int main(void) {
|
||||
stage2_args->display_initialized = false;
|
||||
strcpy(stage2_args->bct0, "");
|
||||
g_chainloader_argc = 2;
|
||||
|
||||
|
||||
/* Wait a while. */
|
||||
mdelay(1500);
|
||||
|
||||
|
||||
/* Deinitialize the display, console, etc. */
|
||||
cleanup_env();
|
||||
|
||||
|
||||
@@ -13,76 +13,17 @@
|
||||
* 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 <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include "panic.h"
|
||||
#include "di.h"
|
||||
#include "pmc.h"
|
||||
#include "se.h"
|
||||
#include "fuse.h"
|
||||
#include "utils.h"
|
||||
|
||||
static uint32_t g_panic_code = 0;
|
||||
|
||||
void check_and_display_panic(void) {
|
||||
/* We also handle our own panics. */
|
||||
/* In the case of our own panics, we assume that the display has already been initialized. */
|
||||
bool has_panic = APBDEV_PMC_RST_STATUS_0 != 0 || g_panic_code != 0;
|
||||
uint32_t code = g_panic_code == 0 ? APBDEV_PMC_SCRATCH200_0 : g_panic_code;
|
||||
|
||||
has_panic = has_panic && !(APBDEV_PMC_RST_STATUS_0 != 1 && code == PANIC_CODE_SAFEMODE);
|
||||
|
||||
if (has_panic) {
|
||||
uint32_t color;
|
||||
|
||||
/* Check for predefined codes: */
|
||||
switch (code & MASK(20)) {
|
||||
case 0x01: /* Package2 signature verification failed. */
|
||||
case 0x02: /* Package2 meta verification failed. */
|
||||
case 0x03: /* Package2 version check failed. */
|
||||
case 0x04: /* Package2 payload verification failed. */
|
||||
color = PANIC_COLOR_KERNEL;
|
||||
break;
|
||||
case 0x05: /* Unknown SMC. */
|
||||
case 0x06: /* Unknown Abort. */
|
||||
color = PANIC_COLOR_SECMON_GENERIC;
|
||||
break;
|
||||
case 0x07: /* Invalid CPU context. */
|
||||
case 0x08: /* Invalid SE state. */
|
||||
case 0x09: /* CPU is already awake (2.0.0+). */
|
||||
color = PANIC_COLOR_SECMON_DEEPSLEEP;
|
||||
break;
|
||||
case 0x10: /* Unknown exception. */
|
||||
color = PANIC_COLOR_SECMON_EXCEPTION;
|
||||
break;
|
||||
case 0x30: /* General bootloader error. */
|
||||
case 0x31: /* Invalid DRAM ID. */
|
||||
case 0x32: /* Invalid size. */
|
||||
case 0x33: /* Invalid arguement. */
|
||||
case 0x34: /* Bad GPT. */
|
||||
case 0x35: /* Failed to boot SafeMode. */
|
||||
case 0x36: /* Activity monitor fired (4.0.0+). */
|
||||
color = PANIC_COLOR_BOOTLOADER_GENERIC;
|
||||
break;
|
||||
case 0x40: /* Kernel panic. */
|
||||
color = PANIC_COLOR_KERNEL;
|
||||
break;
|
||||
default:
|
||||
color = code >> 20;
|
||||
color |= color << 4;
|
||||
break;
|
||||
}
|
||||
|
||||
if (g_panic_code == 0) {
|
||||
display_init();
|
||||
}
|
||||
|
||||
display_color_screen(color);
|
||||
wait_for_button_and_reboot();
|
||||
} else {
|
||||
g_panic_code = 0;
|
||||
APBDEV_PMC_SCRATCH200_0 = 0;
|
||||
}
|
||||
}
|
||||
|
||||
__attribute__ ((noreturn)) void panic(uint32_t code) {
|
||||
/* Set panic code. */
|
||||
if (g_panic_code == 0) {
|
||||
@@ -90,9 +31,13 @@ __attribute__ ((noreturn)) void panic(uint32_t code) {
|
||||
APBDEV_PMC_SCRATCH200_0 = code;
|
||||
}
|
||||
|
||||
/* Clear all keyslots. */
|
||||
for (size_t i = 0; i < 0x10; i++) {
|
||||
clear_aes_keyslot(i);
|
||||
}
|
||||
|
||||
fuse_disable_programming();
|
||||
APBDEV_PMC_CRYPTO_OP_0 = 1; /* Disable all SE operations. */
|
||||
|
||||
check_and_display_panic();
|
||||
while(true);
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
* 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 FUSEE_PANIC_H
|
||||
#define FUSEE_PANIC_H
|
||||
|
||||
@@ -28,7 +28,6 @@
|
||||
|
||||
#define PANIC_CODE_SAFEMODE 0x00000020
|
||||
|
||||
void check_and_display_panic(void);
|
||||
__attribute__ ((noreturn)) void panic(uint32_t code);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
.macro CLEAR_GPR_REG_ITER
|
||||
mov r\@, #0
|
||||
.endm
|
||||
@@ -26,13 +26,18 @@
|
||||
_start:
|
||||
/* Switch to system mode, mask all interrupts, clear all flags */
|
||||
msr cpsr_cxsf, #0xDF
|
||||
b begin_relocation_loop
|
||||
_version:
|
||||
.word 0x00000000 /* Version. */
|
||||
.word 0x00000000 /* Reserved. */
|
||||
|
||||
begin_relocation_loop:
|
||||
/* Relocate ourselves if necessary */
|
||||
ldr r2, =__start__
|
||||
adr r3, _start
|
||||
cmp r2, r3
|
||||
beq _relocation_loop_end
|
||||
|
||||
|
||||
/* If we are relocating, we are not rebooting to ourselves. Note that. */
|
||||
ldr r0, =0x4003FFFC
|
||||
mov r1, #0x0
|
||||
@@ -50,12 +55,12 @@ _start:
|
||||
|
||||
ldr r12, =_second_relocation_start
|
||||
bx r12
|
||||
|
||||
|
||||
_second_relocation_start:
|
||||
ldr r4, =__bss_start__
|
||||
sub r4, r4, r2
|
||||
mov r1, #0x0
|
||||
|
||||
|
||||
_second_relocation_loop:
|
||||
ldmia r3!, {r5-r12}
|
||||
stmia r2!, {r5-r12}
|
||||
@@ -67,7 +72,7 @@ _start:
|
||||
bx r12
|
||||
|
||||
_relocation_loop_end:
|
||||
|
||||
|
||||
/* Set the stack pointer */
|
||||
ldr sp, =__stack_top__
|
||||
mov fp, #0
|
||||
@@ -78,7 +83,9 @@ _start:
|
||||
CLEAR_GPR_REG_ITER
|
||||
.endr
|
||||
ldr lr, =__program_exit
|
||||
b main
|
||||
ldr r0, =_version
|
||||
ldr r0, [r0]
|
||||
b sept_main
|
||||
|
||||
/* No need to include this in normal programs: */
|
||||
.section .chainloader.text.start, "ax", %progbits
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
* 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 <stdbool.h>
|
||||
#include <stdarg.h>
|
||||
#include "utils.h"
|
||||
@@ -66,13 +66,16 @@ __attribute__((noreturn)) void pmc_reboot(uint32_t scratch0) {
|
||||
}
|
||||
|
||||
void prepare_for_reboot_to_self(void) {
|
||||
/* Write warmboot to scratch0. */
|
||||
APBDEV_PMC_SCRATCH0_0 = 0x00000001;
|
||||
|
||||
/* Patch SDRAM init to perform an SVC immediately after second write */
|
||||
APBDEV_PMC_SCRATCH45_0 = 0x2E38DFFF;
|
||||
APBDEV_PMC_SCRATCH46_0 = 0x6001DC28;
|
||||
/* Set SVC handler to jump to reboot stub in IRAM. */
|
||||
APBDEV_PMC_SCRATCH33_0 = 0x4003F000;
|
||||
APBDEV_PMC_SCRATCH40_0 = 0x6000F208;
|
||||
|
||||
|
||||
/* Copy reboot stub into IRAM high. */
|
||||
for (size_t i = 0; i < rebootstub_bin_size; i += sizeof(uint32_t)) {
|
||||
write32le((void *)0x4003F000, i, read32le(rebootstub_bin, i));
|
||||
@@ -82,7 +85,7 @@ void prepare_for_reboot_to_self(void) {
|
||||
__attribute__((noreturn)) void reboot_to_self(void) {
|
||||
/* Prep IRAM for reboot. */
|
||||
prepare_for_reboot_to_self();
|
||||
|
||||
|
||||
/* Trigger warm reboot. */
|
||||
pmc_reboot(1 << 0);
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#pragma once
|
||||
#define AMS_LOGO_WIDTH 0xA0
|
||||
#define AMS_LOGO_HEIGHT 0x80
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
* 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 <switch.h>
|
||||
#include "fatal_types.hpp"
|
||||
#include "fatal_config.hpp"
|
||||
@@ -38,22 +38,22 @@ IEvent *GetFatalSettingsEvent() {
|
||||
}
|
||||
g_fatal_settings_event = LoadReadOnlySystemEvent(evt.revent, [](u64 timeout) {
|
||||
u64 flags_0, flags_1;
|
||||
if (R_SUCCEEDED(setsysGetFatalDirtyFlags(&flags_0, &flags_1)) && (flags_0 & 1)) {
|
||||
if (R_SUCCEEDED(setsysGetFatalDirtyFlags(&flags_0, &flags_1)) && (flags_0 & 1)) {
|
||||
UpdateLanguageCode();
|
||||
}
|
||||
return ResultSuccess;
|
||||
}, true);
|
||||
}
|
||||
|
||||
|
||||
return g_fatal_settings_event;
|
||||
}
|
||||
|
||||
static void SetupConfigLanguages() {
|
||||
FatalConfig *config = GetFatalConfig();
|
||||
|
||||
|
||||
/* Defaults. */
|
||||
config->error_msg = u8"Error Code: 2%03d-%04d (0x%x)\n";
|
||||
|
||||
|
||||
if (config->quest_flag) {
|
||||
config->error_desc = u8"Please call 1-800-875-1852 for service.\n";
|
||||
} else {
|
||||
@@ -64,7 +64,7 @@ static void SetupConfigLanguages() {
|
||||
u8"If the problem persists, refer to the Nintendo Support Website.\n"
|
||||
u8"support.nintendo.com/switch/error\n";
|
||||
}
|
||||
|
||||
|
||||
/* TODO: Try to load dynamically. */
|
||||
/* FsStorage message_storage; */
|
||||
/* TODO: if (R_SUCCEEDED(fsOpenDataStorageByDataId(0x010000000000081D, "fatal_msg"))) { ... } */
|
||||
@@ -72,18 +72,18 @@ static void SetupConfigLanguages() {
|
||||
|
||||
void InitializeFatalConfig() {
|
||||
FatalConfig *config = GetFatalConfig();
|
||||
|
||||
|
||||
memset(config, 0, sizeof(*config));
|
||||
setsysGetSerialNumber(config->serial_number);
|
||||
setsysGetFirmwareVersion(&config->firmware_version);
|
||||
UpdateLanguageCode();
|
||||
|
||||
|
||||
setsysGetSettingsItemValue("fatal", "transition_to_fatal", &config->transition_to_fatal, sizeof(config->transition_to_fatal));
|
||||
setsysGetSettingsItemValue("fatal", "show_extra_info", &config->show_extra_info, sizeof(config->show_extra_info));
|
||||
setsysGetSettingsItemValue("fatal", "quest_reboot_interval_second", &config->quest_reboot_interval_second, sizeof(config->quest_reboot_interval_second));
|
||||
|
||||
|
||||
setsysGetFlag(SetSysFlag_Quest, &config->quest_flag);
|
||||
|
||||
|
||||
config->is_auto_reboot_enabled = R_SUCCEEDED(setsysGetSettingsItemValue("atmosphere", "fatal_auto_reboot_interval", &config->fatal_auto_reboot_interval, sizeof(config->fatal_auto_reboot_interval)));
|
||||
config->is_auto_reboot_enabled &= (config->fatal_auto_reboot_interval != 0);
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#pragma once
|
||||
#include <switch.h>
|
||||
#include <stratosphere.hpp>
|
||||
|
||||
@@ -21,20 +21,20 @@
|
||||
static bool IsAddressReadable(Handle debug_handle, u64 address, u64 size, MemoryInfo *o_mi) {
|
||||
MemoryInfo mi;
|
||||
u32 pi;
|
||||
|
||||
|
||||
if (o_mi == NULL) {
|
||||
o_mi = &mi;
|
||||
}
|
||||
|
||||
|
||||
if (R_FAILED(svcQueryDebugProcessMemory(o_mi, &pi, debug_handle, address))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/* Must be readable */
|
||||
if ((o_mi->perm & Perm_R) != Perm_R) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/* Must have space for both userdata address and userdata size. */
|
||||
if (address < o_mi->addr || o_mi->addr + o_mi->size < address + size) {
|
||||
return false;
|
||||
@@ -51,83 +51,83 @@ static bool CheckThreadIsFatalCaller(FatalThrowContext *ctx, u64 debug_handle, u
|
||||
if (R_FAILED(svcGetDebugThreadParam(&_, &thread_state, debug_handle, thread_id, DebugThreadParam_State))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
if (thread_state > 1) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Get the thread context. */
|
||||
if (R_FAILED(svcGetDebugThreadContext(thread_ctx, debug_handle, thread_id, 0xF))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/* Check if PC is readable. */
|
||||
if (!IsAddressReadable(debug_handle, thread_ctx->pc.x, sizeof(u32), NULL)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/* Try to read the current instruction. */
|
||||
u32 insn;
|
||||
if (R_FAILED(svcReadDebugProcessMemory(&insn, debug_handle, thread_ctx->pc.x, sizeof(insn)))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/* If the instruction isn't svcSendSyncRequest, it's not the fatal caller. */
|
||||
if (insn != 0xD4000421) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/* The fatal caller will have readable tls. */
|
||||
if (!IsAddressReadable(debug_handle, thread_tls_addr, 0x100, NULL)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/* Read in the fatal caller's tls. */
|
||||
u8 thread_tls[0x100];
|
||||
if (R_FAILED(svcReadDebugProcessMemory(thread_tls, debug_handle, thread_tls_addr, sizeof(thread_tls)))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/* Replace our tls with the fatal caller's. */
|
||||
std::memcpy(armGetTls(), thread_tls, sizeof(thread_tls));
|
||||
|
||||
|
||||
/* Parse the command that the thread sent. */
|
||||
{
|
||||
IpcParsedCommand r;
|
||||
if (R_FAILED(ipcParse(&r))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/* Fatal command takes in a PID, only one buffer max. */
|
||||
if (!r.HasPid || r.NumStatics || r.NumStaticsOut || r.NumHandles) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
struct {
|
||||
u32 magic;
|
||||
u32 version;
|
||||
u64 cmd_id;
|
||||
u32 err_code;
|
||||
} *raw = (decltype(raw))(r.Raw);
|
||||
|
||||
|
||||
if (raw->magic != SFCI_MAGIC) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
if (raw->cmd_id > 2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
if (raw->cmd_id != 2 && r.NumBuffers) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
if (raw->err_code != ctx->error_code) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* We found our caller. */
|
||||
return true;
|
||||
}
|
||||
@@ -137,7 +137,7 @@ void TryCollectDebugInformation(FatalThrowContext *ctx, u64 pid) {
|
||||
if (R_SUCCEEDED(svcDebugActiveProcess(&debug_handle, pid))) {
|
||||
/* Ensure we close the debugged process. */
|
||||
ON_SCOPE_EXIT { svcCloseHandle(debug_handle); };
|
||||
|
||||
|
||||
/* First things first, check if process is 64 bits, and get list of thread infos. */
|
||||
std::unordered_map<u64, u64> thread_id_to_tls;
|
||||
{
|
||||
@@ -152,17 +152,17 @@ void TryCollectDebugInformation(FatalThrowContext *ctx, u64 pid) {
|
||||
thread_id_to_tls[d.info.attach_thread.thread_id] = d.info.attach_thread.tls_address;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!got_attach_process) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* TODO: Try to collect information on 32-bit fatals. This shouldn't really matter for any real use case. */
|
||||
if (ctx->cpu_ctx.is_aarch32) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* Welcome to hell. */
|
||||
bool found_fatal_caller = false;
|
||||
u64 thread_id = 0;
|
||||
@@ -174,14 +174,14 @@ void TryCollectDebugInformation(FatalThrowContext *ctx, u64 pid) {
|
||||
if (R_FAILED(svcGetThreadList(&thread_count, thread_ids, 0x60, debug_handle))) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* We need to locate the thread that's called fatal. */
|
||||
for (u32 i = 0; i < thread_count; i++) {
|
||||
const u64 cur_thread_id = thread_ids[i];
|
||||
if (thread_id_to_tls.find(cur_thread_id) == thread_id_to_tls.end()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
if (CheckThreadIsFatalCaller(ctx, debug_handle, cur_thread_id, thread_id_to_tls[cur_thread_id], &thread_ctx)) {
|
||||
thread_id = cur_thread_id;
|
||||
found_fatal_caller = true;
|
||||
@@ -195,7 +195,7 @@ void TryCollectDebugInformation(FatalThrowContext *ctx, u64 pid) {
|
||||
if (R_FAILED(svcGetDebugThreadContext(&thread_ctx, debug_handle, thread_id, 0xF))) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* So we found our caller. */
|
||||
for (u32 i = 0; i < 29; i++) {
|
||||
/* GetDebugThreadContext won't give us any of these registers, because thread is in SVC :( */
|
||||
@@ -208,7 +208,7 @@ void TryCollectDebugInformation(FatalThrowContext *ctx, u64 pid) {
|
||||
ctx->cpu_ctx.aarch64_ctx.lr = thread_ctx.lr;
|
||||
ctx->cpu_ctx.aarch64_ctx.sp = thread_ctx.sp;
|
||||
ctx->cpu_ctx.aarch64_ctx.pc = thread_ctx.pc.x;
|
||||
|
||||
|
||||
|
||||
/* Parse a stack trace. */
|
||||
u64 cur_fp = thread_ctx.fp;
|
||||
@@ -217,18 +217,18 @@ void TryCollectDebugInformation(FatalThrowContext *ctx, u64 pid) {
|
||||
if (cur_fp == 0 || (cur_fp & 0xF)) {
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
/* Read a new frame. */
|
||||
StackFrame cur_frame;
|
||||
if (R_FAILED(svcReadDebugProcessMemory(&cur_frame, debug_handle, cur_fp, sizeof(StackFrame)))) {
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
/* Advance to the next frame. */
|
||||
ctx->cpu_ctx.aarch64_ctx.stack_trace[ctx->cpu_ctx.aarch64_ctx.stack_trace_size++] = cur_frame.lr;
|
||||
cur_fp = cur_frame.fp;
|
||||
}
|
||||
|
||||
|
||||
/* Try to read up to 0x100 of stack. */
|
||||
for (size_t sz = 0x100; sz > 0; sz -= 0x10) {
|
||||
if (IsAddressReadable(debug_handle, ctx->cpu_ctx.aarch64_ctx.sp, sz, nullptr)) {
|
||||
@@ -246,25 +246,25 @@ void TryCollectDebugInformation(FatalThrowContext *ctx, u64 pid) {
|
||||
if (R_FAILED(svcQueryDebugProcessMemory(&mi, &pi, debug_handle, guess)) || mi.perm != Perm_Rx) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/* Iterate backwards until we find the memory before the code region. */
|
||||
while (mi.addr > 0) {
|
||||
if (R_FAILED(svcQueryDebugProcessMemory(&mi, &pi, debug_handle, guess))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
if (mi.type == MemType_Unmapped) {
|
||||
/* Code region will be at the end of the unmapped region preceding it. */
|
||||
ctx->cpu_ctx.aarch64_ctx.start_address = mi.addr + mi.size;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
guess -= 4;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
|
||||
/* Parse the starting address. */
|
||||
{
|
||||
if (TryGuessStartAddress(thread_ctx.pc.x)) {
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#pragma once
|
||||
#include <switch.h>
|
||||
#include <stratosphere.hpp>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user