Compare commits
164 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
22ecb34fec | ||
|
|
cb46e4bc40 | ||
|
|
6c2d0cf162 | ||
|
|
4907afd9f3 | ||
|
|
acb43b67db | ||
|
|
baac8dc2fb | ||
|
|
7add4b6b13 | ||
|
|
a146a38af7 | ||
|
|
c45be1258a | ||
|
|
b9776882fd | ||
|
|
b0f2ce4211 | ||
|
|
f9cf371cf9 | ||
|
|
b273b1e5ab | ||
|
|
0bf3b35582 | ||
|
|
2cac144ba8 | ||
|
|
0d98f65f99 | ||
|
|
83e6bf7090 | ||
|
|
4aca6e5fcf | ||
|
|
aa6d522c16 | ||
|
|
2cced5bdac | ||
|
|
9178813338 | ||
|
|
7ad77cffb0 | ||
|
|
12c3ffc2e4 | ||
|
|
305c372d8c | ||
|
|
931cbc829f | ||
|
|
87d4e4c5f1 | ||
|
|
6ee5c8cb5f | ||
|
|
a3d4636d84 | ||
|
|
52c6438e32 | ||
|
|
ab4e88f1de | ||
|
|
0c039e03c3 | ||
|
|
adc9d2e5bf | ||
|
|
317e4b2038 | ||
|
|
bd99e2a138 | ||
|
|
4c4a6511f3 | ||
|
|
2bbcf63bd9 | ||
|
|
78722d9a90 | ||
|
|
e24f8ad722 | ||
|
|
28fb01b155 | ||
|
|
b8b37e78ba | ||
|
|
82a4d03985 | ||
|
|
195d9797fe | ||
|
|
15e1210179 | ||
|
|
e892e69929 | ||
|
|
7e8e3ece66 | ||
|
|
b5a9d94d35 | ||
|
|
f95b6e399f | ||
|
|
6551930233 | ||
|
|
c2a2694baf | ||
|
|
03df13f34c | ||
|
|
070f9c676d | ||
|
|
7dc3500a17 | ||
|
|
97bbe2a333 | ||
|
|
a6eaa1ec51 | ||
|
|
f93cc0ff44 | ||
|
|
ee145ca9aa | ||
|
|
8832b240a4 | ||
|
|
744f90611a | ||
|
|
440a921980 | ||
|
|
d0799e3cd1 | ||
|
|
5b32937f8f | ||
|
|
f438827263 | ||
|
|
0e60746179 | ||
|
|
0e39c8dda9 | ||
|
|
45a732c388 | ||
|
|
034384622f | ||
|
|
9efbbc9317 | ||
|
|
30afcddd3a | ||
|
|
38f349618f | ||
|
|
33a64abfb0 | ||
|
|
c4783fc2ca | ||
|
|
887972d67c | ||
|
|
9aff029ee4 | ||
|
|
bfcdc2ffd5 | ||
|
|
e4ae9d9d7c | ||
|
|
d255dcf665 | ||
|
|
f1a4b05524 | ||
|
|
d5c23ebf96 | ||
|
|
4e1368faaf | ||
|
|
2d6411f60a | ||
|
|
7191743f5d | ||
|
|
9d36f741d9 | ||
|
|
ff618bc285 | ||
|
|
c60eb4b722 | ||
|
|
6aed4ad7b3 | ||
|
|
761ceb7dbe | ||
|
|
3f6d1b532c | ||
|
|
144dc3a3f5 | ||
|
|
5cb50722cf | ||
|
|
7c7dd7178f | ||
|
|
d93b50205a | ||
|
|
405cb46b77 | ||
|
|
7f7c2e65ee | ||
|
|
c2df3d80dd | ||
|
|
a3b876ea3e | ||
|
|
4309194a11 | ||
|
|
ae57cb1e63 | ||
|
|
a86294218c | ||
|
|
eecefd634c | ||
|
|
37ce49a31f | ||
|
|
ab061cf0b3 | ||
|
|
1a2fd158e9 | ||
|
|
eb8652c6ec | ||
|
|
9885308bce | ||
|
|
1410fa185f | ||
|
|
6724f364b5 | ||
|
|
008d3ab494 | ||
|
|
00bd1cd083 | ||
|
|
6af2bb63b8 | ||
|
|
02504c8a36 | ||
|
|
ef76834ef4 | ||
|
|
6d75aa688c | ||
|
|
225a17116c | ||
|
|
e1f4c24686 | ||
|
|
3e8cd67129 | ||
|
|
697fc3a086 | ||
|
|
6518f37b1c | ||
|
|
81e97fa820 | ||
|
|
12802bf371 | ||
|
|
d1678be654 | ||
|
|
2a78d3c924 | ||
|
|
d4010ba04d | ||
|
|
7b6c19f820 | ||
|
|
3274d18b83 | ||
|
|
472c0e293a | ||
|
|
2e61413627 | ||
|
|
ebe9815b7b | ||
|
|
7f85f00db8 | ||
|
|
8151afb446 | ||
|
|
c0f930e75d | ||
|
|
47df1b9cd1 | ||
|
|
ae225abb75 | ||
|
|
e837e2e6ed | ||
|
|
fd74812d2b | ||
|
|
527cdae1a6 | ||
|
|
8731550688 | ||
|
|
b0094f133c | ||
|
|
73a6fc460b | ||
|
|
57714daa87 | ||
|
|
65f38ba459 | ||
|
|
3abb52c962 | ||
|
|
d33bf83138 | ||
|
|
79027591ac | ||
|
|
cd4f2cd347 | ||
|
|
c0c020e505 | ||
|
|
746b263527 | ||
|
|
be79d64deb | ||
|
|
990a49e0b8 | ||
|
|
7b0faabf38 | ||
|
|
ff062a232b | ||
|
|
e8ddc9cf2f | ||
|
|
1c5b049453 | ||
|
|
0c4be1f917 | ||
|
|
d4eb56a35f | ||
|
|
9281e4bbbc | ||
|
|
d000f86c89 | ||
|
|
7dc9320b41 | ||
|
|
f3808edb40 | ||
|
|
7a35d2b00c | ||
|
|
a094ac4496 | ||
|
|
ada4fd2c7f | ||
|
|
819d08415d | ||
|
|
45eb25270f | ||
|
|
5b15e4cdf7 |
12
.github/FUNDING.yml
vendored
Normal file
12
.github/FUNDING.yml
vendored
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
# These are supported funding model platforms
|
||||||
|
|
||||||
|
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
|
||||||
|
patreon: # Replace with a single Patreon username
|
||||||
|
open_collective: # Replace with a single Open Collective username
|
||||||
|
ko_fi: suchmememanyskill
|
||||||
|
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
||||||
|
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
|
||||||
|
liberapay: # Replace with a single Liberapay username
|
||||||
|
issuehunt: # Replace with a single IssueHunt username
|
||||||
|
otechie: # Replace with a single Otechie username
|
||||||
|
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
|
||||||
6
Makefile
6
Makefile
@@ -8,8 +8,8 @@ include $(DEVKITARM)/base_rules
|
|||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
|
|
||||||
IPL_LOAD_ADDR := 0x40003000
|
IPL_LOAD_ADDR := 0x40008000
|
||||||
LPVERSION_MAJOR := 1
|
LPVERSION_MAJOR := 3
|
||||||
LPVERSION_MINOR := 0
|
LPVERSION_MINOR := 0
|
||||||
LPVERSION_BUGFX := 0
|
LPVERSION_BUGFX := 0
|
||||||
|
|
||||||
@@ -29,7 +29,7 @@ OBJS = $(patsubst $(SOURCEDIR)/%.S, $(BUILDDIR)/$(TARGET)/%.o, \
|
|||||||
CUSTOMDEFINES := -DIPL_LOAD_ADDR=$(IPL_LOAD_ADDR)
|
CUSTOMDEFINES := -DIPL_LOAD_ADDR=$(IPL_LOAD_ADDR)
|
||||||
CUSTOMDEFINES += -DLP_VER_MJ=$(LPVERSION_MAJOR) -DLP_VER_MN=$(LPVERSION_MINOR) -DLP_VER_BF=$(LPVERSION_BUGFX)
|
CUSTOMDEFINES += -DLP_VER_MJ=$(LPVERSION_MAJOR) -DLP_VER_MN=$(LPVERSION_MINOR) -DLP_VER_BF=$(LPVERSION_BUGFX)
|
||||||
|
|
||||||
ARCH := -march=armv4t -mtune=arm7tdmi -mthumb-interwork
|
ARCH := -march=armv4t -mtune=arm7tdmi -mthumb -mthumb-interwork
|
||||||
CFLAGS = $(ARCH) -O2 -nostdlib -ffunction-sections -fdata-sections -fomit-frame-pointer -std=gnu11 -Wall $(CUSTOMDEFINES)
|
CFLAGS = $(ARCH) -O2 -nostdlib -ffunction-sections -fdata-sections -fomit-frame-pointer -std=gnu11 -Wall $(CUSTOMDEFINES)
|
||||||
LDFLAGS = $(ARCH) -nostartfiles -lgcc -Wl,--nmagic,--gc-sections -Xlinker --defsym=IPL_LOAD_ADDR=$(IPL_LOAD_ADDR)
|
LDFLAGS = $(ARCH) -nostartfiles -lgcc -Wl,--nmagic,--gc-sections -Xlinker --defsym=IPL_LOAD_ADDR=$(IPL_LOAD_ADDR)
|
||||||
|
|
||||||
|
|||||||
30
README.md
30
README.md
@@ -1,5 +1,33 @@
|
|||||||
# TegraExplorer
|
# TegraExplorer
|
||||||
A payload-based file explorer for your switch!
|
A payload-based file explorer for your switch!
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
1. Get your favorite payload injector
|
||||||
|
2. Inject TegraExplorer as a payload
|
||||||
|
|
||||||
|
Navigate around the menus using the vol+, vol- and power buttons
|
||||||
|
|
||||||
|
## Functions
|
||||||
|
- Navigate the SD card
|
||||||
|
- Navigate the System partition of your sysnand/sysmmc
|
||||||
|
- Interact with files
|
||||||
|
- Deleting, copying or moving files
|
||||||
|
- Launching payloads files
|
||||||
|
- Viewing the hex data of a file
|
||||||
|
- Interacting with folders
|
||||||
|
- Deleting or copying folders
|
||||||
|
- Dumping your current firmware to sd
|
||||||
|
- Formatting the sd card
|
||||||
|
|
||||||
|
## Support
|
||||||
|
|
||||||
|
For general CFW support, go to the [Nintendo Homebrew](https://discord.gg/C29hYvh) discord
|
||||||
|
|
||||||
|
For question specifically for TegraExplorer, go to [my discord](https://discord.gg/aH9rsuP)
|
||||||
|
|
||||||
# Credits
|
# Credits
|
||||||
Based on [Lockpick_RCM](https://github.com/shchmue/Lockpick_RCM), and thus based on [Hekate](https://github.com/CTCaer/hekate)
|
Based on [Lockpick_RCM](https://github.com/shchmue/Lockpick_RCM), and thus also based on [Hekate](https://github.com/CTCaer/hekate)
|
||||||
|
|
||||||
|
Lots of help from:
|
||||||
|
- shchmue
|
||||||
|
- Denn
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
/*
|
/*
|
||||||
* Common Gfx Header
|
* Common Gfx Header
|
||||||
* Copyright (c) 2018 naehrwert
|
* Copyright (c) 2018 naehrwert
|
||||||
* Copyright (C) 2018 CTCaer
|
* Copyright (c) 2018 CTCaer
|
||||||
* Copyright (C) 2018 M4xw
|
* Copyright (c) 2018 M4xw
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
* under the terms and conditions of the GNU General Public License,
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ typedef struct _hnode
|
|||||||
u32 size;
|
u32 size;
|
||||||
struct _hnode *prev;
|
struct _hnode *prev;
|
||||||
struct _hnode *next;
|
struct _hnode *next;
|
||||||
|
u32 align[4]; // Align to arch cache line size.
|
||||||
} hnode_t;
|
} hnode_t;
|
||||||
|
|
||||||
typedef struct _heap
|
typedef struct _heap
|
||||||
@@ -32,3 +33,9 @@ typedef struct _heap
|
|||||||
u32 start;
|
u32 start;
|
||||||
hnode_t *first;
|
hnode_t *first;
|
||||||
} heap_t;
|
} heap_t;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
u32 total;
|
||||||
|
u32 used;
|
||||||
|
} heap_monitor_t;
|
||||||
|
|||||||
39
common/common_module.h
Normal file
39
common/common_module.h
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* Common Module Header
|
||||||
|
* Copyright (c) 2018 M4xw
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <stddef.h>
|
||||||
|
//TODO: Move it to BDK
|
||||||
|
#include "common_gfx.h"
|
||||||
|
#include "common_heap.h"
|
||||||
|
|
||||||
|
// Module Callback
|
||||||
|
typedef void (*cbMainModule_t)(const char *s);
|
||||||
|
typedef void (*memcpy_t)(void *, void *, size_t);
|
||||||
|
typedef void (*memset_t)(void *, int, size_t);
|
||||||
|
|
||||||
|
typedef struct _bdkParams_t
|
||||||
|
{
|
||||||
|
gfx_con_t *gfxCon;
|
||||||
|
gfx_ctxt_t *gfxCtx;
|
||||||
|
heap_t *sharedHeap;
|
||||||
|
memcpy_t memcpy;
|
||||||
|
memset_t memset;
|
||||||
|
} *bdkParams_t;
|
||||||
|
|
||||||
|
// Module Entrypoint
|
||||||
|
typedef void (*moduleEntrypoint_t)(void *, bdkParams_t);
|
||||||
101
common/memory_map.h
Normal file
101
common/memory_map.h
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019 CTCaer
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _MEMORY_MAP_H_
|
||||||
|
#define _MEMORY_MAP_H_
|
||||||
|
|
||||||
|
//#define IPL_STACK_TOP 0x4003FF00
|
||||||
|
/* --- BIT/BCT: 0x40000000 - 0x40003000 --- */
|
||||||
|
/* --- IPL: 0x40008000 - 0x40028000 --- */
|
||||||
|
#define IPL_LOAD_ADDR 0x40008000
|
||||||
|
#define IPL_SZ_MAX 0x20000 // 128KB.
|
||||||
|
//#define IRAM_LIB_ADDR 0x4002B000
|
||||||
|
#define SDRAM_PARAMS_ADDR 0x40030000 // SDRAM extraction buffer during sdram init.
|
||||||
|
#define CBFS_DRAM_EN_ADDR 0x4003e000 // u32.
|
||||||
|
|
||||||
|
/* --- DRAM START --- */
|
||||||
|
#define DRAM_START 0x80000000
|
||||||
|
#define HOS_RSVD 0x1000000 // Do not write anything in this area.
|
||||||
|
|
||||||
|
#define NYX_LOAD_ADDR 0x81000000
|
||||||
|
#define NYX_SZ_MAX 0x1000000 // 16MB
|
||||||
|
/* --- Gap: 0x82000000 - 0x82FFFFFF --- */
|
||||||
|
|
||||||
|
/* Stack theoretical max: 33MB */
|
||||||
|
#define IPL_STACK_TOP 0x83100000
|
||||||
|
#define IPL_HEAP_START 0x84000000
|
||||||
|
#define IPL_HEAP_SZ 0x20000000 // 512MB.
|
||||||
|
/* --- Gap: 1040MB 0xA4000000 - 0xE4FFFFFF --- */
|
||||||
|
|
||||||
|
// Virtual disk / Chainloader buffers.
|
||||||
|
#define RAM_DISK_ADDR 0xA4000000
|
||||||
|
#define RAM_DISK_SZ 0x41000000 // 1040MB.
|
||||||
|
|
||||||
|
//#define DRAM_LIB_ADDR 0xE0000000
|
||||||
|
/* --- Chnldr: 252MB 0xC03C0000 - 0xCFFFFFFF --- */ //! Only used when chainloading.
|
||||||
|
|
||||||
|
// SDMMC DMA buffers 1
|
||||||
|
#define SDMMC_UPPER_BUFFER 0xE5000000
|
||||||
|
#define SDMMC_UP_BUF_SZ 0x8000000 // 128MB.
|
||||||
|
|
||||||
|
// Nyx buffers.
|
||||||
|
#define NYX_STORAGE_ADDR 0xED000000
|
||||||
|
#define NYX_RES_ADDR 0xEE000000
|
||||||
|
#define NYX_RES_SZ 0x1000000 // 16MB.
|
||||||
|
|
||||||
|
// SDMMC DMA buffers 2
|
||||||
|
#define SDXC_BUF_ALIGNED 0xEF000000
|
||||||
|
#define MIXD_BUF_ALIGNED 0xF0000000
|
||||||
|
#define EMMC_BUF_ALIGNED MIXD_BUF_ALIGNED
|
||||||
|
#define SDMMC_DMA_BUF_SZ 0x1000000 // 16MB (4MB currently used).
|
||||||
|
|
||||||
|
// Nyx LvGL buffers.
|
||||||
|
#define NYX_LV_VDB_ADR 0xF1000000
|
||||||
|
#define NYX_FB_SZ 0x384000 // 1280 x 720 x 4.
|
||||||
|
#define NYX_LV_MEM_ADR 0xF1400000
|
||||||
|
#define NYX_LV_MEM_SZ 0x6600000 // 70MB.
|
||||||
|
|
||||||
|
// Framebuffer addresses.
|
||||||
|
#define IPL_FB_ADDRESS 0xF5A00000
|
||||||
|
#define IPL_FB_SZ 0x384000 // 720 x 1280 x 4.
|
||||||
|
#define LOG_FB_ADDRESS 0xF5E00000
|
||||||
|
#define LOG_FB_SZ 0x334000 // 1280 x 656 x 4.
|
||||||
|
#define NYX_FB_ADDRESS 0xF6200000
|
||||||
|
#define NYX_FB2_ADDRESS 0xF6600000
|
||||||
|
#define NYX_FB_SZ 0x384000 // 1280 x 720 x 4.
|
||||||
|
|
||||||
|
#define DRAM_MEM_HOLE_ADR 0xF6A00000
|
||||||
|
#define DRAM_MEM_HOLE_SZ 0x8140000
|
||||||
|
/* --- Hole: 129MB 0xF6A00000 - 0xFEB3FFFF --- */
|
||||||
|
#define DRAM_START2 0xFEB40000
|
||||||
|
|
||||||
|
// NX BIS driver sector cache.
|
||||||
|
#define NX_BIS_CACHE_ADDR 0xFEE00000
|
||||||
|
#define NX_BIS_CACHE_SZ 0x8800
|
||||||
|
|
||||||
|
// USB buffers.
|
||||||
|
#define USBD_ADDR 0xFEF00000
|
||||||
|
#define USB_DESCRIPTOR_ADDR 0xFEF40000
|
||||||
|
#define USB_EP_CONTROL_BUF_ADDR 0xFEF80000
|
||||||
|
#define USB_EP_BULK_IN_BUF_ADDR 0xFF000000
|
||||||
|
#define USB_EP_BULK_OUT_BUF_ADDR 0xFF800000
|
||||||
|
#define USB_EP_BULK_OUT_MAX_XFER 0x800000
|
||||||
|
|
||||||
|
// #define EXT_PAYLOAD_ADDR 0xC0000000
|
||||||
|
// #define RCM_PAYLOAD_ADDR (EXT_PAYLOAD_ADDR + ALIGN(PATCHED_RELOC_SZ, 0x10))
|
||||||
|
// #define COREBOOT_ADDR (0xD0000000 - rom_size)
|
||||||
|
|
||||||
|
#endif
|
||||||
616
source/config/config.c
Normal file
616
source/config/config.c
Normal file
@@ -0,0 +1,616 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 CTCaer
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
#include "ini.h"
|
||||||
|
#include "../gfx/gfx.h"
|
||||||
|
#include "../gfx/tui.h"
|
||||||
|
#include "../libs/fatfs/ff.h"
|
||||||
|
#include "../soc/t210.h"
|
||||||
|
#include "../storage/nx_sd.h"
|
||||||
|
#include "../storage/sdmmc.h"
|
||||||
|
#include "../utils/btn.h"
|
||||||
|
#include "../utils/list.h"
|
||||||
|
#include "../utils/util.h"
|
||||||
|
|
||||||
|
extern hekate_config h_cfg;
|
||||||
|
|
||||||
|
void set_default_configuration()
|
||||||
|
{
|
||||||
|
h_cfg.autoboot = 0;
|
||||||
|
h_cfg.autoboot_list = 0;
|
||||||
|
h_cfg.bootwait = 3;
|
||||||
|
h_cfg.se_keygen_done = 0;
|
||||||
|
h_cfg.sbar_time_keeping = 0;
|
||||||
|
h_cfg.backlight = 100;
|
||||||
|
h_cfg.autohosoff = 0;
|
||||||
|
h_cfg.autonogc = 1;
|
||||||
|
h_cfg.updater2p = 0;
|
||||||
|
h_cfg.brand = NULL;
|
||||||
|
h_cfg.tagline = NULL;
|
||||||
|
h_cfg.errors = 0;
|
||||||
|
h_cfg.eks = NULL;
|
||||||
|
h_cfg.sept_run = EMC(EMC_SCRATCH0) & EMC_SEPT_RUN;
|
||||||
|
h_cfg.rcm_patched = true;
|
||||||
|
h_cfg.emummc_force_disable = false;
|
||||||
|
|
||||||
|
sd_power_cycle_time_start = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int create_config_entry()
|
||||||
|
{
|
||||||
|
if (!sd_mount())
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
char lbuf[32];
|
||||||
|
FIL fp;
|
||||||
|
bool mainIniFound = false;
|
||||||
|
|
||||||
|
LIST_INIT(ini_sections);
|
||||||
|
|
||||||
|
if (ini_parse(&ini_sections, "bootloader/hekate_ipl.ini", false))
|
||||||
|
mainIniFound = true;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
u8 res = f_open(&fp, "bootloader/hekate_ipl.ini", FA_READ);
|
||||||
|
if (res == FR_NO_FILE || res == FR_NO_PATH)
|
||||||
|
{
|
||||||
|
f_mkdir("bootloader");
|
||||||
|
f_mkdir("bootloader/ini");
|
||||||
|
f_mkdir("bootloader/payloads");
|
||||||
|
f_mkdir("bootloader/sys");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!res)
|
||||||
|
f_close(&fp);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (f_open(&fp, "bootloader/hekate_ipl.ini", FA_WRITE | FA_CREATE_ALWAYS) != FR_OK)
|
||||||
|
return 1;
|
||||||
|
// Add config entry.
|
||||||
|
f_puts("[config]\nautoboot=", &fp);
|
||||||
|
itoa(h_cfg.autoboot, lbuf, 10);
|
||||||
|
f_puts(lbuf, &fp);
|
||||||
|
f_puts("\nautoboot_list=", &fp);
|
||||||
|
itoa(h_cfg.autoboot_list, lbuf, 10);
|
||||||
|
f_puts(lbuf, &fp);
|
||||||
|
f_puts("\nbootwait=", &fp);
|
||||||
|
itoa(h_cfg.bootwait, lbuf, 10);
|
||||||
|
f_puts(lbuf, &fp);
|
||||||
|
f_puts("\nbacklight=", &fp);
|
||||||
|
itoa(h_cfg.backlight, lbuf, 10);
|
||||||
|
f_puts(lbuf, &fp);
|
||||||
|
f_puts("\nautohosoff=", &fp);
|
||||||
|
itoa(h_cfg.autohosoff, lbuf, 10);
|
||||||
|
f_puts(lbuf, &fp);
|
||||||
|
f_puts("\nautonogc=", &fp);
|
||||||
|
itoa(h_cfg.autonogc, lbuf, 10);
|
||||||
|
f_puts(lbuf, &fp);
|
||||||
|
f_puts("\nupdater2p=", &fp);
|
||||||
|
itoa(h_cfg.updater2p, lbuf, 10);
|
||||||
|
f_puts(lbuf, &fp);
|
||||||
|
if (h_cfg.brand)
|
||||||
|
{
|
||||||
|
f_puts("\nbrand=", &fp);
|
||||||
|
f_puts(h_cfg.brand, &fp);
|
||||||
|
}
|
||||||
|
if (h_cfg.tagline)
|
||||||
|
{
|
||||||
|
f_puts("\ntagline=", &fp);
|
||||||
|
f_puts(h_cfg.tagline, &fp);
|
||||||
|
}
|
||||||
|
f_puts("\n", &fp);
|
||||||
|
|
||||||
|
if (mainIniFound)
|
||||||
|
{
|
||||||
|
// Re-construct existing entries.
|
||||||
|
LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_sections, link)
|
||||||
|
{
|
||||||
|
if (!strcmp(ini_sec->name, "config"))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
switch (ini_sec->type)
|
||||||
|
{
|
||||||
|
case INI_CHOICE: // Re-construct Boot entry [ ].
|
||||||
|
f_puts("[", &fp);
|
||||||
|
f_puts(ini_sec->name, &fp);
|
||||||
|
f_puts("]\n", &fp);
|
||||||
|
// Re-construct boot entry's config.
|
||||||
|
LIST_FOREACH_ENTRY(ini_kv_t, kv, &ini_sec->kvs, link)
|
||||||
|
{
|
||||||
|
f_puts(kv->key, &fp);
|
||||||
|
f_puts("=", &fp);
|
||||||
|
f_puts(kv->val, &fp);
|
||||||
|
f_puts("\n", &fp);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case INI_CAPTION: // Re-construct caption entry { }.
|
||||||
|
f_puts("{", &fp);
|
||||||
|
f_puts(ini_sec->name, &fp);
|
||||||
|
f_puts("}\n", &fp);
|
||||||
|
break;
|
||||||
|
case INI_NEWLINE: // Re-construct cosmetic newline \n.
|
||||||
|
f_puts("\n", &fp);
|
||||||
|
break;
|
||||||
|
case INI_COMMENT: // Re-construct comment entry #.
|
||||||
|
f_puts("#", &fp);
|
||||||
|
f_puts(ini_sec->name, &fp);
|
||||||
|
f_puts("\n", &fp);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
f_close(&fp);
|
||||||
|
sd_unmount();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma GCC push_options
|
||||||
|
#pragma GCC optimize ("Os")
|
||||||
|
|
||||||
|
static void _save_config()
|
||||||
|
{
|
||||||
|
gfx_clear_grey(0x1B);
|
||||||
|
gfx_con_setpos(0, 0);
|
||||||
|
|
||||||
|
if (!create_config_entry())
|
||||||
|
gfx_puts("\nConfiguration was saved!\n");
|
||||||
|
else
|
||||||
|
EPRINTF("\nConfiguration saving failed!");
|
||||||
|
gfx_puts("\nPress any key...");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _config_autoboot_list(void *ent)
|
||||||
|
{
|
||||||
|
gfx_clear_grey(0x1B);
|
||||||
|
gfx_con_setpos(0, 0);
|
||||||
|
|
||||||
|
u32 *temp_autoboot = NULL;
|
||||||
|
|
||||||
|
LIST_INIT(ini_sections);
|
||||||
|
|
||||||
|
u8 max_entries = 30;
|
||||||
|
|
||||||
|
ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * (max_entries + 3));
|
||||||
|
u32 *boot_values = (u32 *)malloc(sizeof(u32) * max_entries);
|
||||||
|
char *boot_text = (char *)malloc(512 * max_entries);
|
||||||
|
|
||||||
|
for (u32 j = 0; j < max_entries; j++)
|
||||||
|
boot_values[j] = j;
|
||||||
|
|
||||||
|
if (sd_mount())
|
||||||
|
{
|
||||||
|
if (ini_parse(&ini_sections, "bootloader/ini", true))
|
||||||
|
{
|
||||||
|
// Build configuration menu.
|
||||||
|
ments[0].type = MENT_BACK;
|
||||||
|
ments[0].caption = "Back";
|
||||||
|
|
||||||
|
ments[1].type = MENT_CHGLINE;
|
||||||
|
|
||||||
|
u32 i = 2;
|
||||||
|
LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_sections, link)
|
||||||
|
{
|
||||||
|
// Skip other ini entries for autoboot.
|
||||||
|
if (ini_sec->type == INI_CHOICE)
|
||||||
|
{
|
||||||
|
if (!strcmp(ini_sec->name, "config"))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (strlen(ini_sec->name) > 510)
|
||||||
|
ments[i].caption = ini_sec->name;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (h_cfg.autoboot != (i - 1) || !h_cfg.autoboot_list)
|
||||||
|
boot_text[(i - 1) * 512] = ' ';
|
||||||
|
|
||||||
|
else
|
||||||
|
boot_text[(i - 1) * 512] = '*';
|
||||||
|
strcpy(boot_text + (i - 1) * 512 + 1, ini_sec->name);
|
||||||
|
ments[i].caption = &boot_text[(i - 1) * 512];
|
||||||
|
}
|
||||||
|
ments[i].type = ini_sec->type;
|
||||||
|
ments[i].data = &boot_values[i - 1];
|
||||||
|
i++;
|
||||||
|
|
||||||
|
if ((i - 1) > max_entries)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(&ments[i], 0, sizeof(ment_t));
|
||||||
|
menu_t menu = {ments, "Select an entry to auto boot", 0, 0};
|
||||||
|
temp_autoboot = (u32 *)tui_do_menu(&menu);
|
||||||
|
if (temp_autoboot != NULL)
|
||||||
|
{
|
||||||
|
h_cfg.autoboot = *(u32 *)temp_autoboot;
|
||||||
|
h_cfg.autoboot_list = 1;
|
||||||
|
_save_config();
|
||||||
|
|
||||||
|
ment_t *tmp = (ment_t *)ent;
|
||||||
|
tmp->data = NULL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
goto out2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
EPRINTF("Could not open 'bootloader/hekate_ipl.ini'.\nMake sure it exists!.");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
out:;
|
||||||
|
btn_wait();
|
||||||
|
out2:;
|
||||||
|
free(ments);
|
||||||
|
free(boot_values);
|
||||||
|
free(boot_text);
|
||||||
|
|
||||||
|
sd_unmount();
|
||||||
|
}
|
||||||
|
|
||||||
|
void config_autoboot()
|
||||||
|
{
|
||||||
|
gfx_clear_grey(0x1B);
|
||||||
|
gfx_con_setpos(0, 0);
|
||||||
|
|
||||||
|
u32 *temp_autoboot = NULL;
|
||||||
|
|
||||||
|
LIST_INIT(ini_sections);
|
||||||
|
|
||||||
|
u8 max_entries = 30;
|
||||||
|
u32 boot_text_size = 512;
|
||||||
|
|
||||||
|
ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * (max_entries + 5));
|
||||||
|
u32 *boot_values = (u32 *)malloc(sizeof(u32) * max_entries);
|
||||||
|
char *boot_text = (char *)malloc(boot_text_size * max_entries);
|
||||||
|
|
||||||
|
for (u32 j = 0; j < max_entries; j++)
|
||||||
|
boot_values[j] = j;
|
||||||
|
|
||||||
|
if (sd_mount())
|
||||||
|
{
|
||||||
|
if (ini_parse(&ini_sections, "bootloader/hekate_ipl.ini", false))
|
||||||
|
{
|
||||||
|
// Build configuration menu.
|
||||||
|
ments[0].type = MENT_BACK;
|
||||||
|
ments[0].caption = "Back";
|
||||||
|
|
||||||
|
ments[1].type = MENT_CHGLINE;
|
||||||
|
|
||||||
|
ments[2].type = MENT_DATA;
|
||||||
|
if (!h_cfg.autoboot)
|
||||||
|
ments[2].caption = "*Disable";
|
||||||
|
else
|
||||||
|
ments[2].caption = " Disable";
|
||||||
|
ments[2].data = &boot_values[0];
|
||||||
|
|
||||||
|
ments[3].type = MENT_HDLR_RE;
|
||||||
|
if (h_cfg.autoboot_list)
|
||||||
|
ments[3].caption = "*More configs...";
|
||||||
|
else
|
||||||
|
ments[3].caption = " More configs...";
|
||||||
|
ments[3].handler = _config_autoboot_list;
|
||||||
|
ments[3].data = (void *)0xCAFE;
|
||||||
|
|
||||||
|
ments[4].type = MENT_CHGLINE;
|
||||||
|
|
||||||
|
u32 i = 5;
|
||||||
|
LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_sections, link)
|
||||||
|
{
|
||||||
|
// Skip other ini entries for autoboot.
|
||||||
|
if (ini_sec->type == INI_CHOICE)
|
||||||
|
{
|
||||||
|
if (!strcmp(ini_sec->name, "config"))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (strlen(ini_sec->name) > 510)
|
||||||
|
ments[i].caption = ini_sec->name;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (h_cfg.autoboot != (i - 4) || h_cfg.autoboot_list)
|
||||||
|
boot_text[(i - 4) * boot_text_size] = ' ';
|
||||||
|
|
||||||
|
else
|
||||||
|
boot_text[(i - 4) * boot_text_size] = '*';
|
||||||
|
strcpy(boot_text + (i - 4) * boot_text_size + 1, ini_sec->name);
|
||||||
|
ments[i].caption = &boot_text[(i - 4) * boot_text_size];
|
||||||
|
}
|
||||||
|
ments[i].type = ini_sec->type;
|
||||||
|
ments[i].data = &boot_values[i - 4];
|
||||||
|
i++;
|
||||||
|
|
||||||
|
if ((i - 4) > max_entries)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (i < 6 && !h_cfg.autoboot_list)
|
||||||
|
{
|
||||||
|
ments[i].type = MENT_CAPTION;
|
||||||
|
ments[i].caption = "No main configurations found...";
|
||||||
|
ments[i].color = 0xFFFFDD00;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(&ments[i], 0, sizeof(ment_t));
|
||||||
|
menu_t menu = {ments, "Disable or select entry to auto boot", 0, 0};
|
||||||
|
temp_autoboot = (u32 *)tui_do_menu(&menu);
|
||||||
|
if (temp_autoboot != NULL)
|
||||||
|
{
|
||||||
|
h_cfg.autoboot = *(u32 *)temp_autoboot;
|
||||||
|
h_cfg.autoboot_list = 0;
|
||||||
|
_save_config();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
goto out2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
EPRINTF("Could not open 'bootloader/hekate_ipl.ini'.\nMake sure it exists!.");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
out:;
|
||||||
|
btn_wait();
|
||||||
|
out2:;
|
||||||
|
free(ments);
|
||||||
|
free(boot_values);
|
||||||
|
free(boot_text);
|
||||||
|
|
||||||
|
sd_unmount();
|
||||||
|
|
||||||
|
if (temp_autoboot == NULL)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void config_bootdelay()
|
||||||
|
{
|
||||||
|
gfx_clear_grey(0x1B);
|
||||||
|
gfx_con_setpos(0, 0);
|
||||||
|
|
||||||
|
u32 delay_entries = 6;
|
||||||
|
u32 delay_text_size = 32;
|
||||||
|
|
||||||
|
ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * (delay_entries + 3));
|
||||||
|
u32 *delay_values = (u32 *)malloc(sizeof(u32) * delay_entries);
|
||||||
|
char *delay_text = (char *)malloc(delay_text_size * delay_entries);
|
||||||
|
|
||||||
|
for (u32 j = 0; j < delay_entries; j++)
|
||||||
|
delay_values[j] = j;
|
||||||
|
|
||||||
|
ments[0].type = MENT_BACK;
|
||||||
|
ments[0].caption = "Back";
|
||||||
|
|
||||||
|
ments[1].type = MENT_CHGLINE;
|
||||||
|
|
||||||
|
ments[2].type = MENT_DATA;
|
||||||
|
if (h_cfg.bootwait)
|
||||||
|
ments[2].caption = " 0 seconds (Bootlogo disabled)";
|
||||||
|
else
|
||||||
|
ments[2].caption = "*0 seconds (Bootlogo disabled)";
|
||||||
|
ments[2].data = &delay_values[0];
|
||||||
|
|
||||||
|
u32 i = 0;
|
||||||
|
for (i = 1; i < delay_entries; i++)
|
||||||
|
{
|
||||||
|
if (h_cfg.bootwait != i)
|
||||||
|
delay_text[i * delay_text_size] = ' ';
|
||||||
|
else
|
||||||
|
delay_text[i * delay_text_size] = '*';
|
||||||
|
delay_text[i * delay_text_size + 1] = i + '0';
|
||||||
|
strcpy(delay_text + i * delay_text_size + 2, " seconds");
|
||||||
|
|
||||||
|
ments[i + 2].type = MENT_DATA;
|
||||||
|
ments[i + 2].caption = delay_text + (i * delay_text_size);
|
||||||
|
ments[i + 2].data = &delay_values[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(&ments[i + 2], 0, sizeof(ment_t));
|
||||||
|
menu_t menu = {ments, "Time delay for entering bootloader menu", 0, 0};
|
||||||
|
|
||||||
|
u32 *temp_bootwait = (u32 *)tui_do_menu(&menu);
|
||||||
|
if (temp_bootwait != NULL)
|
||||||
|
{
|
||||||
|
h_cfg.bootwait = *(u32 *)temp_bootwait;
|
||||||
|
_save_config();
|
||||||
|
}
|
||||||
|
|
||||||
|
free(ments);
|
||||||
|
free(delay_values);
|
||||||
|
free(delay_text);
|
||||||
|
|
||||||
|
if (temp_bootwait == NULL)
|
||||||
|
return;
|
||||||
|
btn_wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
void config_backlight()
|
||||||
|
{
|
||||||
|
gfx_clear_grey(0x1B);
|
||||||
|
gfx_con_setpos(0, 0);
|
||||||
|
|
||||||
|
u32 bri_text_size = 8;
|
||||||
|
u32 bri_entries = 11;
|
||||||
|
|
||||||
|
ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * (bri_entries + 3));
|
||||||
|
u32 *bri_values = (u32 *)malloc(sizeof(u32) * bri_entries);
|
||||||
|
char *bri_text = (char *)malloc(bri_text_size * bri_entries);
|
||||||
|
|
||||||
|
for (u32 j = 1; j < bri_entries; j++)
|
||||||
|
bri_values[j] = j * 10;
|
||||||
|
|
||||||
|
ments[0].type = MENT_BACK;
|
||||||
|
ments[0].caption = "Back";
|
||||||
|
|
||||||
|
ments[1].type = MENT_CHGLINE;
|
||||||
|
|
||||||
|
u32 i = 0;
|
||||||
|
for (i = 1; i < bri_entries; i++)
|
||||||
|
{
|
||||||
|
if ((h_cfg.backlight / 20) != i)
|
||||||
|
bri_text[i * bri_text_size] = ' ';
|
||||||
|
else
|
||||||
|
bri_text[i * bri_text_size] = '*';
|
||||||
|
|
||||||
|
if (i < 10)
|
||||||
|
{
|
||||||
|
bri_text[i * bri_text_size + 1] = i + '0';
|
||||||
|
strcpy(bri_text + i * bri_text_size + 2, "0%");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
strcpy(bri_text + i * bri_text_size + 1, "100%");
|
||||||
|
|
||||||
|
ments[i + 1].type = MENT_DATA;
|
||||||
|
ments[i + 1].caption = bri_text + (i * bri_text_size);
|
||||||
|
ments[i + 1].data = &bri_values[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(&ments[i + 1], 0, sizeof(ment_t));
|
||||||
|
menu_t menu = {ments, "Backlight brightness", 0, 0};
|
||||||
|
|
||||||
|
u32 *temp_backlight = (u32 *)tui_do_menu(&menu);
|
||||||
|
if (temp_backlight != NULL)
|
||||||
|
{
|
||||||
|
h_cfg.backlight = (*(u32 *)temp_backlight) * 2;
|
||||||
|
_save_config();
|
||||||
|
}
|
||||||
|
|
||||||
|
free(ments);
|
||||||
|
free(bri_values);
|
||||||
|
free(bri_text);
|
||||||
|
|
||||||
|
if (temp_backlight == NULL)
|
||||||
|
return;
|
||||||
|
btn_wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
void config_auto_hos_poweroff()
|
||||||
|
{
|
||||||
|
gfx_clear_grey(0x1B);
|
||||||
|
gfx_con_setpos(0, 0);
|
||||||
|
|
||||||
|
ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * 6);
|
||||||
|
u32 *hp_values = (u32 *)malloc(sizeof(u32) * 3);
|
||||||
|
|
||||||
|
for (u32 j = 0; j < 3; j++)
|
||||||
|
{
|
||||||
|
hp_values[j] = j;
|
||||||
|
ments[j + 2].type = MENT_DATA;
|
||||||
|
ments[j + 2].data = &hp_values[j];
|
||||||
|
}
|
||||||
|
|
||||||
|
ments[0].type = MENT_BACK;
|
||||||
|
ments[0].caption = "Back";
|
||||||
|
|
||||||
|
ments[1].type = MENT_CHGLINE;
|
||||||
|
|
||||||
|
if (h_cfg.autohosoff == 1)
|
||||||
|
{
|
||||||
|
ments[2].caption = " Disable";
|
||||||
|
ments[3].caption = "*Enable";
|
||||||
|
ments[4].caption = " Enable (No logo)";
|
||||||
|
}
|
||||||
|
else if (h_cfg.autohosoff >= 2)
|
||||||
|
{
|
||||||
|
ments[2].caption = " Disable";
|
||||||
|
ments[3].caption = " Enable";
|
||||||
|
ments[4].caption = "*Enable (No logo)";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ments[2].caption = "*Disable";
|
||||||
|
ments[3].caption = " Enable";
|
||||||
|
ments[4].caption = " Enable (No logo)";
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(&ments[5], 0, sizeof(ment_t));
|
||||||
|
menu_t menu = {ments, "Power off if woke up from HOS", 0, 0};
|
||||||
|
|
||||||
|
u32 *temp_autohosoff = (u32 *)tui_do_menu(&menu);
|
||||||
|
if (temp_autohosoff != NULL)
|
||||||
|
{
|
||||||
|
h_cfg.autohosoff = *(u32 *)temp_autohosoff;
|
||||||
|
_save_config();
|
||||||
|
}
|
||||||
|
|
||||||
|
free(ments);
|
||||||
|
free(hp_values);
|
||||||
|
|
||||||
|
if (temp_autohosoff == NULL)
|
||||||
|
return;
|
||||||
|
btn_wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
void config_nogc()
|
||||||
|
{
|
||||||
|
gfx_clear_grey(0x1B);
|
||||||
|
gfx_con_setpos(0, 0);
|
||||||
|
|
||||||
|
ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * 5);
|
||||||
|
u32 *cb_values = (u32 *)malloc(sizeof(u32) * 2);
|
||||||
|
|
||||||
|
for (u32 j = 0; j < 2; j++)
|
||||||
|
{
|
||||||
|
cb_values[j] = j;
|
||||||
|
ments[j + 2].type = MENT_DATA;
|
||||||
|
ments[j + 2].data = &cb_values[j];
|
||||||
|
}
|
||||||
|
|
||||||
|
ments[0].type = MENT_BACK;
|
||||||
|
ments[0].caption = "Back";
|
||||||
|
|
||||||
|
ments[1].type = MENT_CHGLINE;
|
||||||
|
|
||||||
|
if (h_cfg.autonogc)
|
||||||
|
{
|
||||||
|
ments[2].caption = " Disable";
|
||||||
|
ments[3].caption = "*Auto";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ments[2].caption = "*Disable";
|
||||||
|
ments[3].caption = " Auto";
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(&ments[4], 0, sizeof(ment_t));
|
||||||
|
menu_t menu = {ments, "No Gamecard", 0, 0};
|
||||||
|
|
||||||
|
u32 *temp_nogc = (u32 *)tui_do_menu(&menu);
|
||||||
|
if (temp_nogc != NULL)
|
||||||
|
{
|
||||||
|
h_cfg.autonogc = *(u32 *)temp_nogc;
|
||||||
|
_save_config();
|
||||||
|
}
|
||||||
|
|
||||||
|
free(ments);
|
||||||
|
free(cb_values);
|
||||||
|
|
||||||
|
if (temp_nogc == NULL)
|
||||||
|
return;
|
||||||
|
btn_wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma GCC pop_options
|
||||||
53
source/config/config.h
Normal file
53
source/config/config.h
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2019 CTCaer
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _CONFIG_H_
|
||||||
|
#define _CONFIG_H_
|
||||||
|
|
||||||
|
#include "../hos/hos.h"
|
||||||
|
#include "../utils/types.h"
|
||||||
|
|
||||||
|
typedef struct _hekate_config
|
||||||
|
{
|
||||||
|
// Non-volatile config.
|
||||||
|
u32 autoboot;
|
||||||
|
u32 autoboot_list;
|
||||||
|
u32 bootwait;
|
||||||
|
u32 backlight;
|
||||||
|
u32 autohosoff;
|
||||||
|
u32 autonogc;
|
||||||
|
u32 updater2p;
|
||||||
|
char *brand;
|
||||||
|
char *tagline;
|
||||||
|
// Global temporary config.
|
||||||
|
bool se_keygen_done;
|
||||||
|
bool sept_run;
|
||||||
|
bool emummc_force_disable;
|
||||||
|
bool rcm_patched;
|
||||||
|
u32 sbar_time_keeping;
|
||||||
|
u32 errors;
|
||||||
|
hos_eks_mbr_t *eks;
|
||||||
|
} hekate_config;
|
||||||
|
|
||||||
|
void set_default_configuration();
|
||||||
|
int create_config_entry();
|
||||||
|
void config_autoboot();
|
||||||
|
void config_bootdelay();
|
||||||
|
void config_backlight();
|
||||||
|
void config_auto_hos_poweroff();
|
||||||
|
void config_nogc();
|
||||||
|
|
||||||
|
#endif /* _CONFIG_H_ */
|
||||||
189
source/config/ini.c
Normal file
189
source/config/ini.c
Normal file
@@ -0,0 +1,189 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2018 naehrwert
|
||||||
|
* Copyright (c) 2018-2020 CTCaer
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "ini.h"
|
||||||
|
#include "../libs/fatfs/ff.h"
|
||||||
|
#include "../mem/heap.h"
|
||||||
|
#include "../utils/dirlist.h"
|
||||||
|
|
||||||
|
static char *_strdup(char *str)
|
||||||
|
{
|
||||||
|
if (!str)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
// Remove starting space.
|
||||||
|
if (str[0] == ' ' && strlen(str))
|
||||||
|
str++;
|
||||||
|
|
||||||
|
char *res = (char *)malloc(strlen(str) + 1);
|
||||||
|
strcpy(res, str);
|
||||||
|
|
||||||
|
// Remove trailing space.
|
||||||
|
if (strlen(res) && res[strlen(res) - 1] == ' ')
|
||||||
|
res[strlen(res) - 1] = 0;
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 _find_section_name(char *lbuf, u32 lblen, char schar)
|
||||||
|
{
|
||||||
|
u32 i;
|
||||||
|
// Depends on 'FF_USE_STRFUNC 2' that removes \r.
|
||||||
|
for (i = 0; i < lblen && lbuf[i] != schar && lbuf[i] != '\n'; i++)
|
||||||
|
;
|
||||||
|
lbuf[i] = 0;
|
||||||
|
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
ini_sec_t *_ini_create_section(link_t *dst, ini_sec_t *csec, char *name, u8 type)
|
||||||
|
{
|
||||||
|
if (csec)
|
||||||
|
list_append(dst, &csec->link);
|
||||||
|
|
||||||
|
csec = (ini_sec_t *)calloc(sizeof(ini_sec_t), 1);
|
||||||
|
csec->name = _strdup(name);
|
||||||
|
csec->type = type;
|
||||||
|
|
||||||
|
return csec;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ini_parse(link_t *dst, char *ini_path, bool is_dir)
|
||||||
|
{
|
||||||
|
u32 lblen;
|
||||||
|
u32 pathlen = strlen(ini_path);
|
||||||
|
u32 k = 0;
|
||||||
|
char lbuf[512];
|
||||||
|
char *filelist = NULL;
|
||||||
|
FIL fp;
|
||||||
|
ini_sec_t *csec = NULL;
|
||||||
|
|
||||||
|
char *filename = (char *)malloc(256);
|
||||||
|
|
||||||
|
strcpy(filename, ini_path);
|
||||||
|
|
||||||
|
// Get all ini filenames.
|
||||||
|
if (is_dir)
|
||||||
|
{
|
||||||
|
filelist = dirlist(filename, "*.ini", false);
|
||||||
|
if (!filelist)
|
||||||
|
{
|
||||||
|
free(filename);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
strcpy(filename + pathlen, "/");
|
||||||
|
pathlen++;
|
||||||
|
}
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
// Copy ini filename in path string.
|
||||||
|
if (is_dir)
|
||||||
|
{
|
||||||
|
if (filelist[k * 256])
|
||||||
|
{
|
||||||
|
strcpy(filename + pathlen, &filelist[k * 256]);
|
||||||
|
k++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open ini.
|
||||||
|
if (f_open(&fp, filename, FA_READ) != FR_OK)
|
||||||
|
{
|
||||||
|
free(filelist);
|
||||||
|
free(filename);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
// Fetch one line.
|
||||||
|
lbuf[0] = 0;
|
||||||
|
f_gets(lbuf, 512, &fp);
|
||||||
|
lblen = strlen(lbuf);
|
||||||
|
|
||||||
|
// Remove trailing newline. Depends on 'FF_USE_STRFUNC 2' that removes \r.
|
||||||
|
if (lblen && lbuf[lblen - 1] == '\n')
|
||||||
|
lbuf[lblen - 1] = 0;
|
||||||
|
|
||||||
|
if (lblen > 2 && lbuf[0] == '[') // Create new section.
|
||||||
|
{
|
||||||
|
_find_section_name(lbuf, lblen, ']');
|
||||||
|
|
||||||
|
csec = _ini_create_section(dst, csec, &lbuf[1], INI_CHOICE);
|
||||||
|
list_init(&csec->kvs);
|
||||||
|
}
|
||||||
|
else if (lblen > 1 && lbuf[0] == '{') // Create new caption. Support empty caption '{}'.
|
||||||
|
{
|
||||||
|
_find_section_name(lbuf, lblen, '}');
|
||||||
|
|
||||||
|
csec = _ini_create_section(dst, csec, &lbuf[1], INI_CAPTION);
|
||||||
|
csec->color = 0xFF0AB9E6;
|
||||||
|
}
|
||||||
|
else if (lblen > 2 && lbuf[0] == '#') // Create comment.
|
||||||
|
{
|
||||||
|
csec = _ini_create_section(dst, csec, &lbuf[1], INI_COMMENT);
|
||||||
|
}
|
||||||
|
else if (lblen < 2) // Create empty line.
|
||||||
|
{
|
||||||
|
csec = _ini_create_section(dst, csec, NULL, INI_NEWLINE);
|
||||||
|
}
|
||||||
|
else if (csec && csec->type == INI_CHOICE) // Extract key/value.
|
||||||
|
{
|
||||||
|
u32 i = _find_section_name(lbuf, lblen, '=');
|
||||||
|
|
||||||
|
ini_kv_t *kv = (ini_kv_t *)calloc(sizeof(ini_kv_t), 1);
|
||||||
|
kv->key = _strdup(&lbuf[0]);
|
||||||
|
kv->val = _strdup(&lbuf[i + 1]);
|
||||||
|
list_append(&csec->kvs, &kv->link);
|
||||||
|
}
|
||||||
|
} while (!f_eof(&fp));
|
||||||
|
|
||||||
|
f_close(&fp);
|
||||||
|
|
||||||
|
if (csec)
|
||||||
|
{
|
||||||
|
list_append(dst, &csec->link);
|
||||||
|
if (is_dir)
|
||||||
|
csec = NULL;
|
||||||
|
}
|
||||||
|
} while (is_dir);
|
||||||
|
|
||||||
|
free(filename);
|
||||||
|
free(filelist);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *ini_check_payload_section(ini_sec_t *cfg)
|
||||||
|
{
|
||||||
|
if (cfg == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
LIST_FOREACH_ENTRY(ini_kv_t, kv, &cfg->kvs, link)
|
||||||
|
{
|
||||||
|
if (!strcmp("payload", kv->key))
|
||||||
|
return kv->val;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
50
source/config/ini.h
Normal file
50
source/config/ini.h
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2018 naehrwert
|
||||||
|
* Copyright (c) 2018 CTCaer
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _INI_H_
|
||||||
|
#define _INI_H_
|
||||||
|
|
||||||
|
#include "../utils/types.h"
|
||||||
|
#include "../utils/list.h"
|
||||||
|
|
||||||
|
#define INI_CHOICE 3
|
||||||
|
#define INI_CAPTION 5
|
||||||
|
#define INI_CHGLINE 6
|
||||||
|
#define INI_NEWLINE 0xFE
|
||||||
|
#define INI_COMMENT 0xFF
|
||||||
|
|
||||||
|
typedef struct _ini_kv_t
|
||||||
|
{
|
||||||
|
char *key;
|
||||||
|
char *val;
|
||||||
|
link_t link;
|
||||||
|
} ini_kv_t;
|
||||||
|
|
||||||
|
typedef struct _ini_sec_t
|
||||||
|
{
|
||||||
|
char *name;
|
||||||
|
link_t kvs;
|
||||||
|
link_t link;
|
||||||
|
u32 type;
|
||||||
|
u32 color;
|
||||||
|
} ini_sec_t;
|
||||||
|
|
||||||
|
int ini_parse(link_t *dst, char *ini_path, bool is_dir);
|
||||||
|
char *ini_check_payload_section(ini_sec_t *cfg);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
233
source/exception_handlers.S
Normal file
233
source/exception_handlers.S
Normal file
@@ -0,0 +1,233 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019 CTCaer
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Armv7tdmi Status register.
|
||||||
|
*
|
||||||
|
* bit0: Mode 0.
|
||||||
|
* bit1: Mode 1.
|
||||||
|
* bit2: Mode 2.
|
||||||
|
* bit3: Mode 3.
|
||||||
|
* bit4: Mode 4.
|
||||||
|
* bit5: Thumb state.
|
||||||
|
* bit6: FIQ disable.
|
||||||
|
* bit7: IRQ disable.
|
||||||
|
* bit8-27: Reserved.
|
||||||
|
* bit28: Overflow condition.
|
||||||
|
* bit29: Carry/Borrow/Extend condition.
|
||||||
|
* bit30: Zero condition.
|
||||||
|
* bit31: Negative/Less than condition.
|
||||||
|
*
|
||||||
|
* M[4:0] | Mode | Visible Thumb-state registers | Visible ARM-state registers
|
||||||
|
* 10000 | USER | r0–r7, SP, LR, PC, CPSR | r0–r14, PC, CPSR
|
||||||
|
* 10001 | FIQ | r0–r7, SP_fiq, LR_fiq, PC, CPSR, SPSR_fiq | r0–r7, r8_fiq–r14_fiq, PC, CPSR, SPSR_fiq
|
||||||
|
* 10010 | IRQ | r0–r7, SP_irq, LR_irq, PC, CPSR, SPSR_irq | r0–r12, r13_irq, r14_irq, PC, CPSR, SPSR_irq
|
||||||
|
* 10011 | SVC | r0–r7, SP_svc, LR_svc, PC, CPSR, SPSR_svc | r0–r12, r13_svc, r14_svc, PC, CPSR, SPSR_svc
|
||||||
|
* 10111 | ABRT | r0–r7, SP_abt, LR_abt, PC, CPSR, SPSR_abt | r0–r12, r13_abt, r14_abt, PC, CPSR, SPSR_abt
|
||||||
|
* 11011 | UNDF | r0–r7, SP_und, LR_und, PC, CPSR, SPSR_und | r0–r12, r13_und, r14_und, PC, CPSR, SPSR_und
|
||||||
|
* 11111 | SYS | r0–r7, SP, LR, PC, CPSR | r0–r14, PC, CPSR
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define EXCP_EN_ADDR 0x4003FFFC
|
||||||
|
#define EXCP_TYPE_ADDR 0x4003FFF8
|
||||||
|
#define EXCP_LR_ADDR 0x4003FFF4
|
||||||
|
|
||||||
|
#define EXCP_VEC_BASE 0x6000F000
|
||||||
|
#define EVP_COP_RESET_VECTOR 0x200
|
||||||
|
#define EVP_COP_UNDEF_VECTOR 0x204
|
||||||
|
#define EVP_COP_SWI_VECTOR 0x208
|
||||||
|
#define EVP_COP_PREFETCH_ABORT_VECTOR 0x20C
|
||||||
|
#define EVP_COP_DATA_ABORT_VECTOR 0x210
|
||||||
|
#define EVP_COP_RSVD_VECTOR 0x214
|
||||||
|
#define EVP_COP_IRQ_VECTOR 0x218
|
||||||
|
#define EVP_COP_FIQ_VECTOR 0x21C
|
||||||
|
|
||||||
|
#define MODE_USR 0x10
|
||||||
|
#define MODE_FIQ 0x11
|
||||||
|
#define MODE_IRQ 0x12
|
||||||
|
#define MODE_SVC 0x13
|
||||||
|
#define MODE_ABT 0x17
|
||||||
|
#define MODE_UDF 0x1B
|
||||||
|
#define MODE_SYS 0x1F
|
||||||
|
#define MODE_MASK 0x1F
|
||||||
|
|
||||||
|
#define FIQ 0x40
|
||||||
|
#define IRQ 0x80
|
||||||
|
|
||||||
|
.section .text._irq_setup
|
||||||
|
.arm
|
||||||
|
|
||||||
|
.extern ipl_main
|
||||||
|
.type ipl_main, %function
|
||||||
|
|
||||||
|
.extern svc_handler
|
||||||
|
.type svc_handler, %function
|
||||||
|
|
||||||
|
.extern irq_handler
|
||||||
|
.type irq_handler, %function
|
||||||
|
|
||||||
|
.extern fiq_setup
|
||||||
|
.type fiq_setup, %function
|
||||||
|
|
||||||
|
.extern fiq_handler
|
||||||
|
.type fiq_handler, %function
|
||||||
|
|
||||||
|
.globl _irq_setup
|
||||||
|
.type _irq_setup, %function
|
||||||
|
_irq_setup:
|
||||||
|
MRS R0, CPSR
|
||||||
|
BIC R0, R0, #MODE_MASK /* Clear mode bits */
|
||||||
|
ORR R0, R0, #(MODE_SVC | IRQ | FIQ) /* SUPERVISOR mode, IRQ/FIQ disabled */
|
||||||
|
MSR CPSR, R0
|
||||||
|
|
||||||
|
/* Setup IRQ stack pointer */
|
||||||
|
MSR CPSR, #(MODE_IRQ | IRQ | FIQ) /* IRQ mode, IRQ/FIQ disabled */
|
||||||
|
LDR SP, =0x40040000
|
||||||
|
|
||||||
|
/* Setup SYS stack pointer */
|
||||||
|
MSR CPSR, #(MODE_SYS | IRQ | FIQ) /* SYSTEM mode, IRQ/FIQ disabled */
|
||||||
|
LDR SP, =0x4003FF00 /* Will be changed later to DRAM */
|
||||||
|
|
||||||
|
MOV LR, PC
|
||||||
|
BL setup_vectors
|
||||||
|
/*BL fiq_setup*/
|
||||||
|
|
||||||
|
/* Enable interrupts */
|
||||||
|
BL irq_enable_cpu_irq_exceptions
|
||||||
|
|
||||||
|
B ipl_main
|
||||||
|
B .
|
||||||
|
|
||||||
|
_reset:
|
||||||
|
LDR R0, =EXCP_EN_ADDR
|
||||||
|
LDR R1, =0x30505645 /* EVP0 */
|
||||||
|
STR R1, [R0] /* EVP0 in EXCP_EN_ADDR */
|
||||||
|
LDR R0, =EXCP_LR_ADDR
|
||||||
|
MOV R1, LR
|
||||||
|
STR R1, [R0] /* Save LR in EXCP_LR_ADDR */
|
||||||
|
LDR R0, =__bss_start
|
||||||
|
EOR R1, R1, R1
|
||||||
|
LDR R2, =__bss_end
|
||||||
|
SUB R2, R2, R0
|
||||||
|
BL memset
|
||||||
|
B _irq_setup
|
||||||
|
|
||||||
|
_reset_handler:
|
||||||
|
LDR R0, =EXCP_TYPE_ADDR
|
||||||
|
LDR R1, =0x545352 /* RST */
|
||||||
|
STR R1, [R0] /* RST in EXCP_TYPE_ADDR */
|
||||||
|
B _reset
|
||||||
|
|
||||||
|
_undefined_handler:
|
||||||
|
LDR R0, =EXCP_TYPE_ADDR
|
||||||
|
LDR R1, =0x464455 /* UDF */
|
||||||
|
STR R1, [R0] /* UDF in EXCP_TYPE_ADDR */
|
||||||
|
B _reset
|
||||||
|
|
||||||
|
_prefetch_abort_handler:
|
||||||
|
LDR R0, =EXCP_TYPE_ADDR
|
||||||
|
LDR R1, =0x54424150 /* PABT */
|
||||||
|
STR R1, [R0] /* PABT in EXCP_TYPE_ADDR */
|
||||||
|
B _reset
|
||||||
|
|
||||||
|
_data_abort_handler:
|
||||||
|
LDR R0, =EXCP_TYPE_ADDR
|
||||||
|
LDR R1, =0x54424144 /* DABT */
|
||||||
|
STR R1, [R0] /* DABT in EXCP_TYPE_ADDR */
|
||||||
|
B _reset
|
||||||
|
|
||||||
|
.globl irq_enable_cpu_irq_exceptions
|
||||||
|
.type irq_enable_cpu_irq_exceptions, %function
|
||||||
|
irq_enable_cpu_irq_exceptions:
|
||||||
|
MRS R12, CPSR
|
||||||
|
BIC R12, R12, #(IRQ | FIQ) /* IRQ/FIQ enabled */
|
||||||
|
MSR CPSR, R12
|
||||||
|
BX LR
|
||||||
|
|
||||||
|
.globl irq_disable_cpu_irq_exceptions
|
||||||
|
.type irq_disable_cpu_irq_exceptions, %function
|
||||||
|
irq_disable_cpu_irq_exceptions:
|
||||||
|
MRS R12, CPSR
|
||||||
|
ORR R12, R12, #(IRQ | FIQ) /* IRQ/FIQ disabled */
|
||||||
|
MSR CPSR, R12
|
||||||
|
BX LR
|
||||||
|
|
||||||
|
_irq_handler:
|
||||||
|
MOV R13, R0 /* Save R0 in R13_IRQ */
|
||||||
|
SUB R0, LR, #4 /* Put return address in R0_SYS */
|
||||||
|
MOV LR, R1 /* Save R1 in R14_IRQ (LR) */
|
||||||
|
MRS R1, SPSR /* Put the SPSR in R1_SYS */
|
||||||
|
|
||||||
|
MSR CPSR_c, #(MODE_SYS | IRQ) /* SYSTEM mode, IRQ disabled */
|
||||||
|
STMFD SP!, {R0, R1} /* SPSR and PC */
|
||||||
|
STMFD SP!, {R2-R3, R12, LR} /* AAPCS-clobbered registers */
|
||||||
|
MOV R0, SP /* Make SP_SYS visible to IRQ mode */
|
||||||
|
SUB SP, SP, #8 /* Make room for stacking R0 and R1 */
|
||||||
|
|
||||||
|
MSR CPSR_c, #(MODE_IRQ | IRQ) /* IRQ mode, IRQ disabled */
|
||||||
|
STMFD R0!, {R13, R14} /* Finish saving the context (R0, R1) */
|
||||||
|
|
||||||
|
MSR CPSR_c, #(MODE_SYS | IRQ) /* SYSTEM mode, IRQ disabled */
|
||||||
|
LDR R12, =irq_handler
|
||||||
|
MOV LR, PC /* Copy the return address to link register */
|
||||||
|
BX R12 /* Call the C IRQ handler (ARM/THUMB) */
|
||||||
|
|
||||||
|
MSR CPSR_c, #(MODE_SYS | IRQ | FIQ) /* SYSTEM mode, IRQ/FIQ disabled */
|
||||||
|
MOV R0, SP /* Make SP_SYS visible to IRQ mode */
|
||||||
|
ADD SP, SP, #32 /* Fake unstacking 8 registers from SP_SYS */
|
||||||
|
|
||||||
|
MSR CPSR_c, #(MODE_IRQ | IRQ | FIQ) /* IRQ mode, IRQ/FIQ disabled */
|
||||||
|
MOV SP, R0 /* Copy SP_SYS to SP_IRQ */
|
||||||
|
LDR R0, [SP, #28] /* Load the saved SPSR from the stack */
|
||||||
|
MSR SPSR_cxsf, R0 /* Copy it into SPSR_IRQ */
|
||||||
|
|
||||||
|
LDMFD SP, {R0-R3, R12, LR}^ /* Unstack all saved USER/SYSTEM registers */
|
||||||
|
NOP /* Cant access barked registers immediately */
|
||||||
|
LDR LR, [SP, #24] /* Load return address from the SYS stack */
|
||||||
|
MOVS PC, LR /* Return restoring CPSR from SPSR */
|
||||||
|
|
||||||
|
_fiq_handler:
|
||||||
|
BL fiq_handler
|
||||||
|
|
||||||
|
setup_vectors:
|
||||||
|
/* Setup vectors */
|
||||||
|
LDR R0, =EXCP_VEC_BASE
|
||||||
|
|
||||||
|
LDR R1, =_reset_handler
|
||||||
|
STR R1, [R0, #EVP_COP_RESET_VECTOR]
|
||||||
|
|
||||||
|
LDR R1, =_undefined_handler
|
||||||
|
STR R1, [R0, #EVP_COP_UNDEF_VECTOR]
|
||||||
|
|
||||||
|
LDR R1, =_reset_handler
|
||||||
|
STR R1, [R0, #EVP_COP_SWI_VECTOR]
|
||||||
|
|
||||||
|
LDR R1, =_prefetch_abort_handler
|
||||||
|
STR R1, [R0, #EVP_COP_PREFETCH_ABORT_VECTOR]
|
||||||
|
|
||||||
|
LDR R1, =_data_abort_handler
|
||||||
|
STR R1, [R0, #EVP_COP_DATA_ABORT_VECTOR]
|
||||||
|
|
||||||
|
LDR R1, =_reset_handler
|
||||||
|
STR R1, [R0, #EVP_COP_RSVD_VECTOR]
|
||||||
|
|
||||||
|
LDR R1, =_irq_handler
|
||||||
|
STR R1, [R0, #EVP_COP_IRQ_VECTOR]
|
||||||
|
|
||||||
|
LDR R1, =_fiq_handler
|
||||||
|
STR R1, [R0, #EVP_COP_FIQ_VECTOR]
|
||||||
|
|
||||||
|
BX LR
|
||||||
113
source/gfx/di.c
113
source/gfx/di.c
@@ -18,15 +18,16 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "di.h"
|
#include "di.h"
|
||||||
#include "../soc/t210.h"
|
#include "../gfx/gfx.h"
|
||||||
#include "../utils/util.h"
|
|
||||||
#include "../soc/i2c.h"
|
|
||||||
#include "../soc/pmc.h"
|
|
||||||
#include "../power/max77620.h"
|
#include "../power/max77620.h"
|
||||||
#include "../power/max7762x.h"
|
#include "../power/max7762x.h"
|
||||||
#include "../soc/gpio.h"
|
|
||||||
#include "../soc/pinmux.h"
|
|
||||||
#include "../soc/clock.h"
|
#include "../soc/clock.h"
|
||||||
|
#include "../soc/gpio.h"
|
||||||
|
#include "../soc/i2c.h"
|
||||||
|
#include "../soc/pinmux.h"
|
||||||
|
#include "../soc/pmc.h"
|
||||||
|
#include "../soc/t210.h"
|
||||||
|
#include "../utils/util.h"
|
||||||
|
|
||||||
#include "di.inl"
|
#include "di.inl"
|
||||||
|
|
||||||
@@ -46,54 +47,61 @@ void display_init()
|
|||||||
max77620_regulator_set_volt_and_flags(REGULATOR_LDO0, 1200000, MAX77620_POWER_MODE_NORMAL); // Configure to 1.2V.
|
max77620_regulator_set_volt_and_flags(REGULATOR_LDO0, 1200000, MAX77620_POWER_MODE_NORMAL); // Configure to 1.2V.
|
||||||
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_GPIO7, MAX77620_CNFG_GPIO_OUTPUT_VAL_HIGH | MAX77620_CNFG_GPIO_DRV_PUSHPULL);
|
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_GPIO7, MAX77620_CNFG_GPIO_OUTPUT_VAL_HIGH | MAX77620_CNFG_GPIO_DRV_PUSHPULL);
|
||||||
|
|
||||||
// Enable MIPI CAL, DSI, DISP1, HOST1X, UART_FST_MIPI_CAL, DSIA LP clocks.
|
// Enable Display Interface specific clocks.
|
||||||
CLOCK(CLK_RST_CONTROLLER_RST_DEV_H_CLR) = 0x1010000;
|
CLOCK(CLK_RST_CONTROLLER_RST_DEV_H_CLR) = 0x1010000; // Clear reset DSI, MIPI_CAL.
|
||||||
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) = 0x1010000;
|
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) = 0x1010000; // Set enable clock DSI, MIPI_CAL.
|
||||||
CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_CLR) = 0x18000000;
|
|
||||||
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_SET) = 0x18000000;
|
|
||||||
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_X_SET) = 0x20000;
|
|
||||||
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_UART_FST_MIP_CAL) = 0xA;
|
|
||||||
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_W_SET) = 0x80000;
|
|
||||||
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_DSIA_LP) = 0xA;
|
|
||||||
|
|
||||||
// DPD idle.
|
CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_CLR) = 0x18000000; // Clear reset DISP1, HOST1X.
|
||||||
|
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_SET) = 0x18000000; // Set enable clock DISP1, HOST1X.
|
||||||
|
|
||||||
|
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_X_SET) = 0x20000; // Set enable clock UART_FST_MIPI_CAL.
|
||||||
|
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_UART_FST_MIPI_CAL) = 10; // Set PLLP_OUT3 and div 6 (17MHz).
|
||||||
|
|
||||||
|
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_W_SET) = 0x80000; // Set enable clock DSIA_LP.
|
||||||
|
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_DSIA_LP) = 10; // Set PLLP_OUT and div 6 (68MHz).
|
||||||
|
|
||||||
|
// Disable deap power down.
|
||||||
PMC(APBDEV_PMC_IO_DPD_REQ) = 0x40000000;
|
PMC(APBDEV_PMC_IO_DPD_REQ) = 0x40000000;
|
||||||
PMC(APBDEV_PMC_IO_DPD2_REQ) = 0x40000000;
|
PMC(APBDEV_PMC_IO_DPD2_REQ) = 0x40000000;
|
||||||
|
|
||||||
// Config pins.
|
// Config LCD and Backlight pins.
|
||||||
PINMUX_AUX(PINMUX_AUX_NFC_EN) &= ~PINMUX_TRISTATE;
|
PINMUX_AUX(PINMUX_AUX_NFC_EN) &= ~PINMUX_TRISTATE;
|
||||||
PINMUX_AUX(PINMUX_AUX_NFC_INT) &= ~PINMUX_TRISTATE;
|
PINMUX_AUX(PINMUX_AUX_NFC_INT) &= ~PINMUX_TRISTATE;
|
||||||
PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) &= ~PINMUX_TRISTATE;
|
PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) &= ~PINMUX_TRISTATE;
|
||||||
PINMUX_AUX(PINMUX_AUX_LCD_BL_EN) &= ~PINMUX_TRISTATE;
|
PINMUX_AUX(PINMUX_AUX_LCD_BL_EN) &= ~PINMUX_TRISTATE;
|
||||||
PINMUX_AUX(PINMUX_AUX_LCD_RST) &= ~PINMUX_TRISTATE;
|
PINMUX_AUX(PINMUX_AUX_LCD_RST) &= ~PINMUX_TRISTATE;
|
||||||
|
|
||||||
gpio_config(GPIO_PORT_I, GPIO_PIN_0 | GPIO_PIN_1, GPIO_MODE_GPIO); // Backlight +-5V.
|
// Set Backlight +-5V pins mode and direction
|
||||||
gpio_output_enable(GPIO_PORT_I, GPIO_PIN_0 | GPIO_PIN_1, GPIO_OUTPUT_ENABLE); // Backlight +-5V.
|
gpio_config(GPIO_PORT_I, GPIO_PIN_0 | GPIO_PIN_1, GPIO_MODE_GPIO);
|
||||||
|
gpio_output_enable(GPIO_PORT_I, GPIO_PIN_0 | GPIO_PIN_1, GPIO_OUTPUT_ENABLE);
|
||||||
|
|
||||||
|
// Enable Backlight power.
|
||||||
gpio_write(GPIO_PORT_I, GPIO_PIN_0, GPIO_HIGH); // Backlight +5V enable.
|
gpio_write(GPIO_PORT_I, GPIO_PIN_0, GPIO_HIGH); // Backlight +5V enable.
|
||||||
|
|
||||||
usleep(10000);
|
usleep(10000);
|
||||||
|
|
||||||
gpio_write(GPIO_PORT_I, GPIO_PIN_1, GPIO_HIGH); // Backlight -5V enable.
|
gpio_write(GPIO_PORT_I, GPIO_PIN_1, GPIO_HIGH); // Backlight -5V enable.
|
||||||
|
|
||||||
usleep(10000);
|
usleep(10000);
|
||||||
|
|
||||||
gpio_config(GPIO_PORT_V, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2, GPIO_MODE_GPIO); // Backlight PWM, Enable, Reset.
|
// Configure Backlight pins (PWM, EN, RST).
|
||||||
|
gpio_config(GPIO_PORT_V, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2, GPIO_MODE_GPIO);
|
||||||
gpio_output_enable(GPIO_PORT_V, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2, GPIO_OUTPUT_ENABLE);
|
gpio_output_enable(GPIO_PORT_V, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2, GPIO_OUTPUT_ENABLE);
|
||||||
gpio_write(GPIO_PORT_V, GPIO_PIN_1, GPIO_HIGH); // Backlight Enable enable.
|
gpio_write(GPIO_PORT_V, GPIO_PIN_1, GPIO_HIGH); // Enable Backlight EN.
|
||||||
|
|
||||||
// Config display interface and display.
|
// Power up supply regulator for display interface.
|
||||||
MIPI_CAL(MIPI_CAL_MIPI_BIAS_PAD_CFG2) = 0;
|
MIPI_CAL(MIPI_CAL_MIPI_BIAS_PAD_CFG2) = 0;
|
||||||
|
|
||||||
|
// Set DISP1 clock source and parrent clock.
|
||||||
exec_cfg((u32 *)CLOCK_BASE, _display_config_1, 4);
|
exec_cfg((u32 *)CLOCK_BASE, _display_config_1, 4);
|
||||||
|
|
||||||
|
// Setup display communication interfaces.
|
||||||
exec_cfg((u32 *)DISPLAY_A_BASE, _display_config_2, 94);
|
exec_cfg((u32 *)DISPLAY_A_BASE, _display_config_2, 94);
|
||||||
exec_cfg((u32 *)DSI_BASE, _display_config_3, 61);
|
exec_cfg((u32 *)DSI_BASE, _display_config_3, 61);
|
||||||
|
|
||||||
usleep(10000);
|
usleep(10000);
|
||||||
|
|
||||||
gpio_write(GPIO_PORT_V, GPIO_PIN_2, GPIO_HIGH); // Backlight Reset enable.
|
// Enable Backlight Reset.
|
||||||
|
gpio_write(GPIO_PORT_V, GPIO_PIN_2, GPIO_HIGH);
|
||||||
usleep(60000);
|
usleep(60000);
|
||||||
|
|
||||||
|
// Setups DSI packet configuration and request display id.
|
||||||
DSI(_DSIREG(DSI_BTA_TIMING)) = 0x50204;
|
DSI(_DSIREG(DSI_BTA_TIMING)) = 0x50204;
|
||||||
DSI(_DSIREG(DSI_WR_DATA)) = 0x337; // MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE
|
DSI(_DSIREG(DSI_WR_DATA)) = 0x337; // MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE
|
||||||
DSI(_DSIREG(DSI_TRIGGER)) = DSI_TRIGGER_HOST;
|
DSI(_DSIREG(DSI_TRIGGER)) = DSI_TRIGGER_HOST;
|
||||||
@@ -122,19 +130,22 @@ void display_init()
|
|||||||
|
|
||||||
usleep(20000);
|
usleep(20000);
|
||||||
|
|
||||||
|
// Configure PLLD for DISP1.
|
||||||
exec_cfg((u32 *)CLOCK_BASE, _display_config_6, 3);
|
exec_cfg((u32 *)CLOCK_BASE, _display_config_6, 3);
|
||||||
|
|
||||||
|
// Finalize DSI configuration.
|
||||||
exec_cfg((u32 *)DSI_BASE, _display_config_5, 21);
|
exec_cfg((u32 *)DSI_BASE, _display_config_5, 21);
|
||||||
DISPLAY_A(_DIREG(DC_DISP_DISP_CLOCK_CONTROL)) = 4;
|
DISPLAY_A(_DIREG(DC_DISP_DISP_CLOCK_CONTROL)) = 4;
|
||||||
exec_cfg((u32 *)DSI_BASE, _display_config_7, 10);
|
exec_cfg((u32 *)DSI_BASE, _display_config_7, 10);
|
||||||
|
|
||||||
usleep(10000);
|
usleep(10000);
|
||||||
|
|
||||||
|
// Calibrate display communication pads.
|
||||||
exec_cfg((u32 *)MIPI_CAL_BASE, _display_config_8, 6);
|
exec_cfg((u32 *)MIPI_CAL_BASE, _display_config_8, 6);
|
||||||
exec_cfg((u32 *)DSI_BASE, _display_config_9, 4);
|
exec_cfg((u32 *)DSI_BASE, _display_config_9, 4);
|
||||||
exec_cfg((u32 *)MIPI_CAL_BASE, _display_config_10, 16);
|
exec_cfg((u32 *)MIPI_CAL_BASE, _display_config_10, 16);
|
||||||
|
|
||||||
usleep(10000);
|
usleep(10000);
|
||||||
|
|
||||||
|
// Enable video display controller.
|
||||||
exec_cfg((u32 *)DISPLAY_A_BASE, _display_config_11, 113);
|
exec_cfg((u32 *)DISPLAY_A_BASE, _display_config_11, 113);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -142,11 +153,10 @@ void display_backlight_pwm_init()
|
|||||||
{
|
{
|
||||||
clock_enable_pwm();
|
clock_enable_pwm();
|
||||||
|
|
||||||
PWM(PWM_CONTROLLER_PWM_CSR_0) = (1 << 31); // Enable PWM
|
PWM(PWM_CONTROLLER_PWM_CSR_0) = PWM_CSR_EN; // Enable PWM and set it to 25KHz PFM.
|
||||||
|
|
||||||
PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) = (PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) >> 2) << 2 | 1; // PWM clock source.
|
PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) = (PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) & 0xFFFFFFFC) | 1; // PWM clock source.
|
||||||
gpio_config(GPIO_PORT_V, GPIO_PIN_0, GPIO_MODE_SPIO); // Backlight power mode.
|
gpio_config(GPIO_PORT_V, GPIO_PIN_0, GPIO_MODE_SPIO); // Backlight power mode.
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void display_backlight(bool enable)
|
void display_backlight(bool enable)
|
||||||
@@ -167,7 +177,7 @@ void display_backlight_brightness(u32 brightness, u32 step_delay)
|
|||||||
{
|
{
|
||||||
for (u32 i = old_value; i < brightness + 1; i++)
|
for (u32 i = old_value; i < brightness + 1; i++)
|
||||||
{
|
{
|
||||||
PWM(PWM_CONTROLLER_PWM_CSR_0) = (1 << 31) | (i << 16); // Enable PWM
|
PWM(PWM_CONTROLLER_PWM_CSR_0) = PWM_CSR_EN | (i << 16); // Enable PWM and set it to 25KHz PFM.
|
||||||
usleep(step_delay);
|
usleep(step_delay);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -175,7 +185,7 @@ void display_backlight_brightness(u32 brightness, u32 step_delay)
|
|||||||
{
|
{
|
||||||
for (u32 i = old_value; i > brightness; i--)
|
for (u32 i = old_value; i > brightness; i--)
|
||||||
{
|
{
|
||||||
PWM(PWM_CONTROLLER_PWM_CSR_0) = (1 << 31) | (i << 16); // Enable PWM
|
PWM(PWM_CONTROLLER_PWM_CSR_0) = PWM_CSR_EN | (i << 16); // Enable PWM and set it to 25KHz PFM.
|
||||||
usleep(step_delay);
|
usleep(step_delay);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -191,13 +201,14 @@ void display_end()
|
|||||||
DSI(_DSIREG(DSI_WR_DATA)) = 0x2805; // MIPI_DCS_SET_DISPLAY_OFF
|
DSI(_DSIREG(DSI_WR_DATA)) = 0x2805; // MIPI_DCS_SET_DISPLAY_OFF
|
||||||
|
|
||||||
DISPLAY_A(_DIREG(DC_CMD_STATE_ACCESS)) = READ_MUX | WRITE_MUX;
|
DISPLAY_A(_DIREG(DC_CMD_STATE_ACCESS)) = READ_MUX | WRITE_MUX;
|
||||||
DSI(_DSIREG(DSI_VIDEO_MODE_CONTROL)) = 0;
|
DSI(_DSIREG(DSI_VIDEO_MODE_CONTROL)) = 0; // Disable host cmd packet.
|
||||||
|
|
||||||
|
// De-initialize video controller.
|
||||||
exec_cfg((u32 *)DISPLAY_A_BASE, _display_config_12, 17);
|
exec_cfg((u32 *)DISPLAY_A_BASE, _display_config_12, 17);
|
||||||
exec_cfg((u32 *)DSI_BASE, _display_config_13, 16);
|
exec_cfg((u32 *)DSI_BASE, _display_config_13, 16);
|
||||||
|
|
||||||
usleep(10000);
|
usleep(10000);
|
||||||
|
|
||||||
|
// De-initialize display panel.
|
||||||
if (_display_ver == 0x10)
|
if (_display_ver == 0x10)
|
||||||
exec_cfg((u32 *)DSI_BASE, _display_config_14, 22);
|
exec_cfg((u32 *)DSI_BASE, _display_config_14, 22);
|
||||||
|
|
||||||
@@ -206,31 +217,31 @@ void display_end()
|
|||||||
|
|
||||||
usleep(50000);
|
usleep(50000);
|
||||||
|
|
||||||
|
// Disable display and backlight pins.
|
||||||
gpio_write(GPIO_PORT_V, GPIO_PIN_2, GPIO_LOW); //Backlight Reset disable.
|
gpio_write(GPIO_PORT_V, GPIO_PIN_2, GPIO_LOW); //Backlight Reset disable.
|
||||||
|
|
||||||
usleep(10000);
|
usleep(10000);
|
||||||
|
|
||||||
gpio_write(GPIO_PORT_I, GPIO_PIN_1, GPIO_LOW); //Backlight -5V disable.
|
gpio_write(GPIO_PORT_I, GPIO_PIN_1, GPIO_LOW); //Backlight -5V disable.
|
||||||
|
|
||||||
usleep(10000);
|
usleep(10000);
|
||||||
|
|
||||||
gpio_write(GPIO_PORT_I, GPIO_PIN_0, GPIO_LOW); //Backlight +5V disable.
|
gpio_write(GPIO_PORT_I, GPIO_PIN_0, GPIO_LOW); //Backlight +5V disable.
|
||||||
|
|
||||||
usleep(10000);
|
usleep(10000);
|
||||||
|
|
||||||
// Disable clocks.
|
// Disable Display Interface specific clocks.
|
||||||
CLOCK(CLK_RST_CONTROLLER_RST_DEV_H_SET) = 0x1010000;
|
CLOCK(CLK_RST_CONTROLLER_RST_DEV_H_SET) = 0x1010000; // Set reset clock DSI, MIPI_CAL.
|
||||||
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_CLR) = 0x1010000;
|
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_CLR) = 0x1010000; // Clear enable clock DSI, MIPI_CAL.
|
||||||
CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = 0x18000000;
|
CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = 0x18000000; // Set reset DISP1, HOST1X.
|
||||||
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_CLR) = 0x18000000;
|
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_CLR) = 0x18000000; // Clear enable DISP1, HOST1X.
|
||||||
|
|
||||||
|
// Power down pads.
|
||||||
DSI(_DSIREG(DSI_PAD_CONTROL_0)) = DSI_PAD_CONTROL_VS1_PULLDN_CLK | DSI_PAD_CONTROL_VS1_PULLDN(0xF) | DSI_PAD_CONTROL_VS1_PDIO_CLK | DSI_PAD_CONTROL_VS1_PDIO(0xF);
|
DSI(_DSIREG(DSI_PAD_CONTROL_0)) = DSI_PAD_CONTROL_VS1_PULLDN_CLK | DSI_PAD_CONTROL_VS1_PULLDN(0xF) | DSI_PAD_CONTROL_VS1_PDIO_CLK | DSI_PAD_CONTROL_VS1_PDIO(0xF);
|
||||||
DSI(_DSIREG(DSI_POWER_CONTROL)) = 0;
|
DSI(_DSIREG(DSI_POWER_CONTROL)) = 0;
|
||||||
|
|
||||||
|
// Switch to automatic function mode.
|
||||||
gpio_config(GPIO_PORT_V, GPIO_PIN_0, GPIO_MODE_SPIO); // Backlight PWM.
|
gpio_config(GPIO_PORT_V, GPIO_PIN_0, GPIO_MODE_SPIO); // Backlight PWM.
|
||||||
|
|
||||||
PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) = (PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) & ~PINMUX_TRISTATE) | PINMUX_TRISTATE;
|
PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) = (PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) & ~PINMUX_TRISTATE) | PINMUX_TRISTATE;
|
||||||
PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) = (PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) >> 2) << 2 | 1;
|
PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) = (PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) & 0xFFFFFFFC)| 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void display_color_screen(u32 color)
|
void display_color_screen(u32 color)
|
||||||
@@ -243,7 +254,6 @@ void display_color_screen(u32 color)
|
|||||||
DISPLAY_A(_DIREG(DC_WIN_CD_WIN_OPTIONS)) = 0;
|
DISPLAY_A(_DIREG(DC_WIN_CD_WIN_OPTIONS)) = 0;
|
||||||
DISPLAY_A(_DIREG(DC_DISP_BLEND_BACKGROUND_COLOR)) = color;
|
DISPLAY_A(_DIREG(DC_DISP_BLEND_BACKGROUND_COLOR)) = color;
|
||||||
DISPLAY_A(_DIREG(DC_CMD_STATE_CONTROL)) = (DISPLAY_A(_DIREG(DC_CMD_STATE_CONTROL)) & 0xFFFFFFFE) | GENERAL_ACT_REQ;
|
DISPLAY_A(_DIREG(DC_CMD_STATE_CONTROL)) = (DISPLAY_A(_DIREG(DC_CMD_STATE_CONTROL)) & 0xFFFFFFFE) | GENERAL_ACT_REQ;
|
||||||
|
|
||||||
usleep(35000);
|
usleep(35000);
|
||||||
|
|
||||||
display_backlight(true);
|
display_backlight(true);
|
||||||
@@ -252,11 +262,12 @@ void display_color_screen(u32 color)
|
|||||||
u32 *display_init_framebuffer()
|
u32 *display_init_framebuffer()
|
||||||
{
|
{
|
||||||
// Sanitize framebuffer area.
|
// Sanitize framebuffer area.
|
||||||
memset((u32 *)0xC0000000, 0, 0x3C0000);
|
memset((u32 *)IPL_FB_ADDRESS, 0, 0x3C0000);
|
||||||
// This configures the framebuffer @ 0xC0000000 with a resolution of 1280x720 (line stride 768).
|
|
||||||
exec_cfg((u32 *)DISPLAY_A_BASE, cfg_display_framebuffer, 32);
|
|
||||||
|
|
||||||
|
// This configures the framebuffer @ IPL_FB_ADDRESS with a resolution of 1280x720 (line stride 720).
|
||||||
|
exec_cfg((u32 *)DISPLAY_A_BASE, cfg_display_framebuffer, 32);
|
||||||
usleep(35000);
|
usleep(35000);
|
||||||
|
|
||||||
return (u32 *)0xC0000000;
|
return (u32 *)IPL_FB_ADDRESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2018 naehrwert
|
* Copyright (c) 2018 naehrwert
|
||||||
* Copyright (C) 2018 CTCaer
|
* Copyright (c) 2018 CTCaer
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
* under the terms and conditions of the GNU General Public License,
|
* under the terms and conditions of the GNU General Public License,
|
||||||
@@ -18,6 +18,7 @@
|
|||||||
#ifndef _DI_H_
|
#ifndef _DI_H_
|
||||||
#define _DI_H_
|
#define _DI_H_
|
||||||
|
|
||||||
|
#include "../../common/memory_map.h"
|
||||||
#include "../utils/types.h"
|
#include "../utils/types.h"
|
||||||
|
|
||||||
/*! Display registers. */
|
/*! Display registers. */
|
||||||
@@ -233,7 +234,7 @@
|
|||||||
#define UV_LINE_STRIDE(x) (((x) & 0xffff) << 16)
|
#define UV_LINE_STRIDE(x) (((x) & 0xffff) << 16)
|
||||||
#define DC_WIN_DV_CONTROL 0x70E
|
#define DC_WIN_DV_CONTROL 0x70E
|
||||||
|
|
||||||
// The following registers are A/B/C shadows of the 0xBC0/0xDC0/0xFC0 registers (see DISPLAY_WINDOW_HEADER).
|
/*! The following registers are A/B/C shadows of the 0xBC0/0xDC0/0xFC0 registers (see DISPLAY_WINDOW_HEADER). */
|
||||||
#define DC_WINBUF_START_ADDR 0x800
|
#define DC_WINBUF_START_ADDR 0x800
|
||||||
#define DC_WINBUF_ADDR_H_OFFSET 0x806
|
#define DC_WINBUF_ADDR_H_OFFSET 0x806
|
||||||
#define DC_WINBUF_ADDR_V_OFFSET 0x808
|
#define DC_WINBUF_ADDR_V_OFFSET 0x808
|
||||||
@@ -333,7 +334,7 @@
|
|||||||
#define DSI_PAD_CONTROL_VS1_PDIO_CLK (1 << 8)
|
#define DSI_PAD_CONTROL_VS1_PDIO_CLK (1 << 8)
|
||||||
#define DSI_PAD_CONTROL_VS1_PDIO(x) (((x) & 0xf) << 0)
|
#define DSI_PAD_CONTROL_VS1_PDIO(x) (((x) & 0xf) << 0)
|
||||||
|
|
||||||
#define DSI_PAD_CONTROL_CD 0x4c
|
#define DSI_PAD_CONTROL_CD 0x4C
|
||||||
#define DSI_VIDEO_MODE_CONTROL 0x4E
|
#define DSI_VIDEO_MODE_CONTROL 0x4E
|
||||||
|
|
||||||
#define DSI_PAD_CONTROL_1 0x4F
|
#define DSI_PAD_CONTROL_1 0x4F
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2018 naehrwert
|
* Copyright (c) 2018 naehrwert
|
||||||
* Copyright (C) 2018 CTCaer
|
* Copyright (c) 2018 CTCaer
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
* under the terms and conditions of the GNU General Public License,
|
* under the terms and conditions of the GNU General Public License,
|
||||||
@@ -122,7 +122,7 @@ static const cfg_op_t _display_config_2[94] = {
|
|||||||
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT},
|
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT},
|
||||||
{DC_WIN_WIN_OPTIONS, 0},
|
{DC_WIN_WIN_OPTIONS, 0},
|
||||||
{DC_DISP_DISP_WIN_OPTIONS, 0},
|
{DC_DISP_DISP_WIN_OPTIONS, 0},
|
||||||
{DC_CMD_DISPLAY_COMMAND, 0},
|
{DC_CMD_DISPLAY_COMMAND, DISP_CTRL_MODE_STOP},
|
||||||
{DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE | WIN_B_UPDATE | WIN_C_UPDATE},
|
{DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE | WIN_B_UPDATE | WIN_C_UPDATE},
|
||||||
{DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ | WIN_B_ACT_REQ | WIN_C_ACT_REQ}
|
{DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ | WIN_B_ACT_REQ | WIN_C_ACT_REQ}
|
||||||
};
|
};
|
||||||
@@ -405,7 +405,7 @@ static const cfg_op_t _display_config_11[113] = {
|
|||||||
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT},
|
{DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT},
|
||||||
{DC_WIN_WIN_OPTIONS, 0},
|
{DC_WIN_WIN_OPTIONS, 0},
|
||||||
{DC_DISP_DISP_WIN_OPTIONS, 0},
|
{DC_DISP_DISP_WIN_OPTIONS, 0},
|
||||||
{DC_CMD_DISPLAY_COMMAND, 0},
|
{DC_CMD_DISPLAY_COMMAND, DISP_CTRL_MODE_STOP},
|
||||||
{DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE | WIN_B_UPDATE | WIN_C_UPDATE},
|
{DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE | WIN_B_UPDATE | WIN_C_UPDATE},
|
||||||
{DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ | WIN_B_ACT_REQ | WIN_C_ACT_REQ},
|
{DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ | WIN_B_ACT_REQ | WIN_C_ACT_REQ},
|
||||||
{DC_CMD_STATE_ACCESS, 0},
|
{DC_CMD_STATE_ACCESS, 0},
|
||||||
@@ -455,7 +455,7 @@ static const cfg_op_t _display_config_12[17] = {
|
|||||||
{DC_CMD_STATE_ACCESS, 0},
|
{DC_CMD_STATE_ACCESS, 0},
|
||||||
{DC_CMD_INT_ENABLE, 0},
|
{DC_CMD_INT_ENABLE, 0},
|
||||||
{DC_CMD_CONT_SYNCPT_VSYNC, 0},
|
{DC_CMD_CONT_SYNCPT_VSYNC, 0},
|
||||||
{DC_CMD_DISPLAY_COMMAND, 0},
|
{DC_CMD_DISPLAY_COMMAND, DISP_CTRL_MODE_STOP},
|
||||||
{DC_CMD_STATE_CONTROL, GENERAL_UPDATE},
|
{DC_CMD_STATE_CONTROL, GENERAL_UPDATE},
|
||||||
{DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ},
|
{DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ},
|
||||||
{DC_CMD_STATE_CONTROL, GENERAL_UPDATE},
|
{DC_CMD_STATE_CONTROL, GENERAL_UPDATE},
|
||||||
@@ -548,7 +548,7 @@ static const cfg_op_t cfg_display_framebuffer[32] = {
|
|||||||
{DC_WIN_LINE_STRIDE, UV_LINE_STRIDE(720 * 2) | LINE_STRIDE(720 * 4)}, //768*2x768*4 (= 0x600 x 0xC00) bytes, see TRM for alignment requirements.
|
{DC_WIN_LINE_STRIDE, UV_LINE_STRIDE(720 * 2) | LINE_STRIDE(720 * 4)}, //768*2x768*4 (= 0x600 x 0xC00) bytes, see TRM for alignment requirements.
|
||||||
{DC_WIN_BUFFER_CONTROL, 0},
|
{DC_WIN_BUFFER_CONTROL, 0},
|
||||||
{DC_WINBUF_SURFACE_KIND, 0}, //Regular surface.
|
{DC_WINBUF_SURFACE_KIND, 0}, //Regular surface.
|
||||||
{DC_WINBUF_START_ADDR, 0xC0000000}, //Framebuffer address.
|
{DC_WINBUF_START_ADDR, IPL_FB_ADDRESS}, // Framebuffer address.
|
||||||
{DC_WINBUF_ADDR_H_OFFSET, 0},
|
{DC_WINBUF_ADDR_H_OFFSET, 0},
|
||||||
{DC_WINBUF_ADDR_V_OFFSET, 0},
|
{DC_WINBUF_ADDR_V_OFFSET, 0},
|
||||||
{DC_WIN_WIN_OPTIONS, 0},
|
{DC_WIN_WIN_OPTIONS, 0},
|
||||||
|
|||||||
149
source/gfx/gfx.c
149
source/gfx/gfx.c
@@ -19,9 +19,10 @@
|
|||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "gfx.h"
|
#include "gfx.h"
|
||||||
//#include "../utils/types.h"
|
|
||||||
|
|
||||||
static const u8 _gfx_font[] = {
|
static const u8 _gfx_font[] = {
|
||||||
|
0x00, 0x0C, 0x12, 0x7E, 0x42, 0x42, 0x7E, 0x00, // Char 030 (folder)
|
||||||
|
0x00, 0x0E, 0x12, 0x22, 0x22, 0x22, 0x3E, 0x00, // Char 031 (file)
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Char 032 ( )
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Char 032 ( )
|
||||||
0x00, 0x30, 0x30, 0x18, 0x18, 0x00, 0x0C, 0x00, // Char 033 (!)
|
0x00, 0x30, 0x30, 0x18, 0x18, 0x00, 0x0C, 0x00, // Char 033 (!)
|
||||||
0x00, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00, // Char 034 (")
|
0x00, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00, // Char 034 (")
|
||||||
@@ -129,12 +130,12 @@ void gfx_init_ctxt(u32 *fb, u32 width, u32 height, u32 stride)
|
|||||||
|
|
||||||
void gfx_clear_grey(u8 color)
|
void gfx_clear_grey(u8 color)
|
||||||
{
|
{
|
||||||
memset(gfx_ctxt.fb, color, 0x3C0000);
|
memset(gfx_ctxt.fb, color, gfx_ctxt.width * gfx_ctxt.height * 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
void gfx_clear_color(u32 color)
|
void gfx_clear_color(u32 color)
|
||||||
{
|
{
|
||||||
for (u32 i = 0; i < gfx_ctxt.height * gfx_ctxt.stride; i++)
|
for (u32 i = 0; i < gfx_ctxt.width * gfx_ctxt.height; i++)
|
||||||
gfx_ctxt.fb[i] = color;
|
gfx_ctxt.fb[i] = color;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -153,8 +154,7 @@ void gfx_con_init()
|
|||||||
gfx_con.savedy = 0;
|
gfx_con.savedy = 0;
|
||||||
gfx_con.fgcol = 0xFFCCCCCC;
|
gfx_con.fgcol = 0xFFCCCCCC;
|
||||||
gfx_con.fillbg = 1;
|
gfx_con.fillbg = 1;
|
||||||
//gfx_con.bgcol = 0xFF1B1B1B;
|
gfx_con.bgcol = 0xFF1B1B1B;
|
||||||
gfx_con.bgcol = 0xFF009600;
|
|
||||||
gfx_con.mute = 0;
|
gfx_con.mute = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -167,14 +167,14 @@ void gfx_con_setcol(u32 fgcol, int fillbg, u32 bgcol)
|
|||||||
|
|
||||||
void gfx_con_getpos(u32 *x, u32 *y)
|
void gfx_con_getpos(u32 *x, u32 *y)
|
||||||
{
|
{
|
||||||
*x = gfx_con.x;
|
*x = YLEFT - gfx_con.y;
|
||||||
*y = gfx_con.y;
|
*y = gfx_con.x;
|
||||||
}
|
}
|
||||||
|
|
||||||
void gfx_con_setpos(u32 x, u32 y)
|
void gfx_con_setpos(u32 x, u32 y)
|
||||||
{
|
{
|
||||||
gfx_con.x = x;
|
gfx_con.x = y;
|
||||||
gfx_con.y = y;
|
gfx_con.y = YLEFT - x;
|
||||||
}
|
}
|
||||||
|
|
||||||
void gfx_putc(char c)
|
void gfx_putc(char c)
|
||||||
@@ -183,14 +183,14 @@ void gfx_putc(char c)
|
|||||||
switch (gfx_con.fntsz)
|
switch (gfx_con.fntsz)
|
||||||
{
|
{
|
||||||
case 16:
|
case 16:
|
||||||
if (c >= 32 && c <= 126)
|
if (c >= 30 && c <= 126)
|
||||||
{
|
{
|
||||||
u8 *cbuf = (u8 *)&_gfx_font[8 * (c - 32)];
|
u8 *cbuf = (u8 *)&_gfx_font[8 * (c - 30)];
|
||||||
u32 *fb = gfx_ctxt.fb + gfx_con.x + gfx_con.y * gfx_ctxt.stride;
|
u32 *fb = gfx_ctxt.fb + gfx_con.x + gfx_con.y * gfx_ctxt.stride;
|
||||||
|
|
||||||
for (u32 i = 0; i < 16; i+=2)
|
for (u32 i = 0; i < 16; i+=2)
|
||||||
{
|
{
|
||||||
u8 v = *cbuf++;
|
u8 v = *cbuf;
|
||||||
for (u32 k = 0; k < 2; k++)
|
for (u32 k = 0; k < 2; k++)
|
||||||
{
|
{
|
||||||
for (u32 j = 0; j < 8; j++)
|
for (u32 j = 0; j < 8; j++)
|
||||||
@@ -198,46 +198,60 @@ void gfx_putc(char c)
|
|||||||
if (v & 1)
|
if (v & 1)
|
||||||
{
|
{
|
||||||
*fb = gfx_con.fgcol;
|
*fb = gfx_con.fgcol;
|
||||||
fb++;
|
fb -= gfx_ctxt.stride;
|
||||||
*fb = gfx_con.fgcol;
|
*fb = gfx_con.fgcol;
|
||||||
}
|
}
|
||||||
else if (gfx_con.fillbg)
|
else if (gfx_con.fillbg)
|
||||||
{
|
{
|
||||||
*fb = gfx_con.bgcol;
|
*fb = gfx_con.bgcol;
|
||||||
fb++;
|
fb -= gfx_ctxt.stride;
|
||||||
*fb = gfx_con.bgcol;
|
*fb = gfx_con.bgcol;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
fb++;
|
fb -= gfx_ctxt.stride;
|
||||||
v >>= 1;
|
v >>= 1;
|
||||||
fb++;
|
fb -= gfx_ctxt.stride;
|
||||||
}
|
}
|
||||||
fb += gfx_ctxt.stride - 16;
|
//fb += gfx_ctxt.stride - 16;
|
||||||
|
//fb = fbtop + 2;
|
||||||
|
fb += (gfx_ctxt.stride * 16) + 1;
|
||||||
v = *cbuf;
|
v = *cbuf;
|
||||||
}
|
}
|
||||||
|
cbuf++;
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
gfx_con.x += 16;
|
gfx_con.x += 16;
|
||||||
if (gfx_con.x >= gfx_ctxt.width - 16) {
|
if (gfx_con.x >= gfx_ctxt.width - 16) {
|
||||||
gfx_con.x = 0;
|
gfx_con.x = 0;
|
||||||
gfx_con.y += 16;
|
gfx_con.y += 16;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
gfx_con.y -= 16;
|
||||||
|
if (gfx_con.y < 16){
|
||||||
|
gfx_con.y = YLEFT;
|
||||||
|
gfx_con.x += 16;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (c == '\n')
|
else if (c == '\n')
|
||||||
{
|
{
|
||||||
gfx_con.x = 0;
|
gfx_con.y = YLEFT;
|
||||||
gfx_con.y +=16;
|
gfx_con.x += 16;
|
||||||
if (gfx_con.y > gfx_ctxt.height - 16)
|
if (gfx_con.x > gfx_ctxt.width - 16)
|
||||||
gfx_con.y = 0;
|
|
||||||
}
|
|
||||||
else if (c == '\r'){
|
|
||||||
gfx_con.x = 0;
|
gfx_con.x = 0;
|
||||||
}
|
}
|
||||||
|
else if (c == '\e')
|
||||||
|
gfx_con.y = 575;
|
||||||
|
else if (c == '\a')
|
||||||
|
gfx_con.y = 639;
|
||||||
|
else if (c == '\r')
|
||||||
|
gfx_con.y = YLEFT;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case 8:
|
case 8:
|
||||||
default:
|
default:
|
||||||
if (c >= 32 && c <= 126)
|
if (c >= 30 && c <= 126)
|
||||||
{
|
{
|
||||||
u8 *cbuf = (u8 *)&_gfx_font[8 * (c - 32)];
|
u8 *cbuf = (u8 *)&_gfx_font[8 * (c - 30)];
|
||||||
u32 *fb = gfx_ctxt.fb + gfx_con.x + gfx_con.y * gfx_ctxt.stride;
|
u32 *fb = gfx_ctxt.fb + gfx_con.x + gfx_con.y * gfx_ctxt.stride;
|
||||||
for (u32 i = 0; i < 8; i++)
|
for (u32 i = 0; i < 8; i++)
|
||||||
{
|
{
|
||||||
@@ -249,26 +263,34 @@ void gfx_putc(char c)
|
|||||||
else if (gfx_con.fillbg)
|
else if (gfx_con.fillbg)
|
||||||
*fb = gfx_con.bgcol;
|
*fb = gfx_con.bgcol;
|
||||||
v >>= 1;
|
v >>= 1;
|
||||||
fb++;
|
fb -= gfx_ctxt.stride;
|
||||||
}
|
}
|
||||||
fb += gfx_ctxt.stride - 8;
|
fb += (gfx_ctxt.stride * 8) + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gfx_con.y -= 8;
|
||||||
|
if (gfx_con.y < 8){
|
||||||
|
gfx_con.y = YLEFT;
|
||||||
gfx_con.x += 8;
|
gfx_con.x += 8;
|
||||||
if (gfx_con.x >= gfx_ctxt.width - 8) {
|
|
||||||
gfx_con.x = 0;
|
|
||||||
gfx_con.y += 8;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
else if (c == '\n')
|
else if (c == '\n')
|
||||||
{
|
{
|
||||||
|
gfx_con.y = YLEFT;
|
||||||
|
gfx_con.x += 8;
|
||||||
|
if (gfx_con.x > gfx_ctxt.width - 8)
|
||||||
gfx_con.x = 0;
|
gfx_con.x = 0;
|
||||||
gfx_con.y += 8;
|
|
||||||
if (gfx_con.y > gfx_ctxt.height - 8)
|
|
||||||
gfx_con.y = 0;
|
|
||||||
}
|
}
|
||||||
|
else if (c == '\e')
|
||||||
|
gfx_con.y = 575;
|
||||||
|
else if (c == '\a')
|
||||||
|
gfx_con.y = 639;
|
||||||
|
else if (c == '\r')
|
||||||
|
gfx_con.y = YLEFT;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void gfx_puts(const char *s)
|
void gfx_puts(const char *s)
|
||||||
@@ -327,15 +349,10 @@ void gfx_put_big_sep()
|
|||||||
gfx_con.fntsz = prevFontSize;
|
gfx_con.fntsz = prevFontSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
void gfx_printf(const char *fmt, ...)
|
void gfx_vprintf(const char *fmt, va_list ap)
|
||||||
{
|
{
|
||||||
if (gfx_con.mute)
|
|
||||||
return;
|
|
||||||
|
|
||||||
va_list ap;
|
|
||||||
int fill, fcnt;
|
int fill, fcnt;
|
||||||
|
|
||||||
va_start(ap, fmt);
|
|
||||||
while(*fmt)
|
while(*fmt)
|
||||||
{
|
{
|
||||||
if(*fmt == '%')
|
if(*fmt == '%')
|
||||||
@@ -371,8 +388,6 @@ void gfx_printf(const char *fmt, ...)
|
|||||||
_gfx_putn(va_arg(ap, u32), 10, fill, fcnt);
|
_gfx_putn(va_arg(ap, u32), 10, fill, fcnt);
|
||||||
break;
|
break;
|
||||||
case 'p':
|
case 'p':
|
||||||
gfx_con.bgcol = va_arg(ap, u32);
|
|
||||||
break;
|
|
||||||
case 'P':
|
case 'P':
|
||||||
case 'x':
|
case 'x':
|
||||||
case 'X':
|
case 'X':
|
||||||
@@ -389,7 +404,7 @@ void gfx_printf(const char *fmt, ...)
|
|||||||
gfx_putc('%');
|
gfx_putc('%');
|
||||||
break;
|
break;
|
||||||
case '\0':
|
case '\0':
|
||||||
goto out;
|
return;
|
||||||
default:
|
default:
|
||||||
gfx_putc('%');
|
gfx_putc('%');
|
||||||
gfx_putc(*fmt);
|
gfx_putc(*fmt);
|
||||||
@@ -400,8 +415,17 @@ void gfx_printf(const char *fmt, ...)
|
|||||||
gfx_putc(*fmt);
|
gfx_putc(*fmt);
|
||||||
fmt++;
|
fmt++;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void gfx_printf(const char *fmt, ...)
|
||||||
|
{
|
||||||
|
if (gfx_con.mute)
|
||||||
|
return;
|
||||||
|
|
||||||
|
va_list ap;
|
||||||
|
va_start(ap, fmt);
|
||||||
|
gfx_vprintf(fmt, ap);
|
||||||
|
|
||||||
out:
|
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -495,14 +519,6 @@ void gfx_line(int x0, int y0, int x1, int y1, u32 color)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void gfx_box(int x0, int y0, int x1, int y1, u32 color){
|
|
||||||
int i = y0;
|
|
||||||
while(y1 >= i){
|
|
||||||
gfx_line(x0, i, x1, i, color);
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void gfx_set_rect_grey(const u8 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y)
|
void gfx_set_rect_grey(const u8 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y)
|
||||||
{
|
{
|
||||||
u32 pos = 0;
|
u32 pos = 0;
|
||||||
@@ -516,7 +532,34 @@ void gfx_set_rect_grey(const u8 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void gfx_boxGrey(int x0, int y0, int x1, int y1, u8 shade){
|
||||||
|
for (int y = (YLEFT - x0); y >= (YLEFT - x1); y--){
|
||||||
|
memset(gfx_ctxt.fb + y * gfx_ctxt.stride + y0, shade, (y1 - y0 + 1) * 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
void gfx_boxGrey_old(int x0, int y0, int x1, int y1, u8 shade){
|
||||||
|
for (int y = y0; y <= y1; y++){
|
||||||
|
memset(gfx_ctxt.fb + y * gfx_ctxt.stride + x0, shade, (x1 - x0) * 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
void gfx_box(int x0, int y0, int x1, int y1, u32 color){
|
||||||
|
for (int y = (YLEFT - x0); y >= (YLEFT - x1); y--){
|
||||||
|
for (int x = y0; x <= y1; x++){
|
||||||
|
gfx_set_pixel(x, y, color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
void gfx_box_old(int x0, int y0, int x1, int y1, u32 color){
|
||||||
|
for (int x = x0; x < x1 + 1; x++){
|
||||||
|
for (int y = y0; y < y1 + 1; y++){
|
||||||
|
gfx_set_pixel(x, y, color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
void gfx_set_rect_rgb(const u8 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y)
|
void gfx_set_rect_rgb(const u8 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y)
|
||||||
{
|
{
|
||||||
u32 pos = 0;
|
u32 pos = 0;
|
||||||
|
|||||||
@@ -20,12 +20,15 @@
|
|||||||
#define _GFX_H_
|
#define _GFX_H_
|
||||||
|
|
||||||
#include "../../common/common_gfx.h"
|
#include "../../common/common_gfx.h"
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
#define EPRINTF(text) gfx_printf("%k"text"%k\n", 0xFFFF0000, 0xFFCCCCCC)
|
#define EPRINTF(text) gfx_printf("%k"text"%k\n", 0xFFFF0000, 0xFFCCCCCC)
|
||||||
#define EPRINTFARGS(text, args...) gfx_printf("%k"text"%k\n", 0xFFFF0000, args, 0xFFCCCCCC)
|
#define EPRINTFARGS(text, args...) gfx_printf("%k"text"%k\n", 0xFFFF0000, args, 0xFFCCCCCC)
|
||||||
#define WPRINTF(text) gfx_printf("%k"text"%k\n", 0xFFFFDD00, 0xFFCCCCCC)
|
#define WPRINTF(text) gfx_printf("%k"text"%k\n", 0xFFFFDD00, 0xFFCCCCCC)
|
||||||
#define WPRINTFARGS(text, args...) gfx_printf("%k"text"%k\n", 0xFFFFDD00, args, 0xFFCCCCCC)
|
#define WPRINTFARGS(text, args...) gfx_printf("%k"text"%k\n", 0xFFFFDD00, args, 0xFFCCCCCC)
|
||||||
|
|
||||||
|
#define YLEFT 1279
|
||||||
|
|
||||||
void gfx_init_ctxt(u32 *fb, u32 width, u32 height, u32 stride);
|
void gfx_init_ctxt(u32 *fb, u32 width, u32 height, u32 stride);
|
||||||
void gfx_clear_grey(u8 color);
|
void gfx_clear_grey(u8 color);
|
||||||
void gfx_clear_partial_grey(u8 color, u32 pos_x, u32 height);
|
void gfx_clear_partial_grey(u8 color, u32 pos_x, u32 height);
|
||||||
@@ -37,17 +40,25 @@ void gfx_con_setpos(u32 x, u32 y);
|
|||||||
void gfx_putc(char c);
|
void gfx_putc(char c);
|
||||||
void gfx_puts(const char *s);
|
void gfx_puts(const char *s);
|
||||||
void gfx_printf(const char *fmt, ...);
|
void gfx_printf(const char *fmt, ...);
|
||||||
|
void gfx_vprintf(const char *fmt, va_list ap);
|
||||||
void gfx_hexdump(u32 base, const u8 *buf, u32 len);
|
void gfx_hexdump(u32 base, const u8 *buf, u32 len);
|
||||||
|
|
||||||
void gfx_set_pixel(u32 x, u32 y, u32 color);
|
void gfx_set_pixel(u32 x, u32 y, u32 color);
|
||||||
void gfx_line(int x0, int y0, int x1, int y1, u32 color);
|
void gfx_line(int x0, int y0, int x1, int y1, u32 color);
|
||||||
void gfx_box(int x0, int y0, int x1, int y1, u32 color);
|
|
||||||
void gfx_put_small_sep();
|
void gfx_put_small_sep();
|
||||||
void gfx_put_big_sep();
|
void gfx_put_big_sep();
|
||||||
void gfx_set_rect_grey(const u8 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y);
|
void gfx_set_rect_grey(const u8 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y);
|
||||||
void gfx_set_rect_rgb(const u8 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y);
|
void gfx_set_rect_rgb(const u8 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y);
|
||||||
void gfx_set_rect_argb(const u32 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y);
|
void gfx_set_rect_argb(const u32 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y);
|
||||||
void gfx_render_bmp_argb(const u32 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y);
|
void gfx_render_bmp_argb(const u32 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y);
|
||||||
|
void gfx_box(int x0, int y0, int x1, int y1, u32 color);
|
||||||
|
void gfx_boxGrey(int x0, int y0, int x1, int y1, u8 shade);
|
||||||
|
|
||||||
|
/*
|
||||||
|
#define GFX_SETPOSCORRECTED(x, y) gfx_con_setpos(y - YLEFT, x)
|
||||||
|
#define GFX_BOXCORRECTED(x0, y0, x1, y1, color) gfx_box_old((y0 - YLEFT), x0, (y1 - YLEFT), x1, color)
|
||||||
|
#define GFX_BOXGREYCORRECTED(x0, y0, x1, y1, shade) gfx_boxGrey((y0 - YLEFT), x0, (y1 - YLEFT), x1, shade)
|
||||||
|
*/
|
||||||
|
|
||||||
// Global gfx console and context.
|
// Global gfx console and context.
|
||||||
gfx_ctxt_t gfx_ctxt;
|
gfx_ctxt_t gfx_ctxt;
|
||||||
|
|||||||
225
source/gfx/tui.c
Normal file
225
source/gfx/tui.c
Normal file
@@ -0,0 +1,225 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2018 naehrwert
|
||||||
|
* Copyright (c) 2018 CTCaer
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "di.h"
|
||||||
|
#include "tui.h"
|
||||||
|
#include "../utils/btn.h"
|
||||||
|
#include "../config/config.h"
|
||||||
|
#include "../power/max17050.h"
|
||||||
|
#include "../utils/util.h"
|
||||||
|
|
||||||
|
#ifdef MENU_LOGO_ENABLE
|
||||||
|
extern u8 *Kc_MENU_LOGO;
|
||||||
|
#define X_MENU_LOGO 119
|
||||||
|
#define Y_MENU_LOGO 57
|
||||||
|
#define X_POS_MENU_LOGO 577
|
||||||
|
#define Y_POS_MENU_LOGO 1179
|
||||||
|
#endif //MENU_LOGO_ENABLE
|
||||||
|
|
||||||
|
extern hekate_config h_cfg;
|
||||||
|
|
||||||
|
void tui_sbar(bool force_update)
|
||||||
|
{
|
||||||
|
u32 cx, cy;
|
||||||
|
|
||||||
|
u32 timePassed = get_tmr_s() - h_cfg.sbar_time_keeping;
|
||||||
|
if (!force_update)
|
||||||
|
if (timePassed < 5)
|
||||||
|
return;
|
||||||
|
|
||||||
|
u8 prevFontSize = gfx_con.fntsz;
|
||||||
|
gfx_con.fntsz = 16;
|
||||||
|
h_cfg.sbar_time_keeping = get_tmr_s();
|
||||||
|
|
||||||
|
u32 battPercent = 0;
|
||||||
|
int battVoltCurr = 0;
|
||||||
|
|
||||||
|
gfx_con_getpos(&cx, &cy);
|
||||||
|
gfx_con_setpos(0, 1260);
|
||||||
|
|
||||||
|
max17050_get_property(MAX17050_RepSOC, (int *)&battPercent);
|
||||||
|
max17050_get_property(MAX17050_VCELL, &battVoltCurr);
|
||||||
|
|
||||||
|
gfx_clear_partial_grey(0x30, 1256, 24);
|
||||||
|
gfx_printf("%K%k Battery: %d.%d%% (%d mV) - Charge:", 0xFF303030, 0xFF888888,
|
||||||
|
(battPercent >> 8) & 0xFF, (battPercent & 0xFF) / 26, battVoltCurr);
|
||||||
|
|
||||||
|
max17050_get_property(MAX17050_Current, &battVoltCurr);
|
||||||
|
|
||||||
|
if (battVoltCurr >= 0)
|
||||||
|
gfx_printf(" %k+%d mA%k%K\n",
|
||||||
|
0xFF008800, battVoltCurr / 1000, 0xFFCCCCCC, 0xFF1B1B1B);
|
||||||
|
else
|
||||||
|
gfx_printf(" %k-%d mA%k%K\n",
|
||||||
|
0xFF880000, (~battVoltCurr) / 1000, 0xFFCCCCCC, 0xFF1B1B1B);
|
||||||
|
gfx_con.fntsz = prevFontSize;
|
||||||
|
gfx_con_setpos(cx, cy);
|
||||||
|
}
|
||||||
|
|
||||||
|
void tui_pbar(int x, int y, u32 val, u32 fgcol, u32 bgcol)
|
||||||
|
{
|
||||||
|
u32 cx, cy;
|
||||||
|
if (val > 200)
|
||||||
|
val = 200;
|
||||||
|
|
||||||
|
gfx_con_getpos(&cx, &cy);
|
||||||
|
|
||||||
|
gfx_con_setpos(x, y);
|
||||||
|
|
||||||
|
gfx_printf("%k[%3d%%]%k", fgcol, val, 0xFFCCCCCC);
|
||||||
|
|
||||||
|
x += 7 * gfx_con.fntsz;
|
||||||
|
|
||||||
|
for (int i = 0; i < (gfx_con.fntsz >> 3) * 6; i++)
|
||||||
|
{
|
||||||
|
gfx_line(x, y + i + 1, x + 3 * val, y + i + 1, fgcol);
|
||||||
|
gfx_line(x + 3 * val, y + i + 1, x + 3 * 100, y + i + 1, bgcol);
|
||||||
|
}
|
||||||
|
|
||||||
|
gfx_con_setpos(cx, cy);
|
||||||
|
|
||||||
|
// Update status bar.
|
||||||
|
tui_sbar(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void *tui_do_menu(menu_t *menu)
|
||||||
|
{
|
||||||
|
int idx = 0, prev_idx = 0, cnt = 0x7FFFFFFF;
|
||||||
|
|
||||||
|
gfx_clear_partial_grey(0x1B, 0, 1256);
|
||||||
|
tui_sbar(true);
|
||||||
|
|
||||||
|
#ifdef MENU_LOGO_ENABLE
|
||||||
|
gfx_set_rect_rgb(Kc_MENU_LOGO,
|
||||||
|
X_MENU_LOGO, Y_MENU_LOGO, X_POS_MENU_LOGO, Y_POS_MENU_LOGO);
|
||||||
|
#endif //MENU_LOGO_ENABLE
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
gfx_con_setcol(0xFFCCCCCC, 1, 0xFF1B1B1B);
|
||||||
|
gfx_con_setpos(menu->x, menu->y);
|
||||||
|
gfx_printf("[%kLo%kck%kpi%kck%k_R%kCM%k v%d.%d.%d%k]\n\n",
|
||||||
|
colors[0], colors[1], colors[2], colors[3], colors[4], colors[5], 0xFFFF00FF, LP_VER_MJ, LP_VER_MN, LP_VER_BF, 0xFFCCCCCC);
|
||||||
|
|
||||||
|
// Skip caption or seperator lines selection.
|
||||||
|
while (menu->ents[idx].type == MENT_CAPTION ||
|
||||||
|
menu->ents[idx].type == MENT_CHGLINE)
|
||||||
|
{
|
||||||
|
if (prev_idx <= idx || (!idx && prev_idx == cnt - 1))
|
||||||
|
{
|
||||||
|
idx++;
|
||||||
|
if (idx > (cnt - 1))
|
||||||
|
{
|
||||||
|
idx = 0;
|
||||||
|
prev_idx = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
idx--;
|
||||||
|
if (idx < 0)
|
||||||
|
{
|
||||||
|
idx = cnt - 1;
|
||||||
|
prev_idx = cnt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
prev_idx = idx;
|
||||||
|
|
||||||
|
// Draw the menu.
|
||||||
|
for (cnt = 0; menu->ents[cnt].type != MENT_END; cnt++)
|
||||||
|
{
|
||||||
|
if (cnt == idx)
|
||||||
|
gfx_con_setcol(0xFF1B1B1B, 1, 0xFFCCCCCC);
|
||||||
|
else
|
||||||
|
gfx_con_setcol(0xFFCCCCCC, 1, 0xFF1B1B1B);
|
||||||
|
if (menu->ents[cnt].type != MENT_CHGLINE && menu->ents[cnt].type != MENT_MENU) {
|
||||||
|
if (cnt == idx)
|
||||||
|
gfx_printf(" %s", menu->ents[cnt].caption);
|
||||||
|
else
|
||||||
|
gfx_printf("%k %s", menu->ents[cnt].color, menu->ents[cnt].caption);
|
||||||
|
}
|
||||||
|
if(menu->ents[cnt].type == MENT_MENU)
|
||||||
|
gfx_printf("%k...", 0xFF0099EE);
|
||||||
|
gfx_printf(" \n");
|
||||||
|
}
|
||||||
|
gfx_con_setcol(0xFFCCCCCC, 1, 0xFF1B1B1B);
|
||||||
|
gfx_putc('\n');
|
||||||
|
|
||||||
|
// Print help and battery status.
|
||||||
|
gfx_con_setpos(0, 1127);
|
||||||
|
if (h_cfg.emummc_force_disable)
|
||||||
|
gfx_printf("%kNo emuMMC config found.\n", 0xFF800000);
|
||||||
|
gfx_con_setpos(0, 1191);
|
||||||
|
gfx_printf("%k VOL: Move up/down\n PWR: Select option%k", 0xFF555555, 0xFFCCCCCC);
|
||||||
|
|
||||||
|
display_backlight_brightness(h_cfg.backlight, 1000);
|
||||||
|
|
||||||
|
// Wait for user command.
|
||||||
|
u32 btn = btn_wait();
|
||||||
|
|
||||||
|
if (btn & BTN_VOL_DOWN && idx < (cnt - 1))
|
||||||
|
idx++;
|
||||||
|
else if (btn & BTN_VOL_DOWN && idx == (cnt - 1))
|
||||||
|
{
|
||||||
|
idx = 0;
|
||||||
|
prev_idx = -1;
|
||||||
|
}
|
||||||
|
if (btn & BTN_VOL_UP && idx > 0)
|
||||||
|
idx--;
|
||||||
|
else if (btn & BTN_VOL_UP && idx == 0)
|
||||||
|
{
|
||||||
|
idx = cnt - 1;
|
||||||
|
prev_idx = cnt;
|
||||||
|
}
|
||||||
|
if (btn & BTN_POWER)
|
||||||
|
{
|
||||||
|
ment_t *ent = &menu->ents[idx];
|
||||||
|
switch (ent->type)
|
||||||
|
{
|
||||||
|
case MENT_HANDLER:
|
||||||
|
ent->handler(ent->data);
|
||||||
|
break;
|
||||||
|
case MENT_MENU:
|
||||||
|
return tui_do_menu(ent->menu);
|
||||||
|
break;
|
||||||
|
case MENT_DATA:
|
||||||
|
return ent->data;
|
||||||
|
break;
|
||||||
|
case MENT_BACK:
|
||||||
|
return NULL;
|
||||||
|
break;
|
||||||
|
case MENT_HDLR_RE:
|
||||||
|
ent->handler(ent);
|
||||||
|
if (!ent->data)
|
||||||
|
return NULL;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
gfx_con.fntsz = 16;
|
||||||
|
gfx_clear_partial_grey(0x1B, 0, 1256);
|
||||||
|
#ifdef MENU_LOGO_ENABLE
|
||||||
|
gfx_set_rect_rgb(Kc_MENU_LOGO,
|
||||||
|
X_MENU_LOGO, Y_MENU_LOGO, X_POS_MENU_LOGO, Y_POS_MENU_LOGO);
|
||||||
|
#endif //MENU_LOGO_ENABLE
|
||||||
|
}
|
||||||
|
tui_sbar(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
66
source/gfx/tui.h
Normal file
66
source/gfx/tui.h
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2018 naehrwert
|
||||||
|
* Copyright (C) 2018 CTCaer
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _TUI_H_
|
||||||
|
#define _TUI_H_
|
||||||
|
|
||||||
|
#include "../utils/types.h"
|
||||||
|
#include "gfx.h"
|
||||||
|
|
||||||
|
#define MENT_END 0
|
||||||
|
#define MENT_HANDLER 1
|
||||||
|
#define MENT_MENU 2
|
||||||
|
#define MENT_DATA 3
|
||||||
|
#define MENT_BACK 4
|
||||||
|
#define MENT_CAPTION 5
|
||||||
|
#define MENT_CHGLINE 6
|
||||||
|
#define MENT_HDLR_RE 7
|
||||||
|
|
||||||
|
typedef struct _ment_t
|
||||||
|
{
|
||||||
|
u32 type;
|
||||||
|
const char *caption;
|
||||||
|
u32 color;
|
||||||
|
void *data;
|
||||||
|
union
|
||||||
|
{
|
||||||
|
void(*handler)(void *);
|
||||||
|
struct _menu_t *menu;
|
||||||
|
};
|
||||||
|
} ment_t;
|
||||||
|
|
||||||
|
typedef struct _menu_t
|
||||||
|
{
|
||||||
|
ment_t *ents;
|
||||||
|
const char *caption;
|
||||||
|
u32 x;
|
||||||
|
u32 y;
|
||||||
|
} menu_t;
|
||||||
|
|
||||||
|
#define MDEF_END() {MENT_END}
|
||||||
|
#define MDEF_HANDLER(caption, _handler, color) { MENT_HANDLER, caption, color, NULL, { .handler = _handler } }
|
||||||
|
#define MDEF_HANDLER_EX(caption, data, _handler, color) { MENT_HANDLER, caption, color, data, { .handler = _handler } }
|
||||||
|
#define MDEF_MENU(caption, _menu) { MENT_MENU, caption, 0, NULL, { .menu = _menu } }
|
||||||
|
#define MDEF_BACK() { MENT_BACK, "Back" }
|
||||||
|
#define MDEF_CAPTION(caption, color) { MENT_CAPTION, caption, color }
|
||||||
|
#define MDEF_CHGLINE() {MENT_CHGLINE}
|
||||||
|
|
||||||
|
void tui_sbar(bool force_update);
|
||||||
|
void tui_pbar(int x, int y, u32 val, u32 fgcol, u32 bgcol);
|
||||||
|
void *tui_do_menu(menu_t *menu);
|
||||||
|
|
||||||
|
#endif
|
||||||
116
source/hid/hid.c
Normal file
116
source/hid/hid.c
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
#include "hid.h"
|
||||||
|
#include "joycon.h"
|
||||||
|
#include "../utils/btn.h"
|
||||||
|
#include "../gfx/gfx.h"
|
||||||
|
#include "../utils/types.h"
|
||||||
|
#include "../tegraexplorer/utils/utils.h"
|
||||||
|
|
||||||
|
static Inputs inputs = {0};
|
||||||
|
u16 LbaseX = 0, LbaseY = 0, RbaseX = 0, RbaseY = 0;
|
||||||
|
|
||||||
|
void hidInit(){
|
||||||
|
jc_init_hw();
|
||||||
|
}
|
||||||
|
|
||||||
|
Inputs *hidRead(){
|
||||||
|
jc_gamepad_rpt_t *controller = joycon_poll();
|
||||||
|
static bool errPrint = false;
|
||||||
|
|
||||||
|
if (controller->cap)
|
||||||
|
utils_takeScreenshot();
|
||||||
|
|
||||||
|
|
||||||
|
u8 btn = btn_read();
|
||||||
|
inputs.volp = (btn & BTN_VOL_UP) ? 1 : 0;
|
||||||
|
inputs.volm = (btn & BTN_VOL_DOWN) ? 1 : 0;
|
||||||
|
inputs.pow = (btn & BTN_POWER) ? 1 : 0;
|
||||||
|
|
||||||
|
inputs.a = controller->a;
|
||||||
|
inputs.b = controller->b;
|
||||||
|
inputs.x = controller->x;
|
||||||
|
inputs.y = controller->y;
|
||||||
|
inputs.r = controller->r;
|
||||||
|
inputs.l = controller->l;
|
||||||
|
inputs.zr = controller->zr;
|
||||||
|
inputs.zl = controller->zl;
|
||||||
|
inputs.minus = controller->minus;
|
||||||
|
inputs.plus = controller->plus;
|
||||||
|
inputs.home = controller->home;
|
||||||
|
inputs.cap = controller->cap;
|
||||||
|
|
||||||
|
if (controller->conn_l && controller->conn_r){
|
||||||
|
if (errPrint){
|
||||||
|
gfx_boxGrey(1008, 703, 1279, 719, 0xFF);
|
||||||
|
errPrint = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
u32 x, y;
|
||||||
|
gfx_con_getpos(&x, &y);
|
||||||
|
gfx_con_setpos(1008, 703);
|
||||||
|
gfx_printf("%k%K%s %s MISS%k%K", COLOR_DEFAULT, COLOR_WHITE, (controller->conn_l) ? " " : "JOYL", (controller->conn_r) ? " " : "JOYR", COLOR_WHITE, COLOR_DEFAULT);
|
||||||
|
gfx_con_setpos(x, y);
|
||||||
|
errPrint = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (controller->conn_l){
|
||||||
|
if ((LbaseX == 0 || LbaseY == 0) || controller->l3){
|
||||||
|
LbaseX = controller->lstick_x;
|
||||||
|
LbaseY = controller->lstick_y;
|
||||||
|
}
|
||||||
|
|
||||||
|
inputs.Lup = (controller->up || (controller->lstick_y > LbaseY + 500)) ? 1 : 0;
|
||||||
|
inputs.Ldown = (controller->down || (controller->lstick_y < LbaseY - 500)) ? 1 : 0;
|
||||||
|
inputs.Lleft = (controller->left || (controller->lstick_x < LbaseX - 500)) ? 1 : 0;
|
||||||
|
inputs.Lright = (controller->right || (controller->lstick_x > LbaseX + 500)) ? 1 : 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
inputs.Lup = inputs.volp;
|
||||||
|
inputs.Ldown = inputs.volm;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (controller->conn_r){
|
||||||
|
if ((RbaseX == 0 || RbaseY == 0) || controller->r3){
|
||||||
|
RbaseX = controller->rstick_x;
|
||||||
|
RbaseY = controller->rstick_y;
|
||||||
|
}
|
||||||
|
|
||||||
|
inputs.Rup = (controller->rstick_y > RbaseY + 500) ? 1 : 0;
|
||||||
|
inputs.Rdown = (controller->rstick_y < RbaseY - 500) ? 1 : 0;
|
||||||
|
inputs.Rleft = (controller->rstick_x < RbaseX - 500) ? 1 : 0;
|
||||||
|
inputs.Rright = (controller->rstick_x > RbaseX + 500) ? 1 : 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
inputs.a = inputs.pow;
|
||||||
|
|
||||||
|
return &inputs;
|
||||||
|
}
|
||||||
|
|
||||||
|
Inputs *hidWaitMask(u32 mask){
|
||||||
|
Inputs *in = hidRead();
|
||||||
|
|
||||||
|
while (in->buttons & mask)
|
||||||
|
hidRead();
|
||||||
|
|
||||||
|
while (!(in->buttons & mask)){
|
||||||
|
hidRead();
|
||||||
|
}
|
||||||
|
|
||||||
|
return in;
|
||||||
|
}
|
||||||
|
|
||||||
|
Inputs *hidWait(){
|
||||||
|
Inputs *in = hidRead();
|
||||||
|
|
||||||
|
while (in->buttons)
|
||||||
|
hidRead();
|
||||||
|
|
||||||
|
while (!(in->buttons))
|
||||||
|
hidRead();
|
||||||
|
return in;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool hidConnected(){
|
||||||
|
jc_gamepad_rpt_t *controller = joycon_poll();
|
||||||
|
return (controller->conn_l && controller->conn_r) ? 1 : 0;
|
||||||
|
}
|
||||||
59
source/hid/hid.h
Normal file
59
source/hid/hid.h
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "../utils/types.h"
|
||||||
|
|
||||||
|
#define BIT(n) (1 << n)
|
||||||
|
#define KEY_A BIT(3)
|
||||||
|
#define KEY_B BIT(2)
|
||||||
|
#define KEY_Y BIT(0)
|
||||||
|
#define KEY_X BIT(1)
|
||||||
|
#define KEY_LUP BIT(18)
|
||||||
|
#define KEY_LDOWN BIT(17)
|
||||||
|
#define KEY_LRIGHT BIT(19)
|
||||||
|
#define KEY_LLEFT BIT(20)
|
||||||
|
#define KEY_RUP BIT(7)
|
||||||
|
#define KEY_RDOWN BIT(6)
|
||||||
|
#define KEY_VOLP BIT(14)
|
||||||
|
#define KEY_VOLM BIT(15)
|
||||||
|
#define KEY_POW BIT(16)
|
||||||
|
|
||||||
|
typedef struct _inputs {
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
// Joy-Con (R).
|
||||||
|
u32 y:1;
|
||||||
|
u32 x:1;
|
||||||
|
u32 b:1;
|
||||||
|
u32 a:1;
|
||||||
|
u32 r:1;
|
||||||
|
u32 zr:1;
|
||||||
|
u32 Rdown:1;
|
||||||
|
u32 Rup:1;
|
||||||
|
u32 Rright:1;
|
||||||
|
u32 Rleft:1;
|
||||||
|
|
||||||
|
// Shared
|
||||||
|
u32 minus:1;
|
||||||
|
u32 plus:1;
|
||||||
|
u32 home:1;
|
||||||
|
u32 cap:1;
|
||||||
|
u32 volp:1;
|
||||||
|
u32 volm:1;
|
||||||
|
u32 pow:1;
|
||||||
|
|
||||||
|
// Joy-Con (L).
|
||||||
|
u32 Ldown:1;
|
||||||
|
u32 Lup:1;
|
||||||
|
u32 Lright:1;
|
||||||
|
u32 Lleft:1;
|
||||||
|
u32 l:1;
|
||||||
|
u32 zl:1;
|
||||||
|
};
|
||||||
|
u32 buttons;
|
||||||
|
};
|
||||||
|
} Inputs;
|
||||||
|
|
||||||
|
void hidInit();
|
||||||
|
Inputs *hidRead();
|
||||||
|
Inputs *hidWait();
|
||||||
|
Inputs *hidWaitMask(u32 mask);
|
||||||
|
bool hidConnected();
|
||||||
807
source/hid/joycon.c
Normal file
807
source/hid/joycon.c
Normal file
@@ -0,0 +1,807 @@
|
|||||||
|
/*
|
||||||
|
* Joy-Con UART driver for Nintendo Switch
|
||||||
|
*
|
||||||
|
* Copyright (c) 2019 CTCaer
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "joycon.h"
|
||||||
|
#include "../gfx/gfx.h"
|
||||||
|
#include "../power/max17050.h"
|
||||||
|
#include "../power/regulator_5v.h"
|
||||||
|
#include "../soc/bpmp.h"
|
||||||
|
#include "../soc/clock.h"
|
||||||
|
#include "../soc/gpio.h"
|
||||||
|
#include "../soc/pinmux.h"
|
||||||
|
#include "../soc/uart.h"
|
||||||
|
#include "../soc/t210.h"
|
||||||
|
#include "../utils/util.h"
|
||||||
|
|
||||||
|
// For disabling driver when logging is enabled.
|
||||||
|
// #include "../libs/lvgl/lvgl.h"
|
||||||
|
|
||||||
|
#define JC_WIRED_CMD 0x91
|
||||||
|
#define JC_WIRED_HID 0x92
|
||||||
|
#define JC_WIRED_INIT_REPLY 0x94
|
||||||
|
#define JC_INIT_HANDSHAKE 0xA5
|
||||||
|
|
||||||
|
#define JC_WIRED_CMD_MAC 0x01
|
||||||
|
#define JC_WIRED_CMD_10 0x10
|
||||||
|
|
||||||
|
#define JC_HID_OUTPUT_RPT 0x01
|
||||||
|
#define JC_HID_RUMBLE_RPT 0x10
|
||||||
|
|
||||||
|
#define JC_HID_INPUT_RPT 0x30
|
||||||
|
#define JC_HID_SUBMCD_RPT 0x21
|
||||||
|
|
||||||
|
#define JC_HID_SUBCMD_HCI_STATE 0x06
|
||||||
|
#define HCI_STATE_SLEEP 0x00
|
||||||
|
#define HCI_STATE_RECONNECT 0x01
|
||||||
|
#define HCI_STATE_PAIR 0x02
|
||||||
|
#define HCI_STATE_HOME 0x04
|
||||||
|
#define JC_HID_SUBCMD_SPI_READ 0x10
|
||||||
|
#define JC_HID_SUBCMD_RUMBLE_CTL 0x48
|
||||||
|
#define JC_HID_SUBCMD_SND_RUMBLE 0xFF
|
||||||
|
|
||||||
|
#define JC_BTN_MASK_L 0xFF2900 // 0xFFE900: with charge status.
|
||||||
|
#define JC_BTN_MASK_R 0x76FF
|
||||||
|
|
||||||
|
#define JC_ID_L 1
|
||||||
|
#define JC_ID_R 2
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
JC_BATT_EMTPY = 0,
|
||||||
|
JC_BATT_CRIT = 2,
|
||||||
|
JC_BATT_LOW = 4,
|
||||||
|
JC_BATT_MID = 6,
|
||||||
|
JC_BATT_FULL = 8
|
||||||
|
};
|
||||||
|
|
||||||
|
static const u8 init_jc[] = {
|
||||||
|
0xA1, 0xA2, 0xA3, 0xA4
|
||||||
|
};
|
||||||
|
|
||||||
|
static const u8 init_handshake[] = {
|
||||||
|
0x19, 0x01, 0x03, 0x07, 0x00, // Uart header.
|
||||||
|
JC_INIT_HANDSHAKE, 0x02, // Wired cmd and wired subcmd.
|
||||||
|
0x01, 0x7E, 0x00, 0x00, 0x00 // Wired subcmd data.
|
||||||
|
};
|
||||||
|
|
||||||
|
static const u8 init_get_info[] = {
|
||||||
|
0x19, 0x01, 0x03, 0x07, 0x00, // Uart header.
|
||||||
|
JC_WIRED_CMD, JC_WIRED_CMD_MAC, // Wired cmd and subcmd.
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x24 // Wired subcmd data.
|
||||||
|
};
|
||||||
|
|
||||||
|
static const u8 init_finilize[] = {
|
||||||
|
0x19, 0x01, 0x03, 0x07, 0x00, // Uart header.
|
||||||
|
JC_WIRED_CMD, JC_WIRED_CMD_10, // Wired cmd and subcmd.
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x3D // Wired subcmd data.
|
||||||
|
};
|
||||||
|
|
||||||
|
static const u8 nx_pad_status[] = {
|
||||||
|
0x19, 0x01, 0x03, 0x08, 0x00, // Uart header.
|
||||||
|
JC_WIRED_HID, 0x00, // Wired cmd and hid cmd.
|
||||||
|
0x01, 0x00, 0x00, 0x69, 0x2D, 0x1F // hid data.
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct _jc_uart_hdr_t
|
||||||
|
{
|
||||||
|
u8 magic[3];
|
||||||
|
u8 total_size_lsb;
|
||||||
|
u8 total_size_msb;
|
||||||
|
} jc_uart_hdr_t;
|
||||||
|
|
||||||
|
typedef struct _jc_wired_hdr_t
|
||||||
|
{
|
||||||
|
jc_uart_hdr_t uart_hdr;
|
||||||
|
u8 cmd;
|
||||||
|
u8 data[5];
|
||||||
|
u8 crc;
|
||||||
|
u8 payload[];
|
||||||
|
} jc_wired_hdr_t;
|
||||||
|
|
||||||
|
typedef struct _jc_hid_out_rpt_t
|
||||||
|
{
|
||||||
|
u8 cmd;
|
||||||
|
u8 pkt_id;
|
||||||
|
u8 rumble[8];
|
||||||
|
u8 subcmd;
|
||||||
|
u8 subcmd_data[];
|
||||||
|
} jc_hid_out_rpt_t;
|
||||||
|
|
||||||
|
typedef struct _jc_hid_out_spi_read_t
|
||||||
|
{
|
||||||
|
u32 addr;
|
||||||
|
u8 size;
|
||||||
|
} jc_hid_out_spi_read_t;
|
||||||
|
|
||||||
|
typedef struct _jc_hid_in_rpt_t
|
||||||
|
{
|
||||||
|
u8 cmd;
|
||||||
|
u8 pkt_id;
|
||||||
|
u8 conn_info:4;
|
||||||
|
u8 batt_info:4;
|
||||||
|
u8 btn_right;
|
||||||
|
u8 btn_shared;
|
||||||
|
u8 btn_left;
|
||||||
|
u8 stick_h_left;
|
||||||
|
u8 stick_m_left;
|
||||||
|
u8 stick_v_left;
|
||||||
|
u8 stick_h_right;
|
||||||
|
u8 stick_m_right;
|
||||||
|
u8 stick_v_right;
|
||||||
|
u8 vib_decider;
|
||||||
|
u8 submcd_ack;
|
||||||
|
u8 subcmd;
|
||||||
|
u8 subcmd_data[];
|
||||||
|
} jc_hid_in_rpt_t;
|
||||||
|
|
||||||
|
typedef struct _jc_hid_in_spi_read_t
|
||||||
|
{
|
||||||
|
u32 addr;
|
||||||
|
u8 size;
|
||||||
|
u8 data[];
|
||||||
|
} jc_hid_in_spi_read_t;
|
||||||
|
|
||||||
|
typedef struct _jc_hid_in_pair_data_t
|
||||||
|
{
|
||||||
|
u8 magic;
|
||||||
|
u8 size;
|
||||||
|
u16 checksum;
|
||||||
|
u8 mac[6];
|
||||||
|
u8 ltk[16];
|
||||||
|
u8 pad0[10];
|
||||||
|
u8 bt_caps; // bit3: Secure conn supported host, bit5: Paired to TBFC supported host, bit6: iTBFC page supported
|
||||||
|
u8 pad1;
|
||||||
|
} jc_hid_in_pair_data_t;
|
||||||
|
|
||||||
|
typedef struct _joycon_ctxt_t
|
||||||
|
{
|
||||||
|
u8 buf[0x100]; //FIXME: If heap is used, dumping breaks.
|
||||||
|
u8 uart;
|
||||||
|
u8 type;
|
||||||
|
u8 mac[6];
|
||||||
|
u32 hw_init_done;
|
||||||
|
u32 last_received_time;
|
||||||
|
u32 last_status_req_time;
|
||||||
|
u8 rumble_sent;
|
||||||
|
u8 connected;
|
||||||
|
} joycon_ctxt_t;
|
||||||
|
|
||||||
|
static joycon_ctxt_t jc_l;
|
||||||
|
static joycon_ctxt_t jc_r;
|
||||||
|
|
||||||
|
static bool jc_init_done = false;
|
||||||
|
static u32 hid_pkt_inc = 0;
|
||||||
|
|
||||||
|
static jc_gamepad_rpt_t jc_gamepad;
|
||||||
|
|
||||||
|
void jc_power_supply(u8 uart, bool enable);
|
||||||
|
|
||||||
|
void joycon_send_raw(u8 uart_port, const u8 *buf, u16 size)
|
||||||
|
{
|
||||||
|
uart_send(uart_port, buf, size);
|
||||||
|
uart_wait_idle(uart_port, UART_TX_IDLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static u16 jc_packet_add_uart_hdr(jc_wired_hdr_t *out, u8 wired_cmd, u8 *data, u16 size)
|
||||||
|
{
|
||||||
|
out->uart_hdr.magic[0] = 0x19;
|
||||||
|
out->uart_hdr.magic[1] = 0x01;
|
||||||
|
out->uart_hdr.magic[2] = 0x3;
|
||||||
|
|
||||||
|
out->uart_hdr.total_size_lsb = 7;
|
||||||
|
out->uart_hdr.total_size_msb = 0;
|
||||||
|
out->cmd = wired_cmd;
|
||||||
|
|
||||||
|
if (data)
|
||||||
|
memcpy(out->data, data, size);
|
||||||
|
|
||||||
|
out->crc = 0; // wired crc8ccit can be skipped.
|
||||||
|
|
||||||
|
return sizeof(jc_wired_hdr_t);
|
||||||
|
}
|
||||||
|
|
||||||
|
static u16 jc_hid_output_rpt_craft(jc_wired_hdr_t *rpt, u8 *payload, u16 size)
|
||||||
|
{
|
||||||
|
u16 pkt_size = jc_packet_add_uart_hdr(rpt, JC_WIRED_HID, NULL, 0);
|
||||||
|
pkt_size += size;
|
||||||
|
|
||||||
|
rpt->uart_hdr.total_size_lsb += size;
|
||||||
|
rpt->data[0] = size >> 8;
|
||||||
|
rpt->data[1] = size & 0xFF;
|
||||||
|
|
||||||
|
if (payload)
|
||||||
|
memcpy(rpt->payload, payload, size);
|
||||||
|
|
||||||
|
return pkt_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
void jc_send_hid_output_rpt(u8 uart, u8 *payload, u16 size)
|
||||||
|
{
|
||||||
|
u8 rpt[0x50];
|
||||||
|
memset(rpt, 0, sizeof(rpt));
|
||||||
|
|
||||||
|
u32 rpt_size = jc_hid_output_rpt_craft((jc_wired_hdr_t *)rpt, payload, size);
|
||||||
|
|
||||||
|
joycon_send_raw(uart, rpt, rpt_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
static u8 jc_hid_pkt_id_incr()
|
||||||
|
{
|
||||||
|
u8 curr_id = hid_pkt_inc;
|
||||||
|
hid_pkt_inc++;
|
||||||
|
|
||||||
|
return (curr_id & 0xF);
|
||||||
|
}
|
||||||
|
|
||||||
|
void jc_send_hid_cmd(u8 uart, u8 subcmd, u8 *data, u16 size)
|
||||||
|
{
|
||||||
|
u8 temp[0x30];
|
||||||
|
u8 rumble_neutral[8] = {0x00, 0x01, 0x40, 0x40, 0x00, 0x01, 0x40, 0x40};
|
||||||
|
u8 rumble_init[8] = {0xc2, 0xc8, 0x03, 0x72, 0xc2, 0xc8, 0x03, 0x72};
|
||||||
|
|
||||||
|
memset(temp, 0, sizeof(temp));
|
||||||
|
|
||||||
|
jc_hid_out_rpt_t *hid_pkt = (jc_hid_out_rpt_t *)temp;
|
||||||
|
|
||||||
|
memcpy(hid_pkt->rumble, rumble_neutral, sizeof(rumble_neutral));
|
||||||
|
|
||||||
|
if (subcmd == JC_HID_SUBCMD_SND_RUMBLE)
|
||||||
|
{
|
||||||
|
bool send_r_rumble = jc_r.connected && !jc_r.rumble_sent;
|
||||||
|
bool send_l_rumble = jc_l.connected && !jc_l.rumble_sent;
|
||||||
|
|
||||||
|
// Enable rumble.
|
||||||
|
hid_pkt->cmd = JC_HID_OUTPUT_RPT;
|
||||||
|
hid_pkt->pkt_id = jc_hid_pkt_id_incr();
|
||||||
|
hid_pkt->subcmd = JC_HID_SUBCMD_RUMBLE_CTL;
|
||||||
|
hid_pkt->subcmd_data[0] = 1;
|
||||||
|
if (send_r_rumble)
|
||||||
|
jc_send_hid_output_rpt(UART_B, (u8 *)hid_pkt, 0x10);
|
||||||
|
if (send_l_rumble)
|
||||||
|
jc_send_hid_output_rpt(UART_C, (u8 *)hid_pkt, 0x10);
|
||||||
|
|
||||||
|
// Send rumble.
|
||||||
|
hid_pkt->cmd = JC_HID_RUMBLE_RPT;
|
||||||
|
hid_pkt->pkt_id = jc_hid_pkt_id_incr();
|
||||||
|
memcpy(hid_pkt->rumble, rumble_init, sizeof(rumble_init));
|
||||||
|
if (send_r_rumble)
|
||||||
|
jc_send_hid_output_rpt(UART_B, (u8 *)hid_pkt, 10);
|
||||||
|
if (send_l_rumble)
|
||||||
|
jc_send_hid_output_rpt(UART_C, (u8 *)hid_pkt, 10);
|
||||||
|
|
||||||
|
msleep(15);
|
||||||
|
|
||||||
|
// Disable rumble.
|
||||||
|
hid_pkt->cmd = JC_HID_OUTPUT_RPT;
|
||||||
|
hid_pkt->pkt_id = jc_hid_pkt_id_incr();
|
||||||
|
hid_pkt->subcmd = JC_HID_SUBCMD_RUMBLE_CTL;
|
||||||
|
hid_pkt->subcmd_data[0] = 0;
|
||||||
|
memcpy(hid_pkt->rumble, rumble_neutral, sizeof(rumble_neutral));
|
||||||
|
if (send_r_rumble)
|
||||||
|
jc_send_hid_output_rpt(UART_B, (u8 *)hid_pkt, 0x10);
|
||||||
|
if (send_l_rumble)
|
||||||
|
jc_send_hid_output_rpt(UART_C, (u8 *)hid_pkt, 0x10);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
hid_pkt->cmd = JC_HID_OUTPUT_RPT;
|
||||||
|
hid_pkt->pkt_id = jc_hid_pkt_id_incr();
|
||||||
|
hid_pkt->subcmd = subcmd;
|
||||||
|
if (data)
|
||||||
|
memcpy(hid_pkt->subcmd_data, data, size);
|
||||||
|
|
||||||
|
u8 pkt_size = sizeof(jc_hid_out_rpt_t) + size;
|
||||||
|
|
||||||
|
if (subcmd != JC_HID_SUBCMD_SPI_READ)
|
||||||
|
jc_send_hid_output_rpt(uart, (u8 *)hid_pkt, pkt_size);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
jc_send_hid_output_rpt(UART_B, (u8 *)hid_pkt, pkt_size);
|
||||||
|
jc_send_hid_output_rpt(UART_C, (u8 *)hid_pkt, pkt_size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void jc_charging_decider(u8 batt, u8 uart)
|
||||||
|
{
|
||||||
|
u32 system_batt_enough = max17050_get_cached_batt_volt() > 4000;
|
||||||
|
|
||||||
|
// Power supply control based on battery levels and charging.
|
||||||
|
if ((batt >> 1 << 1) < JC_BATT_LOW) // Level without checking charging.
|
||||||
|
jc_power_supply(uart, true);
|
||||||
|
else if (batt > (system_batt_enough ? JC_BATT_FULL : JC_BATT_MID)) // Addresses the charging bit.
|
||||||
|
jc_power_supply(uart, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void jc_parse_wired_hid(joycon_ctxt_t *jc, const u8* packet, u32 size)
|
||||||
|
{
|
||||||
|
u32 btn_tmp;
|
||||||
|
jc_hid_in_rpt_t *hid_pkt = (jc_hid_in_rpt_t *)packet;
|
||||||
|
|
||||||
|
switch (hid_pkt->cmd)
|
||||||
|
{
|
||||||
|
case JC_HID_INPUT_RPT:
|
||||||
|
btn_tmp = hid_pkt->btn_right | hid_pkt->btn_shared << 8 | hid_pkt->btn_left << 16;
|
||||||
|
|
||||||
|
if (jc->type & JC_ID_L)
|
||||||
|
{
|
||||||
|
jc_gamepad.buttons &= ~JC_BTN_MASK_L;
|
||||||
|
jc_gamepad.buttons |= (btn_tmp & JC_BTN_MASK_L);
|
||||||
|
|
||||||
|
jc_gamepad.lstick_x = hid_pkt->stick_h_left | ((hid_pkt->stick_m_left & 0xF) << 8);
|
||||||
|
jc_gamepad.lstick_y = (hid_pkt->stick_m_left >> 4) | (hid_pkt->stick_v_left << 4);
|
||||||
|
|
||||||
|
jc_gamepad.batt_info_l = hid_pkt->batt_info;
|
||||||
|
}
|
||||||
|
else if (jc->type & JC_ID_R)
|
||||||
|
{
|
||||||
|
jc_gamepad.buttons &= ~JC_BTN_MASK_R;
|
||||||
|
jc_gamepad.buttons |= (btn_tmp & JC_BTN_MASK_R);
|
||||||
|
|
||||||
|
jc_gamepad.rstick_x = hid_pkt->stick_h_right | ((hid_pkt->stick_m_right & 0xF) << 8);
|
||||||
|
jc_gamepad.rstick_y = (hid_pkt->stick_m_right >> 4) | (hid_pkt->stick_v_right << 4);
|
||||||
|
|
||||||
|
jc_gamepad.batt_info_r = hid_pkt->batt_info;
|
||||||
|
}
|
||||||
|
|
||||||
|
jc_gamepad.conn_l = jc_l.connected;
|
||||||
|
jc_gamepad.conn_r = jc_r.connected;
|
||||||
|
|
||||||
|
jc_charging_decider(hid_pkt->batt_info, jc->uart);
|
||||||
|
break;
|
||||||
|
case JC_HID_SUBMCD_RPT:
|
||||||
|
if (hid_pkt->subcmd == JC_HID_SUBCMD_SPI_READ)
|
||||||
|
{
|
||||||
|
jc_bt_conn_t *bt_conn;
|
||||||
|
|
||||||
|
if (jc->type & JC_ID_L)
|
||||||
|
bt_conn = &jc_gamepad.bt_conn_l;
|
||||||
|
else
|
||||||
|
bt_conn = &jc_gamepad.bt_conn_r;
|
||||||
|
|
||||||
|
jc_hid_in_spi_read_t *spi_info = (jc_hid_in_spi_read_t *)hid_pkt->subcmd_data;
|
||||||
|
jc_hid_in_pair_data_t *pair_data = (jc_hid_in_pair_data_t *)spi_info->data;
|
||||||
|
|
||||||
|
// Check if we reply is pairing info.
|
||||||
|
if (spi_info->addr == 0x2000 && spi_info->size == 0x1A && pair_data->magic == 0x95)
|
||||||
|
{
|
||||||
|
bt_conn->type = jc->type;
|
||||||
|
|
||||||
|
memcpy(bt_conn->mac, jc->mac, 6);
|
||||||
|
memcpy(bt_conn->host_mac, pair_data->mac, 6);
|
||||||
|
for (u32 i = 16; i > 0; i--)
|
||||||
|
bt_conn->ltk[16 - i] = pair_data->ltk[i - 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
jc->last_received_time = get_tmr_ms();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void jc_parse_wired_init(joycon_ctxt_t *jc, const u8* data, u32 size)
|
||||||
|
{
|
||||||
|
switch (data[0])
|
||||||
|
{
|
||||||
|
case JC_WIRED_CMD_MAC:
|
||||||
|
for (int i = 12; i > 6; i--)
|
||||||
|
jc->mac[12 - i] = data[i];
|
||||||
|
jc->type = data[6];
|
||||||
|
jc->connected = true;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void jc_uart_pkt_parse(joycon_ctxt_t *jc, const u8* packet, size_t size)
|
||||||
|
{
|
||||||
|
jc_wired_hdr_t *pkt = (jc_wired_hdr_t *)packet;
|
||||||
|
switch (pkt->cmd)
|
||||||
|
{
|
||||||
|
case JC_WIRED_HID:
|
||||||
|
jc_parse_wired_hid(jc, pkt->payload, (pkt->data[0] << 8) | pkt->data[1]);
|
||||||
|
break;
|
||||||
|
case JC_WIRED_INIT_REPLY:
|
||||||
|
jc_parse_wired_init(jc, pkt->data, size - sizeof(jc_uart_hdr_t) - 1);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void jc_rcv_pkt(joycon_ctxt_t *jc)
|
||||||
|
{
|
||||||
|
if (gpio_read(GPIO_PORT_E, GPIO_PIN_6) && jc->uart == UART_C)
|
||||||
|
return;
|
||||||
|
else if (gpio_read(GPIO_PORT_H, GPIO_PIN_6) && jc->uart == UART_B)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Check if device stopped sending data.
|
||||||
|
u32 uart_irq = uart_get_IIR(jc->uart);
|
||||||
|
if ((uart_irq & 0x8) != 0x8)
|
||||||
|
return;
|
||||||
|
|
||||||
|
u32 len = uart_recv(jc->uart, (u8 *)jc->buf, 0);
|
||||||
|
|
||||||
|
// Check valid size and uart reply magic.
|
||||||
|
if (len > 7 && !memcmp(jc->buf, "\x19\x81\x03", 3))
|
||||||
|
{
|
||||||
|
jc_wired_hdr_t *pkt = (jc_wired_hdr_t *)(jc->buf);
|
||||||
|
|
||||||
|
jc_uart_pkt_parse(jc, jc->buf, pkt->uart_hdr.total_size_lsb + sizeof(jc_uart_hdr_t));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool jc_send_init_rumble(joycon_ctxt_t *jc)
|
||||||
|
{
|
||||||
|
// Send init rumble or request nx pad status report.
|
||||||
|
if ((jc_r.connected && !jc_r.rumble_sent) || (jc_l.connected && !jc_l.rumble_sent))
|
||||||
|
{
|
||||||
|
gpio_config(GPIO_PORT_G, GPIO_PIN_0, GPIO_MODE_SPIO);
|
||||||
|
gpio_config(GPIO_PORT_D, GPIO_PIN_1, GPIO_MODE_SPIO);
|
||||||
|
|
||||||
|
jc_send_hid_cmd(jc->uart, JC_HID_SUBCMD_SND_RUMBLE, NULL, 0);
|
||||||
|
|
||||||
|
if (jc_l.connected)
|
||||||
|
jc_l.rumble_sent = true;
|
||||||
|
if (jc_r.connected)
|
||||||
|
jc_r.rumble_sent = true;
|
||||||
|
|
||||||
|
if (jc->uart != UART_B)
|
||||||
|
gpio_config(GPIO_PORT_G, GPIO_PIN_0, GPIO_MODE_GPIO);
|
||||||
|
else
|
||||||
|
gpio_config(GPIO_PORT_D, GPIO_PIN_1, GPIO_MODE_GPIO);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void jc_req_nx_pad_status(joycon_ctxt_t *jc)
|
||||||
|
{
|
||||||
|
bool sent_rumble = jc_send_init_rumble(jc);
|
||||||
|
|
||||||
|
if (sent_rumble)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (jc->last_status_req_time > get_tmr_ms() || !jc->connected)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Turn off Joy-Con detect.
|
||||||
|
if (jc->uart == UART_B)
|
||||||
|
gpio_config(GPIO_PORT_G, GPIO_PIN_0, GPIO_MODE_SPIO);
|
||||||
|
else
|
||||||
|
gpio_config(GPIO_PORT_D, GPIO_PIN_1, GPIO_MODE_SPIO);
|
||||||
|
|
||||||
|
joycon_send_raw(jc->uart, nx_pad_status, sizeof(nx_pad_status));
|
||||||
|
|
||||||
|
// Turn Joy-Con detect on.
|
||||||
|
if (jc->uart == UART_B)
|
||||||
|
gpio_config(GPIO_PORT_G, GPIO_PIN_0, GPIO_MODE_GPIO);
|
||||||
|
else
|
||||||
|
gpio_config(GPIO_PORT_D, GPIO_PIN_1, GPIO_MODE_GPIO);
|
||||||
|
|
||||||
|
jc->last_status_req_time = get_tmr_ms() + 15;
|
||||||
|
}
|
||||||
|
|
||||||
|
jc_gamepad_rpt_t *jc_get_bt_pairing_info()
|
||||||
|
{
|
||||||
|
u8 retries;
|
||||||
|
jc_bt_conn_t *bt_conn;
|
||||||
|
|
||||||
|
bt_conn = &jc_gamepad.bt_conn_l;
|
||||||
|
memset(bt_conn->host_mac, 0, 6);
|
||||||
|
memset(bt_conn->ltk, 0, 16);
|
||||||
|
|
||||||
|
bt_conn = &jc_gamepad.bt_conn_r;
|
||||||
|
memset(bt_conn->host_mac, 0, 6);
|
||||||
|
memset(bt_conn->ltk, 0, 16);
|
||||||
|
|
||||||
|
while (jc_l.last_status_req_time > get_tmr_ms())
|
||||||
|
{
|
||||||
|
jc_rcv_pkt(&jc_r);
|
||||||
|
jc_rcv_pkt(&jc_l);
|
||||||
|
}
|
||||||
|
|
||||||
|
jc_hid_in_spi_read_t subcmd_data;
|
||||||
|
subcmd_data.addr = 0x2000;
|
||||||
|
subcmd_data.size = 0x1A;
|
||||||
|
|
||||||
|
// Turn off Joy-Con detect.
|
||||||
|
gpio_config(GPIO_PORT_G, GPIO_PIN_0, GPIO_MODE_SPIO);
|
||||||
|
gpio_config(GPIO_PORT_D, GPIO_PIN_1, GPIO_MODE_SPIO);
|
||||||
|
|
||||||
|
bool jc_r_found = jc_r.connected ? false : true;
|
||||||
|
bool jc_l_found = jc_l.connected ? false : true;
|
||||||
|
|
||||||
|
u32 total_retries = 5;
|
||||||
|
retry:
|
||||||
|
retries = 10;
|
||||||
|
while (retries)
|
||||||
|
{
|
||||||
|
if (jc_l.last_status_req_time < get_tmr_ms())
|
||||||
|
{
|
||||||
|
jc_send_hid_cmd(0, JC_HID_SUBCMD_SPI_READ, (u8 *)&subcmd_data, 5);
|
||||||
|
jc_l.last_status_req_time = get_tmr_ms() + 15;
|
||||||
|
jc_r.last_status_req_time = get_tmr_ms() + 15;
|
||||||
|
retries--;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!jc_r_found)
|
||||||
|
{
|
||||||
|
memset(jc_r.buf, 0, 0x100);
|
||||||
|
jc_rcv_pkt(&jc_r);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!jc_l_found)
|
||||||
|
{
|
||||||
|
memset(jc_l.buf, 0, 0x100);
|
||||||
|
jc_rcv_pkt(&jc_l);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (jc_l.connected &&
|
||||||
|
memcmp(&jc_gamepad.bt_conn_l.ltk[0], "\x00\x00\x00\x00", 4) &&
|
||||||
|
memcmp(&jc_gamepad.bt_conn_l.ltk[8], "\x00\x00\x00\x00", 4))
|
||||||
|
jc_l_found = true;
|
||||||
|
|
||||||
|
if (jc_r.connected &&
|
||||||
|
memcmp(&jc_gamepad.bt_conn_r.ltk[0], "\x00\x00\x00\x00", 4) &&
|
||||||
|
memcmp(&jc_gamepad.bt_conn_r.ltk[8], "\x00\x00\x00\x00", 4))
|
||||||
|
jc_r_found = true;
|
||||||
|
|
||||||
|
if (total_retries && (!jc_l_found || !jc_r_found))
|
||||||
|
{
|
||||||
|
total_retries--;
|
||||||
|
goto retry;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Turn Joy-Con detect on.
|
||||||
|
gpio_config(GPIO_PORT_G, GPIO_PIN_0, GPIO_MODE_GPIO);
|
||||||
|
gpio_config(GPIO_PORT_D, GPIO_PIN_1, GPIO_MODE_GPIO);
|
||||||
|
|
||||||
|
return &jc_gamepad;
|
||||||
|
}
|
||||||
|
|
||||||
|
void jc_deinit()
|
||||||
|
{
|
||||||
|
gpio_config(GPIO_PORT_G, GPIO_PIN_0, GPIO_MODE_SPIO);
|
||||||
|
gpio_config(GPIO_PORT_D, GPIO_PIN_1, GPIO_MODE_SPIO);
|
||||||
|
|
||||||
|
u8 data = HCI_STATE_SLEEP;
|
||||||
|
|
||||||
|
if (jc_r.connected)
|
||||||
|
{
|
||||||
|
jc_send_hid_cmd(UART_B, JC_HID_SUBCMD_HCI_STATE, &data, 1);
|
||||||
|
msleep(1);
|
||||||
|
jc_rcv_pkt(&jc_r);
|
||||||
|
}
|
||||||
|
if (jc_l.connected)
|
||||||
|
{
|
||||||
|
jc_send_hid_cmd(UART_C, JC_HID_SUBCMD_HCI_STATE, &data, 1);
|
||||||
|
msleep(1);
|
||||||
|
jc_rcv_pkt(&jc_l);
|
||||||
|
}
|
||||||
|
|
||||||
|
jc_power_supply(UART_B, false);
|
||||||
|
jc_power_supply(UART_C, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void jc_init_conn(joycon_ctxt_t *jc)
|
||||||
|
{
|
||||||
|
if (((u32)get_tmr_ms() - jc->last_received_time) > 1000)
|
||||||
|
{
|
||||||
|
jc_power_supply(jc->uart, true);
|
||||||
|
|
||||||
|
// Turn off Joy-Con detect.
|
||||||
|
if (jc->uart == UART_B)
|
||||||
|
{
|
||||||
|
jc_gamepad.buttons &= ~JC_BTN_MASK_R;
|
||||||
|
jc_gamepad.conn_r = false;
|
||||||
|
gpio_config(GPIO_PORT_G, GPIO_PIN_0, GPIO_MODE_SPIO);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
jc_gamepad.buttons &= ~JC_BTN_MASK_L;
|
||||||
|
jc_gamepad.conn_l = false;
|
||||||
|
gpio_config(GPIO_PORT_D, GPIO_PIN_1, GPIO_MODE_SPIO);
|
||||||
|
}
|
||||||
|
|
||||||
|
uart_init(jc->uart, 1000000);
|
||||||
|
uart_invert(jc->uart, true, UART_INVERT_TXD);
|
||||||
|
uart_set_IIR(jc->uart);
|
||||||
|
|
||||||
|
joycon_send_raw(jc->uart, init_jc, 4);
|
||||||
|
joycon_send_raw(jc->uart, init_handshake, sizeof(init_handshake));
|
||||||
|
|
||||||
|
msleep(5);
|
||||||
|
jc_rcv_pkt(jc);
|
||||||
|
|
||||||
|
joycon_send_raw(jc->uart, init_get_info, sizeof(init_get_info));
|
||||||
|
msleep(5);
|
||||||
|
jc_rcv_pkt(jc);
|
||||||
|
|
||||||
|
joycon_send_raw(jc->uart, init_finilize, sizeof(init_finilize));
|
||||||
|
msleep(5);
|
||||||
|
jc_rcv_pkt(jc);
|
||||||
|
|
||||||
|
// Turn Joy-Con detect on.
|
||||||
|
if (jc->uart == UART_B)
|
||||||
|
gpio_config(GPIO_PORT_G, GPIO_PIN_0, GPIO_MODE_GPIO);
|
||||||
|
else
|
||||||
|
gpio_config(GPIO_PORT_D, GPIO_PIN_1, GPIO_MODE_GPIO);
|
||||||
|
|
||||||
|
jc->last_received_time = get_tmr_ms();
|
||||||
|
|
||||||
|
if (jc->connected)
|
||||||
|
jc_power_supply(jc->uart, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void jc_conn_check()
|
||||||
|
{
|
||||||
|
// Check if a Joy-Con was disconnected.
|
||||||
|
if (gpio_read(GPIO_PORT_E, GPIO_PIN_6))
|
||||||
|
{
|
||||||
|
jc_power_supply(UART_C, false);
|
||||||
|
|
||||||
|
hid_pkt_inc = 0;
|
||||||
|
|
||||||
|
jc_l.connected = false;
|
||||||
|
jc_l.rumble_sent = false;
|
||||||
|
|
||||||
|
jc_gamepad.buttons &= ~JC_BTN_MASK_L;
|
||||||
|
jc_gamepad.conn_l = false;
|
||||||
|
|
||||||
|
jc_gamepad.batt_info_l = 0;
|
||||||
|
jc_gamepad.bt_conn_l.type = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gpio_read(GPIO_PORT_H, GPIO_PIN_6))
|
||||||
|
{
|
||||||
|
jc_power_supply(UART_B, false);
|
||||||
|
|
||||||
|
hid_pkt_inc = 0;
|
||||||
|
|
||||||
|
jc_r.connected = false;
|
||||||
|
jc_r.rumble_sent = false;
|
||||||
|
|
||||||
|
jc_gamepad.buttons &= ~JC_BTN_MASK_R;
|
||||||
|
jc_gamepad.conn_r = false;
|
||||||
|
|
||||||
|
jc_gamepad.batt_info_r = 0;
|
||||||
|
jc_gamepad.bt_conn_r.type = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void jc_power_supply(u8 uart, bool enable)
|
||||||
|
{
|
||||||
|
if (enable)
|
||||||
|
{
|
||||||
|
if (regulator_get_5v_dev_enabled(1 << uart))
|
||||||
|
return;
|
||||||
|
|
||||||
|
regulator_enable_5v(1 << uart);
|
||||||
|
|
||||||
|
if (jc_init_done)
|
||||||
|
{
|
||||||
|
if (uart == UART_C)
|
||||||
|
gpio_write(GPIO_PORT_CC, GPIO_PIN_3, GPIO_HIGH);
|
||||||
|
else
|
||||||
|
gpio_write(GPIO_PORT_K, GPIO_PIN_3, GPIO_HIGH);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (uart == UART_C)
|
||||||
|
{
|
||||||
|
// Joy-Con(L) Charge Detect.
|
||||||
|
PINMUX_AUX(PINMUX_AUX_SPDIF_IN) = PINMUX_PULL_DOWN | 1;
|
||||||
|
gpio_config(GPIO_PORT_CC, GPIO_PIN_3, GPIO_MODE_GPIO);
|
||||||
|
gpio_output_enable(GPIO_PORT_CC, GPIO_PIN_3, GPIO_OUTPUT_ENABLE);
|
||||||
|
gpio_write(GPIO_PORT_CC, GPIO_PIN_3, GPIO_HIGH);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Joy-Con(R) Charge Detect.
|
||||||
|
PINMUX_AUX(PINMUX_AUX_GPIO_PK3) = PINMUX_DRIVE_4X | PINMUX_PULL_DOWN | 2;
|
||||||
|
gpio_config(GPIO_PORT_K, GPIO_PIN_3, GPIO_MODE_GPIO);
|
||||||
|
gpio_output_enable(GPIO_PORT_K, GPIO_PIN_3, GPIO_OUTPUT_ENABLE);
|
||||||
|
gpio_write(GPIO_PORT_K, GPIO_PIN_3, GPIO_HIGH);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!regulator_get_5v_dev_enabled(1 << uart))
|
||||||
|
return;
|
||||||
|
|
||||||
|
regulator_disable_5v(1 << uart);
|
||||||
|
|
||||||
|
if (uart == UART_C)
|
||||||
|
gpio_write(GPIO_PORT_CC, GPIO_PIN_3, GPIO_LOW);
|
||||||
|
else
|
||||||
|
gpio_write(GPIO_PORT_K, GPIO_PIN_3, GPIO_LOW);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void jc_init_hw()
|
||||||
|
{
|
||||||
|
jc_l.uart = UART_C;
|
||||||
|
jc_r.uart = UART_B;
|
||||||
|
|
||||||
|
#if (LV_LOG_PRINTF != 1)
|
||||||
|
jc_power_supply(UART_C, true);
|
||||||
|
jc_power_supply(UART_B, true);
|
||||||
|
|
||||||
|
// Joy-Con (R) IsAttached.
|
||||||
|
PINMUX_AUX(PINMUX_AUX_GPIO_PH6) = PINMUX_INPUT_ENABLE | PINMUX_TRISTATE;
|
||||||
|
gpio_config(GPIO_PORT_H, GPIO_PIN_6, GPIO_MODE_GPIO);
|
||||||
|
|
||||||
|
// Joy-Con (L) IsAttached.
|
||||||
|
PINMUX_AUX(PINMUX_AUX_GPIO_PE6) = PINMUX_INPUT_ENABLE | PINMUX_TRISTATE;
|
||||||
|
gpio_config(GPIO_PORT_E, GPIO_PIN_6, GPIO_MODE_GPIO);
|
||||||
|
|
||||||
|
// Configure pinmuxing for UART B and C.
|
||||||
|
pinmux_config_uart(UART_B);
|
||||||
|
pinmux_config_uart(UART_C);
|
||||||
|
|
||||||
|
// Ease the stress to APB.
|
||||||
|
bpmp_clk_rate_set(BPMP_CLK_NORMAL);
|
||||||
|
|
||||||
|
// Enable UART B and C clocks.
|
||||||
|
clock_enable_uart(UART_B);
|
||||||
|
clock_enable_uart(UART_C);
|
||||||
|
|
||||||
|
// Restore OC.
|
||||||
|
bpmp_clk_rate_set(BPMP_CLK_DEFAULT_BOOST);
|
||||||
|
|
||||||
|
// Turn Joy-Con detect on.
|
||||||
|
gpio_config(GPIO_PORT_G, GPIO_PIN_0, GPIO_MODE_GPIO);
|
||||||
|
gpio_config(GPIO_PORT_D, GPIO_PIN_1, GPIO_MODE_GPIO);
|
||||||
|
|
||||||
|
jc_init_done = true;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
jc_gamepad_rpt_t *joycon_poll()
|
||||||
|
{
|
||||||
|
if (!jc_init_done)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (!gpio_read(GPIO_PORT_H, GPIO_PIN_6))
|
||||||
|
jc_init_conn(&jc_r);
|
||||||
|
if (!gpio_read(GPIO_PORT_E, GPIO_PIN_6))
|
||||||
|
jc_init_conn(&jc_l);
|
||||||
|
|
||||||
|
if (!gpio_read(GPIO_PORT_H, GPIO_PIN_6))
|
||||||
|
jc_req_nx_pad_status(&jc_r);
|
||||||
|
if (!gpio_read(GPIO_PORT_E, GPIO_PIN_6))
|
||||||
|
jc_req_nx_pad_status(&jc_l);
|
||||||
|
|
||||||
|
if (!gpio_read(GPIO_PORT_H, GPIO_PIN_6))
|
||||||
|
jc_rcv_pkt(&jc_r);
|
||||||
|
if (!gpio_read(GPIO_PORT_E, GPIO_PIN_6))
|
||||||
|
jc_rcv_pkt(&jc_l);
|
||||||
|
|
||||||
|
jc_conn_check();
|
||||||
|
|
||||||
|
return &jc_gamepad;
|
||||||
|
}
|
||||||
98
source/hid/joycon.h
Normal file
98
source/hid/joycon.h
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
/*
|
||||||
|
* Ambient light sensor driver for Nintendo Switch's Rohm BH1730
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 CTCaer
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __JOYCON_H_
|
||||||
|
#define __JOYCON_H_
|
||||||
|
|
||||||
|
#include "../utils/types.h"
|
||||||
|
|
||||||
|
#define JC_BTNS_DIRECTION_PAD 0xF0000
|
||||||
|
#define JC_BTNS_PREV_NEXT 0x800080
|
||||||
|
#define JC_BTNS_ENTER 0x400008
|
||||||
|
#define JC_BTNS_ESC 0x4
|
||||||
|
|
||||||
|
#define JC_BTNS_ALL (JC_BTNS_PREV_NEXT | JC_BTNS_ENTER | JC_BTNS_DIRECTION_PAD | JC_BTNS_ESC)
|
||||||
|
|
||||||
|
typedef struct _jc_bt_conn_t
|
||||||
|
{
|
||||||
|
u8 type;
|
||||||
|
u8 mac[6];
|
||||||
|
u8 host_mac[6];
|
||||||
|
u8 ltk[16];
|
||||||
|
} jc_bt_conn_t;
|
||||||
|
|
||||||
|
typedef struct _jc_gamepad_rpt_t
|
||||||
|
{
|
||||||
|
union
|
||||||
|
{
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
// Joy-Con (R).
|
||||||
|
u32 y:1;
|
||||||
|
u32 x:1;
|
||||||
|
u32 b:1;
|
||||||
|
u32 a:1;
|
||||||
|
u32 sr_r:1;
|
||||||
|
u32 sl_r:1;
|
||||||
|
u32 r:1;
|
||||||
|
u32 zr:1;
|
||||||
|
|
||||||
|
// Shared
|
||||||
|
u32 minus:1;
|
||||||
|
u32 plus:1;
|
||||||
|
u32 r3:1;
|
||||||
|
u32 l3:1;
|
||||||
|
u32 home:1;
|
||||||
|
u32 cap:1;
|
||||||
|
u32 pad:1;
|
||||||
|
u32 wired:1;
|
||||||
|
|
||||||
|
// Joy-Con (L).
|
||||||
|
u32 down:1;
|
||||||
|
u32 up:1;
|
||||||
|
u32 right:1;
|
||||||
|
u32 left:1;
|
||||||
|
u32 sr_l:1;
|
||||||
|
u32 sl_l:1;
|
||||||
|
u32 l:1;
|
||||||
|
u32 zl:1;
|
||||||
|
};
|
||||||
|
u32 buttons;
|
||||||
|
};
|
||||||
|
|
||||||
|
u16 lstick_x;
|
||||||
|
u16 lstick_y;
|
||||||
|
u16 rstick_x;
|
||||||
|
u16 rstick_y;
|
||||||
|
bool center_stick_l;
|
||||||
|
bool center_stick_r;
|
||||||
|
bool conn_l;
|
||||||
|
bool conn_r;
|
||||||
|
u8 batt_info_l;
|
||||||
|
u8 batt_info_r;
|
||||||
|
jc_bt_conn_t bt_conn_l;
|
||||||
|
jc_bt_conn_t bt_conn_r;
|
||||||
|
} jc_gamepad_rpt_t;
|
||||||
|
|
||||||
|
void jc_power_supply(u8 uart, bool enable);
|
||||||
|
void jc_init_hw();
|
||||||
|
void jc_deinit();
|
||||||
|
jc_gamepad_rpt_t *joycon_poll();
|
||||||
|
jc_gamepad_rpt_t *jc_get_bt_pairing_info();
|
||||||
|
|
||||||
|
#endif
|
||||||
247
source/hos/fss.c
Normal file
247
source/hos/fss.c
Normal file
@@ -0,0 +1,247 @@
|
|||||||
|
/*
|
||||||
|
* Atmosphère Fusée Secondary Storage parser.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2019-2020 CTCaer
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "fss.h"
|
||||||
|
#include "hos.h"
|
||||||
|
#include "../config/config.h"
|
||||||
|
#include "../libs/fatfs/ff.h"
|
||||||
|
#include "../mem/heap.h"
|
||||||
|
#include "../storage/emummc.h"
|
||||||
|
#include "../storage/nx_sd.h"
|
||||||
|
|
||||||
|
#include "../gfx/gfx.h"
|
||||||
|
#define DPRINTF(...)
|
||||||
|
|
||||||
|
extern hekate_config h_cfg;
|
||||||
|
|
||||||
|
extern bool is_ipl_updated(void *buf, char *path, bool force);
|
||||||
|
|
||||||
|
// FSS0 Magic and Meta header offset.
|
||||||
|
#define FSS0_MAGIC 0x30535346
|
||||||
|
#define FSS0_META_OFFSET 0x4
|
||||||
|
|
||||||
|
// FSS0 Content Types.
|
||||||
|
#define CNT_TYPE_FSP 0
|
||||||
|
#define CNT_TYPE_EXO 1 // Exosphere (Secure Monitor).
|
||||||
|
#define CNT_TYPE_WBT 2 // Warmboot (SC7Exit fw).
|
||||||
|
#define CNT_TYPE_RBT 3 // Rebootstub (Warmboot based reboot fw).
|
||||||
|
#define CNT_TYPE_SP1 4 // Sept Primary (TSEC and Sept Secondary loader).
|
||||||
|
#define CNT_TYPE_SP2 5 // Sept Secondary (Acts as pkg11 and derives keys).
|
||||||
|
#define CNT_TYPE_KIP 6 // KIP1 (Used for replacement or addition).
|
||||||
|
#define CNT_TYPE_BMP 7
|
||||||
|
#define CNT_TYPE_EMC 8
|
||||||
|
#define CNT_TYPE_KLD 9 // Kernel Loader.
|
||||||
|
#define CNT_TYPE_KRN 10 // Kernel.
|
||||||
|
|
||||||
|
// FSS0 Content Flags.
|
||||||
|
#define CNT_FLAG0_EXPERIMENTAL (1 << 0)
|
||||||
|
|
||||||
|
// FSS0 Meta Header.
|
||||||
|
typedef struct _fss_meta_t
|
||||||
|
{
|
||||||
|
u32 magic;
|
||||||
|
u32 size;
|
||||||
|
u32 crt0_off;
|
||||||
|
u32 cnt_off;
|
||||||
|
u32 cnt_count;
|
||||||
|
u32 hos_ver;
|
||||||
|
u32 version;
|
||||||
|
u32 git_rev;
|
||||||
|
} fss_meta_t;
|
||||||
|
|
||||||
|
// FSS0 Content Header.
|
||||||
|
typedef struct _fss_content_t
|
||||||
|
{
|
||||||
|
u32 offset;
|
||||||
|
u32 size;
|
||||||
|
u8 type;
|
||||||
|
u8 flags0;
|
||||||
|
u8 flags1;
|
||||||
|
u8 flags2;
|
||||||
|
u32 rsvd1;
|
||||||
|
char name[0x10];
|
||||||
|
} fss_content_t;
|
||||||
|
|
||||||
|
static void _update_r2p(const char *path)
|
||||||
|
{
|
||||||
|
char *r2p_path = malloc(256);
|
||||||
|
u32 path_len = strlen(path);
|
||||||
|
strcpy(r2p_path, path);
|
||||||
|
|
||||||
|
while(path_len)
|
||||||
|
{
|
||||||
|
if ((r2p_path[path_len - 1] == '/') || (r2p_path[path_len - 1] == 0x5C))
|
||||||
|
{
|
||||||
|
r2p_path[path_len] = 0;
|
||||||
|
strcat(r2p_path, "reboot_payload.bin");
|
||||||
|
u8 *r2p_payload = sd_file_read(r2p_path, NULL);
|
||||||
|
|
||||||
|
is_ipl_updated(r2p_payload, r2p_path, h_cfg.updater2p ? true : false);
|
||||||
|
|
||||||
|
free(r2p_payload);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
path_len--;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(r2p_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
int parse_fss(launch_ctxt_t *ctxt, const char *path, fss0_sept_t *sept_ctxt)
|
||||||
|
{
|
||||||
|
FIL fp;
|
||||||
|
|
||||||
|
bool stock = false;
|
||||||
|
int sept_used = 0;
|
||||||
|
|
||||||
|
if (!sept_ctxt)
|
||||||
|
{
|
||||||
|
LIST_FOREACH_ENTRY(ini_kv_t, kv, &ctxt->cfg->kvs, link)
|
||||||
|
{
|
||||||
|
if (!strcmp("stock", kv->key))
|
||||||
|
if (kv->val[0] == '1')
|
||||||
|
stock = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stock && ctxt->pkg1_id->kb <= KB_FIRMWARE_VERSION_620 && (!emu_cfg.enabled || h_cfg.emummc_force_disable))
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (f_open(&fp, path, FA_READ) != FR_OK)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
void *fss = malloc(f_size(&fp));
|
||||||
|
|
||||||
|
// Read first 1024 bytes of the fss file.
|
||||||
|
f_read(&fp, fss, 1024, NULL);
|
||||||
|
|
||||||
|
// Get FSS0 Meta header offset.
|
||||||
|
u32 fss_meta_addr = *(u32 *)(fss + FSS0_META_OFFSET);
|
||||||
|
fss_meta_t *fss_meta = (fss_meta_t *)(fss + fss_meta_addr);
|
||||||
|
|
||||||
|
// Check if valid FSS0 and parse it.
|
||||||
|
if (fss_meta->magic == FSS0_MAGIC)
|
||||||
|
{
|
||||||
|
gfx_printf("Found FSS0, Atmosphere %d.%d.%d-%08x\n"
|
||||||
|
"Max HOS supported: %d.%d.%d\n"
|
||||||
|
"Unpacking and loading components.. ",
|
||||||
|
fss_meta->version >> 24, (fss_meta->version >> 16) & 0xFF, (fss_meta->version >> 8) & 0xFF, fss_meta->git_rev,
|
||||||
|
fss_meta->hos_ver >> 24, (fss_meta->hos_ver >> 16) & 0xFF, (fss_meta->hos_ver >> 8) & 0xFF);
|
||||||
|
|
||||||
|
if (!sept_ctxt)
|
||||||
|
{
|
||||||
|
ctxt->atmosphere = true;
|
||||||
|
ctxt->fss0_hosver = fss_meta->hos_ver;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse FSS0 contents.
|
||||||
|
fss_content_t *curr_fss_cnt = (fss_content_t *)(fss + fss_meta->cnt_off);
|
||||||
|
void *content;
|
||||||
|
for (u32 i = 0; i < fss_meta->cnt_count; i++)
|
||||||
|
{
|
||||||
|
content = (void *)(fss + curr_fss_cnt[i].offset);
|
||||||
|
|
||||||
|
// Check if offset is inside limits.
|
||||||
|
if ((curr_fss_cnt[i].offset + curr_fss_cnt[i].size) > fss_meta->size)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// If content is experimental and experimental flag is not enabled, skip it.
|
||||||
|
if ((curr_fss_cnt[i].flags0 & CNT_FLAG0_EXPERIMENTAL) && !ctxt->fss0_enable_experimental)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Parse content.
|
||||||
|
if (!sept_ctxt)
|
||||||
|
{
|
||||||
|
// Prepare content context.
|
||||||
|
switch (curr_fss_cnt[i].type)
|
||||||
|
{
|
||||||
|
case CNT_TYPE_KIP:
|
||||||
|
if (stock)
|
||||||
|
continue;
|
||||||
|
merge_kip_t *mkip1 = (merge_kip_t *)malloc(sizeof(merge_kip_t));
|
||||||
|
mkip1->kip1 = content;
|
||||||
|
list_append(&ctxt->kip1_list, &mkip1->link);
|
||||||
|
DPRINTF("Loaded %s.kip1 from FSS0 (size %08X)\n", curr_fss_cnt[i].name, curr_fss_cnt[i].size);
|
||||||
|
break;
|
||||||
|
case CNT_TYPE_EXO:
|
||||||
|
ctxt->secmon_size = curr_fss_cnt[i].size;
|
||||||
|
ctxt->secmon = content;
|
||||||
|
break;
|
||||||
|
case CNT_TYPE_WBT:
|
||||||
|
ctxt->warmboot_size = curr_fss_cnt[i].size;
|
||||||
|
ctxt->warmboot = content;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load content to launch context.
|
||||||
|
f_lseek(&fp, curr_fss_cnt[i].offset);
|
||||||
|
f_read(&fp, content, curr_fss_cnt[i].size, NULL);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Load sept content directly to launch context.
|
||||||
|
switch (curr_fss_cnt[i].type)
|
||||||
|
{
|
||||||
|
case CNT_TYPE_SP1:
|
||||||
|
f_lseek(&fp, curr_fss_cnt[i].offset);
|
||||||
|
f_read(&fp, sept_ctxt->sept_primary, curr_fss_cnt[i].size, NULL);
|
||||||
|
break;
|
||||||
|
case CNT_TYPE_SP2:
|
||||||
|
if (!memcmp(curr_fss_cnt[i].name, (sept_ctxt->kb < KB_FIRMWARE_VERSION_810) ? "septsecondary00" : "septsecondary01", 15))
|
||||||
|
{
|
||||||
|
f_lseek(&fp, curr_fss_cnt[i].offset);
|
||||||
|
f_read(&fp, sept_ctxt->sept_secondary, curr_fss_cnt[i].size, NULL);
|
||||||
|
sept_used = 1;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
gfx_printf("Done!\n");
|
||||||
|
f_close(&fp);
|
||||||
|
|
||||||
|
_update_r2p(path);
|
||||||
|
|
||||||
|
return (!sept_ctxt ? 1 : sept_used);
|
||||||
|
}
|
||||||
|
|
||||||
|
f_close(&fp);
|
||||||
|
free(fss);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int load_sept_from_ffs0(fss0_sept_t *sept_ctxt)
|
||||||
|
{
|
||||||
|
LIST_FOREACH_ENTRY(ini_kv_t, kv, &sept_ctxt->cfg_sec->kvs, link)
|
||||||
|
{
|
||||||
|
if (!strcmp("fss0", kv->key))
|
||||||
|
return parse_fss(NULL, kv->val, sept_ctxt);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
34
source/hos/fss.h
Normal file
34
source/hos/fss.h
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019 CTCaer
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _FSS_H_
|
||||||
|
#define _FSS_H_
|
||||||
|
|
||||||
|
#include "hos.h"
|
||||||
|
|
||||||
|
typedef struct _fss0_sept_t
|
||||||
|
{
|
||||||
|
u32 kb;
|
||||||
|
ini_sec_t *cfg_sec;
|
||||||
|
void *sept_primary;
|
||||||
|
void *sept_secondary;
|
||||||
|
|
||||||
|
} fss0_sept_t;
|
||||||
|
|
||||||
|
int parse_fss(launch_ctxt_t *ctxt, const char *path, fss0_sept_t *sept_ctxt);
|
||||||
|
int load_sept_from_ffs0(fss0_sept_t *sept_ctxt);
|
||||||
|
|
||||||
|
#endif
|
||||||
953
source/hos/hos.c
Normal file
953
source/hos/hos.c
Normal file
@@ -0,0 +1,953 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2018 naehrwert
|
||||||
|
* Copyright (c) 2018 st4rk
|
||||||
|
* Copyright (c) 2018 Ced2911
|
||||||
|
* Copyright (c) 2018-2020 CTCaer
|
||||||
|
* Copyright (c) 2018 balika011
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "hos.h"
|
||||||
|
#include "hos_config.h"
|
||||||
|
#include "sept.h"
|
||||||
|
#include "secmon_exo.h"
|
||||||
|
#include "../config/config.h"
|
||||||
|
#include "../gfx/di.h"
|
||||||
|
#include "../mem/heap.h"
|
||||||
|
#include "../mem/mc.h"
|
||||||
|
#include "../mem/minerva.h"
|
||||||
|
#include "../sec/se.h"
|
||||||
|
#include "../sec/se_t210.h"
|
||||||
|
#include "../sec/tsec.h"
|
||||||
|
#include "../soc/bpmp.h"
|
||||||
|
#include "../soc/cluster.h"
|
||||||
|
#include "../soc/fuse.h"
|
||||||
|
#include "../soc/pmc.h"
|
||||||
|
#include "../soc/smmu.h"
|
||||||
|
#include "../soc/t210.h"
|
||||||
|
#include "../storage/emummc.h"
|
||||||
|
#include "../storage/nx_emmc.h"
|
||||||
|
#include "../storage/nx_sd.h"
|
||||||
|
#include "../storage/sdmmc.h"
|
||||||
|
#include "../utils/util.h"
|
||||||
|
#include "../gfx/gfx.h"
|
||||||
|
|
||||||
|
extern hekate_config h_cfg;
|
||||||
|
|
||||||
|
//#define DPRINTF(...) gfx_printf(__VA_ARGS__)
|
||||||
|
#define DPRINTF(...)
|
||||||
|
|
||||||
|
#define EHPRINTFARGS(text, args...) \
|
||||||
|
({ display_backlight_brightness(h_cfg.backlight, 1000); \
|
||||||
|
gfx_con.mute = false; \
|
||||||
|
gfx_printf("%k"text"%k\n", 0xFFFF0000, args, 0xFFCCCCCC); })
|
||||||
|
|
||||||
|
#define PKG2_LOAD_ADDR 0xA9800000
|
||||||
|
|
||||||
|
// Secmon mailbox.
|
||||||
|
#define SECMON_MB_ADDR 0x40002EF8
|
||||||
|
#define SECMON7_MB_ADDR 0x400000F8
|
||||||
|
typedef struct _secmon_mailbox_t
|
||||||
|
{
|
||||||
|
// < 4.0.0 Signals - 0: Not ready, 1: BCT ready, 2: DRAM and pkg2 ready, 3: Continue boot.
|
||||||
|
// >= 4.0.0 Signals - 0: Not ready, 1: BCT ready, 2: DRAM ready, 4: pkg2 ready and continue boot.
|
||||||
|
u32 in;
|
||||||
|
// Non-zero: Secmon ready.
|
||||||
|
u32 out;
|
||||||
|
} secmon_mailbox_t;
|
||||||
|
|
||||||
|
static const u8 keyblob_keyseeds[][0x10] = {
|
||||||
|
{ 0xDF, 0x20, 0x6F, 0x59, 0x44, 0x54, 0xEF, 0xDC, 0x70, 0x74, 0x48, 0x3B, 0x0D, 0xED, 0x9F, 0xD3 }, //1.0.0
|
||||||
|
{ 0x0C, 0x25, 0x61, 0x5D, 0x68, 0x4C, 0xEB, 0x42, 0x1C, 0x23, 0x79, 0xEA, 0x82, 0x25, 0x12, 0xAC }, //3.0.0
|
||||||
|
{ 0x33, 0x76, 0x85, 0xEE, 0x88, 0x4A, 0xAE, 0x0A, 0xC2, 0x8A, 0xFD, 0x7D, 0x63, 0xC0, 0x43, 0x3B }, //3.0.1
|
||||||
|
{ 0x2D, 0x1F, 0x48, 0x80, 0xED, 0xEC, 0xED, 0x3E, 0x3C, 0xF2, 0x48, 0xB5, 0x65, 0x7D, 0xF7, 0xBE }, //4.0.0
|
||||||
|
{ 0xBB, 0x5A, 0x01, 0xF9, 0x88, 0xAF, 0xF5, 0xFC, 0x6C, 0xFF, 0x07, 0x9E, 0x13, 0x3C, 0x39, 0x80 }, //5.0.0
|
||||||
|
{ 0xD8, 0xCC, 0xE1, 0x26, 0x6A, 0x35, 0x3F, 0xCC, 0x20, 0xF3, 0x2D, 0x3B, 0x51, 0x7D, 0xE9, 0xC0 } //6.0.0
|
||||||
|
};
|
||||||
|
|
||||||
|
static const u8 cmac_keyseed[0x10] =
|
||||||
|
{ 0x59, 0xC7, 0xFB, 0x6F, 0xBE, 0x9B, 0xBE, 0x87, 0x65, 0x6B, 0x15, 0xC0, 0x53, 0x73, 0x36, 0xA5 };
|
||||||
|
|
||||||
|
static const u8 master_keyseed_retail[0x10] =
|
||||||
|
{ 0xD8, 0xA2, 0x41, 0x0A, 0xC6, 0xC5, 0x90, 0x01, 0xC6, 0x1D, 0x6A, 0x26, 0x7C, 0x51, 0x3F, 0x3C };
|
||||||
|
|
||||||
|
static const u8 console_keyseed[0x10] =
|
||||||
|
{ 0x4F, 0x02, 0x5F, 0x0E, 0xB6, 0x6D, 0x11, 0x0E, 0xDC, 0x32, 0x7D, 0x41, 0x86, 0xC2, 0xF4, 0x78 };
|
||||||
|
|
||||||
|
const u8 package2_keyseed[] =
|
||||||
|
{ 0xFB, 0x8B, 0x6A, 0x9C, 0x79, 0x00, 0xC8, 0x49, 0xEF, 0xD2, 0x4D, 0x85, 0x4D, 0x30, 0xA0, 0xC7 };
|
||||||
|
|
||||||
|
static const u8 master_keyseed_4xx_5xx_610[0x10] =
|
||||||
|
{ 0x2D, 0xC1, 0xF4, 0x8D, 0xF3, 0x5B, 0x69, 0x33, 0x42, 0x10, 0xAC, 0x65, 0xDA, 0x90, 0x46, 0x66 };
|
||||||
|
|
||||||
|
static const u8 master_keyseed_620[0x10] =
|
||||||
|
{ 0x37, 0x4B, 0x77, 0x29, 0x59, 0xB4, 0x04, 0x30, 0x81, 0xF6, 0xE5, 0x8C, 0x6D, 0x36, 0x17, 0x9A };
|
||||||
|
|
||||||
|
static const u8 console_keyseed_4xx_5xx[0x10] =
|
||||||
|
{ 0x0C, 0x91, 0x09, 0xDB, 0x93, 0x93, 0x07, 0x81, 0x07, 0x3C, 0xC4, 0x16, 0x22, 0x7C, 0x6C, 0x28 };
|
||||||
|
|
||||||
|
static void _hos_crit_error(const char *text)
|
||||||
|
{
|
||||||
|
gfx_con.mute = false;
|
||||||
|
gfx_printf("%k%s%k\n", 0xFFFF0000, text, 0xFFCCCCCC);
|
||||||
|
|
||||||
|
display_backlight_brightness(h_cfg.backlight, 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _se_lock(bool lock_se)
|
||||||
|
{
|
||||||
|
if (lock_se)
|
||||||
|
{
|
||||||
|
for (u32 i = 0; i < 16; i++)
|
||||||
|
se_key_acc_ctrl(i, SE_KEY_TBL_DIS_KEYREAD_FLAG | SE_KEY_TBL_DIS_OIVREAD_FLAG | SE_KEY_TBL_DIS_UIVREAD_FLAG);
|
||||||
|
|
||||||
|
for (u32 i = 0; i < 2; i++)
|
||||||
|
se_rsa_acc_ctrl(i, SE_RSA_KEY_TBL_DIS_KEYREAD_FLAG);
|
||||||
|
SE(SE_TZRAM_SECURITY_0) = 0; // Make SE TZRAM secure only.
|
||||||
|
SE(SE_KEY_TABLE_ACCESS_LOCK_OFFSET) = 0; // Make all key access regs secure only.
|
||||||
|
SE(SE_RSA_KEYTABLE_ACCESS_LOCK_OFFSET) = 0; // Make all RSA access regs secure only.
|
||||||
|
SE(SE_SECURITY_0) &= 0xFFFFFFFB; // Make access lock regs secure only.
|
||||||
|
}
|
||||||
|
|
||||||
|
memset((void *)IPATCH_BASE, 0, 14 * sizeof(u32));
|
||||||
|
SB(SB_CSR) = SB_CSR_PIROM_DISABLE;
|
||||||
|
|
||||||
|
// This is useful for documenting the bits in the SE config registers, so we can keep it around.
|
||||||
|
/*gfx_printf("SE(SE_SECURITY_0) = %08X\n", SE(SE_SECURITY_0));
|
||||||
|
gfx_printf("SE(0x4) = %08X\n", SE(0x4));
|
||||||
|
gfx_printf("SE(SE_KEY_TABLE_ACCESS_LOCK_OFFSET) = %08X\n", SE(SE_KEY_TABLE_ACCESS_LOCK_OFFSET));
|
||||||
|
gfx_printf("SE(SE_RSA_KEYTABLE_ACCESS_LOCK_OFFSET) = %08X\n", SE(SE_RSA_KEYTABLE_ACCESS_LOCK_OFFSET));
|
||||||
|
for(u32 i = 0; i < 16; i++)
|
||||||
|
gfx_printf("%02X ", SE(SE_KEY_TABLE_ACCESS_REG_OFFSET + i * 4) & 0xFF);
|
||||||
|
gfx_putc('\n');
|
||||||
|
for(u32 i = 0; i < 2; i++)
|
||||||
|
gfx_printf("%02X ", SE(SE_RSA_KEYTABLE_ACCESS_REG_OFFSET + i * 4) & 0xFF);
|
||||||
|
gfx_putc('\n');
|
||||||
|
gfx_hexdump(SE_BASE, (void *)SE_BASE, 0x400);*/
|
||||||
|
}
|
||||||
|
|
||||||
|
void _pmc_scratch_lock(u32 kb)
|
||||||
|
{
|
||||||
|
switch (kb)
|
||||||
|
{
|
||||||
|
case KB_FIRMWARE_VERSION_100_200:
|
||||||
|
case KB_FIRMWARE_VERSION_300:
|
||||||
|
case KB_FIRMWARE_VERSION_301:
|
||||||
|
PMC(APBDEV_PMC_SEC_DISABLE) = 0x7FFFF3;
|
||||||
|
PMC(APBDEV_PMC_SEC_DISABLE2) = 0xFFFFFFFF;
|
||||||
|
PMC(APBDEV_PMC_SEC_DISABLE3) = 0xFFAFFFFF;
|
||||||
|
PMC(APBDEV_PMC_SEC_DISABLE4) = 0xFFFFFFFF;
|
||||||
|
PMC(APBDEV_PMC_SEC_DISABLE5) = 0xFFFFFFFF;
|
||||||
|
PMC(APBDEV_PMC_SEC_DISABLE6) = 0xFFFFFFFF;
|
||||||
|
PMC(APBDEV_PMC_SEC_DISABLE7) = 0xFFFFFFFF;
|
||||||
|
PMC(APBDEV_PMC_SEC_DISABLE8) = 0xFFAAFFFF;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
PMC(APBDEV_PMC_SEC_DISABLE2) |= 0x3FCFFFF;
|
||||||
|
PMC(APBDEV_PMC_SEC_DISABLE4) |= 0x3F3FFFFF;
|
||||||
|
PMC(APBDEV_PMC_SEC_DISABLE5) = 0xFFFFFFFF;
|
||||||
|
PMC(APBDEV_PMC_SEC_DISABLE6) |= 0xF3FFC00F;
|
||||||
|
PMC(APBDEV_PMC_SEC_DISABLE7) |= 0x3FFFFF;
|
||||||
|
PMC(APBDEV_PMC_SEC_DISABLE8) |= 0xFF;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _sysctr0_reset()
|
||||||
|
{
|
||||||
|
SYSCTR0(SYSCTR0_CNTCR) = 0;
|
||||||
|
SYSCTR0(SYSCTR0_COUNTERID0) = 0;
|
||||||
|
SYSCTR0(SYSCTR0_COUNTERID1) = 0;
|
||||||
|
SYSCTR0(SYSCTR0_COUNTERID2) = 0;
|
||||||
|
SYSCTR0(SYSCTR0_COUNTERID3) = 0;
|
||||||
|
SYSCTR0(SYSCTR0_COUNTERID4) = 0;
|
||||||
|
SYSCTR0(SYSCTR0_COUNTERID5) = 0;
|
||||||
|
SYSCTR0(SYSCTR0_COUNTERID6) = 0;
|
||||||
|
SYSCTR0(SYSCTR0_COUNTERID7) = 0;
|
||||||
|
SYSCTR0(SYSCTR0_COUNTERID8) = 0;
|
||||||
|
SYSCTR0(SYSCTR0_COUNTERID9) = 0;
|
||||||
|
SYSCTR0(SYSCTR0_COUNTERID10) = 0;
|
||||||
|
SYSCTR0(SYSCTR0_COUNTERID11) = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void hos_eks_get()
|
||||||
|
{
|
||||||
|
// Check if EKS already found and parsed.
|
||||||
|
if (!h_cfg.eks)
|
||||||
|
{
|
||||||
|
u8 *mbr = calloc(512 , 1);
|
||||||
|
|
||||||
|
// Read EKS blob.
|
||||||
|
sdmmc_storage_read(&sd_storage, 0, 1, mbr);
|
||||||
|
|
||||||
|
// Decrypt EKS blob.
|
||||||
|
hos_eks_mbr_t *eks = (hos_eks_mbr_t *)(mbr + 0x10);
|
||||||
|
se_aes_crypt_ecb(14, 0, eks, sizeof(hos_eks_mbr_t), eks, sizeof(hos_eks_mbr_t));
|
||||||
|
|
||||||
|
// Check if valid and for this unit.
|
||||||
|
if (eks->enabled &&
|
||||||
|
eks->magic == HOS_EKS_MAGIC &&
|
||||||
|
eks->magic2 == HOS_EKS_MAGIC &&
|
||||||
|
eks->sbk_low[0] == FUSE(FUSE_PRIVATE_KEY0) &&
|
||||||
|
eks->sbk_low[1] == FUSE(FUSE_PRIVATE_KEY1))
|
||||||
|
{
|
||||||
|
h_cfg.eks = eks;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(mbr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void hos_eks_save(u32 kb)
|
||||||
|
{
|
||||||
|
if (kb >= KB_FIRMWARE_VERSION_700)
|
||||||
|
{
|
||||||
|
// Only 6 Master keys for now.
|
||||||
|
u8 key_idx = kb - KB_FIRMWARE_VERSION_700;
|
||||||
|
if (key_idx > 5)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!h_cfg.eks)
|
||||||
|
h_cfg.eks = calloc(512 , 1);
|
||||||
|
|
||||||
|
// If matching blob doesn't exist, create it.
|
||||||
|
if (!(h_cfg.eks->enabled & (1 << key_idx)))
|
||||||
|
{
|
||||||
|
// Get keys.
|
||||||
|
u8 *keys = (u8 *)calloc(0x1000, 1);
|
||||||
|
se_get_aes_keys(keys + 0x800, keys, 0x10);
|
||||||
|
|
||||||
|
// Set magic and personalized info.
|
||||||
|
h_cfg.eks->magic = HOS_EKS_MAGIC;
|
||||||
|
h_cfg.eks->magic2 = HOS_EKS_MAGIC;
|
||||||
|
h_cfg.eks->enabled |= 1 << key_idx;
|
||||||
|
h_cfg.eks->sbk_low[0] = FUSE(FUSE_PRIVATE_KEY0);
|
||||||
|
h_cfg.eks->sbk_low[1] = FUSE(FUSE_PRIVATE_KEY1);
|
||||||
|
|
||||||
|
// Copy new keys.
|
||||||
|
memcpy(h_cfg.eks->keys[key_idx].dkg, keys + 10 * 0x10, 0x10);
|
||||||
|
memcpy(h_cfg.eks->keys[key_idx].mkk, keys + 12 * 0x10, 0x10);
|
||||||
|
memcpy(h_cfg.eks->keys[key_idx].fdk, keys + 13 * 0x10, 0x10);
|
||||||
|
memcpy(h_cfg.eks->keys[key_idx].dkk, keys + 15 * 0x10, 0x10);
|
||||||
|
|
||||||
|
// Encrypt EKS.
|
||||||
|
u8 *eks = calloc(512 , 1);
|
||||||
|
memcpy(eks, h_cfg.eks, sizeof(hos_eks_mbr_t));
|
||||||
|
se_aes_crypt_ecb(14, 1, eks, sizeof(hos_eks_mbr_t), eks, sizeof(hos_eks_mbr_t));
|
||||||
|
|
||||||
|
// Write EKS to SD.
|
||||||
|
u8 *mbr = calloc(512 , 1);
|
||||||
|
sdmmc_storage_read(&sd_storage, 0, 1, mbr);
|
||||||
|
memcpy(mbr + 0x10, eks, sizeof(hos_eks_mbr_t));
|
||||||
|
sdmmc_storage_write(&sd_storage, 0, 1, mbr);
|
||||||
|
|
||||||
|
free(eks);
|
||||||
|
free(mbr);
|
||||||
|
free(keys);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void hos_eks_clear(u32 kb)
|
||||||
|
{
|
||||||
|
if (h_cfg.eks && kb >= KB_FIRMWARE_VERSION_700)
|
||||||
|
{
|
||||||
|
// Check if Current Master key is enabled.
|
||||||
|
u8 key_idx = kb - KB_FIRMWARE_VERSION_700;
|
||||||
|
if (h_cfg.eks->enabled & (1 << key_idx))
|
||||||
|
{
|
||||||
|
// Disable current Master key version.
|
||||||
|
h_cfg.eks->enabled &= ~(1 << key_idx);
|
||||||
|
|
||||||
|
// Encrypt EKS.
|
||||||
|
u8 *eks = calloc(512 , 1);
|
||||||
|
memcpy(eks, h_cfg.eks, sizeof(hos_eks_mbr_t));
|
||||||
|
se_aes_crypt_ecb(14, 1, eks, sizeof(hos_eks_mbr_t), eks, sizeof(hos_eks_mbr_t));
|
||||||
|
|
||||||
|
// Write EKS to SD.
|
||||||
|
u8 *mbr = calloc(512 , 1);
|
||||||
|
sdmmc_storage_read(&sd_storage, 0, 1, mbr);
|
||||||
|
memcpy(mbr + 0x10, eks, sizeof(hos_eks_mbr_t));
|
||||||
|
sdmmc_storage_write(&sd_storage, 0, 1, mbr);
|
||||||
|
|
||||||
|
free(eks);
|
||||||
|
free(mbr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int hos_keygen(u8 *keyblob, u32 kb, tsec_ctxt_t *tsec_ctxt, launch_ctxt_t *hos_ctxt)
|
||||||
|
{
|
||||||
|
u8 tmp[0x20];
|
||||||
|
u32 retries = 0;
|
||||||
|
|
||||||
|
if (kb > KB_FIRMWARE_VERSION_MAX)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (kb <= KB_FIRMWARE_VERSION_600)
|
||||||
|
tsec_ctxt->size = 0xF00;
|
||||||
|
else if (kb == KB_FIRMWARE_VERSION_620)
|
||||||
|
tsec_ctxt->size = 0x2900;
|
||||||
|
else if (kb == KB_FIRMWARE_VERSION_700)
|
||||||
|
tsec_ctxt->size = 0x3000;
|
||||||
|
else
|
||||||
|
tsec_ctxt->size = 0x3300;
|
||||||
|
|
||||||
|
// Prepare smmu tsec page for 6.2.0.
|
||||||
|
if (kb == KB_FIRMWARE_VERSION_620)
|
||||||
|
{
|
||||||
|
u8 *tsec_paged = (u8 *)page_alloc(3);
|
||||||
|
memcpy(tsec_paged, (void *)tsec_ctxt->fw, tsec_ctxt->size);
|
||||||
|
tsec_ctxt->fw = tsec_paged;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get TSEC key.
|
||||||
|
if (kb <= KB_FIRMWARE_VERSION_620)
|
||||||
|
{
|
||||||
|
while (tsec_query(tmp, kb, tsec_ctxt) < 0)
|
||||||
|
{
|
||||||
|
memset(tmp, 0x00, 0x20);
|
||||||
|
retries++;
|
||||||
|
|
||||||
|
// We rely on racing conditions, make sure we cover even the unluckiest cases.
|
||||||
|
if (retries > 15)
|
||||||
|
{
|
||||||
|
_hos_crit_error("\nFailed to get TSEC keys. Please try again.");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (kb >= KB_FIRMWARE_VERSION_700)
|
||||||
|
{
|
||||||
|
// Use HOS EKS if it exists.
|
||||||
|
u8 key_idx = kb - KB_FIRMWARE_VERSION_700;
|
||||||
|
if (h_cfg.eks && (h_cfg.eks->enabled & (1 << key_idx)))
|
||||||
|
{
|
||||||
|
// Set Device keygen key to slot 10.
|
||||||
|
se_aes_key_set(10, h_cfg.eks->keys[key_idx].dkg, 0x10);
|
||||||
|
// Set Master key to slot 12.
|
||||||
|
se_aes_key_set(12, h_cfg.eks->keys[key_idx].mkk, 0x10);
|
||||||
|
// Set FW Device key key to slot 13.
|
||||||
|
se_aes_key_set(13, h_cfg.eks->keys[key_idx].fdk, 0x10);
|
||||||
|
// Set Device key to slot 15.
|
||||||
|
se_aes_key_set(15, h_cfg.eks->keys[key_idx].dkk, 0x10);
|
||||||
|
|
||||||
|
// Lock FDK.
|
||||||
|
se_key_acc_ctrl(13, SE_KEY_TBL_DIS_KEYREAD_FLAG | SE_KEY_TBL_DIS_OIVREAD_FLAG | SE_KEY_TBL_DIS_UIVREAD_FLAG);
|
||||||
|
}
|
||||||
|
|
||||||
|
se_aes_key_clear(8);
|
||||||
|
se_aes_unwrap_key(8, 12, package2_keyseed);
|
||||||
|
}
|
||||||
|
else if (kb == KB_FIRMWARE_VERSION_620)
|
||||||
|
{
|
||||||
|
// Set TSEC key.
|
||||||
|
se_aes_key_set(12, tmp, 0x10);
|
||||||
|
// Set TSEC root key.
|
||||||
|
se_aes_key_set(13, tmp + 0x10, 0x10);
|
||||||
|
|
||||||
|
if (!(emu_cfg.enabled && !h_cfg.emummc_force_disable) && hos_ctxt->stock)
|
||||||
|
{
|
||||||
|
// Package2 key.
|
||||||
|
se_aes_key_set(8, tmp + 0x10, 0x10);
|
||||||
|
se_aes_unwrap_key(8, 8, master_keyseed_620);
|
||||||
|
se_aes_unwrap_key(8, 8, master_keyseed_retail);
|
||||||
|
se_aes_unwrap_key(8, 8, package2_keyseed);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Decrypt keyblob and set keyslots
|
||||||
|
se_aes_crypt_block_ecb(12, 0, tmp + 0x20, keyblob_keyseeds[0]);
|
||||||
|
se_aes_unwrap_key(15, 14, tmp + 0x20);
|
||||||
|
se_aes_unwrap_key(14, 15, console_keyseed_4xx_5xx);
|
||||||
|
se_aes_unwrap_key(15, 15, console_keyseed);
|
||||||
|
|
||||||
|
se_aes_unwrap_key(13, 13, master_keyseed_620);
|
||||||
|
se_aes_unwrap_key(12, 13, master_keyseed_retail);
|
||||||
|
se_aes_unwrap_key(10, 13, master_keyseed_4xx_5xx_610);
|
||||||
|
|
||||||
|
// Package2 key.
|
||||||
|
se_aes_unwrap_key(8, 12, package2_keyseed);
|
||||||
|
|
||||||
|
h_cfg.se_keygen_done = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
se_key_acc_ctrl(13, SE_KEY_TBL_DIS_KEYREAD_FLAG | SE_KEY_TBL_DIS_OIVREAD_FLAG | SE_KEY_TBL_DIS_UIVREAD_FLAG);
|
||||||
|
se_key_acc_ctrl(14, SE_KEY_TBL_DIS_KEYREAD_FLAG | SE_KEY_TBL_DIS_OIVREAD_FLAG | SE_KEY_TBL_DIS_UIVREAD_FLAG);
|
||||||
|
|
||||||
|
// Set TSEC key.
|
||||||
|
se_aes_key_set(13, tmp, 0x10);
|
||||||
|
|
||||||
|
// Derive keyblob keys from TSEC+SBK.
|
||||||
|
se_aes_crypt_block_ecb(13, 0, tmp, keyblob_keyseeds[0]);
|
||||||
|
se_aes_unwrap_key(15, 14, tmp);
|
||||||
|
se_aes_crypt_block_ecb(13, 0, tmp, keyblob_keyseeds[kb]);
|
||||||
|
se_aes_unwrap_key(13, 14, tmp);
|
||||||
|
|
||||||
|
// Clear SBK.
|
||||||
|
se_aes_key_clear(14);
|
||||||
|
|
||||||
|
//TODO: verify keyblob CMAC.
|
||||||
|
//se_aes_unwrap_key(11, 13, cmac_keyseed);
|
||||||
|
//se_aes_cmac(tmp, 0x10, 11, keyblob + 0x10, 0xA0);
|
||||||
|
//if (!memcmp(keyblob, tmp, 0x10))
|
||||||
|
// return 0;
|
||||||
|
|
||||||
|
se_aes_crypt_block_ecb(13, 0, tmp, cmac_keyseed);
|
||||||
|
se_aes_unwrap_key(11, 13, cmac_keyseed);
|
||||||
|
|
||||||
|
// Decrypt keyblob and set keyslots.
|
||||||
|
se_aes_crypt_ctr(13, keyblob + 0x20, 0x90, keyblob + 0x20, 0x90, keyblob + 0x10);
|
||||||
|
se_aes_key_set(11, keyblob + 0x20 + 0x80, 0x10); // Package1 key.
|
||||||
|
se_aes_key_set(12, keyblob + 0x20, 0x10);
|
||||||
|
se_aes_key_set(13, keyblob + 0x20, 0x10);
|
||||||
|
|
||||||
|
se_aes_crypt_block_ecb(12, 0, tmp, master_keyseed_retail);
|
||||||
|
|
||||||
|
switch (kb)
|
||||||
|
{
|
||||||
|
case KB_FIRMWARE_VERSION_100_200:
|
||||||
|
case KB_FIRMWARE_VERSION_300:
|
||||||
|
case KB_FIRMWARE_VERSION_301:
|
||||||
|
se_aes_unwrap_key(13, 15, console_keyseed);
|
||||||
|
se_aes_unwrap_key(12, 12, master_keyseed_retail);
|
||||||
|
break;
|
||||||
|
case KB_FIRMWARE_VERSION_400:
|
||||||
|
se_aes_unwrap_key(13, 15, console_keyseed_4xx_5xx);
|
||||||
|
se_aes_unwrap_key(15, 15, console_keyseed);
|
||||||
|
se_aes_unwrap_key(14, 12, master_keyseed_4xx_5xx_610);
|
||||||
|
se_aes_unwrap_key(12, 12, master_keyseed_retail);
|
||||||
|
break;
|
||||||
|
case KB_FIRMWARE_VERSION_500:
|
||||||
|
case KB_FIRMWARE_VERSION_600:
|
||||||
|
se_aes_unwrap_key(10, 15, console_keyseed_4xx_5xx);
|
||||||
|
se_aes_unwrap_key(15, 15, console_keyseed);
|
||||||
|
se_aes_unwrap_key(14, 12, master_keyseed_4xx_5xx_610);
|
||||||
|
se_aes_unwrap_key(12, 12, master_keyseed_retail);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Package2 key.
|
||||||
|
se_key_acc_ctrl(8, SE_KEY_TBL_DIS_KEYREAD_FLAG | SE_KEY_TBL_DIS_OIVREAD_FLAG | SE_KEY_TBL_DIS_UIVREAD_FLAG);
|
||||||
|
se_aes_unwrap_key(8, 12, package2_keyseed);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _read_emmc_pkg1(launch_ctxt_t *ctxt)
|
||||||
|
{
|
||||||
|
sdmmc_storage_t storage;
|
||||||
|
sdmmc_t sdmmc;
|
||||||
|
|
||||||
|
int res = emummc_storage_init_mmc(&storage, &sdmmc);
|
||||||
|
|
||||||
|
if (res)
|
||||||
|
{
|
||||||
|
if (res == 2)
|
||||||
|
_hos_crit_error("Failed to init eMMC");
|
||||||
|
else
|
||||||
|
_hos_crit_error("Failed to init emuMMC");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read package1.
|
||||||
|
ctxt->pkg1 = (void *)malloc(0x40000);
|
||||||
|
emummc_storage_set_mmc_partition(&storage, EMMC_BOOT0);
|
||||||
|
emummc_storage_read(&storage, 0x100000 / NX_EMMC_BLOCKSIZE, 0x40000 / NX_EMMC_BLOCKSIZE, ctxt->pkg1);
|
||||||
|
ctxt->pkg1_id = pkg1_identify(ctxt->pkg1);
|
||||||
|
if (!ctxt->pkg1_id)
|
||||||
|
{
|
||||||
|
_hos_crit_error("Unknown pkg1 version.");
|
||||||
|
EHPRINTFARGS("%sNot yet supported HOS version!",
|
||||||
|
(emu_cfg.enabled && !h_cfg.emummc_force_disable) ? "Is emuMMC corrupt?\nOr " : "");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
gfx_printf("Identified pkg1 and Keyblob %d\n\n", ctxt->pkg1_id->kb);
|
||||||
|
|
||||||
|
// Read the correct keyblob.
|
||||||
|
ctxt->keyblob = (u8 *)calloc(NX_EMMC_BLOCKSIZE, 1);
|
||||||
|
emummc_storage_read(&storage, 0x180000 / NX_EMMC_BLOCKSIZE + ctxt->pkg1_id->kb, 1, ctxt->keyblob);
|
||||||
|
|
||||||
|
res = 1;
|
||||||
|
|
||||||
|
out:;
|
||||||
|
sdmmc_storage_end(&storage);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static u8 *_read_emmc_pkg2(launch_ctxt_t *ctxt)
|
||||||
|
{
|
||||||
|
u8 *bctBuf = NULL;
|
||||||
|
sdmmc_storage_t storage;
|
||||||
|
sdmmc_t sdmmc;
|
||||||
|
|
||||||
|
int res = emummc_storage_init_mmc(&storage, &sdmmc);
|
||||||
|
|
||||||
|
if (res)
|
||||||
|
{
|
||||||
|
if (res == 2)
|
||||||
|
_hos_crit_error("Failed to init eMMC");
|
||||||
|
else
|
||||||
|
_hos_crit_error("Failed to init emuMMC");
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
emummc_storage_set_mmc_partition(&storage, EMMC_GPP);
|
||||||
|
|
||||||
|
// Parse eMMC GPT.
|
||||||
|
LIST_INIT(gpt);
|
||||||
|
nx_emmc_gpt_parse(&gpt, &storage);
|
||||||
|
DPRINTF("Parsed GPT\n");
|
||||||
|
// Find package2 partition.
|
||||||
|
emmc_part_t *pkg2_part = nx_emmc_part_find(&gpt, "BCPKG2-1-Normal-Main");
|
||||||
|
if (!pkg2_part)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
// Read in package2 header and get package2 real size.
|
||||||
|
//TODO: implement memalign for DMA buffers.
|
||||||
|
static const u32 BCT_SIZE = 0x4000;
|
||||||
|
bctBuf = (u8 *)malloc(BCT_SIZE);
|
||||||
|
nx_emmc_part_read(&storage, pkg2_part, BCT_SIZE / NX_EMMC_BLOCKSIZE, 1, bctBuf);
|
||||||
|
u32 *hdr = (u32 *)(bctBuf + 0x100);
|
||||||
|
u32 pkg2_size = hdr[0] ^ hdr[2] ^ hdr[3];
|
||||||
|
DPRINTF("pkg2 size on emmc is %08X\n", pkg2_size);
|
||||||
|
|
||||||
|
// Read in Boot Config.
|
||||||
|
memset(bctBuf, 0, BCT_SIZE);
|
||||||
|
nx_emmc_part_read(&storage, pkg2_part, 0, BCT_SIZE / NX_EMMC_BLOCKSIZE, bctBuf);
|
||||||
|
|
||||||
|
// Read in package2.
|
||||||
|
u32 pkg2_size_aligned = ALIGN(pkg2_size, NX_EMMC_BLOCKSIZE);
|
||||||
|
DPRINTF("pkg2 size aligned is %08X\n", pkg2_size_aligned);
|
||||||
|
ctxt->pkg2 = malloc(pkg2_size_aligned);
|
||||||
|
ctxt->pkg2_size = pkg2_size;
|
||||||
|
nx_emmc_part_read(&storage, pkg2_part, BCT_SIZE / NX_EMMC_BLOCKSIZE,
|
||||||
|
pkg2_size_aligned / NX_EMMC_BLOCKSIZE, ctxt->pkg2);
|
||||||
|
out:;
|
||||||
|
nx_emmc_gpt_free(&gpt);
|
||||||
|
sdmmc_storage_end(&storage);
|
||||||
|
|
||||||
|
return bctBuf;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _free_launch_components(launch_ctxt_t *ctxt)
|
||||||
|
{
|
||||||
|
free(ctxt->keyblob);
|
||||||
|
free(ctxt->pkg1);
|
||||||
|
free(ctxt->pkg2);
|
||||||
|
free(ctxt->warmboot);
|
||||||
|
free(ctxt->secmon);
|
||||||
|
free(ctxt->kernel);
|
||||||
|
free(ctxt->kip1_patches);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool _get_fs_exfat_compatible(link_t *info)
|
||||||
|
{
|
||||||
|
u32 fs_idx;
|
||||||
|
u32 fs_ids_cnt;
|
||||||
|
u32 sha_buf[32 / sizeof(u32)];
|
||||||
|
kip1_id_t *kip_ids;
|
||||||
|
|
||||||
|
LIST_FOREACH_ENTRY(pkg2_kip1_info_t, ki, info, link)
|
||||||
|
{
|
||||||
|
if (strncmp((const char*)ki->kip1->name, "FS", 2))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!se_calc_sha256(sha_buf, ki->kip1, ki->size))
|
||||||
|
break;
|
||||||
|
|
||||||
|
pkg2_get_ids(&kip_ids, &fs_ids_cnt);
|
||||||
|
|
||||||
|
for (fs_idx = 0; fs_idx < fs_ids_cnt; fs_idx++)
|
||||||
|
if (!memcmp(sha_buf, kip_ids[fs_idx].hash, 8))
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Return false if FAT32 only.
|
||||||
|
if (fs_ids_cnt <= fs_idx && !(fs_idx & 1))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int hos_launch(ini_sec_t *cfg)
|
||||||
|
{
|
||||||
|
minerva_change_freq(FREQ_1600);
|
||||||
|
launch_ctxt_t ctxt;
|
||||||
|
tsec_ctxt_t tsec_ctxt;
|
||||||
|
volatile secmon_mailbox_t *secmon_mb;
|
||||||
|
|
||||||
|
memset(&ctxt, 0, sizeof(launch_ctxt_t));
|
||||||
|
memset(&tsec_ctxt, 0, sizeof(tsec_ctxt_t));
|
||||||
|
list_init(&ctxt.kip1_list);
|
||||||
|
|
||||||
|
ctxt.cfg = cfg;
|
||||||
|
|
||||||
|
if (!gfx_con.mute)
|
||||||
|
gfx_clear_grey(0x1B);
|
||||||
|
gfx_con_setpos(0, 0);
|
||||||
|
|
||||||
|
gfx_printf("Initializing...\n\n");
|
||||||
|
|
||||||
|
// Read package1 and the correct keyblob.
|
||||||
|
if (!_read_emmc_pkg1(&ctxt))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// Try to parse config if present.
|
||||||
|
if (ctxt.cfg && !parse_boot_config(&ctxt))
|
||||||
|
{
|
||||||
|
_hos_crit_error("Wrong ini cfg or missing files!");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enable emummc patching.
|
||||||
|
if (emu_cfg.enabled && !h_cfg.emummc_force_disable)
|
||||||
|
{
|
||||||
|
if (ctxt.stock)
|
||||||
|
{
|
||||||
|
_hos_crit_error("Stock emuMMC is not supported yet!");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctxt.atmosphere = true; // Set atmosphere patching in case of Stock emuMMC and no fss0.
|
||||||
|
config_kip1patch(&ctxt, "emummc");
|
||||||
|
}
|
||||||
|
else if (!emu_cfg.enabled && ctxt.emummc_forced)
|
||||||
|
{
|
||||||
|
_hos_crit_error("emuMMC is forced but not enabled!");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if fuses lower than 4.0.0 or 9.0.0 and if yes apply NO Gamecard patch.
|
||||||
|
// Additionally check if running emuMMC and disable GC if v3 fuses are burnt and HOS is <= 8.1.0.
|
||||||
|
if (!ctxt.stock)
|
||||||
|
{
|
||||||
|
u32 fuses = fuse_read_odm(7);
|
||||||
|
if ((h_cfg.autonogc &&
|
||||||
|
((!(fuses & ~0xF) && (ctxt.pkg1_id->kb >= KB_FIRMWARE_VERSION_400)) || // LAFW v2.
|
||||||
|
(!(fuses & ~0x3FF) && (ctxt.pkg1_id->kb >= KB_FIRMWARE_VERSION_900)))) // LAFW v3.
|
||||||
|
|| ((emu_cfg.enabled && !h_cfg.emummc_force_disable) &&
|
||||||
|
((fuses & 0x400) && (ctxt.pkg1_id->kb <= KB_FIRMWARE_VERSION_810))))
|
||||||
|
config_kip1patch(&ctxt, "nogc");
|
||||||
|
}
|
||||||
|
|
||||||
|
gfx_printf("Loaded config, pkg1 and keyblob\n");
|
||||||
|
|
||||||
|
// Generate keys.
|
||||||
|
if (!h_cfg.se_keygen_done)
|
||||||
|
{
|
||||||
|
tsec_ctxt.fw = (u8 *)ctxt.pkg1 + ctxt.pkg1_id->tsec_off;
|
||||||
|
tsec_ctxt.pkg1 = ctxt.pkg1;
|
||||||
|
tsec_ctxt.pkg11_off = ctxt.pkg1_id->pkg11_off;
|
||||||
|
tsec_ctxt.secmon_base = ctxt.pkg1_id->secmon_base;
|
||||||
|
|
||||||
|
if (ctxt.pkg1_id->kb >= KB_FIRMWARE_VERSION_700 && !h_cfg.sept_run)
|
||||||
|
{
|
||||||
|
_hos_crit_error("Failed to run sept");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hos_keygen(ctxt.keyblob, ctxt.pkg1_id->kb, &tsec_ctxt, &ctxt))
|
||||||
|
return 0;
|
||||||
|
gfx_printf("Generated keys\n");
|
||||||
|
if (ctxt.pkg1_id->kb <= KB_FIRMWARE_VERSION_600)
|
||||||
|
h_cfg.se_keygen_done = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decrypt and unpack package1 if we require parts of it.
|
||||||
|
if (!ctxt.warmboot || !ctxt.secmon)
|
||||||
|
{
|
||||||
|
if (ctxt.pkg1_id->kb <= KB_FIRMWARE_VERSION_600)
|
||||||
|
pkg1_decrypt(ctxt.pkg1_id, ctxt.pkg1);
|
||||||
|
|
||||||
|
if (ctxt.pkg1_id->kb <= KB_FIRMWARE_VERSION_620 && !(emu_cfg.enabled && !h_cfg.emummc_force_disable))
|
||||||
|
{
|
||||||
|
pkg1_unpack((void *)ctxt.pkg1_id->warmboot_base, (void *)ctxt.pkg1_id->secmon_base, NULL, ctxt.pkg1_id, ctxt.pkg1);
|
||||||
|
gfx_printf("Decrypted & unpacked pkg1\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_hos_crit_error("No mandatory secmon or warmboot provided!");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Replace 'warmboot.bin' if requested.
|
||||||
|
if (ctxt.warmboot)
|
||||||
|
memcpy((void *)ctxt.pkg1_id->warmboot_base, ctxt.warmboot, ctxt.warmboot_size);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (ctxt.pkg1_id->kb >= KB_FIRMWARE_VERSION_700)
|
||||||
|
{
|
||||||
|
_hos_crit_error("No warmboot provided!");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
// Else we patch it to allow downgrading.
|
||||||
|
patch_t *warmboot_patchset = ctxt.pkg1_id->warmboot_patchset;
|
||||||
|
gfx_printf("%kPatching Warmboot%k\n", 0xFFFFBA00, 0xFFCCCCCC);
|
||||||
|
for (u32 i = 0; warmboot_patchset[i].off != 0xFFFFFFFF; i++)
|
||||||
|
*(vu32 *)(ctxt.pkg1_id->warmboot_base + warmboot_patchset[i].off) = warmboot_patchset[i].val;
|
||||||
|
}
|
||||||
|
// Set warmboot address in PMC if required.
|
||||||
|
if (ctxt.pkg1_id->set_warmboot)
|
||||||
|
PMC(APBDEV_PMC_SCRATCH1) = ctxt.pkg1_id->warmboot_base;
|
||||||
|
|
||||||
|
// Replace 'SecureMonitor' if requested.
|
||||||
|
if (ctxt.secmon)
|
||||||
|
memcpy((void *)ctxt.pkg1_id->secmon_base, ctxt.secmon, ctxt.secmon_size);
|
||||||
|
else if (ctxt.pkg1_id->secmon_patchset)
|
||||||
|
{
|
||||||
|
// Else we patch it to allow for an unsigned package2 and patched kernel.
|
||||||
|
patch_t *secmon_patchset = ctxt.pkg1_id->secmon_patchset;
|
||||||
|
gfx_printf("%kPatching Secure Monitor%k\n", 0xFFFFBA00, 0xFFCCCCCC);
|
||||||
|
for (u32 i = 0; secmon_patchset[i].off != 0xFFFFFFFF; i++)
|
||||||
|
*(vu32 *)(ctxt.pkg1_id->secmon_base + secmon_patchset[i].off) = secmon_patchset[i].val;
|
||||||
|
}
|
||||||
|
|
||||||
|
gfx_printf("Loaded warmboot and secmon\n");
|
||||||
|
|
||||||
|
// Read package2.
|
||||||
|
u8 *bootConfigBuf = _read_emmc_pkg2(&ctxt);
|
||||||
|
if (!bootConfigBuf)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
gfx_printf("Read pkg2\n");
|
||||||
|
|
||||||
|
// Decrypt package2 and parse KIP1 blobs in INI1 section.
|
||||||
|
pkg2_hdr_t *pkg2_hdr = pkg2_decrypt(ctxt.pkg2, ctxt.pkg1_id->kb);
|
||||||
|
if (!pkg2_hdr)
|
||||||
|
{
|
||||||
|
_hos_crit_error("Pkg2 decryption failed!");
|
||||||
|
if (ctxt.pkg1_id->kb >= KB_FIRMWARE_VERSION_700)
|
||||||
|
{
|
||||||
|
EPRINTF("Is Sept updated?");
|
||||||
|
|
||||||
|
// Clear EKS slot, in case something went wrong with sept keygen.
|
||||||
|
hos_eks_clear(ctxt.pkg1_id->kb);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else if (ctxt.pkg1_id->kb >= KB_FIRMWARE_VERSION_700)
|
||||||
|
hos_eks_save(ctxt.pkg1_id->kb); // Save EKS slot if it doesn't exist.
|
||||||
|
|
||||||
|
LIST_INIT(kip1_info);
|
||||||
|
if (!pkg2_parse_kips(&kip1_info, pkg2_hdr, &ctxt.new_pkg2))
|
||||||
|
{
|
||||||
|
_hos_crit_error("INI1 parsing failed!");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
gfx_printf("Parsed ini1\n");
|
||||||
|
|
||||||
|
// Use the kernel included in package2 in case we didn't load one already.
|
||||||
|
if (!ctxt.kernel)
|
||||||
|
{
|
||||||
|
ctxt.kernel = pkg2_hdr->data;
|
||||||
|
ctxt.kernel_size = pkg2_hdr->sec_size[PKG2_SEC_KERNEL];
|
||||||
|
|
||||||
|
if (!ctxt.stock && (ctxt.svcperm || ctxt.debugmode || ctxt.atmosphere))
|
||||||
|
{
|
||||||
|
u8 kernel_hash[0x20];
|
||||||
|
// Hash only Kernel when it embeds INI1.
|
||||||
|
if (!ctxt.new_pkg2)
|
||||||
|
se_calc_sha256(kernel_hash, ctxt.kernel, ctxt.kernel_size);
|
||||||
|
else
|
||||||
|
se_calc_sha256(kernel_hash, ctxt.kernel + PKG2_NEWKERN_START,
|
||||||
|
pkg2_newkern_ini1_start - PKG2_NEWKERN_START);
|
||||||
|
|
||||||
|
ctxt.pkg2_kernel_id = pkg2_identify(kernel_hash);
|
||||||
|
if (!ctxt.pkg2_kernel_id)
|
||||||
|
{
|
||||||
|
_hos_crit_error("Failed to identify kernel!");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// In case a kernel patch option is set; allows to disable SVC verification or/and enable debug mode.
|
||||||
|
kernel_patch_t *kernel_patchset = ctxt.pkg2_kernel_id->kernel_patchset;
|
||||||
|
if (kernel_patchset != NULL)
|
||||||
|
{
|
||||||
|
gfx_printf("%kPatching kernel%k\n", 0xFFFFBA00, 0xFFCCCCCC);
|
||||||
|
u32 *temp;
|
||||||
|
for (u32 i = 0; kernel_patchset[i].id != 0xFFFFFFFF; i++)
|
||||||
|
{
|
||||||
|
if ((ctxt.svcperm && kernel_patchset[i].id == SVC_VERIFY_DS)
|
||||||
|
|| (ctxt.debugmode && kernel_patchset[i].id == DEBUG_MODE_EN && !(ctxt.atmosphere && ctxt.secmon))
|
||||||
|
|| (ctxt.atmosphere && kernel_patchset[i].id == ATM_GEN_PATCH))
|
||||||
|
*(vu32 *)(ctxt.kernel + kernel_patchset[i].off) = kernel_patchset[i].val;
|
||||||
|
else if (ctxt.atmosphere && kernel_patchset[i].id == ATM_ARR_PATCH)
|
||||||
|
{
|
||||||
|
temp = (u32 *)kernel_patchset[i].ptr;
|
||||||
|
for (u32 j = 0; j < kernel_patchset[i].val; j++)
|
||||||
|
*(vu32 *)(ctxt.kernel + kernel_patchset[i].off + (j << 2)) = temp[j];
|
||||||
|
}
|
||||||
|
else if (kernel_patchset[i].id < SVC_VERIFY_DS)
|
||||||
|
*(vu32 *)(ctxt.kernel + kernel_patchset[i].off) = kernel_patchset[i].val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Merge extra KIP1s into loaded ones.
|
||||||
|
gfx_printf("%kPatching kips%k\n", 0xFFFFBA00, 0xFFCCCCCC);
|
||||||
|
LIST_FOREACH_ENTRY(merge_kip_t, mki, &ctxt.kip1_list, link)
|
||||||
|
pkg2_merge_kip(&kip1_info, (pkg2_kip1_t *)mki->kip1);
|
||||||
|
|
||||||
|
// Check if FS is compatible with exFAT.
|
||||||
|
if (!ctxt.stock && sd_fs.fs_type == FS_EXFAT && !_get_fs_exfat_compatible(&kip1_info))
|
||||||
|
{
|
||||||
|
_hos_crit_error("SD Card is exFAT and the installed\nFS only supports FAT32!");
|
||||||
|
|
||||||
|
_free_launch_components(&ctxt);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Patch kip1s in memory if needed.
|
||||||
|
const char* unappliedPatch = pkg2_patch_kips(&kip1_info, ctxt.kip1_patches);
|
||||||
|
if (unappliedPatch != NULL)
|
||||||
|
{
|
||||||
|
EHPRINTFARGS("Failed to apply '%s'!", unappliedPatch);
|
||||||
|
|
||||||
|
_free_launch_components(&ctxt);
|
||||||
|
return 0; // MUST stop here, because if user requests 'nogc' but it's not applied, their GC controller gets updated!
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rebuild and encrypt package2.
|
||||||
|
pkg2_build_encrypt((void *)PKG2_LOAD_ADDR, ctxt.kernel, ctxt.kernel_size, &kip1_info, ctxt.new_pkg2);
|
||||||
|
|
||||||
|
gfx_printf("Rebuilt & loaded pkg2\n");
|
||||||
|
|
||||||
|
// Unmount SD card.
|
||||||
|
sd_unmount();
|
||||||
|
|
||||||
|
gfx_printf("\n%kBooting...%k\n", 0xFF96FF00, 0xFFCCCCCC);
|
||||||
|
|
||||||
|
// Clear pkg1/pkg2 keys.
|
||||||
|
se_aes_key_clear(8);
|
||||||
|
se_aes_key_clear(11);
|
||||||
|
|
||||||
|
// Finalize per firmware keys.
|
||||||
|
int bootStateDramPkg2 = 0;
|
||||||
|
int bootStatePkg2Continue = 0;
|
||||||
|
|
||||||
|
switch (ctxt.pkg1_id->kb)
|
||||||
|
{
|
||||||
|
case KB_FIRMWARE_VERSION_100_200:
|
||||||
|
case KB_FIRMWARE_VERSION_300:
|
||||||
|
case KB_FIRMWARE_VERSION_301:
|
||||||
|
if (ctxt.pkg1_id->kb == KB_FIRMWARE_VERSION_300)
|
||||||
|
PMC(APBDEV_PMC_SECURE_SCRATCH32) = 0xE3; // Warmboot 3.0.0 PA address id.
|
||||||
|
else if (ctxt.pkg1_id->kb == KB_FIRMWARE_VERSION_301)
|
||||||
|
PMC(APBDEV_PMC_SECURE_SCRATCH32) = 0x104; // Warmboot 3.0.1/.2 PA address id.
|
||||||
|
se_key_acc_ctrl(12, SE_KEY_TBL_DIS_KEY_ACCESS_FLAG | SE_KEY_TBL_DIS_KEY_LOCK_FLAG);
|
||||||
|
se_key_acc_ctrl(13, SE_KEY_TBL_DIS_KEY_ACCESS_FLAG | SE_KEY_TBL_DIS_KEY_LOCK_FLAG);
|
||||||
|
bootStateDramPkg2 = 2;
|
||||||
|
bootStatePkg2Continue = 3;
|
||||||
|
break;
|
||||||
|
case KB_FIRMWARE_VERSION_400:
|
||||||
|
case KB_FIRMWARE_VERSION_500:
|
||||||
|
case KB_FIRMWARE_VERSION_600:
|
||||||
|
se_key_acc_ctrl(12, SE_KEY_TBL_DIS_KEY_ACCESS_FLAG | SE_KEY_TBL_DIS_KEY_LOCK_FLAG);
|
||||||
|
se_key_acc_ctrl(15, SE_KEY_TBL_DIS_KEY_ACCESS_FLAG | SE_KEY_TBL_DIS_KEY_LOCK_FLAG);
|
||||||
|
default:
|
||||||
|
bootStateDramPkg2 = 2;
|
||||||
|
bootStatePkg2Continue = 4;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear BCT area for retail units and copy it over if dev unit.
|
||||||
|
if (ctxt.pkg1_id->kb <= KB_FIRMWARE_VERSION_500)
|
||||||
|
{
|
||||||
|
memset((void *)0x4003D000, 0, 0x3000);
|
||||||
|
if ((fuse_read_odm(4) & 3) == 3)
|
||||||
|
memcpy((void *)0x4003D000, bootConfigBuf, 0x1000);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
memset((void *)0x4003F000, 0, 0x1000);
|
||||||
|
if ((fuse_read_odm(4) & 3) == 3)
|
||||||
|
memcpy((void *)0x4003F800, bootConfigBuf, 0x800);
|
||||||
|
}
|
||||||
|
free(bootConfigBuf);
|
||||||
|
|
||||||
|
// Config Exosphère if booting full Atmosphère.
|
||||||
|
if (ctxt.atmosphere && ctxt.secmon)
|
||||||
|
config_exosphere(&ctxt);
|
||||||
|
|
||||||
|
// Finalize MC carveout.
|
||||||
|
if (ctxt.pkg1_id->kb <= KB_FIRMWARE_VERSION_301)
|
||||||
|
mc_config_carveout();
|
||||||
|
|
||||||
|
// Lock SE before starting 'SecureMonitor' if < 6.2.0, otherwise lock bootrom and ipatches.
|
||||||
|
_se_lock(ctxt.pkg1_id->kb <= KB_FIRMWARE_VERSION_600);
|
||||||
|
|
||||||
|
// Reset sysctr0 counters.
|
||||||
|
if (ctxt.pkg1_id->kb >= KB_FIRMWARE_VERSION_620)
|
||||||
|
_sysctr0_reset();
|
||||||
|
|
||||||
|
// < 4.0.0 pkg1.1 locks PMC scratches.
|
||||||
|
//_pmc_scratch_lock(ctxt.pkg1_id->kb);
|
||||||
|
|
||||||
|
// Set secmon mailbox address.
|
||||||
|
if (ctxt.pkg1_id->kb >= KB_FIRMWARE_VERSION_700)
|
||||||
|
secmon_mb = (secmon_mailbox_t *)SECMON7_MB_ADDR;
|
||||||
|
else
|
||||||
|
secmon_mb = (secmon_mailbox_t *)SECMON_MB_ADDR;
|
||||||
|
|
||||||
|
// Start from DRAM ready signal and reset outgoing value.
|
||||||
|
secmon_mb->in = bootStateDramPkg2;
|
||||||
|
secmon_mb->out = 0;
|
||||||
|
|
||||||
|
// Disable display. This must be executed before secmon to provide support for all fw versions.
|
||||||
|
display_end();
|
||||||
|
|
||||||
|
// Clear EMC_SCRATCH0.
|
||||||
|
EMC(EMC_SCRATCH0) = 0;
|
||||||
|
|
||||||
|
// Flush cache and disable MMU.
|
||||||
|
bpmp_mmu_disable();
|
||||||
|
bpmp_clk_rate_set(BPMP_CLK_NORMAL);
|
||||||
|
minerva_change_freq(FREQ_1600);
|
||||||
|
|
||||||
|
// emuMMC: Some cards (Sandisk U1), do not like a fast power cycle. Wait min 100ms.
|
||||||
|
sdmmc_storage_init_wait_sd();
|
||||||
|
|
||||||
|
// Wait for secmon to get ready.
|
||||||
|
if (smmu_is_used())
|
||||||
|
smmu_exit();
|
||||||
|
else
|
||||||
|
cluster_boot_cpu0(ctxt.pkg1_id->secmon_base);
|
||||||
|
while (!secmon_mb->out)
|
||||||
|
; // A usleep(1) only works when in IRAM or with a trained DRAM.
|
||||||
|
|
||||||
|
// Signal pkg2 ready and continue boot.
|
||||||
|
secmon_mb->in = bootStatePkg2Continue;
|
||||||
|
|
||||||
|
// Halt ourselves in waitevent state and resume if there's JTAG activity.
|
||||||
|
while (true)
|
||||||
|
bpmp_halt();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
120
source/hos/hos.h
Normal file
120
source/hos/hos.h
Normal file
@@ -0,0 +1,120 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2018 naehrwert
|
||||||
|
* Copyright (c) 2018-2020 CTCaer
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _HOS_H_
|
||||||
|
#define _HOS_H_
|
||||||
|
|
||||||
|
#include "pkg1.h"
|
||||||
|
#include "pkg2.h"
|
||||||
|
#include "../utils/types.h"
|
||||||
|
#include "../config/ini.h"
|
||||||
|
#include "../sec/tsec.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#define KB_FIRMWARE_VERSION_100_200 0
|
||||||
|
#define KB_FIRMWARE_VERSION_300 1
|
||||||
|
#define KB_FIRMWARE_VERSION_301 2
|
||||||
|
#define KB_FIRMWARE_VERSION_400 3
|
||||||
|
#define KB_FIRMWARE_VERSION_500 4
|
||||||
|
#define KB_FIRMWARE_VERSION_600 5
|
||||||
|
#define KB_FIRMWARE_VERSION_620 6
|
||||||
|
#define KB_FIRMWARE_VERSION_700 7
|
||||||
|
#define KB_FIRMWARE_VERSION_810 8
|
||||||
|
#define KB_FIRMWARE_VERSION_900 9
|
||||||
|
#define KB_FIRMWARE_VERSION_910 10
|
||||||
|
#define KB_FIRMWARE_VERSION_MAX KB_FIRMWARE_VERSION_910
|
||||||
|
|
||||||
|
#define HOS_PKG11_MAGIC 0x31314B50
|
||||||
|
#define HOS_EKS_MAGIC 0x30534B45
|
||||||
|
|
||||||
|
typedef struct _exo_ctxt_t
|
||||||
|
{
|
||||||
|
bool no_user_exceptions;
|
||||||
|
bool user_pmu;
|
||||||
|
bool *cal0_blank;
|
||||||
|
bool *cal0_allow_writes_sys;
|
||||||
|
} exo_ctxt_t;
|
||||||
|
|
||||||
|
typedef struct _hos_eks_keys_t
|
||||||
|
{
|
||||||
|
u8 dkg[0x10];
|
||||||
|
u8 mkk[0x10];
|
||||||
|
u8 fdk[0x10];
|
||||||
|
u8 dkk[0x10];
|
||||||
|
} hos_eks_keys_t;
|
||||||
|
|
||||||
|
typedef struct _hos_eks_mbr_t
|
||||||
|
{
|
||||||
|
u32 magic;
|
||||||
|
u32 enabled;
|
||||||
|
u32 sbk_low[2];
|
||||||
|
hos_eks_keys_t keys[6];
|
||||||
|
u32 magic2;
|
||||||
|
u32 rsvd2[3];
|
||||||
|
} hos_eks_mbr_t;
|
||||||
|
|
||||||
|
static_assert(sizeof(hos_eks_mbr_t) < 424, "HOS EKS storage bigger than MBR!");
|
||||||
|
|
||||||
|
typedef struct _launch_ctxt_t
|
||||||
|
{
|
||||||
|
void *keyblob;
|
||||||
|
|
||||||
|
void *pkg1;
|
||||||
|
const pkg1_id_t *pkg1_id;
|
||||||
|
const pkg2_kernel_id_t *pkg2_kernel_id;
|
||||||
|
|
||||||
|
void *warmboot;
|
||||||
|
u32 warmboot_size;
|
||||||
|
void *secmon;
|
||||||
|
u32 secmon_size;
|
||||||
|
|
||||||
|
void *pkg2;
|
||||||
|
u32 pkg2_size;
|
||||||
|
bool new_pkg2;
|
||||||
|
|
||||||
|
void *kernel;
|
||||||
|
u32 kernel_size;
|
||||||
|
link_t kip1_list;
|
||||||
|
char* kip1_patches;
|
||||||
|
|
||||||
|
u32 fss0_hosver;
|
||||||
|
bool svcperm;
|
||||||
|
bool debugmode;
|
||||||
|
bool stock;
|
||||||
|
bool atmosphere;
|
||||||
|
bool fss0_enable_experimental;
|
||||||
|
bool emummc_forced;
|
||||||
|
|
||||||
|
exo_ctxt_t exo_cfg;
|
||||||
|
|
||||||
|
ini_sec_t *cfg;
|
||||||
|
} launch_ctxt_t;
|
||||||
|
|
||||||
|
typedef struct _merge_kip_t
|
||||||
|
{
|
||||||
|
void *kip1;
|
||||||
|
link_t link;
|
||||||
|
} merge_kip_t;
|
||||||
|
|
||||||
|
void hos_eks_get();
|
||||||
|
void hos_eks_save(u32 kb);
|
||||||
|
void hos_eks_clear(u32 kb);
|
||||||
|
int hos_launch(ini_sec_t *cfg);
|
||||||
|
int hos_keygen(u8 *keyblob, u32 kb, tsec_ctxt_t *tsec_ctxt, launch_ctxt_t *hos_ctxt);
|
||||||
|
|
||||||
|
#endif
|
||||||
309
source/hos/hos_config.c
Normal file
309
source/hos/hos_config.c
Normal file
@@ -0,0 +1,309 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2018 naehrwert
|
||||||
|
* Copyright (c) 2018-2020 CTCaer
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "hos.h"
|
||||||
|
#include "hos_config.h"
|
||||||
|
#include "fss.h"
|
||||||
|
#include "../libs/fatfs/ff.h"
|
||||||
|
#include "../mem/heap.h"
|
||||||
|
#include "../storage/nx_sd.h"
|
||||||
|
#include "../utils/dirlist.h"
|
||||||
|
|
||||||
|
#include "../gfx/gfx.h"
|
||||||
|
|
||||||
|
//#define DPRINTF(...) gfx_printf(__VA_ARGS__)
|
||||||
|
#define DPRINTF(...)
|
||||||
|
|
||||||
|
static int _config_warmboot(launch_ctxt_t *ctxt, const char *value)
|
||||||
|
{
|
||||||
|
ctxt->warmboot = sd_file_read(value, &ctxt->warmboot_size);
|
||||||
|
if (!ctxt->warmboot)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _config_secmon(launch_ctxt_t *ctxt, const char *value)
|
||||||
|
{
|
||||||
|
ctxt->secmon = sd_file_read(value, &ctxt->secmon_size);
|
||||||
|
if (!ctxt->secmon)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _config_kernel(launch_ctxt_t *ctxt, const char *value)
|
||||||
|
{
|
||||||
|
ctxt->kernel = sd_file_read(value, &ctxt->kernel_size);
|
||||||
|
if (!ctxt->kernel)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _config_kip1(launch_ctxt_t *ctxt, const char *value)
|
||||||
|
{
|
||||||
|
u32 size;
|
||||||
|
|
||||||
|
if (!memcmp(value + strlen(value) - 1, "*", 1))
|
||||||
|
{
|
||||||
|
char *dir = (char *)malloc(256);
|
||||||
|
strcpy(dir, value);
|
||||||
|
|
||||||
|
u32 dirlen = 0;
|
||||||
|
dir[strlen(dir) - 2] = 0;
|
||||||
|
char *filelist = dirlist(dir, "*.kip*", false);
|
||||||
|
|
||||||
|
strcat(dir, "/");
|
||||||
|
dirlen = strlen(dir);
|
||||||
|
|
||||||
|
u32 i = 0;
|
||||||
|
if (filelist)
|
||||||
|
{
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
if (!filelist[i * 256])
|
||||||
|
break;
|
||||||
|
|
||||||
|
strcpy(dir + dirlen, &filelist[i * 256]);
|
||||||
|
|
||||||
|
merge_kip_t *mkip1 = (merge_kip_t *)malloc(sizeof(merge_kip_t));
|
||||||
|
mkip1->kip1 = sd_file_read(dir, &size);
|
||||||
|
if (!mkip1->kip1)
|
||||||
|
{
|
||||||
|
free(mkip1);
|
||||||
|
free(dir);
|
||||||
|
free(filelist);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
DPRINTF("Loaded kip1 from SD (size %08X)\n", size);
|
||||||
|
list_append(&ctxt->kip1_list, &mkip1->link);
|
||||||
|
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
free(dir);
|
||||||
|
free(filelist);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
merge_kip_t *mkip1 = (merge_kip_t *)malloc(sizeof(merge_kip_t));
|
||||||
|
mkip1->kip1 = sd_file_read(value, &size);
|
||||||
|
if (!mkip1->kip1)
|
||||||
|
{
|
||||||
|
free(mkip1);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
DPRINTF("Loaded kip1 from SD (size %08X)\n", size);
|
||||||
|
list_append(&ctxt->kip1_list, &mkip1->link);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int config_kip1patch(launch_ctxt_t *ctxt, const char *value)
|
||||||
|
{
|
||||||
|
if (value == NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
int valueLen = strlen(value);
|
||||||
|
if (!valueLen)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (ctxt->kip1_patches == NULL)
|
||||||
|
{
|
||||||
|
ctxt->kip1_patches = malloc(valueLen + 1);
|
||||||
|
memcpy(ctxt->kip1_patches, value, valueLen);
|
||||||
|
ctxt->kip1_patches[valueLen] = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
char *oldAlloc = ctxt->kip1_patches;
|
||||||
|
int oldSize = strlen(oldAlloc);
|
||||||
|
ctxt->kip1_patches = malloc(oldSize + 1 + valueLen + 1);
|
||||||
|
memcpy(ctxt->kip1_patches, oldAlloc, oldSize);
|
||||||
|
free(oldAlloc);
|
||||||
|
oldAlloc = NULL;
|
||||||
|
ctxt->kip1_patches[oldSize++] = ',';
|
||||||
|
memcpy(&ctxt->kip1_patches[oldSize], value, valueLen);
|
||||||
|
ctxt->kip1_patches[oldSize + valueLen] = 0;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _config_svcperm(launch_ctxt_t *ctxt, const char *value)
|
||||||
|
{
|
||||||
|
if (*value == '1')
|
||||||
|
{
|
||||||
|
DPRINTF("Disabled SVC verification\n");
|
||||||
|
ctxt->svcperm = true;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _config_debugmode(launch_ctxt_t *ctxt, const char *value)
|
||||||
|
{
|
||||||
|
if (*value == '1')
|
||||||
|
{
|
||||||
|
DPRINTF("Enabled Debug mode\n");
|
||||||
|
ctxt->debugmode = true;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _config_stock(launch_ctxt_t *ctxt, const char *value)
|
||||||
|
{
|
||||||
|
if (*value == '1')
|
||||||
|
{
|
||||||
|
DPRINTF("Disabled all patching\n");
|
||||||
|
ctxt->stock = true;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _config_emummc_forced(launch_ctxt_t *ctxt, const char *value)
|
||||||
|
{
|
||||||
|
if (*value == '1')
|
||||||
|
{
|
||||||
|
DPRINTF("Forced emuMMC\n");
|
||||||
|
ctxt->emummc_forced = true;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _config_atmosphere(launch_ctxt_t *ctxt, const char *value)
|
||||||
|
{
|
||||||
|
if (*value == '1')
|
||||||
|
{
|
||||||
|
DPRINTF("Enabled atmosphere patching\n");
|
||||||
|
ctxt->atmosphere = true;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _config_dis_exo_user_exceptions(launch_ctxt_t *ctxt, const char *value)
|
||||||
|
{
|
||||||
|
if (*value == '1')
|
||||||
|
{
|
||||||
|
DPRINTF("Disabled exosphere user exception handlers\n");
|
||||||
|
ctxt->exo_cfg.no_user_exceptions = true;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _config_exo_user_pmu_access(launch_ctxt_t *ctxt, const char *value)
|
||||||
|
{
|
||||||
|
if (*value == '1')
|
||||||
|
{
|
||||||
|
DPRINTF("Enabled user access to PMU\n");
|
||||||
|
ctxt->exo_cfg.user_pmu = true;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _config_exo_cal0_blanking(launch_ctxt_t *ctxt, const char *value)
|
||||||
|
{
|
||||||
|
// Override key found.
|
||||||
|
ctxt->exo_cfg.cal0_blank = calloc(1, 1);
|
||||||
|
|
||||||
|
if (*value == '1')
|
||||||
|
{
|
||||||
|
DPRINTF("Enabled prodinfo blanking\n");
|
||||||
|
*ctxt->exo_cfg.cal0_blank = true;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _config_exo_cal0_writes_enable(launch_ctxt_t *ctxt, const char *value)
|
||||||
|
{
|
||||||
|
// Override key found.
|
||||||
|
ctxt->exo_cfg.cal0_allow_writes_sys = calloc(1, 1);
|
||||||
|
|
||||||
|
if (*value == '1')
|
||||||
|
{
|
||||||
|
DPRINTF("Enabled prodinfo writes\n");
|
||||||
|
*ctxt->exo_cfg.cal0_allow_writes_sys = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _config_fss(launch_ctxt_t *ctxt, const char *value)
|
||||||
|
{
|
||||||
|
LIST_FOREACH_ENTRY(ini_kv_t, kv, &ctxt->cfg->kvs, link)
|
||||||
|
{
|
||||||
|
if (!strcmp("fss0experimental", kv->key))
|
||||||
|
{
|
||||||
|
ctxt->fss0_enable_experimental = *kv->val == '1';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return parse_fss(ctxt, value, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct _cfg_handler_t
|
||||||
|
{
|
||||||
|
const char *key;
|
||||||
|
int (*handler)(launch_ctxt_t *ctxt, const char *value);
|
||||||
|
} cfg_handler_t;
|
||||||
|
|
||||||
|
static const cfg_handler_t _config_handlers[] = {
|
||||||
|
{ "warmboot", _config_warmboot },
|
||||||
|
{ "secmon", _config_secmon },
|
||||||
|
{ "kernel", _config_kernel },
|
||||||
|
{ "kip1", _config_kip1 },
|
||||||
|
{ "kip1patch", config_kip1patch },
|
||||||
|
{ "fullsvcperm", _config_svcperm },
|
||||||
|
{ "debugmode", _config_debugmode },
|
||||||
|
{ "stock", _config_stock },
|
||||||
|
{ "atmosphere", _config_atmosphere },
|
||||||
|
{ "fss0", _config_fss },
|
||||||
|
{ "emummcforce", _config_emummc_forced },
|
||||||
|
{ "nouserexceptions", _config_dis_exo_user_exceptions },
|
||||||
|
{ "userpmu", _config_exo_user_pmu_access },
|
||||||
|
{ "cal0blank", _config_exo_cal0_blanking },
|
||||||
|
{ "cal0writesys", _config_exo_cal0_writes_enable },
|
||||||
|
{ NULL, NULL },
|
||||||
|
};
|
||||||
|
|
||||||
|
int parse_boot_config(launch_ctxt_t *ctxt)
|
||||||
|
{
|
||||||
|
LIST_FOREACH_ENTRY(ini_kv_t, kv, &ctxt->cfg->kvs, link)
|
||||||
|
{
|
||||||
|
for(u32 i = 0; _config_handlers[i].key; i++)
|
||||||
|
{
|
||||||
|
if (!strcmp(_config_handlers[i].key, kv->key))
|
||||||
|
{
|
||||||
|
if (!_config_handlers[i].handler(ctxt, kv->val))
|
||||||
|
{
|
||||||
|
gfx_con.mute = false;
|
||||||
|
EPRINTFARGS("Error while loading %s:\n%s", kv->key, kv->val);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
26
source/hos/hos_config.h
Normal file
26
source/hos/hos_config.h
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2018 naehrwert
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _HOS_CONFIG_H_
|
||||||
|
#define _HOS_CONFIG_H_
|
||||||
|
|
||||||
|
#include "hos.h"
|
||||||
|
|
||||||
|
int parse_boot_config(launch_ctxt_t *ctxt);
|
||||||
|
int config_kip1patch(launch_ctxt_t *ctxt, const char *value);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2018 naehrwert
|
* Copyright (c) 2018 naehrwert
|
||||||
* Copyright (c) 2018 st4rk
|
* Copyright (c) 2018 st4rk
|
||||||
* Copyright (c) 2018-2019 CTCaer
|
* Copyright (c) 2018-2020 CTCaer
|
||||||
* Copyright (c) 2018 balika011
|
* Copyright (c) 2018 balika011
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
@@ -20,21 +20,135 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "pkg1.h"
|
#include "pkg1.h"
|
||||||
|
#include "../gfx/gfx.h"
|
||||||
|
#include "../mem/heap.h"
|
||||||
#include "../sec/se.h"
|
#include "../sec/se.h"
|
||||||
|
#include "../utils/aarch64_util.h"
|
||||||
|
|
||||||
|
#define _NOPv7() 0xE320F000
|
||||||
|
|
||||||
|
#define SM_100_ADR 0x4002B020
|
||||||
|
PATCHSET_DEF(_secmon_1_patchset,
|
||||||
|
// Patch the relocator to be able to run from SM_100_ADR.
|
||||||
|
{ 0x1E0, _ADRP(0, 0x7C013000 - _PAGEOFF(SM_100_ADR)) },
|
||||||
|
//Patch package2 decryption and signature/hash checks.
|
||||||
|
{ 0x9F0 + 0xADC, _NOP() }, //Header signature.
|
||||||
|
{ 0x9F0 + 0xB8C, _NOP() }, //Version.
|
||||||
|
{ 0x9F0 + 0xBB0, _NOP() } //Sections SHA2.
|
||||||
|
);
|
||||||
|
|
||||||
|
PATCHSET_DEF(_secmon_2_patchset,
|
||||||
|
// Patch package2 decryption and signature/hash checks.
|
||||||
|
{ 0xAC8 + 0xAAC, _NOP() }, //Header signature.
|
||||||
|
{ 0xAC8 + 0xB3C, _NOP() }, //Version.
|
||||||
|
{ 0xAC8 + 0xB58, _NOP() } //Sections SHA2.
|
||||||
|
);
|
||||||
|
|
||||||
|
PATCHSET_DEF(_secmon_3_patchset,
|
||||||
|
// Patch package2 decryption and signature/hash checks.
|
||||||
|
{ 0xAC8 + 0xA30, _NOP() }, //Header signature.
|
||||||
|
{ 0xAC8 + 0xAB4, _NOP() }, //package2 structure.
|
||||||
|
{ 0xAC8 + 0xAC0, _NOP() }, //Version.
|
||||||
|
{ 0xAC8 + 0xADC, _NOP() } //Sections SHA2.
|
||||||
|
);
|
||||||
|
|
||||||
|
PATCHSET_DEF(_secmon_4_patchset,
|
||||||
|
// Patch package2 decryption and signature/hash checks.
|
||||||
|
{ 0x2300 + 0x5D80, _NOP() }, //package2 structure.
|
||||||
|
{ 0x2300 + 0x5D8C, _NOP() }, //Version.
|
||||||
|
{ 0x2300 + 0x5EFC, _NOP() }, //Header signature.
|
||||||
|
{ 0xAC8 + 0xA2C, _NOP() } //Sections SHA2.
|
||||||
|
);
|
||||||
|
|
||||||
|
PATCHSET_DEF(_secmon_5_patchset,
|
||||||
|
// Patch package2 decryption and signature/hash checks.
|
||||||
|
{ 0xDA8 + 0x9D8, _NOP() }, //package2 structure.
|
||||||
|
{ 0xDA8 + 0x9E4, _NOP() }, //Version.
|
||||||
|
{ 0xDA8 + 0xC9C, _NOP() }, //Header signature.
|
||||||
|
{ 0xDA8 + 0x1038, _NOP() } //Sections SHA2.
|
||||||
|
);
|
||||||
|
|
||||||
|
PATCHSET_DEF(_secmon_6_patchset,
|
||||||
|
// Patch package2 decryption and signature/hash checks.
|
||||||
|
{ 0xDC8 + 0x820, _NOP() }, //package2 structure.
|
||||||
|
{ 0xDC8 + 0x82C, _NOP() }, //Version.
|
||||||
|
{ 0xDC8 + 0xE90, _NOP() }, //Header signature.
|
||||||
|
{ 0xDC8 + 0x112C, _NOP() } //Sections SHA2.
|
||||||
|
// Fix sleep mode for debug.
|
||||||
|
// { 0x1A68 + 0x3854, 0x94000E45 }, //gpio_config_for_uart.
|
||||||
|
// { 0x1A68 + 0x3858, 0x97FFFC0F }, //clkrst_reboot_uarta.
|
||||||
|
// { 0x1A68 + 0x385C, 0x52A00021 }, //MOV W1, #0x10000 ; baudrate.
|
||||||
|
// { 0x1A68 + 0x3860, 0x2A1F03E0 }, //MOV W0, WZR ; uart_port -> A.
|
||||||
|
// { 0x1A68 + 0x3864, 0x72984001 }, //MOVK W1, #0xC200 ; baudrate.
|
||||||
|
// { 0x1A68 + 0x3868, 0x94000C8C }, //uart_configure.
|
||||||
|
// { 0x1A68 + 0x3A6C, _NOP() } // warmboot UARTA cfg.
|
||||||
|
);
|
||||||
|
|
||||||
|
PATCHSET_DEF(_secmon_620_patchset,
|
||||||
|
// Patch package2 decryption and signature/hash checks.
|
||||||
|
{ 0xDC8 + 0x604, _NOP() }, //package2 structure.
|
||||||
|
{ 0xDC8 + 0x610, _NOP() }, //Version.
|
||||||
|
{ 0xDC8 + 0xC74, _NOP() }, //Header signature.
|
||||||
|
{ 0xDC8 + 0xF10, _NOP() } //Sections SHA2.
|
||||||
|
// Fix sleep mode for debug.
|
||||||
|
// { 0x2AC8 + 0x3854, 0x94000F42 }, //gpio_config_for_uart.
|
||||||
|
// { 0x2AC8 + 0x3858, 0x97FFFC0F }, //clkrst_reboot_uarta.
|
||||||
|
// { 0x2AC8 + 0x385C, 0x52A00021 }, //MOV W1, #0x10000 ; baudrate.
|
||||||
|
// { 0x2AC8 + 0x3860, 0x2A1F03E0 }, //MOV W0, WZR ; uart_port -> A.
|
||||||
|
// { 0x2AC8 + 0x3864, 0x72984001 }, //MOVK W1, #0xC200 ; baudrate.
|
||||||
|
// { 0x2AC8 + 0x3868, 0x94000D89 }, //uart_configure.
|
||||||
|
// { 0x2AC8 + 0x3A6C, _NOP() } // warmboot UARTA cfg.
|
||||||
|
);
|
||||||
|
|
||||||
|
PATCHSET_DEF(_warmboot_1_patchset,
|
||||||
|
{ 0x4DC, _NOPv7() } // Fuse check.
|
||||||
|
);
|
||||||
|
|
||||||
|
PATCHSET_DEF(_warmboot_2_patchset,
|
||||||
|
{ 0x4DC, _NOPv7() } // Fuse check.
|
||||||
|
);
|
||||||
|
|
||||||
|
PATCHSET_DEF(_warmboot_3_patchset,
|
||||||
|
{ 0x4DC, _NOPv7() }, // Fuse check.
|
||||||
|
{ 0x4F0, _NOPv7() } // Segment id check.
|
||||||
|
);
|
||||||
|
|
||||||
|
PATCHSET_DEF(_warmboot_4_patchset,
|
||||||
|
{ 0x544, _NOPv7() }, // Fuse check.
|
||||||
|
{ 0x558, _NOPv7() } // Segment id check.
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* package1.1 header: <wb, ldr, sm>
|
||||||
|
* package1.1 layout:
|
||||||
|
* 1.0: {sm, ldr, wb} { 2, 1, 0 }
|
||||||
|
* 2.0: {wb, ldr, sm} { 0, 1, 2 }
|
||||||
|
* 3.0: {wb, ldr, sm} { 0, 1, 2 }
|
||||||
|
* 3.1: {wb, ldr, sm} { 0, 1, 2 }
|
||||||
|
* 4.0: {ldr, sm, wb} { 1, 2, 0 }
|
||||||
|
* 5.0: {ldr, sm, wb} { 1, 2, 0 }
|
||||||
|
* 6.0: {ldr, sm, wb} { 1, 2, 0 }
|
||||||
|
* 6.2: {ldr, sm, wb} { 1, 2, 0 }
|
||||||
|
* 7.0: {ldr, sm, wb} { 1, 2, 0 }
|
||||||
|
*/
|
||||||
|
|
||||||
static const pkg1_id_t _pkg1_ids[] = {
|
static const pkg1_id_t _pkg1_ids[] = {
|
||||||
{ "20161121183008", 0 }, //1.0.0
|
{ "20161121183008", 0, 0x1900, 0x3FE0, { 2, 1, 0 }, SM_100_ADR, 0x8000D000, true, _secmon_1_patchset, _warmboot_1_patchset }, //1.0.0 (Patched relocator)
|
||||||
{ "20170210155124", 0 }, //2.0.0 - 2.3.0
|
{ "20170210155124", 0, 0x1900, 0x3FE0, { 0, 1, 2 }, 0x4002D000, 0x8000D000, true, _secmon_2_patchset, _warmboot_2_patchset }, //2.0.0 - 2.3.0
|
||||||
{ "20170519101410", 1 }, //3.0.0
|
{ "20170519101410", 1, 0x1A00, 0x3FE0, { 0, 1, 2 }, 0x4002D000, 0x8000D000, true, _secmon_3_patchset, _warmboot_3_patchset }, //3.0.0
|
||||||
{ "20170710161758", 2 }, //3.0.1 - 3.0.2
|
{ "20170710161758", 2, 0x1A00, 0x3FE0, { 0, 1, 2 }, 0x4002D000, 0x8000D000, true, _secmon_3_patchset, _warmboot_3_patchset }, //3.0.1 - 3.0.2
|
||||||
{ "20170921172629", 3 }, //4.0.0 - 4.1.0
|
{ "20170921172629", 3, 0x1800, 0x3FE0, { 1, 2, 0 }, 0x4002B000, 0x4003B000, false, _secmon_4_patchset, _warmboot_4_patchset }, //4.0.0 - 4.1.0
|
||||||
{ "20180220163747", 4 }, //5.0.0 - 5.1.0
|
{ "20180220163747", 4, 0x1900, 0x3FE0, { 1, 2, 0 }, 0x4002B000, 0x4003B000, false, _secmon_5_patchset, _warmboot_4_patchset }, //5.0.0 - 5.1.0
|
||||||
{ "20180802162753", 5 }, //6.0.0 - 6.1.0
|
{ "20180802162753", 5, 0x1900, 0x3FE0, { 1, 2, 0 }, 0x4002B000, 0x4003D800, false, _secmon_6_patchset, _warmboot_4_patchset }, //6.0.0 - 6.1.0
|
||||||
{ "20181107105733", 6 }, //6.2.0
|
{ "20181107105733", 6, 0x0E00, 0x6FE0, { 1, 2, 0 }, 0x4002B000, 0x4003D800, false, _secmon_620_patchset, _warmboot_4_patchset }, //6.2.0
|
||||||
{ "20181218175730", 7 }, //7.0.0
|
{ "20181218175730", 7, 0x0F00, 0x6FE0, { 1, 2, 0 }, 0x40030000, 0x4003E000, false, NULL, NULL }, //7.0.0
|
||||||
{ "20190208150037", 7 }, //7.0.1
|
{ "20190208150037", 7, 0x0F00, 0x6FE0, { 1, 2, 0 }, 0x40030000, 0x4003E000, false, NULL, NULL }, //7.0.1
|
||||||
{ "20190314172056", 7 }, //8.0.0
|
{ "20190314172056", 7, 0x0E00, 0x6FE0, { 1, 2, 0 }, 0x40030000, 0x4003E000, false, NULL, NULL }, //8.0.0 - 8.0.1
|
||||||
{ "20190531152432", 8 }, //8.1.0
|
{ "20190531152432", 8, 0x0E00, 0x6FE0, { 1, 2, 0 }, 0x40030000, 0x4003E000, false, NULL, NULL }, //8.1.0
|
||||||
|
{ "20190809135709", 9, 0x0E00, 0x6FE0, { 1, 2, 0 }, 0x40030000, 0x4003E000, false, NULL, NULL }, //9.0.0 - 9.0.1
|
||||||
|
{ "20191021113848", 10, 0x0E00, 0x6FE0, { 1, 2, 0 }, 0x40030000, 0x4003E000, false, NULL, NULL }, //9.1.0
|
||||||
|
{ "20200303104606", 10, 0x0E00, 0x6FE0, { 1, 2, 0 }, 0x40030000, 0x4003E000, false, NULL, NULL }, //10.0.0
|
||||||
{ NULL } //End.
|
{ NULL } //End.
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -45,3 +159,31 @@ const pkg1_id_t *pkg1_identify(u8 *pkg1)
|
|||||||
return &_pkg1_ids[i];
|
return &_pkg1_ids[i];
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void pkg1_decrypt(const pkg1_id_t *id, u8 *pkg1)
|
||||||
|
{
|
||||||
|
// Decrypt package1.
|
||||||
|
u8 *pkg11 = pkg1 + id->pkg11_off;
|
||||||
|
u32 pkg11_size = *(u32 *)pkg11;
|
||||||
|
se_aes_crypt_ctr(11, pkg11 + 0x20, pkg11_size, pkg11 + 0x20, pkg11_size, pkg11 + 0x10);
|
||||||
|
}
|
||||||
|
|
||||||
|
void pkg1_unpack(void *warmboot_dst, void *secmon_dst, void *ldr_dst, const pkg1_id_t *id, u8 *pkg1)
|
||||||
|
{
|
||||||
|
pk11_hdr_t *hdr = (pk11_hdr_t *)(pkg1 + id->pkg11_off + 0x20);
|
||||||
|
|
||||||
|
u32 sec_size[3] = { hdr->wb_size, hdr->ldr_size, hdr->sm_size };
|
||||||
|
//u32 sec_off[3] = { hdr->wb_off, hdr->ldr_off, hdr->sm_off };
|
||||||
|
|
||||||
|
u8 *pdata = (u8 *)hdr + sizeof(pk11_hdr_t);
|
||||||
|
for (u32 i = 0; i < 3; i++)
|
||||||
|
{
|
||||||
|
if (id->sec_map[i] == 0 && warmboot_dst)
|
||||||
|
memcpy(warmboot_dst, pdata, sec_size[id->sec_map[i]]);
|
||||||
|
else if (id->sec_map[i] == 1 && ldr_dst)
|
||||||
|
memcpy(ldr_dst, pdata, sec_size[id->sec_map[i]]);
|
||||||
|
else if (id->sec_map[i] == 2 && secmon_dst)
|
||||||
|
memcpy(secmon_dst, pdata, sec_size[id->sec_map[i]]);
|
||||||
|
pdata += sec_size[id->sec_map[i]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -19,12 +19,46 @@
|
|||||||
|
|
||||||
#include "../utils/types.h"
|
#include "../utils/types.h"
|
||||||
|
|
||||||
|
typedef struct _patch_t
|
||||||
|
{
|
||||||
|
u32 off;
|
||||||
|
u32 val;
|
||||||
|
} patch_t;
|
||||||
|
|
||||||
|
#define PATCHSET_DEF(name, ...) \
|
||||||
|
patch_t name[] = { \
|
||||||
|
__VA_ARGS__, \
|
||||||
|
{ 0xFFFFFFFF, 0xFFFFFFFF } \
|
||||||
|
}
|
||||||
|
|
||||||
typedef struct _pkg1_id_t
|
typedef struct _pkg1_id_t
|
||||||
{
|
{
|
||||||
const char *id;
|
const char *id;
|
||||||
u32 kb;
|
u32 kb;
|
||||||
|
u32 tsec_off;
|
||||||
|
u32 pkg11_off;
|
||||||
|
u32 sec_map[3];
|
||||||
|
u32 secmon_base;
|
||||||
|
u32 warmboot_base;
|
||||||
|
bool set_warmboot;
|
||||||
|
patch_t *secmon_patchset;
|
||||||
|
patch_t *warmboot_patchset;
|
||||||
} pkg1_id_t;
|
} pkg1_id_t;
|
||||||
|
|
||||||
|
typedef struct _pk11_hdr_t
|
||||||
|
{
|
||||||
|
u32 magic;
|
||||||
|
u32 wb_size;
|
||||||
|
u32 wb_off;
|
||||||
|
u32 pad;
|
||||||
|
u32 ldr_size;
|
||||||
|
u32 ldr_off;
|
||||||
|
u32 sm_size;
|
||||||
|
u32 sm_off;
|
||||||
|
} pk11_hdr_t;
|
||||||
|
|
||||||
const pkg1_id_t *pkg1_identify(u8 *pkg1);
|
const pkg1_id_t *pkg1_identify(u8 *pkg1);
|
||||||
|
void pkg1_decrypt(const pkg1_id_t *id, u8 *pkg1);
|
||||||
|
void pkg1_unpack(void *warmboot_dst, void *secmon_dst, void *ldr_dst, const pkg1_id_t *id, u8 *pkg1);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
1298
source/hos/pkg2.c
1298
source/hos/pkg2.c
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2018 naehrwert
|
* Copyright (c) 2018 naehrwert
|
||||||
* Copyright (C) 2018-2019 CTCaer
|
* Copyright (c) 2018-2020 CTCaer
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
* under the terms and conditions of the GNU General Public License,
|
* under the terms and conditions of the GNU General Public License,
|
||||||
@@ -26,7 +26,40 @@
|
|||||||
#define PKG2_SEC_KERNEL 0
|
#define PKG2_SEC_KERNEL 0
|
||||||
#define PKG2_SEC_INI1 1
|
#define PKG2_SEC_INI1 1
|
||||||
|
|
||||||
#define PKG2_NEWKERN_INI1_START 0x168
|
#define INI1_MAGIC 0x31494E49
|
||||||
|
#define PKG2_NEWKERN_GET_INI1_HEURISTIC 0xD2800015 // Offset of OP + 12 is the INI1 offset.
|
||||||
|
#define PKG2_NEWKERN_START 0x800
|
||||||
|
|
||||||
|
u32 pkg2_newkern_ini1_val;
|
||||||
|
u32 pkg2_newkern_ini1_start;
|
||||||
|
u32 pkg2_newkern_ini1_end;
|
||||||
|
|
||||||
|
typedef struct _kernel_patch_t
|
||||||
|
{
|
||||||
|
u32 id;
|
||||||
|
u32 off;
|
||||||
|
u32 val;
|
||||||
|
u32 *ptr;
|
||||||
|
} kernel_patch_t;
|
||||||
|
|
||||||
|
#define KERNEL_PATCHSET_DEF(name, ...) \
|
||||||
|
kernel_patch_t name[] = { \
|
||||||
|
__VA_ARGS__, \
|
||||||
|
{0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, (u32 *)0xFFFFFFFF} \
|
||||||
|
}
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
// Always applied.
|
||||||
|
SVC_GENERIC = 0,
|
||||||
|
// Generic instruction patches.
|
||||||
|
SVC_VERIFY_DS = 0x10,
|
||||||
|
DEBUG_MODE_EN = 0x11,
|
||||||
|
ATM_GEN_PATCH = 0x12,
|
||||||
|
ATM_SYSM_INCR = ATM_GEN_PATCH,
|
||||||
|
// >4 bytes patches. Value is a pointer of a u32 array.
|
||||||
|
ATM_ARR_PATCH = 0x13,
|
||||||
|
};
|
||||||
|
|
||||||
typedef struct _pkg2_hdr_t
|
typedef struct _pkg2_hdr_t
|
||||||
{
|
{
|
||||||
@@ -83,8 +116,44 @@ typedef struct _pkg2_kip1_info_t
|
|||||||
link_t link;
|
link_t link;
|
||||||
} pkg2_kip1_info_t;
|
} pkg2_kip1_info_t;
|
||||||
|
|
||||||
void pkg2_parse_kips(link_t *info, pkg2_hdr_t *pkg2);
|
typedef struct _pkg2_kernel_id_t
|
||||||
int pkg2_decompress_kip(pkg2_kip1_info_t* ki, u32 sectsToDecomp);
|
{
|
||||||
pkg2_hdr_t *pkg2_decrypt(void *data);
|
u8 hash[8];
|
||||||
|
kernel_patch_t *kernel_patchset;
|
||||||
|
} pkg2_kernel_id_t;
|
||||||
|
|
||||||
|
typedef struct _kip1_patch_t
|
||||||
|
{
|
||||||
|
u32 offset; // section+offset of patch to apply.
|
||||||
|
u32 length; // In bytes, 0 means last patch.
|
||||||
|
char* srcData; // That must match.
|
||||||
|
char* dstData; // That it gets replaced by.
|
||||||
|
} kip1_patch_t;
|
||||||
|
|
||||||
|
typedef struct _kip1_patchset_t
|
||||||
|
{
|
||||||
|
char* name; // NULL means end.
|
||||||
|
kip1_patch_t* patches; // NULL means not necessary.
|
||||||
|
} kip1_patchset_t;
|
||||||
|
|
||||||
|
typedef struct _kip1_id_t
|
||||||
|
{
|
||||||
|
const char* name;
|
||||||
|
u8 hash[8];
|
||||||
|
kip1_patchset_t* patchset;
|
||||||
|
} kip1_id_t;
|
||||||
|
|
||||||
|
void pkg2_get_newkern_info(u8 *kern_data);
|
||||||
|
bool pkg2_parse_kips(link_t *info, pkg2_hdr_t *pkg2, bool *new_pkg2);
|
||||||
|
int pkg2_has_kip(link_t *info, u64 tid);
|
||||||
|
void pkg2_replace_kip(link_t *info, u64 tid, pkg2_kip1_t *kip1);
|
||||||
|
void pkg2_add_kip(link_t *info, pkg2_kip1_t *kip1);
|
||||||
|
void pkg2_merge_kip(link_t *info, pkg2_kip1_t *kip1);
|
||||||
|
void pkg2_get_ids(kip1_id_t **ids, u32 *entries);
|
||||||
|
const char* pkg2_patch_kips(link_t *info, char* patchNames);
|
||||||
|
|
||||||
|
const pkg2_kernel_id_t *pkg2_identify(u8 *hash);
|
||||||
|
pkg2_hdr_t *pkg2_decrypt(void *data, u8 kb);
|
||||||
|
void pkg2_build_encrypt(void *dst, void *kernel, u32 kernel_size, link_t *kips_info, bool new_pkg2);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
156
source/hos/pkg2_ini_kippatch.c
Normal file
156
source/hos/pkg2_ini_kippatch.c
Normal file
@@ -0,0 +1,156 @@
|
|||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "pkg2_ini_kippatch.h"
|
||||||
|
#include "../libs/fatfs/ff.h"
|
||||||
|
#include "../mem/heap.h"
|
||||||
|
|
||||||
|
#define KPS(x) ((u32)(x) << 29)
|
||||||
|
|
||||||
|
static u8 *_htoa(u8 *result, const char *ptr, u8 byte_len)
|
||||||
|
{
|
||||||
|
char ch = *ptr;
|
||||||
|
u32 ascii_len = byte_len * 2;
|
||||||
|
if (!result)
|
||||||
|
result = malloc(byte_len);
|
||||||
|
u8 *dst = result;
|
||||||
|
|
||||||
|
while (ch == ' ' || ch == '\t')
|
||||||
|
ch = *(++ptr);
|
||||||
|
|
||||||
|
bool shift = true;
|
||||||
|
while (ascii_len)
|
||||||
|
{
|
||||||
|
u8 tmp = 0;
|
||||||
|
if (ch >= '0' && ch <= '9')
|
||||||
|
tmp = (ch - '0');
|
||||||
|
else if (ch >= 'A' && ch <= 'F')
|
||||||
|
tmp = (ch - 'A' + 10);
|
||||||
|
else if (ch >= 'a' && ch <= 'f')
|
||||||
|
tmp = (ch - 'a' + 10);
|
||||||
|
|
||||||
|
if (shift)
|
||||||
|
*dst = (tmp << 4) & 0xF0;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*dst |= (tmp & 0x0F);
|
||||||
|
dst++;
|
||||||
|
}
|
||||||
|
|
||||||
|
ascii_len--;
|
||||||
|
ch = *(++ptr);
|
||||||
|
shift = !shift;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *_strdup(char *str)
|
||||||
|
{
|
||||||
|
if (!str)
|
||||||
|
return NULL;
|
||||||
|
if (str[0] == ' ' && (strlen(str) > 1))
|
||||||
|
str++;
|
||||||
|
char *res = (char *)malloc(strlen(str) + 1);
|
||||||
|
strcpy(res, str);
|
||||||
|
if (res[strlen(res) - 1] == ' ' && (strlen(res) > 1))
|
||||||
|
res[strlen(res) - 1] = 0;
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static u32 _find_patch_section_name(char *lbuf, u32 lblen, char schar)
|
||||||
|
{
|
||||||
|
u32 i;
|
||||||
|
for (i = 0; i < lblen && lbuf[i] != schar && lbuf[i] != '\n' && lbuf[i] != '\r'; i++)
|
||||||
|
;
|
||||||
|
lbuf[i] = 0;
|
||||||
|
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ini_kip_sec_t *_ini_create_kip_section(link_t *dst, ini_kip_sec_t *ksec, char *name)
|
||||||
|
{
|
||||||
|
if (ksec)
|
||||||
|
list_append(dst, &ksec->link);
|
||||||
|
|
||||||
|
ksec = (ini_kip_sec_t *)calloc(sizeof(ini_kip_sec_t), 1);
|
||||||
|
u32 i = _find_patch_section_name(name, strlen(name), ':') + 1;
|
||||||
|
ksec->name = _strdup(name);
|
||||||
|
|
||||||
|
// Get hash section.
|
||||||
|
_htoa(ksec->hash, &name[i], 8);
|
||||||
|
|
||||||
|
return ksec;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ini_patch_parse(link_t *dst, char *ini_path)
|
||||||
|
{
|
||||||
|
u32 lblen;
|
||||||
|
char lbuf[512];
|
||||||
|
FIL fp;
|
||||||
|
ini_kip_sec_t *ksec = NULL;
|
||||||
|
|
||||||
|
// Open ini.
|
||||||
|
if (f_open(&fp, ini_path, FA_READ) != FR_OK)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
// Fetch one line.
|
||||||
|
lbuf[0] = 0;
|
||||||
|
f_gets(lbuf, 512, &fp);
|
||||||
|
lblen = strlen(lbuf);
|
||||||
|
|
||||||
|
// Remove trailing newline. Depends on 'FF_USE_STRFUNC 2' that removes \r.
|
||||||
|
if (lblen && lbuf[lblen - 1] == '\n')
|
||||||
|
lbuf[lblen - 1] = 0;
|
||||||
|
|
||||||
|
if (lblen > 2 && lbuf[0] == '[') // Create new section.
|
||||||
|
{
|
||||||
|
_find_patch_section_name(lbuf, lblen, ']');
|
||||||
|
|
||||||
|
ksec = _ini_create_kip_section(dst, ksec, &lbuf[1]);
|
||||||
|
list_init(&ksec->pts);
|
||||||
|
}
|
||||||
|
else if (ksec && lbuf[0] == '.') //Extract key/value.
|
||||||
|
{
|
||||||
|
u32 tmp = 0;
|
||||||
|
u32 i = _find_patch_section_name(lbuf, lblen, '=');
|
||||||
|
|
||||||
|
ini_patchset_t *pt = (ini_patchset_t *)calloc(sizeof(ini_patchset_t), 1);
|
||||||
|
|
||||||
|
pt->name = _strdup(&lbuf[1]);
|
||||||
|
|
||||||
|
u8 kip_sidx = lbuf[i + 1] - '0';
|
||||||
|
|
||||||
|
if (kip_sidx < 6)
|
||||||
|
{
|
||||||
|
pt->offset = KPS(kip_sidx);
|
||||||
|
tmp = _find_patch_section_name(&lbuf[i + 3], lblen, ':');
|
||||||
|
pt->offset |= strtol(&lbuf[i + 3], NULL, 16);
|
||||||
|
|
||||||
|
i += tmp + 4;
|
||||||
|
|
||||||
|
tmp = _find_patch_section_name(&lbuf[i], lblen, ':');
|
||||||
|
pt->length = strtol(&lbuf[i], NULL, 16);
|
||||||
|
|
||||||
|
i += tmp + 1;
|
||||||
|
|
||||||
|
tmp = _find_patch_section_name(&lbuf[i], lblen, ',');
|
||||||
|
pt->srcData = _htoa(NULL, &lbuf[i], pt->length);
|
||||||
|
i += tmp + 1;
|
||||||
|
pt->dstData = _htoa(NULL, &lbuf[i], pt->length);
|
||||||
|
}
|
||||||
|
|
||||||
|
list_append(&ksec->pts, &pt->link);
|
||||||
|
}
|
||||||
|
} while (!f_eof(&fp));
|
||||||
|
|
||||||
|
f_close(&fp);
|
||||||
|
|
||||||
|
if (ksec)
|
||||||
|
list_append(dst, &ksec->link);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
43
source/hos/pkg2_ini_kippatch.h
Normal file
43
source/hos/pkg2_ini_kippatch.h
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019 CTCaer
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _INIPATCH_H_
|
||||||
|
#define _INIPATCH_H_
|
||||||
|
|
||||||
|
#include "../utils/types.h"
|
||||||
|
#include "../utils/list.h"
|
||||||
|
|
||||||
|
typedef struct _ini_patchset_t
|
||||||
|
{
|
||||||
|
char *name;
|
||||||
|
u32 offset; // section + offset of patch to apply.
|
||||||
|
u32 length; // In bytes, 0 means last patch.
|
||||||
|
u8 *srcData; // That must match.
|
||||||
|
u8 *dstData; // Gets replaced with.
|
||||||
|
link_t link;
|
||||||
|
} ini_patchset_t;
|
||||||
|
|
||||||
|
typedef struct _ini_kip_sec_t
|
||||||
|
{
|
||||||
|
char *name;
|
||||||
|
u8 hash[8];
|
||||||
|
link_t pts;
|
||||||
|
link_t link;
|
||||||
|
} ini_kip_sec_t;
|
||||||
|
|
||||||
|
int ini_patch_parse(link_t *dst, char *ini_path);
|
||||||
|
|
||||||
|
#endif
|
||||||
355
source/hos/secmon_exo.c
Normal file
355
source/hos/secmon_exo.c
Normal file
@@ -0,0 +1,355 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 CTCaer
|
||||||
|
* Copyright (c) 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 <stdlib.h>
|
||||||
|
|
||||||
|
#include "hos.h"
|
||||||
|
#include "../config/config.h"
|
||||||
|
#include "../gfx/di.h"
|
||||||
|
#include "../gfx/gfx.h"
|
||||||
|
#include "../libs/fatfs/ff.h"
|
||||||
|
#include "../mem/heap.h"
|
||||||
|
#include "../soc/fuse.h"
|
||||||
|
#include "../storage/emummc.h"
|
||||||
|
#include "../storage/nx_sd.h"
|
||||||
|
#include "../storage/sdmmc.h"
|
||||||
|
#include "../utils/btn.h"
|
||||||
|
#include "../utils/util.h"
|
||||||
|
#include "../utils/types.h"
|
||||||
|
|
||||||
|
extern hekate_config h_cfg;
|
||||||
|
|
||||||
|
enum emuMMC_Type
|
||||||
|
{
|
||||||
|
emuMMC_None = 0,
|
||||||
|
emuMMC_Partition,
|
||||||
|
emuMMC_File,
|
||||||
|
emuMMC_MAX
|
||||||
|
};
|
||||||
|
|
||||||
|
/* "EFS0" */
|
||||||
|
#define EMUMMC_MAGIC 0x30534645
|
||||||
|
#define EMUMMC_FILE_PATH_MAX 0x80
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
u32 magic;
|
||||||
|
u32 type;
|
||||||
|
u32 id;
|
||||||
|
u32 fs_ver;
|
||||||
|
} emummc_base_config_t;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
u64 start_sector;
|
||||||
|
} emummc_partition_config_t;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
char path[EMUMMC_FILE_PATH_MAX];
|
||||||
|
} emummc_file_config_t;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
emummc_base_config_t base_cfg;
|
||||||
|
union
|
||||||
|
{
|
||||||
|
emummc_partition_config_t partition_cfg;
|
||||||
|
emummc_file_config_t file_cfg;
|
||||||
|
};
|
||||||
|
char nintendo_path[EMUMMC_FILE_PATH_MAX];
|
||||||
|
} exo_emummc_config_t;
|
||||||
|
|
||||||
|
typedef struct _exo_cfg_t
|
||||||
|
{
|
||||||
|
u32 magic;
|
||||||
|
u32 fwno;
|
||||||
|
u32 flags;
|
||||||
|
u32 reserved[5];
|
||||||
|
exo_emummc_config_t emummc_cfg;
|
||||||
|
} exo_cfg_t;
|
||||||
|
|
||||||
|
typedef struct _atm_meta_t
|
||||||
|
{
|
||||||
|
u32 magic;
|
||||||
|
u32 fwno;
|
||||||
|
} wb_cfg_t;
|
||||||
|
|
||||||
|
// Atmosphère reboot-to-fatal-error.
|
||||||
|
typedef struct _atm_fatal_error_ctx
|
||||||
|
{
|
||||||
|
u32 magic;
|
||||||
|
u32 error_desc;
|
||||||
|
u64 title_id;
|
||||||
|
union
|
||||||
|
{
|
||||||
|
u64 gprs[32];
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
u64 _gprs[29];
|
||||||
|
u64 fp;
|
||||||
|
u64 lr;
|
||||||
|
u64 sp;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
u64 pc;
|
||||||
|
u64 module_base;
|
||||||
|
u32 pstate;
|
||||||
|
u32 afsr0;
|
||||||
|
u32 afsr1;
|
||||||
|
u32 esr;
|
||||||
|
u64 far;
|
||||||
|
u64 report_identifier; // Normally just system tick.
|
||||||
|
u64 stack_trace_size;
|
||||||
|
u64 stack_dump_size;
|
||||||
|
u64 stack_trace[0x20];
|
||||||
|
u8 stack_dump[0x100];
|
||||||
|
u8 tls[0x100];
|
||||||
|
} atm_fatal_error_ctx;
|
||||||
|
|
||||||
|
#define ATM_FATAL_ERR_CTX_ADDR 0x4003E000
|
||||||
|
#define ATM_FATAL_MAGIC 0x30454641 // AFE0
|
||||||
|
|
||||||
|
#define ATM_WB_HEADER_OFF 0x244
|
||||||
|
#define ATM_WB_MAGIC 0x30544257
|
||||||
|
|
||||||
|
// Exosphère mailbox defines.
|
||||||
|
#define EXO_CFG_ADDR 0x8000F000
|
||||||
|
#define EXO_MAGIC_VAL 0x304F5845
|
||||||
|
#define EXO_FLAG_DBG_PRIV (1 << 1)
|
||||||
|
#define EXO_FLAG_DBG_USER (1 << 2)
|
||||||
|
#define EXO_FLAG_NO_USER_EXC (1 << 3)
|
||||||
|
#define EXO_FLAG_USER_PMU (1 << 4)
|
||||||
|
#define EXO_FLAG_CAL0_BLANKING (1 << 5)
|
||||||
|
#define EXO_FLAG_CAL0_WRITES_SYS (1 << 6)
|
||||||
|
|
||||||
|
void config_exosphere(launch_ctxt_t *ctxt)
|
||||||
|
{
|
||||||
|
u32 exoFwNo = 0;
|
||||||
|
u32 exoFlags = 0;
|
||||||
|
u32 kb = ctxt->pkg1_id->kb;
|
||||||
|
bool user_debug = false;
|
||||||
|
bool cal0_blanking = false;
|
||||||
|
bool cal0_allow_writes_sys = false;
|
||||||
|
|
||||||
|
memset((exo_cfg_t *)EXO_CFG_ADDR, 0, sizeof(exo_cfg_t));
|
||||||
|
|
||||||
|
volatile exo_cfg_t *exo_cfg = (exo_cfg_t *)EXO_CFG_ADDR;
|
||||||
|
|
||||||
|
switch (kb)
|
||||||
|
{
|
||||||
|
case KB_FIRMWARE_VERSION_100_200:
|
||||||
|
if (!strcmp(ctxt->pkg1_id->id, "20161121183008"))
|
||||||
|
exoFwNo = 1;
|
||||||
|
else
|
||||||
|
exoFwNo = 2;
|
||||||
|
break;
|
||||||
|
case KB_FIRMWARE_VERSION_300:
|
||||||
|
exoFwNo = 3;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
exoFwNo = kb + 1;
|
||||||
|
if (!strcmp(ctxt->pkg1_id->id, "20190314172056") || (kb >= KB_FIRMWARE_VERSION_810))
|
||||||
|
exoFwNo++; // ATM_TARGET_FW_800/810/900/910.
|
||||||
|
if (!strcmp(ctxt->pkg1_id->id, "20200303104606"))
|
||||||
|
exoFwNo++; // ATM_TARGET_FW_1000.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ctxt->stock)
|
||||||
|
{
|
||||||
|
// Parse exosphere.ini.
|
||||||
|
LIST_INIT(ini_sections);
|
||||||
|
if (ini_parse(&ini_sections, "exosphere.ini", false))
|
||||||
|
{
|
||||||
|
LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_sections, link)
|
||||||
|
{
|
||||||
|
// Only parse exosphere section.
|
||||||
|
if (!(ini_sec->type == INI_CHOICE) || strcmp(ini_sec->name, "exosphere"))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
LIST_FOREACH_ENTRY(ini_kv_t, kv, &ini_sec->kvs, link)
|
||||||
|
{
|
||||||
|
if (!strcmp("debugmode_user", kv->key))
|
||||||
|
user_debug = atoi(kv->val);
|
||||||
|
else if (emu_cfg.enabled && !h_cfg.emummc_force_disable)
|
||||||
|
{
|
||||||
|
if (!strcmp("blank_prodinfo_emummc", kv->key))
|
||||||
|
cal0_blanking = atoi(kv->val);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!strcmp("blank_prodinfo_sysmmc", kv->key))
|
||||||
|
cal0_blanking = atoi(kv->val);
|
||||||
|
else if (!strcmp("allow_writing_to_cal_sysmmc", kv->key))
|
||||||
|
cal0_allow_writes_sys = atoi(kv->val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// To avoid problems, make private debug mode always on if not semi-stock.
|
||||||
|
if (!ctxt->stock || (emu_cfg.enabled && !h_cfg.emummc_force_disable))
|
||||||
|
exoFlags |= EXO_FLAG_DBG_PRIV;
|
||||||
|
|
||||||
|
// Enable user debug.
|
||||||
|
if (user_debug)
|
||||||
|
exoFlags |= EXO_FLAG_DBG_USER;
|
||||||
|
|
||||||
|
// Disable proper failure handling.
|
||||||
|
if (ctxt->exo_cfg.no_user_exceptions)
|
||||||
|
exoFlags |= EXO_FLAG_NO_USER_EXC;
|
||||||
|
|
||||||
|
// Enable user access to PMU.
|
||||||
|
if (ctxt->exo_cfg.user_pmu)
|
||||||
|
exoFlags |= EXO_FLAG_USER_PMU;
|
||||||
|
|
||||||
|
// Check if exo ini value is overridden and enable prodinfo blanking.
|
||||||
|
if ((ctxt->exo_cfg.cal0_blank && *ctxt->exo_cfg.cal0_blank)
|
||||||
|
|| (!ctxt->exo_cfg.cal0_blank && cal0_blanking))
|
||||||
|
exoFlags |= EXO_FLAG_CAL0_BLANKING;
|
||||||
|
|
||||||
|
// Check if exo ini value is overridden and allow prodinfo writes.
|
||||||
|
if ((ctxt->exo_cfg.cal0_allow_writes_sys && *ctxt->exo_cfg.cal0_allow_writes_sys)
|
||||||
|
|| (!ctxt->exo_cfg.cal0_allow_writes_sys && cal0_allow_writes_sys))
|
||||||
|
exoFlags |= EXO_FLAG_CAL0_WRITES_SYS;
|
||||||
|
|
||||||
|
// Set mailbox values.
|
||||||
|
exo_cfg->magic = EXO_MAGIC_VAL;
|
||||||
|
exo_cfg->fwno = exoFwNo;
|
||||||
|
exo_cfg->flags = exoFlags;
|
||||||
|
|
||||||
|
// If warmboot is lp0fw, add in RSA modulus.
|
||||||
|
volatile wb_cfg_t *wb_cfg = (wb_cfg_t *)(ctxt->pkg1_id->warmboot_base + ATM_WB_HEADER_OFF);
|
||||||
|
|
||||||
|
if (wb_cfg->magic == ATM_WB_MAGIC)
|
||||||
|
{
|
||||||
|
wb_cfg->fwno = exoFwNo;
|
||||||
|
|
||||||
|
sdmmc_storage_t storage;
|
||||||
|
sdmmc_t sdmmc;
|
||||||
|
|
||||||
|
// Set warmboot binary rsa modulus.
|
||||||
|
u8 *rsa_mod = (u8 *)malloc(512);
|
||||||
|
|
||||||
|
sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_BUS_WIDTH_8, SDHCI_TIMING_MMC_HS400);
|
||||||
|
sdmmc_storage_set_mmc_partition(&storage, EMMC_BOOT0);
|
||||||
|
sdmmc_storage_read(&storage, 1, 1, rsa_mod);
|
||||||
|
sdmmc_storage_end(&storage);
|
||||||
|
|
||||||
|
// Patch AutoRCM out.
|
||||||
|
if ((fuse_read_odm(4) & 3) != 3)
|
||||||
|
rsa_mod[0x10] = 0xF7;
|
||||||
|
else
|
||||||
|
rsa_mod[0x10] = 0x37;
|
||||||
|
|
||||||
|
memcpy((void *)(ctxt->pkg1_id->warmboot_base + 0x10), rsa_mod + 0x10, 0x100);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (emu_cfg.enabled && !h_cfg.emummc_force_disable)
|
||||||
|
{
|
||||||
|
exo_cfg->emummc_cfg.base_cfg.magic = EMUMMC_MAGIC;
|
||||||
|
exo_cfg->emummc_cfg.base_cfg.type = emu_cfg.sector ? emuMMC_Partition : emuMMC_File;
|
||||||
|
exo_cfg->emummc_cfg.base_cfg.fs_ver = emu_cfg.fs_ver;
|
||||||
|
exo_cfg->emummc_cfg.base_cfg.id = emu_cfg.id;
|
||||||
|
|
||||||
|
if (emu_cfg.sector)
|
||||||
|
exo_cfg->emummc_cfg.partition_cfg.start_sector = emu_cfg.sector;
|
||||||
|
else
|
||||||
|
strcpy((char *)exo_cfg->emummc_cfg.file_cfg.path, emu_cfg.path);
|
||||||
|
|
||||||
|
if (emu_cfg.nintendo_path && !ctxt->stock)
|
||||||
|
strcpy((char *)exo_cfg->emummc_cfg.nintendo_path, emu_cfg.nintendo_path);
|
||||||
|
else if (ctxt->stock)
|
||||||
|
strcpy((char *)exo_cfg->emummc_cfg.nintendo_path, "Nintendo");
|
||||||
|
else
|
||||||
|
exo_cfg->emummc_cfg.nintendo_path[0] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *get_error_desc(u32 error_desc)
|
||||||
|
{
|
||||||
|
switch (error_desc)
|
||||||
|
{
|
||||||
|
case 0x100:
|
||||||
|
return "Instruction Abort";
|
||||||
|
case 0x101:
|
||||||
|
return "Data Abort";
|
||||||
|
case 0x102:
|
||||||
|
return "PC Misalignment";
|
||||||
|
case 0x103:
|
||||||
|
return "SP Misalignment";
|
||||||
|
case 0x104:
|
||||||
|
return "Trap";
|
||||||
|
case 0x106:
|
||||||
|
return "SError";
|
||||||
|
case 0x301:
|
||||||
|
return "Bad SVC";
|
||||||
|
case 0xFFE:
|
||||||
|
return "std::abort()";
|
||||||
|
default:
|
||||||
|
return "Unknown";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void secmon_exo_check_panic()
|
||||||
|
{
|
||||||
|
volatile atm_fatal_error_ctx *rpt = (atm_fatal_error_ctx *)ATM_FATAL_ERR_CTX_ADDR;
|
||||||
|
|
||||||
|
// Mask magic to maintain compatibility with any AFE version, thanks to additive struct members.
|
||||||
|
if ((rpt->magic & 0xF0FFFFFF) != ATM_FATAL_MAGIC)
|
||||||
|
return;
|
||||||
|
|
||||||
|
gfx_clear_grey(0x1B);
|
||||||
|
gfx_con_setpos(0, 0);
|
||||||
|
|
||||||
|
WPRINTF("Panic occurred while running Atmosphere.\n\n");
|
||||||
|
WPRINTFARGS("Title ID: %08X%08X", (u32)((u64)rpt->title_id >> 32), (u32)rpt->title_id);
|
||||||
|
WPRINTFARGS("Error Desc: %s (0x%x)\n", get_error_desc(rpt->error_desc), rpt->error_desc);
|
||||||
|
|
||||||
|
// Save context to the SD card.
|
||||||
|
char filepath[0x40];
|
||||||
|
f_mkdir("atmosphere/fatal_errors");
|
||||||
|
strcpy(filepath, "/atmosphere/fatal_errors/report_");
|
||||||
|
itoa((u32)((u64)rpt->report_identifier >> 32), filepath + strlen(filepath), 16);
|
||||||
|
itoa((u32)(rpt->report_identifier), filepath + strlen(filepath), 16);
|
||||||
|
strcat(filepath, ".bin");
|
||||||
|
|
||||||
|
sd_save_to_file((void *)rpt, sizeof(atm_fatal_error_ctx), filepath);
|
||||||
|
|
||||||
|
gfx_con.fntsz = 8;
|
||||||
|
WPRINTFARGS("Report saved to %s\n", filepath);
|
||||||
|
|
||||||
|
// Change magic to invalid, to prevent double-display of error/bootlooping.
|
||||||
|
rpt->magic = 0x0;
|
||||||
|
|
||||||
|
gfx_con.fntsz = 16;
|
||||||
|
gfx_printf("\n\nPress POWER to continue.\n");
|
||||||
|
|
||||||
|
display_backlight_brightness(100, 1000);
|
||||||
|
msleep(1000);
|
||||||
|
|
||||||
|
u32 btn = btn_wait();
|
||||||
|
while (!(btn & BTN_POWER))
|
||||||
|
btn = btn_wait();
|
||||||
|
|
||||||
|
display_backlight_brightness(0, 1000);
|
||||||
|
gfx_con_setpos(0, 0);
|
||||||
|
}
|
||||||
25
source/hos/secmon_exo.h
Normal file
25
source/hos/secmon_exo.h
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2019 CTCaer
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _SECMON_EXO_H_
|
||||||
|
#define _SECMON_EXO_H_
|
||||||
|
|
||||||
|
#include "../utils/types.h"
|
||||||
|
|
||||||
|
void config_exosphere(launch_ctxt_t *ctxt);
|
||||||
|
void secmon_exo_check_panic();
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -16,19 +16,27 @@
|
|||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "hos.h"
|
||||||
|
#include "fss.h"
|
||||||
#include "sept.h"
|
#include "sept.h"
|
||||||
|
#include "../config/config.h"
|
||||||
#include "../gfx/di.h"
|
#include "../gfx/di.h"
|
||||||
|
#include "../ianos/ianos.h"
|
||||||
#include "../libs/fatfs/ff.h"
|
#include "../libs/fatfs/ff.h"
|
||||||
#include "../mem/heap.h"
|
#include "../mem/heap.h"
|
||||||
|
#include "../soc/hw_init.h"
|
||||||
#include "../soc/pmc.h"
|
#include "../soc/pmc.h"
|
||||||
#include "../soc/t210.h"
|
#include "../soc/t210.h"
|
||||||
|
#include "../storage/emummc.h"
|
||||||
#include "../storage/nx_emmc.h"
|
#include "../storage/nx_emmc.h"
|
||||||
|
#include "../storage/nx_sd.h"
|
||||||
#include "../storage/sdmmc.h"
|
#include "../storage/sdmmc.h"
|
||||||
#include "../utils/btn.h"
|
#include "../utils/btn.h"
|
||||||
#include "../utils/types.h"
|
#include "../utils/types.h"
|
||||||
|
|
||||||
#include "../gfx/gfx.h"
|
#include "../gfx/gfx.h"
|
||||||
|
|
||||||
|
#define RELOC_META_OFF 0x7C
|
||||||
#define PATCHED_RELOC_SZ 0x94
|
#define PATCHED_RELOC_SZ 0x94
|
||||||
|
|
||||||
#define WB_RST_ADDR 0x40010ED0
|
#define WB_RST_ADDR 0x40010ED0
|
||||||
@@ -49,27 +57,108 @@ u8 warmboot_reboot[] = {
|
|||||||
#define SEPT_PRI_ADDR 0x4003F000
|
#define SEPT_PRI_ADDR 0x4003F000
|
||||||
|
|
||||||
#define SEPT_PK1T_ADDR 0xC0400000
|
#define SEPT_PK1T_ADDR 0xC0400000
|
||||||
#define SEPT_PK1T_STACK 0x40008000
|
|
||||||
#define SEPT_TCSZ_ADDR (SEPT_PK1T_ADDR - 0x4)
|
#define SEPT_TCSZ_ADDR (SEPT_PK1T_ADDR - 0x4)
|
||||||
#define SEPT_STG1_ADDR (SEPT_PK1T_ADDR + 0x2E100)
|
#define SEPT_STG1_ADDR (SEPT_PK1T_ADDR + 0x2E100)
|
||||||
#define SEPT_STG2_ADDR (SEPT_PK1T_ADDR + 0x60E0)
|
#define SEPT_STG2_ADDR (SEPT_PK1T_ADDR + 0x60E0)
|
||||||
#define SEPT_PKG_SZ (0x2F100 + WB_RST_SIZE)
|
#define SEPT_PKG_SZ (0x2F100 + WB_RST_SIZE)
|
||||||
|
|
||||||
extern boot_cfg_t b_cfg;
|
extern boot_cfg_t b_cfg;
|
||||||
extern void sd_unmount();
|
extern hekate_config h_cfg;
|
||||||
|
extern const volatile ipl_ver_meta_t ipl_ver;
|
||||||
|
|
||||||
|
extern bool is_ipl_updated(void *buf);
|
||||||
extern void reloc_patcher(u32 payload_dst, u32 payload_src, u32 payload_size);
|
extern void reloc_patcher(u32 payload_dst, u32 payload_src, u32 payload_size);
|
||||||
|
|
||||||
int reboot_to_sept(const u8 *tsec_fw, const u32 tsec_size, const u32 kb)
|
void check_sept(ini_sec_t *cfg_sec)
|
||||||
|
{
|
||||||
|
hos_eks_get();
|
||||||
|
|
||||||
|
// Check if non-hekate payload is used for sept and restore it.
|
||||||
|
if (h_cfg.sept_run)
|
||||||
|
{
|
||||||
|
if (!f_stat("sept/payload.bak", NULL))
|
||||||
|
{
|
||||||
|
f_unlink("sept/payload.bin");
|
||||||
|
f_rename("sept/payload.bak", "sept/payload.bin");
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
u8 *pkg1 = (u8 *)calloc(1, 0x40000);
|
||||||
|
|
||||||
|
sdmmc_storage_t storage;
|
||||||
|
sdmmc_t sdmmc;
|
||||||
|
int res = emummc_storage_init_mmc(&storage, &sdmmc);
|
||||||
|
if (res)
|
||||||
|
{
|
||||||
|
if (res == 2)
|
||||||
|
EPRINTF("Failed to init eMMC");
|
||||||
|
else
|
||||||
|
EPRINTF("Failed to init emuMMC");
|
||||||
|
|
||||||
|
goto out_free;
|
||||||
|
}
|
||||||
|
|
||||||
|
emummc_storage_set_mmc_partition(&storage, EMMC_BOOT0);
|
||||||
|
|
||||||
|
// Read package1.
|
||||||
|
emummc_storage_read(&storage, 0x100000 / NX_EMMC_BLOCKSIZE, 0x40000 / NX_EMMC_BLOCKSIZE, pkg1);
|
||||||
|
const pkg1_id_t *pkg1_id = pkg1_identify(pkg1);
|
||||||
|
if (!pkg1_id)
|
||||||
|
{
|
||||||
|
gfx_con.fntsz = 16;
|
||||||
|
EPRINTF("Unknown pkg1 version.");
|
||||||
|
goto out_free;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pkg1_id->kb >= KB_FIRMWARE_VERSION_700 && !h_cfg.sept_run)
|
||||||
|
{
|
||||||
|
u8 key_idx = pkg1_id->kb - KB_FIRMWARE_VERSION_700;
|
||||||
|
if (h_cfg.eks && (h_cfg.eks->enabled & (1 << key_idx)))
|
||||||
|
{
|
||||||
|
h_cfg.sept_run = true;
|
||||||
|
EMC(EMC_SCRATCH0) |= EMC_SEPT_RUN;
|
||||||
|
goto out_free;
|
||||||
|
}
|
||||||
|
|
||||||
|
sdmmc_storage_end(&storage);
|
||||||
|
reboot_to_sept((u8 *)pkg1 + pkg1_id->tsec_off, pkg1_id->kb, cfg_sec);
|
||||||
|
}
|
||||||
|
|
||||||
|
out_free:
|
||||||
|
free(pkg1);
|
||||||
|
sdmmc_storage_end(&storage);
|
||||||
|
}
|
||||||
|
|
||||||
|
int reboot_to_sept(const u8 *tsec_fw, u32 kb, ini_sec_t *cfg_sec)
|
||||||
{
|
{
|
||||||
FIL fp;
|
FIL fp;
|
||||||
|
bool fss0_sept_used = false;
|
||||||
|
|
||||||
// Copy warmboot reboot code and TSEC fw.
|
// Copy warmboot reboot code and TSEC fw.
|
||||||
|
u32 tsec_fw_size = 0x3000;
|
||||||
|
if (kb > KB_FIRMWARE_VERSION_700)
|
||||||
|
tsec_fw_size = 0x3300;
|
||||||
memcpy((u8 *)(SEPT_PK1T_ADDR - WB_RST_SIZE), (u8 *)warmboot_reboot, sizeof(warmboot_reboot));
|
memcpy((u8 *)(SEPT_PK1T_ADDR - WB_RST_SIZE), (u8 *)warmboot_reboot, sizeof(warmboot_reboot));
|
||||||
memcpy((void *)SEPT_PK1T_ADDR, tsec_fw, tsec_size);
|
memcpy((void *)SEPT_PK1T_ADDR, tsec_fw, tsec_fw_size);
|
||||||
*(vu32 *)SEPT_TCSZ_ADDR = tsec_size;
|
*(vu32 *)SEPT_TCSZ_ADDR = tsec_fw_size;
|
||||||
|
|
||||||
|
if (cfg_sec)
|
||||||
|
{
|
||||||
|
fss0_sept_t sept_ctxt;
|
||||||
|
sept_ctxt.kb = kb;
|
||||||
|
sept_ctxt.cfg_sec = cfg_sec;
|
||||||
|
sept_ctxt.sept_primary = (void *)SEPT_STG1_ADDR;
|
||||||
|
sept_ctxt.sept_secondary = (void *)SEPT_STG2_ADDR;
|
||||||
|
|
||||||
|
fss0_sept_used = load_sept_from_ffs0(&sept_ctxt);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!fss0_sept_used)
|
||||||
|
{
|
||||||
// Copy sept-primary.
|
// Copy sept-primary.
|
||||||
if (f_open(&fp, "sd:/sept/sept-primary.bin", FA_READ))
|
if (f_open(&fp, "sept/sept-primary.bin", FA_READ))
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
if (f_read(&fp, (u8 *)SEPT_STG1_ADDR, f_size(&fp), NULL))
|
if (f_read(&fp, (u8 *)SEPT_STG1_ADDR, f_size(&fp), NULL))
|
||||||
@@ -80,10 +169,17 @@ int reboot_to_sept(const u8 *tsec_fw, const u32 tsec_size, const u32 kb)
|
|||||||
f_close(&fp);
|
f_close(&fp);
|
||||||
|
|
||||||
// Copy sept-secondary.
|
// Copy sept-secondary.
|
||||||
if ((kb == 7) && f_open(&fp, "sd:/sept/sept-secondary.enc", FA_READ) && f_open(&fp, "sd:/sept/sept-secondary_00.enc", FA_READ))
|
if (kb < KB_FIRMWARE_VERSION_810)
|
||||||
|
{
|
||||||
|
if (f_open(&fp, "sept/sept-secondary_00.enc", FA_READ))
|
||||||
|
if (f_open(&fp, "sept/sept-secondary.enc", FA_READ)) // Try the deprecated version.
|
||||||
goto error;
|
goto error;
|
||||||
else if ((kb == 8) && f_open(&fp, "sd:/sept/sept-secondary_01.enc", FA_READ))
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (f_open(&fp, "sept/sept-secondary_01.enc", FA_READ))
|
||||||
goto error;
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
if (f_read(&fp, (u8 *)SEPT_STG2_ADDR, f_size(&fp), NULL))
|
if (f_read(&fp, (u8 *)SEPT_STG2_ADDR, f_size(&fp), NULL))
|
||||||
{
|
{
|
||||||
@@ -91,24 +187,48 @@ int reboot_to_sept(const u8 *tsec_fw, const u32 tsec_size, const u32 kb)
|
|||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
f_close(&fp);
|
f_close(&fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
b_cfg.boot_cfg |= (BOOT_CFG_AUTOBOOT_EN | BOOT_CFG_SEPT_RUN);
|
||||||
|
|
||||||
|
bool update_sept_payload = true;
|
||||||
|
if (!f_open(&fp, "sept/payload.bin", FA_READ | FA_WRITE))
|
||||||
|
{
|
||||||
|
ipl_ver_meta_t tmp_ver;
|
||||||
|
f_lseek(&fp, PATCHED_RELOC_SZ + sizeof(boot_cfg_t));
|
||||||
|
f_read(&fp, &tmp_ver, sizeof(ipl_ver_meta_t), NULL);
|
||||||
|
|
||||||
|
if (tmp_ver.magic == ipl_ver.magic)
|
||||||
|
{
|
||||||
|
if (tmp_ver.version == ipl_ver.version)
|
||||||
|
{
|
||||||
// Save auto boot config to sept payload, if any.
|
// Save auto boot config to sept payload, if any.
|
||||||
boot_cfg_t *tmp_cfg = malloc(sizeof(boot_cfg_t));
|
boot_cfg_t *tmp_cfg = malloc(sizeof(boot_cfg_t));
|
||||||
memcpy(tmp_cfg, &b_cfg, sizeof(boot_cfg_t));
|
memcpy(tmp_cfg, &b_cfg, sizeof(boot_cfg_t));
|
||||||
|
|
||||||
tmp_cfg->boot_cfg |= BOOT_CFG_SEPT_RUN;
|
|
||||||
|
|
||||||
if (f_open(&fp, "sd:/sept/payload.bin", FA_READ | FA_WRITE))
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
f_lseek(&fp, PATCHED_RELOC_SZ);
|
f_lseek(&fp, PATCHED_RELOC_SZ);
|
||||||
f_write(&fp, tmp_cfg, sizeof(boot_cfg_t), NULL);
|
f_write(&fp, tmp_cfg, sizeof(boot_cfg_t), NULL);
|
||||||
|
update_sept_payload = false;
|
||||||
|
}
|
||||||
|
|
||||||
f_close(&fp);
|
f_close(&fp);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
f_close(&fp);
|
||||||
|
f_rename("sept/payload.bin", "sept/payload.bak"); // Backup foreign payload.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (update_sept_payload)
|
||||||
|
{
|
||||||
|
volatile reloc_meta_t *reloc = (reloc_meta_t *)(IPL_LOAD_ADDR + RELOC_META_OFF);
|
||||||
|
f_mkdir("sept");
|
||||||
|
f_open(&fp, "sept/payload.bin", FA_WRITE | FA_CREATE_ALWAYS);
|
||||||
|
f_write(&fp, (u8 *)reloc->start, reloc->end - reloc->start, NULL);
|
||||||
|
f_close(&fp);
|
||||||
|
}
|
||||||
|
|
||||||
sd_unmount();
|
sd_unmount();
|
||||||
gfx_printf("\n%kPress Power or Vol +/-\n%k to Reboot to Sept...", COLOR_BLUE, COLOR_VIOLET);
|
|
||||||
btn_wait();
|
|
||||||
|
|
||||||
u32 pk1t_sept = SEPT_PK1T_ADDR - (ALIGN(PATCHED_RELOC_SZ, 0x10) + WB_RST_SIZE);
|
u32 pk1t_sept = SEPT_PK1T_ADDR - (ALIGN(PATCHED_RELOC_SZ, 0x10) + WB_RST_SIZE);
|
||||||
|
|
||||||
@@ -123,13 +243,13 @@ int reboot_to_sept(const u8 *tsec_fw, const u32 tsec_size, const u32 kb)
|
|||||||
PMC(APBDEV_PMC_SCRATCH33) = SEPT_PRI_ADDR;
|
PMC(APBDEV_PMC_SCRATCH33) = SEPT_PRI_ADDR;
|
||||||
PMC(APBDEV_PMC_SCRATCH40) = 0x6000F208;
|
PMC(APBDEV_PMC_SCRATCH40) = 0x6000F208;
|
||||||
|
|
||||||
display_end();
|
reconfig_hw_workaround(false, 0);
|
||||||
|
|
||||||
(*sept)();
|
(*sept)();
|
||||||
|
|
||||||
error:
|
error:
|
||||||
EPRINTF("Sept files not found in sd:/sept!\nPlace appropriate files and try again.");
|
gfx_con.mute = false;
|
||||||
display_backlight_brightness(100, 1000);
|
EPRINTF("Failed to run sept\n");
|
||||||
|
|
||||||
btn_wait();
|
btn_wait();
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
|
|
||||||
#include "../utils/types.h"
|
#include "../utils/types.h"
|
||||||
|
|
||||||
int reboot_to_sept(const u8 *tsec_fw, const u32 tsec_size, const u32 kb);
|
void check_sept(ini_sec_t *cfg_sec);
|
||||||
|
int reboot_to_sept(const u8 *tsec_fw, u32 kb, ini_sec_t *cfg_sec);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
128
source/ianos/ianos.c
Normal file
128
source/ianos/ianos.c
Normal file
@@ -0,0 +1,128 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2018 M4xw
|
||||||
|
* Copyright (c) 2018-2019 CTCaer
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "ianos.h"
|
||||||
|
#include "../../common/common_module.h"
|
||||||
|
#include "../gfx/gfx.h"
|
||||||
|
#include "../libs/elfload/elfload.h"
|
||||||
|
#include "../mem/heap.h"
|
||||||
|
#include "../storage/nx_sd.h"
|
||||||
|
#include "../utils/types.h"
|
||||||
|
|
||||||
|
#define IRAM_LIB_ADDR 0x4002B000
|
||||||
|
#define DRAM_LIB_ADDR 0xE0000000
|
||||||
|
|
||||||
|
extern heap_t _heap;
|
||||||
|
|
||||||
|
void *elfBuf = NULL;
|
||||||
|
void *fileBuf = NULL;
|
||||||
|
|
||||||
|
static void _ianos_call_ep(moduleEntrypoint_t entrypoint, void *moduleConfig)
|
||||||
|
{
|
||||||
|
bdkParams_t bdkParameters = (bdkParams_t)malloc(sizeof(struct _bdkParams_t));
|
||||||
|
bdkParameters->gfxCon = &gfx_con;
|
||||||
|
bdkParameters->gfxCtx = &gfx_ctxt;
|
||||||
|
bdkParameters->memcpy = (memcpy_t)&memcpy;
|
||||||
|
bdkParameters->memset = (memset_t)&memset;
|
||||||
|
bdkParameters->sharedHeap = &_heap;
|
||||||
|
|
||||||
|
entrypoint(moduleConfig, bdkParameters);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *_ianos_alloc_cb(el_ctx *ctx, Elf_Addr phys, Elf_Addr virt, Elf_Addr size)
|
||||||
|
{
|
||||||
|
(void)ctx;
|
||||||
|
(void)phys;
|
||||||
|
(void)size;
|
||||||
|
return (void *)virt;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool _ianos_read_cb(el_ctx *ctx, void *dest, size_t numberBytes, size_t offset)
|
||||||
|
{
|
||||||
|
(void)ctx;
|
||||||
|
|
||||||
|
memcpy(dest, fileBuf + offset, numberBytes);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO: Support shared libraries.
|
||||||
|
uintptr_t ianos_loader(bool sdmount, char *path, elfType_t type, void *moduleConfig)
|
||||||
|
{
|
||||||
|
uintptr_t epaddr = 0;
|
||||||
|
|
||||||
|
if (sdmount)
|
||||||
|
{
|
||||||
|
if (!sd_mount())
|
||||||
|
goto elfLoadFinalOut;
|
||||||
|
}
|
||||||
|
|
||||||
|
fileBuf = sd_file_read(path, NULL);
|
||||||
|
|
||||||
|
if (sdmount)
|
||||||
|
sd_unmount();
|
||||||
|
|
||||||
|
if (!fileBuf)
|
||||||
|
goto elfLoadFinalOut;
|
||||||
|
|
||||||
|
|
||||||
|
el_ctx ctx;
|
||||||
|
ctx.pread = _ianos_read_cb;
|
||||||
|
|
||||||
|
if (el_init(&ctx))
|
||||||
|
goto elfLoadFinalOut;
|
||||||
|
|
||||||
|
// Set our relocated library's buffer.
|
||||||
|
switch (type & 0xFFFF)
|
||||||
|
{
|
||||||
|
case EXEC_ELF:
|
||||||
|
case AR64_ELF:
|
||||||
|
elfBuf = (void *)DRAM_LIB_ADDR;
|
||||||
|
sd_unmount();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
elfBuf = malloc(ctx.memsz); // Aligned to 0x10 by default.
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!elfBuf)
|
||||||
|
goto elfLoadFinalOut;
|
||||||
|
|
||||||
|
// Load and relocate library.
|
||||||
|
ctx.base_load_vaddr = ctx.base_load_paddr = (uintptr_t)elfBuf;
|
||||||
|
if (el_load(&ctx, _ianos_alloc_cb))
|
||||||
|
goto elfFreeOut;
|
||||||
|
|
||||||
|
if (el_relocate(&ctx))
|
||||||
|
goto elfFreeOut;
|
||||||
|
|
||||||
|
// Launch.
|
||||||
|
epaddr = ctx.ehdr.e_entry + (uintptr_t)elfBuf;
|
||||||
|
moduleEntrypoint_t ep = (moduleEntrypoint_t)epaddr;
|
||||||
|
|
||||||
|
_ianos_call_ep(ep, moduleConfig);
|
||||||
|
|
||||||
|
elfFreeOut:
|
||||||
|
free(fileBuf);
|
||||||
|
elfBuf = NULL;
|
||||||
|
fileBuf = NULL;
|
||||||
|
|
||||||
|
elfLoadFinalOut:
|
||||||
|
|
||||||
|
return epaddr;
|
||||||
|
}
|
||||||
34
source/ianos/ianos.h
Normal file
34
source/ianos/ianos.h
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2018 M4xw
|
||||||
|
* Copyright (c) 2018 CTCaer
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef IANOS_H
|
||||||
|
#define IANOS_H
|
||||||
|
|
||||||
|
#include "../utils/types.h"
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
DRAM_LIB = 0, // DRAM library.
|
||||||
|
EXEC_ELF = 1, // Executable elf that does not return.
|
||||||
|
DR64_LIB = 2, // AARCH64 DRAM library.
|
||||||
|
AR64_ELF = 3, // Executable elf that does not return.
|
||||||
|
KEEP_IN_RAM = (1 << 31) // Shared library mask.
|
||||||
|
} elfType_t;
|
||||||
|
|
||||||
|
uintptr_t ianos_loader(bool sdmount, char *path, elfType_t type, void* config);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -1,141 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2019 shchmue
|
|
||||||
*
|
|
||||||
* 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/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
static const u8 zeros[0x10] = {0};
|
|
||||||
|
|
||||||
static const u8 keyblob_key_source[][0x10] = {
|
|
||||||
{0xDF, 0x20, 0x6F, 0x59, 0x44, 0x54, 0xEF, 0xDC, 0x70, 0x74, 0x48, 0x3B, 0x0D, 0xED, 0x9F, 0xD3}, //1.0.0
|
|
||||||
{0x0C, 0x25, 0x61, 0x5D, 0x68, 0x4C, 0xEB, 0x42, 0x1C, 0x23, 0x79, 0xEA, 0x82, 0x25, 0x12, 0xAC}, //3.0.0
|
|
||||||
{0x33, 0x76, 0x85, 0xEE, 0x88, 0x4A, 0xAE, 0x0A, 0xC2, 0x8A, 0xFD, 0x7D, 0x63, 0xC0, 0x43, 0x3B}, //3.0.1
|
|
||||||
{0x2D, 0x1F, 0x48, 0x80, 0xED, 0xEC, 0xED, 0x3E, 0x3C, 0xF2, 0x48, 0xB5, 0x65, 0x7D, 0xF7, 0xBE}, //4.0.0
|
|
||||||
{0xBB, 0x5A, 0x01, 0xF9, 0x88, 0xAF, 0xF5, 0xFC, 0x6C, 0xFF, 0x07, 0x9E, 0x13, 0x3C, 0x39, 0x80}, //5.0.0
|
|
||||||
{0xD8, 0xCC, 0xE1, 0x26, 0x6A, 0x35, 0x3F, 0xCC, 0x20, 0xF3, 0x2D, 0x3B, 0x51, 0x7D, 0xE9, 0xC0} //6.0.0
|
|
||||||
};
|
|
||||||
|
|
||||||
static const u8 master_kek_sources[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_VERSION_600][0x10] = {
|
|
||||||
{0x37, 0x4B, 0x77, 0x29, 0x59, 0xB4, 0x04, 0x30, 0x81, 0xF6, 0xE5, 0x8C, 0x6D, 0x36, 0x17, 0x9A}, //6.2.0
|
|
||||||
{0x9A, 0x3E, 0xA9, 0xAB, 0xFD, 0x56, 0x46, 0x1C, 0x9B, 0xF6, 0x48, 0x7F, 0x5C, 0xFA, 0x09, 0x5C}, //7.0.0
|
|
||||||
{0xDE, 0xDC, 0xE3, 0x39, 0x30, 0x88, 0x16, 0xF8, 0xAE, 0x97, 0xAD, 0xEC, 0x64, 0x2D, 0x41, 0x41}, //8.1.0
|
|
||||||
};
|
|
||||||
|
|
||||||
static const u8 mkey_vectors[KB_FIRMWARE_VERSION_MAX+1][0x10] =
|
|
||||||
{
|
|
||||||
{0x0C, 0xF0, 0x59, 0xAC, 0x85, 0xF6, 0x26, 0x65, 0xE1, 0xE9, 0x19, 0x55, 0xE6, 0xF2, 0x67, 0x3D}, /* Zeroes encrypted with Master Key 00. */
|
|
||||||
{0x29, 0x4C, 0x04, 0xC8, 0xEB, 0x10, 0xED, 0x9D, 0x51, 0x64, 0x97, 0xFB, 0xF3, 0x4D, 0x50, 0xDD}, /* Master key 00 encrypted with Master key 01. */
|
|
||||||
{0xDE, 0xCF, 0xEB, 0xEB, 0x10, 0xAE, 0x74, 0xD8, 0xAD, 0x7C, 0xF4, 0x9E, 0x62, 0xE0, 0xE8, 0x72}, /* Master key 01 encrypted with Master key 02. */
|
|
||||||
{0x0A, 0x0D, 0xDF, 0x34, 0x22, 0x06, 0x6C, 0xA4, 0xE6, 0xB1, 0xEC, 0x71, 0x85, 0xCA, 0x4E, 0x07}, /* Master key 02 encrypted with Master key 03. */
|
|
||||||
{0x6E, 0x7D, 0x2D, 0xC3, 0x0F, 0x59, 0xC8, 0xFA, 0x87, 0xA8, 0x2E, 0xD5, 0x89, 0x5E, 0xF3, 0xE9}, /* Master key 03 encrypted with Master key 04. */
|
|
||||||
{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. */
|
|
||||||
};
|
|
||||||
|
|
||||||
//======================================Keys======================================//
|
|
||||||
// from Package1 -> Secure_Monitor
|
|
||||||
static const u8 aes_kek_generation_source[0x10] = {
|
|
||||||
0x4D, 0x87, 0x09, 0x86, 0xC4, 0x5D, 0x20, 0x72, 0x2F, 0xBA, 0x10, 0x53, 0xDA, 0x92, 0xE8, 0xA9};
|
|
||||||
static const u8 aes_kek_seed_01[0x10] = {
|
|
||||||
0xA2, 0xAB, 0xBF, 0x9C, 0x92, 0x2F, 0xBB, 0xE3, 0x78, 0x79, 0x9B, 0xC0, 0xCC, 0xEA, 0xA5, 0x74};
|
|
||||||
static const u8 aes_kek_seed_03[0x10] = {
|
|
||||||
0xE5, 0x4D, 0x9A, 0x02, 0xF0, 0x4F, 0x5F, 0xA8, 0xAD, 0x76, 0x0A, 0xF6, 0x32, 0x95, 0x59, 0xBB};
|
|
||||||
static const u8 package2_key_source[0x10] = {
|
|
||||||
0xFB, 0x8B, 0x6A, 0x9C, 0x79, 0x00, 0xC8, 0x49, 0xEF, 0xD2, 0x4D, 0x85, 0x4D, 0x30, 0xA0, 0xC7};
|
|
||||||
static const u8 titlekek_source[0x10] = {
|
|
||||||
0x1E, 0xDC, 0x7B, 0x3B, 0x60, 0xE6, 0xB4, 0xD8, 0x78, 0xB8, 0x17, 0x15, 0x98, 0x5E, 0x62, 0x9B};
|
|
||||||
static const u8 retail_specific_aes_key_source[0x10] = {
|
|
||||||
0xE2, 0xD6, 0xB8, 0x7A, 0x11, 0x9C, 0xB8, 0x80, 0xE8, 0x22, 0x88, 0x8A, 0x46, 0xFB, 0xA1, 0x95};
|
|
||||||
|
|
||||||
// from Package1ldr (or Secure_Monitor on 6.2.0)
|
|
||||||
static const u8 keyblob_mac_key_source[0x10] = {
|
|
||||||
0x59, 0xC7, 0xFB, 0x6F, 0xBE, 0x9B, 0xBE, 0x87, 0x65, 0x6B, 0x15, 0xC0, 0x53, 0x73, 0x36, 0xA5};
|
|
||||||
static const u8 master_key_source[0x10] = {
|
|
||||||
0xD8, 0xA2, 0x41, 0x0A, 0xC6, 0xC5, 0x90, 0x01, 0xC6, 0x1D, 0x6A, 0x26, 0x7C, 0x51, 0x3F, 0x3C};
|
|
||||||
static const u8 per_console_key_source[0x10] = {
|
|
||||||
0x4F, 0x02, 0x5F, 0x0E, 0xB6, 0x6D, 0x11, 0x0E, 0xDC, 0x32, 0x7D, 0x41, 0x86, 0xC2, 0xF4, 0x78};
|
|
||||||
|
|
||||||
// from SPL
|
|
||||||
static const u8 aes_key_generation_source[0x10] = {
|
|
||||||
0x89, 0x61, 0x5E, 0xE0, 0x5C, 0x31, 0xB6, 0x80, 0x5F, 0xE5, 0x8F, 0x3D, 0xA2, 0x4F, 0x7A, 0xA8};
|
|
||||||
|
|
||||||
// from FS
|
|
||||||
static const u8 bis_kek_source[0x10] = {
|
|
||||||
0x34, 0xC1, 0xA0, 0xC4, 0x82, 0x58, 0xF8, 0xB4, 0xFA, 0x9E, 0x5E, 0x6A, 0xDA, 0xFC, 0x7E, 0x4F};
|
|
||||||
static const u8 bis_key_source[3][0x20] = {
|
|
||||||
{
|
|
||||||
0xF8, 0x3F, 0x38, 0x6E, 0x2C, 0xD2, 0xCA, 0x32, 0xA8, 0x9A, 0xB9, 0xAA, 0x29, 0xBF, 0xC7, 0x48,
|
|
||||||
0x7D, 0x92, 0xB0, 0x3A, 0xA8, 0xBF, 0xDE, 0xE1, 0xA7, 0x4C, 0x3B, 0x6E, 0x35, 0xCB, 0x71, 0x06},
|
|
||||||
{
|
|
||||||
0x41, 0x00, 0x30, 0x49, 0xDD, 0xCC, 0xC0, 0x65, 0x64, 0x7A, 0x7E, 0xB4, 0x1E, 0xED, 0x9C, 0x5F,
|
|
||||||
0x44, 0x42, 0x4E, 0xDA, 0xB4, 0x9D, 0xFC, 0xD9, 0x87, 0x77, 0x24, 0x9A, 0xDC, 0x9F, 0x7C, 0xA4},
|
|
||||||
{
|
|
||||||
0x52, 0xC2, 0xE9, 0xEB, 0x09, 0xE3, 0xEE, 0x29, 0x32, 0xA1, 0x0C, 0x1F, 0xB6, 0xA0, 0x92, 0x6C,
|
|
||||||
0x4D, 0x12, 0xE1, 0x4B, 0x2A, 0x47, 0x4C, 0x1C, 0x09, 0xCB, 0x03, 0x59, 0xF0, 0x15, 0xF4, 0xE4}
|
|
||||||
};
|
|
||||||
|
|
||||||
static const u8 fs_hashes_sha256[10][0x20] = {
|
|
||||||
{ // header_kek_source
|
|
||||||
0x18, 0x88, 0xca, 0xed, 0x55, 0x51, 0xb3, 0xed, 0xe0, 0x14, 0x99, 0xe8, 0x7c, 0xe0, 0xd8, 0x68,
|
|
||||||
0x27, 0xf8, 0x08, 0x20, 0xef, 0xb2, 0x75, 0x92, 0x10, 0x55, 0xaa, 0x4e, 0x2a, 0xbd, 0xff, 0xc2},
|
|
||||||
{ // header_key_source
|
|
||||||
0x8f, 0x78, 0x3e, 0x46, 0x85, 0x2d, 0xf6, 0xbe, 0x0b, 0xa4, 0xe1, 0x92, 0x73, 0xc4, 0xad, 0xba,
|
|
||||||
0xee, 0x16, 0x38, 0x00, 0x43, 0xe1, 0xb8, 0xc4, 0x18, 0xc4, 0x08, 0x9a, 0x8b, 0xd6, 0x4a, 0xa6},
|
|
||||||
{ // key_area_key_application_source
|
|
||||||
0x04, 0xad, 0x66, 0x14, 0x3c, 0x72, 0x6b, 0x2a, 0x13, 0x9f, 0xb6, 0xb2, 0x11, 0x28, 0xb4, 0x6f,
|
|
||||||
0x56, 0xc5, 0x53, 0xb2, 0xb3, 0x88, 0x71, 0x10, 0x30, 0x42, 0x98, 0xd8, 0xd0, 0x09, 0x2d, 0x9e},
|
|
||||||
{ // key_area_key_ocean_source
|
|
||||||
0xfd, 0x43, 0x40, 0x00, 0xc8, 0xff, 0x2b, 0x26, 0xf8, 0xe9, 0xa9, 0xd2, 0xd2, 0xc1, 0x2f, 0x6b,
|
|
||||||
0xe5, 0x77, 0x3c, 0xbb, 0x9d, 0xc8, 0x63, 0x00, 0xe1, 0xbd, 0x99, 0xf8, 0xea, 0x33, 0xa4, 0x17},
|
|
||||||
{ // key_area_key_system_source
|
|
||||||
0x1f, 0x17, 0xb1, 0xfd, 0x51, 0xad, 0x1c, 0x23, 0x79, 0xb5, 0x8f, 0x15, 0x2c, 0xa4, 0x91, 0x2e,
|
|
||||||
0xc2, 0x10, 0x64, 0x41, 0xe5, 0x17, 0x22, 0xf3, 0x87, 0x00, 0xd5, 0x93, 0x7a, 0x11, 0x62, 0xf7},
|
|
||||||
{ // save_mac_kek_source
|
|
||||||
0x3D, 0xCB, 0xA1, 0x00, 0xAD, 0x4D, 0xF1, 0x54, 0x7F, 0xE3, 0xC4, 0x79, 0x5C, 0x4B, 0x22, 0x8A,
|
|
||||||
0xA9, 0x80, 0x38, 0xF0, 0x7A, 0x36, 0xF1, 0xBC, 0x14, 0x8E, 0xEA, 0xF3, 0xDC, 0xD7, 0x50, 0xF4},
|
|
||||||
{ // save_mac_key_source
|
|
||||||
0xB4, 0x7B, 0x60, 0x0B, 0x1A, 0xD3, 0x14, 0xF9, 0x41, 0x14, 0x7D, 0x8B, 0x39, 0x1D, 0x4B, 0x19,
|
|
||||||
0x87, 0xCC, 0x8C, 0x88, 0x4A, 0xC8, 0x9F, 0xFC, 0x91, 0xCA, 0xE2, 0x21, 0xC5, 0x24, 0x51, 0xF7},
|
|
||||||
{ // sd_card_kek_source
|
|
||||||
0x6B, 0x2E, 0xD8, 0x77, 0xC2, 0xC5, 0x23, 0x34, 0xAC, 0x51, 0xE5, 0x9A, 0xBF, 0xA7, 0xEC, 0x45,
|
|
||||||
0x7F, 0x4A, 0x7D, 0x01, 0xE4, 0x62, 0x91, 0xE9, 0xF2, 0xEA, 0xA4, 0x5F, 0x01, 0x1D, 0x24, 0xB7},
|
|
||||||
{ // sd_card_nca_key_source
|
|
||||||
0x2E, 0x75, 0x1C, 0xEC, 0xF7, 0xD9, 0x3A, 0x2B, 0x95, 0x7B, 0xD5, 0xFF, 0xCB, 0x08, 0x2F, 0xD0,
|
|
||||||
0x38, 0xCC, 0x28, 0x53, 0x21, 0x9D, 0xD3, 0x09, 0x2C, 0x6D, 0xAB, 0x98, 0x38, 0xF5, 0xA7, 0xCC},
|
|
||||||
{ // sd_card_save_key_source
|
|
||||||
0xD4, 0x82, 0x74, 0x35, 0x63, 0xD3, 0xEA, 0x5D, 0xCD, 0xC3, 0xB7, 0x4E, 0x97, 0xC9, 0xAC, 0x8A,
|
|
||||||
0x34, 0x21, 0x64, 0xFA, 0x04, 0x1A, 0x1D, 0xC8, 0x0F, 0x17, 0xF6, 0xD3, 0x1E, 0x4B, 0xC0, 0x1C}
|
|
||||||
};
|
|
||||||
|
|
||||||
static const u8 es_hashes_sha256[3][0x20] = {
|
|
||||||
{ // eticket_rsa_kek
|
|
||||||
0xB7, 0x1D, 0xB2, 0x71, 0xDC, 0x33, 0x8D, 0xF3, 0x80, 0xAA, 0x2C, 0x43, 0x35, 0xEF, 0x88, 0x73,
|
|
||||||
0xB1, 0xAF, 0xD4, 0x08, 0xE8, 0x0B, 0x35, 0x82, 0xD8, 0x71, 0x9F, 0xC8, 0x1C, 0x5E, 0x51, 0x1C},
|
|
||||||
{ // eticket_rsa_kekek
|
|
||||||
0xE8, 0x96, 0x5A, 0x18, 0x7D, 0x30, 0xE5, 0x78, 0x69, 0xF5, 0x62, 0xD0, 0x43, 0x83, 0xC9, 0x96,
|
|
||||||
0xDE, 0x48, 0x7B, 0xBA, 0x57, 0x61, 0x36, 0x3D, 0x2D, 0x4D, 0x32, 0x39, 0x18, 0x66, 0xA8, 0x5C},
|
|
||||||
{ // ssl_rsa_kek_source_x
|
|
||||||
0x69, 0xA0, 0x8E, 0x62, 0xE0, 0xAE, 0x50, 0x7B, 0xB5, 0xDA, 0x0E, 0x65, 0x17, 0x9A, 0xE3, 0xBE,
|
|
||||||
0x05, 0x1F, 0xED, 0x3C, 0x49, 0x94, 0x1D, 0xF4, 0xEF, 0x29, 0x56, 0xD3, 0x6D, 0x30, 0x11, 0x0C}
|
|
||||||
};
|
|
||||||
|
|
||||||
static const u8 ssl_hashes_sha256[2][0x20] = {
|
|
||||||
{ // ssl_rsa_kek_source_x
|
|
||||||
0x69, 0xA0, 0x8E, 0x62, 0xE0, 0xAE, 0x50, 0x7B, 0xB5, 0xDA, 0x0E, 0x65, 0x17, 0x9A, 0xE3, 0xBE,
|
|
||||||
0x05, 0x1F, 0xED, 0x3C, 0x49, 0x94, 0x1D, 0xF4, 0xEF, 0x29, 0x56, 0xD3, 0x6D, 0x30, 0x11, 0x0C},
|
|
||||||
{ // ssl_rsa_kek_source_y
|
|
||||||
0x1C, 0x86, 0xF3, 0x63, 0x26, 0x54, 0x17, 0xD4, 0x99, 0x22, 0x9E, 0xB1, 0xC4, 0xAD, 0xC7, 0x47,
|
|
||||||
0x9B, 0x2A, 0x15, 0xF9, 0x31, 0x26, 0x1F, 0x31, 0xEE, 0x67, 0x76, 0xAE, 0xB4, 0xC7, 0x65, 0x42}
|
|
||||||
};
|
|
||||||
@@ -1,871 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2019 shchmue
|
|
||||||
*
|
|
||||||
* 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 "keys.h"
|
|
||||||
#include "../gfx/di.h"
|
|
||||||
#include "../gfx/gfx.h"
|
|
||||||
#include "../hos/pkg1.h"
|
|
||||||
#include "../hos/pkg2.h"
|
|
||||||
#include "../hos/sept.h"
|
|
||||||
#include "../libs/fatfs/ff.h"
|
|
||||||
#include "../mem/heap.h"
|
|
||||||
#include "../mem/mc.h"
|
|
||||||
#include "../mem/sdram.h"
|
|
||||||
#include "../sec/se.h"
|
|
||||||
#include "../sec/se_t210.h"
|
|
||||||
#include "../sec/tsec.h"
|
|
||||||
#include "../soc/fuse.h"
|
|
||||||
#include "../soc/smmu.h"
|
|
||||||
#include "../soc/t210.h"
|
|
||||||
#include "../storage/nx_emmc.h"
|
|
||||||
#include "../storage/sdmmc.h"
|
|
||||||
#include "../utils/btn.h"
|
|
||||||
#include "../utils/list.h"
|
|
||||||
#include "../utils/sprintf.h"
|
|
||||||
#include "../utils/util.h"
|
|
||||||
|
|
||||||
#include "key_sources.inl"
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
extern bool sd_mount();
|
|
||||||
extern void sd_unmount();
|
|
||||||
extern int sd_save_to_file(void *buf, u32 size, const char *filename);
|
|
||||||
|
|
||||||
u32 _key_count = 0;
|
|
||||||
sdmmc_storage_t storage;
|
|
||||||
emmc_part_t *system_part;
|
|
||||||
|
|
||||||
#define TPRINTF(text) \
|
|
||||||
end_time = get_tmr_ms(); \
|
|
||||||
gfx_printf(text" done @ %d.%03ds\n", (end_time - start_time) / 1000, (end_time - start_time) % 1000)
|
|
||||||
#define TPRINTFARGS(text, args...) \
|
|
||||||
end_time = get_tmr_ms(); \
|
|
||||||
gfx_printf(text" done @ %d.%03ds\n", args, (end_time - start_time) / 1000, (end_time - start_time) % 1000)
|
|
||||||
#define SAVE_KEY(name, src, len) _save_key(name, src, len, text_buffer)
|
|
||||||
#define SAVE_KEY_FAMILY(name, src, count, len) _save_key_family(name, src, count, len, text_buffer)
|
|
||||||
|
|
||||||
static u8 temp_key[0x10],
|
|
||||||
bis_key[4][0x20] = {0},
|
|
||||||
device_key[0x10] = {0},
|
|
||||||
sd_seed[0x10] = {0},
|
|
||||||
// FS-related keys
|
|
||||||
fs_keys[10][0x20] = {0},
|
|
||||||
header_key[0x20] = {0},
|
|
||||||
save_mac_key[0x10] = {0},
|
|
||||||
// other sysmodule sources
|
|
||||||
es_keys[3][0x10] = {0},
|
|
||||||
eticket_rsa_kek[0x10] = {0},
|
|
||||||
ssl_keys[2][0x10] = {0},
|
|
||||||
ssl_rsa_kek[0x10] = {0},
|
|
||||||
// keyblob-derived families
|
|
||||||
keyblob[KB_FIRMWARE_VERSION_600+1][0x90] = {0},
|
|
||||||
keyblob_key[KB_FIRMWARE_VERSION_600+1][0x10] = {0},
|
|
||||||
keyblob_mac_key[KB_FIRMWARE_VERSION_600+1][0x10] = {0},
|
|
||||||
package1_key[KB_FIRMWARE_VERSION_600+1][0x10] = {0},
|
|
||||||
// master key-derived families
|
|
||||||
key_area_key[3][KB_FIRMWARE_VERSION_MAX+1][0x10] = {0},
|
|
||||||
master_kek[KB_FIRMWARE_VERSION_MAX+1][0x10] = {0},
|
|
||||||
master_key[KB_FIRMWARE_VERSION_MAX+1][0x10] = {0},
|
|
||||||
package2_key[KB_FIRMWARE_VERSION_MAX+1][0x10] = {0},
|
|
||||||
titlekek[KB_FIRMWARE_VERSION_MAX+1][0x10] = {0};
|
|
||||||
|
|
||||||
static const u32 colors[6] = {COLOR_RED, COLOR_ORANGE, COLOR_YELLOW, COLOR_GREEN, COLOR_BLUE, COLOR_VIOLET};
|
|
||||||
|
|
||||||
// key functions
|
|
||||||
static bool _key_exists(const void *data) { return memcmp(data, zeros, 0x10); };
|
|
||||||
static void _save_key(const char *name, const void *data, const u32 len, char *outbuf);
|
|
||||||
static void _save_key_family(const char *name, const void *data, const u32 num_keys, const u32 len, char *outbuf);
|
|
||||||
static void _generate_kek(u32 ks, const void *key_source, void *master_key, const void *kek_seed, const void *key_seed);
|
|
||||||
// nca functions
|
|
||||||
static void *_nca_process(u32 hk_ks1, u32 hk_ks2, FIL *fp, u32 key_offset, u32 len);
|
|
||||||
static u32 _nca_fread_ctr(u32 ks, FIL *fp, void *buffer, u32 offset, u32 len, u8 *ctr);
|
|
||||||
static void _update_ctr(u8 *ctr, u32 ofs);
|
|
||||||
|
|
||||||
void dump_keys() {
|
|
||||||
display_backlight_brightness(100, 1000);
|
|
||||||
gfx_clear_grey(0x1B);
|
|
||||||
gfx_con_setpos(0, 0);
|
|
||||||
|
|
||||||
gfx_printf("[%kLo%kck%kpi%kck%k-R%kCM%k v%d.%d.%d%k]\n\n",
|
|
||||||
colors[0], colors[1], colors[2], colors[3], colors[4], colors[5], 0xFFFF00FF, LP_VER_MJ, LP_VER_MN, LP_VER_BF, 0xFFCCCCCC);
|
|
||||||
|
|
||||||
u32 start_time = get_tmr_ms(),
|
|
||||||
end_time,
|
|
||||||
retries = 0;
|
|
||||||
|
|
||||||
tsec_ctxt_t tsec_ctxt;
|
|
||||||
sdmmc_t sdmmc;
|
|
||||||
|
|
||||||
sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4);
|
|
||||||
|
|
||||||
// Read package1.
|
|
||||||
u8 *pkg1 = (u8 *)malloc(0x40000);
|
|
||||||
sdmmc_storage_set_mmc_partition(&storage, 1);
|
|
||||||
sdmmc_storage_read(&storage, 0x100000 / NX_EMMC_BLOCKSIZE, 0x40000 / NX_EMMC_BLOCKSIZE, pkg1);
|
|
||||||
const pkg1_id_t *pkg1_id = pkg1_identify(pkg1);
|
|
||||||
if (!pkg1_id) {
|
|
||||||
EPRINTF("Unknown pkg1 version.");
|
|
||||||
goto out_wait;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool found_tsec_fw = false;
|
|
||||||
for (const u32 *pos = (const u32 *)pkg1; (u8 *)pos < pkg1 + 0x40000; pos += 0x100 / sizeof(u32)) {
|
|
||||||
if (*pos == 0xCF42004D) {
|
|
||||||
tsec_ctxt.fw = (u8 *)pos;
|
|
||||||
found_tsec_fw = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!found_tsec_fw) {
|
|
||||||
EPRINTF("Failed to locate TSEC firmware.");
|
|
||||||
goto out_wait;
|
|
||||||
}
|
|
||||||
|
|
||||||
tsec_key_data_t *key_data = (tsec_key_data_t *)(tsec_ctxt.fw + TSEC_KEY_DATA_ADDR);
|
|
||||||
tsec_ctxt.pkg1 = pkg1;
|
|
||||||
tsec_ctxt.size = 0x100 + key_data->blob0_size + key_data->blob1_size + key_data->blob2_size + key_data->blob3_size + key_data->blob4_size;
|
|
||||||
|
|
||||||
u32 MAX_KEY = 6;
|
|
||||||
if (pkg1_id->kb >= KB_FIRMWARE_VERSION_620)
|
|
||||||
MAX_KEY = pkg1_id->kb + 1;
|
|
||||||
|
|
||||||
if (pkg1_id->kb >= KB_FIRMWARE_VERSION_700) {
|
|
||||||
if (!f_stat("sd:/sept/payload.bak", NULL)) {
|
|
||||||
f_unlink("sd:/sept/payload.bin");
|
|
||||||
f_rename("sd:/sept/payload.bak", "sd:/sept/payload.bin");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(EMC(EMC_SCRATCH0) & EMC_SEPT_RUN)) {
|
|
||||||
// bundle lp0 fw for sept instead of loading it from SD as hekate does
|
|
||||||
sdram_lp0_save_params(sdram_get_params_patched());
|
|
||||||
FIL fp;
|
|
||||||
if (f_stat("sd:/sept", NULL)) {
|
|
||||||
EPRINTF("On firmware 7.x+ but Sept missing.\nSkipping new key derivation...");
|
|
||||||
goto get_tsec;
|
|
||||||
}
|
|
||||||
// backup post-reboot payload
|
|
||||||
if (!f_stat("sd:/sept/payload.bin", NULL))
|
|
||||||
f_rename("sd:/sept/payload.bin", "sd:/sept/payload.bak");
|
|
||||||
// write self to payload.bin to run again when sept finishes
|
|
||||||
f_open(&fp, "sd:/sept/payload.bin", FA_CREATE_NEW | FA_WRITE);
|
|
||||||
u32 payload_size = *(u32 *)(IPL_LOAD_ADDR + 0x84) - IPL_LOAD_ADDR;
|
|
||||||
f_write(&fp, (u8 *)IPL_LOAD_ADDR, payload_size, NULL);
|
|
||||||
f_close(&fp);
|
|
||||||
gfx_printf("%kFirmware 7.x or higher detected.\n%kRenamed /sept/payload.bin", colors[0], colors[1]);
|
|
||||||
gfx_printf("\n%k to /sept/payload.bak\n%kCopied self to /sept/payload.bin",colors[2], colors[3]);
|
|
||||||
sdmmc_storage_end(&storage);
|
|
||||||
if (!reboot_to_sept((u8 *)tsec_ctxt.fw, tsec_ctxt.size, pkg1_id->kb))
|
|
||||||
goto out_wait;
|
|
||||||
} else {
|
|
||||||
se_aes_key_read(12, master_key[pkg1_id->kb], 0x10);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
get_tsec: ;
|
|
||||||
u8 tsec_keys[0x10 * 2] = {0};
|
|
||||||
|
|
||||||
if (pkg1_id->kb == KB_FIRMWARE_VERSION_620) {
|
|
||||||
u8 *tsec_paged = (u8 *)page_alloc(3);
|
|
||||||
memcpy(tsec_paged, (void *)tsec_ctxt.fw, tsec_ctxt.size);
|
|
||||||
tsec_ctxt.fw = tsec_paged;
|
|
||||||
}
|
|
||||||
|
|
||||||
int res = 0;
|
|
||||||
|
|
||||||
mc_disable_ahb_redirect();
|
|
||||||
|
|
||||||
while (tsec_query(tsec_keys, pkg1_id->kb, &tsec_ctxt) < 0) {
|
|
||||||
memset(tsec_keys, 0x00, 0x20);
|
|
||||||
retries++;
|
|
||||||
if (retries > 15) {
|
|
||||||
res = -1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
free(pkg1);
|
|
||||||
|
|
||||||
mc_enable_ahb_redirect();
|
|
||||||
|
|
||||||
if (res < 0) {
|
|
||||||
EPRINTFARGS("ERROR %x dumping TSEC.\n", res);
|
|
||||||
goto out_wait;
|
|
||||||
}
|
|
||||||
|
|
||||||
TPRINTFARGS("%kTSEC key(s)... ", colors[0]);
|
|
||||||
|
|
||||||
// Master key derivation
|
|
||||||
if (pkg1_id->kb == KB_FIRMWARE_VERSION_620 && _key_exists(tsec_keys + 0x10)) {
|
|
||||||
se_aes_key_set(8, tsec_keys + 0x10, 0x10); // mkek6 = unwrap(mkeks6, tsecroot)
|
|
||||||
se_aes_crypt_block_ecb(8, 0, master_kek[6], master_kek_sources[0]);
|
|
||||||
se_aes_key_set(8, master_kek[6], 0x10); // mkey = unwrap(mkek, mks)
|
|
||||||
se_aes_crypt_block_ecb(8, 0, master_key[6], master_key_source);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pkg1_id->kb >= KB_FIRMWARE_VERSION_620 && _key_exists(master_key[pkg1_id->kb])) {
|
|
||||||
// derive all lower master keys in the event keyblobs are bad
|
|
||||||
for (u32 i = pkg1_id->kb; i > 0; i--) {
|
|
||||||
se_aes_key_set(8, master_key[i], 0x10);
|
|
||||||
se_aes_crypt_block_ecb(8, 0, master_key[i-1], mkey_vectors[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
u8 *keyblob_block = (u8 *)calloc(NX_EMMC_BLOCKSIZE, 1);
|
|
||||||
u8 keyblob_mac[0x10] = {0};
|
|
||||||
u32 sbk[4] = {FUSE(FUSE_PRIVATE_KEY0), FUSE(FUSE_PRIVATE_KEY1),
|
|
||||||
FUSE(FUSE_PRIVATE_KEY2), FUSE(FUSE_PRIVATE_KEY3)};
|
|
||||||
se_aes_key_set(8, tsec_keys, 0x10);
|
|
||||||
se_aes_key_set(9, sbk, 0x10);
|
|
||||||
for (u32 i = 0; i <= KB_FIRMWARE_VERSION_600; i++) {
|
|
||||||
se_aes_crypt_block_ecb(8, 0, keyblob_key[i], keyblob_key_source[i]); // temp = unwrap(kbks, tsec)
|
|
||||||
se_aes_crypt_block_ecb(9, 0, keyblob_key[i], keyblob_key[i]); // kbk = unwrap(temp, sbk)
|
|
||||||
se_aes_key_set(7, keyblob_key[i], 0x10);
|
|
||||||
se_aes_crypt_block_ecb(7, 0, keyblob_mac_key[i], keyblob_mac_key_source); // kbm = unwrap(kbms, kbk)
|
|
||||||
if (i == 0)
|
|
||||||
se_aes_crypt_block_ecb(7, 0, device_key, per_console_key_source); // devkey = unwrap(pcks, kbk0)
|
|
||||||
|
|
||||||
// verify keyblob is not corrupt
|
|
||||||
sdmmc_storage_read(&storage, 0x180000 / NX_EMMC_BLOCKSIZE + i, 1, keyblob_block);
|
|
||||||
se_aes_key_set(3, keyblob_mac_key[i], 0x10);
|
|
||||||
se_aes_cmac(3, keyblob_mac, 0x10, keyblob_block + 0x10, 0xa0);
|
|
||||||
if (memcmp(keyblob_block, keyblob_mac, 0x10)) {
|
|
||||||
EPRINTFARGS("Keyblob %x corrupt.", i);
|
|
||||||
gfx_hexdump(i, keyblob_block, 0x10);
|
|
||||||
gfx_hexdump(i, keyblob_mac, 0x10);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// decrypt keyblobs
|
|
||||||
se_aes_key_set(2, keyblob_key[i], 0x10);
|
|
||||||
se_aes_crypt_ctr(2, keyblob[i], 0x90, keyblob_block + 0x20, 0x90, keyblob_block + 0x10);
|
|
||||||
|
|
||||||
memcpy(package1_key[i], keyblob[i] + 0x80, 0x10);
|
|
||||||
memcpy(master_kek[i], keyblob[i], 0x10);
|
|
||||||
se_aes_key_set(7, master_kek[i], 0x10);
|
|
||||||
se_aes_crypt_block_ecb(7, 0, master_key[i], master_key_source);
|
|
||||||
}
|
|
||||||
free(keyblob_block);
|
|
||||||
|
|
||||||
TPRINTFARGS("%kMaster keys... ", colors[1]);
|
|
||||||
|
|
||||||
/* key = unwrap(source, wrapped_key):
|
|
||||||
key_set(ks, wrapped_key), block_ecb(ks, 0, key, source) -> final key in key
|
|
||||||
*/
|
|
||||||
if (_key_exists(device_key)) {
|
|
||||||
se_aes_key_set(8, device_key, 0x10);
|
|
||||||
se_aes_unwrap_key(8, 8, retail_specific_aes_key_source); // kek = unwrap(rsaks, devkey)
|
|
||||||
se_aes_crypt_block_ecb(8, 0, bis_key[0] + 0x00, bis_key_source[0] + 0x00); // bkey = unwrap(bkeys, kek)
|
|
||||||
se_aes_crypt_block_ecb(8, 0, bis_key[0] + 0x10, bis_key_source[0] + 0x10);
|
|
||||||
// kek = generate_kek(bkeks, devkey, aeskek, aeskey)
|
|
||||||
_generate_kek(8, bis_kek_source, device_key, aes_kek_generation_source, aes_key_generation_source);
|
|
||||||
se_aes_crypt_block_ecb(8, 0, bis_key[1] + 0x00, bis_key_source[1] + 0x00); // bkey = unwrap(bkeys, kek)
|
|
||||||
se_aes_crypt_block_ecb(8, 0, bis_key[1] + 0x10, bis_key_source[1] + 0x10);
|
|
||||||
se_aes_crypt_block_ecb(8, 0, bis_key[2] + 0x00, bis_key_source[2] + 0x00);
|
|
||||||
se_aes_crypt_block_ecb(8, 0, bis_key[2] + 0x10, bis_key_source[2] + 0x10);
|
|
||||||
memcpy(bis_key[3], bis_key[2], 0x20);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Dump package2.
|
|
||||||
u8 *pkg2 = NULL;
|
|
||||||
pkg2_kip1_info_t *ki = NULL;
|
|
||||||
|
|
||||||
sdmmc_storage_set_mmc_partition(&storage, 0);
|
|
||||||
// Parse eMMC GPT.
|
|
||||||
LIST_INIT(gpt);
|
|
||||||
nx_emmc_gpt_parse(&gpt, &storage);
|
|
||||||
|
|
||||||
// Find package2 partition.
|
|
||||||
emmc_part_t *pkg2_part = nx_emmc_part_find(&gpt, "BCPKG2-1-Normal-Main");
|
|
||||||
if (!pkg2_part) {
|
|
||||||
EPRINTF("Failed to locate Package2.");
|
|
||||||
goto pkg2_done;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read in package2 header and get package2 real size.
|
|
||||||
u8 *tmp = (u8 *)malloc(NX_EMMC_BLOCKSIZE);
|
|
||||||
nx_emmc_part_read(&storage, pkg2_part, 0x4000 / NX_EMMC_BLOCKSIZE, 1, tmp);
|
|
||||||
u32 *hdr_pkg2_raw = (u32 *)(tmp + 0x100);
|
|
||||||
u32 pkg2_size = hdr_pkg2_raw[0] ^ hdr_pkg2_raw[2] ^ hdr_pkg2_raw[3];
|
|
||||||
free(tmp);
|
|
||||||
|
|
||||||
if (pkg2_size > 0x7FC000) {
|
|
||||||
EPRINTF("Invalid Package2 header.");
|
|
||||||
goto pkg2_done;
|
|
||||||
}
|
|
||||||
// Read in package2.
|
|
||||||
u32 pkg2_size_aligned = ALIGN(pkg2_size, NX_EMMC_BLOCKSIZE);
|
|
||||||
pkg2 = malloc(pkg2_size_aligned);
|
|
||||||
nx_emmc_part_read(&storage, pkg2_part, 0x4000 / NX_EMMC_BLOCKSIZE, pkg2_size_aligned / NX_EMMC_BLOCKSIZE, pkg2);
|
|
||||||
|
|
||||||
// Decrypt package2 and parse KIP1 blobs in INI1 section. Try all available key generations in case of pkg1/pkg2 mismatch.
|
|
||||||
pkg2_hdr_t *pkg2_hdr;
|
|
||||||
pkg2_hdr_t hdr;
|
|
||||||
u32 pkg2_kb;
|
|
||||||
for (pkg2_kb = 0; pkg2_kb < MAX_KEY; pkg2_kb++) {
|
|
||||||
se_aes_key_set(8, master_key[pkg2_kb], 0x10);
|
|
||||||
se_aes_unwrap_key(8, 8, package2_key_source);
|
|
||||||
memcpy(&hdr, pkg2 + 0x100, sizeof(pkg2_hdr_t));
|
|
||||||
se_aes_crypt_ctr(8, &hdr, sizeof(pkg2_hdr_t), &hdr, sizeof(pkg2_hdr_t), &hdr);
|
|
||||||
if (hdr.magic == PKG2_MAGIC)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (pkg2_kb == MAX_KEY) {
|
|
||||||
EPRINTF("Failed to decrypt Package2.");
|
|
||||||
goto pkg2_done;
|
|
||||||
} else if (pkg2_kb != pkg1_id->kb)
|
|
||||||
EPRINTF("Warning: Package1-Package2 mismatch.");
|
|
||||||
pkg2_hdr = pkg2_decrypt(pkg2);
|
|
||||||
|
|
||||||
TPRINTFARGS("%kDecrypt pkg2... ", colors[2]);
|
|
||||||
|
|
||||||
LIST_INIT(kip1_info);
|
|
||||||
pkg2_parse_kips(&kip1_info, pkg2_hdr);
|
|
||||||
LIST_FOREACH_ENTRY(pkg2_kip1_info_t, ki_tmp, &kip1_info, link) {
|
|
||||||
if(ki_tmp->kip1->tid == 0x0100000000000000ULL) {
|
|
||||||
ki = malloc(sizeof(pkg2_kip1_info_t));
|
|
||||||
memcpy(ki, ki_tmp, sizeof(pkg2_kip1_info_t));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
LIST_FOREACH_SAFE(iter, &kip1_info)
|
|
||||||
free(CONTAINER_OF(iter, pkg2_kip1_info_t, link));
|
|
||||||
|
|
||||||
if (!ki) {
|
|
||||||
EPRINTF("Failed to parse INI1.");
|
|
||||||
goto pkg2_done;
|
|
||||||
}
|
|
||||||
|
|
||||||
pkg2_decompress_kip(ki, 2 | 4); // we only need .rodata and .data
|
|
||||||
TPRINTFARGS("%kDecompress FS...", colors[3]);
|
|
||||||
|
|
||||||
u8 hash_index = 0, hash_max = 9, hash_order[10],
|
|
||||||
key_lengths[10] = {0x10, 0x20, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x20, 0x20};
|
|
||||||
u32 start_offset = 0, hks_offset_from_end = ki->kip1->sections[2].size_decomp, alignment = 1;
|
|
||||||
|
|
||||||
// the FS keys appear in different orders
|
|
||||||
if (!memcmp(pkg1_id->id, "2016", 4)) {
|
|
||||||
// 1.0.0 doesn't have SD keys at all
|
|
||||||
hash_max = 6;
|
|
||||||
// the first key isn't aligned with the rest
|
|
||||||
memcpy(fs_keys[2], ki->kip1->data + ki->kip1->sections[0].size_comp + 0x1ae0e, 0x10);
|
|
||||||
hash_index = 1;
|
|
||||||
start_offset = 0x1b517;
|
|
||||||
hks_offset_from_end = 0x125bc2;
|
|
||||||
alignment = 0x10;
|
|
||||||
u8 temp[7] = {2, 3, 4, 0, 5, 6, 1};
|
|
||||||
memcpy(hash_order, temp, 7);
|
|
||||||
} else {
|
|
||||||
// 2.0.0 - 8.0.0
|
|
||||||
alignment = 0x40;
|
|
||||||
switch (pkg1_id->kb) {
|
|
||||||
case KB_FIRMWARE_VERSION_100_200:
|
|
||||||
start_offset = 0x1d226;
|
|
||||||
alignment = 0x10;
|
|
||||||
hks_offset_from_end -= 0x26fe;
|
|
||||||
break;
|
|
||||||
case KB_FIRMWARE_VERSION_300:
|
|
||||||
start_offset = 0x1ffa6;
|
|
||||||
hks_offset_from_end -= 0x298b;
|
|
||||||
break;
|
|
||||||
case KB_FIRMWARE_VERSION_301:
|
|
||||||
start_offset = 0x20026;
|
|
||||||
hks_offset_from_end -= 0x29ab;
|
|
||||||
break;
|
|
||||||
case KB_FIRMWARE_VERSION_400:
|
|
||||||
start_offset = 0x1c64c;
|
|
||||||
hks_offset_from_end -= 0x37eb;
|
|
||||||
break;
|
|
||||||
case KB_FIRMWARE_VERSION_500:
|
|
||||||
start_offset = 0x1f3b4;
|
|
||||||
hks_offset_from_end -= 0x465b;
|
|
||||||
alignment = 0x20;
|
|
||||||
break;
|
|
||||||
case KB_FIRMWARE_VERSION_600:
|
|
||||||
case KB_FIRMWARE_VERSION_620:
|
|
||||||
start_offset = 0x27350;
|
|
||||||
hks_offset_from_end = 0x17ff5;
|
|
||||||
alignment = 8;
|
|
||||||
break;
|
|
||||||
case KB_FIRMWARE_VERSION_700:
|
|
||||||
case KB_FIRMWARE_VERSION_810:
|
|
||||||
start_offset = 0x29c50;
|
|
||||||
hks_offset_from_end -= 0x6a73;
|
|
||||||
alignment = 8;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pkg1_id->kb <= KB_FIRMWARE_VERSION_500) {
|
|
||||||
u8 temp[10] = {2, 3, 4, 0, 5, 7, 9, 8, 6, 1};
|
|
||||||
memcpy(hash_order, temp, 10);
|
|
||||||
} else {
|
|
||||||
u8 temp[10] = {6, 5, 7, 2, 3, 4, 0, 9, 8, 1};
|
|
||||||
memcpy(hash_order, temp, 10);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
u8 temp_hash[0x20];
|
|
||||||
for (u32 i = ki->kip1->sections[0].size_comp + start_offset; i < ki->size - 0x20; ) {
|
|
||||||
se_calc_sha256(temp_hash, ki->kip1->data + i, key_lengths[hash_order[hash_index]]);
|
|
||||||
if (!memcmp(temp_hash, fs_hashes_sha256[hash_order[hash_index]], 0x20)) {
|
|
||||||
memcpy(fs_keys[hash_order[hash_index]], ki->kip1->data + i, key_lengths[hash_order[hash_index]]);
|
|
||||||
/*if (hash_index == hash_max) {
|
|
||||||
TPRINTFARGS("%d: %x end -%x", hash_index, (*(ki->kip1->data + i)), ki->size - i);
|
|
||||||
} else {
|
|
||||||
TPRINTFARGS("%d: %x rodata +%x", hash_index, (*(ki->kip1->data + i)), i - ki->kip1->sections[0].size_comp);
|
|
||||||
}*/
|
|
||||||
i += key_lengths[hash_order[hash_index]];
|
|
||||||
if (hash_index == hash_max - 1) {
|
|
||||||
i = ki->size - hks_offset_from_end;
|
|
||||||
} else if (hash_index == hash_max) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
hash_index++;
|
|
||||||
} else {
|
|
||||||
i += alignment;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pkg2_done:
|
|
||||||
free(pkg2);
|
|
||||||
free(ki);
|
|
||||||
|
|
||||||
TPRINTFARGS("%kFS keys... ", colors[4]);
|
|
||||||
|
|
||||||
if (_key_exists(fs_keys[0]) && _key_exists(fs_keys[1]) && _key_exists(master_key[0])) {
|
|
||||||
_generate_kek(8, fs_keys[0], master_key[0], aes_kek_generation_source, aes_key_generation_source);
|
|
||||||
se_aes_crypt_block_ecb(8, 0, header_key + 0x00, fs_keys[1] + 0x00);
|
|
||||||
se_aes_crypt_block_ecb(8, 0, header_key + 0x10, fs_keys[1] + 0x10);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_key_exists(fs_keys[5]) && _key_exists(fs_keys[6]) && _key_exists(device_key)) {
|
|
||||||
_generate_kek(8, fs_keys[5], device_key, aes_kek_generation_source, NULL);
|
|
||||||
se_aes_crypt_block_ecb(8, 0, save_mac_key, fs_keys[6]);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (u32 i = 0; i < MAX_KEY; i++) {
|
|
||||||
if (!_key_exists(master_key[i]))
|
|
||||||
continue;
|
|
||||||
if (_key_exists(fs_keys[2]) && _key_exists(fs_keys[3]) && _key_exists(fs_keys[4])) {
|
|
||||||
for (u32 j = 0; j < 3; j++) {
|
|
||||||
_generate_kek(8, fs_keys[2 + j], master_key[i], aes_kek_generation_source, NULL);
|
|
||||||
se_aes_crypt_block_ecb(8, 0, key_area_key[j][i], aes_key_generation_source);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
se_aes_key_set(8, master_key[i], 0x10);
|
|
||||||
se_aes_crypt_block_ecb(8, 0, package2_key[i], package2_key_source);
|
|
||||||
se_aes_crypt_block_ecb(8, 0, titlekek[i], titlekek_source);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (!_key_exists(header_key) || !_key_exists(bis_key[2]))
|
|
||||||
goto key_output;
|
|
||||||
|
|
||||||
se_aes_key_set(4, header_key + 0x00, 0x10);
|
|
||||||
se_aes_key_set(5, header_key + 0x10, 0x10);
|
|
||||||
se_aes_key_set(8, bis_key[2] + 0x00, 0x10);
|
|
||||||
se_aes_key_set(9, bis_key[2] + 0x10, 0x10);
|
|
||||||
|
|
||||||
system_part = nx_emmc_part_find(&gpt, "SYSTEM");
|
|
||||||
if (!system_part) {
|
|
||||||
EPRINTF("Failed to locate System partition.");
|
|
||||||
goto key_output;
|
|
||||||
}
|
|
||||||
__attribute__ ((aligned (16))) FATFS emmc_fs;
|
|
||||||
if (f_mount(&emmc_fs, "emmc:", 1)) {
|
|
||||||
EPRINTF("Mount failed.");
|
|
||||||
goto key_output;
|
|
||||||
}
|
|
||||||
|
|
||||||
DIR dir;
|
|
||||||
FILINFO fno;
|
|
||||||
FIL fp;
|
|
||||||
// sysmodule NCAs only ever have one section (exefs) so 0x600 is sufficient
|
|
||||||
u8 *dec_header = (u8*)malloc(0x600);
|
|
||||||
char path[100] = "emmc:/Contents/registered";
|
|
||||||
u32 titles_found = 0, title_limit = 2, read_bytes = 0;
|
|
||||||
if (!memcmp(pkg1_id->id, "2016", 4))
|
|
||||||
title_limit = 1;
|
|
||||||
u8 *temp_file = NULL;
|
|
||||||
|
|
||||||
if (f_opendir(&dir, path)) {
|
|
||||||
EPRINTF("Failed to open System:/Contents/registered.");
|
|
||||||
goto dismount;
|
|
||||||
}
|
|
||||||
|
|
||||||
// prepopulate /Contents/registered in decrypted sector cache
|
|
||||||
while (!f_readdir(&dir, &fno) && fno.fname[0]) {}
|
|
||||||
f_closedir(&dir);
|
|
||||||
|
|
||||||
if (f_opendir(&dir, path)) {
|
|
||||||
EPRINTF("Failed to open System:/Contents/registered.");
|
|
||||||
goto dismount;
|
|
||||||
}
|
|
||||||
|
|
||||||
path[25] = '/';
|
|
||||||
start_offset = 0;
|
|
||||||
|
|
||||||
while (!f_readdir(&dir, &fno) && fno.fname[0] && titles_found < title_limit) {
|
|
||||||
memcpy(path + 26, fno.fname, 36);
|
|
||||||
path[62] = 0;
|
|
||||||
if (fno.fattrib & AM_DIR)
|
|
||||||
memcpy(path + 62, "/00", 4);
|
|
||||||
if (f_open(&fp, path, FA_READ | FA_OPEN_EXISTING)) continue;
|
|
||||||
if (f_lseek(&fp, 0x200) || f_read(&fp, dec_header, 32, &read_bytes) || read_bytes != 32) {
|
|
||||||
f_close(&fp);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
se_aes_xts_crypt(5, 4, 0, 1, dec_header + 0x200, dec_header, 32, 1);
|
|
||||||
// es doesn't contain es key sources on 1.0.0
|
|
||||||
if (memcmp(pkg1_id->id, "2016", 4) && *(u32*)(dec_header + 0x210) == 0x33 && dec_header[0x205] == 0) {
|
|
||||||
// es (offset 0x210 is lower half of titleid, 0x205 == 0 means it's program nca, not meta)
|
|
||||||
switch (pkg1_id->kb) {
|
|
||||||
case KB_FIRMWARE_VERSION_100_200:
|
|
||||||
start_offset = 0x557b;
|
|
||||||
break;
|
|
||||||
case KB_FIRMWARE_VERSION_300:
|
|
||||||
case KB_FIRMWARE_VERSION_301:
|
|
||||||
start_offset = 0x552d;
|
|
||||||
break;
|
|
||||||
case KB_FIRMWARE_VERSION_400:
|
|
||||||
start_offset = 0x5382;
|
|
||||||
break;
|
|
||||||
case KB_FIRMWARE_VERSION_500:
|
|
||||||
start_offset = 0x5a63;
|
|
||||||
break;
|
|
||||||
case KB_FIRMWARE_VERSION_600:
|
|
||||||
case KB_FIRMWARE_VERSION_620:
|
|
||||||
start_offset = 0x5674;
|
|
||||||
break;
|
|
||||||
case KB_FIRMWARE_VERSION_700:
|
|
||||||
case KB_FIRMWARE_VERSION_810:
|
|
||||||
start_offset = 0x5563;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
hash_order[2] = 2;
|
|
||||||
if (pkg1_id->kb < KB_FIRMWARE_VERSION_500) {
|
|
||||||
hash_order[0] = 0;
|
|
||||||
hash_order[1] = 1;
|
|
||||||
} else {
|
|
||||||
hash_order[0] = 1;
|
|
||||||
hash_order[1] = 0;
|
|
||||||
}
|
|
||||||
hash_index = 0;
|
|
||||||
// decrypt only what is needed to locate needed keys
|
|
||||||
temp_file = (u8*)_nca_process(5, 4, &fp, start_offset, 0xc0);
|
|
||||||
for (u32 i = 0; i <= 0xb0; ) {
|
|
||||||
se_calc_sha256(temp_hash, temp_file + i, 0x10);
|
|
||||||
if (!memcmp(temp_hash, es_hashes_sha256[hash_order[hash_index]], 0x10)) {
|
|
||||||
memcpy(es_keys[hash_order[hash_index]], temp_file + i, 0x10);
|
|
||||||
hash_index++;
|
|
||||||
if (hash_index == 3)
|
|
||||||
break;
|
|
||||||
i += 0x10;
|
|
||||||
} else {
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
free(temp_file);
|
|
||||||
temp_file = NULL;
|
|
||||||
titles_found++;
|
|
||||||
} else if (*(u32*)(dec_header + 0x210) == 0x24 && dec_header[0x205] == 0) {
|
|
||||||
// ssl
|
|
||||||
switch (pkg1_id->kb) {
|
|
||||||
case KB_FIRMWARE_VERSION_100_200:
|
|
||||||
start_offset = 0x3d41a;
|
|
||||||
break;
|
|
||||||
case KB_FIRMWARE_VERSION_300:
|
|
||||||
case KB_FIRMWARE_VERSION_301:
|
|
||||||
start_offset = 0x3cb81;
|
|
||||||
break;
|
|
||||||
case KB_FIRMWARE_VERSION_400:
|
|
||||||
start_offset = 0x3711c;
|
|
||||||
break;
|
|
||||||
case KB_FIRMWARE_VERSION_500:
|
|
||||||
start_offset = 0x37901;
|
|
||||||
break;
|
|
||||||
case KB_FIRMWARE_VERSION_600:
|
|
||||||
case KB_FIRMWARE_VERSION_620:
|
|
||||||
start_offset = 0x1d5be;
|
|
||||||
break;
|
|
||||||
case KB_FIRMWARE_VERSION_700:
|
|
||||||
case KB_FIRMWARE_VERSION_810:
|
|
||||||
start_offset = 0x1d437;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (!memcmp(pkg1_id->id, "2016", 4))
|
|
||||||
start_offset = 0x449dc;
|
|
||||||
temp_file = (u8*)_nca_process(5, 4, &fp, start_offset, 0x70);
|
|
||||||
for (u32 i = 0; i <= 0x60; i++) {
|
|
||||||
se_calc_sha256(temp_hash, temp_file + i, 0x10);
|
|
||||||
if (!memcmp(temp_hash, ssl_hashes_sha256[1], 0x10)) {
|
|
||||||
memcpy(ssl_keys[1], temp_file + i, 0x10);
|
|
||||||
// only get ssl_rsa_kek_source_x from SSL on 1.0.0
|
|
||||||
// we get it from ES on every other firmware
|
|
||||||
// and it's located oddly distant from ssl_rsa_kek_source_y on >= 6.0.0
|
|
||||||
if (!memcmp(pkg1_id->id, "2016", 4)) {
|
|
||||||
se_calc_sha256(temp_hash, temp_file + i + 0x10, 0x10);
|
|
||||||
if (!memcmp(temp_hash, ssl_hashes_sha256[0], 0x10))
|
|
||||||
memcpy(es_keys[2], temp_file + i + 0x10, 0x10);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
free(temp_file);
|
|
||||||
temp_file = NULL;
|
|
||||||
titles_found++;
|
|
||||||
}
|
|
||||||
f_close(&fp);
|
|
||||||
}
|
|
||||||
f_closedir(&dir);
|
|
||||||
free(dec_header);
|
|
||||||
|
|
||||||
if (f_open(&fp, "sd:/Nintendo/Contents/private", FA_READ | FA_OPEN_EXISTING)) {
|
|
||||||
EPRINTF("Unable to locate SD seed. Skipping.");
|
|
||||||
goto dismount;
|
|
||||||
}
|
|
||||||
// get sd seed verification vector
|
|
||||||
if (f_read(&fp, temp_key, 0x10, &read_bytes) || read_bytes != 0x10) {
|
|
||||||
EPRINTF("Unable to locate SD seed. Skipping.");
|
|
||||||
f_close(&fp);
|
|
||||||
goto dismount;
|
|
||||||
}
|
|
||||||
f_close(&fp);
|
|
||||||
|
|
||||||
if (f_open(&fp, "emmc:/save/8000000000000043", FA_READ | FA_OPEN_EXISTING)) {
|
|
||||||
EPRINTF("Failed to open ns_appman save.\nSkipping SD seed.");
|
|
||||||
goto dismount;
|
|
||||||
}
|
|
||||||
|
|
||||||
// locate sd seed
|
|
||||||
u8 read_buf[0x20] = {0};
|
|
||||||
for (u32 i = 0; i < f_size(&fp); i += 0x4000) {
|
|
||||||
if (f_lseek(&fp, i) || f_read(&fp, read_buf, 0x20, &read_bytes) || read_bytes != 0x20)
|
|
||||||
break;
|
|
||||||
if (!memcmp(temp_key, read_buf, 0x10)) {
|
|
||||||
memcpy(sd_seed, read_buf + 0x10, 0x10);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
f_close(&fp);
|
|
||||||
|
|
||||||
dismount:
|
|
||||||
f_mount(NULL, "emmc:", 1);
|
|
||||||
nx_emmc_gpt_free(&gpt);
|
|
||||||
sdmmc_storage_end(&storage);
|
|
||||||
|
|
||||||
if (memcmp(pkg1_id->id, "2016", 4)) {
|
|
||||||
TPRINTFARGS("%kES & SSL keys...", colors[5]);
|
|
||||||
} else {
|
|
||||||
TPRINTFARGS("%kSSL keys... ", colors[5]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// derive eticket_rsa_kek and ssl_rsa_kek
|
|
||||||
if (_key_exists(es_keys[0]) && _key_exists(es_keys[1]) && _key_exists(master_key[0])) {
|
|
||||||
for (u32 i = 0; i < 0x10; i++)
|
|
||||||
temp_key[i] = aes_kek_generation_source[i] ^ aes_kek_seed_03[i];
|
|
||||||
_generate_kek(8, es_keys[1], master_key[0], temp_key, NULL);
|
|
||||||
se_aes_crypt_block_ecb(8, 0, eticket_rsa_kek, es_keys[0]);
|
|
||||||
}
|
|
||||||
if (_key_exists(ssl_keys[1]) && _key_exists(es_keys[2]) && _key_exists(master_key[0])) {
|
|
||||||
for (u32 i = 0; i < 0x10; i++)
|
|
||||||
temp_key[i] = aes_kek_generation_source[i] ^ aes_kek_seed_01[i];
|
|
||||||
_generate_kek(8, es_keys[2], master_key[0], temp_key, NULL);
|
|
||||||
se_aes_crypt_block_ecb(8, 0, ssl_rsa_kek, ssl_keys[1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
key_output: ;
|
|
||||||
__attribute__ ((aligned (16))) char text_buffer[0x3000] = {0};
|
|
||||||
|
|
||||||
SAVE_KEY("aes_kek_generation_source", aes_kek_generation_source, 0x10);
|
|
||||||
SAVE_KEY("aes_key_generation_source", aes_key_generation_source, 0x10);
|
|
||||||
SAVE_KEY("bis_kek_source", bis_kek_source, 0x10);
|
|
||||||
SAVE_KEY_FAMILY("bis_key", bis_key, 4, 0x20);
|
|
||||||
SAVE_KEY_FAMILY("bis_key_source", bis_key_source, 3, 0x20);
|
|
||||||
SAVE_KEY("device_key", device_key, 0x10);
|
|
||||||
SAVE_KEY("eticket_rsa_kek", eticket_rsa_kek, 0x10);
|
|
||||||
SAVE_KEY("eticket_rsa_kek_source", es_keys[0], 0x10);
|
|
||||||
SAVE_KEY("eticket_rsa_kekek_source", es_keys[1], 0x10);
|
|
||||||
SAVE_KEY("header_kek_source", fs_keys[0], 0x10);
|
|
||||||
SAVE_KEY("header_key", header_key, 0x20);
|
|
||||||
SAVE_KEY("header_key_source", fs_keys[1], 0x20);
|
|
||||||
SAVE_KEY_FAMILY("key_area_key_application", key_area_key[0], MAX_KEY, 0x10);
|
|
||||||
SAVE_KEY("key_area_key_application_source", fs_keys[2], 0x10);
|
|
||||||
SAVE_KEY_FAMILY("key_area_key_ocean", key_area_key[1], MAX_KEY, 0x10);
|
|
||||||
SAVE_KEY("key_area_key_ocean_source", fs_keys[3], 0x10);
|
|
||||||
SAVE_KEY_FAMILY("key_area_key_system", key_area_key[2], MAX_KEY, 0x10);
|
|
||||||
SAVE_KEY("key_area_key_system_source", fs_keys[4], 0x10);
|
|
||||||
SAVE_KEY_FAMILY("keyblob", keyblob, 6, 0x90);
|
|
||||||
SAVE_KEY_FAMILY("keyblob_key", keyblob_key, 6, 0x10);
|
|
||||||
SAVE_KEY_FAMILY("keyblob_key_source", keyblob_key_source, 6, 0x10);
|
|
||||||
SAVE_KEY_FAMILY("keyblob_mac_key", keyblob_mac_key, 6, 0x10);
|
|
||||||
SAVE_KEY("keyblob_mac_key_source", keyblob_mac_key_source, 0x10);
|
|
||||||
SAVE_KEY_FAMILY("master_kek", master_kek, MAX_KEY, 0x10);
|
|
||||||
SAVE_KEY("master_kek_source_06", master_kek_sources[0], 0x10);
|
|
||||||
SAVE_KEY("master_kek_source_07", master_kek_sources[1], 0x10);
|
|
||||||
SAVE_KEY("master_kek_source_08", master_kek_sources[2], 0x10);
|
|
||||||
SAVE_KEY_FAMILY("master_key", master_key, MAX_KEY, 0x10);
|
|
||||||
SAVE_KEY("master_key_source", master_key_source, 0x10);
|
|
||||||
SAVE_KEY_FAMILY("package1_key", package1_key, 6, 0x10);
|
|
||||||
SAVE_KEY_FAMILY("package2_key", package2_key, MAX_KEY, 0x10);
|
|
||||||
SAVE_KEY("package2_key_source", package2_key_source, 0x10);
|
|
||||||
SAVE_KEY("per_console_key_source", per_console_key_source, 0x10);
|
|
||||||
SAVE_KEY("retail_specific_aes_key_source", retail_specific_aes_key_source, 0x10);
|
|
||||||
for (u32 i = 0; i < 0x10; i++)
|
|
||||||
temp_key[i] = aes_kek_generation_source[i] ^ aes_kek_seed_03[i];
|
|
||||||
SAVE_KEY("rsa_oaep_kek_generation_source", temp_key, 0x10);
|
|
||||||
for (u32 i = 0; i < 0x10; i++)
|
|
||||||
temp_key[i] = aes_kek_generation_source[i] ^ aes_kek_seed_01[i];
|
|
||||||
SAVE_KEY("rsa_private_kek_generation_source", temp_key, 0x10);
|
|
||||||
SAVE_KEY("save_mac_kek_source", fs_keys[5], 0x10);
|
|
||||||
SAVE_KEY("save_mac_key", save_mac_key, 0x10);
|
|
||||||
SAVE_KEY("save_mac_key_source", fs_keys[6], 0x10);
|
|
||||||
SAVE_KEY("sd_card_kek_source", fs_keys[7], 0x10);
|
|
||||||
SAVE_KEY("sd_card_nca_key_source", fs_keys[8], 0x20);
|
|
||||||
SAVE_KEY("sd_card_save_key_source", fs_keys[9], 0x20);
|
|
||||||
SAVE_KEY("sd_seed", sd_seed, 0x10);
|
|
||||||
SAVE_KEY("secure_boot_key", sbk, 0x10);
|
|
||||||
SAVE_KEY("ssl_rsa_kek", ssl_rsa_kek, 0x10);
|
|
||||||
SAVE_KEY("ssl_rsa_kek_source_x", es_keys[2], 0x10);
|
|
||||||
SAVE_KEY("ssl_rsa_kek_source_y", ssl_keys[1], 0x10);
|
|
||||||
SAVE_KEY_FAMILY("titlekek", titlekek, MAX_KEY, 0x10);
|
|
||||||
SAVE_KEY("titlekek_source", titlekek_source, 0x10);
|
|
||||||
SAVE_KEY("tsec_key", tsec_keys, 0x10);
|
|
||||||
if (pkg1_id->kb == KB_FIRMWARE_VERSION_620)
|
|
||||||
SAVE_KEY("tsec_root_key", tsec_keys + 0x10, 0x10);
|
|
||||||
|
|
||||||
//gfx_con.fntsz = 8; gfx_puts(text_buffer); gfx_con.fntsz = 16;
|
|
||||||
|
|
||||||
TPRINTFARGS("\n%kFound %d keys.\n%kLockpick totally", colors[0], _key_count, colors[1]);
|
|
||||||
|
|
||||||
f_mkdir("switch");
|
|
||||||
char keyfile_path[30] = "sd:/switch/";
|
|
||||||
if (!(fuse_read_odm(4) & 3))
|
|
||||||
sprintf(&keyfile_path[11], "prod.keys");
|
|
||||||
else
|
|
||||||
sprintf(&keyfile_path[11], "dev.keys");
|
|
||||||
if (!sd_save_to_file(text_buffer, strlen(text_buffer), keyfile_path) && !f_stat(keyfile_path, &fno)) {
|
|
||||||
gfx_printf("%kWrote %d bytes to %s\n", colors[2], (u32)fno.fsize, keyfile_path);
|
|
||||||
} else
|
|
||||||
EPRINTF("Failed to save keys to SD.");
|
|
||||||
sd_unmount();
|
|
||||||
|
|
||||||
out_wait:
|
|
||||||
gfx_printf("\n%kVOL + -> Reboot to RCM\n%kVOL - -> Reboot normally\n%kPower -> Power off", colors[3], colors[4], colors[5]);
|
|
||||||
|
|
||||||
u32 btn = btn_wait();
|
|
||||||
if (btn & BTN_VOL_UP)
|
|
||||||
reboot_rcm();
|
|
||||||
else if (btn & BTN_VOL_DOWN)
|
|
||||||
reboot_normal();
|
|
||||||
else
|
|
||||||
power_off();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void _save_key(const char *name, const void *data, const u32 len, char *outbuf) {
|
|
||||||
if (!_key_exists(data))
|
|
||||||
return;
|
|
||||||
u32 pos = strlen(outbuf);
|
|
||||||
pos += sprintf(&outbuf[pos], "%s = ", name);
|
|
||||||
for (u32 i = 0; i < len; i++)
|
|
||||||
pos += sprintf(&outbuf[pos], "%02x", *(u8*)(data + i));
|
|
||||||
sprintf(&outbuf[pos], "\n");
|
|
||||||
_key_count++;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void _save_key_family(const char *name, const void *data, const u32 num_keys, const u32 len, char *outbuf) {
|
|
||||||
char temp_name[0x40] = {0};
|
|
||||||
for (u32 i = 0; i < num_keys; i++) {
|
|
||||||
sprintf(temp_name, "%s_%02x", name, i);
|
|
||||||
_save_key(temp_name, data + i * len, len, outbuf);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void _generate_kek(u32 ks, const void *key_source, void *master_key, const void *kek_seed, const void *key_seed) {
|
|
||||||
if (!_key_exists(key_source) || !_key_exists(master_key) || !_key_exists(kek_seed))
|
|
||||||
return;
|
|
||||||
|
|
||||||
se_aes_key_set(ks, master_key, 0x10);
|
|
||||||
se_aes_unwrap_key(ks, ks, kek_seed);
|
|
||||||
se_aes_unwrap_key(ks, ks, key_source);
|
|
||||||
if (key_seed && _key_exists(key_seed))
|
|
||||||
se_aes_unwrap_key(ks, ks, key_seed);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline u32 _read_le_u32(const void *buffer, u32 offset) {
|
|
||||||
return (*(u8*)(buffer + offset + 0) ) |
|
|
||||||
(*(u8*)(buffer + offset + 1) << 0x08) |
|
|
||||||
(*(u8*)(buffer + offset + 2) << 0x10) |
|
|
||||||
(*(u8*)(buffer + offset + 3) << 0x18);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void *_nca_process(u32 hk_ks1, u32 hk_ks2, FIL *fp, u32 key_offset, u32 len) {
|
|
||||||
u32 read_bytes = 0, crypt_offset, read_size, num_files, string_table_size, rodata_offset;
|
|
||||||
|
|
||||||
u8 *temp_file = (u8*)malloc(0x400),
|
|
||||||
ctr[0x10] = {0};
|
|
||||||
if (f_lseek(fp, 0x200) || f_read(fp, temp_file, 0x400, &read_bytes) || read_bytes != 0x400)
|
|
||||||
return NULL;
|
|
||||||
se_aes_xts_crypt(hk_ks1, hk_ks2, 0, 1, temp_file, temp_file, 0x200, 2);
|
|
||||||
// both 1.x and 2.x use master_key_00
|
|
||||||
temp_file[0x20] -= temp_file[0x20] ? 1 : 0;
|
|
||||||
// decrypt key area and load decrypted key area key
|
|
||||||
se_aes_key_set(7, key_area_key[temp_file[7]][temp_file[0x20]], 0x10);
|
|
||||||
se_aes_crypt_block_ecb(7, 0, temp_file + 0x120, temp_file + 0x120);
|
|
||||||
se_aes_key_set(2, temp_file + 0x120, 0x10);
|
|
||||||
for (u32 i = 0; i < 8; i++)
|
|
||||||
ctr[i] = temp_file[0x347 - i];
|
|
||||||
crypt_offset = _read_le_u32(temp_file, 0x40) * 0x200 + _read_le_u32(temp_file, 0x240);
|
|
||||||
read_size = 0x10;
|
|
||||||
_nca_fread_ctr(2, fp, temp_file, crypt_offset, read_size, ctr);
|
|
||||||
num_files = _read_le_u32(temp_file, 4);
|
|
||||||
string_table_size = _read_le_u32(temp_file, 8);
|
|
||||||
if (!memcmp(temp_file + 0x10 + num_files * 0x18, "main.npdm", 9))
|
|
||||||
crypt_offset += _read_le_u32(temp_file, 0x18);
|
|
||||||
crypt_offset += 0x10 + num_files * 0x18 + string_table_size;
|
|
||||||
read_size = 0x40;
|
|
||||||
_nca_fread_ctr(2, fp, temp_file, crypt_offset, read_size, ctr);
|
|
||||||
rodata_offset = _read_le_u32(temp_file, 0x20);
|
|
||||||
|
|
||||||
void *buf = malloc(len);
|
|
||||||
_nca_fread_ctr(2, fp, buf, crypt_offset + rodata_offset + key_offset, len, ctr);
|
|
||||||
free(temp_file);
|
|
||||||
|
|
||||||
return buf;
|
|
||||||
}
|
|
||||||
|
|
||||||
static u32 _nca_fread_ctr(u32 ks, FIL *fp, void *buffer, u32 offset, u32 len, u8 *ctr) {
|
|
||||||
u32 br;
|
|
||||||
if (f_lseek(fp, offset) || f_read(fp, buffer, len, &br) || br != len)
|
|
||||||
return 0;
|
|
||||||
_update_ctr(ctr, offset);
|
|
||||||
|
|
||||||
if (offset % 0x10) {
|
|
||||||
u8 *temp = (u8*)malloc(ALIGN(br + offset % 0x10, 0x10));
|
|
||||||
memcpy(temp + offset % 0x10, buffer, br);
|
|
||||||
se_aes_crypt_ctr(ks, temp, ALIGN(br + offset % 0x10, 0x10), temp, ALIGN(br + offset % 0x10, 0x10), ctr);
|
|
||||||
memcpy(buffer, temp + offset % 0x10, br);
|
|
||||||
free(temp);
|
|
||||||
return br;
|
|
||||||
}
|
|
||||||
se_aes_crypt_ctr(ks, buffer, br, buffer, br, ctr);
|
|
||||||
return br;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void _update_ctr(u8 *ctr, u32 ofs) {
|
|
||||||
ofs >>= 4;
|
|
||||||
for (u32 i = 0; i < 4; i++, ofs >>= 8)
|
|
||||||
ctr[0x10-i-1] = (u8)(ofs & 0xff);
|
|
||||||
}
|
|
||||||
589
source/libs/elfload/elf.h
Normal file
589
source/libs/elfload/elf.h
Normal file
@@ -0,0 +1,589 @@
|
|||||||
|
/* $OpenBSD: exec_elf.h,v 1.53 2014/01/03 03:00:39 guenther Exp $ */
|
||||||
|
/*
|
||||||
|
* Copyright (c) 1995, 1996 Erik Theisen. All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. The name of the author may not be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* imported sys/exec_elf.h from OpenBSD */
|
||||||
|
|
||||||
|
#ifndef ELF_H
|
||||||
|
#define ELF_H
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
typedef uint8_t Elf_Byte;
|
||||||
|
|
||||||
|
typedef uint32_t Elf32_Addr; /* Unsigned program address */
|
||||||
|
typedef uint32_t Elf32_Off; /* Unsigned file offset */
|
||||||
|
typedef int32_t Elf32_Sword; /* Signed large integer */
|
||||||
|
typedef uint32_t Elf32_Word; /* Unsigned large integer */
|
||||||
|
typedef uint16_t Elf32_Half; /* Unsigned medium integer */
|
||||||
|
|
||||||
|
typedef uint64_t Elf64_Addr;
|
||||||
|
typedef uint64_t Elf64_Off;
|
||||||
|
typedef int32_t Elf64_Shalf;
|
||||||
|
|
||||||
|
#ifdef __alpha__
|
||||||
|
typedef int64_t Elf64_Sword;
|
||||||
|
typedef uint64_t Elf64_Word;
|
||||||
|
#else
|
||||||
|
typedef int32_t Elf64_Sword;
|
||||||
|
typedef uint32_t Elf64_Word;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef int64_t Elf64_Sxword;
|
||||||
|
typedef uint64_t Elf64_Xword;
|
||||||
|
|
||||||
|
typedef uint32_t Elf64_Half;
|
||||||
|
typedef uint16_t Elf64_Quarter;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* e_ident[] identification indexes
|
||||||
|
* See http://www.sco.com/developers/gabi/latest/ch4.eheader.html
|
||||||
|
*/
|
||||||
|
#define EI_MAG0 0 /* file ID */
|
||||||
|
#define EI_MAG1 1 /* file ID */
|
||||||
|
#define EI_MAG2 2 /* file ID */
|
||||||
|
#define EI_MAG3 3 /* file ID */
|
||||||
|
#define EI_CLASS 4 /* file class */
|
||||||
|
#define EI_DATA 5 /* data encoding */
|
||||||
|
#define EI_VERSION 6 /* ELF header version */
|
||||||
|
#define EI_OSABI 7 /* OS/ABI ID */
|
||||||
|
#define EI_ABIVERSION 8 /* ABI version */
|
||||||
|
#define EI_PAD 9 /* start of pad bytes */
|
||||||
|
#define EI_NIDENT 16 /* Size of e_ident[] */
|
||||||
|
|
||||||
|
/* e_ident[] magic number */
|
||||||
|
#define ELFMAG0 0x7f /* e_ident[EI_MAG0] */
|
||||||
|
#define ELFMAG1 'E' /* e_ident[EI_MAG1] */
|
||||||
|
#define ELFMAG2 'L' /* e_ident[EI_MAG2] */
|
||||||
|
#define ELFMAG3 'F' /* e_ident[EI_MAG3] */
|
||||||
|
#define ELFMAG "\177ELF" /* magic */
|
||||||
|
#define SELFMAG 4 /* size of magic */
|
||||||
|
|
||||||
|
/* e_ident[] file class */
|
||||||
|
#define ELFCLASSNONE 0 /* invalid */
|
||||||
|
#define ELFCLASS32 1 /* 32-bit objs */
|
||||||
|
#define ELFCLASS64 2 /* 64-bit objs */
|
||||||
|
#define ELFCLASSNUM 3 /* number of classes */
|
||||||
|
|
||||||
|
/* e_ident[] data encoding */
|
||||||
|
#define ELFDATANONE 0 /* invalid */
|
||||||
|
#define ELFDATA2LSB 1 /* Little-Endian */
|
||||||
|
#define ELFDATA2MSB 2 /* Big-Endian */
|
||||||
|
#define ELFDATANUM 3 /* number of data encode defines */
|
||||||
|
|
||||||
|
/* e_ident[] Operating System/ABI */
|
||||||
|
#define ELFOSABI_SYSV 0 /* UNIX System V ABI */
|
||||||
|
#define ELFOSABI_HPUX 1 /* HP-UX operating system */
|
||||||
|
#define ELFOSABI_NETBSD 2 /* NetBSD */
|
||||||
|
#define ELFOSABI_LINUX 3 /* GNU/Linux */
|
||||||
|
#define ELFOSABI_HURD 4 /* GNU/Hurd */
|
||||||
|
#define ELFOSABI_86OPEN 5 /* 86Open common IA32 ABI */
|
||||||
|
#define ELFOSABI_SOLARIS 6 /* Solaris */
|
||||||
|
#define ELFOSABI_MONTEREY 7 /* Monterey */
|
||||||
|
#define ELFOSABI_IRIX 8 /* IRIX */
|
||||||
|
#define ELFOSABI_FREEBSD 9 /* FreeBSD */
|
||||||
|
#define ELFOSABI_TRU64 10 /* TRU64 UNIX */
|
||||||
|
#define ELFOSABI_MODESTO 11 /* Novell Modesto */
|
||||||
|
#define ELFOSABI_OPENBSD 12 /* OpenBSD */
|
||||||
|
#define ELFOSABI_ARM 97 /* ARM */
|
||||||
|
#define ELFOSABI_STANDALONE 255 /* Standalone (embedded) application */
|
||||||
|
|
||||||
|
/* e_ident */
|
||||||
|
#define IS_ELF(ehdr) ((ehdr).e_ident[EI_MAG0] == ELFMAG0 && \
|
||||||
|
(ehdr).e_ident[EI_MAG1] == ELFMAG1 && \
|
||||||
|
(ehdr).e_ident[EI_MAG2] == ELFMAG2 && \
|
||||||
|
(ehdr).e_ident[EI_MAG3] == ELFMAG3)
|
||||||
|
|
||||||
|
/* ELF Header */
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
unsigned char e_ident[EI_NIDENT]; /* ELF Identification */
|
||||||
|
Elf32_Half e_type; /* object file type */
|
||||||
|
Elf32_Half e_machine; /* machine */
|
||||||
|
Elf32_Word e_version; /* object file version */
|
||||||
|
Elf32_Addr e_entry; /* virtual entry point */
|
||||||
|
Elf32_Off e_phoff; /* program header table offset */
|
||||||
|
Elf32_Off e_shoff; /* section header table offset */
|
||||||
|
Elf32_Word e_flags; /* processor-specific flags */
|
||||||
|
Elf32_Half e_ehsize; /* ELF header size */
|
||||||
|
Elf32_Half e_phentsize; /* program header entry size */
|
||||||
|
Elf32_Half e_phnum; /* number of program header entries */
|
||||||
|
Elf32_Half e_shentsize; /* section header entry size */
|
||||||
|
Elf32_Half e_shnum; /* number of section header entries */
|
||||||
|
Elf32_Half e_shstrndx; /* section header table's "section
|
||||||
|
header string table" entry offset */
|
||||||
|
} Elf32_Ehdr;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
unsigned char e_ident[EI_NIDENT]; /* Id bytes */
|
||||||
|
Elf64_Quarter e_type; /* file type */
|
||||||
|
Elf64_Quarter e_machine; /* machine type */
|
||||||
|
Elf64_Half e_version; /* version number */
|
||||||
|
Elf64_Addr e_entry; /* entry point */
|
||||||
|
Elf64_Off e_phoff; /* Program hdr offset */
|
||||||
|
Elf64_Off e_shoff; /* Section hdr offset */
|
||||||
|
Elf64_Half e_flags; /* Processor flags */
|
||||||
|
Elf64_Quarter e_ehsize; /* sizeof ehdr */
|
||||||
|
Elf64_Quarter e_phentsize; /* Program header entry size */
|
||||||
|
Elf64_Quarter e_phnum; /* Number of program headers */
|
||||||
|
Elf64_Quarter e_shentsize; /* Section header entry size */
|
||||||
|
Elf64_Quarter e_shnum; /* Number of section headers */
|
||||||
|
Elf64_Quarter e_shstrndx; /* String table index */
|
||||||
|
} Elf64_Ehdr;
|
||||||
|
|
||||||
|
/* e_type */
|
||||||
|
#define ET_NONE 0 /* No file type */
|
||||||
|
#define ET_REL 1 /* relocatable file */
|
||||||
|
#define ET_EXEC 2 /* executable file */
|
||||||
|
#define ET_DYN 3 /* shared object file */
|
||||||
|
#define ET_CORE 4 /* core file */
|
||||||
|
#define ET_NUM 5 /* number of types */
|
||||||
|
#define ET_LOPROC 0xff00 /* reserved range for processor */
|
||||||
|
#define ET_HIPROC 0xffff /* specific e_type */
|
||||||
|
|
||||||
|
/* e_machine */
|
||||||
|
#define EM_NONE 0 /* No Machine */
|
||||||
|
#define EM_M32 1 /* AT&T WE 32100 */
|
||||||
|
#define EM_SPARC 2 /* SPARC */
|
||||||
|
#define EM_386 3 /* Intel 80386 */
|
||||||
|
#define EM_68K 4 /* Motorola 68000 */
|
||||||
|
#define EM_88K 5 /* Motorola 88000 */
|
||||||
|
#define EM_486 6 /* Intel 80486 - unused? */
|
||||||
|
#define EM_860 7 /* Intel 80860 */
|
||||||
|
#define EM_MIPS 8 /* MIPS R3000 Big-Endian only */
|
||||||
|
/*
|
||||||
|
* Don't know if EM_MIPS_RS4_BE,
|
||||||
|
* EM_SPARC64, EM_PARISC,
|
||||||
|
* or EM_PPC are ABI compliant
|
||||||
|
*/
|
||||||
|
#define EM_MIPS_RS4_BE 10 /* MIPS R4000 Big-Endian */
|
||||||
|
#define EM_SPARC64 11 /* SPARC v9 64-bit unofficial */
|
||||||
|
#define EM_PARISC 15 /* HPPA */
|
||||||
|
#define EM_SPARC32PLUS 18 /* Enhanced instruction set SPARC */
|
||||||
|
#define EM_PPC 20 /* PowerPC */
|
||||||
|
#define EM_ARM 40 /* ARM AArch32 */
|
||||||
|
#define EM_ALPHA 41 /* DEC ALPHA */
|
||||||
|
#define EM_SH 42 /* Hitachi/Renesas Super-H */
|
||||||
|
#define EM_SPARCV9 43 /* SPARC version 9 */
|
||||||
|
#define EM_IA_64 50 /* Intel IA-64 Processor */
|
||||||
|
#define EM_AMD64 62 /* AMD64 architecture */
|
||||||
|
#define EM_VAX 75 /* DEC VAX */
|
||||||
|
#define EM_AARCH64 183 /* ARM AArch64 */
|
||||||
|
|
||||||
|
/* Non-standard */
|
||||||
|
#define EM_ALPHA_EXP 0x9026 /* DEC ALPHA */
|
||||||
|
|
||||||
|
/* Version */
|
||||||
|
#define EV_NONE 0 /* Invalid */
|
||||||
|
#define EV_CURRENT 1 /* Current */
|
||||||
|
#define EV_NUM 2 /* number of versions */
|
||||||
|
|
||||||
|
/* Section Header */
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
Elf32_Word sh_name; /* name - index into section header
|
||||||
|
* string table section */
|
||||||
|
Elf32_Word sh_type; /* type */
|
||||||
|
Elf32_Word sh_flags; /* flags */
|
||||||
|
Elf32_Addr sh_addr; /* address */
|
||||||
|
Elf32_Off sh_offset; /* file offset */
|
||||||
|
Elf32_Word sh_size; /* section size */
|
||||||
|
Elf32_Word sh_link; /* section header table index link */
|
||||||
|
Elf32_Word sh_info; /* extra information */
|
||||||
|
Elf32_Word sh_addralign; /* address alignment */
|
||||||
|
Elf32_Word sh_entsize; /* section entry size */
|
||||||
|
} Elf32_Shdr;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
Elf64_Half sh_name; /* section name */
|
||||||
|
Elf64_Half sh_type; /* section type */
|
||||||
|
Elf64_Xword sh_flags; /* section flags */
|
||||||
|
Elf64_Addr sh_addr; /* virtual address */
|
||||||
|
Elf64_Off sh_offset; /* file offset */
|
||||||
|
Elf64_Xword sh_size; /* section size */
|
||||||
|
Elf64_Half sh_link; /* link to another */
|
||||||
|
Elf64_Half sh_info; /* misc info */
|
||||||
|
Elf64_Xword sh_addralign; /* memory alignment */
|
||||||
|
Elf64_Xword sh_entsize; /* table entry size */
|
||||||
|
} Elf64_Shdr;
|
||||||
|
|
||||||
|
/* Special Section Indexes */
|
||||||
|
#define SHN_UNDEF 0 /* undefined */
|
||||||
|
#define SHN_LORESERVE 0xff00 /* lower bounds of reserved indexes */
|
||||||
|
#define SHN_LOPROC 0xff00 /* reserved range for processor */
|
||||||
|
#define SHN_HIPROC 0xff1f /* specific section indexes */
|
||||||
|
#define SHN_ABS 0xfff1 /* absolute value */
|
||||||
|
#define SHN_COMMON 0xfff2 /* common symbol */
|
||||||
|
#define SHN_HIRESERVE 0xffff /* upper bounds of reserved indexes */
|
||||||
|
|
||||||
|
/* sh_type */
|
||||||
|
#define SHT_NULL 0 /* inactive */
|
||||||
|
#define SHT_PROGBITS 1 /* program defined information */
|
||||||
|
#define SHT_SYMTAB 2 /* symbol table section */
|
||||||
|
#define SHT_STRTAB 3 /* string table section */
|
||||||
|
#define SHT_RELA 4 /* relocation section with addends*/
|
||||||
|
#define SHT_HASH 5 /* symbol hash table section */
|
||||||
|
#define SHT_DYNAMIC 6 /* dynamic section */
|
||||||
|
#define SHT_NOTE 7 /* note section */
|
||||||
|
#define SHT_NOBITS 8 /* no space section */
|
||||||
|
#define SHT_REL 9 /* relation section without addends */
|
||||||
|
#define SHT_SHLIB 10 /* reserved - purpose unknown */
|
||||||
|
#define SHT_DYNSYM 11 /* dynamic symbol table section */
|
||||||
|
#define SHT_NUM 12 /* number of section types */
|
||||||
|
#define SHT_LOPROC 0x70000000 /* reserved range for processor */
|
||||||
|
#define SHT_HIPROC 0x7fffffff /* specific section header types */
|
||||||
|
#define SHT_LOUSER 0x80000000 /* reserved range for application */
|
||||||
|
#define SHT_HIUSER 0xffffffff /* specific indexes */
|
||||||
|
|
||||||
|
/* Section names */
|
||||||
|
#define ELF_BSS ".bss" /* uninitialized data */
|
||||||
|
#define ELF_DATA ".data" /* initialized data */
|
||||||
|
#define ELF_DEBUG ".debug" /* debug */
|
||||||
|
#define ELF_DYNAMIC ".dynamic" /* dynamic linking information */
|
||||||
|
#define ELF_DYNSTR ".dynstr" /* dynamic string table */
|
||||||
|
#define ELF_DYNSYM ".dynsym" /* dynamic symbol table */
|
||||||
|
#define ELF_FINI ".fini" /* termination code */
|
||||||
|
#define ELF_GOT ".got" /* global offset table */
|
||||||
|
#define ELF_HASH ".hash" /* symbol hash table */
|
||||||
|
#define ELF_INIT ".init" /* initialization code */
|
||||||
|
#define ELF_REL_DATA ".rel.data" /* relocation data */
|
||||||
|
#define ELF_REL_FINI ".rel.fini" /* relocation termination code */
|
||||||
|
#define ELF_REL_INIT ".rel.init" /* relocation initialization code */
|
||||||
|
#define ELF_REL_DYN ".rel.dyn" /* relocation dynamic link info */
|
||||||
|
#define ELF_REL_RODATA ".rel.rodata" /* relocation read-only data */
|
||||||
|
#define ELF_REL_TEXT ".rel.text" /* relocation code */
|
||||||
|
#define ELF_RODATA ".rodata" /* read-only data */
|
||||||
|
#define ELF_SHSTRTAB ".shstrtab" /* section header string table */
|
||||||
|
#define ELF_STRTAB ".strtab" /* string table */
|
||||||
|
#define ELF_SYMTAB ".symtab" /* symbol table */
|
||||||
|
#define ELF_TEXT ".text" /* code */
|
||||||
|
|
||||||
|
/* Section Attribute Flags - sh_flags */
|
||||||
|
#define SHF_WRITE 0x1 /* Writable */
|
||||||
|
#define SHF_ALLOC 0x2 /* occupies memory */
|
||||||
|
#define SHF_EXECINSTR 0x4 /* executable */
|
||||||
|
#define SHF_TLS 0x400 /* thread local storage */
|
||||||
|
#define SHF_MASKPROC 0xf0000000 /* reserved bits for processor \
|
||||||
|
* specific section attributes */
|
||||||
|
|
||||||
|
/* Symbol Table Entry */
|
||||||
|
typedef struct elf32_sym
|
||||||
|
{
|
||||||
|
Elf32_Word st_name; /* name - index into string table */
|
||||||
|
Elf32_Addr st_value; /* symbol value */
|
||||||
|
Elf32_Word st_size; /* symbol size */
|
||||||
|
unsigned char st_info; /* type and binding */
|
||||||
|
unsigned char st_other; /* 0 - no defined meaning */
|
||||||
|
Elf32_Half st_shndx; /* section header index */
|
||||||
|
} Elf32_Sym;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
Elf64_Half st_name; /* Symbol name index in str table */
|
||||||
|
Elf_Byte st_info; /* type / binding attrs */
|
||||||
|
Elf_Byte st_other; /* unused */
|
||||||
|
Elf64_Quarter st_shndx; /* section index of symbol */
|
||||||
|
Elf64_Xword st_value; /* value of symbol */
|
||||||
|
Elf64_Xword st_size; /* size of symbol */
|
||||||
|
} Elf64_Sym;
|
||||||
|
|
||||||
|
/* Symbol table index */
|
||||||
|
#define STN_UNDEF 0 /* undefined */
|
||||||
|
|
||||||
|
/* Extract symbol info - st_info */
|
||||||
|
#define ELF32_ST_BIND(x) ((x) >> 4)
|
||||||
|
#define ELF32_ST_TYPE(x) (((unsigned int)x) & 0xf)
|
||||||
|
#define ELF32_ST_INFO(b, t) (((b) << 4) + ((t)&0xf))
|
||||||
|
|
||||||
|
#define ELF64_ST_BIND(x) ((x) >> 4)
|
||||||
|
#define ELF64_ST_TYPE(x) (((unsigned int)x) & 0xf)
|
||||||
|
#define ELF64_ST_INFO(b, t) (((b) << 4) + ((t)&0xf))
|
||||||
|
|
||||||
|
/* Symbol Binding - ELF32_ST_BIND - st_info */
|
||||||
|
#define STB_LOCAL 0 /* Local symbol */
|
||||||
|
#define STB_GLOBAL 1 /* Global symbol */
|
||||||
|
#define STB_WEAK 2 /* like global - lower precedence */
|
||||||
|
#define STB_NUM 3 /* number of symbol bindings */
|
||||||
|
#define STB_LOPROC 13 /* reserved range for processor */
|
||||||
|
#define STB_HIPROC 15 /* specific symbol bindings */
|
||||||
|
|
||||||
|
/* Symbol type - ELF32_ST_TYPE - st_info */
|
||||||
|
#define STT_NOTYPE 0 /* not specified */
|
||||||
|
#define STT_OBJECT 1 /* data object */
|
||||||
|
#define STT_FUNC 2 /* function */
|
||||||
|
#define STT_SECTION 3 /* section */
|
||||||
|
#define STT_FILE 4 /* file */
|
||||||
|
#define STT_TLS 6 /* thread local storage */
|
||||||
|
#define STT_LOPROC 13 /* reserved range for processor */
|
||||||
|
#define STT_HIPROC 15 /* specific symbol types */
|
||||||
|
|
||||||
|
/* Relocation entry with implicit addend */
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
Elf32_Addr r_offset; /* offset of relocation */
|
||||||
|
Elf32_Word r_info; /* symbol table index and type */
|
||||||
|
} Elf32_Rel;
|
||||||
|
|
||||||
|
/* Relocation entry with explicit addend */
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
Elf32_Addr r_offset; /* offset of relocation */
|
||||||
|
Elf32_Word r_info; /* symbol table index and type */
|
||||||
|
Elf32_Sword r_addend;
|
||||||
|
} Elf32_Rela;
|
||||||
|
|
||||||
|
/* Extract relocation info - r_info */
|
||||||
|
#define ELF32_R_SYM(i) ((i) >> 8)
|
||||||
|
#define ELF32_R_TYPE(i) ((unsigned char)(i))
|
||||||
|
#define ELF32_R_INFO(s, t) (((s) << 8) + (unsigned char)(t))
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
Elf64_Xword r_offset; /* where to do it */
|
||||||
|
Elf64_Xword r_info; /* index & type of relocation */
|
||||||
|
} Elf64_Rel;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
Elf64_Xword r_offset; /* where to do it */
|
||||||
|
Elf64_Xword r_info; /* index & type of relocation */
|
||||||
|
Elf64_Sxword r_addend; /* adjustment value */
|
||||||
|
} Elf64_Rela;
|
||||||
|
|
||||||
|
#define ELF64_R_SYM(info) ((info) >> 32)
|
||||||
|
#define ELF64_R_TYPE(info) ((info)&0xFFFFFFFF)
|
||||||
|
#define ELF64_R_INFO(s, t) (((s) << 32) + (__uint32_t)(t))
|
||||||
|
|
||||||
|
#if defined(__mips64__) && defined(__MIPSEL__)
|
||||||
|
/*
|
||||||
|
* The 64-bit MIPS ELF ABI uses a slightly different relocation format
|
||||||
|
* than the regular ELF ABI: the r_info field is split into several
|
||||||
|
* pieces (see gnu/usr.bin/binutils/include/elf/mips.h for details).
|
||||||
|
*/
|
||||||
|
#undef ELF64_R_SYM
|
||||||
|
#undef ELF64_R_TYPE
|
||||||
|
#undef ELF64_R_INFO
|
||||||
|
#define ELF64_R_TYPE(info) (swap32((info) >> 32))
|
||||||
|
#define ELF64_R_SYM(info) ((info)&0xFFFFFFFF)
|
||||||
|
#define ELF64_R_INFO(s, t) (((__uint64_t)swap32(t) << 32) + (__uint32_t)(s))
|
||||||
|
#endif /* __mips64__ && __MIPSEL__ */
|
||||||
|
|
||||||
|
/* Program Header */
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
Elf32_Word p_type; /* segment type */
|
||||||
|
Elf32_Off p_offset; /* segment offset */
|
||||||
|
Elf32_Addr p_vaddr; /* virtual address of segment */
|
||||||
|
Elf32_Addr p_paddr; /* physical address - ignored? */
|
||||||
|
Elf32_Word p_filesz; /* number of bytes in file for seg. */
|
||||||
|
Elf32_Word p_memsz; /* number of bytes in mem. for seg. */
|
||||||
|
Elf32_Word p_flags; /* flags */
|
||||||
|
Elf32_Word p_align; /* memory alignment */
|
||||||
|
} Elf32_Phdr;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
Elf64_Half p_type; /* entry type */
|
||||||
|
Elf64_Half p_flags; /* flags */
|
||||||
|
Elf64_Off p_offset; /* offset */
|
||||||
|
Elf64_Addr p_vaddr; /* virtual address */
|
||||||
|
Elf64_Addr p_paddr; /* physical address */
|
||||||
|
Elf64_Xword p_filesz; /* file size */
|
||||||
|
Elf64_Xword p_memsz; /* memory size */
|
||||||
|
Elf64_Xword p_align; /* memory & file alignment */
|
||||||
|
} Elf64_Phdr;
|
||||||
|
|
||||||
|
/* Segment types - p_type */
|
||||||
|
#define PT_NULL 0 /* unused */
|
||||||
|
#define PT_LOAD 1 /* loadable segment */
|
||||||
|
#define PT_DYNAMIC 2 /* dynamic linking section */
|
||||||
|
#define PT_INTERP 3 /* the RTLD */
|
||||||
|
#define PT_NOTE 4 /* auxiliary information */
|
||||||
|
#define PT_SHLIB 5 /* reserved - purpose undefined */
|
||||||
|
#define PT_PHDR 6 /* program header */
|
||||||
|
#define PT_TLS 7 /* thread local storage */
|
||||||
|
#define PT_LOOS 0x60000000 /* reserved range for OS */
|
||||||
|
#define PT_HIOS 0x6fffffff /* specific segment types */
|
||||||
|
#define PT_LOPROC 0x70000000 /* reserved range for processor */
|
||||||
|
#define PT_HIPROC 0x7fffffff /* specific segment types */
|
||||||
|
|
||||||
|
#define PT_OPENBSD_RANDOMIZE 0x65a3dbe6 /* fill with random data */
|
||||||
|
#define PT_GANDR_KERNEL 0x67646b6c /* gdkl */
|
||||||
|
|
||||||
|
/* Segment flags - p_flags */
|
||||||
|
#define PF_X 0x1 /* Executable */
|
||||||
|
#define PF_W 0x2 /* Writable */
|
||||||
|
#define PF_R 0x4 /* Readable */
|
||||||
|
#define PF_MASKPROC 0xf0000000 /* reserved bits for processor */
|
||||||
|
/* specific segment flags */
|
||||||
|
|
||||||
|
/* Dynamic structure */
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
Elf32_Sword d_tag; /* controls meaning of d_val */
|
||||||
|
union {
|
||||||
|
Elf32_Word d_val; /* Multiple meanings - see d_tag */
|
||||||
|
Elf32_Addr d_ptr; /* program virtual address */
|
||||||
|
} d_un;
|
||||||
|
} Elf32_Dyn;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
Elf64_Xword d_tag; /* controls meaning of d_val */
|
||||||
|
union {
|
||||||
|
Elf64_Addr d_ptr;
|
||||||
|
Elf64_Xword d_val;
|
||||||
|
} d_un;
|
||||||
|
} Elf64_Dyn;
|
||||||
|
|
||||||
|
/* Dynamic Array Tags - d_tag */
|
||||||
|
#define DT_NULL 0 /* marks end of _DYNAMIC array */
|
||||||
|
#define DT_NEEDED 1 /* string table offset of needed lib */
|
||||||
|
#define DT_PLTRELSZ 2 /* size of relocation entries in PLT */
|
||||||
|
#define DT_PLTGOT 3 /* address PLT/GOT */
|
||||||
|
#define DT_HASH 4 /* address of symbol hash table */
|
||||||
|
#define DT_STRTAB 5 /* address of string table */
|
||||||
|
#define DT_SYMTAB 6 /* address of symbol table */
|
||||||
|
#define DT_RELA 7 /* address of relocation table */
|
||||||
|
#define DT_RELASZ 8 /* size of relocation table */
|
||||||
|
#define DT_RELAENT 9 /* size of relocation entry */
|
||||||
|
#define DT_STRSZ 10 /* size of string table */
|
||||||
|
#define DT_SYMENT 11 /* size of symbol table entry */
|
||||||
|
#define DT_INIT 12 /* address of initialization func. */
|
||||||
|
#define DT_FINI 13 /* address of termination function */
|
||||||
|
#define DT_SONAME 14 /* string table offset of shared obj */
|
||||||
|
#define DT_RPATH 15 /* string table offset of library \
|
||||||
|
* search path */
|
||||||
|
#define DT_SYMBOLIC 16 /* start sym search in shared obj. */
|
||||||
|
#define DT_REL 17 /* address of rel. tbl. w addends */
|
||||||
|
#define DT_RELSZ 18 /* size of DT_REL relocation table */
|
||||||
|
#define DT_RELENT 19 /* size of DT_REL relocation entry */
|
||||||
|
#define DT_PLTREL 20 /* PLT referenced relocation entry */
|
||||||
|
#define DT_DEBUG 21 /* bugger */
|
||||||
|
#define DT_TEXTREL 22 /* Allow rel. mod. to unwritable seg */
|
||||||
|
#define DT_JMPREL 23 /* add. of PLT's relocation entries */
|
||||||
|
#define DT_BIND_NOW 24 /* Bind now regardless of env setting */
|
||||||
|
#define DT_LOOS 0x6000000d /* reserved range for OS */
|
||||||
|
#define DT_HIOS 0x6ffff000 /* specific dynamic array tags */
|
||||||
|
#define DT_LOPROC 0x70000000 /* reserved range for processor */
|
||||||
|
#define DT_HIPROC 0x7fffffff /* specific dynamic array tags */
|
||||||
|
|
||||||
|
/* some other useful tags */
|
||||||
|
#define DT_RELACOUNT 0x6ffffff9 /* if present, number of RELATIVE */
|
||||||
|
#define DT_RELCOUNT 0x6ffffffa /* relocs, which must come first */
|
||||||
|
#define DT_FLAGS_1 0x6ffffffb
|
||||||
|
|
||||||
|
/* Dynamic Flags - DT_FLAGS_1 .dynamic entry */
|
||||||
|
#define DF_1_NOW 0x00000001
|
||||||
|
#define DF_1_GLOBAL 0x00000002
|
||||||
|
#define DF_1_GROUP 0x00000004
|
||||||
|
#define DF_1_NODELETE 0x00000008
|
||||||
|
#define DF_1_LOADFLTR 0x00000010
|
||||||
|
#define DF_1_INITFIRST 0x00000020
|
||||||
|
#define DF_1_NOOPEN 0x00000040
|
||||||
|
#define DF_1_ORIGIN 0x00000080
|
||||||
|
#define DF_1_DIRECT 0x00000100
|
||||||
|
#define DF_1_TRANS 0x00000200
|
||||||
|
#define DF_1_INTERPOSE 0x00000400
|
||||||
|
#define DF_1_NODEFLIB 0x00000800
|
||||||
|
#define DF_1_NODUMP 0x00001000
|
||||||
|
#define DF_1_CONLFAT 0x00002000
|
||||||
|
|
||||||
|
/* ld.so: number of low tags that are used saved internally (0 .. DT_NUM-1) */
|
||||||
|
#define DT_NUM (DT_JMPREL + 1)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Note Definitions
|
||||||
|
*/
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
Elf32_Word namesz;
|
||||||
|
Elf32_Word descsz;
|
||||||
|
Elf32_Word type;
|
||||||
|
} Elf32_Note;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
Elf64_Half namesz;
|
||||||
|
Elf64_Half descsz;
|
||||||
|
Elf64_Half type;
|
||||||
|
} Elf64_Note;
|
||||||
|
|
||||||
|
#if defined(ELFSIZE) && (ELFSIZE == 32)
|
||||||
|
#define Elf_Ehdr Elf32_Ehdr
|
||||||
|
#define Elf_Phdr Elf32_Phdr
|
||||||
|
#define Elf_Shdr Elf32_Shdr
|
||||||
|
#define Elf_Sym Elf32_Sym
|
||||||
|
#define Elf_Rel Elf32_Rel
|
||||||
|
#define Elf_RelA Elf32_Rela
|
||||||
|
#define Elf_Dyn Elf32_Dyn
|
||||||
|
#define Elf_Half Elf32_Half
|
||||||
|
#define Elf_Word Elf32_Word
|
||||||
|
#define Elf_Sword Elf32_Sword
|
||||||
|
#define Elf_Addr Elf32_Addr
|
||||||
|
#define Elf_Off Elf32_Off
|
||||||
|
#define Elf_Nhdr Elf32_Nhdr
|
||||||
|
#define Elf_Note Elf32_Note
|
||||||
|
|
||||||
|
#define ELF_R_SYM ELF32_R_SYM
|
||||||
|
#define ELF_R_TYPE ELF32_R_TYPE
|
||||||
|
#define ELF_R_INFO ELF32_R_INFO
|
||||||
|
#define ELFCLASS ELFCLASS32
|
||||||
|
|
||||||
|
#define ELF_ST_BIND ELF32_ST_BIND
|
||||||
|
#define ELF_ST_TYPE ELF32_ST_TYPE
|
||||||
|
#define ELF_ST_INFO ELF32_ST_INFO
|
||||||
|
|
||||||
|
#elif defined(ELFSIZE) && (ELFSIZE == 64)
|
||||||
|
|
||||||
|
#define Elf_Ehdr Elf64_Ehdr
|
||||||
|
#define Elf_Phdr Elf64_Phdr
|
||||||
|
#define Elf_Shdr Elf64_Shdr
|
||||||
|
#define Elf_Sym Elf64_Sym
|
||||||
|
#define Elf_Rel Elf64_Rel
|
||||||
|
#define Elf_RelA Elf64_Rela
|
||||||
|
#define Elf_Dyn Elf64_Dyn
|
||||||
|
#define Elf_Half Elf64_Half
|
||||||
|
#define Elf_Word Elf64_Word
|
||||||
|
#define Elf_Sword Elf64_Sword
|
||||||
|
#define Elf_Addr Elf64_Addr
|
||||||
|
#define Elf_Off Elf64_Off
|
||||||
|
#define Elf_Nhdr Elf64_Nhdr
|
||||||
|
#define Elf_Note Elf64_Note
|
||||||
|
|
||||||
|
#define ELF_R_SYM ELF64_R_SYM
|
||||||
|
#define ELF_R_TYPE ELF64_R_TYPE
|
||||||
|
#define ELF_R_INFO ELF64_R_INFO
|
||||||
|
#define ELFCLASS ELFCLASS64
|
||||||
|
|
||||||
|
#define ELF_ST_BIND ELF64_ST_BIND
|
||||||
|
#define ELF_ST_TYPE ELF64_ST_TYPE
|
||||||
|
#define ELF_ST_INFO ELF64_ST_INFO
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
49
source/libs/elfload/elfarch.h
Normal file
49
source/libs/elfload/elfarch.h
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2014, Owen Shepherd
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||||
|
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||||
|
* AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||||
|
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||||
|
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||||
|
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||||
|
* PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef ELFARCH_H
|
||||||
|
#define ELFARCH_H
|
||||||
|
|
||||||
|
#if defined(__i386__)
|
||||||
|
#define EM_THIS EM_386
|
||||||
|
#define EL_ARCH_USES_REL
|
||||||
|
#elif defined(__amd64__)
|
||||||
|
#define EM_THIS EM_AMD64
|
||||||
|
#define EL_ARCH_USES_RELA
|
||||||
|
#elif defined(__arm__)
|
||||||
|
#define EM_THIS EM_ARM
|
||||||
|
#define EL_ARCH_USES_REL
|
||||||
|
#elif defined(__aarch64__)
|
||||||
|
#define EM_THIS EM_AARCH64
|
||||||
|
#define EL_ARCH_USES_RELA
|
||||||
|
#define EL_ARCH_USES_REL
|
||||||
|
#else
|
||||||
|
#error specify your ELF architecture
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__LP64__) || defined(__LLP64__)
|
||||||
|
#define ELFSIZE 64
|
||||||
|
#else
|
||||||
|
#define ELFSIZE 32
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
||||||
|
#define ELFDATATHIS ELFDATA2LSB
|
||||||
|
#else
|
||||||
|
#define ELFDATATHIS ELFDATA2MSB
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
324
source/libs/elfload/elfload.c
Normal file
324
source/libs/elfload/elfload.c
Normal file
@@ -0,0 +1,324 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2018, M4xw
|
||||||
|
* Copyright © 2014, Owen Shepherd
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||||
|
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||||
|
* AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||||
|
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||||
|
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||||
|
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||||
|
* PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "elfload.h"
|
||||||
|
|
||||||
|
el_status el_pread(el_ctx *ctx, void *def, size_t nb, size_t offset)
|
||||||
|
{
|
||||||
|
return ctx->pread(ctx, def, nb, offset) ? EL_OK : EL_EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define EL_PHOFF(ctx, num) (((ctx)->ehdr.e_phoff + (num) *(ctx)->ehdr.e_phentsize))
|
||||||
|
el_status el_findphdr(el_ctx *ctx, Elf_Phdr *phdr, uint32_t type, unsigned *i)
|
||||||
|
{
|
||||||
|
el_status rv = EL_OK;
|
||||||
|
for (; *i < ctx->ehdr.e_phnum; (*i)++)
|
||||||
|
{
|
||||||
|
if ((rv = el_pread(ctx, phdr, sizeof *phdr, EL_PHOFF(ctx, *i))))
|
||||||
|
return rv;
|
||||||
|
|
||||||
|
if (phdr->p_type == type)
|
||||||
|
{
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*i = -1;
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define EL_SHOFF(ctx, num) (((ctx)->ehdr.e_shoff + (num) *(ctx)->ehdr.e_shentsize))
|
||||||
|
el_status el_findshdr(el_ctx *ctx, Elf_Shdr *shdr, uint32_t type, unsigned *i)
|
||||||
|
{
|
||||||
|
el_status rv = EL_OK;
|
||||||
|
|
||||||
|
for (; *i < ctx->ehdr.e_shnum; (*i)++)
|
||||||
|
{
|
||||||
|
if ((rv = el_pread(ctx, shdr, sizeof *shdr, EL_SHOFF(ctx, *i))))
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
|
||||||
|
if (shdr->sh_type == type)
|
||||||
|
{
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*i = -1;
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
el_status el_init(el_ctx *ctx)
|
||||||
|
{
|
||||||
|
el_status rv = EL_OK;
|
||||||
|
if ((rv = el_pread(ctx, &ctx->ehdr, sizeof ctx->ehdr, 0)))
|
||||||
|
return rv;
|
||||||
|
|
||||||
|
/* validate header */
|
||||||
|
|
||||||
|
if (!IS_ELF(ctx->ehdr))
|
||||||
|
return EL_NOTELF;
|
||||||
|
|
||||||
|
if (ctx->ehdr.e_ident[EI_CLASS] != ELFCLASS)
|
||||||
|
return EL_WRONGBITS;
|
||||||
|
|
||||||
|
if (ctx->ehdr.e_ident[EI_DATA] != ELFDATATHIS)
|
||||||
|
return EL_WRONGENDIAN;
|
||||||
|
|
||||||
|
if (ctx->ehdr.e_ident[EI_VERSION] != EV_CURRENT)
|
||||||
|
return EL_NOTELF;
|
||||||
|
|
||||||
|
if (ctx->ehdr.e_type != ET_EXEC && ctx->ehdr.e_type != ET_DYN)
|
||||||
|
return EL_NOTEXEC;
|
||||||
|
|
||||||
|
if (ctx->ehdr.e_machine != EM_THIS)
|
||||||
|
return EL_WRONGARCH;
|
||||||
|
|
||||||
|
if (ctx->ehdr.e_version != EV_CURRENT)
|
||||||
|
return EL_NOTELF;
|
||||||
|
|
||||||
|
/* load phdrs */
|
||||||
|
Elf_Phdr ph;
|
||||||
|
|
||||||
|
/* iterate through, calculate extents */
|
||||||
|
ctx->base_load_paddr = ctx->base_load_vaddr = 0;
|
||||||
|
ctx->align = 1;
|
||||||
|
ctx->memsz = 0;
|
||||||
|
|
||||||
|
unsigned i = 0;
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
if ((rv = el_findphdr(ctx, &ph, PT_LOAD, &i)))
|
||||||
|
return rv;
|
||||||
|
|
||||||
|
if (i == (unsigned)-1)
|
||||||
|
break;
|
||||||
|
|
||||||
|
Elf_Addr phend = ph.p_vaddr + ph.p_memsz;
|
||||||
|
if (phend > ctx->memsz)
|
||||||
|
ctx->memsz = phend;
|
||||||
|
|
||||||
|
if (ph.p_align > ctx->align)
|
||||||
|
ctx->align = ph.p_align;
|
||||||
|
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Program Header
|
||||||
|
if (ctx->ehdr.e_type == ET_DYN)
|
||||||
|
{
|
||||||
|
i = 0;
|
||||||
|
|
||||||
|
if ((rv = el_findphdr(ctx, &ph, PT_DYNAMIC, &i)))
|
||||||
|
return rv;
|
||||||
|
|
||||||
|
if (i == (unsigned)-1)
|
||||||
|
return EL_NODYN;
|
||||||
|
|
||||||
|
ctx->dynoff = ph.p_offset;
|
||||||
|
ctx->dynsize = ph.p_filesz;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ctx->dynoff = 0;
|
||||||
|
ctx->dynsize = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Section String Table
|
||||||
|
if (ctx->ehdr.e_type == ET_DYN)
|
||||||
|
{
|
||||||
|
i = ctx->ehdr.e_shstrndx - 1;
|
||||||
|
|
||||||
|
if ((rv = el_findshdr(ctx, &ctx->shstr, SHT_STRTAB, &i)))
|
||||||
|
return rv;
|
||||||
|
|
||||||
|
// Reset
|
||||||
|
i = 0;
|
||||||
|
|
||||||
|
if ((rv = el_findshdr(ctx, &ctx->symtab, SHT_SYMTAB, &i)))
|
||||||
|
return rv;
|
||||||
|
|
||||||
|
if (i == (unsigned)-1)
|
||||||
|
return EL_NODYN;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
typedef void* (*el_alloc_cb)(
|
||||||
|
el_ctx *ctx,
|
||||||
|
Elf_Addr phys,
|
||||||
|
Elf_Addr virt,
|
||||||
|
Elf_Addr size);
|
||||||
|
*/
|
||||||
|
|
||||||
|
el_status el_load(el_ctx *ctx, el_alloc_cb alloc)
|
||||||
|
{
|
||||||
|
el_status rv = EL_OK;
|
||||||
|
|
||||||
|
/* address deltas */
|
||||||
|
Elf_Addr pdelta = ctx->base_load_paddr;
|
||||||
|
Elf_Addr vdelta = ctx->base_load_vaddr;
|
||||||
|
|
||||||
|
/* iterate paddrs */
|
||||||
|
Elf_Phdr ph;
|
||||||
|
unsigned i = 0;
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
if ((rv = el_findphdr(ctx, &ph, PT_LOAD, &i)))
|
||||||
|
return rv;
|
||||||
|
|
||||||
|
if (i == (unsigned)-1)
|
||||||
|
break;
|
||||||
|
|
||||||
|
Elf_Addr pload = ph.p_paddr + pdelta;
|
||||||
|
Elf_Addr vload = ph.p_vaddr + vdelta;
|
||||||
|
|
||||||
|
/* allocate mem */
|
||||||
|
char *dest = alloc(ctx, pload, vload, ph.p_memsz);
|
||||||
|
if (!dest)
|
||||||
|
return EL_ENOMEM;
|
||||||
|
|
||||||
|
EL_DEBUG("Loading seg fileoff %x, vaddr %x to %p\n",
|
||||||
|
ph.p_offset, ph.p_vaddr, dest);
|
||||||
|
|
||||||
|
/* read loaded portion */
|
||||||
|
if ((rv = el_pread(ctx, dest, ph.p_filesz, ph.p_offset)))
|
||||||
|
return rv;
|
||||||
|
|
||||||
|
/* zero mem-only portion */
|
||||||
|
memset(dest + ph.p_filesz, 0, ph.p_memsz - ph.p_filesz);
|
||||||
|
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
el_status el_finddyn(el_ctx *ctx, Elf_Dyn *dyn, uint32_t tag)
|
||||||
|
{
|
||||||
|
el_status rv = EL_OK;
|
||||||
|
size_t ndyn = ctx->dynsize / sizeof(Elf_Dyn);
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < ndyn; i++)
|
||||||
|
{
|
||||||
|
if ((rv = el_pread(ctx, dyn, sizeof *dyn, ctx->dynoff + i * sizeof *dyn)))
|
||||||
|
return rv;
|
||||||
|
|
||||||
|
if (dyn->d_tag == tag)
|
||||||
|
return EL_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
dyn->d_tag = DT_NULL;
|
||||||
|
return EL_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
el_status el_findrelocs(el_ctx *ctx, el_relocinfo *ri, uint32_t type)
|
||||||
|
{
|
||||||
|
el_status rv = EL_OK;
|
||||||
|
|
||||||
|
Elf_Dyn rel, relsz, relent;
|
||||||
|
|
||||||
|
if ((rv = el_finddyn(ctx, &rel, type)))
|
||||||
|
return rv;
|
||||||
|
|
||||||
|
if ((rv = el_finddyn(ctx, &relsz, type + 1)))
|
||||||
|
return rv;
|
||||||
|
|
||||||
|
if ((rv = el_finddyn(ctx, &relent, type + 2)))
|
||||||
|
return rv;
|
||||||
|
|
||||||
|
if (rel.d_tag == DT_NULL || relsz.d_tag == DT_NULL || relent.d_tag == DT_NULL)
|
||||||
|
{
|
||||||
|
ri->entrysize = 0;
|
||||||
|
ri->tablesize = 0;
|
||||||
|
ri->tableoff = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ri->tableoff = rel.d_un.d_ptr;
|
||||||
|
ri->tablesize = relsz.d_un.d_val;
|
||||||
|
ri->entrysize = relent.d_un.d_val;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern el_status el_applyrel(el_ctx *ctx, Elf_Rel *rel);
|
||||||
|
extern el_status el_applyrela(el_ctx *ctx, Elf_RelA *rela);
|
||||||
|
|
||||||
|
el_status el_relocate(el_ctx *ctx)
|
||||||
|
{
|
||||||
|
el_status rv = EL_OK;
|
||||||
|
|
||||||
|
// not dynamic
|
||||||
|
if (ctx->ehdr.e_type != ET_DYN)
|
||||||
|
return EL_OK;
|
||||||
|
|
||||||
|
char *base = (char *)ctx->base_load_paddr;
|
||||||
|
|
||||||
|
el_relocinfo ri;
|
||||||
|
#ifdef EL_ARCH_USES_REL
|
||||||
|
if ((rv = el_findrelocs(ctx, &ri, DT_REL)))
|
||||||
|
return rv;
|
||||||
|
|
||||||
|
if (ri.entrysize != sizeof(Elf_Rel) && ri.tablesize)
|
||||||
|
{
|
||||||
|
EL_DEBUG("Relocation size %u doesn't match expected %u\n",
|
||||||
|
ri.entrysize, sizeof(Elf_Rel));
|
||||||
|
return EL_BADREL;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t relcnt = ri.tablesize / sizeof(Elf_Rel);
|
||||||
|
Elf_Rel *reltab = (Elf_Rel *)(base + ri.tableoff);
|
||||||
|
for (size_t i = 0; i < relcnt; i++)
|
||||||
|
{
|
||||||
|
if ((rv = el_applyrel(ctx, &reltab[i])))
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef EL_ARCH_USES_RELA
|
||||||
|
if ((rv = el_findrelocs(ctx, &ri, DT_RELA)))
|
||||||
|
return rv;
|
||||||
|
|
||||||
|
if (ri.entrysize != sizeof(Elf_RelA) && ri.tablesize)
|
||||||
|
{
|
||||||
|
EL_DEBUG("Relocation size %u doesn't match expected %u\n",
|
||||||
|
ri.entrysize, sizeof(Elf_RelA));
|
||||||
|
return EL_BADREL;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t relacnt = ri.tablesize / sizeof(Elf_RelA);
|
||||||
|
Elf_RelA *relatab = (Elf_RelA *)(base + ri.tableoff);
|
||||||
|
for (size_t i = 0; i < relacnt; i++)
|
||||||
|
{
|
||||||
|
if ((rv = el_applyrela(ctx, &relatab[i])))
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(EL_ARCH_USES_REL) && !defined(EL_ARCH_USES_RELA)
|
||||||
|
#error No relocation type defined!
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
127
source/libs/elfload/elfload.h
Normal file
127
source/libs/elfload/elfload.h
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2018, M4xw
|
||||||
|
* Copyright © 2014, Owen Shepherd
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||||
|
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||||
|
* AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||||
|
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||||
|
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||||
|
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||||
|
* PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef ELFLOAD_H
|
||||||
|
#define ELFLOAD_H
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#include "elfarch.h"
|
||||||
|
#include "elf.h"
|
||||||
|
|
||||||
|
#include "../../utils/types.h"
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
#include "../../gfx/gfx.h"
|
||||||
|
#define EL_DEBUG(format, ...) \
|
||||||
|
gfx_printf(format __VA_OPT__(, ) __VA_ARGS__)
|
||||||
|
#else
|
||||||
|
#define EL_DEBUG(...) \
|
||||||
|
do \
|
||||||
|
{ \
|
||||||
|
} while (0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
EL_OK = 0,
|
||||||
|
|
||||||
|
EL_EIO,
|
||||||
|
EL_ENOMEM,
|
||||||
|
|
||||||
|
EL_NOTELF,
|
||||||
|
EL_WRONGBITS,
|
||||||
|
EL_WRONGENDIAN,
|
||||||
|
EL_WRONGARCH,
|
||||||
|
EL_WRONGOS,
|
||||||
|
EL_NOTEXEC,
|
||||||
|
EL_NODYN,
|
||||||
|
EL_BADREL,
|
||||||
|
|
||||||
|
} el_status;
|
||||||
|
|
||||||
|
typedef struct el_ctx
|
||||||
|
{
|
||||||
|
bool (*pread)(struct el_ctx *ctx, void *dest, size_t nb, size_t offset);
|
||||||
|
|
||||||
|
/* base_load_* -> address we are actually going to load at
|
||||||
|
*/
|
||||||
|
Elf_Addr
|
||||||
|
base_load_paddr,
|
||||||
|
base_load_vaddr;
|
||||||
|
|
||||||
|
/* size in memory of binary */
|
||||||
|
Elf_Addr memsz;
|
||||||
|
|
||||||
|
/* required alignment */
|
||||||
|
Elf_Addr align;
|
||||||
|
|
||||||
|
/* ELF header */
|
||||||
|
Elf_Ehdr ehdr;
|
||||||
|
|
||||||
|
// Section Header Str Table
|
||||||
|
Elf_Shdr shstr;
|
||||||
|
Elf_Shdr symtab;
|
||||||
|
|
||||||
|
/* Offset of dynamic table (0 if not ET_DYN) */
|
||||||
|
Elf_Off dynoff;
|
||||||
|
/* Size of dynamic table (0 if not ET_DYN) */
|
||||||
|
Elf_Addr dynsize;
|
||||||
|
} el_ctx;
|
||||||
|
|
||||||
|
el_status el_pread(el_ctx *ctx, void *def, size_t nb, size_t offset);
|
||||||
|
|
||||||
|
el_status el_init(el_ctx *ctx);
|
||||||
|
typedef void *(*el_alloc_cb)(
|
||||||
|
el_ctx *ctx,
|
||||||
|
Elf_Addr phys,
|
||||||
|
Elf_Addr virt,
|
||||||
|
Elf_Addr size);
|
||||||
|
|
||||||
|
el_status el_load(el_ctx *ctx, el_alloc_cb alloccb);
|
||||||
|
|
||||||
|
/* find the next phdr of type \p type, starting at \p *i.
|
||||||
|
* On success, returns EL_OK with *i set to the phdr number, and the phdr loaded
|
||||||
|
* in *phdr.
|
||||||
|
*
|
||||||
|
* If the end of the phdrs table was reached, *i is set to -1 and the contents
|
||||||
|
* of *phdr are undefined
|
||||||
|
*/
|
||||||
|
el_status el_findphdr(el_ctx *ctx, Elf_Phdr *phdr, uint32_t type, unsigned *i);
|
||||||
|
|
||||||
|
/* Relocate the loaded executable */
|
||||||
|
el_status el_relocate(el_ctx *ctx);
|
||||||
|
|
||||||
|
/* find a dynamic table entry
|
||||||
|
* returns the entry on success, dyn->d_tag = DT_NULL on failure
|
||||||
|
*/
|
||||||
|
el_status el_finddyn(el_ctx *ctx, Elf_Dyn *dyn, uint32_t type);
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
Elf_Off tableoff;
|
||||||
|
Elf_Addr tablesize;
|
||||||
|
Elf_Addr entrysize;
|
||||||
|
} el_relocinfo;
|
||||||
|
|
||||||
|
/* find all information regarding relocations of a specific type.
|
||||||
|
*
|
||||||
|
* pass DT_REL or DT_RELA for type
|
||||||
|
* sets ri->entrysize = 0 if not found
|
||||||
|
*/
|
||||||
|
el_status el_findrelocs(el_ctx *ctx, el_relocinfo *ri, uint32_t type);
|
||||||
|
|
||||||
|
#endif
|
||||||
84
source/libs/elfload/elfreloc_aarch64.c
Normal file
84
source/libs/elfload/elfreloc_aarch64.c
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2014, Owen Shepherd
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||||
|
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||||
|
* AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||||
|
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||||
|
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||||
|
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||||
|
* PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "elfload.h"
|
||||||
|
|
||||||
|
#if defined(__aarch64__)
|
||||||
|
|
||||||
|
#define R_AARCH64_NONE 0
|
||||||
|
#define R_AARCH64_RELATIVE 1027
|
||||||
|
|
||||||
|
el_status el_applyrela(el_ctx *ctx, Elf_RelA *rel)
|
||||||
|
{
|
||||||
|
uintptr_t *p = (uintptr_t *)(rel->r_offset + ctx->base_load_paddr);
|
||||||
|
uint32_t type = ELF_R_TYPE(rel->r_info);
|
||||||
|
uint32_t sym = ELF_R_SYM(rel->r_info);
|
||||||
|
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case R_AARCH64_NONE:
|
||||||
|
EL_DEBUG("R_AARCH64_NONE\n");
|
||||||
|
break;
|
||||||
|
case R_AARCH64_RELATIVE:
|
||||||
|
if (sym)
|
||||||
|
{
|
||||||
|
EL_DEBUG("R_AARCH64_RELATIVE with symbol ref!\n");
|
||||||
|
return EL_BADREL;
|
||||||
|
}
|
||||||
|
|
||||||
|
EL_DEBUG("Applying R_AARCH64_RELATIVE reloc @%p\n", p);
|
||||||
|
*p = rel->r_addend + ctx->base_load_vaddr;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
EL_DEBUG("Bad relocation %u\n", type);
|
||||||
|
return EL_BADREL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return EL_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
el_status el_applyrel(el_ctx *ctx, Elf_Rel *rel)
|
||||||
|
{
|
||||||
|
uintptr_t *p = (uintptr_t *)(rel->r_offset + ctx->base_load_paddr);
|
||||||
|
uint32_t type = ELF_R_TYPE(rel->r_info);
|
||||||
|
uint32_t sym = ELF_R_SYM(rel->r_info);
|
||||||
|
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case R_AARCH64_NONE:
|
||||||
|
EL_DEBUG("R_AARCH64_NONE\n");
|
||||||
|
break;
|
||||||
|
case R_AARCH64_RELATIVE:
|
||||||
|
if (sym)
|
||||||
|
{
|
||||||
|
EL_DEBUG("R_AARCH64_RELATIVE with symbol ref!\n");
|
||||||
|
return EL_BADREL;
|
||||||
|
}
|
||||||
|
|
||||||
|
EL_DEBUG("Applying R_AARCH64_RELATIVE reloc @%p\n", p);
|
||||||
|
*p += ctx->base_load_vaddr;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
EL_DEBUG("Bad relocation %u\n", type);
|
||||||
|
return EL_BADREL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return EL_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
66
source/libs/elfload/elfreloc_arm.c
Normal file
66
source/libs/elfload/elfreloc_arm.c
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
/*
|
||||||
|
* ----------------------------------------------------------------------------
|
||||||
|
* "THE BEER-WARE LICENSE" (Revision 42):
|
||||||
|
* <m4x@m4xw.net> wrote this file. As long as you retain this notice you can do
|
||||||
|
* whatever you want with this stuff. If we meet some day, and you think this
|
||||||
|
* stuff is worth it, you can buy me a beer in return. M4xw
|
||||||
|
* ----------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "elfload.h"
|
||||||
|
|
||||||
|
#if defined(__arm__)
|
||||||
|
|
||||||
|
// Taken from http://infocenter.arm.com/help/topic/com.arm.doc.ihi0044f/IHI0044F_aaelf.pdf
|
||||||
|
#define R_ARM_NONE 0
|
||||||
|
#define R_ARM_ABS32 2
|
||||||
|
#define R_ARM_JUMP_SLOT 22
|
||||||
|
#define R_ARM_GLOB_DAT 21
|
||||||
|
#define R_ARM_RELATIVE 23
|
||||||
|
|
||||||
|
el_status el_applyrel(el_ctx *ctx, Elf_Rel *rel)
|
||||||
|
{
|
||||||
|
uint32_t sym = ELF_R_SYM(rel->r_info); // Symbol offset
|
||||||
|
uint32_t type = ELF_R_TYPE(rel->r_info); // Relocation Type
|
||||||
|
uintptr_t *p = (uintptr_t *)(rel->r_offset + ctx->base_load_paddr); // Target Addr
|
||||||
|
|
||||||
|
#if 0 // For later symbol usage
|
||||||
|
Elf32_Sym *elfSym;
|
||||||
|
const char *symbolName;
|
||||||
|
|
||||||
|
// We resolve relocs from the originating elf-image
|
||||||
|
elfSym = (Elf32_Sym *)(ctx->symtab.sh_offset + (char *)buffteg) + sym;
|
||||||
|
int strtab_offset = ctx->shstr.sh_offset;
|
||||||
|
char *strtab = (char *)buffteg + strtab_offset;
|
||||||
|
symbolName = strtab + elfSym->st_name;
|
||||||
|
//EL_DEBUG("Str: %s sz: %x val: %x\n", symbolName, elfSym->st_size, elfSym->st_value);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case R_ARM_NONE:
|
||||||
|
EL_DEBUG("R_ARM_NONE\n");
|
||||||
|
break;
|
||||||
|
case R_ARM_JUMP_SLOT:
|
||||||
|
case R_ARM_ABS32:
|
||||||
|
case R_ARM_GLOB_DAT:
|
||||||
|
// Stubbed for later purpose
|
||||||
|
//*p += elfSym->st_value; // + vaddr from sec
|
||||||
|
//*p |= 0; // 1 if Thumb && STT_FUNC, ignored for now
|
||||||
|
break;
|
||||||
|
case R_ARM_RELATIVE: // Needed for PIE
|
||||||
|
if (sym)
|
||||||
|
{
|
||||||
|
return EL_BADREL;
|
||||||
|
}
|
||||||
|
*p += ctx->base_load_vaddr;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return EL_BADREL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return EL_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -24,14 +24,15 @@
|
|||||||
/*-----------------------------------------------------------------------*/
|
/*-----------------------------------------------------------------------*/
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "../../../common/memory_map.h"
|
||||||
|
|
||||||
#include "diskio.h" /* FatFs lower layer API */
|
#include "diskio.h" /* FatFs lower layer API */
|
||||||
#include "../../mem/heap.h"
|
#include "../../mem/heap.h"
|
||||||
#include "../../sec/se.h"
|
#include "../../sec/se.h"
|
||||||
#include "../../storage/nx_emmc.h"
|
#include "../../storage/nx_emmc.h"
|
||||||
#include "../../storage/sdmmc.h"
|
#include "../../storage/sdmmc.h"
|
||||||
|
#include "../../storage/emummc.h"
|
||||||
#define SDMMC_UPPER_BUFFER 0xB8000000
|
|
||||||
#define DRAM_START 0x80000000
|
|
||||||
|
|
||||||
extern sdmmc_storage_t sd_storage;
|
extern sdmmc_storage_t sd_storage;
|
||||||
extern sdmmc_storage_t storage;
|
extern sdmmc_storage_t storage;
|
||||||
@@ -42,11 +43,13 @@ typedef struct {
|
|||||||
u32 visit_count;
|
u32 visit_count;
|
||||||
u8 tweak[0x10];
|
u8 tweak[0x10];
|
||||||
u8 cached_sector[0x200];
|
u8 cached_sector[0x200];
|
||||||
|
u8 align[8];
|
||||||
} sector_cache_t;
|
} sector_cache_t;
|
||||||
|
|
||||||
#define MAX_SEC_CACHE_ENTRIES 64
|
#define MAX_SEC_CACHE_ENTRIES 64
|
||||||
static sector_cache_t *sector_cache = (sector_cache_t*)0x40020000;
|
static sector_cache_t *sector_cache = NULL;
|
||||||
static u32 secindex = 0;
|
static u32 secindex = 0;
|
||||||
|
bool clear_sector_cache = false;
|
||||||
|
|
||||||
DSTATUS disk_status (
|
DSTATUS disk_status (
|
||||||
BYTE pdrv /* Physical drive number to identify the drive */
|
BYTE pdrv /* Physical drive number to identify the drive */
|
||||||
@@ -105,7 +108,7 @@ static inline int _emmc_xts(u32 ks1, u32 ks2, u32 enc, u8 *tweak, bool regen_twe
|
|||||||
pdst += 0x10;
|
pdst += 0x10;
|
||||||
}
|
}
|
||||||
|
|
||||||
se_aes_crypt_ecb(ks2, 0, dst, secsize, src, secsize);
|
se_aes_crypt_ecb(ks2, enc, dst, secsize, src, secsize);
|
||||||
|
|
||||||
pdst = (u8 *)dst;
|
pdst = (u8 *)dst;
|
||||||
|
|
||||||
@@ -134,14 +137,28 @@ DRESULT disk_read (
|
|||||||
switch (pdrv)
|
switch (pdrv)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
|
if (((u32)buff >= DRAM_START) && !((u32)buff % 8))
|
||||||
return sdmmc_storage_read(&sd_storage, sector, count, buff) ? RES_OK : RES_ERROR;
|
return sdmmc_storage_read(&sd_storage, sector, count, buff) ? RES_OK : RES_ERROR;
|
||||||
|
u8 *buf = (u8 *)SDMMC_UPPER_BUFFER;
|
||||||
|
if (sdmmc_storage_read(&sd_storage, sector, count, buf))
|
||||||
|
{
|
||||||
|
memcpy(buff, buf, 512 * count);
|
||||||
|
return RES_OK;
|
||||||
|
}
|
||||||
|
return RES_ERROR;
|
||||||
|
|
||||||
case 1:;
|
case 1:;
|
||||||
__attribute__ ((aligned (16))) static u8 tweak[0x10];
|
__attribute__ ((aligned (16))) static u8 tweak[0x10];
|
||||||
__attribute__ ((aligned (16))) static u64 prev_cluster = -1;
|
__attribute__ ((aligned (16))) static u64 prev_cluster = -1;
|
||||||
__attribute__ ((aligned (16))) static u32 prev_sector = 0;
|
__attribute__ ((aligned (16))) static u32 prev_sector = 0;
|
||||||
u32 tweak_exp = 0;
|
//bool needs_cache_sector = false;
|
||||||
bool regen_tweak = true, cache_sector = false;
|
/*
|
||||||
|
if (secindex == 0 || clear_sector_cache) {
|
||||||
|
if (!sector_cache)
|
||||||
|
sector_cache = (sector_cache_t *)malloc(sizeof(sector_cache_t) * MAX_SEC_CACHE_ENTRIES);
|
||||||
|
clear_sector_cache = false;
|
||||||
|
secindex = 0;
|
||||||
|
}
|
||||||
|
|
||||||
u32 s = 0;
|
u32 s = 0;
|
||||||
if (count == 1) {
|
if (count == 1) {
|
||||||
@@ -159,12 +176,15 @@ DRESULT disk_read (
|
|||||||
if (s == secindex && s < MAX_SEC_CACHE_ENTRIES) {
|
if (s == secindex && s < MAX_SEC_CACHE_ENTRIES) {
|
||||||
sector_cache[s].sector = sector;
|
sector_cache[s].sector = sector;
|
||||||
sector_cache[s].visit_count++;
|
sector_cache[s].visit_count++;
|
||||||
cache_sector = true;
|
needs_cache_sector = true;
|
||||||
secindex++;
|
secindex++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
//system_part (pdrv == 1) ? system_part_sys : system_part_usr
|
||||||
if (nx_emmc_part_read(&storage, system_part, sector, count, buff)) {
|
if (nx_emmc_part_read(&storage, system_part, sector, count, buff)) {
|
||||||
|
u32 tweak_exp = 0;
|
||||||
|
bool regen_tweak = true;
|
||||||
if (prev_cluster != sector / 0x20) { // sector in different cluster than last read
|
if (prev_cluster != sector / 0x20) { // sector in different cluster than last read
|
||||||
prev_cluster = sector / 0x20;
|
prev_cluster = sector / 0x20;
|
||||||
tweak_exp = sector % 0x20;
|
tweak_exp = sector % 0x20;
|
||||||
@@ -177,10 +197,12 @@ DRESULT disk_read (
|
|||||||
|
|
||||||
// fatfs will never pull more than a cluster
|
// fatfs will never pull more than a cluster
|
||||||
_emmc_xts(9, 8, 0, tweak, regen_tweak, tweak_exp, prev_cluster, buff, buff, count * 0x200);
|
_emmc_xts(9, 8, 0, tweak, regen_tweak, tweak_exp, prev_cluster, buff, buff, count * 0x200);
|
||||||
if (cache_sector) {
|
/*
|
||||||
|
if (needs_cache_sector) {
|
||||||
memcpy(sector_cache[s].cached_sector, buff, 0x200);
|
memcpy(sector_cache[s].cached_sector, buff, 0x200);
|
||||||
memcpy(sector_cache[s].tweak, tweak, 0x10);
|
memcpy(sector_cache[s].tweak, tweak, 0x10);
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
prev_sector = sector + count - 1;
|
prev_sector = sector + count - 1;
|
||||||
return RES_OK;
|
return RES_OK;
|
||||||
}
|
}
|
||||||
@@ -191,14 +213,47 @@ DRESULT disk_read (
|
|||||||
|
|
||||||
DRESULT disk_write (
|
DRESULT disk_write (
|
||||||
BYTE pdrv, /* Physical drive number to identify the drive */
|
BYTE pdrv, /* Physical drive number to identify the drive */
|
||||||
const BYTE *buff, /* Data to be written */
|
BYTE *buff, /* Data to be written */
|
||||||
DWORD sector, /* Start sector in LBA */
|
DWORD sector, /* Start sector in LBA */
|
||||||
UINT count /* Number of sectors to write */
|
UINT count /* Number of sectors to write */
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
if (pdrv == 1)
|
switch (pdrv){
|
||||||
return RES_WRPRT;
|
case 0:
|
||||||
|
if (((u32)buff >= DRAM_START) && !((u32)buff % 8))
|
||||||
return sdmmc_storage_write(&sd_storage, sector, count, (void *)buff) ? RES_OK : RES_ERROR;
|
return sdmmc_storage_write(&sd_storage, sector, count, (void *)buff) ? RES_OK : RES_ERROR;
|
||||||
|
u8 *buf = (u8 *)SDMMC_UPPER_BUFFER; //TODO: define this somewhere.
|
||||||
|
memcpy(buf, buff, 512 * count);
|
||||||
|
if (sdmmc_storage_write(&sd_storage, sector, count, buf))
|
||||||
|
return RES_OK;
|
||||||
|
return RES_ERROR;
|
||||||
|
case 1:;
|
||||||
|
__attribute__ ((aligned (16))) static u8 tweak[0x10];
|
||||||
|
__attribute__ ((aligned (16))) static u64 prev_cluster = -1;
|
||||||
|
__attribute__ ((aligned (16))) static u32 prev_sector = 0;
|
||||||
|
u32 tweak_exp = 0;
|
||||||
|
bool regen_tweak = true;
|
||||||
|
|
||||||
|
if (prev_cluster != sector / 0x20) { // sector in different cluster than last read
|
||||||
|
prev_cluster = sector / 0x20;
|
||||||
|
tweak_exp = sector % 0x20;
|
||||||
|
} else if (sector > prev_sector) { // sector in same cluster and past last sector
|
||||||
|
tweak_exp = sector - prev_sector - 1;
|
||||||
|
regen_tweak = false;
|
||||||
|
} else { // sector in same cluster and before or same as last sector
|
||||||
|
tweak_exp = sector % 0x20;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_emmc_xts(9, 8, 1, tweak, regen_tweak, tweak_exp, prev_cluster, buff, buff, count * 0x200)){
|
||||||
|
if (nx_emmc_part_write(&storage, system_part, sector, count, buff)){
|
||||||
|
prev_sector = sector + count - 1;
|
||||||
|
return RES_OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return RES_ERROR;
|
||||||
|
}
|
||||||
|
return RES_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
DRESULT disk_ioctl (
|
DRESULT disk_ioctl (
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ typedef enum {
|
|||||||
DSTATUS disk_initialize (BYTE pdrv);
|
DSTATUS disk_initialize (BYTE pdrv);
|
||||||
DSTATUS disk_status (BYTE pdrv);
|
DSTATUS disk_status (BYTE pdrv);
|
||||||
DRESULT disk_read (BYTE pdrv, BYTE* buff, DWORD sector, UINT count);
|
DRESULT disk_read (BYTE pdrv, BYTE* buff, DWORD sector, UINT count);
|
||||||
DRESULT disk_write (BYTE pdrv, const BYTE* buff, DWORD sector, UINT count);
|
DRESULT disk_write (BYTE pdrv, BYTE* buff, DWORD sector, UINT count);
|
||||||
DRESULT disk_ioctl (BYTE pdrv, BYTE cmd, void* buff);
|
DRESULT disk_ioctl (BYTE pdrv, BYTE cmd, void* buff);
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,25 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2018 naehrwert
|
||||||
|
* Copyright (c) 2018-2019 CTCaer
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
/*----------------------------------------------------------------------------/
|
/*----------------------------------------------------------------------------/
|
||||||
/ FatFs - Generic FAT Filesystem Module R0.13c (p3) /
|
/ FatFs - Generic FAT Filesystem Module R0.13c (p4) /
|
||||||
/-----------------------------------------------------------------------------/
|
/-----------------------------------------------------------------------------/
|
||||||
/
|
/
|
||||||
/ Copyright (C) 2018, ChaN, all right reserved.
|
/ Copyright (C) 2018, ChaN, all right reserved.
|
||||||
/ Copyright (c) 2018 naehrwert
|
|
||||||
/ Copyright (C) 2018-2019 CTCaer
|
|
||||||
/
|
/
|
||||||
/ FatFs module is an open source software. Redistribution and use of FatFs in
|
/ FatFs module is an open source software. Redistribution and use of FatFs in
|
||||||
/ source and binary forms, with or without modification, are permitted provided
|
/ source and binary forms, with or without modification, are permitted provided
|
||||||
@@ -24,6 +39,8 @@
|
|||||||
#include "ff.h" /* Declarations of FatFs API */
|
#include "ff.h" /* Declarations of FatFs API */
|
||||||
#include "diskio.h" /* Declarations of device I/O functions */
|
#include "diskio.h" /* Declarations of device I/O functions */
|
||||||
#include "../../gfx/gfx.h"
|
#include "../../gfx/gfx.h"
|
||||||
|
#include "../../storage/sdmmc.h"
|
||||||
|
extern sdmmc_storage_t sd_storage;
|
||||||
|
|
||||||
#define EFSPRINTF(text, ...) print_error(); gfx_printf("%k"text"%k\n", 0xFFFFFF00, 0xFFFFFFFF);
|
#define EFSPRINTF(text, ...) print_error(); gfx_printf("%k"text"%k\n", 0xFFFFFF00, 0xFFFFFFFF);
|
||||||
//#define EFSPRINTF(...)
|
//#define EFSPRINTF(...)
|
||||||
@@ -33,6 +50,18 @@
|
|||||||
Module Private Definitions
|
Module Private Definitions
|
||||||
|
|
||||||
---------------------------------------------------------------------------*/
|
---------------------------------------------------------------------------*/
|
||||||
|
/*
|
||||||
|
PARTITION VolToPart[] = {
|
||||||
|
{0, 1},
|
||||||
|
{1, 8},
|
||||||
|
{1, 9}
|
||||||
|
};
|
||||||
|
*/
|
||||||
|
|
||||||
|
PARTITION VolToPart[] = {
|
||||||
|
{0, 1},
|
||||||
|
{1, 0}
|
||||||
|
};
|
||||||
|
|
||||||
#if FF_DEFINED != 86604 /* Revision ID */
|
#if FF_DEFINED != 86604 /* Revision ID */
|
||||||
#error Wrong include file (ff.h).
|
#error Wrong include file (ff.h).
|
||||||
@@ -3472,7 +3501,7 @@ static FRESULT find_volume ( /* FR_OK(0): successful, !=0: an error occurred */
|
|||||||
#if FF_USE_LFN == 1
|
#if FF_USE_LFN == 1
|
||||||
fs->lfnbuf = LfnBuf; /* Static LFN working buffer */
|
fs->lfnbuf = LfnBuf; /* Static LFN working buffer */
|
||||||
#if FF_FS_EXFAT
|
#if FF_FS_EXFAT
|
||||||
fs->dirbuf = DirBuf; /* Static directory block scratchpad buuffer */
|
fs->dirbuf = DirBuf; /* Static directory block scratchpad buffer */
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
#if FF_FS_RPATH != 0
|
#if FF_FS_RPATH != 0
|
||||||
@@ -4243,9 +4272,9 @@ FRESULT f_getcwd (
|
|||||||
TCHAR *tp = buff;
|
TCHAR *tp = buff;
|
||||||
#if FF_VOLUMES >= 2
|
#if FF_VOLUMES >= 2
|
||||||
UINT vl;
|
UINT vl;
|
||||||
#endif
|
|
||||||
#if FF_STR_VOLUME_ID
|
#if FF_STR_VOLUME_ID
|
||||||
const char *vp;
|
const char *vp;
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
FILINFO fno;
|
FILINFO fno;
|
||||||
DEF_NAMBUF
|
DEF_NAMBUF
|
||||||
@@ -4726,7 +4755,7 @@ FRESULT f_getfree (
|
|||||||
/* Get logical drive */
|
/* Get logical drive */
|
||||||
res = find_volume(&path, &fs, 0);
|
res = find_volume(&path, &fs, 0);
|
||||||
if (res == FR_OK) {
|
if (res == FR_OK) {
|
||||||
*fatfs = fs; /* Return ptr to the fs object */
|
if (fatfs) *fatfs = fs; /* Return ptr to the fs object */
|
||||||
/* If free_clst is valid, return it without full FAT scan */
|
/* If free_clst is valid, return it without full FAT scan */
|
||||||
if (fs->free_clst <= fs->n_fatent - 2) {
|
if (fs->free_clst <= fs->n_fatent - 2) {
|
||||||
*nclst = fs->free_clst;
|
*nclst = fs->free_clst;
|
||||||
@@ -6024,7 +6053,7 @@ FRESULT f_mkfs (
|
|||||||
sys = 0x07; /* HPFS/NTFS/exFAT */
|
sys = 0x07; /* HPFS/NTFS/exFAT */
|
||||||
} else {
|
} else {
|
||||||
if (fmt == FS_FAT32) {
|
if (fmt == FS_FAT32) {
|
||||||
sys = 0x0C; /* FAT32X */
|
sys = 0x0B; /* FAT32X */
|
||||||
} else {
|
} else {
|
||||||
if (sz_vol >= 0x10000) {
|
if (sz_vol >= 0x10000) {
|
||||||
sys = 0x06; /* FAT12/16 (large) */
|
sys = 0x06; /* FAT12/16 (large) */
|
||||||
@@ -6078,17 +6107,19 @@ FRESULT f_fdisk (
|
|||||||
void* work /* Pointer to the working buffer (null: use heap memory) */
|
void* work /* Pointer to the working buffer (null: use heap memory) */
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
UINT i, n, sz_cyl, tot_cyl, b_cyl, e_cyl, p_cyl;
|
UINT i, n, sz_cyl, tot_cyl, e_cyl;
|
||||||
BYTE s_hd, e_hd, *p, *buf = (BYTE*)work;
|
BYTE s_hd, e_hd, *p, *buf = (BYTE*)work;
|
||||||
DSTATUS stat;
|
DSTATUS stat;
|
||||||
DWORD sz_disk, sz_part, s_part;
|
DWORD sz_disk, p_sect, b_cyl, b_sect;
|
||||||
FRESULT res;
|
FRESULT res;
|
||||||
|
|
||||||
|
BYTE *empty_buff;
|
||||||
|
empty_buff = ff_memcalloc(sizeof(BYTE), 16384);
|
||||||
|
|
||||||
stat = disk_initialize(pdrv);
|
stat = disk_initialize(pdrv);
|
||||||
if (stat & STA_NOINIT) return FR_NOT_READY;
|
if (stat & STA_NOINIT) return FR_NOT_READY;
|
||||||
if (stat & STA_PROTECT) return FR_WRITE_PROTECTED;
|
if (stat & STA_PROTECT) return FR_WRITE_PROTECTED;
|
||||||
if (disk_ioctl(pdrv, GET_SECTOR_COUNT, &sz_disk)) return FR_DISK_ERR;
|
sz_disk = sd_storage.csd.capacity;
|
||||||
|
|
||||||
buf = (BYTE*)work;
|
buf = (BYTE*)work;
|
||||||
#if FF_USE_LFN == 3
|
#if FF_USE_LFN == 3
|
||||||
@@ -6105,20 +6136,26 @@ FRESULT f_fdisk (
|
|||||||
|
|
||||||
/* Create partition table */
|
/* Create partition table */
|
||||||
mem_set(buf, 0, FF_MAX_SS);
|
mem_set(buf, 0, FF_MAX_SS);
|
||||||
p = buf + MBR_Table; b_cyl = 0;
|
p = buf + MBR_Table; b_cyl = 0, b_sect = 0;
|
||||||
for (i = 0; i < 4; i++, p += SZ_PTE) {
|
for (i = 0; i < 4; i++, p += SZ_PTE) {
|
||||||
p_cyl = (szt[i] <= 100U) ? (DWORD)tot_cyl * szt[i] / 100 : szt[i] / sz_cyl; /* Number of cylinders */
|
p_sect = szt[i]; /* Number of sectors */
|
||||||
if (p_cyl == 0) continue;
|
|
||||||
s_part = (DWORD)sz_cyl * b_cyl;
|
if (p_sect == 0)
|
||||||
sz_part = (DWORD)sz_cyl * p_cyl;
|
continue;
|
||||||
if (i == 0) { /* Exclude first track of cylinder 0 */
|
|
||||||
|
if (i == 0) { /* Exclude first 16MiB of sd */
|
||||||
s_hd = 1;
|
s_hd = 1;
|
||||||
s_part += 63; sz_part -= 63;
|
b_sect += 32768; p_sect -= 32768;
|
||||||
} else {
|
|
||||||
s_hd = 0;
|
|
||||||
}
|
}
|
||||||
e_cyl = b_cyl + p_cyl - 1; /* End cylinder */
|
else
|
||||||
if (e_cyl >= tot_cyl) LEAVE_MKFS(FR_INVALID_PARAMETER);
|
s_hd = 0;
|
||||||
|
|
||||||
|
b_cyl = b_sect / sz_cyl;
|
||||||
|
e_cyl = ((b_sect + p_sect) / sz_cyl) - 1; /* End cylinder */
|
||||||
|
|
||||||
|
if (e_cyl >= tot_cyl)
|
||||||
|
LEAVE_MKFS(FR_INVALID_PARAMETER);
|
||||||
|
|
||||||
|
|
||||||
/* Set partition table */
|
/* Set partition table */
|
||||||
p[1] = s_hd; /* Start head */
|
p[1] = s_hd; /* Start head */
|
||||||
@@ -6128,13 +6165,17 @@ FRESULT f_fdisk (
|
|||||||
p[5] = e_hd; /* End head */
|
p[5] = e_hd; /* End head */
|
||||||
p[6] = (BYTE)(((e_cyl >> 2) & 0xC0) | 63); /* End sector */
|
p[6] = (BYTE)(((e_cyl >> 2) & 0xC0) | 63); /* End sector */
|
||||||
p[7] = (BYTE)e_cyl; /* End cylinder */
|
p[7] = (BYTE)e_cyl; /* End cylinder */
|
||||||
st_dword(p + 8, s_part); /* Start sector in LBA */
|
st_dword(p + 8, b_sect); /* Start sector in LBA */
|
||||||
st_dword(p + 12, sz_part); /* Number of sectors */
|
st_dword(p + 12, p_sect); /* Number of sectors */
|
||||||
|
|
||||||
/* Next partition */
|
/* Next partition */
|
||||||
b_cyl += p_cyl;
|
b_sect += p_sect;
|
||||||
|
|
||||||
|
for (int cursect = 0; cursect < 1024; cursect++){
|
||||||
|
disk_write(pdrv, empty_buff, b_sect + (32 * cursect), 32);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
st_word(p, 0xAA55); /* MBR signature (always at offset 510) */
|
st_word(p, 0xAA55); /* MBR signature (always at offset 510) */
|
||||||
|
ff_memfree(empty_buff);
|
||||||
|
|
||||||
/* Write it to the MBR */
|
/* Write it to the MBR */
|
||||||
res = (disk_write(pdrv, buf, 0, 1) == RES_OK && disk_ioctl(pdrv, CTRL_SYNC, 0) == RES_OK) ? FR_OK : FR_DISK_ERR;
|
res = (disk_write(pdrv, buf, 0, 1) == RES_OK && disk_ioctl(pdrv, CTRL_SYNC, 0) == RES_OK) ? FR_OK : FR_DISK_ERR;
|
||||||
@@ -6632,4 +6673,3 @@ FRESULT f_setcp (
|
|||||||
return FR_OK;
|
return FR_OK;
|
||||||
}
|
}
|
||||||
#endif /* FF_CODE_PAGE == 0 */
|
#endif /* FF_CODE_PAGE == 0 */
|
||||||
|
|
||||||
|
|||||||
@@ -95,6 +95,7 @@ typedef DWORD FSIZE_t;
|
|||||||
/* Filesystem object structure (FATFS) */
|
/* Filesystem object structure (FATFS) */
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
BYTE win[FF_MAX_SS]; /* Disk access window for Directory, FAT (and file data at tiny cfg) */
|
||||||
BYTE fs_type; /* Filesystem type (0:not mounted) */
|
BYTE fs_type; /* Filesystem type (0:not mounted) */
|
||||||
BYTE pdrv; /* Associated physical drive */
|
BYTE pdrv; /* Associated physical drive */
|
||||||
BYTE n_fats; /* Number of FATs (1 or 2) */
|
BYTE n_fats; /* Number of FATs (1 or 2) */
|
||||||
@@ -137,8 +138,6 @@ typedef struct {
|
|||||||
DWORD bitbase; /* Allocation bitmap base sector */
|
DWORD bitbase; /* Allocation bitmap base sector */
|
||||||
#endif
|
#endif
|
||||||
DWORD winsect; /* Current sector appearing in the win[] */
|
DWORD winsect; /* Current sector appearing in the win[] */
|
||||||
DWORD padding; /* Ensure window is 16-aligned */
|
|
||||||
BYTE win[FF_MAX_SS]; /* Disk access window for Directory, FAT (and file data at tiny cfg) */
|
|
||||||
} FATFS;
|
} FATFS;
|
||||||
|
|
||||||
|
|
||||||
@@ -169,6 +168,9 @@ typedef struct {
|
|||||||
/* File object structure (FIL) */
|
/* File object structure (FIL) */
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
#if !FF_FS_TINY
|
||||||
|
BYTE buf[FF_MAX_SS]; /* File private data read/write window */
|
||||||
|
#endif
|
||||||
FFOBJID obj; /* Object identifier (must be the 1st member to detect invalid object pointer) */
|
FFOBJID obj; /* Object identifier (must be the 1st member to detect invalid object pointer) */
|
||||||
BYTE flag; /* File status flags */
|
BYTE flag; /* File status flags */
|
||||||
BYTE err; /* Abort flag (error code) */
|
BYTE err; /* Abort flag (error code) */
|
||||||
@@ -179,9 +181,6 @@ typedef struct {
|
|||||||
DWORD dir_sect; /* Sector number containing the directory entry (not used at exFAT) */
|
DWORD dir_sect; /* Sector number containing the directory entry (not used at exFAT) */
|
||||||
BYTE* dir_ptr; /* Pointer to the directory entry in the win[] (not used at exFAT) */
|
BYTE* dir_ptr; /* Pointer to the directory entry in the win[] (not used at exFAT) */
|
||||||
#endif
|
#endif
|
||||||
#if !FF_FS_TINY
|
|
||||||
BYTE buf[FF_MAX_SS]; /* File private data read/write window */
|
|
||||||
#endif
|
|
||||||
#if FF_USE_FASTSEEK
|
#if FF_USE_FASTSEEK
|
||||||
DWORD* cltbl; /* Pointer to the cluster link map table (nulled on open, set by application) */
|
DWORD* cltbl; /* Pointer to the cluster link map table (nulled on open, set by application) */
|
||||||
#endif
|
#endif
|
||||||
@@ -280,7 +279,7 @@ FRESULT f_getfree (const TCHAR* path, DWORD* nclst, FATFS** fatfs); /* Get numbe
|
|||||||
FRESULT f_getlabel (const TCHAR* path, TCHAR* label, DWORD* vsn); /* Get volume label */
|
FRESULT f_getlabel (const TCHAR* path, TCHAR* label, DWORD* vsn); /* Get volume label */
|
||||||
FRESULT f_setlabel (const TCHAR* label); /* Set volume label */
|
FRESULT f_setlabel (const TCHAR* label); /* Set volume label */
|
||||||
FRESULT f_forward (FIL* fp, UINT(*func)(const BYTE*,UINT), UINT btf, UINT* bf); /* Forward data to the stream */
|
FRESULT f_forward (FIL* fp, UINT(*func)(const BYTE*,UINT), UINT btf, UINT* bf); /* Forward data to the stream */
|
||||||
FRESULT f_expand (FIL* fp, FSIZE_t szf, BYTE opt); /* Allocate a contiguous block to the file */
|
FRESULT f_expand (FIL* fp, FSIZE_t fsz, BYTE opt); /* Allocate a contiguous block to the file */
|
||||||
FRESULT f_mount (FATFS* fs, const TCHAR* path, BYTE opt); /* Mount/Unmount a logical drive */
|
FRESULT f_mount (FATFS* fs, const TCHAR* path, BYTE opt); /* Mount/Unmount a logical drive */
|
||||||
FRESULT f_mkfs (const TCHAR* path, BYTE opt, DWORD au, void* work, UINT len); /* Create a FAT volume */
|
FRESULT f_mkfs (const TCHAR* path, BYTE opt, DWORD au, void* work, UINT len); /* Create a FAT volume */
|
||||||
FRESULT f_fdisk (BYTE pdrv, const DWORD* szt, void* work); /* Divide a physical drive into some partitions */
|
FRESULT f_fdisk (BYTE pdrv, const DWORD* szt, void* work); /* Divide a physical drive into some partitions */
|
||||||
@@ -322,6 +321,7 @@ DWORD ff_wtoupper (DWORD uni); /* Unicode upper-case conversion */
|
|||||||
#endif
|
#endif
|
||||||
#if FF_USE_LFN == 3 /* Dynamic memory allocation */
|
#if FF_USE_LFN == 3 /* Dynamic memory allocation */
|
||||||
void* ff_memalloc (UINT msize); /* Allocate memory block */
|
void* ff_memalloc (UINT msize); /* Allocate memory block */
|
||||||
|
void* ff_memcalloc (UINT msize, UINT amount);
|
||||||
void ff_memfree (void* mblock); /* Free memory block */
|
void ff_memfree (void* mblock); /* Free memory block */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -25,7 +25,7 @@
|
|||||||
/ 3: f_lseek() function is removed in addition to 2. */
|
/ 3: f_lseek() function is removed in addition to 2. */
|
||||||
|
|
||||||
|
|
||||||
#define FF_USE_STRFUNC 0
|
#define FF_USE_STRFUNC 2
|
||||||
/* This option switches string functions, f_gets(), f_putc(), f_puts() and f_printf().
|
/* This option switches string functions, f_gets(), f_putc(), f_puts() and f_printf().
|
||||||
/
|
/
|
||||||
/ 0: Disable string functions.
|
/ 0: Disable string functions.
|
||||||
@@ -33,12 +33,12 @@
|
|||||||
/ 2: Enable with LF-CRLF conversion. */
|
/ 2: Enable with LF-CRLF conversion. */
|
||||||
|
|
||||||
|
|
||||||
#define FF_USE_FIND 0
|
#define FF_USE_FIND 1
|
||||||
/* This option switches filtered directory read functions, f_findfirst() and
|
/* This option switches filtered directory read functions, f_findfirst() and
|
||||||
/ f_findnext(). (0:Disable, 1:Enable 2:Enable with matching altname[] too) */
|
/ f_findnext(). (0:Disable, 1:Enable 2:Enable with matching altname[] too) */
|
||||||
|
|
||||||
|
|
||||||
#define FF_USE_MKFS 0
|
#define FF_USE_MKFS 1
|
||||||
/* This option switches f_mkfs() function. (0:Disable or 1:Enable) */
|
/* This option switches f_mkfs() function. (0:Disable or 1:Enable) */
|
||||||
|
|
||||||
|
|
||||||
@@ -50,7 +50,7 @@
|
|||||||
/* This option switches f_expand function. (0:Disable or 1:Enable) */
|
/* This option switches f_expand function. (0:Disable or 1:Enable) */
|
||||||
|
|
||||||
|
|
||||||
#define FF_USE_CHMOD 0
|
#define FF_USE_CHMOD 1
|
||||||
/* This option switches attribute manipulation functions, f_chmod() and f_utime().
|
/* This option switches attribute manipulation functions, f_chmod() and f_utime().
|
||||||
/ (0:Disable or 1:Enable) Also FF_FS_READONLY needs to be 0 to enable this option. */
|
/ (0:Disable or 1:Enable) Also FF_FS_READONLY needs to be 0 to enable this option. */
|
||||||
|
|
||||||
@@ -97,7 +97,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#define FF_USE_LFN 1
|
#define FF_USE_LFN 3
|
||||||
#define FF_MAX_LFN 255
|
#define FF_MAX_LFN 255
|
||||||
/* The FF_USE_LFN switches the support for LFN (long file name).
|
/* The FF_USE_LFN switches the support for LFN (long file name).
|
||||||
/
|
/
|
||||||
@@ -169,6 +169,7 @@
|
|||||||
|
|
||||||
#define FF_STR_VOLUME_ID 1
|
#define FF_STR_VOLUME_ID 1
|
||||||
#define FF_VOLUME_STRS "sd", "emmc"
|
#define FF_VOLUME_STRS "sd", "emmc"
|
||||||
|
|
||||||
/* FF_STR_VOLUME_ID switches support for volume ID in arbitrary strings.
|
/* FF_STR_VOLUME_ID switches support for volume ID in arbitrary strings.
|
||||||
/ When FF_STR_VOLUME_ID is set to 1 or 2, arbitrary strings can be used as drive
|
/ When FF_STR_VOLUME_ID is set to 1 or 2, arbitrary strings can be used as drive
|
||||||
/ number in the path name. FF_VOLUME_STRS defines the volume ID strings for each
|
/ number in the path name. FF_VOLUME_STRS defines the volume ID strings for each
|
||||||
@@ -181,7 +182,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#define FF_MULTI_PARTITION 0
|
#define FF_MULTI_PARTITION 1
|
||||||
/* This option switches support for multiple volumes on the physical drive.
|
/* This option switches support for multiple volumes on the physical drive.
|
||||||
/ By default (0), each logical drive number is bound to the same physical drive
|
/ By default (0), each logical drive number is bound to the same physical drive
|
||||||
/ number and only an FAT volume found on the physical drive will be mounted.
|
/ number and only an FAT volume found on the physical drive will be mounted.
|
||||||
@@ -191,7 +192,7 @@
|
|||||||
|
|
||||||
|
|
||||||
#define FF_MIN_SS 512
|
#define FF_MIN_SS 512
|
||||||
#define FF_MAX_SS 4096
|
#define FF_MAX_SS 512
|
||||||
/* This set of options configures the range of sector size to be supported. (512,
|
/* This set of options configures the range of sector size to be supported. (512,
|
||||||
/ 1024, 2048 or 4096) Always set both 512 for most systems, generic memory card and
|
/ 1024, 2048 or 4096) Always set both 512 for most systems, generic memory card and
|
||||||
/ harddisk. But a larger value may be required for on-board flash memory and some
|
/ harddisk. But a larger value may be required for on-board flash memory and some
|
||||||
|
|||||||
@@ -23,6 +23,10 @@ void* ff_memalloc ( /* Returns pointer to the allocated memory block (null if no
|
|||||||
return malloc(msize); /* Allocate a new memory block with POSIX API */
|
return malloc(msize); /* Allocate a new memory block with POSIX API */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void* ff_memcalloc (UINT msize, UINT amount){
|
||||||
|
return calloc(amount, msize);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*------------------------------------------------------------------------*/
|
/*------------------------------------------------------------------------*/
|
||||||
/* Free a memory block */
|
/* Free a memory block */
|
||||||
|
|||||||
@@ -34,7 +34,6 @@
|
|||||||
#define MERGE2(a, b) a ## b
|
#define MERGE2(a, b) a ## b
|
||||||
#define CVTBL(tbl, cp) MERGE2(tbl, cp)
|
#define CVTBL(tbl, cp) MERGE2(tbl, cp)
|
||||||
|
|
||||||
|
|
||||||
/*------------------------------------------------------------------------*/
|
/*------------------------------------------------------------------------*/
|
||||||
/* Code Conversion Tables */
|
/* Code Conversion Tables */
|
||||||
/*------------------------------------------------------------------------*/
|
/*------------------------------------------------------------------------*/
|
||||||
@@ -623,5 +622,4 @@ DWORD ff_wtoupper ( /* Returns up-converted code point */
|
|||||||
return uni;
|
return uni;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#endif /* #if FF_USE_LFN */
|
#endif /* #if FF_USE_LFN */
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ SECTIONS {
|
|||||||
.text : {
|
.text : {
|
||||||
*(.text._start);
|
*(.text._start);
|
||||||
*(._boot_cfg);
|
*(._boot_cfg);
|
||||||
|
*(.text._irq_setup);
|
||||||
*(.text*);
|
*(.text*);
|
||||||
}
|
}
|
||||||
.data : {
|
.data : {
|
||||||
|
|||||||
374
source/main.c
374
source/main.c
@@ -18,28 +18,41 @@
|
|||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "config/config.h"
|
||||||
|
#include "config/ini.h"
|
||||||
#include "gfx/di.h"
|
#include "gfx/di.h"
|
||||||
#include "gfx/gfx.h"
|
#include "gfx/gfx.h"
|
||||||
|
#include "gfx/tui.h"
|
||||||
|
#include "hos/pkg1.h"
|
||||||
#include "libs/fatfs/ff.h"
|
#include "libs/fatfs/ff.h"
|
||||||
#include "mem/heap.h"
|
#include "mem/heap.h"
|
||||||
|
#include "mem/minerva.h"
|
||||||
#include "power/max77620.h"
|
#include "power/max77620.h"
|
||||||
#include "rtc/max77620-rtc.h"
|
#include "rtc/max77620-rtc.h"
|
||||||
|
#include "soc/bpmp.h"
|
||||||
#include "soc/hw_init.h"
|
#include "soc/hw_init.h"
|
||||||
|
#include "storage/emummc.h"
|
||||||
|
#include "storage/nx_emmc.h"
|
||||||
#include "storage/sdmmc.h"
|
#include "storage/sdmmc.h"
|
||||||
#include "utils/util.h"
|
|
||||||
#include "utils/btn.h"
|
#include "utils/btn.h"
|
||||||
#include "meme/main.h"
|
#include "utils/dirlist.h"
|
||||||
#include "meme/utils.h"
|
#include "utils/sprintf.h"
|
||||||
|
#include "utils/util.h"
|
||||||
|
#include "tegraexplorer/mainmenu.h"
|
||||||
|
#include "tegraexplorer/gfx/gfxutils.h"
|
||||||
|
#include "storage/nx_sd.h"
|
||||||
|
|
||||||
#include "keys/keys.h"
|
//#include "keys/keys.h"
|
||||||
|
|
||||||
sdmmc_t sd_sdmmc;
|
sdmmc_t sd_sdmmc;
|
||||||
sdmmc_storage_t sd_storage;
|
sdmmc_storage_t sd_storage;
|
||||||
__attribute__ ((aligned (16))) FATFS sd_fs;
|
__attribute__ ((aligned (16))) FATFS sd_fs;
|
||||||
static bool sd_mounted;
|
bool sd_mounted, sd_inited;
|
||||||
|
volatile nyx_storage_t *nyx_str = (nyx_storage_t *)NYX_STORAGE_ADDR;
|
||||||
|
hekate_config h_cfg;
|
||||||
boot_cfg_t __attribute__((section ("._boot_cfg"))) b_cfg;
|
boot_cfg_t __attribute__((section ("._boot_cfg"))) b_cfg;
|
||||||
|
|
||||||
|
/*
|
||||||
bool sd_mount()
|
bool sd_mount()
|
||||||
{
|
{
|
||||||
if (sd_mounted)
|
if (sd_mounted)
|
||||||
@@ -48,9 +61,11 @@ bool sd_mount()
|
|||||||
if (!sdmmc_storage_init_sd(&sd_storage, &sd_sdmmc, SDMMC_1, SDMMC_BUS_WIDTH_4, 11))
|
if (!sdmmc_storage_init_sd(&sd_storage, &sd_sdmmc, SDMMC_1, SDMMC_BUS_WIDTH_4, 11))
|
||||||
{
|
{
|
||||||
EPRINTF("Failed to init SD card.\nMake sure that it is inserted.\nOr that SD reader is properly seated!");
|
EPRINTF("Failed to init SD card.\nMake sure that it is inserted.\nOr that SD reader is properly seated!");
|
||||||
|
sd_inited = false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
sd_inited = true;
|
||||||
int res = 0;
|
int res = 0;
|
||||||
res = f_mount(&sd_fs, "sd:", 1);
|
res = f_mount(&sd_fs, "sd:", 1);
|
||||||
if (res == FR_OK)
|
if (res == FR_OK)
|
||||||
@@ -74,6 +89,7 @@ void sd_unmount()
|
|||||||
f_mount(NULL, "sd:", 1);
|
f_mount(NULL, "sd:", 1);
|
||||||
sdmmc_storage_end(&sd_storage);
|
sdmmc_storage_end(&sd_storage);
|
||||||
sd_mounted = false;
|
sd_mounted = false;
|
||||||
|
sd_inited = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -110,7 +126,7 @@ int sd_save_to_file(void *buf, u32 size, const char *filename)
|
|||||||
if (res)
|
if (res)
|
||||||
{
|
{
|
||||||
EPRINTFARGS("Error (%d) creating file\n%s.\n", res, filename);
|
EPRINTFARGS("Error (%d) creating file\n%s.\n", res, filename);
|
||||||
return 1;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
f_write(&fp, buf, size, NULL);
|
f_write(&fp, buf, size, NULL);
|
||||||
@@ -118,15 +134,20 @@ int sd_save_to_file(void *buf, u32 size, const char *filename)
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
// This is a safe and unused DRAM region for our payloads.
|
// This is a safe and unused DRAM region for our payloads.
|
||||||
#define RELOC_META_OFF 0x7C
|
#define RELOC_META_OFF 0x7C
|
||||||
#define PATCHED_RELOC_SZ 0x94
|
#define PATCHED_RELOC_SZ 0x94
|
||||||
#define PATCHED_RELOC_STACK 0x40007000
|
#define PATCHED_RELOC_STACK 0x40007000
|
||||||
#define COREBOOT_ADDR (0xD0000000 - 0x100000)
|
#define PATCHED_RELOC_ENTRY 0x40010000
|
||||||
|
#define EXT_PAYLOAD_ADDR 0xC0000000
|
||||||
|
#define RCM_PAYLOAD_ADDR (EXT_PAYLOAD_ADDR + ALIGN(PATCHED_RELOC_SZ, 0x10))
|
||||||
|
#define COREBOOT_END_ADDR 0xD0000000
|
||||||
#define CBFS_DRAM_EN_ADDR 0x4003e000
|
#define CBFS_DRAM_EN_ADDR 0x4003e000
|
||||||
#define CBFS_DRAM_MAGIC 0x4452414D // "DRAM"
|
#define CBFS_DRAM_MAGIC 0x4452414D // "DRAM"
|
||||||
|
|
||||||
|
static void *coreboot_addr;
|
||||||
|
|
||||||
void reloc_patcher(u32 payload_dst, u32 payload_src, u32 payload_size)
|
void reloc_patcher(u32 payload_dst, u32 payload_src, u32 payload_size)
|
||||||
{
|
{
|
||||||
@@ -141,31 +162,354 @@ void reloc_patcher(u32 payload_dst, u32 payload_src, u32 payload_size)
|
|||||||
|
|
||||||
if (payload_size == 0x7000)
|
if (payload_size == 0x7000)
|
||||||
{
|
{
|
||||||
memcpy((u8 *)(payload_src + ALIGN(PATCHED_RELOC_SZ, 0x10)), (u8 *)COREBOOT_ADDR, 0x7000); //Bootblock
|
memcpy((u8 *)(payload_src + ALIGN(PATCHED_RELOC_SZ, 0x10)), coreboot_addr, 0x7000); //Bootblock
|
||||||
*(vu32 *)CBFS_DRAM_EN_ADDR = CBFS_DRAM_MAGIC;
|
*(vu32 *)CBFS_DRAM_EN_ADDR = CBFS_DRAM_MAGIC;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#define IPL_STACK_TOP 0x4003F000
|
int launch_payload(char *path)
|
||||||
#define IPL_HEAP_START 0x90020000
|
{
|
||||||
|
gfx_clear_grey(0x1B);
|
||||||
|
gfx_con_setpos(0, 0);
|
||||||
|
if (!path)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if (sd_mount())
|
||||||
|
{
|
||||||
|
FIL fp;
|
||||||
|
if (f_open(&fp, path, FA_READ))
|
||||||
|
{
|
||||||
|
EPRINTFARGS("Payload file is missing!\n(%s)", path);
|
||||||
|
sd_unmount();
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read and copy the payload to our chosen address
|
||||||
|
void *buf;
|
||||||
|
u32 size = f_size(&fp);
|
||||||
|
|
||||||
|
if (size < 0x30000)
|
||||||
|
buf = (void *)RCM_PAYLOAD_ADDR;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
coreboot_addr = (void *)(COREBOOT_END_ADDR - size);
|
||||||
|
buf = coreboot_addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (f_read(&fp, buf, size, NULL))
|
||||||
|
{
|
||||||
|
f_close(&fp);
|
||||||
|
sd_unmount();
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
f_close(&fp);
|
||||||
|
|
||||||
|
sd_unmount();
|
||||||
|
|
||||||
|
if (size < 0x30000)
|
||||||
|
{
|
||||||
|
reloc_patcher(PATCHED_RELOC_ENTRY, EXT_PAYLOAD_ADDR, ALIGN(size, 0x10));
|
||||||
|
|
||||||
|
reconfig_hw_workaround(false, byte_swap_32(*(u32 *)(buf + size - sizeof(u32))));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
reloc_patcher(PATCHED_RELOC_ENTRY, EXT_PAYLOAD_ADDR, 0x7000);
|
||||||
|
reconfig_hw_workaround(true, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Some cards (Sandisk U1), do not like a fast power cycle. Wait min 100ms.
|
||||||
|
sdmmc_storage_init_wait_sd();
|
||||||
|
|
||||||
|
void (*ext_payload_ptr)() = (void *)EXT_PAYLOAD_ADDR;
|
||||||
|
|
||||||
|
// Launch our payload.
|
||||||
|
(*ext_payload_ptr)();
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
void launch_tools()
|
||||||
|
{
|
||||||
|
u8 max_entries = 61;
|
||||||
|
char *filelist = NULL;
|
||||||
|
char *file_sec = NULL;
|
||||||
|
char *dir = NULL;
|
||||||
|
|
||||||
|
ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * (max_entries + 3));
|
||||||
|
|
||||||
|
gfx_clear_grey(0x1B);
|
||||||
|
gfx_con_setpos(0, 0);
|
||||||
|
|
||||||
|
if (sd_mount())
|
||||||
|
{
|
||||||
|
dir = (char *)malloc(256);
|
||||||
|
|
||||||
|
memcpy(dir, "sd:/bootloader/payloads", 24);
|
||||||
|
|
||||||
|
filelist = dirlist(dir, NULL, false);
|
||||||
|
|
||||||
|
u32 i = 0;
|
||||||
|
u32 i_off = 2;
|
||||||
|
|
||||||
|
if (filelist)
|
||||||
|
{
|
||||||
|
// Build configuration menu.
|
||||||
|
u32 color_idx = 0;
|
||||||
|
|
||||||
|
ments[0].type = MENT_BACK;
|
||||||
|
ments[0].caption = "Back";
|
||||||
|
ments[0].color = colors[(color_idx++) % 6];
|
||||||
|
ments[1].type = MENT_CHGLINE;
|
||||||
|
ments[1].color = colors[(color_idx++) % 6];
|
||||||
|
if (!f_stat("sd:/atmosphere/reboot_payload.bin", NULL))
|
||||||
|
{
|
||||||
|
ments[i_off].type = INI_CHOICE;
|
||||||
|
ments[i_off].caption = "reboot_payload.bin";
|
||||||
|
ments[i_off].color = colors[(color_idx++) % 6];
|
||||||
|
ments[i_off].data = "sd:/atmosphere/reboot_payload.bin";
|
||||||
|
i_off++;
|
||||||
|
}
|
||||||
|
if (!f_stat("sd:/ReiNX.bin", NULL))
|
||||||
|
{
|
||||||
|
ments[i_off].type = INI_CHOICE;
|
||||||
|
ments[i_off].caption = "ReiNX.bin";
|
||||||
|
ments[i_off].color = colors[(color_idx++) % 6];
|
||||||
|
ments[i_off].data = "sd:/ReiNX.bin";
|
||||||
|
i_off++;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
if (i > max_entries || !filelist[i * 256])
|
||||||
|
break;
|
||||||
|
ments[i + i_off].type = INI_CHOICE;
|
||||||
|
ments[i + i_off].caption = &filelist[i * 256];
|
||||||
|
ments[i + i_off].color = colors[(color_idx++) % 6];
|
||||||
|
ments[i + i_off].data = &filelist[i * 256];
|
||||||
|
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i > 0)
|
||||||
|
{
|
||||||
|
memset(&ments[i + i_off], 0, sizeof(ment_t));
|
||||||
|
menu_t menu = { ments, "Choose a file to launch", 0, 0 };
|
||||||
|
|
||||||
|
file_sec = (char *)tui_do_menu(&menu);
|
||||||
|
|
||||||
|
if (!file_sec)
|
||||||
|
{
|
||||||
|
free(ments);
|
||||||
|
free(dir);
|
||||||
|
free(filelist);
|
||||||
|
sd_unmount();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
EPRINTF("No payloads or modules found.");
|
||||||
|
|
||||||
|
free(ments);
|
||||||
|
free(filelist);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
free(ments);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file_sec)
|
||||||
|
{
|
||||||
|
if (memcmp("sd:/", file_sec, 4)) {
|
||||||
|
memcpy(dir + strlen(dir), "/", 2);
|
||||||
|
memcpy(dir + strlen(dir), file_sec, strlen(file_sec) + 1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
memcpy(dir, file_sec, strlen(file_sec) + 1);
|
||||||
|
|
||||||
|
if (launch_payload(dir))
|
||||||
|
{
|
||||||
|
EPRINTF("Failed to launch payload.");
|
||||||
|
free(dir);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
sd_unmount();
|
||||||
|
free(dir);
|
||||||
|
|
||||||
|
btn_wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
void dump_sysnand()
|
||||||
|
{
|
||||||
|
h_cfg.emummc_force_disable = true;
|
||||||
|
b_cfg.extra_cfg &= ~EXTRA_CFG_DUMP_EMUMMC;
|
||||||
|
//dump_keys();
|
||||||
|
}
|
||||||
|
|
||||||
|
void dump_emunand()
|
||||||
|
{
|
||||||
|
if (h_cfg.emummc_force_disable)
|
||||||
|
return;
|
||||||
|
emu_cfg.enabled = 1;
|
||||||
|
b_cfg.extra_cfg |= EXTRA_CFG_DUMP_EMUMMC;
|
||||||
|
//dump_keys();
|
||||||
|
}
|
||||||
|
|
||||||
|
ment_t ment_top[] = {
|
||||||
|
MDEF_HANDLER("Dump from SysNAND | Key generation: unk", dump_sysnand, COLOR_RED),
|
||||||
|
MDEF_HANDLER("Dump from EmuNAND | Key generation: unk", dump_emunand, COLOR_ORANGE),
|
||||||
|
MDEF_CAPTION("---------------", COLOR_YELLOW),
|
||||||
|
MDEF_HANDLER("Payloads...", launch_tools, COLOR_GREEN),
|
||||||
|
MDEF_CAPTION("---------------", COLOR_BLUE),
|
||||||
|
MDEF_HANDLER("Reboot (Normal)", reboot_normal, COLOR_VIOLET),
|
||||||
|
MDEF_HANDLER("Reboot (RCM)", reboot_rcm, COLOR_RED),
|
||||||
|
MDEF_HANDLER("Power off", power_off, COLOR_ORANGE),
|
||||||
|
MDEF_END()
|
||||||
|
};
|
||||||
|
|
||||||
|
menu_t menu_top = { ment_top, NULL, 0, 0 };
|
||||||
|
|
||||||
|
void _get_key_generations(char *sysnand_label, char *emunand_label) {
|
||||||
|
sdmmc_t sdmmc;
|
||||||
|
sdmmc_storage_t storage;
|
||||||
|
sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4);
|
||||||
|
u8 *pkg1 = (u8 *)malloc(NX_EMMC_BLOCKSIZE);
|
||||||
|
sdmmc_storage_set_mmc_partition(&storage, 1);
|
||||||
|
sdmmc_storage_read(&storage, 0x100000 / NX_EMMC_BLOCKSIZE, 1, pkg1);
|
||||||
|
const pkg1_id_t *pkg1_id = pkg1_identify(pkg1);
|
||||||
|
sdmmc_storage_end(&storage);
|
||||||
|
|
||||||
|
if (pkg1_id)
|
||||||
|
sprintf(sysnand_label + 36, "% 3d", pkg1_id->kb);
|
||||||
|
ment_top[0].caption = sysnand_label;
|
||||||
|
if (h_cfg.emummc_force_disable) {
|
||||||
|
free(pkg1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
emummc_storage_init_mmc(&storage, &sdmmc);
|
||||||
|
memset(pkg1, 0, NX_EMMC_BLOCKSIZE);
|
||||||
|
emummc_storage_set_mmc_partition(&storage, 1);
|
||||||
|
emummc_storage_read(&storage, 0x100000 / NX_EMMC_BLOCKSIZE, 1, pkg1);
|
||||||
|
pkg1_id = pkg1_identify(pkg1);
|
||||||
|
emummc_storage_end(&storage);
|
||||||
|
|
||||||
|
if (pkg1_id)
|
||||||
|
sprintf(emunand_label + 36, "% 3d", pkg1_id->kb);
|
||||||
|
free(pkg1);
|
||||||
|
ment_top[1].caption = emunand_label;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define EXCP_EN_ADDR 0x4003FFFC
|
||||||
|
#define EXCP_MAGIC 0x30505645 // EVP0
|
||||||
|
#define EXCP_TYPE_ADDR 0x4003FFF8
|
||||||
|
#define EXCP_TYPE_RESET 0x545352 // RST
|
||||||
|
#define EXCP_TYPE_UNDEF 0x464455 // UDF
|
||||||
|
#define EXCP_TYPE_PABRT 0x54424150 // PABT
|
||||||
|
#define EXCP_TYPE_DABRT 0x54424144 // DABT
|
||||||
|
#define EXCP_LR_ADDR 0x4003FFF4
|
||||||
|
|
||||||
|
static void _show_errors(){
|
||||||
|
u32 *excp_enabled = (u32 *)EXCP_EN_ADDR;
|
||||||
|
u32 *excp_type = (u32 *)EXCP_TYPE_ADDR;
|
||||||
|
u32 *excp_lr = (u32 *)EXCP_LR_ADDR;
|
||||||
|
|
||||||
|
if (*excp_enabled == EXCP_MAGIC)
|
||||||
|
h_cfg.errors |= ERR_EXCEPT_ENB;
|
||||||
|
|
||||||
|
if (h_cfg.errors & ERR_EXCEPT_ENB){
|
||||||
|
gfx_clearscreen();
|
||||||
|
SWAPCOLOR(COLOR_ORANGE);
|
||||||
|
gfx_printf("\nAn exception has occured while running TegraExplorer!\n(LR %08X)\n\n", *excp_lr);
|
||||||
|
|
||||||
|
SWAPCOLOR(COLOR_VIOLET);
|
||||||
|
gfx_printf("Exception: ");
|
||||||
|
SWAPCOLOR(COLOR_YELLOW);
|
||||||
|
switch (*excp_type){
|
||||||
|
case EXCP_TYPE_RESET:
|
||||||
|
gfx_printf("Reset");
|
||||||
|
break;
|
||||||
|
case EXCP_TYPE_UNDEF:
|
||||||
|
gfx_printf("Undefined instruction");
|
||||||
|
break;
|
||||||
|
case EXCP_TYPE_PABRT:
|
||||||
|
gfx_printf("Prefetch abort");
|
||||||
|
break;
|
||||||
|
case EXCP_TYPE_DABRT:
|
||||||
|
gfx_printf("Data abort");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
RESETCOLOR;
|
||||||
|
gfx_printf("\n\nPress vol+/- or power to continue");
|
||||||
|
|
||||||
|
*excp_enabled = 0;
|
||||||
|
btn_wait();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
extern void pivot_stack(u32 stack_top);
|
extern void pivot_stack(u32 stack_top);
|
||||||
|
|
||||||
|
// todo: chainload to reboot payload or payloads folder option?
|
||||||
|
|
||||||
void ipl_main()
|
void ipl_main()
|
||||||
{
|
{
|
||||||
bool sd_mounted = false;
|
|
||||||
config_hw();
|
config_hw();
|
||||||
pivot_stack(IPL_STACK_TOP);
|
pivot_stack(IPL_STACK_TOP);
|
||||||
heap_init(IPL_HEAP_START);
|
heap_init(IPL_HEAP_START);
|
||||||
|
|
||||||
|
set_default_configuration();
|
||||||
|
|
||||||
|
sd_mount();
|
||||||
|
minerva_init();
|
||||||
|
minerva_change_freq(FREQ_1600);
|
||||||
|
|
||||||
display_init();
|
display_init();
|
||||||
u32 *fb = display_init_framebuffer();
|
u32 *fb = display_init_framebuffer();
|
||||||
gfx_init_ctxt(fb, 720, 1280, 720);
|
gfx_init_ctxt(fb, 720, 1280, 720);
|
||||||
gfx_con_init();
|
gfx_con_init();
|
||||||
display_backlight_pwm_init();
|
display_backlight_pwm_init();
|
||||||
|
display_backlight_brightness(100, 1000);
|
||||||
|
|
||||||
|
bpmp_clk_rate_set(BPMP_CLK_DEFAULT_BOOST);
|
||||||
|
|
||||||
sd_mounted = sd_mount();
|
/*
|
||||||
meme_main(sd_mounted);
|
h_cfg.emummc_force_disable = emummc_load_cfg();
|
||||||
sd_unmount();
|
|
||||||
|
if (b_cfg.boot_cfg & BOOT_CFG_SEPT_RUN)
|
||||||
|
{
|
||||||
|
if (!(b_cfg.extra_cfg & EXTRA_CFG_DUMP_EMUMMC))
|
||||||
|
h_cfg.emummc_force_disable = true;
|
||||||
|
dump_keys();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (h_cfg.emummc_force_disable)
|
||||||
|
{
|
||||||
|
ment_top[1].type = MENT_CAPTION;
|
||||||
|
ment_top[1].color = 0xFF555555;
|
||||||
|
ment_top[1].handler = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
_get_key_generations((char *)ment_top[0].caption, (char *)ment_top[1].caption);
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
tui_do_menu(&menu_top);
|
||||||
|
*/
|
||||||
|
|
||||||
|
_show_errors();
|
||||||
|
|
||||||
|
te_main();
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
bpmp_halt();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
* arch/arm/mach-tegra/tegra21_emc.h
|
* arch/arm/mach-tegra/tegra21_emc.h
|
||||||
*
|
*
|
||||||
* Copyright (c) 2014-2015, NVIDIA CORPORATION. All rights reserved.
|
* Copyright (c) 2014-2015, NVIDIA CORPORATION. All rights reserved.
|
||||||
|
* Copyright (c) 2019-2020, CTCaer.
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -231,6 +232,7 @@
|
|||||||
#define EMC_COMP_PAD_SW_CTRL 0x57c
|
#define EMC_COMP_PAD_SW_CTRL 0x57c
|
||||||
#define EMC_REQ_CTRL 0x2b0
|
#define EMC_REQ_CTRL 0x2b0
|
||||||
#define EMC_EMC_STATUS 0x2b4
|
#define EMC_EMC_STATUS 0x2b4
|
||||||
|
#define EMC_STATUS_MRR_DIVLD (1 << 20)
|
||||||
#define EMC_CFG_2 0x2b8
|
#define EMC_CFG_2 0x2b8
|
||||||
#define EMC_CFG_DIG_DLL 0x2bc
|
#define EMC_CFG_DIG_DLL 0x2bc
|
||||||
#define EMC_CFG_DIG_DLL_PERIOD 0x2c0
|
#define EMC_CFG_DIG_DLL_PERIOD 0x2c0
|
||||||
@@ -664,4 +666,28 @@
|
|||||||
#define EMC_PMC_SCRATCH2 0x444
|
#define EMC_PMC_SCRATCH2 0x444
|
||||||
#define EMC_PMC_SCRATCH3 0x448
|
#define EMC_PMC_SCRATCH3 0x448
|
||||||
|
|
||||||
|
#define EMC_STATUS_UPDATE_TIMEOUT 1000
|
||||||
|
|
||||||
|
typedef enum _emc_mr_t
|
||||||
|
{
|
||||||
|
MR5_MAN_ID = 5,
|
||||||
|
MR6_REV_ID1 = 6,
|
||||||
|
MR7_REV_ID2 = 7,
|
||||||
|
MR8_DENSITY = 8,
|
||||||
|
} emc_mr_t;
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
EMC_CHAN0 = 0,
|
||||||
|
EMC_CHAN1 = 1
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct _emc_mr_data_t
|
||||||
|
{
|
||||||
|
u8 dev0_ch0;
|
||||||
|
u8 dev0_ch1;
|
||||||
|
u8 dev1_ch0;
|
||||||
|
u8 dev1_ch1;
|
||||||
|
} emc_mr_data_t;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2018 naehrwert
|
* Copyright (c) 2018 naehrwert
|
||||||
|
* Copyright (c) 2018-2020 CTCaer
|
||||||
* Copyright (c) 2018 M4xw
|
* Copyright (c) 2018 M4xw
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
@@ -17,6 +18,7 @@
|
|||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "heap.h"
|
#include "heap.h"
|
||||||
|
#include "../gfx/gfx.h"
|
||||||
#include "../../common/common_heap.h"
|
#include "../../common/common_heap.h"
|
||||||
|
|
||||||
static void _heap_create(heap_t *heap, u32 start)
|
static void _heap_create(heap_t *heap, u32 start)
|
||||||
@@ -25,12 +27,13 @@ static void _heap_create(heap_t *heap, u32 start)
|
|||||||
heap->first = NULL;
|
heap->first = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static u32 _heap_alloc(heap_t *heap, u32 size, u32 alignment)
|
// Node info is before node address.
|
||||||
|
static u32 _heap_alloc(heap_t *heap, u32 size)
|
||||||
{
|
{
|
||||||
hnode_t *node, *new;
|
hnode_t *node, *new_node;
|
||||||
int search = 1;
|
|
||||||
|
|
||||||
size = ALIGN(size, alignment);
|
// Align to cache line size.
|
||||||
|
size = ALIGN(size, sizeof(hnode_t));
|
||||||
|
|
||||||
if (!heap->first)
|
if (!heap->first)
|
||||||
{
|
{
|
||||||
@@ -45,36 +48,55 @@ static u32 _heap_alloc(heap_t *heap, u32 size, u32 alignment)
|
|||||||
}
|
}
|
||||||
|
|
||||||
node = heap->first;
|
node = heap->first;
|
||||||
while (search)
|
while (true)
|
||||||
{
|
{
|
||||||
if (!node->used && size + sizeof(hnode_t) < node->size)
|
// Check if there's available unused node.
|
||||||
|
if (!node->used && (size <= node->size))
|
||||||
{
|
{
|
||||||
new = (hnode_t *)((u32)node + sizeof(hnode_t) + size);
|
// Size and offset of the new unused node.
|
||||||
|
u32 new_size = node->size - size;
|
||||||
|
new_node = (hnode_t *)((u32)node + sizeof(hnode_t) + size);
|
||||||
|
|
||||||
|
// If there's aligned unused space from the old node,
|
||||||
|
// create a new one and set the leftover size.
|
||||||
|
if (new_size >= (sizeof(hnode_t) << 2))
|
||||||
|
{
|
||||||
|
new_node->size = new_size - sizeof(hnode_t);
|
||||||
|
new_node->used = 0;
|
||||||
|
new_node->next = node->next;
|
||||||
|
|
||||||
|
// Check that we are not on first node.
|
||||||
|
if (new_node->next)
|
||||||
|
new_node->next->prev = new_node;
|
||||||
|
|
||||||
|
new_node->prev = node;
|
||||||
|
node->next = new_node;
|
||||||
|
}
|
||||||
|
else // Unused node size is just enough.
|
||||||
|
size += new_size;
|
||||||
|
|
||||||
new->size = node->size - sizeof(hnode_t) - size;
|
|
||||||
node->size = size;
|
node->size = size;
|
||||||
node->used = 1;
|
node->used = 1;
|
||||||
new->used = 0;
|
|
||||||
new->next = node->next;
|
|
||||||
new->prev = node;
|
|
||||||
node->next = new;
|
|
||||||
|
|
||||||
return (u32)node + sizeof(hnode_t);
|
return (u32)node + sizeof(hnode_t);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// No unused node found, try the next one.
|
||||||
if (node->next)
|
if (node->next)
|
||||||
node = node->next;
|
node = node->next;
|
||||||
else
|
else
|
||||||
search = 0;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
new = (hnode_t *)((u32)node + sizeof(hnode_t) + node->size);
|
// No unused node found, create a new one.
|
||||||
new->used = 1;
|
new_node = (hnode_t *)((u32)node + sizeof(hnode_t) + node->size);
|
||||||
new->size = size;
|
new_node->used = 1;
|
||||||
new->prev = node;
|
new_node->size = size;
|
||||||
new->next = NULL;
|
new_node->prev = node;
|
||||||
node->next = new;
|
new_node->next = NULL;
|
||||||
|
node->next = new_node;
|
||||||
|
|
||||||
return (u32)new + sizeof(hnode_t);
|
return (u32)new_node + sizeof(hnode_t);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _heap_free(heap_t *heap, u32 addr)
|
static void _heap_free(heap_t *heap, u32 addr)
|
||||||
@@ -90,6 +112,7 @@ static void _heap_free(heap_t *heap, u32 addr)
|
|||||||
{
|
{
|
||||||
node->prev->size += node->size + sizeof(hnode_t);
|
node->prev->size += node->size + sizeof(hnode_t);
|
||||||
node->prev->next = node->next;
|
node->prev->next = node->next;
|
||||||
|
|
||||||
if (node->next)
|
if (node->next)
|
||||||
node->next->prev = node->prev;
|
node->next->prev = node->prev;
|
||||||
}
|
}
|
||||||
@@ -107,17 +130,12 @@ void heap_init(u32 base)
|
|||||||
|
|
||||||
void *malloc(u32 size)
|
void *malloc(u32 size)
|
||||||
{
|
{
|
||||||
return (void *)_heap_alloc(&_heap, size, 0x10);
|
return (void *)_heap_alloc(&_heap, size);
|
||||||
}
|
|
||||||
|
|
||||||
void *memalign(u32 align, u32 size)
|
|
||||||
{
|
|
||||||
return (void *)_heap_alloc(&_heap, size, align);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void *calloc(u32 num, u32 size)
|
void *calloc(u32 num, u32 size)
|
||||||
{
|
{
|
||||||
void *res = (void *)_heap_alloc(&_heap, num * size, 0x10);
|
void *res = (void *)_heap_alloc(&_heap, num * size);
|
||||||
memset(res, 0, num * size);
|
memset(res, 0, num * size);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
@@ -127,3 +145,30 @@ void free(void *buf)
|
|||||||
if ((u32)buf >= _heap.start)
|
if ((u32)buf >= _heap.start)
|
||||||
_heap_free(&_heap, (u32)buf);
|
_heap_free(&_heap, (u32)buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void heap_monitor(heap_monitor_t *mon, bool print_node_stats)
|
||||||
|
{
|
||||||
|
u32 count = 0;
|
||||||
|
memset(mon, 0, sizeof(heap_monitor_t));
|
||||||
|
|
||||||
|
hnode_t *node = _heap.first;
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
if (node->used)
|
||||||
|
mon->used += node->size + sizeof(hnode_t);
|
||||||
|
else
|
||||||
|
mon->total += node->size + sizeof(hnode_t);
|
||||||
|
|
||||||
|
if (print_node_stats)
|
||||||
|
gfx_printf("%3d - %d, addr: 0x%08X, size: 0x%X\n",
|
||||||
|
count, node->used, (u32)node + sizeof(hnode_t), node->size);
|
||||||
|
|
||||||
|
count++;
|
||||||
|
|
||||||
|
if (node->next)
|
||||||
|
node = node->next;
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
mon->total += mon->used;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2018 naehrwert
|
* Copyright (c) 2018 naehrwert
|
||||||
|
* Copyright (c) 2018-2020 CTCaer
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
* under the terms and conditions of the GNU General Public License,
|
* under the terms and conditions of the GNU General Public License,
|
||||||
@@ -18,11 +19,12 @@
|
|||||||
#define _HEAP_H_
|
#define _HEAP_H_
|
||||||
|
|
||||||
#include "../utils/types.h"
|
#include "../utils/types.h"
|
||||||
|
#include "../../common/common_heap.h"
|
||||||
|
|
||||||
void heap_init(u32 base);
|
void heap_init(u32 base);
|
||||||
void *malloc(u32 size);
|
void *malloc(u32 size);
|
||||||
void *calloc(u32 num, u32 size);
|
void *calloc(u32 num, u32 size);
|
||||||
void free(void *buf);
|
void free(void *buf);
|
||||||
void *memalign(u32 align, u32 size);
|
void heap_monitor(heap_monitor_t *mon, bool print_node_stats);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -127,7 +127,7 @@ void mc_disable_ahb_redirect()
|
|||||||
void mc_enable()
|
void mc_enable()
|
||||||
{
|
{
|
||||||
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC) & 0x1FFFFFFF) | 0x40000000;
|
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC) & 0x1FFFFFFF) | 0x40000000;
|
||||||
// Enable MIPI CAL clock.
|
// Enable EMC clock.
|
||||||
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) = (CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) & 0xFDFFFFFF) | 0x2000000;
|
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) = (CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) & 0xFDFFFFFF) | 0x2000000;
|
||||||
// Enable MC clock.
|
// Enable MC clock.
|
||||||
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) = (CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) & 0xFFFFFFFE) | 1;
|
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) = (CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) & 0xFFFFFFFE) | 1;
|
||||||
|
|||||||
@@ -463,4 +463,54 @@
|
|||||||
#define MC_ERR_APB_ASID_UPDATE_STATUS 0x9d0
|
#define MC_ERR_APB_ASID_UPDATE_STATUS 0x9d0
|
||||||
#define MC_DA_CONFIG0 0x9dc
|
#define MC_DA_CONFIG0 0x9dc
|
||||||
|
|
||||||
|
// MC_SECURITY_CARVEOUTX_CFG0
|
||||||
|
// Mode of LOCK_MODE.
|
||||||
|
#define PROTECT_MODE_SHIFT 0
|
||||||
|
#define SEC_CARVEOUT_CFG_SECURE (0 << PROTECT_MODE_SHIFT0)
|
||||||
|
#define SEC_CARVEOUT_CFG_TZ_SECURE (1 << PROTECT_MODE_SHIFT0)
|
||||||
|
// Enables PROTECT_MODE.
|
||||||
|
#define LOCK_MODE_SHIFT 1
|
||||||
|
#define SEC_CARVEOUT_CFG_UNLOCKED (0 << LOCK_MODE_SHIFT)
|
||||||
|
#define SEC_CARVEOUT_CFG_LOCKED (1 << LOCK_MODE_SHIFT)
|
||||||
|
|
||||||
|
#define ADDRESS_TYPE_SHIFT 2
|
||||||
|
#define SEC_CARVEOUT_CFG_ANY_ADDRESS (0 << ADDRESS_TYPE_SHIFT)
|
||||||
|
#define SEC_CARVEOUT_CFG_UNTRANSLATED_ONLY (1 << ADDRESS_TYPE_SHIFT)
|
||||||
|
|
||||||
|
#define READ_ACCESS_LEVEL_SHIFT 3
|
||||||
|
#define SEC_CARVEOUT_CFG_RD_ALL (1 << READ_ACCESS_LEVEL_SHIFT)
|
||||||
|
#define SEC_CARVEOUT_CFG_RD_UNK (2 << READ_ACCESS_LEVEL_SHIFT)
|
||||||
|
#define SEC_CARVEOUT_CFG_RD_FALCON_LS (4 << READ_ACCESS_LEVEL_SHIFT)
|
||||||
|
#define SEC_CARVEOUT_CFG_RD_FALCON_HS (8 << READ_ACCESS_LEVEL_SHIFT)
|
||||||
|
|
||||||
|
#define WRITE_ACCESS_LEVEL_SHIFT 7
|
||||||
|
#define SEC_CARVEOUT_CFG_WR_ALL (1 << WRITE_ACCESS_LEVEL_SHIFT)
|
||||||
|
#define SEC_CARVEOUT_CFG_WR_UNK (2 << WRITE_ACCESS_LEVEL_SHIFT)
|
||||||
|
#define SEC_CARVEOUT_CFG_WR_FALCON_LS (4 << WRITE_ACCESS_LEVEL_SHIFT)
|
||||||
|
#define SEC_CARVEOUT_CFG_WR_FALCON_HS (8 << WRITE_ACCESS_LEVEL_SHIFT)
|
||||||
|
|
||||||
|
#define SEC_CARVEOUT_CFG_APERTURE_ID_MASK (3 << 11)
|
||||||
|
|
||||||
|
#define DISABLE_READ_CHECK_ACCESS_LEVEL_SHIFT 14
|
||||||
|
#define SEC_CARVEOUT_CFG_DIS_RD_CHECK_L0 (1 << DISABLE_READ_CHECK_ACCESS_LEVEL_SHIFT)
|
||||||
|
#define SEC_CARVEOUT_CFG_DIS_RD_CHECK_L1 (2 << DISABLE_READ_CHECK_ACCESS_LEVEL_SHIFT)
|
||||||
|
#define SEC_CARVEOUT_CFG_DIS_RD_CHECK_L2 (4 << DISABLE_READ_CHECK_ACCESS_LEVEL_SHIFT)
|
||||||
|
#define SEC_CARVEOUT_CFG_DIS_RD_CHECK_L3 (8 << DISABLE_READ_CHECK_ACCESS_LEVEL_SHIFT)
|
||||||
|
|
||||||
|
#define DISABLE_WRITE_CHECK_ACCESS_LEVEL_SHIFT 18
|
||||||
|
#define SEC_CARVEOUT_CFG_DIS_WR_CHECK_L0 (1 << DISABLE_WRITE_CHECK_ACCESS_LEVEL_SHIFT)
|
||||||
|
#define SEC_CARVEOUT_CFG_DIS_WR_CHECK_L1 (2 << DISABLE_WRITE_CHECK_ACCESS_LEVEL_SHIFT)
|
||||||
|
#define SEC_CARVEOUT_CFG_DIS_WR_CHECK_L2 (4 << DISABLE_WRITE_CHECK_ACCESS_LEVEL_SHIFT)
|
||||||
|
#define SEC_CARVEOUT_CFG_DIS_WR_CHECK_L3 (8 << DISABLE_WRITE_CHECK_ACCESS_LEVEL_SHIFT)
|
||||||
|
|
||||||
|
#define SEC_CARVEOUT_CFG_SEND_CFG_TO_GPU (1 << 22)
|
||||||
|
|
||||||
|
#define SEC_CARVEOUT_CFG_TZ_GLOBAL_WR_EN_BYPASS_CHECK (1 << 23)
|
||||||
|
#define SEC_CARVEOUT_CFG_TZ_GLOBAL_RD_EN_BYPASS_CHECK (1 << 24)
|
||||||
|
|
||||||
|
#define SEC_CARVEOUT_CFG_ALLOW_APERTURE_ID_MISMATCH (1 << 25)
|
||||||
|
#define SEC_CARVEOUT_CFG_FORCE_APERTURE_ID_MATCH (1 << 26)
|
||||||
|
|
||||||
|
#define SEC_CARVEOUT_CFG_IS_WPR (1 << 27)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
109
source/mem/minerva.c
Normal file
109
source/mem/minerva.c
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019 CTCaer
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "minerva.h"
|
||||||
|
#include "../soc/fuse.h"
|
||||||
|
#include "../utils/util.h"
|
||||||
|
|
||||||
|
#include "../soc/clock.h"
|
||||||
|
#include "../ianos/ianos.h"
|
||||||
|
#include "../soc/fuse.h"
|
||||||
|
#include "../soc/t210.h"
|
||||||
|
|
||||||
|
extern volatile nyx_storage_t *nyx_str;
|
||||||
|
|
||||||
|
u32 minerva_init()
|
||||||
|
{
|
||||||
|
u32 curr_ram_idx = 0;
|
||||||
|
|
||||||
|
minerva_cfg = NULL;
|
||||||
|
mtc_config_t *mtc_cfg = (mtc_config_t *)&nyx_str->mtc_cfg;
|
||||||
|
memset(mtc_cfg, 0, sizeof(mtc_config_t));
|
||||||
|
|
||||||
|
// Set table to nyx storage.
|
||||||
|
mtc_cfg->mtc_table = (emc_table_t *)nyx_str->mtc_table;
|
||||||
|
|
||||||
|
mtc_cfg->sdram_id = (fuse_read_odm(4) >> 3) & 0x1F;
|
||||||
|
mtc_cfg->init_done = MTC_NEW_MAGIC; // Initialize mtc table.
|
||||||
|
|
||||||
|
u32 ep_addr = ianos_loader(false, "bootloader/sys/libsys_minerva.bso", DRAM_LIB, (void *)mtc_cfg);
|
||||||
|
|
||||||
|
// Ensure that Minerva is new.
|
||||||
|
if (mtc_cfg->init_done == MTC_INIT_MAGIC)
|
||||||
|
minerva_cfg = (void *)ep_addr;
|
||||||
|
else
|
||||||
|
mtc_cfg->init_done = 0;
|
||||||
|
|
||||||
|
if (!minerva_cfg)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
// Get current frequency
|
||||||
|
for (curr_ram_idx = 0; curr_ram_idx < 10; curr_ram_idx++)
|
||||||
|
{
|
||||||
|
if (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC) == mtc_cfg->mtc_table[curr_ram_idx].clk_src_emc)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
mtc_cfg->rate_from = mtc_cfg->mtc_table[curr_ram_idx].rate_khz;
|
||||||
|
mtc_cfg->rate_to = 204000;
|
||||||
|
mtc_cfg->train_mode = OP_TRAIN;
|
||||||
|
minerva_cfg(mtc_cfg, NULL);
|
||||||
|
mtc_cfg->rate_to = 800000;
|
||||||
|
minerva_cfg(mtc_cfg, NULL);
|
||||||
|
mtc_cfg->rate_to = 1600000;
|
||||||
|
minerva_cfg(mtc_cfg, NULL);
|
||||||
|
|
||||||
|
// FSP WAR.
|
||||||
|
mtc_cfg->train_mode = OP_SWITCH;
|
||||||
|
mtc_cfg->rate_to = 800000;
|
||||||
|
minerva_cfg(mtc_cfg, NULL);
|
||||||
|
|
||||||
|
// Switch to max.
|
||||||
|
mtc_cfg->rate_to = 1600000;
|
||||||
|
minerva_cfg(mtc_cfg, NULL);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void minerva_change_freq(minerva_freq_t freq)
|
||||||
|
{
|
||||||
|
if (!minerva_cfg)
|
||||||
|
return;
|
||||||
|
|
||||||
|
mtc_config_t *mtc_cfg = (mtc_config_t *)&nyx_str->mtc_cfg;
|
||||||
|
if (mtc_cfg->rate_from != freq)
|
||||||
|
{
|
||||||
|
mtc_cfg->rate_to = freq;
|
||||||
|
mtc_cfg->train_mode = OP_SWITCH;
|
||||||
|
minerva_cfg(mtc_cfg, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void minerva_periodic_training()
|
||||||
|
{
|
||||||
|
if (!minerva_cfg)
|
||||||
|
return;
|
||||||
|
|
||||||
|
mtc_config_t *mtc_cfg = (mtc_config_t *)&nyx_str->mtc_cfg;
|
||||||
|
if (mtc_cfg->rate_from == FREQ_1600)
|
||||||
|
{
|
||||||
|
mtc_cfg->train_mode = OP_PERIODIC_TRAIN;
|
||||||
|
minerva_cfg(mtc_cfg, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
65
source/mem/minerva.h
Normal file
65
source/mem/minerva.h
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019 CTCaer
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _FE_MINERVA_H_
|
||||||
|
#define _FE_MINERVA_H_
|
||||||
|
|
||||||
|
#include "mtc_table.h"
|
||||||
|
#include "../utils/types.h"
|
||||||
|
|
||||||
|
#define MTC_INIT_MAGIC 0x3043544D
|
||||||
|
#define MTC_NEW_MAGIC 0x5243544D
|
||||||
|
|
||||||
|
#define EMC_PERIODIC_TRAIN_MS 250
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
s32 rate_to;
|
||||||
|
s32 rate_from;
|
||||||
|
emc_table_t *mtc_table;
|
||||||
|
u32 table_entries;
|
||||||
|
emc_table_t *current_emc_table;
|
||||||
|
u32 train_mode;
|
||||||
|
u32 sdram_id;
|
||||||
|
u32 prev_temp;
|
||||||
|
bool emc_2X_clk_src_is_pllmb;
|
||||||
|
bool fsp_for_src_freq;
|
||||||
|
bool train_ram_patterns;
|
||||||
|
bool init_done;
|
||||||
|
} mtc_config_t;
|
||||||
|
|
||||||
|
enum train_mode_t
|
||||||
|
{
|
||||||
|
OP_SWITCH = 0,
|
||||||
|
OP_TRAIN = 1,
|
||||||
|
OP_TRAIN_SWITCH = 2,
|
||||||
|
OP_PERIODIC_TRAIN = 3,
|
||||||
|
OP_TEMP_COMP = 4
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
FREQ_204 = 204000,
|
||||||
|
FREQ_800 = 800000,
|
||||||
|
FREQ_1600 = 1600000
|
||||||
|
} minerva_freq_t;
|
||||||
|
|
||||||
|
void (*minerva_cfg)(mtc_config_t *mtc_cfg, void *);
|
||||||
|
u32 minerva_init();
|
||||||
|
void minerva_change_freq(minerva_freq_t freq);
|
||||||
|
void minerva_periodic_training();
|
||||||
|
|
||||||
|
#endif
|
||||||
560
source/mem/mtc_table.h
Normal file
560
source/mem/mtc_table.h
Normal file
@@ -0,0 +1,560 @@
|
|||||||
|
/*
|
||||||
|
* Minerva Training Cell
|
||||||
|
* DRAM Training for Tegra X1 SoC. Supports DDR2/3 and LPDDR3/4.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 CTCaer <ctcaer@gmail.com>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _MTC_TABLE_H_
|
||||||
|
#define _MTC_TABLE_H_
|
||||||
|
|
||||||
|
#include "../utils/types.h"
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
s32 pll_osc_in;
|
||||||
|
s32 pll_out;
|
||||||
|
u32 pll_feedback_div;
|
||||||
|
u32 pll_input_div;
|
||||||
|
u32 pll_post_div;
|
||||||
|
} pllm_clk_config_t;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
u32 emc_rc_idx;
|
||||||
|
u32 emc_rfc_idx;
|
||||||
|
u32 emc_rfcpb_idx;
|
||||||
|
u32 emc_refctrl2_idx;
|
||||||
|
u32 emc_rfc_slr_idx;
|
||||||
|
u32 emc_ras_idx;
|
||||||
|
u32 emc_rp_idx;
|
||||||
|
u32 emc_r2w_idx;
|
||||||
|
u32 emc_w2r_idx;
|
||||||
|
u32 emc_r2p_idx;
|
||||||
|
u32 emc_w2p_idx;
|
||||||
|
u32 emc_r2r_idx;
|
||||||
|
u32 emc_tppd_idx;
|
||||||
|
u32 emc_ccdmw_idx;
|
||||||
|
u32 emc_rd_rcd_idx;
|
||||||
|
u32 emc_wr_rcd_idx;
|
||||||
|
u32 emc_rrd_idx;
|
||||||
|
u32 emc_rext_idx;
|
||||||
|
u32 emc_wext_idx;
|
||||||
|
u32 emc_wdv_chk_idx;
|
||||||
|
u32 emc_wdv_idx;
|
||||||
|
u32 emc_wsv_idx;
|
||||||
|
u32 emc_wev_idx;
|
||||||
|
u32 emc_wdv_mask_idx;
|
||||||
|
u32 emc_ws_duration_idx;
|
||||||
|
u32 emc_we_duration_idx;
|
||||||
|
u32 emc_quse_idx;
|
||||||
|
u32 emc_quse_width_idx;
|
||||||
|
u32 emc_ibdly_idx;
|
||||||
|
u32 emc_obdly_idx;
|
||||||
|
u32 emc_einput_idx;
|
||||||
|
u32 emc_mrw6_idx;
|
||||||
|
u32 emc_einput_duration_idx;
|
||||||
|
u32 emc_puterm_extra_idx;
|
||||||
|
u32 emc_puterm_width_idx;
|
||||||
|
u32 emc_qrst_idx;
|
||||||
|
u32 emc_qsafe_idx;
|
||||||
|
u32 emc_rdv_idx;
|
||||||
|
u32 emc_rdv_mask_idx;
|
||||||
|
u32 emc_rdv_early_idx;
|
||||||
|
u32 emc_rdv_early_mask_idx;
|
||||||
|
u32 emc_refresh_idx;
|
||||||
|
u32 emc_burst_refresh_num_idx;
|
||||||
|
u32 emc_pre_refresh_req_cnt_idx;
|
||||||
|
u32 emc_pdex2wr_idx;
|
||||||
|
u32 emc_pdex2rd_idx;
|
||||||
|
u32 emc_pchg2pden_idx;
|
||||||
|
u32 emc_act2pden_idx;
|
||||||
|
u32 emc_ar2pden_idx;
|
||||||
|
u32 emc_rw2pden_idx;
|
||||||
|
u32 emc_cke2pden_idx;
|
||||||
|
u32 emc_pdex2cke_idx;
|
||||||
|
u32 emc_pdex2mrr_idx;
|
||||||
|
u32 emc_txsr_idx;
|
||||||
|
u32 emc_txsrdll_idx;
|
||||||
|
u32 emc_tcke_idx;
|
||||||
|
u32 emc_tckesr_idx;
|
||||||
|
u32 emc_tpd_idx;
|
||||||
|
u32 emc_tfaw_idx;
|
||||||
|
u32 emc_trpab_idx;
|
||||||
|
u32 emc_tclkstable_idx;
|
||||||
|
u32 emc_tclkstop_idx;
|
||||||
|
u32 emc_mrw7_idx;
|
||||||
|
u32 emc_trefbw_idx;
|
||||||
|
u32 emc_odt_write_idx;
|
||||||
|
u32 emc_fbio_cfg5_idx;
|
||||||
|
u32 emc_fbio_cfg7_idx;
|
||||||
|
u32 emc_cfg_dig_dll_idx;
|
||||||
|
u32 emc_cfg_dig_dll_period_idx;
|
||||||
|
u32 emc_pmacro_ib_rxrt_idx;
|
||||||
|
u32 emc_cfg_pipe_1_idx;
|
||||||
|
u32 emc_cfg_pipe_2_idx;
|
||||||
|
u32 emc_pmacro_quse_ddll_rank0_4_idx;
|
||||||
|
u32 emc_pmacro_quse_ddll_rank0_5_idx;
|
||||||
|
u32 emc_pmacro_quse_ddll_rank1_4_idx;
|
||||||
|
u32 emc_pmacro_quse_ddll_rank1_5_idx;
|
||||||
|
u32 emc_mrw8_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_long_dq_rank1_4_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_long_dq_rank1_5_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_long_dqs_rank0_0_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_long_dqs_rank0_1_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_long_dqs_rank0_2_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_long_dqs_rank0_3_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_long_dqs_rank0_4_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_long_dqs_rank0_5_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_long_dqs_rank1_0_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_long_dqs_rank1_1_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_long_dqs_rank1_2_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_long_dqs_rank1_3_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_long_dqs_rank1_4_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_long_dqs_rank1_5_idx;
|
||||||
|
u32 emc_pmacro_ddll_long_cmd_0_idx;
|
||||||
|
u32 emc_pmacro_ddll_long_cmd_1_idx;
|
||||||
|
u32 emc_pmacro_ddll_long_cmd_2_idx;
|
||||||
|
u32 emc_pmacro_ddll_long_cmd_3_idx;
|
||||||
|
u32 emc_pmacro_ddll_long_cmd_4_idx;
|
||||||
|
u32 emc_pmacro_ddll_short_cmd_0_idx;
|
||||||
|
u32 emc_pmacro_ddll_short_cmd_1_idx;
|
||||||
|
u32 emc_pmacro_ddll_short_cmd_2_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte0_3_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte1_3_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte2_3_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte3_3_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte4_3_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte5_3_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte6_3_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte7_3_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd0_3_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd1_3_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd2_3_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd3_3_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte0_3_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte1_3_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte2_3_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte3_3_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte4_3_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte5_3_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte6_3_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte7_3_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd0_0_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd0_1_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd0_2_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd0_3_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd1_0_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd1_1_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd1_2_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd1_3_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd2_0_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd2_1_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd2_2_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd2_3_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd3_0_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd3_1_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd3_2_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_short_dq_rank1_cmd3_3_idx;
|
||||||
|
u32 emc_txdsrvttgen_idx;
|
||||||
|
u32 emc_fdpd_ctrl_dq_idx;
|
||||||
|
u32 emc_fdpd_ctrl_cmd_idx;
|
||||||
|
u32 emc_fbio_spare_idx;
|
||||||
|
u32 emc_zcal_interval_idx;
|
||||||
|
u32 emc_zcal_wait_cnt_idx;
|
||||||
|
u32 emc_mrs_wait_cnt_idx;
|
||||||
|
u32 emc_mrs_wait_cnt2_idx;
|
||||||
|
u32 emc_auto_cal_channel_idx;
|
||||||
|
u32 emc_dll_cfg_0_idx;
|
||||||
|
u32 emc_dll_cfg_1_idx;
|
||||||
|
u32 emc_pmacro_autocal_cfg_common_idx;
|
||||||
|
u32 emc_pmacro_zctrl_idx;
|
||||||
|
u32 emc_cfg_idx;
|
||||||
|
u32 emc_cfg_pipe_idx;
|
||||||
|
u32 emc_dyn_self_ref_control_idx;
|
||||||
|
u32 emc_qpop_idx;
|
||||||
|
u32 emc_dqs_brlshft_0_idx;
|
||||||
|
u32 emc_dqs_brlshft_1_idx;
|
||||||
|
u32 emc_cmd_brlshft_2_idx;
|
||||||
|
u32 emc_cmd_brlshft_3_idx;
|
||||||
|
u32 emc_pmacro_pad_cfg_ctrl_idx;
|
||||||
|
u32 emc_pmacro_data_pad_rx_ctrl_idx;
|
||||||
|
u32 emc_pmacro_cmd_pad_rx_ctrl_idx;
|
||||||
|
u32 emc_pmacro_data_rx_term_mode_idx;
|
||||||
|
u32 emc_pmacro_cmd_rx_term_mode_idx;
|
||||||
|
u32 emc_pmacro_cmd_pad_tx_ctrl_idx;
|
||||||
|
u32 emc_pmacro_data_pad_tx_ctrl_idx;
|
||||||
|
u32 emc_pmacro_common_pad_tx_ctrl_idx;
|
||||||
|
u32 emc_pmacro_vttgen_ctrl_0_idx;
|
||||||
|
u32 emc_pmacro_vttgen_ctrl_1_idx;
|
||||||
|
u32 emc_pmacro_vttgen_ctrl_2_idx;
|
||||||
|
u32 emc_pmacro_brick_ctrl_rfu1_idx;
|
||||||
|
u32 emc_pmacro_cmd_brick_ctrl_fdpd_idx;
|
||||||
|
u32 emc_pmacro_brick_ctrl_rfu2_idx;
|
||||||
|
u32 emc_pmacro_data_brick_ctrl_fdpd_idx;
|
||||||
|
u32 emc_pmacro_bg_bias_ctrl_0_idx;
|
||||||
|
u32 emc_cfg_3_idx;
|
||||||
|
u32 emc_pmacro_tx_pwrd_0_idx;
|
||||||
|
u32 emc_pmacro_tx_pwrd_1_idx;
|
||||||
|
u32 emc_pmacro_tx_pwrd_2_idx;
|
||||||
|
u32 emc_pmacro_tx_pwrd_3_idx;
|
||||||
|
u32 emc_pmacro_tx_pwrd_4_idx;
|
||||||
|
u32 emc_pmacro_tx_pwrd_5_idx;
|
||||||
|
u32 emc_config_sample_delay_idx;
|
||||||
|
u32 emc_pmacro_tx_sel_clk_src_0_idx;
|
||||||
|
u32 emc_pmacro_tx_sel_clk_src_1_idx;
|
||||||
|
u32 emc_pmacro_tx_sel_clk_src_2_idx;
|
||||||
|
u32 emc_pmacro_tx_sel_clk_src_3_idx;
|
||||||
|
u32 emc_pmacro_tx_sel_clk_src_4_idx;
|
||||||
|
u32 emc_pmacro_tx_sel_clk_src_5_idx;
|
||||||
|
u32 emc_pmacro_ddll_bypass_idx;
|
||||||
|
u32 emc_pmacro_ddll_pwrd_0_idx;
|
||||||
|
u32 emc_pmacro_ddll_pwrd_1_idx;
|
||||||
|
u32 emc_pmacro_ddll_pwrd_2_idx;
|
||||||
|
u32 emc_pmacro_cmd_ctrl_0_idx;
|
||||||
|
u32 emc_pmacro_cmd_ctrl_1_idx;
|
||||||
|
u32 emc_pmacro_cmd_ctrl_2_idx;
|
||||||
|
u32 emc_tr_timing_0_idx;
|
||||||
|
u32 emc_tr_dvfs_idx;
|
||||||
|
u32 emc_tr_ctrl_1_idx;
|
||||||
|
u32 emc_tr_rdv_idx;
|
||||||
|
u32 emc_tr_qpop_idx;
|
||||||
|
u32 emc_tr_rdv_mask_idx;
|
||||||
|
u32 emc_mrw14_idx;
|
||||||
|
u32 emc_tr_qsafe_idx;
|
||||||
|
u32 emc_tr_qrst_idx;
|
||||||
|
u32 emc_training_ctrl_idx;
|
||||||
|
u32 emc_training_settle_idx;
|
||||||
|
u32 emc_training_vref_settle_idx;
|
||||||
|
u32 emc_training_ca_fine_ctrl_idx;
|
||||||
|
u32 emc_training_ca_ctrl_misc_idx;
|
||||||
|
u32 emc_training_ca_ctrl_misc1_idx;
|
||||||
|
u32 emc_training_ca_vref_ctrl_idx;
|
||||||
|
u32 emc_training_quse_cors_ctrl_idx;
|
||||||
|
u32 emc_training_quse_fine_ctrl_idx;
|
||||||
|
u32 emc_training_quse_ctrl_misc_idx;
|
||||||
|
u32 emc_training_quse_vref_ctrl_idx;
|
||||||
|
u32 emc_training_read_fine_ctrl_idx;
|
||||||
|
u32 emc_training_read_ctrl_misc_idx;
|
||||||
|
u32 emc_training_read_vref_ctrl_idx;
|
||||||
|
u32 emc_training_write_fine_ctrl_idx;
|
||||||
|
u32 emc_training_write_ctrl_misc_idx;
|
||||||
|
u32 emc_training_write_vref_ctrl_idx;
|
||||||
|
u32 emc_training_mpc_idx;
|
||||||
|
u32 emc_mrw15_idx;
|
||||||
|
} burst_regs_t;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
u32 burst_regs[221];
|
||||||
|
u32 burst_reg_per_ch[8];
|
||||||
|
u32 shadow_regs_ca_train[221];
|
||||||
|
u32 shadow_regs_quse_train[221];
|
||||||
|
u32 shadow_regs_rdwr_train[221];
|
||||||
|
} burst_regs_table_t;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
u32 ptfv_dqsosc_movavg_c0d0u0_idx;
|
||||||
|
u32 ptfv_dqsosc_movavg_c0d0u1_idx;
|
||||||
|
u32 ptfv_dqsosc_movavg_c0d1u0_idx;
|
||||||
|
u32 ptfv_dqsosc_movavg_c0d1u1_idx;
|
||||||
|
u32 ptfv_dqsosc_movavg_c1d0u0_idx;
|
||||||
|
u32 ptfv_dqsosc_movavg_c1d0u1_idx;
|
||||||
|
u32 ptfv_dqsosc_movavg_c1d1u0_idx;
|
||||||
|
u32 ptfv_dqsosc_movavg_c1d1u1_idx;
|
||||||
|
u32 ptfv_write_samples_idx;
|
||||||
|
u32 ptfv_dvfs_samples_idx;
|
||||||
|
u32 ptfv_movavg_weight_idx;
|
||||||
|
u32 ptfv_config_ctrl_idx;
|
||||||
|
} ptfv_list_table_t;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
u32 emc0_mrw10_idx;
|
||||||
|
u32 emc1_mrw10_idx;
|
||||||
|
u32 emc0_mrw11_idx;
|
||||||
|
u32 emc1_mrw11_idx;
|
||||||
|
u32 emc0_mrw12_idx;
|
||||||
|
u32 emc1_mrw12_idx;
|
||||||
|
u32 emc0_mrw13_idx;
|
||||||
|
u32 emc1_mrw13_idx;
|
||||||
|
} burst_reg_per_ch_t;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
u32 emc_pmacro_ib_ddll_long_dqs_rank0_0_idx;
|
||||||
|
u32 emc_pmacro_ib_ddll_long_dqs_rank0_1_idx;
|
||||||
|
u32 emc_pmacro_ib_ddll_long_dqs_rank0_2_idx;
|
||||||
|
u32 emc_pmacro_ib_ddll_long_dqs_rank0_3_idx;
|
||||||
|
u32 emc_pmacro_ib_ddll_long_dqs_rank1_0_idx;
|
||||||
|
u32 emc_pmacro_ib_ddll_long_dqs_rank1_1_idx;
|
||||||
|
u32 emc_pmacro_ib_ddll_long_dqs_rank1_2_idx;
|
||||||
|
u32 emc_pmacro_ib_ddll_long_dqs_rank1_3_idx;
|
||||||
|
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte0_0_idx;
|
||||||
|
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte0_1_idx;
|
||||||
|
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte0_2_idx;
|
||||||
|
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte1_0_idx;
|
||||||
|
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte1_1_idx;
|
||||||
|
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte1_2_idx;
|
||||||
|
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte2_0_idx;
|
||||||
|
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte2_1_idx;
|
||||||
|
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte2_2_idx;
|
||||||
|
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte3_0_idx;
|
||||||
|
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte3_1_idx;
|
||||||
|
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte3_2_idx;
|
||||||
|
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte4_0_idx;
|
||||||
|
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte4_1_idx;
|
||||||
|
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte4_2_idx;
|
||||||
|
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte5_0_idx;
|
||||||
|
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte5_1_idx;
|
||||||
|
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte5_2_idx;
|
||||||
|
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte6_0_idx;
|
||||||
|
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte6_1_idx;
|
||||||
|
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte6_2_idx;
|
||||||
|
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte7_0_idx;
|
||||||
|
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte7_1_idx;
|
||||||
|
u32 emc_pmacro_ib_ddll_short_dq_rank0_byte7_2_idx;
|
||||||
|
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte0_0_idx;
|
||||||
|
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte0_1_idx;
|
||||||
|
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte0_2_idx;
|
||||||
|
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte1_0_idx;
|
||||||
|
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte1_1_idx;
|
||||||
|
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte1_2_idx;
|
||||||
|
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte2_0_idx;
|
||||||
|
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte2_1_idx;
|
||||||
|
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte2_2_idx;
|
||||||
|
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte3_0_idx;
|
||||||
|
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte3_1_idx;
|
||||||
|
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte3_2_idx;
|
||||||
|
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte4_0_idx;
|
||||||
|
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte4_1_idx;
|
||||||
|
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte4_2_idx;
|
||||||
|
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte5_0_idx;
|
||||||
|
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte5_1_idx;
|
||||||
|
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte5_2_idx;
|
||||||
|
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte6_0_idx;
|
||||||
|
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte6_1_idx;
|
||||||
|
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte6_2_idx;
|
||||||
|
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte7_0_idx;
|
||||||
|
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte7_1_idx;
|
||||||
|
u32 emc_pmacro_ib_ddll_short_dq_rank1_byte7_2_idx;
|
||||||
|
u32 emc_pmacro_ib_vref_dqs_0_idx;
|
||||||
|
u32 emc_pmacro_ib_vref_dqs_1_idx;
|
||||||
|
u32 emc_pmacro_ib_vref_dq_0_idx;
|
||||||
|
u32 emc_pmacro_ib_vref_dq_1_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_long_dq_rank0_0_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_long_dq_rank0_1_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_long_dq_rank0_2_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_long_dq_rank0_3_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_long_dq_rank0_4_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_long_dq_rank0_5_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_long_dq_rank1_0_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_long_dq_rank1_1_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_long_dq_rank1_2_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_long_dq_rank1_3_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte0_0_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte0_1_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte0_2_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte1_0_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte1_1_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte1_2_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte2_0_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte2_1_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte2_2_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte3_0_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte3_1_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte3_2_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte4_0_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte4_1_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte4_2_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte5_0_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte5_1_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte5_2_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte6_0_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte6_1_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte6_2_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte7_0_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte7_1_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_short_dq_rank0_byte7_2_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd0_0_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd0_1_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd0_2_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd1_0_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd1_1_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd1_2_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd2_0_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd2_1_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd2_2_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd3_0_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd3_1_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_short_dq_rank0_cmd3_2_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte0_0_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte0_1_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte0_2_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte1_0_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte1_1_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte1_2_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte2_0_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte2_1_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte2_2_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte3_0_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte3_1_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte3_2_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte4_0_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte4_1_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte4_2_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte5_0_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte5_1_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte5_2_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte6_0_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte6_1_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte6_2_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte7_0_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte7_1_idx;
|
||||||
|
u32 emc_pmacro_ob_ddll_short_dq_rank1_byte7_2_idx;
|
||||||
|
u32 emc_pmacro_quse_ddll_rank0_0_idx;
|
||||||
|
u32 emc_pmacro_quse_ddll_rank0_1_idx;
|
||||||
|
u32 emc_pmacro_quse_ddll_rank0_2_idx;
|
||||||
|
u32 emc_pmacro_quse_ddll_rank0_3_idx;
|
||||||
|
u32 emc_pmacro_quse_ddll_rank1_0_idx;
|
||||||
|
u32 emc_pmacro_quse_ddll_rank1_1_idx;
|
||||||
|
u32 emc_pmacro_quse_ddll_rank1_2_idx;
|
||||||
|
u32 emc_pmacro_quse_ddll_rank1_3_idx;
|
||||||
|
} trim_regs_t;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
u32 emc_cmd_brlshft_0_idx;
|
||||||
|
u32 emc_cmd_brlshft_1_idx;
|
||||||
|
u32 emc0_data_brlshft_0_idx;
|
||||||
|
u32 emc1_data_brlshft_0_idx;
|
||||||
|
u32 emc0_data_brlshft_1_idx;
|
||||||
|
u32 emc1_data_brlshft_1_idx;
|
||||||
|
u32 emc_quse_brlshft_0_idx;
|
||||||
|
u32 emc_quse_brlshft_1_idx;
|
||||||
|
u32 emc_quse_brlshft_2_idx;
|
||||||
|
u32 emc_quse_brlshft_3_idx;
|
||||||
|
} trim_perch_regs_t;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
u32 t_rp;
|
||||||
|
u32 t_fc_lpddr4;
|
||||||
|
u32 t_rfc;
|
||||||
|
u32 t_pdex;
|
||||||
|
u32 rl;
|
||||||
|
} dram_timings_t;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
u32 emc0_training_opt_dqs_ib_vref_rank0_idx;
|
||||||
|
u32 emc1_training_opt_dqs_ib_vref_rank0_idx;
|
||||||
|
u32 emc0_training_opt_dqs_ib_vref_rank1_idx;
|
||||||
|
u32 emc1_training_opt_dqs_ib_vref_rank1_idx;
|
||||||
|
} vref_perch_regs_t;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
u32 trim_regs[138];
|
||||||
|
u32 trim_perch_regs[10];
|
||||||
|
u32 vref_perch_regs[4];
|
||||||
|
} trim_regs_table_t;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
u32 rev;
|
||||||
|
char dvfs_ver[60];
|
||||||
|
u32 rate_khz;
|
||||||
|
u32 min_volt;
|
||||||
|
u32 gpu_min_volt;
|
||||||
|
char clock_src[32];
|
||||||
|
u32 clk_src_emc;
|
||||||
|
u32 needs_training;
|
||||||
|
u32 training_pattern;
|
||||||
|
u32 trained;
|
||||||
|
u32 periodic_training;
|
||||||
|
u32 trained_dram_clktree_c0d0u0;
|
||||||
|
u32 trained_dram_clktree_c0d0u1;
|
||||||
|
u32 trained_dram_clktree_c0d1u0;
|
||||||
|
u32 trained_dram_clktree_c0d1u1;
|
||||||
|
u32 trained_dram_clktree_c1d0u0;
|
||||||
|
u32 trained_dram_clktree_c1d0u1;
|
||||||
|
u32 trained_dram_clktree_c1d1u0;
|
||||||
|
u32 trained_dram_clktree_c1d1u1;
|
||||||
|
u32 current_dram_clktree_c0d0u0;
|
||||||
|
u32 current_dram_clktree_c0d0u1;
|
||||||
|
u32 current_dram_clktree_c0d1u0;
|
||||||
|
u32 current_dram_clktree_c0d1u1;
|
||||||
|
u32 current_dram_clktree_c1d0u0;
|
||||||
|
u32 current_dram_clktree_c1d0u1;
|
||||||
|
u32 current_dram_clktree_c1d1u0;
|
||||||
|
u32 current_dram_clktree_c1d1u1;
|
||||||
|
u32 run_clocks;
|
||||||
|
u32 tree_margin;
|
||||||
|
u32 num_burst;
|
||||||
|
u32 num_burst_per_ch;
|
||||||
|
u32 num_trim;
|
||||||
|
u32 num_trim_per_ch;
|
||||||
|
u32 num_mc_regs;
|
||||||
|
u32 num_up_down;
|
||||||
|
u32 vref_num;
|
||||||
|
u32 training_mod_num;
|
||||||
|
u32 dram_timing_num;
|
||||||
|
|
||||||
|
ptfv_list_table_t ptfv_list;
|
||||||
|
|
||||||
|
burst_regs_t burst_regs;
|
||||||
|
burst_reg_per_ch_t burst_reg_per_ch;
|
||||||
|
burst_regs_t shadow_regs_ca_train;
|
||||||
|
burst_regs_t shadow_regs_quse_train;
|
||||||
|
burst_regs_t shadow_regs_rdwr_train;
|
||||||
|
trim_regs_t trim_regs;
|
||||||
|
trim_perch_regs_t trim_perch_regs;
|
||||||
|
vref_perch_regs_t vref_perch_regs;
|
||||||
|
dram_timings_t dram_timings;
|
||||||
|
|
||||||
|
u32 training_mod_regs[20];
|
||||||
|
u32 save_restore_mod_regs[12];
|
||||||
|
u32 burst_mc_regs[33];
|
||||||
|
u32 la_scale_regs[24];
|
||||||
|
|
||||||
|
u32 min_mrs_wait;
|
||||||
|
u32 emc_mrw;
|
||||||
|
u32 emc_mrw2;
|
||||||
|
u32 emc_mrw3;
|
||||||
|
u32 emc_mrw4;
|
||||||
|
u32 emc_mrw9;
|
||||||
|
u32 emc_mrs;
|
||||||
|
u32 emc_emrs;
|
||||||
|
u32 emc_emrs2;
|
||||||
|
u32 emc_auto_cal_config;
|
||||||
|
u32 emc_auto_cal_config2;
|
||||||
|
u32 emc_auto_cal_config3;
|
||||||
|
u32 emc_auto_cal_config4;
|
||||||
|
u32 emc_auto_cal_config5;
|
||||||
|
u32 emc_auto_cal_config6;
|
||||||
|
u32 emc_auto_cal_config7;
|
||||||
|
u32 emc_auto_cal_config8;
|
||||||
|
u32 emc_cfg_2;
|
||||||
|
u32 emc_sel_dpd_ctrl;
|
||||||
|
u32 emc_fdpd_ctrl_cmd_no_ramp;
|
||||||
|
u32 dll_clk_src;
|
||||||
|
u32 clk_out_enb_x_0_clk_enb_emc_dll;
|
||||||
|
u32 latency;
|
||||||
|
} emc_table_t;
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2018 naehrwert
|
* Copyright (c) 2018 naehrwert
|
||||||
* Copyright (c) 2018 balika011
|
* Copyright (c) 2018 balika011
|
||||||
* Copyright (c) 2019 CTCaer
|
* Copyright (c) 2019-2020 CTCaer
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
* under the terms and conditions of the GNU General Public License,
|
* under the terms and conditions of the GNU General Public License,
|
||||||
@@ -16,19 +16,22 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "../soc/i2c.h"
|
#include <string.h>
|
||||||
#include "../soc/t210.h"
|
|
||||||
#include "mc.h"
|
#include "mc.h"
|
||||||
#include "emc.h"
|
#include "emc.h"
|
||||||
#include "sdram_param_t210.h"
|
#include "sdram_param_t210.h"
|
||||||
#include "../soc/pmc.h"
|
#include "../../common/memory_map.h"
|
||||||
#include "../utils/util.h"
|
|
||||||
#include "../soc/fuse.h"
|
|
||||||
#include "../power/max77620.h"
|
#include "../power/max77620.h"
|
||||||
#include "../power/max7762x.h"
|
#include "../power/max7762x.h"
|
||||||
#include "../soc/clock.h"
|
#include "../soc/clock.h"
|
||||||
|
#include "../soc/fuse.h"
|
||||||
|
#include "../soc/i2c.h"
|
||||||
|
#include "../soc/pmc.h"
|
||||||
|
#include "../soc/t210.h"
|
||||||
|
#include "../utils/util.h"
|
||||||
|
|
||||||
#define CONFIG_SDRAM_COMPRESS_CFG
|
#define CONFIG_SDRAM_KEEP_ALIVE
|
||||||
|
|
||||||
#ifdef CONFIG_SDRAM_COMPRESS_CFG
|
#ifdef CONFIG_SDRAM_COMPRESS_CFG
|
||||||
#include "../libs/compr/lz.h"
|
#include "../libs/compr/lz.h"
|
||||||
@@ -39,25 +42,91 @@
|
|||||||
|
|
||||||
static u32 _get_sdram_id()
|
static u32 _get_sdram_id()
|
||||||
{
|
{
|
||||||
return (fuse_read_odm(4) & 0x38) >> 3;
|
return ((fuse_read_odm(4) & 0x38) >> 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool _sdram_wait_emc_status(u32 reg_offset, u32 bit_mask, bool updated_state, s32 emc_channel)
|
||||||
|
{
|
||||||
|
bool err = true;
|
||||||
|
|
||||||
|
for (s32 i = 0; i < EMC_STATUS_UPDATE_TIMEOUT; i++)
|
||||||
|
{
|
||||||
|
if (emc_channel)
|
||||||
|
{
|
||||||
|
if (emc_channel != 1)
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
if (((EMC_CH1(reg_offset) & bit_mask) != 0) == updated_state)
|
||||||
|
{
|
||||||
|
err = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (((EMC(reg_offset) & bit_mask) != 0) == updated_state)
|
||||||
|
{
|
||||||
|
err = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
usleep(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
done:
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _sdram_req_mrr_data(u32 data, bool dual_channel)
|
||||||
|
{
|
||||||
|
EMC(EMC_MRR) = data;
|
||||||
|
_sdram_wait_emc_status(EMC_EMC_STATUS, EMC_STATUS_MRR_DIVLD, true, EMC_CHAN0);
|
||||||
|
if (dual_channel)
|
||||||
|
_sdram_wait_emc_status(EMC_EMC_STATUS, EMC_STATUS_MRR_DIVLD, true, EMC_CHAN1);
|
||||||
|
}
|
||||||
|
|
||||||
|
emc_mr_data_t sdram_read_mrx(emc_mr_t mrx)
|
||||||
|
{
|
||||||
|
emc_mr_data_t data;
|
||||||
|
_sdram_req_mrr_data((1 << 31) | (mrx << 16), EMC_CHAN0);
|
||||||
|
data.dev0_ch0 = EMC(EMC_MRR) & 0xFF;
|
||||||
|
data.dev0_ch1 = (EMC(EMC_MRR) & 0xFF00 >> 8);
|
||||||
|
_sdram_req_mrr_data((1 << 30) | (mrx << 16), EMC_CHAN1);
|
||||||
|
data.dev1_ch0 = EMC(EMC_MRR) & 0xFF;
|
||||||
|
data.dev1_ch1 = (EMC(EMC_MRR) & 0xFF00 >> 8);
|
||||||
|
|
||||||
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _sdram_config(const sdram_params_t *params)
|
static void _sdram_config(const sdram_params_t *params)
|
||||||
{
|
{
|
||||||
PMC(APBDEV_PMC_IO_DPD3_REQ) = (((4 * params->emc_pmc_scratch1 >> 2) + 0x80000000) ^ 0xFFFF) & 0xC000FFFF;
|
// Program DPD3/DPD4 regs (coldboot path).
|
||||||
|
// Enable sel_dpd on unused pins.
|
||||||
|
u32 dpd_req = (params->emc_pmc_scratch1 & 0x3FFFFFFF) | 0x80000000;
|
||||||
|
PMC(APBDEV_PMC_IO_DPD3_REQ) = (dpd_req ^ 0xFFFF) & 0xC000FFFF;
|
||||||
usleep(params->pmc_io_dpd3_req_wait);
|
usleep(params->pmc_io_dpd3_req_wait);
|
||||||
|
|
||||||
u32 req = (4 * params->emc_pmc_scratch2 >> 2) + 0x80000000;
|
// Disable e_dpd_vttgen.
|
||||||
PMC(APBDEV_PMC_IO_DPD4_REQ) = (req >> 16 << 16) ^ 0x3FFF0000;
|
dpd_req = (params->emc_pmc_scratch2 & 0x3FFFFFFF) | 0x80000000;
|
||||||
|
PMC(APBDEV_PMC_IO_DPD4_REQ) = (dpd_req & 0xFFFF0000) ^ 0x3FFF0000;
|
||||||
usleep(params->pmc_io_dpd4_req_wait);
|
usleep(params->pmc_io_dpd4_req_wait);
|
||||||
PMC(APBDEV_PMC_IO_DPD4_REQ) = (req ^ 0xFFFF) & 0xC000FFFF;
|
|
||||||
|
// Disable e_dpd_bg.
|
||||||
|
PMC(APBDEV_PMC_IO_DPD4_REQ) = (dpd_req ^ 0xFFFF) & 0xC000FFFF;
|
||||||
usleep(params->pmc_io_dpd4_req_wait);
|
usleep(params->pmc_io_dpd4_req_wait);
|
||||||
|
|
||||||
PMC(APBDEV_PMC_WEAK_BIAS) = 0;
|
PMC(APBDEV_PMC_WEAK_BIAS) = 0;
|
||||||
usleep(1);
|
usleep(1);
|
||||||
|
|
||||||
|
// Start clocks.
|
||||||
CLOCK(CLK_RST_CONTROLLER_PLLM_MISC1) = params->pllm_setup_control;
|
CLOCK(CLK_RST_CONTROLLER_PLLM_MISC1) = params->pllm_setup_control;
|
||||||
CLOCK(CLK_RST_CONTROLLER_PLLM_MISC2) = 0;
|
CLOCK(CLK_RST_CONTROLLER_PLLM_MISC2) = 0;
|
||||||
CLOCK(CLK_RST_CONTROLLER_PLLM_BASE) = (params->pllm_feedback_divider << 8) | params->pllm_input_divider | 0x40000000 | ((params->pllm_post_divider & 0xFFFF) << 20);
|
|
||||||
|
#ifdef CONFIG_SDRAM_KEEP_ALIVE
|
||||||
|
CLOCK(CLK_RST_CONTROLLER_PLLM_BASE) =
|
||||||
|
(params->pllm_feedback_divider << 8) | params->pllm_input_divider | ((params->pllm_post_divider & 0xFFFF) << 20) | PLLCX_BASE_ENABLE;
|
||||||
|
#else
|
||||||
|
u32 pllm_div = (params->pllm_feedback_divider << 8) | params->pllm_input_divider | ((params->pllm_post_divider & 0xFFFF) << 20);
|
||||||
|
CLOCK(CLK_RST_CONTROLLER_PLLM_BASE) = pllm_div;
|
||||||
|
CLOCK(CLK_RST_CONTROLLER_PLLM_BASE) = pllm_div | PLLCX_BASE_ENABLE;
|
||||||
|
#endif
|
||||||
|
|
||||||
u32 wait_end = get_tmr_us() + 300;
|
u32 wait_end = get_tmr_us() + 300;
|
||||||
while (!(CLOCK(CLK_RST_CONTROLLER_PLLM_BASE) & 0x8000000))
|
while (!(CLOCK(CLK_RST_CONTROLLER_PLLM_BASE) & 0x8000000))
|
||||||
@@ -66,24 +135,35 @@ static void _sdram_config(const sdram_params_t *params)
|
|||||||
goto break_nosleep;
|
goto break_nosleep;
|
||||||
}
|
}
|
||||||
usleep(10);
|
usleep(10);
|
||||||
break_nosleep:
|
|
||||||
|
|
||||||
|
break_nosleep:
|
||||||
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC) = ((params->mc_emem_arb_misc0 >> 11) & 0x10000) | (params->emc_clock_source & 0xFFFEFFFF);
|
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC) = ((params->mc_emem_arb_misc0 >> 11) & 0x10000) | (params->emc_clock_source & 0xFFFEFFFF);
|
||||||
if (params->emc_clock_source_dll)
|
if (params->emc_clock_source_dll)
|
||||||
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC_DLL) = params->emc_clock_source_dll;
|
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_EMC_DLL) = params->emc_clock_source_dll;
|
||||||
if (params->clear_clock2_mc1)
|
if (params->clear_clock2_mc1)
|
||||||
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_W_CLR) = 0x40000000;
|
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_W_CLR) = 0x40000000; // Clear Reset to MC1.
|
||||||
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) = 0x2000001;
|
|
||||||
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_X_SET) = 0x4000;
|
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_H_SET) = 0x2000001; // Enable EMC and MEM clocks.
|
||||||
CLOCK(CLK_RST_CONTROLLER_RST_DEV_H_CLR) = 0x2000001;
|
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_X_SET) = 0x4000; // Enable EMC_DLL clock.
|
||||||
|
CLOCK(CLK_RST_CONTROLLER_RST_DEV_H_CLR) = 0x2000001; // Clear EMC and MEM resets.
|
||||||
|
|
||||||
|
// Set pad macros.
|
||||||
EMC(EMC_PMACRO_VTTGEN_CTRL_0) = params->emc_pmacro_vttgen_ctrl0;
|
EMC(EMC_PMACRO_VTTGEN_CTRL_0) = params->emc_pmacro_vttgen_ctrl0;
|
||||||
EMC(EMC_PMACRO_VTTGEN_CTRL_1) = params->emc_pmacro_vttgen_ctrl1;
|
EMC(EMC_PMACRO_VTTGEN_CTRL_1) = params->emc_pmacro_vttgen_ctrl1;
|
||||||
EMC(EMC_PMACRO_VTTGEN_CTRL_2) = params->emc_pmacro_vttgen_ctrl2;
|
EMC(EMC_PMACRO_VTTGEN_CTRL_2) = params->emc_pmacro_vttgen_ctrl2;
|
||||||
EMC(EMC_TIMING_CONTROL) = 1;
|
|
||||||
usleep(1);
|
EMC(EMC_TIMING_CONTROL) = 1; // Trigger timing update so above writes take place.
|
||||||
|
usleep(10); // Ensure the regulators settle.
|
||||||
|
|
||||||
|
// Select EMC write mux.
|
||||||
EMC(EMC_DBG) = (params->emc_dbg_write_mux << 1) | params->emc_dbg;
|
EMC(EMC_DBG) = (params->emc_dbg_write_mux << 1) | params->emc_dbg;
|
||||||
|
|
||||||
|
// Patch 2 using BCT spare variables.
|
||||||
if (params->emc_bct_spare2)
|
if (params->emc_bct_spare2)
|
||||||
*(vu32 *)params->emc_bct_spare2 = params->emc_bct_spare3;
|
*(vu32 *)params->emc_bct_spare2 = params->emc_bct_spare3;
|
||||||
|
|
||||||
|
// Program CMD mapping. Required before brick mapping, else
|
||||||
|
// we can't guarantee CK will be differential at all times.
|
||||||
EMC(EMC_FBIO_CFG7) = params->emc_fbio_cfg7;
|
EMC(EMC_FBIO_CFG7) = params->emc_fbio_cfg7;
|
||||||
EMC(EMC_CMD_MAPPING_CMD0_0) = params->emc_cmd_mapping_cmd0_0;
|
EMC(EMC_CMD_MAPPING_CMD0_0) = params->emc_cmd_mapping_cmd0_0;
|
||||||
EMC(EMC_CMD_MAPPING_CMD0_1) = params->emc_cmd_mapping_cmd0_1;
|
EMC(EMC_CMD_MAPPING_CMD0_1) = params->emc_cmd_mapping_cmd0_1;
|
||||||
@@ -98,25 +178,40 @@ break_nosleep:
|
|||||||
EMC(EMC_CMD_MAPPING_CMD3_1) = params->emc_cmd_mapping_cmd3_1;
|
EMC(EMC_CMD_MAPPING_CMD3_1) = params->emc_cmd_mapping_cmd3_1;
|
||||||
EMC(EMC_CMD_MAPPING_CMD3_2) = params->emc_cmd_mapping_cmd3_2;
|
EMC(EMC_CMD_MAPPING_CMD3_2) = params->emc_cmd_mapping_cmd3_2;
|
||||||
EMC(EMC_CMD_MAPPING_BYTE) = params->emc_cmd_mapping_byte;
|
EMC(EMC_CMD_MAPPING_BYTE) = params->emc_cmd_mapping_byte;
|
||||||
|
|
||||||
|
// Program brick mapping.
|
||||||
EMC(EMC_PMACRO_BRICK_MAPPING_0) = params->emc_pmacro_brick_mapping0;
|
EMC(EMC_PMACRO_BRICK_MAPPING_0) = params->emc_pmacro_brick_mapping0;
|
||||||
EMC(EMC_PMACRO_BRICK_MAPPING_1) = params->emc_pmacro_brick_mapping1;
|
EMC(EMC_PMACRO_BRICK_MAPPING_1) = params->emc_pmacro_brick_mapping1;
|
||||||
EMC(EMC_PMACRO_BRICK_MAPPING_2) = params->emc_pmacro_brick_mapping2;
|
EMC(EMC_PMACRO_BRICK_MAPPING_2) = params->emc_pmacro_brick_mapping2;
|
||||||
|
|
||||||
EMC(EMC_PMACRO_BRICK_CTRL_RFU1) = (params->emc_pmacro_brick_ctrl_rfu1 & 0x1120112) | 0x1EED1EED;
|
EMC(EMC_PMACRO_BRICK_CTRL_RFU1) = (params->emc_pmacro_brick_ctrl_rfu1 & 0x1120112) | 0x1EED1EED;
|
||||||
|
|
||||||
|
// This is required to do any reads from the pad macros.
|
||||||
EMC(EMC_CONFIG_SAMPLE_DELAY) = params->emc_config_sample_delay;
|
EMC(EMC_CONFIG_SAMPLE_DELAY) = params->emc_config_sample_delay;
|
||||||
|
|
||||||
EMC(EMC_FBIO_CFG8) = params->emc_fbio_cfg8;
|
EMC(EMC_FBIO_CFG8) = params->emc_fbio_cfg8;
|
||||||
|
|
||||||
|
// Set swizzle for Rank 0.
|
||||||
EMC(EMC_SWIZZLE_RANK0_BYTE0) = params->emc_swizzle_rank0_byte0;
|
EMC(EMC_SWIZZLE_RANK0_BYTE0) = params->emc_swizzle_rank0_byte0;
|
||||||
EMC(EMC_SWIZZLE_RANK0_BYTE1) = params->emc_swizzle_rank0_byte1;
|
EMC(EMC_SWIZZLE_RANK0_BYTE1) = params->emc_swizzle_rank0_byte1;
|
||||||
EMC(EMC_SWIZZLE_RANK0_BYTE2) = params->emc_swizzle_rank0_byte2;
|
EMC(EMC_SWIZZLE_RANK0_BYTE2) = params->emc_swizzle_rank0_byte2;
|
||||||
EMC(EMC_SWIZZLE_RANK0_BYTE3) = params->emc_swizzle_rank0_byte3;
|
EMC(EMC_SWIZZLE_RANK0_BYTE3) = params->emc_swizzle_rank0_byte3;
|
||||||
|
// Set swizzle for Rank 1.
|
||||||
EMC(EMC_SWIZZLE_RANK1_BYTE0) = params->emc_swizzle_rank1_byte0;
|
EMC(EMC_SWIZZLE_RANK1_BYTE0) = params->emc_swizzle_rank1_byte0;
|
||||||
EMC(EMC_SWIZZLE_RANK1_BYTE1) = params->emc_swizzle_rank1_byte1;
|
EMC(EMC_SWIZZLE_RANK1_BYTE1) = params->emc_swizzle_rank1_byte1;
|
||||||
EMC(EMC_SWIZZLE_RANK1_BYTE2) = params->emc_swizzle_rank1_byte2;
|
EMC(EMC_SWIZZLE_RANK1_BYTE2) = params->emc_swizzle_rank1_byte2;
|
||||||
EMC(EMC_SWIZZLE_RANK1_BYTE3) = params->emc_swizzle_rank1_byte3;
|
EMC(EMC_SWIZZLE_RANK1_BYTE3) = params->emc_swizzle_rank1_byte3;
|
||||||
|
|
||||||
|
// Patch 4 using BCT spare variables.
|
||||||
if (params->emc_bct_spare6)
|
if (params->emc_bct_spare6)
|
||||||
*(vu32 *)params->emc_bct_spare6 = params->emc_bct_spare7;
|
*(vu32 *)params->emc_bct_spare6 = params->emc_bct_spare7;
|
||||||
|
|
||||||
|
// Set pad controls.
|
||||||
EMC(EMC_XM2COMPPADCTRL) = params->emc_xm2_comp_pad_ctrl;
|
EMC(EMC_XM2COMPPADCTRL) = params->emc_xm2_comp_pad_ctrl;
|
||||||
EMC(EMC_XM2COMPPADCTRL2) = params->emc_xm2_comp_pad_ctrl2;
|
EMC(EMC_XM2COMPPADCTRL2) = params->emc_xm2_comp_pad_ctrl2;
|
||||||
EMC(EMC_XM2COMPPADCTRL3) = params->emc_xm2_comp_pad_ctrl3;
|
EMC(EMC_XM2COMPPADCTRL3) = params->emc_xm2_comp_pad_ctrl3;
|
||||||
|
|
||||||
|
// Program Autocal controls with shadowed register fields.
|
||||||
EMC(EMC_AUTO_CAL_CONFIG2) = params->emc_auto_cal_config2;
|
EMC(EMC_AUTO_CAL_CONFIG2) = params->emc_auto_cal_config2;
|
||||||
EMC(EMC_AUTO_CAL_CONFIG3) = params->emc_auto_cal_config3;
|
EMC(EMC_AUTO_CAL_CONFIG3) = params->emc_auto_cal_config3;
|
||||||
EMC(EMC_AUTO_CAL_CONFIG4) = params->emc_auto_cal_config4;
|
EMC(EMC_AUTO_CAL_CONFIG4) = params->emc_auto_cal_config4;
|
||||||
@@ -124,6 +219,7 @@ break_nosleep:
|
|||||||
EMC(EMC_AUTO_CAL_CONFIG6) = params->emc_auto_cal_config6;
|
EMC(EMC_AUTO_CAL_CONFIG6) = params->emc_auto_cal_config6;
|
||||||
EMC(EMC_AUTO_CAL_CONFIG7) = params->emc_auto_cal_config7;
|
EMC(EMC_AUTO_CAL_CONFIG7) = params->emc_auto_cal_config7;
|
||||||
EMC(EMC_AUTO_CAL_CONFIG8) = params->emc_auto_cal_config8;
|
EMC(EMC_AUTO_CAL_CONFIG8) = params->emc_auto_cal_config8;
|
||||||
|
|
||||||
EMC(EMC_PMACRO_RX_TERM) = params->emc_pmacro_rx_term;
|
EMC(EMC_PMACRO_RX_TERM) = params->emc_pmacro_rx_term;
|
||||||
EMC(EMC_PMACRO_DQ_TX_DRV) = params->emc_pmacro_dq_tx_drive;
|
EMC(EMC_PMACRO_DQ_TX_DRV) = params->emc_pmacro_dq_tx_drive;
|
||||||
EMC(EMC_PMACRO_CA_TX_DRV) = params->emc_pmacro_ca_tx_drive;
|
EMC(EMC_PMACRO_CA_TX_DRV) = params->emc_pmacro_ca_tx_drive;
|
||||||
@@ -131,9 +227,11 @@ break_nosleep:
|
|||||||
EMC(EMC_PMACRO_AUTOCAL_CFG_COMMON) = params->emc_pmacro_auto_cal_common;
|
EMC(EMC_PMACRO_AUTOCAL_CFG_COMMON) = params->emc_pmacro_auto_cal_common;
|
||||||
EMC(EMC_AUTO_CAL_CHANNEL) = params->emc_auto_cal_channel;
|
EMC(EMC_AUTO_CAL_CHANNEL) = params->emc_auto_cal_channel;
|
||||||
EMC(EMC_PMACRO_ZCTRL) = params->emc_pmacro_zcrtl;
|
EMC(EMC_PMACRO_ZCTRL) = params->emc_pmacro_zcrtl;
|
||||||
|
|
||||||
EMC(EMC_DLL_CFG_0) = params->emc_dll_cfg0;
|
EMC(EMC_DLL_CFG_0) = params->emc_dll_cfg0;
|
||||||
EMC(EMC_DLL_CFG_1) = params->emc_dll_cfg1;
|
EMC(EMC_DLL_CFG_1) = params->emc_dll_cfg1;
|
||||||
EMC(EMC_CFG_DIG_DLL_1) = params->emc_cfg_dig_dll_1;
|
EMC(EMC_CFG_DIG_DLL_1) = params->emc_cfg_dig_dll_1;
|
||||||
|
|
||||||
EMC(EMC_DATA_BRLSHFT_0) = params->emc_data_brlshft0;
|
EMC(EMC_DATA_BRLSHFT_0) = params->emc_data_brlshft0;
|
||||||
EMC(EMC_DATA_BRLSHFT_1) = params->emc_data_brlshft1;
|
EMC(EMC_DATA_BRLSHFT_1) = params->emc_data_brlshft1;
|
||||||
EMC(EMC_DQS_BRLSHFT_0) = params->emc_dqs_brlshft0;
|
EMC(EMC_DQS_BRLSHFT_0) = params->emc_dqs_brlshft0;
|
||||||
@@ -146,8 +244,10 @@ break_nosleep:
|
|||||||
EMC(EMC_QUSE_BRLSHFT_1) = params->emc_quse_brlshft1;
|
EMC(EMC_QUSE_BRLSHFT_1) = params->emc_quse_brlshft1;
|
||||||
EMC(EMC_QUSE_BRLSHFT_2) = params->emc_quse_brlshft2;
|
EMC(EMC_QUSE_BRLSHFT_2) = params->emc_quse_brlshft2;
|
||||||
EMC(EMC_QUSE_BRLSHFT_3) = params->emc_quse_brlshft3;
|
EMC(EMC_QUSE_BRLSHFT_3) = params->emc_quse_brlshft3;
|
||||||
|
|
||||||
EMC(EMC_PMACRO_BRICK_CTRL_RFU1) = (params->emc_pmacro_brick_ctrl_rfu1 & 0x1BF01BF) | 0x1E401E40;
|
EMC(EMC_PMACRO_BRICK_CTRL_RFU1) = (params->emc_pmacro_brick_ctrl_rfu1 & 0x1BF01BF) | 0x1E401E40;
|
||||||
EMC(EMC_PMACRO_PAD_CFG_CTRL) = params->emc_pmacro_pad_cfg_ctrl;
|
EMC(EMC_PMACRO_PAD_CFG_CTRL) = params->emc_pmacro_pad_cfg_ctrl;
|
||||||
|
|
||||||
EMC(EMC_PMACRO_CMD_BRICK_CTRL_FDPD) = params->emc_pmacro_cmd_brick_ctrl_fdpd;
|
EMC(EMC_PMACRO_CMD_BRICK_CTRL_FDPD) = params->emc_pmacro_cmd_brick_ctrl_fdpd;
|
||||||
EMC(EMC_PMACRO_BRICK_CTRL_RFU2) = params->emc_pmacro_brick_ctrl_rfu2 & 0xFF7FFF7F;
|
EMC(EMC_PMACRO_BRICK_CTRL_RFU2) = params->emc_pmacro_brick_ctrl_rfu2 & 0xFF7FFF7F;
|
||||||
EMC(EMC_PMACRO_DATA_BRICK_CTRL_FDPD) = params->emc_pmacro_data_brick_ctrl_fdpd;
|
EMC(EMC_PMACRO_DATA_BRICK_CTRL_FDPD) = params->emc_pmacro_data_brick_ctrl_fdpd;
|
||||||
@@ -158,6 +258,7 @@ break_nosleep:
|
|||||||
EMC(EMC_PMACRO_DATA_RX_TERM_MODE) = params->emc_pmacro_data_rx_term_mode;
|
EMC(EMC_PMACRO_DATA_RX_TERM_MODE) = params->emc_pmacro_data_rx_term_mode;
|
||||||
EMC(EMC_PMACRO_CMD_RX_TERM_MODE) = params->emc_pmacro_cmd_rx_term_mode;
|
EMC(EMC_PMACRO_CMD_RX_TERM_MODE) = params->emc_pmacro_cmd_rx_term_mode;
|
||||||
EMC(EMC_PMACRO_CMD_PAD_TX_CTRL) = params->emc_pmacro_cmd_pad_tx_ctrl;
|
EMC(EMC_PMACRO_CMD_PAD_TX_CTRL) = params->emc_pmacro_cmd_pad_tx_ctrl;
|
||||||
|
|
||||||
EMC(EMC_CFG_3) = params->emc_cfg3;
|
EMC(EMC_CFG_3) = params->emc_cfg3;
|
||||||
EMC(EMC_PMACRO_TX_PWRD_0) = params->emc_pmacro_tx_pwrd0;
|
EMC(EMC_PMACRO_TX_PWRD_0) = params->emc_pmacro_tx_pwrd0;
|
||||||
EMC(EMC_PMACRO_TX_PWRD_1) = params->emc_pmacro_tx_pwrd1;
|
EMC(EMC_PMACRO_TX_PWRD_1) = params->emc_pmacro_tx_pwrd1;
|
||||||
@@ -183,6 +284,7 @@ break_nosleep:
|
|||||||
EMC(EMC_PMACRO_IB_VREF_DQS_0) = params->emc_pmacro_ib_vref_dqs_0;
|
EMC(EMC_PMACRO_IB_VREF_DQS_0) = params->emc_pmacro_ib_vref_dqs_0;
|
||||||
EMC(EMC_PMACRO_IB_VREF_DQS_1) = params->emc_pmacro_ib_vref_dqs_1;
|
EMC(EMC_PMACRO_IB_VREF_DQS_1) = params->emc_pmacro_ib_vref_dqs_1;
|
||||||
EMC(EMC_PMACRO_IB_RXRT) = params->emc_pmacro_ib_rxrt;
|
EMC(EMC_PMACRO_IB_RXRT) = params->emc_pmacro_ib_rxrt;
|
||||||
|
|
||||||
EMC(EMC_PMACRO_QUSE_DDLL_RANK0_0) = params->emc_pmacro_quse_ddll_rank0_0;
|
EMC(EMC_PMACRO_QUSE_DDLL_RANK0_0) = params->emc_pmacro_quse_ddll_rank0_0;
|
||||||
EMC(EMC_PMACRO_QUSE_DDLL_RANK0_1) = params->emc_pmacro_quse_ddll_rank0_1;
|
EMC(EMC_PMACRO_QUSE_DDLL_RANK0_1) = params->emc_pmacro_quse_ddll_rank0_1;
|
||||||
EMC(EMC_PMACRO_QUSE_DDLL_RANK0_2) = params->emc_pmacro_quse_ddll_rank0_2;
|
EMC(EMC_PMACRO_QUSE_DDLL_RANK0_2) = params->emc_pmacro_quse_ddll_rank0_2;
|
||||||
@@ -196,6 +298,7 @@ break_nosleep:
|
|||||||
EMC(EMC_PMACRO_QUSE_DDLL_RANK1_4) = params->emc_pmacro_quse_ddll_rank1_4;
|
EMC(EMC_PMACRO_QUSE_DDLL_RANK1_4) = params->emc_pmacro_quse_ddll_rank1_4;
|
||||||
EMC(EMC_PMACRO_QUSE_DDLL_RANK1_5) = params->emc_pmacro_quse_ddll_rank1_5;
|
EMC(EMC_PMACRO_QUSE_DDLL_RANK1_5) = params->emc_pmacro_quse_ddll_rank1_5;
|
||||||
EMC(EMC_PMACRO_BRICK_CTRL_RFU1) = params->emc_pmacro_brick_ctrl_rfu1;
|
EMC(EMC_PMACRO_BRICK_CTRL_RFU1) = params->emc_pmacro_brick_ctrl_rfu1;
|
||||||
|
|
||||||
EMC(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_0) = params->emc_pmacro_ob_ddll_long_dq_rank0_0;
|
EMC(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_0) = params->emc_pmacro_ob_ddll_long_dq_rank0_0;
|
||||||
EMC(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_1) = params->emc_pmacro_ob_ddll_long_dq_rank0_1;
|
EMC(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_1) = params->emc_pmacro_ob_ddll_long_dq_rank0_1;
|
||||||
EMC(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_2) = params->emc_pmacro_ob_ddll_long_dq_rank0_2;
|
EMC(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_2) = params->emc_pmacro_ob_ddll_long_dq_rank0_2;
|
||||||
@@ -208,6 +311,7 @@ break_nosleep:
|
|||||||
EMC(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_3) = params->emc_pmacro_ob_ddll_long_dq_rank1_3;
|
EMC(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_3) = params->emc_pmacro_ob_ddll_long_dq_rank1_3;
|
||||||
EMC(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_4) = params->emc_pmacro_ob_ddll_long_dq_rank1_4;
|
EMC(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_4) = params->emc_pmacro_ob_ddll_long_dq_rank1_4;
|
||||||
EMC(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_5) = params->emc_pmacro_ob_ddll_long_dq_rank1_5;
|
EMC(EMC_PMACRO_OB_DDLL_LONG_DQ_RANK1_5) = params->emc_pmacro_ob_ddll_long_dq_rank1_5;
|
||||||
|
|
||||||
EMC(EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_0) = params->emc_pmacro_ob_ddll_long_dqs_rank0_0;
|
EMC(EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_0) = params->emc_pmacro_ob_ddll_long_dqs_rank0_0;
|
||||||
EMC(EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_1) = params->emc_pmacro_ob_ddll_long_dqs_rank0_1;
|
EMC(EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_1) = params->emc_pmacro_ob_ddll_long_dqs_rank0_1;
|
||||||
EMC(EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_2) = params->emc_pmacro_ob_ddll_long_dqs_rank0_2;
|
EMC(EMC_PMACRO_OB_DDLL_LONG_DQS_RANK0_2) = params->emc_pmacro_ob_ddll_long_dqs_rank0_2;
|
||||||
@@ -228,6 +332,7 @@ break_nosleep:
|
|||||||
EMC(EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_1) = params->emc_pmacro_ib_ddll_long_dqs_rank1_1;
|
EMC(EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_1) = params->emc_pmacro_ib_ddll_long_dqs_rank1_1;
|
||||||
EMC(EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_2) = params->emc_pmacro_ib_ddll_long_dqs_rank1_2;
|
EMC(EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_2) = params->emc_pmacro_ib_ddll_long_dqs_rank1_2;
|
||||||
EMC(EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_3) = params->emc_pmacro_ib_ddll_long_dqs_rank1_3;
|
EMC(EMC_PMACRO_IB_DDLL_LONG_DQS_RANK1_3) = params->emc_pmacro_ib_ddll_long_dqs_rank1_3;
|
||||||
|
|
||||||
EMC(EMC_PMACRO_DDLL_LONG_CMD_0) = params->emc_pmacro_ddll_long_cmd_0;
|
EMC(EMC_PMACRO_DDLL_LONG_CMD_0) = params->emc_pmacro_ddll_long_cmd_0;
|
||||||
EMC(EMC_PMACRO_DDLL_LONG_CMD_1) = params->emc_pmacro_ddll_long_cmd_1;
|
EMC(EMC_PMACRO_DDLL_LONG_CMD_1) = params->emc_pmacro_ddll_long_cmd_1;
|
||||||
EMC(EMC_PMACRO_DDLL_LONG_CMD_2) = params->emc_pmacro_ddll_long_cmd_2;
|
EMC(EMC_PMACRO_DDLL_LONG_CMD_2) = params->emc_pmacro_ddll_long_cmd_2;
|
||||||
@@ -236,10 +341,17 @@ break_nosleep:
|
|||||||
EMC(EMC_PMACRO_DDLL_SHORT_CMD_0) = params->emc_pmacro_ddll_short_cmd_0;
|
EMC(EMC_PMACRO_DDLL_SHORT_CMD_0) = params->emc_pmacro_ddll_short_cmd_0;
|
||||||
EMC(EMC_PMACRO_DDLL_SHORT_CMD_1) = params->emc_pmacro_ddll_short_cmd_1;
|
EMC(EMC_PMACRO_DDLL_SHORT_CMD_1) = params->emc_pmacro_ddll_short_cmd_1;
|
||||||
EMC(EMC_PMACRO_DDLL_SHORT_CMD_2) = params->emc_pmacro_ddll_short_cmd_2;
|
EMC(EMC_PMACRO_DDLL_SHORT_CMD_2) = params->emc_pmacro_ddll_short_cmd_2;
|
||||||
|
|
||||||
|
// Common pad macro (cpm).
|
||||||
EMC(EMC_PMACRO_COMMON_PAD_TX_CTRL) = (params->emc_pmacro_common_pad_tx_ctrl & 1) | 0xE;
|
EMC(EMC_PMACRO_COMMON_PAD_TX_CTRL) = (params->emc_pmacro_common_pad_tx_ctrl & 1) | 0xE;
|
||||||
|
|
||||||
|
// Patch 3 using BCT spare variables.
|
||||||
if (params->emc_bct_spare4)
|
if (params->emc_bct_spare4)
|
||||||
*(vu32 *)params->emc_bct_spare4 = params->emc_bct_spare5;
|
*(vu32 *)params->emc_bct_spare4 = params->emc_bct_spare5;
|
||||||
EMC(EMC_TIMING_CONTROL) = 1;
|
|
||||||
|
EMC(EMC_TIMING_CONTROL) = 1; // Trigger timing update so above writes take place.
|
||||||
|
|
||||||
|
// Initialize MC VPR settings.
|
||||||
MC(MC_VIDEO_PROTECT_BOM) = params->mc_video_protect_bom;
|
MC(MC_VIDEO_PROTECT_BOM) = params->mc_video_protect_bom;
|
||||||
MC(MC_VIDEO_PROTECT_BOM_ADR_HI) = params->mc_video_protect_bom_adr_hi;
|
MC(MC_VIDEO_PROTECT_BOM_ADR_HI) = params->mc_video_protect_bom_adr_hi;
|
||||||
MC(MC_VIDEO_PROTECT_SIZE_MB) = params->mc_video_protect_size_mb;
|
MC(MC_VIDEO_PROTECT_SIZE_MB) = params->mc_video_protect_size_mb;
|
||||||
@@ -247,20 +359,32 @@ break_nosleep:
|
|||||||
MC(MC_VIDEO_PROTECT_VPR_OVERRIDE1) = params->mc_video_protect_vpr_override1;
|
MC(MC_VIDEO_PROTECT_VPR_OVERRIDE1) = params->mc_video_protect_vpr_override1;
|
||||||
MC(MC_VIDEO_PROTECT_GPU_OVERRIDE_0) = params->mc_video_protect_gpu_override0;
|
MC(MC_VIDEO_PROTECT_GPU_OVERRIDE_0) = params->mc_video_protect_gpu_override0;
|
||||||
MC(MC_VIDEO_PROTECT_GPU_OVERRIDE_1) = params->mc_video_protect_gpu_override1;
|
MC(MC_VIDEO_PROTECT_GPU_OVERRIDE_1) = params->mc_video_protect_gpu_override1;
|
||||||
|
|
||||||
|
// Program SDRAM geometry parameters.
|
||||||
MC(MC_EMEM_ADR_CFG) = params->mc_emem_adr_cfg;
|
MC(MC_EMEM_ADR_CFG) = params->mc_emem_adr_cfg;
|
||||||
MC(MC_EMEM_ADR_CFG_DEV0) = params->mc_emem_adr_cfg_dev0;
|
MC(MC_EMEM_ADR_CFG_DEV0) = params->mc_emem_adr_cfg_dev0;
|
||||||
MC(MC_EMEM_ADR_CFG_DEV1) = params->mc_emem_adr_cfg_dev1;
|
MC(MC_EMEM_ADR_CFG_DEV1) = params->mc_emem_adr_cfg_dev1;
|
||||||
MC(MC_EMEM_ADR_CFG_CHANNEL_MASK) = params->mc_emem_adr_cfg_channel_mask;
|
MC(MC_EMEM_ADR_CFG_CHANNEL_MASK) = params->mc_emem_adr_cfg_channel_mask;
|
||||||
|
|
||||||
|
// Program bank swizzling.
|
||||||
MC(MC_EMEM_ADR_CFG_BANK_MASK_0) = params->mc_emem_adr_cfg_bank_mask0;
|
MC(MC_EMEM_ADR_CFG_BANK_MASK_0) = params->mc_emem_adr_cfg_bank_mask0;
|
||||||
MC(MC_EMEM_ADR_CFG_BANK_MASK_1) = params->mc_emem_adr_cfg_bank_mask1;
|
MC(MC_EMEM_ADR_CFG_BANK_MASK_1) = params->mc_emem_adr_cfg_bank_mask1;
|
||||||
MC(MC_EMEM_ADR_CFG_BANK_MASK_2) = params->mc_emem_adr_cfg_bank_mask2;
|
MC(MC_EMEM_ADR_CFG_BANK_MASK_2) = params->mc_emem_adr_cfg_bank_mask2;
|
||||||
|
|
||||||
|
// Program external memory aperture (base and size).
|
||||||
MC(MC_EMEM_CFG) = params->mc_emem_cfg;
|
MC(MC_EMEM_CFG) = params->mc_emem_cfg;
|
||||||
|
|
||||||
|
// Program SEC carveout (base and size).
|
||||||
MC(MC_SEC_CARVEOUT_BOM) = params->mc_sec_carveout_bom;
|
MC(MC_SEC_CARVEOUT_BOM) = params->mc_sec_carveout_bom;
|
||||||
MC(MC_SEC_CARVEOUT_ADR_HI) = params->mc_sec_carveout_adr_hi;
|
MC(MC_SEC_CARVEOUT_ADR_HI) = params->mc_sec_carveout_adr_hi;
|
||||||
MC(MC_SEC_CARVEOUT_SIZE_MB) = params->mc_sec_carveout_size_mb;
|
MC(MC_SEC_CARVEOUT_SIZE_MB) = params->mc_sec_carveout_size_mb;
|
||||||
|
|
||||||
|
// Program MTS carveout (base and size).
|
||||||
MC(MC_MTS_CARVEOUT_BOM) = params->mc_mts_carveout_bom;
|
MC(MC_MTS_CARVEOUT_BOM) = params->mc_mts_carveout_bom;
|
||||||
MC(MC_MTS_CARVEOUT_ADR_HI) = params->mc_mts_carveout_adr_hi;
|
MC(MC_MTS_CARVEOUT_ADR_HI) = params->mc_mts_carveout_adr_hi;
|
||||||
MC(MC_MTS_CARVEOUT_SIZE_MB) = params->mc_mts_carveout_size_mb;
|
MC(MC_MTS_CARVEOUT_SIZE_MB) = params->mc_mts_carveout_size_mb;
|
||||||
|
|
||||||
|
// Program the memory arbiter.
|
||||||
MC(MC_EMEM_ARB_CFG) = params->mc_emem_arb_cfg;
|
MC(MC_EMEM_ARB_CFG) = params->mc_emem_arb_cfg;
|
||||||
MC(MC_EMEM_ARB_OUTSTANDING_REQ) = params->mc_emem_arb_outstanding_req;
|
MC(MC_EMEM_ARB_OUTSTANDING_REQ) = params->mc_emem_arb_outstanding_req;
|
||||||
MC(MC_EMEM_ARB_REFPB_HP_CTRL) = params->emc_emem_arb_refpb_hp_ctrl;
|
MC(MC_EMEM_ARB_REFPB_HP_CTRL) = params->emc_emem_arb_refpb_hp_ctrl;
|
||||||
@@ -289,21 +413,38 @@ break_nosleep:
|
|||||||
MC(MC_EMEM_ARB_OVERRIDE_1) = params->mc_emem_arb_override1;
|
MC(MC_EMEM_ARB_OVERRIDE_1) = params->mc_emem_arb_override1;
|
||||||
MC(MC_EMEM_ARB_RSV) = params->mc_emem_arb_rsv;
|
MC(MC_EMEM_ARB_RSV) = params->mc_emem_arb_rsv;
|
||||||
MC(MC_DA_CONFIG0) = params->mc_da_cfg0;
|
MC(MC_DA_CONFIG0) = params->mc_da_cfg0;
|
||||||
MC(MC_TIMING_CONTROL) = 1;
|
|
||||||
|
MC(MC_TIMING_CONTROL) = 1; // Trigger MC timing update.
|
||||||
|
|
||||||
|
// Program second-level clock enable overrides.
|
||||||
MC(MC_CLKEN_OVERRIDE) = params->mc_clken_override;
|
MC(MC_CLKEN_OVERRIDE) = params->mc_clken_override;
|
||||||
|
|
||||||
|
// Program statistics gathering.
|
||||||
MC(MC_STAT_CONTROL) = params->mc_stat_control;
|
MC(MC_STAT_CONTROL) = params->mc_stat_control;
|
||||||
|
|
||||||
|
// Program SDRAM geometry parameters.
|
||||||
EMC(EMC_ADR_CFG) = params->emc_adr_cfg;
|
EMC(EMC_ADR_CFG) = params->emc_adr_cfg;
|
||||||
|
|
||||||
|
// Program second-level clock enable overrides.
|
||||||
EMC(EMC_CLKEN_OVERRIDE) = params->emc_clken_override;
|
EMC(EMC_CLKEN_OVERRIDE) = params->emc_clken_override;
|
||||||
|
|
||||||
|
// Program EMC pad auto calibration.
|
||||||
EMC(EMC_PMACRO_AUTOCAL_CFG_0) = params->emc_pmacro_auto_cal_cfg0;
|
EMC(EMC_PMACRO_AUTOCAL_CFG_0) = params->emc_pmacro_auto_cal_cfg0;
|
||||||
EMC(EMC_PMACRO_AUTOCAL_CFG_1) = params->emc_pmacro_auto_cal_cfg1;
|
EMC(EMC_PMACRO_AUTOCAL_CFG_1) = params->emc_pmacro_auto_cal_cfg1;
|
||||||
EMC(EMC_PMACRO_AUTOCAL_CFG_2) = params->emc_pmacro_auto_cal_cfg2;
|
EMC(EMC_PMACRO_AUTOCAL_CFG_2) = params->emc_pmacro_auto_cal_cfg2;
|
||||||
|
|
||||||
EMC(EMC_AUTO_CAL_VREF_SEL_0) = params->emc_auto_cal_vref_sel0;
|
EMC(EMC_AUTO_CAL_VREF_SEL_0) = params->emc_auto_cal_vref_sel0;
|
||||||
EMC(EMC_AUTO_CAL_VREF_SEL_1) = params->emc_auto_cal_vref_sel1;
|
EMC(EMC_AUTO_CAL_VREF_SEL_1) = params->emc_auto_cal_vref_sel1;
|
||||||
|
|
||||||
EMC(EMC_AUTO_CAL_INTERVAL) = params->emc_auto_cal_interval;
|
EMC(EMC_AUTO_CAL_INTERVAL) = params->emc_auto_cal_interval;
|
||||||
EMC(EMC_AUTO_CAL_CONFIG) = params->emc_auto_cal_config;
|
EMC(EMC_AUTO_CAL_CONFIG) = params->emc_auto_cal_config;
|
||||||
usleep(params->emc_auto_cal_wait);
|
usleep(params->emc_auto_cal_wait);
|
||||||
|
|
||||||
|
// Patch 5 using BCT spare variables.
|
||||||
if (params->emc_bct_spare8)
|
if (params->emc_bct_spare8)
|
||||||
*(vu32 *)params->emc_bct_spare8 = params->emc_bct_spare9;
|
*(vu32 *)params->emc_bct_spare8 = params->emc_bct_spare9;
|
||||||
|
|
||||||
|
// Program EMC timing configuration.
|
||||||
EMC(EMC_CFG_2) = params->emc_cfg2;
|
EMC(EMC_CFG_2) = params->emc_cfg2;
|
||||||
EMC(EMC_CFG_PIPE) = params->emc_cfg_pipe;
|
EMC(EMC_CFG_PIPE) = params->emc_cfg_pipe;
|
||||||
EMC(EMC_CFG_PIPE_1) = params->emc_cfg_pipe1;
|
EMC(EMC_CFG_PIPE_1) = params->emc_cfg_pipe1;
|
||||||
@@ -348,9 +489,11 @@ break_nosleep:
|
|||||||
EMC(EMC_EINPUT_DURATION) = params->emc_einput_duration;
|
EMC(EMC_EINPUT_DURATION) = params->emc_einput_duration;
|
||||||
EMC(EMC_PUTERM_EXTRA) = params->emc_puterm_extra;
|
EMC(EMC_PUTERM_EXTRA) = params->emc_puterm_extra;
|
||||||
EMC(EMC_PUTERM_WIDTH) = params->emc_puterm_width;
|
EMC(EMC_PUTERM_WIDTH) = params->emc_puterm_width;
|
||||||
|
|
||||||
EMC(EMC_PMACRO_COMMON_PAD_TX_CTRL) = params->emc_pmacro_common_pad_tx_ctrl;
|
EMC(EMC_PMACRO_COMMON_PAD_TX_CTRL) = params->emc_pmacro_common_pad_tx_ctrl;
|
||||||
EMC(EMC_DBG) = params->emc_dbg;
|
EMC(EMC_DBG) = params->emc_dbg;
|
||||||
EMC(EMC_QRST) = params->emc_qrst;
|
EMC(EMC_QRST) = params->emc_qrst;
|
||||||
|
EMC(EMC_ISSUE_QRST) = 1;
|
||||||
EMC(EMC_ISSUE_QRST) = 0;
|
EMC(EMC_ISSUE_QRST) = 0;
|
||||||
EMC(EMC_QSAFE) = params->emc_qsafe;
|
EMC(EMC_QSAFE) = params->emc_qsafe;
|
||||||
EMC(EMC_RDV) = params->emc_rdv;
|
EMC(EMC_RDV) = params->emc_rdv;
|
||||||
@@ -383,6 +526,8 @@ break_nosleep:
|
|||||||
EMC(EMC_ODT_WRITE) = params->emc_odt_write;
|
EMC(EMC_ODT_WRITE) = params->emc_odt_write;
|
||||||
EMC(EMC_CFG_DIG_DLL) = params->emc_cfg_dig_dll;
|
EMC(EMC_CFG_DIG_DLL) = params->emc_cfg_dig_dll;
|
||||||
EMC(EMC_CFG_DIG_DLL_PERIOD) = params->emc_cfg_dig_dll_period;
|
EMC(EMC_CFG_DIG_DLL_PERIOD) = params->emc_cfg_dig_dll_period;
|
||||||
|
|
||||||
|
// Don't write CFG_ADR_EN (bit 1) here - lock bit written later.
|
||||||
EMC(EMC_FBIO_SPARE) = params->emc_fbio_spare & 0xFFFFFFFD;
|
EMC(EMC_FBIO_SPARE) = params->emc_fbio_spare & 0xFFFFFFFD;
|
||||||
EMC(EMC_CFG_RSV) = params->emc_cfg_rsv;
|
EMC(EMC_CFG_RSV) = params->emc_cfg_rsv;
|
||||||
EMC(EMC_PMC_SCRATCH1) = params->emc_pmc_scratch1;
|
EMC(EMC_PMC_SCRATCH1) = params->emc_pmc_scratch1;
|
||||||
@@ -390,70 +535,104 @@ break_nosleep:
|
|||||||
EMC(EMC_PMC_SCRATCH3) = params->emc_pmc_scratch3;
|
EMC(EMC_PMC_SCRATCH3) = params->emc_pmc_scratch3;
|
||||||
EMC(EMC_ACPD_CONTROL) = params->emc_acpd_control;
|
EMC(EMC_ACPD_CONTROL) = params->emc_acpd_control;
|
||||||
EMC(EMC_TXDSRVTTGEN) = params->emc_txdsrvttgen;
|
EMC(EMC_TXDSRVTTGEN) = params->emc_txdsrvttgen;
|
||||||
|
|
||||||
|
// Set pipe bypass enable bits before sending any DRAM commands.
|
||||||
EMC(EMC_CFG) = (params->emc_cfg & 0xE) | 0x3C00000;
|
EMC(EMC_CFG) = (params->emc_cfg & 0xE) | 0x3C00000;
|
||||||
|
|
||||||
|
// Patch BootROM.
|
||||||
if (params->boot_rom_patch_control & (1 << 31))
|
if (params->boot_rom_patch_control & (1 << 31))
|
||||||
{
|
{
|
||||||
*(vu32 *)(APB_MISC_BASE + params->boot_rom_patch_control * 4) = params->boot_rom_patch_data;
|
*(vu32 *)(APB_MISC_BASE + params->boot_rom_patch_control * 4) = params->boot_rom_patch_data;
|
||||||
MC(MC_TIMING_CONTROL) = 1;
|
MC(MC_TIMING_CONTROL) = 1; // Trigger MC timing update.
|
||||||
}
|
}
|
||||||
PMC(APBDEV_PMC_IO_DPD3_REQ) = ((4 * params->emc_pmc_scratch1 >> 2) + 0x40000000) & 0xCFFF0000;
|
|
||||||
|
// Release SEL_DPD_CMD.
|
||||||
|
PMC(APBDEV_PMC_IO_DPD3_REQ) = ((params->emc_pmc_scratch1 & 0x3FFFFFFF) | 0x40000000) & 0xCFFF0000;
|
||||||
usleep(params->pmc_io_dpd3_req_wait);
|
usleep(params->pmc_io_dpd3_req_wait);
|
||||||
|
|
||||||
|
// Set autocal interval if not configured.
|
||||||
if (!params->emc_auto_cal_interval)
|
if (!params->emc_auto_cal_interval)
|
||||||
EMC(EMC_AUTO_CAL_CONFIG) = params->emc_auto_cal_config | 0x200;
|
EMC(EMC_AUTO_CAL_CONFIG) = params->emc_auto_cal_config | 0x200;
|
||||||
|
|
||||||
EMC(EMC_PMACRO_BRICK_CTRL_RFU2) = params->emc_pmacro_brick_ctrl_rfu2;
|
EMC(EMC_PMACRO_BRICK_CTRL_RFU2) = params->emc_pmacro_brick_ctrl_rfu2;
|
||||||
|
|
||||||
|
// ZQ CAL setup (not actually issuing ZQ CAL now).
|
||||||
if (params->emc_zcal_warm_cold_boot_enables & 1)
|
if (params->emc_zcal_warm_cold_boot_enables & 1)
|
||||||
{
|
{
|
||||||
if (params->memory_type == 2)
|
if (params->memory_type == MEMORY_TYPE_DDR3L)
|
||||||
EMC(EMC_ZCAL_WAIT_CNT) = 8 * params->emc_zcal_wait_cnt;
|
EMC(EMC_ZCAL_WAIT_CNT) = params->emc_zcal_wait_cnt << 3;
|
||||||
if (params->memory_type == 3)
|
if (params->memory_type == MEMORY_TYPE_LPDDR4)
|
||||||
{
|
{
|
||||||
EMC(EMC_ZCAL_WAIT_CNT) = params->emc_zcal_wait_cnt;
|
EMC(EMC_ZCAL_WAIT_CNT) = params->emc_zcal_wait_cnt;
|
||||||
EMC(EMC_ZCAL_MRW_CMD) = params->emc_zcal_mrw_cmd;
|
EMC(EMC_ZCAL_MRW_CMD) = params->emc_zcal_mrw_cmd;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
EMC(EMC_TIMING_CONTROL) = 1;
|
|
||||||
|
EMC(EMC_TIMING_CONTROL) = 1; // Trigger timing update so above writes take place.
|
||||||
usleep(params->emc_timing_control_wait);
|
usleep(params->emc_timing_control_wait);
|
||||||
|
|
||||||
|
// Deassert HOLD_CKE_LOW.
|
||||||
PMC(APBDEV_PMC_DDR_CNTRL) &= 0xFFF8007F;
|
PMC(APBDEV_PMC_DDR_CNTRL) &= 0xFFF8007F;
|
||||||
usleep(params->pmc_ddr_ctrl_wait);
|
usleep(params->pmc_ddr_ctrl_wait);
|
||||||
if (params->memory_type == 2)
|
|
||||||
|
// Set clock enable signal.
|
||||||
|
u32 pin_gpio_cfg = (params->emc_pin_gpio_enable << 16) | (params->emc_pin_gpio << 12);
|
||||||
|
if (params->memory_type == MEMORY_TYPE_DDR3L || params->memory_type == MEMORY_TYPE_LPDDR4)
|
||||||
{
|
{
|
||||||
EMC(EMC_PIN) = (params->emc_pin_gpio_enable << 16) | (params->emc_pin_gpio << 12);
|
EMC(EMC_PIN) = pin_gpio_cfg;
|
||||||
|
(void)EMC(EMC_PIN);
|
||||||
usleep(params->emc_pin_extra_wait + 200);
|
usleep(params->emc_pin_extra_wait + 200);
|
||||||
EMC(EMC_PIN) = ((params->emc_pin_gpio_enable << 16) | (params->emc_pin_gpio << 12)) + 256;
|
EMC(EMC_PIN) = pin_gpio_cfg | 0x100;
|
||||||
usleep(params->emc_pin_extra_wait + 500);
|
(void)EMC(EMC_PIN);
|
||||||
}
|
}
|
||||||
if (params->memory_type == 3)
|
|
||||||
{
|
if (params->memory_type == MEMORY_TYPE_LPDDR4)
|
||||||
EMC(EMC_PIN) = (params->emc_pin_gpio_enable << 16) | (params->emc_pin_gpio << 12);
|
|
||||||
usleep(params->emc_pin_extra_wait + 200);
|
|
||||||
EMC(EMC_PIN) = ((params->emc_pin_gpio_enable << 16) | (params->emc_pin_gpio << 12)) + 256;
|
|
||||||
usleep(params->emc_pin_extra_wait + 2000);
|
usleep(params->emc_pin_extra_wait + 2000);
|
||||||
}
|
else if (params->memory_type == MEMORY_TYPE_DDR3L)
|
||||||
EMC(EMC_PIN) = ((params->emc_pin_gpio_enable << 16) | (params->emc_pin_gpio << 12)) + 0x101;
|
usleep(params->emc_pin_extra_wait + 500);
|
||||||
|
|
||||||
|
// Enable clock enable signal.
|
||||||
|
EMC(EMC_PIN) = pin_gpio_cfg | 0x101;
|
||||||
|
(void)EMC(EMC_PIN);
|
||||||
usleep(params->emc_pin_program_wait);
|
usleep(params->emc_pin_program_wait);
|
||||||
if (params->memory_type != 3)
|
|
||||||
|
// Send NOP (trigger just needs to be non-zero).
|
||||||
|
if (params->memory_type != MEMORY_TYPE_LPDDR4)
|
||||||
EMC(EMC_NOP) = (params->emc_dev_select << 30) + 1;
|
EMC(EMC_NOP) = (params->emc_dev_select << 30) + 1;
|
||||||
if (params->memory_type == 1)
|
|
||||||
|
// On coldboot w/LPDDR2/3, wait 200 uSec after asserting CKE high.
|
||||||
|
if (params->memory_type == MEMORY_TYPE_LPDDR2)
|
||||||
usleep(params->emc_pin_extra_wait + 200);
|
usleep(params->emc_pin_extra_wait + 200);
|
||||||
if (params->memory_type == 3)
|
|
||||||
|
// Init zq calibration,
|
||||||
|
if (params->memory_type == MEMORY_TYPE_LPDDR4)
|
||||||
{
|
{
|
||||||
|
// Patch 6 using BCT spare variables.
|
||||||
if (params->emc_bct_spare10)
|
if (params->emc_bct_spare10)
|
||||||
*(vu32 *)params->emc_bct_spare10 = params->emc_bct_spare11;
|
*(vu32 *)params->emc_bct_spare10 = params->emc_bct_spare11;
|
||||||
|
|
||||||
|
// Write mode registers.
|
||||||
EMC(EMC_MRW2) = params->emc_mrw2;
|
EMC(EMC_MRW2) = params->emc_mrw2;
|
||||||
EMC(EMC_MRW) = params->emc_mrw1;
|
EMC(EMC_MRW) = params->emc_mrw1;
|
||||||
EMC(EMC_MRW3) = params->emc_mrw3;
|
EMC(EMC_MRW3) = params->emc_mrw3;
|
||||||
EMC(EMC_MRW4) = params->emc_mrw4;
|
EMC(EMC_MRW4) = params->emc_mrw4;
|
||||||
EMC(EMC_MRW6) = params->emc_mrw6;
|
EMC(EMC_MRW6) = params->emc_mrw6;
|
||||||
EMC(EMC_MRW14) = params->emc_mrw14;
|
EMC(EMC_MRW14) = params->emc_mrw14;
|
||||||
|
|
||||||
EMC(EMC_MRW8) = params->emc_mrw8;
|
EMC(EMC_MRW8) = params->emc_mrw8;
|
||||||
EMC(EMC_MRW12) = params->emc_mrw12;
|
EMC(EMC_MRW12) = params->emc_mrw12;
|
||||||
EMC(EMC_MRW9) = params->emc_mrw9;
|
EMC(EMC_MRW9) = params->emc_mrw9;
|
||||||
EMC(EMC_MRW13) = params->emc_mrw13;
|
EMC(EMC_MRW13) = params->emc_mrw13;
|
||||||
|
|
||||||
if (params->emc_zcal_warm_cold_boot_enables & 1)
|
if (params->emc_zcal_warm_cold_boot_enables & 1)
|
||||||
{
|
{
|
||||||
|
// Issue ZQCAL start, device 0.
|
||||||
EMC(EMC_ZQ_CAL) = params->emc_zcal_init_dev0;
|
EMC(EMC_ZQ_CAL) = params->emc_zcal_init_dev0;
|
||||||
usleep(params->emc_zcal_init_wait);
|
usleep(params->emc_zcal_init_wait);
|
||||||
|
|
||||||
|
// Issue ZQCAL latch.
|
||||||
EMC(EMC_ZQ_CAL) = params->emc_zcal_init_dev0 ^ 3;
|
EMC(EMC_ZQ_CAL) = params->emc_zcal_init_dev0 ^ 3;
|
||||||
|
// Same for device 1.
|
||||||
if (!(params->emc_dev_select & 2))
|
if (!(params->emc_dev_select & 2))
|
||||||
{
|
{
|
||||||
EMC(EMC_ZQ_CAL) = params->emc_zcal_init_dev1;
|
EMC(EMC_ZQ_CAL) = params->emc_zcal_init_dev1;
|
||||||
@@ -462,46 +641,97 @@ break_nosleep:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set package and DPD pad control.
|
||||||
PMC(APBDEV_PMC_DDR_CFG) = params->pmc_ddr_cfg;
|
PMC(APBDEV_PMC_DDR_CFG) = params->pmc_ddr_cfg;
|
||||||
if (params->memory_type - 1 <= 2)
|
|
||||||
|
// Start periodic ZQ calibration (LPDDRx only).
|
||||||
|
if (params->memory_type && params->memory_type <= MEMORY_TYPE_LPDDR4)
|
||||||
{
|
{
|
||||||
EMC(EMC_ZCAL_INTERVAL) = params->emc_zcal_interval;
|
EMC(EMC_ZCAL_INTERVAL) = params->emc_zcal_interval;
|
||||||
EMC(EMC_ZCAL_WAIT_CNT) = params->emc_zcal_wait_cnt;
|
EMC(EMC_ZCAL_WAIT_CNT) = params->emc_zcal_wait_cnt;
|
||||||
EMC(EMC_ZCAL_MRW_CMD) = params->emc_zcal_mrw_cmd;
|
EMC(EMC_ZCAL_MRW_CMD) = params->emc_zcal_mrw_cmd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Patch 7 using BCT spare variables.
|
||||||
if (params->emc_bct_spare12)
|
if (params->emc_bct_spare12)
|
||||||
*(vu32 *)params->emc_bct_spare12 = params->emc_bct_spare13;
|
*(vu32 *)params->emc_bct_spare12 = params->emc_bct_spare13;
|
||||||
EMC(EMC_TIMING_CONTROL) = 1;
|
|
||||||
|
EMC(EMC_TIMING_CONTROL) = 1; // Trigger timing update so above writes take place.
|
||||||
|
|
||||||
if (params->emc_extra_refresh_num)
|
if (params->emc_extra_refresh_num)
|
||||||
EMC(EMC_REF) = ((1 << params->emc_extra_refresh_num << 8) - 0xFD) | (params->emc_pin_gpio << 30);
|
EMC(EMC_REF) = (((1 << params->emc_extra_refresh_num) - 1) << 8) | (params->emc_dev_select << 30) | 3;
|
||||||
|
|
||||||
|
// Enable refresh.
|
||||||
EMC(EMC_REFCTRL) = params->emc_dev_select | 0x80000000;
|
EMC(EMC_REFCTRL) = params->emc_dev_select | 0x80000000;
|
||||||
|
|
||||||
EMC(EMC_DYN_SELF_REF_CONTROL) = params->emc_dyn_self_ref_control;
|
EMC(EMC_DYN_SELF_REF_CONTROL) = params->emc_dyn_self_ref_control;
|
||||||
EMC(EMC_CFG_UPDATE) = params->emc_cfg_update;
|
EMC(EMC_CFG_UPDATE) = params->emc_cfg_update;
|
||||||
EMC(EMC_CFG) = params->emc_cfg;
|
EMC(EMC_CFG) = params->emc_cfg;
|
||||||
EMC(EMC_FDPD_CTRL_DQ) = params->emc_fdpd_ctrl_dq;
|
EMC(EMC_FDPD_CTRL_DQ) = params->emc_fdpd_ctrl_dq;
|
||||||
EMC(EMC_FDPD_CTRL_CMD) = params->emc_fdpd_ctrl_cmd;
|
EMC(EMC_FDPD_CTRL_CMD) = params->emc_fdpd_ctrl_cmd;
|
||||||
EMC(EMC_SEL_DPD_CTRL) = params->emc_sel_dpd_ctrl;
|
EMC(EMC_SEL_DPD_CTRL) = params->emc_sel_dpd_ctrl;
|
||||||
|
|
||||||
|
// Write addr swizzle lock bit.
|
||||||
EMC(EMC_FBIO_SPARE) = params->emc_fbio_spare | 2;
|
EMC(EMC_FBIO_SPARE) = params->emc_fbio_spare | 2;
|
||||||
EMC(EMC_TIMING_CONTROL) = 1;
|
|
||||||
|
EMC(EMC_TIMING_CONTROL) = 1; // Re-trigger timing to latch power saving functions.
|
||||||
|
|
||||||
|
// Enable EMC pipe clock gating.
|
||||||
EMC(EMC_CFG_PIPE_CLK) = params->emc_cfg_pipe_clk;
|
EMC(EMC_CFG_PIPE_CLK) = params->emc_cfg_pipe_clk;
|
||||||
|
|
||||||
|
// Depending on freqency, enable CMD/CLK fdpd.
|
||||||
EMC(EMC_FDPD_CTRL_CMD_NO_RAMP) = params->emc_fdpd_ctrl_cmd_no_ramp;
|
EMC(EMC_FDPD_CTRL_CMD_NO_RAMP) = params->emc_fdpd_ctrl_cmd_no_ramp;
|
||||||
SYSREG(AHB_ARBITRATION_XBAR_CTRL) = (SYSREG(AHB_ARBITRATION_XBAR_CTRL) & 0xFFFEFFFF) | ((params->ahb_arbitration_xbar_ctrl_meminit_done & 0xFFFF) << 16);
|
|
||||||
|
// Enable arbiter.
|
||||||
|
SYSREG(AHB_ARBITRATION_XBAR_CTRL) = (SYSREG(AHB_ARBITRATION_XBAR_CTRL) & 0xFFFEFFFF) | (params->ahb_arbitration_xbar_ctrl_meminit_done << 16);
|
||||||
|
|
||||||
|
// Lock carveouts per BCT cfg.
|
||||||
MC(MC_VIDEO_PROTECT_REG_CTRL) = params->mc_video_protect_write_access;
|
MC(MC_VIDEO_PROTECT_REG_CTRL) = params->mc_video_protect_write_access;
|
||||||
MC(MC_SEC_CARVEOUT_REG_CTRL) = params->mc_sec_carveout_protect_write_access;
|
MC(MC_SEC_CARVEOUT_REG_CTRL) = params->mc_sec_carveout_protect_write_access;
|
||||||
MC(MC_MTS_CARVEOUT_REG_CTRL) = params->mc_mts_carveout_reg_ctrl;
|
MC(MC_MTS_CARVEOUT_REG_CTRL) = params->mc_mts_carveout_reg_ctrl;
|
||||||
MC(MC_EMEM_CFG_ACCESS_CTRL) = 1; //Disable write access to a bunch of EMC registers.
|
|
||||||
|
// Disable write access to a bunch of EMC registers.
|
||||||
|
MC(MC_EMEM_CFG_ACCESS_CTRL) = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef CONFIG_SDRAM_COMPRESS_CFG
|
||||||
|
static void _sdram_patch_model_params(u32 dramid, u32 *params)
|
||||||
|
{
|
||||||
|
for (u32 i = 0; i < sizeof(sdram_cfg_vendor_patches) / sizeof(sdram_vendor_patch_t); i++)
|
||||||
|
if (sdram_cfg_vendor_patches[i].dramid & DRAM_ID(dramid))
|
||||||
|
params[sdram_cfg_vendor_patches[i].addr] = sdram_cfg_vendor_patches[i].val;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
sdram_params_t *sdram_get_params()
|
sdram_params_t *sdram_get_params()
|
||||||
{
|
{
|
||||||
//TODO: sdram_id should be in [0, 7].
|
// Check if id is proper.
|
||||||
|
u32 dramid = _get_sdram_id();
|
||||||
|
if (dramid > 6)
|
||||||
|
dramid = 0;
|
||||||
|
|
||||||
#ifdef CONFIG_SDRAM_COMPRESS_CFG
|
#ifdef CONFIG_SDRAM_COMPRESS_CFG
|
||||||
u8 *buf = (u8 *)0x40030000;
|
u8 *buf = (u8 *)SDRAM_PARAMS_ADDR;
|
||||||
LZ_Uncompress(_dram_cfg_lz, buf, sizeof(_dram_cfg_lz));
|
LZ_Uncompress(_dram_cfg_lz, buf, sizeof(_dram_cfg_lz));
|
||||||
return (sdram_params_t *)&buf[sizeof(sdram_params_t) * _get_sdram_id()];
|
return (sdram_params_t *)&buf[sizeof(sdram_params_t) * dramid];
|
||||||
#else
|
#else
|
||||||
return _dram_cfgs[_get_sdram_id()];
|
sdram_params_t *buf = (sdram_params_t *)SDRAM_PARAMS_ADDR;
|
||||||
|
memcpy(buf, &_dram_cfg_0_samsung_4gb, sizeof(sdram_params_t));
|
||||||
|
switch (dramid)
|
||||||
|
{
|
||||||
|
case DRAM_4GB_SAMSUNG_K4F6E304HB_MGCH:
|
||||||
|
case DRAM_4GB_MICRON_MT53B512M32D2NP_062_WT:
|
||||||
|
break;
|
||||||
|
case DRAM_4GB_HYNIX_H9HCNNNBPUMLHR_NLN:
|
||||||
|
case DRAM_4GB_COPPER_UNK_3:
|
||||||
|
case DRAM_6GB_SAMSUNG_K4FHE3D4HM_MFCH:
|
||||||
|
case DRAM_4GB_COPPER_UNK_5:
|
||||||
|
case DRAM_4GB_COPPER_UNK_6:
|
||||||
|
_sdram_patch_model_params(dramid, (u32 *)buf);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return buf;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -529,25 +759,42 @@ sdram_params_t *sdram_get_params_patched()
|
|||||||
// Disable Warmboot signature check.
|
// Disable Warmboot signature check.
|
||||||
sdram_params->boot_rom_patch_control = (1 << 31) | (((IPATCH_BASE + 4) - APB_MISC_BASE) / 4);
|
sdram_params->boot_rom_patch_control = (1 << 31) | (((IPATCH_BASE + 4) - APB_MISC_BASE) / 4);
|
||||||
sdram_params->boot_rom_patch_data = IPATCH_CONFIG(0x10459E, 0x2000);
|
sdram_params->boot_rom_patch_data = IPATCH_CONFIG(0x10459E, 0x2000);
|
||||||
|
/*
|
||||||
|
// Disable SBK lock.
|
||||||
|
sdram_params->emc_bct_spare8 = (IPATCH_BASE + 7 * 4);
|
||||||
|
sdram_params->emc_bct_spare9 = IPATCH_CONFIG(0x10210E, 0x2000);
|
||||||
|
|
||||||
|
// Disable bootrom read lock.
|
||||||
|
sdram_params->emc_bct_spare10 = (IPATCH_BASE + 10 * 4);
|
||||||
|
sdram_params->emc_bct_spare11 = IPATCH_CONFIG(0x100FDC, 0xF000);
|
||||||
|
sdram_params->emc_bct_spare12 = (IPATCH_BASE + 11 * 4);
|
||||||
|
sdram_params->emc_bct_spare13 = IPATCH_CONFIG(0x100FDE, 0xE320);
|
||||||
|
*/
|
||||||
return sdram_params;
|
return sdram_params;
|
||||||
}
|
}
|
||||||
|
|
||||||
void sdram_init()
|
void sdram_init()
|
||||||
{
|
{
|
||||||
//TODO: sdram_id should be in [0,4].
|
|
||||||
const sdram_params_t *params = (const sdram_params_t *)sdram_get_params();
|
const sdram_params_t *params = (const sdram_params_t *)sdram_get_params();
|
||||||
|
|
||||||
|
// Set DRAM voltage.
|
||||||
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_SD_CFG2, 0x05);
|
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_SD_CFG2, 0x05);
|
||||||
max77620_regulator_set_voltage(REGULATOR_SD1, 1100000);
|
max77620_regulator_set_voltage(REGULATOR_SD1, 1100000);
|
||||||
|
|
||||||
|
// VDDP Select.
|
||||||
PMC(APBDEV_PMC_VDDP_SEL) = params->pmc_vddp_sel;
|
PMC(APBDEV_PMC_VDDP_SEL) = params->pmc_vddp_sel;
|
||||||
usleep(params->pmc_vddp_sel_wait);
|
usleep(params->pmc_vddp_sel_wait);
|
||||||
|
|
||||||
|
// Set DDR pad voltage.
|
||||||
PMC(APBDEV_PMC_DDR_PWR) = PMC(APBDEV_PMC_DDR_PWR);
|
PMC(APBDEV_PMC_DDR_PWR) = PMC(APBDEV_PMC_DDR_PWR);
|
||||||
|
|
||||||
|
// Turn on MEM IO Power.
|
||||||
PMC(APBDEV_PMC_NO_IOPOWER) = params->pmc_no_io_power;
|
PMC(APBDEV_PMC_NO_IOPOWER) = params->pmc_no_io_power;
|
||||||
PMC(APBDEV_PMC_REG_SHORT) = params->pmc_reg_short;
|
PMC(APBDEV_PMC_REG_SHORT) = params->pmc_reg_short;
|
||||||
|
|
||||||
PMC(APBDEV_PMC_DDR_CNTRL) = params->pmc_ddr_ctrl;
|
PMC(APBDEV_PMC_DDR_CNTRL) = params->pmc_ddr_ctrl;
|
||||||
|
|
||||||
|
// Patch 1 using BCT spare variables
|
||||||
if (params->emc_bct_spare0)
|
if (params->emc_bct_spare0)
|
||||||
*(vu32 *)params->emc_bct_spare0 = params->emc_bct_spare1;
|
*(vu32 *)params->emc_bct_spare0 = params->emc_bct_spare1;
|
||||||
|
|
||||||
|
|||||||
@@ -17,11 +17,13 @@
|
|||||||
#ifndef _SDRAM_H_
|
#ifndef _SDRAM_H_
|
||||||
#define _SDRAM_H_
|
#define _SDRAM_H_
|
||||||
|
|
||||||
|
#include "emc.h"
|
||||||
#include "sdram_param_t210.h"
|
#include "sdram_param_t210.h"
|
||||||
|
|
||||||
void sdram_init();
|
void sdram_init();
|
||||||
sdram_params_t *sdram_get_params();
|
sdram_params_t *sdram_get_params();
|
||||||
sdram_params_t *sdram_get_params_patched();
|
sdram_params_t *sdram_get_params_patched();
|
||||||
void sdram_lp0_save_params(const void *params);
|
void sdram_lp0_save_params(const void *params);
|
||||||
|
emc_mr_data_t sdram_read_mrx(emc_mr_t mrx);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2013-2015, NVIDIA CORPORATION. All rights reserved.
|
* Copyright (c) 2013-2015, NVIDIA CORPORATION. All rights reserved.
|
||||||
* Copyright 2014 Google Inc.
|
* Copyright 2014 Google Inc.
|
||||||
* Copyright (C) 2018 CTCaer
|
* Copyright (c) 2018 CTCaer
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
* under the terms and conditions of the GNU General Public License,
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
|||||||
@@ -31,7 +31,7 @@
|
|||||||
#define MEMORY_TYPE_LPDDR 0
|
#define MEMORY_TYPE_LPDDR 0
|
||||||
#define MEMORY_TYPE_DDR2 0
|
#define MEMORY_TYPE_DDR2 0
|
||||||
#define MEMORY_TYPE_LPDDR2 1
|
#define MEMORY_TYPE_LPDDR2 1
|
||||||
#define MEMORY_TYPE_DDR3 2
|
#define MEMORY_TYPE_DDR3L 2
|
||||||
#define MEMORY_TYPE_LPDDR4 3
|
#define MEMORY_TYPE_LPDDR4 3
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,125 +0,0 @@
|
|||||||
#include <string.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include "../gfx/di.h"
|
|
||||||
#include "../gfx/gfx.h"
|
|
||||||
#include "../utils/btn.h"
|
|
||||||
#include "../utils/util.h"
|
|
||||||
#include "graphics.h"
|
|
||||||
#include "utils.h"
|
|
||||||
|
|
||||||
int _copystring(char *out, const char *in, int copynumb){
|
|
||||||
strncpy(out, in, copynumb - 1);
|
|
||||||
int strlength = strlen(in);
|
|
||||||
if (strlength > copynumb + 1) strlength = copynumb;
|
|
||||||
memset(out + strlength, '\0', 1);
|
|
||||||
int ret = copynumb - strlength;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
int messagebox(char *message){
|
|
||||||
int ret = -1;
|
|
||||||
meme_clearscreen();
|
|
||||||
gfx_printf("%s", message);
|
|
||||||
u8 res = btn_wait();
|
|
||||||
if (res & BTN_POWER) ret = 0;
|
|
||||||
else ret = 1;
|
|
||||||
meme_clearscreen();
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
int gfx_menulist(int ypos, char *list[], int length){
|
|
||||||
int i = 0;
|
|
||||||
int highlight = 1;
|
|
||||||
while(1){
|
|
||||||
gfx_con_setpos(0, ypos);
|
|
||||||
while(i < length){
|
|
||||||
if (i == highlight - 1) gfx_printf("%k%p%s%k%p\n", COLOR_DEFAULT, COLOR_WHITE, list[i], COLOR_WHITE, COLOR_DEFAULT);
|
|
||||||
else gfx_printf("%s\n", list[i]);
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
i = 0;
|
|
||||||
u8 res = btn_wait();
|
|
||||||
if (res & BTN_VOL_UP) highlight--;
|
|
||||||
else if (res & BTN_VOL_DOWN) highlight++;
|
|
||||||
else if (res & BTN_POWER) break;
|
|
||||||
if (highlight < 1) highlight = 1;
|
|
||||||
if (highlight > length) highlight = length;
|
|
||||||
}
|
|
||||||
return highlight;
|
|
||||||
}
|
|
||||||
|
|
||||||
void meme_clearscreen(){
|
|
||||||
gfx_clear_grey(0x1B);
|
|
||||||
gfx_con_setpos(0, 0);
|
|
||||||
gfx_box(0, 0, 719, 15, COLOR_WHITE);
|
|
||||||
gfx_printf("%k%pTegraExplorer, by SuchMemeManySkill\n%k%p", COLOR_DEFAULT, COLOR_WHITE, COLOR_WHITE, COLOR_DEFAULT);
|
|
||||||
}
|
|
||||||
|
|
||||||
void _printwithhighlight(int offset, int folderamount, char *items[], int highlight, unsigned int *muhbits){
|
|
||||||
char temp[39];
|
|
||||||
int i = 0;
|
|
||||||
int ret = 0;
|
|
||||||
gfx_con_setpos(0, 32);
|
|
||||||
while(i < folderamount && i < 76){
|
|
||||||
ret = _copystring(temp, items[i + offset], 39);
|
|
||||||
if(i == highlight - 1) gfx_printf("\n%k%p%s%k%p", COLOR_DEFAULT, COLOR_WHITE, temp, COLOR_WHITE, COLOR_DEFAULT);
|
|
||||||
else if ((i == 0 || i == 1) && offset == 0) gfx_printf("%k\n%s%k", COLOR_ORANGE, temp, COLOR_WHITE);
|
|
||||||
else if (muhbits[i+offset] & OPTION1) gfx_printf("\n%s", temp);
|
|
||||||
else gfx_printf("%k\n%s%k", COLOR_VIOLET, temp, COLOR_WHITE);
|
|
||||||
|
|
||||||
while(ret >= 0){
|
|
||||||
gfx_printf(" ");
|
|
||||||
ret = ret - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
gfx_con.x = 720 - (16 * 6);
|
|
||||||
if (muhbits[i + offset] & OPTION1) gfx_printf("DIR");
|
|
||||||
else gfx_printf("FILE");
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int fileexplorergui(char *items[], unsigned int *muhbits, const char path[], int folderamount){
|
|
||||||
bool change = true;
|
|
||||||
int select = 1;
|
|
||||||
int sleepvalue = 300;
|
|
||||||
int offset = 0;
|
|
||||||
char temp[43];
|
|
||||||
gfx_con_setpos(0, 16);
|
|
||||||
_copystring(temp, path, 43);
|
|
||||||
gfx_printf("%k%s\n%k", COLOR_GREEN, temp, COLOR_WHITE);
|
|
||||||
while(1){
|
|
||||||
if (change){
|
|
||||||
_printwithhighlight(offset, folderamount, items, select, muhbits);
|
|
||||||
change = false;
|
|
||||||
msleep(sleepvalue);
|
|
||||||
}
|
|
||||||
|
|
||||||
u8 res = btn_read();
|
|
||||||
if (res & BTN_VOL_UP){
|
|
||||||
select = select - 1, change = true;
|
|
||||||
sleepvalue = sleepvalue - 75;
|
|
||||||
}
|
|
||||||
else if (res & BTN_VOL_DOWN){
|
|
||||||
select++, change = true;
|
|
||||||
sleepvalue = sleepvalue - 75;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
sleepvalue = 300;
|
|
||||||
}
|
|
||||||
if (res & BTN_POWER) break;
|
|
||||||
if (select < 1){
|
|
||||||
select = 1;
|
|
||||||
if (offset > 0) offset = offset - 1;
|
|
||||||
}
|
|
||||||
if (select > folderamount) select = folderamount;
|
|
||||||
if (select > 76){
|
|
||||||
select = 76;
|
|
||||||
if (76 + offset < folderamount) offset++;
|
|
||||||
}
|
|
||||||
if (sleepvalue < 30) sleepvalue = 30;
|
|
||||||
}
|
|
||||||
int ret = select + offset;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
int fileexplorergui(char *items[], unsigned int *muhbits, const char path[], int folderamount);
|
|
||||||
void meme_clearscreen();
|
|
||||||
int gfx_menulist(int ypos, char *list[], int length);
|
|
||||||
int messagebox(char *message);
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
#include <string.h>
|
|
||||||
#include "../gfx/di.h"
|
|
||||||
#include "../gfx/gfx.h"
|
|
||||||
#include "../utils/btn.h"
|
|
||||||
#include "utils.h"
|
|
||||||
#include "main.h"
|
|
||||||
#include "mainfunctions.h"
|
|
||||||
#include "../libs/fatfs/ff.h"
|
|
||||||
#include "../storage/sdmmc.h"
|
|
||||||
#include "graphics.h"
|
|
||||||
|
|
||||||
void meme_main(bool sdinit){
|
|
||||||
utils_gfx_init();
|
|
||||||
//static const u32 colors[7] = {COLOR_RED, COLOR_ORANGE, COLOR_YELLOW, COLOR_GREEN, COLOR_BLUE, COLOR_VIOLET, COLOR_DEFAULT};
|
|
||||||
//gfx_printf("%k%pTegraExplorer, made by SuchMemeManySkill \n%k%p", colors[6], colors[3], colors[3], colors[6]);
|
|
||||||
/*
|
|
||||||
sdmmc_storage_t storage;
|
|
||||||
sdmmc_t sdmmc;
|
|
||||||
|
|
||||||
sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4);
|
|
||||||
sdmmc_storage_set_mmc_partition(&storage, 1);
|
|
||||||
*/
|
|
||||||
//f_rename("sd:/yeet.txt", "sd:/yote.txt");
|
|
||||||
|
|
||||||
|
|
||||||
char *itemsinfolder[500];
|
|
||||||
unsigned int muhbits[500];
|
|
||||||
|
|
||||||
if (sdinit){
|
|
||||||
sdexplorer(itemsinfolder, muhbits);
|
|
||||||
|
|
||||||
//write file and folder menu
|
|
||||||
//make clipboard and shit like that
|
|
||||||
//figure out time from keys.c
|
|
||||||
//figure out how to reboot to payloads https://github.com/CTCaer/hekate/blob/101c8bc1d0813da10016be771a9919c9e8112277/bootloader/main.c#L266
|
|
||||||
gfx_printf("%k\n\nExited main loop, vol+ to reboot to rcm\nvol- to reboot normally\npower to power off\n", COLOR_GREEN);
|
|
||||||
}
|
|
||||||
else gfx_printf("%k%pSD INIT FAILED\n\nvol+ to reboot to rcm\nvol- to reboot normally\npower to power off", COLOR_RED, COLOR_DEFAULT);
|
|
||||||
|
|
||||||
utils_waitforpower();
|
|
||||||
}
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
void meme_main(bool sdinit);
|
|
||||||
@@ -1,87 +0,0 @@
|
|||||||
#include <string.h>
|
|
||||||
#include "../gfx/di.h"
|
|
||||||
#include "../gfx/gfx.h"
|
|
||||||
#include "../utils/btn.h"
|
|
||||||
#include "utils.h"
|
|
||||||
#include "mainfunctions.h"
|
|
||||||
#include "../libs/fatfs/ff.h"
|
|
||||||
#include "../storage/sdmmc.h"
|
|
||||||
#include "graphics.h"
|
|
||||||
|
|
||||||
int _openfilemenu(const char *path, char *clipboardpath){
|
|
||||||
meme_clearscreen();
|
|
||||||
FILINFO fno;
|
|
||||||
f_stat(path, &fno);
|
|
||||||
char *options[4];
|
|
||||||
int res = 0;
|
|
||||||
int mres = -1;
|
|
||||||
int ret = -1;
|
|
||||||
|
|
||||||
addchartoarray("Back", options, 0);
|
|
||||||
addchartoarray("Copy to clipboard", options, 1);
|
|
||||||
addchartoarray("Move to clipboard", options, 2);
|
|
||||||
addchartoarray("Delete file", options, 3);
|
|
||||||
|
|
||||||
gfx_printf("%kPath: %s%k\n\n", COLOR_GREEN, path, COLOR_WHITE);
|
|
||||||
int temp = (fno.fsize / 1024 / 1024);
|
|
||||||
gfx_printf("Size MB: %d", temp);
|
|
||||||
|
|
||||||
res = gfx_menulist(160, options, 4);
|
|
||||||
switch(res){
|
|
||||||
case 2:
|
|
||||||
ret = 0;
|
|
||||||
strcpy(clipboardpath, path);
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
ret = 1;
|
|
||||||
strcpy(clipboardpath, path);
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
mres = messagebox("Are you sure you want to delete this file?\nPower to confirm\nVOL to cancel");
|
|
||||||
if (mres == 0) f_unlink(path);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
meme_clearscreen();
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
void sdexplorer(char *items[], unsigned int *muhbits){
|
|
||||||
int value = 1;
|
|
||||||
int copymode = -1;
|
|
||||||
int folderamount = 0;
|
|
||||||
char path[255] = "sd:/";
|
|
||||||
char clipboard[255] = "";
|
|
||||||
int temp = -1;
|
|
||||||
//static const u32 colors[8] = {COLOR_RED, COLOR_ORANGE, COLOR_YELLOW, COLOR_GREEN, COLOR_BLUE, COLOR_VIOLET, COLOR_DEFAULT, COLOR_WHITE};
|
|
||||||
while(1){
|
|
||||||
gfx_clear_grey(0x1B);
|
|
||||||
gfx_con_setpos(0, 0);
|
|
||||||
gfx_box(0, 0, 719, 15, COLOR_WHITE);
|
|
||||||
folderamount = readfolder(items, muhbits, path);
|
|
||||||
gfx_printf("%k%pTegraExplorer, by SuchMemeManySkill %d\n%k%p", COLOR_DEFAULT, COLOR_WHITE, folderamount - 2, COLOR_WHITE, COLOR_DEFAULT);
|
|
||||||
value = fileexplorergui(items, muhbits, path, folderamount);
|
|
||||||
|
|
||||||
if (value == 1) {
|
|
||||||
if (strcmp("sd:/", path) == 0) break;
|
|
||||||
else removepartpath(path);
|
|
||||||
}
|
|
||||||
else if (value == 2) {
|
|
||||||
if (copymode != -1){
|
|
||||||
copywithpath(clipboard, path, copymode);
|
|
||||||
copymode = -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if(muhbits[value - 1] & OPTION1) addpartpath(path, items[value - 1]);
|
|
||||||
else {
|
|
||||||
addpartpath(path, items[value - 1]);
|
|
||||||
temp = _openfilemenu(path, clipboard);
|
|
||||||
if (temp != -1) copymode = temp;
|
|
||||||
removepartpath(path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
void sdexplorer(char *items[], unsigned int *muhbits);
|
|
||||||
@@ -1,129 +0,0 @@
|
|||||||
#include <string.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include "../gfx/di.h"
|
|
||||||
#include "../gfx/gfx.h"
|
|
||||||
#include "../utils/btn.h"
|
|
||||||
#include "../utils/util.h"
|
|
||||||
#include "utils.h"
|
|
||||||
#include "../libs/fatfs/ff.h"
|
|
||||||
#include "../storage/sdmmc.h"
|
|
||||||
|
|
||||||
void utils_gfx_init(){
|
|
||||||
display_backlight_brightness(100, 1000);
|
|
||||||
gfx_clear_grey(0x1B);
|
|
||||||
gfx_con_setpos(0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void removepartpath(char *path){
|
|
||||||
char *ret;
|
|
||||||
ret = strrchr(path, '/');
|
|
||||||
memset(ret, '\0', 1);
|
|
||||||
if (strcmp(path, "sd:") == 0) strcpy(path, "sd:/");
|
|
||||||
}
|
|
||||||
|
|
||||||
void addpartpath(char *path, char *add){
|
|
||||||
if (strcmp(path, "sd:/") != 0) strcat(path, "/");
|
|
||||||
strcat(path, add);
|
|
||||||
}
|
|
||||||
|
|
||||||
void utils_waitforpower(){
|
|
||||||
u32 btn = btn_wait();
|
|
||||||
if (btn & BTN_VOL_UP)
|
|
||||||
reboot_rcm();
|
|
||||||
else if (btn & BTN_VOL_DOWN)
|
|
||||||
reboot_normal();
|
|
||||||
else
|
|
||||||
power_off();
|
|
||||||
}
|
|
||||||
|
|
||||||
void addchartoarray(char *add, char *items[], int spot){
|
|
||||||
size_t size = strlen(add) + 1;
|
|
||||||
items[spot] = (char*) malloc (size);
|
|
||||||
strlcpy(items[spot], add, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
void _mallocandaddfolderbit(unsigned int *muhbits, int spot, bool value){
|
|
||||||
muhbits[spot] = (unsigned int) malloc (sizeof(int));
|
|
||||||
if (value) muhbits[spot] |= (OPTION1);
|
|
||||||
//ff.h line 368
|
|
||||||
}
|
|
||||||
|
|
||||||
int readfolder(char *items[], unsigned int *muhbits, const char *path){
|
|
||||||
DIR dir;
|
|
||||||
FILINFO fno;
|
|
||||||
int i = 2;
|
|
||||||
addchartoarray("Current folder -> One folder up", items, 0);
|
|
||||||
addchartoarray("Clipboard -> Current folder", items, 1);
|
|
||||||
_mallocandaddfolderbit(muhbits, 0, true);
|
|
||||||
_mallocandaddfolderbit(muhbits, 1, true);
|
|
||||||
|
|
||||||
if (f_opendir(&dir, path)) {
|
|
||||||
gfx_printf("\nFailed to open %s", path);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
while (!f_readdir(&dir, &fno) && fno.fname[0]){
|
|
||||||
addchartoarray(fno.fname, items, i);
|
|
||||||
_mallocandaddfolderbit(muhbits, i, fno.fattrib & AM_DIR);
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
f_closedir(&dir);
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
int copy(const char *src, const char *dst){
|
|
||||||
FIL in;
|
|
||||||
FIL out;
|
|
||||||
|
|
||||||
if (f_open(&in, src, FA_READ) != FR_OK){
|
|
||||||
//something has gone wrong
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (f_open(&out, dst, FA_CREATE_ALWAYS | FA_WRITE) != FR_OK){
|
|
||||||
//something has gone wrong
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int BUFFSIZ = 32768;
|
|
||||||
u64 size = f_size(&in);
|
|
||||||
void *buff = malloc(BUFFSIZ);
|
|
||||||
int kbwritten = 0;
|
|
||||||
gfx_printf("%d\n", size);
|
|
||||||
while(size > BUFFSIZ){
|
|
||||||
int res1, res2;
|
|
||||||
res1 = f_read(&in, buff, BUFFSIZ, NULL);
|
|
||||||
res2 = f_write(&out, buff, BUFFSIZ, NULL);
|
|
||||||
|
|
||||||
kbwritten = kbwritten + BUFFSIZ;
|
|
||||||
|
|
||||||
gfx_printf("Written %d\r", kbwritten);
|
|
||||||
size = size - BUFFSIZ;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(size != 0){
|
|
||||||
f_read(&in, buff, size, NULL);
|
|
||||||
f_write(&out, buff, size, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
f_close(&in);
|
|
||||||
f_close(&out);
|
|
||||||
|
|
||||||
free(buff);
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int copywithpath(const char *src, const char *dstpath, int mode){
|
|
||||||
FILINFO fno;
|
|
||||||
f_stat(src, &fno);
|
|
||||||
char dst[255];
|
|
||||||
strcpy(dst, dstpath);
|
|
||||||
if (strcmp(dstpath, "sd:/") != 0) strcat(dst, "/");
|
|
||||||
strcat(dst, fno.fname);
|
|
||||||
int ret = -1;
|
|
||||||
if (mode == 0) ret = copy(src, dst);
|
|
||||||
if (mode == 1) f_rename(src, dst);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#define OPTION1 (1 << 0)
|
|
||||||
#define OPTION2 (1 << 1)
|
|
||||||
#define OPTION3 (1 << 2)
|
|
||||||
#define OPTION4 (1 << 3)
|
|
||||||
|
|
||||||
void utils_gfx_init();
|
|
||||||
void utils_waitforpower();
|
|
||||||
void removepartpath(char *path);
|
|
||||||
void addpartpath(char *path, char *add);
|
|
||||||
int readfolder(char *items[], unsigned int *muhbits, const char *path);
|
|
||||||
int copy(const char *src, const char *dst);
|
|
||||||
void addchartoarray(char *add, char *items[], int spot);
|
|
||||||
int copywithpath(const char *src, const char *dstpath, int mode);
|
|
||||||
170
source/power/bq24193.c
Normal file
170
source/power/bq24193.c
Normal file
@@ -0,0 +1,170 @@
|
|||||||
|
/*
|
||||||
|
* Battery charger driver for Nintendo Switch's TI BQ24193
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 CTCaer
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "bq24193.h"
|
||||||
|
#include "../soc/i2c.h"
|
||||||
|
#include "../utils/util.h"
|
||||||
|
|
||||||
|
#pragma GCC push_options
|
||||||
|
#pragma GCC optimize ("Os")
|
||||||
|
|
||||||
|
int bq24193_get_property(enum BQ24193_reg_prop prop, int *value)
|
||||||
|
{
|
||||||
|
u8 data;
|
||||||
|
|
||||||
|
switch (prop) {
|
||||||
|
case BQ24193_InputVoltageLimit: // Input voltage limit (mV).
|
||||||
|
data = i2c_recv_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_InputSource);
|
||||||
|
data = (data & BQ24193_INCONFIG_VINDPM_MASK) >> 3;
|
||||||
|
*value = 0;
|
||||||
|
*value += ((data >> 0) & 1) ? 80 : 0;
|
||||||
|
*value += ((data >> 1) & 1) ? 160 : 0;
|
||||||
|
*value += ((data >> 2) & 1) ? 320 : 0;
|
||||||
|
*value += ((data >> 3) & 1) ? 640 : 0;
|
||||||
|
*value += 3880;
|
||||||
|
break;
|
||||||
|
case BQ24193_InputCurrentLimit: // Input current limit (mA).
|
||||||
|
data = i2c_recv_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_InputSource);
|
||||||
|
data &= BQ24193_INCONFIG_INLIMIT_MASK;
|
||||||
|
switch (data)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
*value = 100;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
*value = 150;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
*value = 500;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
*value = 900;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
*value = 1200;
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
*value = 1500;
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
*value = 2000;
|
||||||
|
break;
|
||||||
|
case 7:
|
||||||
|
*value = 3000;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case BQ24193_SystemMinimumVoltage: // Minimum system voltage limit (mV).
|
||||||
|
data = i2c_recv_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_PORConfig);
|
||||||
|
*value = (data & BQ24193_PORCONFIG_SYSMIN_MASK) >> 1;
|
||||||
|
*value *= 100;
|
||||||
|
*value += 3000;
|
||||||
|
break;
|
||||||
|
case BQ24193_FastChargeCurrentLimit: // Fast charge current limit (mA).
|
||||||
|
data = i2c_recv_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_ChrgCurr);
|
||||||
|
data = (data & BQ24193_CHRGCURR_ICHG_MASK) >> 2;
|
||||||
|
*value = 0;
|
||||||
|
*value += ((data >> 0) & 1) ? 64 : 0;
|
||||||
|
*value += ((data >> 1) & 1) ? 128 : 0;
|
||||||
|
*value += ((data >> 2) & 1) ? 256 : 0;
|
||||||
|
*value += ((data >> 3) & 1) ? 512 : 0;
|
||||||
|
*value += ((data >> 4) & 1) ? 1024 : 0;
|
||||||
|
*value += ((data >> 5) & 1) ? 2048 : 0;
|
||||||
|
*value += 512;
|
||||||
|
data = i2c_recv_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_ChrgCurr);
|
||||||
|
data &= BQ24193_CHRGCURR_20PCT_MASK;
|
||||||
|
if (data)
|
||||||
|
*value = *value * 20 / 100; // Fast charge current limit is 20%.
|
||||||
|
break;
|
||||||
|
case BQ24193_ChargeVoltageLimit: // Charge voltage limit (mV).
|
||||||
|
data = i2c_recv_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_ChrgVolt);
|
||||||
|
data = (data & BQ24193_CHRGVOLT_VREG) >> 2;
|
||||||
|
*value = 0;
|
||||||
|
*value += ((data >> 0) & 1) ? 16 : 0;
|
||||||
|
*value += ((data >> 1) & 1) ? 32 : 0;
|
||||||
|
*value += ((data >> 2) & 1) ? 64 : 0;
|
||||||
|
*value += ((data >> 3) & 1) ? 128 : 0;
|
||||||
|
*value += ((data >> 4) & 1) ? 256 : 0;
|
||||||
|
*value += ((data >> 5) & 1) ? 512 : 0;
|
||||||
|
*value += 3504;
|
||||||
|
break;
|
||||||
|
case BQ24193_RechargeThreshold: // Recharge voltage threshold less than voltage limit (mV).
|
||||||
|
data = i2c_recv_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_ChrgVolt);
|
||||||
|
data &= BQ24193_IRTHERMAL_THERM_MASK;
|
||||||
|
if (data)
|
||||||
|
*value = 300;
|
||||||
|
else
|
||||||
|
*value = 100;
|
||||||
|
break;
|
||||||
|
case BQ24193_ThermalRegulation: // Thermal regulation threshold (oC).
|
||||||
|
data = i2c_recv_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_IRCompThermal);
|
||||||
|
data &= BQ24193_IRTHERMAL_THERM_MASK;
|
||||||
|
switch (data)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
*value = 60;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
*value = 80;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
*value = 100;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
*value = 120;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case BQ24193_ChargeStatus: // 0: Not charging, 1: Pre-charge, 2: Fast charging, 3: Charge termination done
|
||||||
|
data = i2c_recv_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_Status);
|
||||||
|
*value = (data & BQ24193_STATUS_CHRG_MASK) >> 4;
|
||||||
|
break;
|
||||||
|
case BQ24193_TempStatus: // 0: Normal, 2: Warm, 3: Cool, 5: Cold, 6: Hot.
|
||||||
|
data = i2c_recv_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_FaultReg);
|
||||||
|
*value = data & BQ24193_FAULT_THERM_MASK;
|
||||||
|
break;
|
||||||
|
case BQ24193_DevID: // Dev ID.
|
||||||
|
data = i2c_recv_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_VendorPart);
|
||||||
|
*value = data & BQ24193_VENDORPART_DEV_MASK;
|
||||||
|
break;
|
||||||
|
case BQ24193_ProductNumber: // Product number.
|
||||||
|
data = i2c_recv_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_VendorPart);
|
||||||
|
*value = (data & BQ24193_VENDORPART_PN_MASK) >> 3;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void bq24193_fake_battery_removal()
|
||||||
|
{
|
||||||
|
u8 value;
|
||||||
|
|
||||||
|
// Disable watchdog to keep BATFET disabled.
|
||||||
|
value = i2c_recv_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_ChrgTermTimer);
|
||||||
|
value &= ~BQ24193_CHRGTERM_WATCHDOG_MASK;
|
||||||
|
i2c_send_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_ChrgTermTimer, value);
|
||||||
|
|
||||||
|
// Force BATFET to disabled state. This disconnects the battery from the system.
|
||||||
|
value = i2c_recv_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_Misc);
|
||||||
|
value |= BQ24193_MISC_BATFET_DI_MASK;
|
||||||
|
i2c_send_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_Misc, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma GCC pop_options
|
||||||
119
source/power/bq24193.h
Normal file
119
source/power/bq24193.h
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
/*
|
||||||
|
* Battery charger driver for Nintendo Switch's TI BQ24193
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 CTCaer
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __BQ24193_H_
|
||||||
|
#define __BQ24193_H_
|
||||||
|
|
||||||
|
#define BQ24193_I2C_ADDR 0x6B
|
||||||
|
|
||||||
|
// REG 0 masks.
|
||||||
|
#define BQ24193_INCONFIG_INLIMIT_MASK (7<<0)
|
||||||
|
#define BQ24193_INCONFIG_VINDPM_MASK 0x78
|
||||||
|
#define BQ24193_INCONFIG_HIZ_EN_MASK (1<<7)
|
||||||
|
|
||||||
|
// REG 1 masks.
|
||||||
|
#define BQ24193_PORCONFIG_BOOST_MASK (1<<0)
|
||||||
|
#define BQ24193_PORCONFIG_SYSMIN_MASK (7<<1)
|
||||||
|
#define BQ24193_PORCONFIG_CHGCONFIG_MASK (3<<4)
|
||||||
|
#define BQ24193_PORCONFIG_I2CWATCHDOG_MASK (1<<6)
|
||||||
|
#define BQ24193_PORCONFIG_RESET_MASK (1<<7)
|
||||||
|
|
||||||
|
// REG 2 masks.
|
||||||
|
#define BQ24193_CHRGCURR_20PCT_MASK (1<<0)
|
||||||
|
#define BQ24193_CHRGCURR_ICHG_MASK 0xFC
|
||||||
|
|
||||||
|
// REG 3 masks.
|
||||||
|
#define BQ24193_PRECHRG_ITERM 0x0F
|
||||||
|
#define BQ24193_PRECHRG_IPRECHG 0xF0
|
||||||
|
|
||||||
|
// REG 4 masks.
|
||||||
|
#define BQ24193_CHRGVOLT_VTHRES (1<<0)
|
||||||
|
#define BQ24193_CHRGVOLT_BATTLOW (1<<1)
|
||||||
|
#define BQ24193_CHRGVOLT_VREG 0xFC
|
||||||
|
|
||||||
|
// REG 5 masks.
|
||||||
|
#define BQ24193_CHRGTERM_ISET_MASK (1<<0)
|
||||||
|
#define BQ24193_CHRGTERM_CHGTIMER_MASK (3<<1)
|
||||||
|
#define BQ24193_CHRGTERM_ENTIMER_MASK (1<<3)
|
||||||
|
#define BQ24193_CHRGTERM_WATCHDOG_MASK (3<<4)
|
||||||
|
#define BQ24193_CHRGTERM_TERM_ST_MASK (1<<6)
|
||||||
|
#define BQ24193_CHRGTERM_TERM_EN_MASK (1<<7)
|
||||||
|
|
||||||
|
// REG 6 masks.
|
||||||
|
#define BQ24193_IRTHERMAL_THERM_MASK (3<<0)
|
||||||
|
#define BQ24193_IRTHERMAL_VCLAMP_MASK (7<<2)
|
||||||
|
#define BQ24193_IRTHERMAL_BATTCOMP_MASK (7<<5)
|
||||||
|
|
||||||
|
// REG 7 masks.
|
||||||
|
#define BQ24193_MISC_INT_MASK (3<<0)
|
||||||
|
#define BQ24193_MISC_VSET_MASK (1<<4)
|
||||||
|
#define BQ24193_MISC_BATFET_DI_MASK (1<<5)
|
||||||
|
#define BQ24193_MISC_TMR2X_EN_MASK (1<<6)
|
||||||
|
#define BQ24193_MISC_DPDM_EN_MASK (1<<7)
|
||||||
|
|
||||||
|
// REG 8 masks.
|
||||||
|
#define BQ24193_STATUS_VSYS_MASK (1<<0)
|
||||||
|
#define BQ24193_STATUS_THERM_MASK (1<<1)
|
||||||
|
#define BQ24193_STATUS_PG_MASK (1<<2)
|
||||||
|
#define BQ24193_STATUS_DPM_MASK (1<<3)
|
||||||
|
#define BQ24193_STATUS_CHRG_MASK (3<<4)
|
||||||
|
#define BQ24193_STATUS_VBUS_MASK (3<<6)
|
||||||
|
|
||||||
|
// REG 9 masks.
|
||||||
|
#define BQ24193_FAULT_THERM_MASK (7<<0)
|
||||||
|
#define BQ24193_FAULT_BATT_OVP_MASK (1<<3)
|
||||||
|
#define BQ24193_FAULT_CHARGE_MASK (3<<4)
|
||||||
|
#define BQ24193_FAULT_BOOST_MASK (1<<6)
|
||||||
|
#define BQ24193_FAULT_WATCHDOG_MASK (1<<7)
|
||||||
|
|
||||||
|
// REG A masks.
|
||||||
|
#define BQ24193_VENDORPART_DEV_MASK (3<<0)
|
||||||
|
#define BQ24193_VENDORPART_PN_MASK (7<<3)
|
||||||
|
|
||||||
|
enum BQ24193_reg {
|
||||||
|
BQ24193_InputSource = 0x00,
|
||||||
|
BQ24193_PORConfig = 0x01,
|
||||||
|
BQ24193_ChrgCurr = 0x02,
|
||||||
|
BQ24193_PreChrgTerm = 0x03,
|
||||||
|
BQ24193_ChrgVolt = 0x04,
|
||||||
|
BQ24193_ChrgTermTimer = 0x05,
|
||||||
|
BQ24193_IRCompThermal = 0x06,
|
||||||
|
BQ24193_Misc = 0x07,
|
||||||
|
BQ24193_Status = 0x08,
|
||||||
|
BQ24193_FaultReg = 0x09,
|
||||||
|
BQ24193_VendorPart = 0x0A,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum BQ24193_reg_prop {
|
||||||
|
BQ24193_InputVoltageLimit, // REG 0.
|
||||||
|
BQ24193_InputCurrentLimit, // REG 0.
|
||||||
|
BQ24193_SystemMinimumVoltage, // REG 1.
|
||||||
|
BQ24193_FastChargeCurrentLimit, // REG 2.
|
||||||
|
BQ24193_ChargeVoltageLimit, // REG 4.
|
||||||
|
BQ24193_RechargeThreshold, // REG 4.
|
||||||
|
BQ24193_ThermalRegulation, // REG 6.
|
||||||
|
BQ24193_ChargeStatus, // REG 8.
|
||||||
|
BQ24193_TempStatus, // REG 9.
|
||||||
|
BQ24193_DevID, // REG A.
|
||||||
|
BQ24193_ProductNumber, // REG A.
|
||||||
|
};
|
||||||
|
|
||||||
|
int bq24193_get_property(enum BQ24193_reg_prop prop, int *value);
|
||||||
|
void bq24193_fake_battery_removal();
|
||||||
|
|
||||||
|
#endif /* __BQ24193_H_ */
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
/*
|
/*
|
||||||
* Fuel gauge driver for Nintendo Switch's Maxim 17050
|
* Fuel gauge driver for Nintendo Switch's Maxim 17050
|
||||||
*
|
*
|
||||||
* Copyright (C) 2011 Samsung Electronics
|
* Copyright (c) 2011 Samsung Electronics
|
||||||
* MyungJoo Ham <myungjoo.ham@samsung.com>
|
* MyungJoo Ham <myungjoo.ham@samsung.com>
|
||||||
* Copyright (C) 2018 CTCaer
|
* Copyright (c) 2018 CTCaer
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -43,6 +43,15 @@
|
|||||||
|
|
||||||
#define MAX17050_VMAX_TOLERANCE 50 /* 50 mV */
|
#define MAX17050_VMAX_TOLERANCE 50 /* 50 mV */
|
||||||
|
|
||||||
|
#pragma GCC push_options
|
||||||
|
#pragma GCC optimize ("Os")
|
||||||
|
|
||||||
|
static u32 battery_voltage = 0;
|
||||||
|
u32 max17050_get_cached_batt_volt()
|
||||||
|
{
|
||||||
|
return battery_voltage;
|
||||||
|
}
|
||||||
|
|
||||||
int max17050_get_property(enum MAX17050_reg reg, int *value)
|
int max17050_get_property(enum MAX17050_reg reg, int *value)
|
||||||
{
|
{
|
||||||
u16 data;
|
u16 data;
|
||||||
@@ -71,6 +80,7 @@ int max17050_get_property(enum MAX17050_reg reg, int *value)
|
|||||||
case MAX17050_VCELL: // Voltage now.
|
case MAX17050_VCELL: // Voltage now.
|
||||||
i2c_recv_buf_small((u8 *)&data, 2, I2C_1, MAXIM17050_I2C_ADDR, MAX17050_VCELL);
|
i2c_recv_buf_small((u8 *)&data, 2, I2C_1, MAXIM17050_I2C_ADDR, MAX17050_VCELL);
|
||||||
*value = data * 625 / 8 / 1000;
|
*value = data * 625 / 8 / 1000;
|
||||||
|
battery_voltage = *value;
|
||||||
break;
|
break;
|
||||||
case MAX17050_AvgVCELL: // Voltage avg.
|
case MAX17050_AvgVCELL: // Voltage avg.
|
||||||
i2c_recv_buf_small((u8 *)&data, 2, I2C_1, MAXIM17050_I2C_ADDR, MAX17050_AvgVCELL);
|
i2c_recv_buf_small((u8 *)&data, 2, I2C_1, MAXIM17050_I2C_ADDR, MAX17050_AvgVCELL);
|
||||||
@@ -264,3 +274,5 @@ int max17050_fix_configuration()
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#pragma GCC pop_options
|
||||||
@@ -2,9 +2,9 @@
|
|||||||
* Fuel gauge driver for Nintendo Switch's Maxim 17050
|
* Fuel gauge driver for Nintendo Switch's Maxim 17050
|
||||||
* Note that Maxim 8966 and 8997 are mfd and this is its subdevice.
|
* Note that Maxim 8966 and 8997 are mfd and this is its subdevice.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2011 Samsung Electronics
|
* Copyright (c) 2011 Samsung Electronics
|
||||||
* MyungJoo Ham <myungjoo.ham@samsung.com>
|
* MyungJoo Ham <myungjoo.ham@samsung.com>
|
||||||
* Copyright (C) 2018 CTCaer
|
* Copyright (c) 2018-2020 CTCaer
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -24,6 +24,8 @@
|
|||||||
#ifndef __MAX17050_H_
|
#ifndef __MAX17050_H_
|
||||||
#define __MAX17050_H_
|
#define __MAX17050_H_
|
||||||
|
|
||||||
|
#include "../utils/types.h"
|
||||||
|
|
||||||
#define MAX17050_STATUS_BattAbsent (1 << 3)
|
#define MAX17050_STATUS_BattAbsent (1 << 3)
|
||||||
#define MAX17050_DEFAULT_SNS_RESISTOR 10000
|
#define MAX17050_DEFAULT_SNS_RESISTOR 10000
|
||||||
|
|
||||||
@@ -96,14 +98,17 @@ enum MAX17050_reg {
|
|||||||
MAX17050_K_empty0 = 0x3B,
|
MAX17050_K_empty0 = 0x3B,
|
||||||
MAX17050_TaskPeriod = 0x3C,
|
MAX17050_TaskPeriod = 0x3C,
|
||||||
MAX17050_FSTAT = 0x3D,
|
MAX17050_FSTAT = 0x3D,
|
||||||
|
MAX17050_TIMER = 0x3E,
|
||||||
MAX17050_SHDNTIMER = 0x3F,
|
MAX17050_SHDNTIMER = 0x3F,
|
||||||
|
|
||||||
MAX17050_QRTbl30 = 0x42,
|
MAX17050_QRTbl30 = 0x42,
|
||||||
|
|
||||||
MAX17050_dQacc = 0x45,
|
MAX17050_dQacc = 0x45,
|
||||||
MAX17050_dPacc = 0x46,
|
MAX17050_dPacc = 0x46,
|
||||||
|
|
||||||
MAX17050_VFSOC0 = 0x48,
|
MAX17050_VFSOC0 = 0x48,
|
||||||
|
|
||||||
|
Max17050_QH0 = 0x4C,
|
||||||
MAX17050_QH = 0x4D,
|
MAX17050_QH = 0x4D,
|
||||||
MAX17050_QL = 0x4E,
|
MAX17050_QL = 0x4E,
|
||||||
|
|
||||||
@@ -111,6 +116,8 @@ enum MAX17050_reg {
|
|||||||
MAX17050_MaxVolt = 0x51, // Custom ID. Not to be sent to i2c.
|
MAX17050_MaxVolt = 0x51, // Custom ID. Not to be sent to i2c.
|
||||||
|
|
||||||
MAX17050_VFSOC0Enable = 0x60,
|
MAX17050_VFSOC0Enable = 0x60,
|
||||||
|
MAX17050_MODELEnable1 = 0x62,
|
||||||
|
MAX17050_MODELEnable2 = 0x63,
|
||||||
|
|
||||||
MAX17050_MODELChrTbl = 0x80,
|
MAX17050_MODELChrTbl = 0x80,
|
||||||
|
|
||||||
@@ -123,5 +130,6 @@ enum MAX17050_reg {
|
|||||||
|
|
||||||
int max17050_get_property(enum MAX17050_reg reg, int *value);
|
int max17050_get_property(enum MAX17050_reg reg, int *value);
|
||||||
int max17050_fix_configuration();
|
int max17050_fix_configuration();
|
||||||
|
u32 max17050_get_cached_batt_volt();
|
||||||
|
|
||||||
#endif /* __MAX17050_H_ */
|
#endif /* __MAX17050_H_ */
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Defining registers address and its bit definitions of MAX77620 and MAX20024
|
* Defining registers address and its bit definitions of MAX77620 and MAX20024
|
||||||
*
|
*
|
||||||
* Copyright (C) 2016 NVIDIA CORPORATION. All rights reserved.
|
* Copyright (c) 2016 NVIDIA CORPORATION. All rights reserved.
|
||||||
* Copyright (c) 2019 CTCaer
|
* Copyright (c) 2019 CTCaer
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
@@ -19,9 +19,19 @@
|
|||||||
#define MAX77620_CNFGGLBL1_LBDAC_EN (1 << 7)
|
#define MAX77620_CNFGGLBL1_LBDAC_EN (1 << 7)
|
||||||
#define MAX77620_CNFGGLBL1_MPPLD (1 << 6)
|
#define MAX77620_CNFGGLBL1_MPPLD (1 << 6)
|
||||||
#define MAX77620_CNFGGLBL1_LBHYST ((1 << 5) | (1 << 4))
|
#define MAX77620_CNFGGLBL1_LBHYST ((1 << 5) | (1 << 4))
|
||||||
#define MAX77620_CNFGGLBL1_LBHYST_N (1 << 4)
|
#define MAX77620_CNFGGLBL1_LBHYST_100 (0 << 4)
|
||||||
#define MAX77620_CNFGGLBL1_LBDAC 0x0E
|
#define MAX77620_CNFGGLBL1_LBHYST_200 (1 << 4)
|
||||||
#define MAX77620_CNFGGLBL1_LBDAC_N (1 << 1)
|
#define MAX77620_CNFGGLBL1_LBHYST_300 (2 << 4)
|
||||||
|
#define MAX77620_CNFGGLBL1_LBHYST_400 (3 << 4)
|
||||||
|
#define MAX77620_CNFGGLBL1_LBDAC_MASK 0x0E
|
||||||
|
#define MAX77620_CNFGGLBL1_LBDAC_2700 (0 << 1)
|
||||||
|
#define MAX77620_CNFGGLBL1_LBDAC_2800 (1 << 1)
|
||||||
|
#define MAX77620_CNFGGLBL1_LBDAC_2900 (2 << 1)
|
||||||
|
#define MAX77620_CNFGGLBL1_LBDAC_3000 (3 << 1)
|
||||||
|
#define MAX77620_CNFGGLBL1_LBDAC_3100 (4 << 1)
|
||||||
|
#define MAX77620_CNFGGLBL1_LBDAC_3200 (5 << 1)
|
||||||
|
#define MAX77620_CNFGGLBL1_LBDAC_3300 (6 << 1)
|
||||||
|
#define MAX77620_CNFGGLBL1_LBDAC_3400 (7 << 1)
|
||||||
#define MAX77620_CNFGGLBL1_LBRSTEN (1 << 0)
|
#define MAX77620_CNFGGLBL1_LBRSTEN (1 << 0)
|
||||||
|
|
||||||
#define MAX77620_REG_CNFGGLBL2 0x01
|
#define MAX77620_REG_CNFGGLBL2 0x01
|
||||||
@@ -130,7 +140,7 @@
|
|||||||
#define MAX77620_POWER_MODE_DISABLE 0
|
#define MAX77620_POWER_MODE_DISABLE 0
|
||||||
#define MAX20024_LDO_CFG2_MPOK_MASK (1 << 2)
|
#define MAX20024_LDO_CFG2_MPOK_MASK (1 << 2)
|
||||||
#define MAX77620_LDO_CFG2_ADE_MASK (1 << 1)
|
#define MAX77620_LDO_CFG2_ADE_MASK (1 << 1)
|
||||||
#define MAX77620_LDO_CFG2_ADE_DISABLE 0
|
#define MAX77620_LDO_CFG2_ADE_DISABLE (0 << 1)
|
||||||
#define MAX77620_LDO_CFG2_ADE_ENABLE (1 << 1)
|
#define MAX77620_LDO_CFG2_ADE_ENABLE (1 << 1)
|
||||||
#define MAX77620_LDO_CFG2_SS_MASK (1 << 0)
|
#define MAX77620_LDO_CFG2_SS_MASK (1 << 0)
|
||||||
#define MAX77620_LDO_CFG2_SS_FAST (1 << 0)
|
#define MAX77620_LDO_CFG2_SS_FAST (1 << 0)
|
||||||
@@ -153,6 +163,24 @@
|
|||||||
#define MAX77620_REG_PUE_GPIO 0x3E
|
#define MAX77620_REG_PUE_GPIO 0x3E
|
||||||
#define MAX77620_REG_PDE_GPIO 0x3F
|
#define MAX77620_REG_PDE_GPIO 0x3F
|
||||||
#define MAX77620_REG_AME_GPIO 0x40
|
#define MAX77620_REG_AME_GPIO 0x40
|
||||||
|
#define MAX77620_CNFG_GPIO_DRV_MASK (1 << 0)
|
||||||
|
#define MAX77620_CNFG_GPIO_DRV_PUSHPULL (1 << 0)
|
||||||
|
#define MAX77620_CNFG_GPIO_DRV_OPENDRAIN (0 << 0)
|
||||||
|
#define MAX77620_CNFG_GPIO_DIR_MASK (1 << 1)
|
||||||
|
#define MAX77620_CNFG_GPIO_DIR_INPUT (1 << 1)
|
||||||
|
#define MAX77620_CNFG_GPIO_DIR_OUTPUT (0 << 1)
|
||||||
|
#define MAX77620_CNFG_GPIO_INPUT_VAL_MASK (1 << 2)
|
||||||
|
#define MAX77620_CNFG_GPIO_OUTPUT_VAL_MASK (1 << 3)
|
||||||
|
#define MAX77620_CNFG_GPIO_OUTPUT_VAL_HIGH (1 << 3)
|
||||||
|
#define MAX77620_CNFG_GPIO_OUTPUT_VAL_LOW (0 << 3)
|
||||||
|
#define MAX77620_CNFG_GPIO_INT_MASK (0x3 << 4)
|
||||||
|
#define MAX77620_CNFG_GPIO_INT_FALLING (1 << 4)
|
||||||
|
#define MAX77620_CNFG_GPIO_INT_RISING (1 << 5)
|
||||||
|
#define MAX77620_CNFG_GPIO_DBNC_MASK (0x3 << 6)
|
||||||
|
#define MAX77620_CNFG_GPIO_DBNC_None (0x0 << 6)
|
||||||
|
#define MAX77620_CNFG_GPIO_DBNC_8ms (0x1 << 6)
|
||||||
|
#define MAX77620_CNFG_GPIO_DBNC_16ms (0x2 << 6)
|
||||||
|
#define MAX77620_CNFG_GPIO_DBNC_32ms (0x3 << 6)
|
||||||
|
|
||||||
#define MAX77620_REG_ONOFFCNFG1 0x41
|
#define MAX77620_REG_ONOFFCNFG1 0x41
|
||||||
#define MAX77620_ONOFFCNFG1_SFT_RST (1 << 7)
|
#define MAX77620_ONOFFCNFG1_SFT_RST (1 << 7)
|
||||||
@@ -259,25 +287,6 @@
|
|||||||
#define MAX77620_SD_CFG1_FSRADE_SD_DISABLE 0
|
#define MAX77620_SD_CFG1_FSRADE_SD_DISABLE 0
|
||||||
#define MAX77620_SD_CFG1_FSRADE_SD_ENABLE (1 << 0)
|
#define MAX77620_SD_CFG1_FSRADE_SD_ENABLE (1 << 0)
|
||||||
|
|
||||||
#define MAX77620_CNFG_GPIO_DRV_MASK (1 << 0)
|
|
||||||
#define MAX77620_CNFG_GPIO_DRV_PUSHPULL (1 << 0)
|
|
||||||
#define MAX77620_CNFG_GPIO_DRV_OPENDRAIN 0
|
|
||||||
#define MAX77620_CNFG_GPIO_DIR_MASK (1 << 1)
|
|
||||||
#define MAX77620_CNFG_GPIO_DIR_INPUT (1 << 1)
|
|
||||||
#define MAX77620_CNFG_GPIO_DIR_OUTPUT 0
|
|
||||||
#define MAX77620_CNFG_GPIO_INPUT_VAL_MASK (1 << 2)
|
|
||||||
#define MAX77620_CNFG_GPIO_OUTPUT_VAL_MASK (1 << 3)
|
|
||||||
#define MAX77620_CNFG_GPIO_OUTPUT_VAL_HIGH (1 << 3)
|
|
||||||
#define MAX77620_CNFG_GPIO_OUTPUT_VAL_LOW 0
|
|
||||||
#define MAX77620_CNFG_GPIO_INT_MASK (0x3 << 4)
|
|
||||||
#define MAX77620_CNFG_GPIO_INT_FALLING (1 << 4)
|
|
||||||
#define MAX77620_CNFG_GPIO_INT_RISING (1 << 5)
|
|
||||||
#define MAX77620_CNFG_GPIO_DBNC_MASK (0x3 << 6)
|
|
||||||
#define MAX77620_CNFG_GPIO_DBNC_None (0x0 << 6)
|
|
||||||
#define MAX77620_CNFG_GPIO_DBNC_8ms (0x1 << 6)
|
|
||||||
#define MAX77620_CNFG_GPIO_DBNC_16ms (0x2 << 6)
|
|
||||||
#define MAX77620_CNFG_GPIO_DBNC_32ms (0x3 << 6)
|
|
||||||
|
|
||||||
#define MAX77620_IRQ_LVL2_GPIO_EDGE0 (1 << 0)
|
#define MAX77620_IRQ_LVL2_GPIO_EDGE0 (1 << 0)
|
||||||
#define MAX77620_IRQ_LVL2_GPIO_EDGE1 (1 << 1)
|
#define MAX77620_IRQ_LVL2_GPIO_EDGE1 (1 << 1)
|
||||||
#define MAX77620_IRQ_LVL2_GPIO_EDGE2 (1 << 2)
|
#define MAX77620_IRQ_LVL2_GPIO_EDGE2 (1 << 2)
|
||||||
|
|||||||
@@ -64,6 +64,16 @@ static const max77620_regulator_t _pmic_regulators[] = {
|
|||||||
{ REGULATOR_LDO, "ldo8", 0x00, 50000, 800000, 1050000, 1050000, MAX77620_REG_LDO8_CFG, MAX77620_REG_LDO8_CFG2, MAX77620_LDO_VOLT_MASK, MAX77620_LDO_POWER_MODE_MASK, MAX77620_LDO_POWER_MODE_SHIFT, 0x00, MAX77620_REG_FPS_LDO8, 3, 7, 0 }
|
{ REGULATOR_LDO, "ldo8", 0x00, 50000, 800000, 1050000, 1050000, MAX77620_REG_LDO8_CFG, MAX77620_REG_LDO8_CFG2, MAX77620_LDO_VOLT_MASK, MAX77620_LDO_POWER_MODE_MASK, MAX77620_LDO_POWER_MODE_SHIFT, 0x00, MAX77620_REG_FPS_LDO8, 3, 7, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void _max77620_try_set_reg(u8 reg, u8 val)
|
||||||
|
{
|
||||||
|
u8 tmp;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, reg, val);
|
||||||
|
tmp = i2c_recv_byte(I2C_5, MAX77620_I2C_ADDR, reg);
|
||||||
|
} while (val != tmp);
|
||||||
|
}
|
||||||
|
|
||||||
int max77620_regulator_get_status(u32 id)
|
int max77620_regulator_get_status(u32 id)
|
||||||
{
|
{
|
||||||
if (id > REGULATOR_MAX)
|
if (id > REGULATOR_MAX)
|
||||||
@@ -83,7 +93,7 @@ int max77620_regulator_config_fps(u32 id)
|
|||||||
|
|
||||||
const max77620_regulator_t *reg = &_pmic_regulators[id];
|
const max77620_regulator_t *reg = &_pmic_regulators[id];
|
||||||
|
|
||||||
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, reg->fps_addr,
|
_max77620_try_set_reg(reg->fps_addr,
|
||||||
(reg->fps_src << MAX77620_FPS_SRC_SHIFT) | (reg->pu_period << MAX77620_FPS_PU_PERIOD_SHIFT) | (reg->pd_period));
|
(reg->fps_src << MAX77620_FPS_SRC_SHIFT) | (reg->pu_period << MAX77620_FPS_PU_PERIOD_SHIFT) | (reg->pd_period));
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
@@ -102,7 +112,7 @@ int max77620_regulator_set_voltage(u32 id, u32 mv)
|
|||||||
u32 mult = (mv + reg->mv_step - 1 - reg->mv_min) / reg->mv_step;
|
u32 mult = (mv + reg->mv_step - 1 - reg->mv_min) / reg->mv_step;
|
||||||
u8 val = i2c_recv_byte(I2C_5, MAX77620_I2C_ADDR, reg->volt_addr);
|
u8 val = i2c_recv_byte(I2C_5, MAX77620_I2C_ADDR, reg->volt_addr);
|
||||||
val = (val & ~reg->volt_mask) | (mult & reg->volt_mask);
|
val = (val & ~reg->volt_mask) | (mult & reg->volt_mask);
|
||||||
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, reg->volt_addr, val);
|
_max77620_try_set_reg(reg->volt_addr, val);
|
||||||
usleep(1000);
|
usleep(1000);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
@@ -121,12 +131,13 @@ int max77620_regulator_enable(u32 id, int enable)
|
|||||||
val = (val & ~reg->enable_mask) | ((MAX77620_POWER_MODE_NORMAL << reg->enable_shift) & reg->enable_mask);
|
val = (val & ~reg->enable_mask) | ((MAX77620_POWER_MODE_NORMAL << reg->enable_shift) & reg->enable_mask);
|
||||||
else
|
else
|
||||||
val &= ~reg->enable_mask;
|
val &= ~reg->enable_mask;
|
||||||
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, addr, val);
|
_max77620_try_set_reg(addr, val);
|
||||||
usleep(1000);
|
usleep(1000);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LDO only.
|
||||||
int max77620_regulator_set_volt_and_flags(u32 id, u32 mv, u8 flags)
|
int max77620_regulator_set_volt_and_flags(u32 id, u32 mv, u8 flags)
|
||||||
{
|
{
|
||||||
if (id > REGULATOR_MAX)
|
if (id > REGULATOR_MAX)
|
||||||
@@ -139,7 +150,7 @@ int max77620_regulator_set_volt_and_flags(u32 id, u32 mv, u8 flags)
|
|||||||
|
|
||||||
u32 mult = (mv + reg->mv_step - 1 - reg->mv_min) / reg->mv_step;
|
u32 mult = (mv + reg->mv_step - 1 - reg->mv_min) / reg->mv_step;
|
||||||
u8 val = ((flags << reg->enable_shift) & ~reg->volt_mask) | (mult & reg->volt_mask);
|
u8 val = ((flags << reg->enable_shift) & ~reg->volt_mask) | (mult & reg->volt_mask);
|
||||||
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, reg->volt_addr, val);
|
_max77620_try_set_reg(reg->volt_addr, val);
|
||||||
usleep(1000);
|
usleep(1000);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
@@ -155,11 +166,12 @@ void max77620_config_default()
|
|||||||
if (_pmic_regulators[i].fps_src != MAX77620_FPS_SRC_NONE)
|
if (_pmic_regulators[i].fps_src != MAX77620_FPS_SRC_NONE)
|
||||||
max77620_regulator_enable(i, 1);
|
max77620_regulator_enable(i, 1);
|
||||||
}
|
}
|
||||||
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_SD_CFG2, 4);
|
_max77620_try_set_reg(MAX77620_REG_SD_CFG2, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
void max77620_low_battery_monitor_config()
|
void max77620_low_battery_monitor_config(bool enable)
|
||||||
{
|
{
|
||||||
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_CNFGGLBL1,
|
_max77620_try_set_reg(MAX77620_REG_CNFGGLBL1,
|
||||||
MAX77620_CNFGGLBL1_LBDAC_EN | MAX77620_CNFGGLBL1_LBHYST_N | MAX77620_CNFGGLBL1_LBDAC_N);
|
MAX77620_CNFGGLBL1_LBDAC_EN | (enable ? MAX77620_CNFGGLBL1_MPPLD : 0) |
|
||||||
|
MAX77620_CNFGGLBL1_LBHYST_200 | MAX77620_CNFGGLBL1_LBDAC_2800);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,7 @@
|
|||||||
* Switch Power domains (max77620):
|
* Switch Power domains (max77620):
|
||||||
* Name | Usage | uV step | uV min | uV default | uV max | Init
|
* Name | Usage | uV step | uV min | uV default | uV max | Init
|
||||||
*-------+---------------+---------+--------+------------+---------+------------------
|
*-------+---------------+---------+--------+------------+---------+------------------
|
||||||
* sd0 | core | 12500 | 600000 | 625000 | 1400000 | 1.125V (pkg1.1)
|
* sd0 | SoC | 12500 | 600000 | 625000 | 1400000 | 1.125V (pkg1.1)
|
||||||
* sd1 | SDRAM | 12500 | 600000 | 1125000 | 1125000 | 1.1V (pkg1.1)
|
* sd1 | SDRAM | 12500 | 600000 | 1125000 | 1125000 | 1.1V (pkg1.1)
|
||||||
* sd2 | ldo{0-1, 7-8} | 12500 | 600000 | 1325000 | 1350000 | 1.325V (pcv)
|
* sd2 | ldo{0-1, 7-8} | 12500 | 600000 | 1325000 | 1350000 | 1.325V (pcv)
|
||||||
* sd3 | 1.8V general | 12500 | 600000 | 1800000 | 1800000 |
|
* sd3 | 1.8V general | 12500 | 600000 | 1800000 | 1800000 |
|
||||||
@@ -33,7 +33,7 @@
|
|||||||
* ldo2 | SDMMC1 | 50000 | 800000 | 1800000 | 3300000 |
|
* ldo2 | SDMMC1 | 50000 | 800000 | 1800000 | 3300000 |
|
||||||
* ldo3 | GC ASIC | 50000 | 800000 | 3100000 | 3100000 | 3.1V (pcv)
|
* ldo3 | GC ASIC | 50000 | 800000 | 3100000 | 3100000 | 3.1V (pcv)
|
||||||
* ldo4 | RTC | 12500 | 800000 | 850000 | 850000 |
|
* ldo4 | RTC | 12500 | 800000 | 850000 | 850000 |
|
||||||
* ldo5 | GC ASIC | 50000 | 800000 | 1800000 | 1800000 | 1.8V (pcv)
|
* ldo5 | GC Card | 50000 | 800000 | 1800000 | 1800000 | 1.8V (pcv)
|
||||||
* ldo6 | Touch, ALS | 50000 | 800000 | 2900000 | 2900000 | 2.9V
|
* ldo6 | Touch, ALS | 50000 | 800000 | 2900000 | 2900000 | 2.9V
|
||||||
* ldo7 | XUSB | 50000 | 800000 | 1050000 | 1050000 |
|
* ldo7 | XUSB | 50000 | 800000 | 1050000 | 1050000 |
|
||||||
* ldo8 | XUSB, DC | 50000 | 800000 | 1050000 | 1050000 |
|
* ldo8 | XUSB, DC | 50000 | 800000 | 1050000 | 1050000 |
|
||||||
@@ -71,6 +71,8 @@
|
|||||||
/* MAX77621_VOUT */
|
/* MAX77621_VOUT */
|
||||||
#define MAX77621_VOUT_ENABLE (1 << 7)
|
#define MAX77621_VOUT_ENABLE (1 << 7)
|
||||||
#define MAX77621_VOUT_MASK 0x7F
|
#define MAX77621_VOUT_MASK 0x7F
|
||||||
|
#define MAX77621_VOUT_0_95V 0x37
|
||||||
|
#define MAX77621_VOUT_1_09V 0x4F
|
||||||
|
|
||||||
/* MAX77621_VOUT_DVC_DVS */
|
/* MAX77621_VOUT_DVC_DVS */
|
||||||
#define MAX77621_DVS_VOUT_MASK 0x7F
|
#define MAX77621_DVS_VOUT_MASK 0x7F
|
||||||
@@ -111,6 +113,6 @@ int max77620_regulator_set_voltage(u32 id, u32 mv);
|
|||||||
int max77620_regulator_enable(u32 id, int enable);
|
int max77620_regulator_enable(u32 id, int enable);
|
||||||
int max77620_regulator_set_volt_and_flags(u32 id, u32 mv, u8 flags);
|
int max77620_regulator_set_volt_and_flags(u32 id, u32 mv, u8 flags);
|
||||||
void max77620_config_default();
|
void max77620_config_default();
|
||||||
void max77620_low_battery_monitor_config();
|
void max77620_low_battery_monitor_config(bool enable);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
76
source/power/regulator_5v.c
Normal file
76
source/power/regulator_5v.c
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019 CTCaer
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "../soc/gpio.h"
|
||||||
|
#include "../soc/pinmux.h"
|
||||||
|
#include "../soc/pmc.h"
|
||||||
|
#include "../soc/t210.h"
|
||||||
|
#include "../utils/types.h"
|
||||||
|
|
||||||
|
static u8 reg_5v_dev = 0;
|
||||||
|
|
||||||
|
void regulator_enable_5v(u8 dev)
|
||||||
|
{
|
||||||
|
// The power supply selection from battery or USB is automatic.
|
||||||
|
if (!reg_5v_dev)
|
||||||
|
{
|
||||||
|
// Fan and Rail power from internal 5V regulator (battery).
|
||||||
|
PINMUX_AUX(PINMUX_AUX_SATA_LED_ACTIVE) = 1;
|
||||||
|
gpio_config(GPIO_PORT_A, GPIO_PIN_5, GPIO_MODE_GPIO);
|
||||||
|
gpio_output_enable(GPIO_PORT_A, GPIO_PIN_5, GPIO_OUTPUT_ENABLE);
|
||||||
|
gpio_write(GPIO_PORT_A, GPIO_PIN_5, GPIO_HIGH);
|
||||||
|
|
||||||
|
// Fan and Rail power from USB 5V VDD.
|
||||||
|
PINMUX_AUX(PINMUX_AUX_USB_VBUS_EN0) = PINMUX_LPDR | 1;
|
||||||
|
gpio_config(GPIO_PORT_CC, GPIO_PIN_4, GPIO_MODE_GPIO);
|
||||||
|
gpio_output_enable(GPIO_PORT_CC, GPIO_PIN_4, GPIO_OUTPUT_ENABLE);
|
||||||
|
gpio_write(GPIO_PORT_CC, GPIO_PIN_4, GPIO_HIGH);
|
||||||
|
|
||||||
|
// Make sure GPIO power is enabled.
|
||||||
|
PMC(APBDEV_PMC_NO_IOPOWER) &= ~PMC_NO_IOPOWER_GPIO_IO_EN;
|
||||||
|
// Override power detect for GPIO AO IO rails.
|
||||||
|
PMC(APBDEV_PMC_PWR_DET_VAL) &= ~PMC_PWR_DET_GPIO_IO_EN;
|
||||||
|
}
|
||||||
|
reg_5v_dev |= dev;
|
||||||
|
}
|
||||||
|
|
||||||
|
void regulator_disable_5v(u8 dev)
|
||||||
|
{
|
||||||
|
reg_5v_dev &= ~dev;
|
||||||
|
|
||||||
|
if (!reg_5v_dev)
|
||||||
|
{
|
||||||
|
// Rail power from internal 5V regulator (battery).
|
||||||
|
gpio_write(GPIO_PORT_A, GPIO_PIN_5, GPIO_LOW);
|
||||||
|
gpio_output_enable(GPIO_PORT_A, GPIO_PIN_5, GPIO_OUTPUT_DISABLE);
|
||||||
|
gpio_config(GPIO_PORT_A, GPIO_PIN_5, GPIO_MODE_SPIO);
|
||||||
|
PINMUX_AUX(PINMUX_AUX_SATA_LED_ACTIVE) = PINMUX_PARKED | PINMUX_INPUT_ENABLE;
|
||||||
|
|
||||||
|
// Rail power from USB 5V VDD.
|
||||||
|
gpio_write(GPIO_PORT_CC, GPIO_PIN_4, GPIO_LOW);
|
||||||
|
gpio_output_enable(GPIO_PORT_CC, GPIO_PIN_4, GPIO_OUTPUT_DISABLE);
|
||||||
|
gpio_config(GPIO_PORT_CC, GPIO_PIN_4, GPIO_MODE_SPIO);
|
||||||
|
PINMUX_AUX(PINMUX_AUX_USB_VBUS_EN0) = PINMUX_IO_HV | PINMUX_LPDR | PINMUX_PARKED | PINMUX_INPUT_ENABLE;
|
||||||
|
|
||||||
|
// GPIO AO IO rails.
|
||||||
|
PMC(APBDEV_PMC_PWR_DET_VAL) |= PMC_PWR_DET_GPIO_IO_EN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool regulator_get_5v_dev_enabled(u8 dev)
|
||||||
|
{
|
||||||
|
return (reg_5v_dev & dev);
|
||||||
|
}
|
||||||
34
source/power/regulator_5v.h
Normal file
34
source/power/regulator_5v.h
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019 CTCaer
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _REGULATOR_5V_H_
|
||||||
|
#define _REGULATOR_5V_H_
|
||||||
|
|
||||||
|
#include "../utils/types.h"
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
REGULATOR_5V_FAN = (1 << 0),
|
||||||
|
REGULATOR_5V_JC_R = (1 << 1),
|
||||||
|
REGULATOR_5V_JC_L = (1 << 2),
|
||||||
|
REGULATOR_5V_ALL = 0xFF
|
||||||
|
};
|
||||||
|
|
||||||
|
void regulator_enable_5v(u8 dev);
|
||||||
|
void regulator_disable_5v(u8 dev);
|
||||||
|
bool regulator_get_5v_dev_enabled(u8 dev);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -1,7 +1,8 @@
|
|||||||
/*
|
/*
|
||||||
* PMIC Real Time Clock driver for Nintendo Switch's MAX77620-RTC
|
* PMIC Real Time Clock driver for Nintendo Switch's MAX77620-RTC
|
||||||
*
|
*
|
||||||
* Copyright (c) 2018 CTCaer
|
* Copyright (c) 2018-2019 CTCaer
|
||||||
|
* Copyright (c) 2019 shchmue
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
* under the terms and conditions of the GNU General Public License,
|
* under the terms and conditions of the GNU General Public License,
|
||||||
@@ -34,10 +35,10 @@ void max77620_rtc_get_time(rtc_time_t *time)
|
|||||||
// Get time.
|
// Get time.
|
||||||
time->sec = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_SEC_REG) & 0x7F;
|
time->sec = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_SEC_REG) & 0x7F;
|
||||||
time->min = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_MIN_REG) & 0x7F;
|
time->min = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_MIN_REG) & 0x7F;
|
||||||
|
u8 hour = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_HOUR_REG);
|
||||||
|
time->hour = hour & 0x1F;
|
||||||
|
|
||||||
time->hour = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_HOUR_REG) & 0x1F;
|
if (!(val & MAX77620_RTC_24H) && (hour & MAX77620_RTC_HOUR_PM_MASK))
|
||||||
|
|
||||||
if (!(val & MAX77620_RTC_24H) && time->hour & MAX77620_RTC_HOUR_PM_MASK)
|
|
||||||
time->hour = (time->hour & 0xF) + 12;
|
time->hour = (time->hour & 0xF) + 12;
|
||||||
|
|
||||||
// Get day of week. 1: Monday to 7: Sunday.
|
// Get day of week. 1: Monday to 7: Sunday.
|
||||||
@@ -52,7 +53,7 @@ void max77620_rtc_get_time(rtc_time_t *time)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get date.
|
// Get date.
|
||||||
time->date = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_DATE_REG) & 0x1f;
|
time->day = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_DATE_REG) & 0x1f;
|
||||||
time->month = (i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_MONTH_REG) & 0xF) - 1;
|
time->month = (i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_MONTH_REG) & 0xF) - 1;
|
||||||
time->year = (i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_YEAR_REG) & 0x7F) + 2000;
|
time->year = (i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_YEAR_REG) & 0x7F) + 2000;
|
||||||
}
|
}
|
||||||
@@ -75,3 +76,94 @@ void max77620_rtc_stop_alarm()
|
|||||||
// Update RTC clock from RTC regs.
|
// Update RTC clock from RTC regs.
|
||||||
i2c_send_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_UPDATE0_REG, MAX77620_RTC_WRITE_UPDATE);
|
i2c_send_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_UPDATE0_REG, MAX77620_RTC_WRITE_UPDATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void max77620_rtc_epoch_to_date(u32 epoch, rtc_time_t *time)
|
||||||
|
{
|
||||||
|
u32 tmp, edays, year, month, day;
|
||||||
|
|
||||||
|
// Set time.
|
||||||
|
time->sec = epoch % 60;
|
||||||
|
epoch /= 60;
|
||||||
|
time->min = epoch % 60;
|
||||||
|
epoch /= 60;
|
||||||
|
time->hour = epoch % 24;
|
||||||
|
epoch /= 24;
|
||||||
|
|
||||||
|
// Calculate base date values.
|
||||||
|
tmp = (u32)(((u64)4 * epoch + 102032) / 146097 + 15);
|
||||||
|
tmp = (u32)((u64)epoch + 2442113 + tmp - (tmp >> 2));
|
||||||
|
|
||||||
|
year = (20 * tmp - 2442) / 7305;
|
||||||
|
edays = tmp - 365 * year - (year >> 2);
|
||||||
|
month = edays * 1000 / 30601;
|
||||||
|
day = edays - month * 30 - month * 601 / 1000;
|
||||||
|
|
||||||
|
// Month/Year offset.
|
||||||
|
if(month < 14)
|
||||||
|
{
|
||||||
|
year -= 4716;
|
||||||
|
month--;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
year -= 4715;
|
||||||
|
month -= 13;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set date.
|
||||||
|
time->year = year;
|
||||||
|
time->month = month;
|
||||||
|
time->day = day;
|
||||||
|
|
||||||
|
// Set weekday.
|
||||||
|
time->weekday = 0; //! TODO.
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 max77620_rtc_date_to_epoch(const rtc_time_t *time, bool hos_encoding)
|
||||||
|
{
|
||||||
|
u32 year, month, epoch;
|
||||||
|
|
||||||
|
//Year
|
||||||
|
year = time->year;
|
||||||
|
//Month of year
|
||||||
|
month = time->month;
|
||||||
|
|
||||||
|
if (!hos_encoding)
|
||||||
|
{
|
||||||
|
// Month/Year offset.
|
||||||
|
if(month < 3)
|
||||||
|
{
|
||||||
|
month += 12;
|
||||||
|
year--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
year -= 2000;
|
||||||
|
month++;
|
||||||
|
|
||||||
|
// Month/Year offset.
|
||||||
|
if(month < 3)
|
||||||
|
{
|
||||||
|
month += 9;
|
||||||
|
year--;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
month -= 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
epoch = (365 * year) + (year >> 2) - (year / 100) + (year / 400); // Years to days.
|
||||||
|
|
||||||
|
if (!hos_encoding)
|
||||||
|
{
|
||||||
|
epoch += (30 * month) + (3 * (month + 1) / 5) + time->day; // Months to days.
|
||||||
|
epoch -= 719561; // Epoch time is 1/1/1970.
|
||||||
|
}
|
||||||
|
else
|
||||||
|
epoch += (30 * month) + ((3 * month + 2) / 5) + 59 + time->day; // Months to days.
|
||||||
|
|
||||||
|
epoch *= 86400; // Days to seconds.
|
||||||
|
epoch += (3600 * time->hour) + (60 * time->min) + time->sec; // Add hours, minutes and seconds.
|
||||||
|
|
||||||
|
return epoch;
|
||||||
|
}
|
||||||
|
|||||||
@@ -64,12 +64,14 @@ typedef struct _rtc_time_t {
|
|||||||
u8 sec;
|
u8 sec;
|
||||||
u8 min;
|
u8 min;
|
||||||
u8 hour;
|
u8 hour;
|
||||||
u8 date;
|
u8 day;
|
||||||
u8 month;
|
u8 month;
|
||||||
u16 year;
|
u16 year;
|
||||||
} rtc_time_t;
|
} rtc_time_t;
|
||||||
|
|
||||||
void max77620_rtc_get_time(rtc_time_t *time);
|
void max77620_rtc_get_time(rtc_time_t *time);
|
||||||
void max77620_rtc_stop_alarm();
|
void max77620_rtc_stop_alarm();
|
||||||
|
void max77620_rtc_epoch_to_date(u32 epoch, rtc_time_t *time);
|
||||||
|
u32 max77620_rtc_date_to_epoch(const rtc_time_t *time, bool hos_encoding);
|
||||||
|
|
||||||
#endif /* _MFD_MAX77620_RTC_H_ */
|
#endif /* _MFD_MAX77620_RTC_H_ */
|
||||||
|
|||||||
227
source/sec/se.c
227
source/sec/se.c
@@ -1,8 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2018 naehrwert
|
* Copyright (c) 2018 naehrwert
|
||||||
* Copyright (c) 2018 CTCaer
|
* Copyright (c) 2018 CTCaer
|
||||||
* Copyright (c) 2018 Atmosphère-NX
|
|
||||||
* Copyright (c) 2019 shchmue
|
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
* under the terms and conditions of the GNU General Public License,
|
* under the terms and conditions of the GNU General Public License,
|
||||||
@@ -21,6 +19,7 @@
|
|||||||
|
|
||||||
#include "../sec/se.h"
|
#include "../sec/se.h"
|
||||||
#include "../mem/heap.h"
|
#include "../mem/heap.h"
|
||||||
|
#include "../soc/bpmp.h"
|
||||||
#include "../soc/t210.h"
|
#include "../soc/t210.h"
|
||||||
#include "../sec/se_t210.h"
|
#include "../sec/se_t210.h"
|
||||||
#include "../utils/util.h"
|
#include "../utils/util.h"
|
||||||
@@ -48,22 +47,6 @@ static void _gf256_mul_x(void *block)
|
|||||||
pdata[0xF] ^= 0x87;
|
pdata[0xF] ^= 0x87;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _gf256_mul_x_le(void *block)
|
|
||||||
{
|
|
||||||
u8 *pdata = (u8 *)block;
|
|
||||||
u32 carry = 0;
|
|
||||||
|
|
||||||
for (u32 i = 0; i < 0x10; i++)
|
|
||||||
{
|
|
||||||
u8 b = pdata[i];
|
|
||||||
pdata[i] = (b << 1) | carry;
|
|
||||||
carry = b >> 7;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (carry)
|
|
||||||
pdata[0x0] ^= 0x87;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void _se_ll_init(se_ll_t *ll, u32 addr, u32 size)
|
static void _se_ll_init(se_ll_t *ll, u32 addr, u32 size)
|
||||||
{
|
{
|
||||||
ll->num = 0;
|
ll->num = 0;
|
||||||
@@ -82,8 +65,8 @@ static int _se_wait()
|
|||||||
while (!(SE(SE_INT_STATUS_REG_OFFSET) & SE_INT_OP_DONE(INT_SET)))
|
while (!(SE(SE_INT_STATUS_REG_OFFSET) & SE_INT_OP_DONE(INT_SET)))
|
||||||
;
|
;
|
||||||
if (SE(SE_INT_STATUS_REG_OFFSET) & SE_INT_ERROR(INT_SET) ||
|
if (SE(SE_INT_STATUS_REG_OFFSET) & SE_INT_ERROR(INT_SET) ||
|
||||||
SE(SE_STATUS_0) & 3 ||
|
SE(SE_STATUS_0) & SE_STATUS_0_STATE_WAIT_IN ||
|
||||||
SE(SE_ERR_STATUS_0) != 0)
|
SE(SE_ERR_STATUS_0) != SE_ERR_STATUS_0_SE_NS_ACCESS_CLEAR)
|
||||||
return 0;
|
return 0;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -108,10 +91,14 @@ static int _se_execute(u32 op, void *dst, u32 dst_size, const void *src, u32 src
|
|||||||
|
|
||||||
SE(SE_ERR_STATUS_0) = SE(SE_ERR_STATUS_0);
|
SE(SE_ERR_STATUS_0) = SE(SE_ERR_STATUS_0);
|
||||||
SE(SE_INT_STATUS_REG_OFFSET) = SE(SE_INT_STATUS_REG_OFFSET);
|
SE(SE_INT_STATUS_REG_OFFSET) = SE(SE_INT_STATUS_REG_OFFSET);
|
||||||
SE(SE_OPERATION_REG_OFFSET) = SE_OPERATION(op);
|
|
||||||
|
|
||||||
|
bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY, false);
|
||||||
|
|
||||||
|
SE(SE_OPERATION_REG_OFFSET) = SE_OPERATION(op);
|
||||||
int res = _se_wait();
|
int res = _se_wait();
|
||||||
|
|
||||||
|
bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY, false);
|
||||||
|
|
||||||
if (src)
|
if (src)
|
||||||
free(ll_src);
|
free(ll_src);
|
||||||
if (dst)
|
if (dst)
|
||||||
@@ -147,21 +134,23 @@ static void _se_aes_ctr_set(void *ctr)
|
|||||||
|
|
||||||
void se_rsa_acc_ctrl(u32 rs, u32 flags)
|
void se_rsa_acc_ctrl(u32 rs, u32 flags)
|
||||||
{
|
{
|
||||||
if (flags & 0x7F)
|
if (flags & SE_RSA_KEY_TBL_DIS_KEY_ALL_FLAG)
|
||||||
SE(SE_RSA_KEYTABLE_ACCESS_REG_OFFSET + 4 * rs) = (((flags >> 4) & 4) | (flags & 3)) ^ 7;
|
SE(SE_RSA_KEYTABLE_ACCESS_REG_OFFSET + 4 * rs) =
|
||||||
if (flags & 0x80)
|
((flags >> SE_RSA_KEY_TBL_DIS_KEYUSE_FLAG_SHIFT) & SE_RSA_KEY_TBL_DIS_KEYUSE_FLAG) |
|
||||||
|
((flags & SE_RSA_KEY_TBL_DIS_KEY_READ_UPDATE_FLAG) ^ SE_RSA_KEY_TBL_DIS_KEY_ALL_COMMON_FLAG);
|
||||||
|
if (flags & SE_RSA_KEY_TBL_DIS_KEY_LOCK_FLAG)
|
||||||
SE(SE_RSA_KEYTABLE_ACCESS_LOCK_OFFSET) &= ~(1 << rs);
|
SE(SE_RSA_KEYTABLE_ACCESS_LOCK_OFFSET) &= ~(1 << rs);
|
||||||
}
|
}
|
||||||
|
|
||||||
void se_key_acc_ctrl(u32 ks, u32 flags)
|
void se_key_acc_ctrl(u32 ks, u32 flags)
|
||||||
{
|
{
|
||||||
if (flags & 0x7F)
|
if (flags & SE_KEY_TBL_DIS_KEY_ACCESS_FLAG)
|
||||||
SE(SE_KEY_TABLE_ACCESS_REG_OFFSET + 4 * ks) = ~flags;
|
SE(SE_KEY_TABLE_ACCESS_REG_OFFSET + 4 * ks) = ~flags;
|
||||||
if (flags & 0x80)
|
if (flags & SE_KEY_TBL_DIS_KEY_LOCK_FLAG)
|
||||||
SE(SE_KEY_TABLE_ACCESS_LOCK_OFFSET) &= ~(1 << ks);
|
SE(SE_KEY_TABLE_ACCESS_LOCK_OFFSET) &= ~(1 << ks);
|
||||||
}
|
}
|
||||||
|
|
||||||
void se_aes_key_set(u32 ks, const void *key, u32 size)
|
void se_aes_key_set(u32 ks, void *key, u32 size)
|
||||||
{
|
{
|
||||||
u32 *data = (u32 *)key;
|
u32 *data = (u32 *)key;
|
||||||
for (u32 i = 0; i < size / 4; i++)
|
for (u32 i = 0; i < size / 4; i++)
|
||||||
@@ -171,16 +160,6 @@ void se_aes_key_set(u32 ks, const void *key, u32 size)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void se_aes_key_read(u32 ks, void *key, u32 size)
|
|
||||||
{
|
|
||||||
u32 *data = (u32 *)key;
|
|
||||||
for (u32 i = 0; i < size / 4; i++)
|
|
||||||
{
|
|
||||||
SE(SE_KEYTABLE_REG_OFFSET) = SE_KEYTABLE_SLOT(ks) | i;
|
|
||||||
data[i] = SE(SE_KEYTABLE_DATA0_REG_OFFSET);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void se_aes_key_clear(u32 ks)
|
void se_aes_key_clear(u32 ks)
|
||||||
{
|
{
|
||||||
for (u32 i = 0; i < TEGRA_SE_AES_MAX_KEY_SIZE / 4; i++)
|
for (u32 i = 0; i < TEGRA_SE_AES_MAX_KEY_SIZE / 4; i++)
|
||||||
@@ -190,15 +169,6 @@ void se_aes_key_clear(u32 ks)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void se_aes_key_iv_clear(u32 ks)
|
|
||||||
{
|
|
||||||
for (u32 i = 0; i < TEGRA_SE_AES_MAX_KEY_SIZE / 4; i++)
|
|
||||||
{
|
|
||||||
SE(SE_KEYTABLE_REG_OFFSET) = SE_KEYTABLE_SLOT(ks) | 8 | i;
|
|
||||||
SE(SE_KEYTABLE_DATA0_REG_OFFSET) = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int se_aes_unwrap_key(u32 ks_dst, u32 ks_src, const void *input)
|
int se_aes_unwrap_key(u32 ks_dst, u32 ks_src, const void *input)
|
||||||
{
|
{
|
||||||
SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_DEC_ALG(ALG_AES_DEC) | SE_CONFIG_DST(DST_KEYTAB);
|
SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_DEC_ALG(ALG_AES_DEC) | SE_CONFIG_DST(DST_KEYTAB);
|
||||||
@@ -225,20 +195,27 @@ int se_aes_crypt_ecb(u32 ks, u32 enc, void *dst, u32 dst_size, const void *src,
|
|||||||
return _se_execute(OP_START, dst, dst_size, src, src_size);
|
return _se_execute(OP_START, dst, dst_size, src, src_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
int se_aes_crypt_block_ecb(u32 ks, u32 enc, void *dst, const void *src)
|
int se_aes_crypt_cbc(u32 ks, u32 enc, void *dst, u32 dst_size, const void *src, u32 src_size)
|
||||||
{
|
{
|
||||||
if (enc)
|
if (enc)
|
||||||
{
|
{
|
||||||
SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_ENC_ALG(ALG_AES_ENC) | SE_CONFIG_DST(DST_MEMORY);
|
SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_ENC_ALG(ALG_AES_ENC) | SE_CONFIG_DST(DST_MEMORY);
|
||||||
SE(SE_CRYPTO_REG_OFFSET) = SE_CRYPTO_KEY_INDEX(ks) | SE_CRYPTO_CORE_SEL(CORE_ENCRYPT);
|
SE(SE_CRYPTO_REG_OFFSET) = SE_CRYPTO_KEY_INDEX(ks) | SE_CRYPTO_VCTRAM_SEL(VCTRAM_PREVAHB) |
|
||||||
|
SE_CRYPTO_CORE_SEL(CORE_ENCRYPT) | SE_CRYPTO_XOR_POS(XOR_BOTTOM);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_DEC_ALG(ALG_AES_DEC) | SE_CONFIG_DST(DST_MEMORY);
|
SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_DEC_ALG(ALG_AES_DEC) | SE_CONFIG_DST(DST_MEMORY);
|
||||||
SE(SE_CRYPTO_REG_OFFSET) = SE_CRYPTO_KEY_INDEX(ks) | SE_CRYPTO_CORE_SEL(CORE_DECRYPT);
|
SE(SE_CRYPTO_REG_OFFSET) = SE_CRYPTO_KEY_INDEX(ks) | SE_CRYPTO_VCTRAM_SEL(VCTRAM_PREVAHB) |
|
||||||
|
SE_CRYPTO_CORE_SEL(CORE_DECRYPT) | SE_CRYPTO_XOR_POS(XOR_BOTTOM);
|
||||||
}
|
}
|
||||||
SE(SE_BLOCK_COUNT_REG_OFFSET) = 0;
|
SE(SE_BLOCK_COUNT_REG_OFFSET) = (src_size >> 4) - 1;
|
||||||
return _se_execute(OP_START, dst, 0x10, src, 0x10);
|
return _se_execute(OP_START, dst, dst_size, src, src_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
int se_aes_crypt_block_ecb(u32 ks, u32 enc, void *dst, const void *src)
|
||||||
|
{
|
||||||
|
return se_aes_crypt_ecb(ks, enc, dst, 0x10, src, 0x10);
|
||||||
}
|
}
|
||||||
|
|
||||||
int se_aes_crypt_ctr(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_size, void *ctr)
|
int se_aes_crypt_ctr(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_size, void *ctr)
|
||||||
@@ -267,7 +244,7 @@ int se_aes_crypt_ctr(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_s
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int se_aes_xts_crypt_sec(u32 ks1, u32 ks2, u32 enc, u64 sec, void *dst, const void *src, u32 secsize)
|
int se_aes_xts_crypt_sec(u32 ks1, u32 ks2, u32 enc, u64 sec, void *dst, void *src, u32 secsize)
|
||||||
{
|
{
|
||||||
int res = 0;
|
int res = 0;
|
||||||
u8 *tweak = (u8 *)malloc(0x10);
|
u8 *tweak = (u8 *)malloc(0x10);
|
||||||
@@ -292,7 +269,7 @@ int se_aes_xts_crypt_sec(u32 ks1, u32 ks2, u32 enc, u64 sec, void *dst, const vo
|
|||||||
goto out;
|
goto out;
|
||||||
for (u32 j = 0; j < 0x10; j++)
|
for (u32 j = 0; j < 0x10; j++)
|
||||||
pdst[j] = pdst[j] ^ tweak[j];
|
pdst[j] = pdst[j] ^ tweak[j];
|
||||||
_gf256_mul_x_le(tweak);
|
_gf256_mul_x(tweak);
|
||||||
psrc += 0x10;
|
psrc += 0x10;
|
||||||
pdst += 0x10;
|
pdst += 0x10;
|
||||||
}
|
}
|
||||||
@@ -304,7 +281,7 @@ out:;
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
int se_aes_xts_crypt(u32 ks1, u32 ks2, u32 enc, u64 sec, void *dst, const void *src, u32 secsize, u32 num_secs)
|
int se_aes_xts_crypt(u32 ks1, u32 ks2, u32 enc, u64 sec, void *dst, void *src, u32 secsize, u32 num_secs)
|
||||||
{
|
{
|
||||||
u8 *pdst = (u8 *)dst;
|
u8 *pdst = (u8 *)dst;
|
||||||
u8 *psrc = (u8 *)src;
|
u8 *psrc = (u8 *)src;
|
||||||
@@ -316,70 +293,20 @@ int se_aes_xts_crypt(u32 ks1, u32 ks2, u32 enc, u64 sec, void *dst, const void *
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// se_aes_cmac() was derived from Atmosphère's se_compute_aes_cmac
|
|
||||||
int se_aes_cmac(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_size)
|
|
||||||
{
|
|
||||||
int res = 0;
|
|
||||||
u8 *key = (u8 *)calloc(0x10, 1);
|
|
||||||
u8 *last_block = (u8 *)calloc(0x10, 1);
|
|
||||||
|
|
||||||
// generate derived key
|
|
||||||
if (!se_aes_crypt_block_ecb(ks, 1, key, key))
|
|
||||||
goto out;
|
|
||||||
_gf256_mul_x(key);
|
|
||||||
if (src_size & 0xF)
|
|
||||||
_gf256_mul_x(key);
|
|
||||||
|
|
||||||
SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_ENC_ALG(ALG_AES_ENC) | SE_CONFIG_DST(DST_HASHREG);
|
|
||||||
SE(SE_CRYPTO_REG_OFFSET) = SE_CRYPTO_KEY_INDEX(ks) | 0x145;
|
|
||||||
se_aes_key_iv_clear(ks);
|
|
||||||
|
|
||||||
u32 num_blocks = (src_size + 0xf) >> 4;
|
|
||||||
if (num_blocks > 1) {
|
|
||||||
SE(SE_BLOCK_COUNT_REG_OFFSET) = num_blocks - 2;
|
|
||||||
if (!_se_execute(OP_START, NULL, 0, src, src_size))
|
|
||||||
goto out;
|
|
||||||
SE(SE_CRYPTO_REG_OFFSET) |= SE_CRYPTO_IV_SEL(IV_UPDATED);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (src_size & 0xf) {
|
|
||||||
memcpy(last_block, src + (src_size & ~0xf), src_size & 0xf);
|
|
||||||
last_block[src_size & 0xf] = 0x80;
|
|
||||||
} else if (src_size >= 0x10) {
|
|
||||||
memcpy(last_block, src + src_size - 0x10, 0x10);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (u32 i = 0; i < 0x10; i++)
|
|
||||||
last_block[i] ^= key[i];
|
|
||||||
|
|
||||||
SE(SE_BLOCK_COUNT_REG_OFFSET) = 0;
|
|
||||||
res = _se_execute(OP_START, NULL, 0, last_block, 0x10);
|
|
||||||
|
|
||||||
u32 *dst32 = (u32 *)dst;
|
|
||||||
for (u32 i = 0; i < (dst_size >> 2); i++)
|
|
||||||
dst32[i] = SE(SE_HASH_RESULT_REG_OFFSET + (i << 2));
|
|
||||||
|
|
||||||
out:;
|
|
||||||
free(key);
|
|
||||||
free(last_block);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
// se_calc_sha256() was derived from Atmosphère's se_calculate_sha256.
|
|
||||||
int se_calc_sha256(void *dst, const void *src, u32 src_size)
|
int se_calc_sha256(void *dst, const void *src, u32 src_size)
|
||||||
{
|
{
|
||||||
int res;
|
int res;
|
||||||
// Setup config for SHA256, size = BITS(src_size).
|
// Setup config for SHA256, size = BITS(src_size).
|
||||||
SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_ENC_MODE(MODE_SHA256) | SE_CONFIG_ENC_ALG(ALG_SHA) | SE_CONFIG_DST(DST_HASHREG);
|
SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_ENC_MODE(MODE_SHA256) | SE_CONFIG_ENC_ALG(ALG_SHA) | SE_CONFIG_DST(DST_HASHREG);
|
||||||
SE(SE_SHA_CONFIG_REG_OFFSET) = SHA_ENABLE;
|
SE(SE_SHA_CONFIG_REG_OFFSET) = SHA_INIT_HASH;
|
||||||
SE(SE_SHA_MSG_LENGTH_REG_OFFSET) = (u32)(src_size << 3);
|
SE(SE_SHA_MSG_LENGTH_0_REG_OFFSET) = (u32)(src_size << 3);
|
||||||
SE(SE_SHA_MSG_LENGTH_REG_OFFSET + 4 * 1) = 0;
|
SE(SE_SHA_MSG_LENGTH_1_REG_OFFSET) = 0;
|
||||||
SE(SE_SHA_MSG_LENGTH_REG_OFFSET + 4 * 2) = 0;
|
SE(SE_SHA_MSG_LENGTH_2_REG_OFFSET) = 0;
|
||||||
SE(SE_SHA_MSG_LENGTH_REG_OFFSET + 4 * 3) = 0;
|
SE(SE_SHA_MSG_LENGTH_3_REG_OFFSET) = 0;
|
||||||
SE(SE_SHA_MSG_LEFT_REG_OFFSET) = (u32)(src_size << 3);
|
SE(SE_SHA_MSG_LEFT_0_REG_OFFSET) = (u32)(src_size << 3);
|
||||||
SE(SE_SHA_MSG_LEFT_REG_OFFSET + 4 * 1) = 0;
|
SE(SE_SHA_MSG_LEFT_1_REG_OFFSET) = 0;
|
||||||
SE(SE_SHA_MSG_LEFT_REG_OFFSET + 4 * 2) = 0;
|
SE(SE_SHA_MSG_LEFT_2_REG_OFFSET) = 0;
|
||||||
SE(SE_SHA_MSG_LEFT_REG_OFFSET + 4 * 3) = 0;
|
SE(SE_SHA_MSG_LEFT_3_REG_OFFSET) = 0;
|
||||||
|
|
||||||
// Trigger the operation.
|
// Trigger the operation.
|
||||||
res = _se_execute(OP_START, NULL, 0, src, src_size);
|
res = _se_execute(OP_START, NULL, 0, src, src_size);
|
||||||
@@ -391,3 +318,77 @@ int se_calc_sha256(void *dst, const void *src, u32 src_size)
|
|||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int se_gen_prng128(void *dst)
|
||||||
|
{
|
||||||
|
// Setup config for X931 PRNG.
|
||||||
|
SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_ENC_MODE(MODE_KEY128) | SE_CONFIG_ENC_ALG(ALG_RNG) | SE_CONFIG_DST(DST_MEMORY);
|
||||||
|
SE(SE_CRYPTO_REG_OFFSET) = SE_CRYPTO_HASH(HASH_DISABLE) | SE_CRYPTO_XOR_POS(XOR_BYPASS) | SE_CRYPTO_INPUT_SEL(INPUT_RANDOM);
|
||||||
|
|
||||||
|
SE(SE_RNG_CONFIG_REG_OFFSET) = SE_RNG_CONFIG_SRC(RNG_SRC_ENTROPY) | SE_RNG_CONFIG_MODE(RNG_MODE_NORMAL);
|
||||||
|
//SE(SE_RNG_SRC_CONFIG_REG_OFFSET) =
|
||||||
|
// SE_RNG_SRC_CONFIG_ENT_SRC(RNG_SRC_RO_ENT_ENABLE) | SE_RNG_SRC_CONFIG_ENT_SRC_LOCK(RNG_SRC_RO_ENT_LOCK_ENABLE);
|
||||||
|
SE(SE_RNG_RESEED_INTERVAL_REG_OFFSET) = 1;
|
||||||
|
|
||||||
|
SE(SE_BLOCK_COUNT_REG_OFFSET) = (16 >> 4) - 1;
|
||||||
|
|
||||||
|
// Trigger the operation.
|
||||||
|
return _se_execute(OP_START, dst, 16, NULL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void se_get_aes_keys(u8 *buf, u8 *keys, u32 keysize)
|
||||||
|
{
|
||||||
|
u8 *aligned_buf = (u8 *)ALIGN((u32)buf, 0x40);
|
||||||
|
|
||||||
|
// Set Secure Random Key.
|
||||||
|
SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_ENC_MODE(MODE_KEY128) | SE_CONFIG_ENC_ALG(ALG_RNG) | SE_CONFIG_DST(DST_SRK);
|
||||||
|
SE(SE_CRYPTO_REG_OFFSET) = SE_CRYPTO_KEY_INDEX(0) | SE_CRYPTO_CORE_SEL(CORE_ENCRYPT) | SE_CRYPTO_INPUT_SEL(INPUT_RANDOM);
|
||||||
|
SE(SE_RNG_CONFIG_REG_OFFSET) = SE_RNG_CONFIG_SRC(RNG_SRC_ENTROPY) | SE_RNG_CONFIG_MODE(RNG_MODE_FORCE_RESEED);
|
||||||
|
SE(SE_CRYPTO_LAST_BLOCK) = 0;
|
||||||
|
_se_execute(OP_START, NULL, 0, NULL, 0);
|
||||||
|
|
||||||
|
// Save AES keys.
|
||||||
|
SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_ENC_MODE(MODE_KEY128) | SE_CONFIG_ENC_ALG(ALG_AES_ENC) | SE_CONFIG_DST(DST_MEMORY);
|
||||||
|
|
||||||
|
for (u32 i = 0; i < TEGRA_SE_KEYSLOT_COUNT; i++)
|
||||||
|
{
|
||||||
|
SE(SE_CONTEXT_SAVE_CONFIG_REG_OFFSET) = SE_CONTEXT_SAVE_SRC(AES_KEYTABLE) |
|
||||||
|
(i << SE_KEY_INDEX_SHIFT) | SE_CONTEXT_SAVE_WORD_QUAD(KEYS_0_3);
|
||||||
|
|
||||||
|
SE(SE_CRYPTO_LAST_BLOCK) = 0;
|
||||||
|
_se_execute(OP_CTX_SAVE, aligned_buf, 0x10, NULL, 0);
|
||||||
|
memcpy(keys + i * keysize, aligned_buf, 0x10);
|
||||||
|
|
||||||
|
if (keysize > 0x10)
|
||||||
|
{
|
||||||
|
SE(SE_CONTEXT_SAVE_CONFIG_REG_OFFSET) = SE_CONTEXT_SAVE_SRC(AES_KEYTABLE) |
|
||||||
|
(i << SE_KEY_INDEX_SHIFT) | SE_CONTEXT_SAVE_WORD_QUAD(KEYS_4_7);
|
||||||
|
|
||||||
|
SE(SE_CRYPTO_LAST_BLOCK) = 0;
|
||||||
|
_se_execute(OP_CTX_SAVE, aligned_buf, 0x10, NULL, 0);
|
||||||
|
memcpy(keys + i * keysize + 0x10, aligned_buf, 0x10);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save SRK to PMC secure scratches.
|
||||||
|
SE(SE_CONTEXT_SAVE_CONFIG_REG_OFFSET) = SE_CONTEXT_SAVE_SRC(SRK);
|
||||||
|
SE(0x80) = 0; // SE_CRYPTO_LAST_BLOCK
|
||||||
|
_se_execute(OP_CTX_SAVE, NULL, 0, NULL, 0);
|
||||||
|
|
||||||
|
// End context save.
|
||||||
|
SE(SE_CONFIG_REG_OFFSET) = 0;
|
||||||
|
_se_execute(OP_CTX_SAVE, NULL, 0, NULL, 0);
|
||||||
|
|
||||||
|
// Get SRK.
|
||||||
|
u32 srk[4];
|
||||||
|
srk[0] = PMC(0xC0);
|
||||||
|
srk[1] = PMC(0xC4);
|
||||||
|
srk[2] = PMC(0x224);
|
||||||
|
srk[3] = PMC(0x228);
|
||||||
|
|
||||||
|
// Decrypt context.
|
||||||
|
se_aes_key_clear(3);
|
||||||
|
se_aes_key_set(3, srk, 0x10);
|
||||||
|
se_aes_crypt_cbc(3, 0, keys, TEGRA_SE_KEYSLOT_COUNT * keysize, keys, TEGRA_SE_KEYSLOT_COUNT * keysize);
|
||||||
|
se_aes_key_clear(3);
|
||||||
|
}
|
||||||
|
|||||||
@@ -21,16 +21,14 @@
|
|||||||
|
|
||||||
void se_rsa_acc_ctrl(u32 rs, u32 flags);
|
void se_rsa_acc_ctrl(u32 rs, u32 flags);
|
||||||
void se_key_acc_ctrl(u32 ks, u32 flags);
|
void se_key_acc_ctrl(u32 ks, u32 flags);
|
||||||
void se_aes_key_set(u32 ks, const void *key, u32 size);
|
void se_get_aes_keys(u8 *buf, u8 *keys, u32 keysize);
|
||||||
void se_aes_key_read(u32 ks, void *key, u32 size);
|
void se_aes_key_set(u32 ks, void *key, u32 size);
|
||||||
void se_aes_key_clear(u32 ks);
|
void se_aes_key_clear(u32 ks);
|
||||||
int se_aes_unwrap_key(u32 ks_dst, u32 ks_src, const void *input);
|
int se_aes_unwrap_key(u32 ks_dst, u32 ks_src, const void *input);
|
||||||
int se_aes_crypt_ecb(u32 ks, u32 enc, void *dst, u32 dst_size, const void *src, u32 src_size);
|
int se_aes_crypt_ecb(u32 ks, u32 enc, void *dst, u32 dst_size, const void *src, u32 src_size);
|
||||||
int se_aes_crypt_block_ecb(u32 ks, u32 enc, void *dst, const void *src);
|
int se_aes_crypt_block_ecb(u32 ks, u32 enc, void *dst, const void *src);
|
||||||
int se_aes_crypt_ctr(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_size, void *ctr);
|
int se_aes_crypt_ctr(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_size, void *ctr);
|
||||||
int se_aes_xts_crypt_sec(u32 ks1, u32 ks2, u32 enc, u64 sec, void *dst, const void *src, u32 secsize);
|
|
||||||
int se_aes_xts_crypt(u32 ks1, u32 ks2, u32 enc, u64 sec, void *dst, const void *src, u32 secsize, u32 num_secs);
|
|
||||||
int se_aes_cmac(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_size);
|
|
||||||
int se_calc_sha256(void *dst, const void *src, u32 src_size);
|
int se_calc_sha256(void *dst, const void *src, u32 src_size);
|
||||||
|
int se_gen_prng128(void *dst);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -36,6 +36,8 @@
|
|||||||
#define SE_SECURITY_0 0x000
|
#define SE_SECURITY_0 0x000
|
||||||
#define SE_KEY_SCHED_READ_SHIFT 3
|
#define SE_KEY_SCHED_READ_SHIFT 3
|
||||||
|
|
||||||
|
#define SE_TZRAM_SECURITY_0 0x004
|
||||||
|
|
||||||
#define SE_CONFIG_REG_OFFSET 0x014
|
#define SE_CONFIG_REG_OFFSET 0x014
|
||||||
#define SE_CONFIG_ENC_ALG_SHIFT 12
|
#define SE_CONFIG_ENC_ALG_SHIFT 12
|
||||||
#define SE_CONFIG_DEC_ALG_SHIFT 8
|
#define SE_CONFIG_DEC_ALG_SHIFT 8
|
||||||
@@ -68,27 +70,26 @@
|
|||||||
#define SE_CONFIG_DEC_MODE(x) (x << SE_CONFIG_DEC_MODE_SHIFT)
|
#define SE_CONFIG_DEC_MODE(x) (x << SE_CONFIG_DEC_MODE_SHIFT)
|
||||||
|
|
||||||
#define SE_RNG_CONFIG_REG_OFFSET 0x340
|
#define SE_RNG_CONFIG_REG_OFFSET 0x340
|
||||||
#define DRBG_MODE_SHIFT 0
|
#define RNG_MODE_SHIFT 0
|
||||||
#define DRBG_MODE_NORMAL 0
|
#define RNG_MODE_NORMAL 0
|
||||||
#define DRBG_MODE_FORCE_INSTANTION 1
|
#define RNG_MODE_FORCE_INSTANTION 1
|
||||||
#define DRBG_MODE_FORCE_RESEED 2
|
#define RNG_MODE_FORCE_RESEED 2
|
||||||
#define SE_RNG_CONFIG_MODE(x) (x << DRBG_MODE_SHIFT)
|
#define SE_RNG_CONFIG_MODE(x) (x << RNG_MODE_SHIFT)
|
||||||
|
#define RNG_SRC_SHIFT 2
|
||||||
|
#define RNG_SRC_NONE 0
|
||||||
|
#define RNG_SRC_ENTROPY 1
|
||||||
|
#define RNG_SRC_LFSR 2
|
||||||
|
#define SE_RNG_CONFIG_SRC(x) (x << RNG_SRC_SHIFT)
|
||||||
|
|
||||||
#define SE_RNG_SRC_CONFIG_REG_OFFSET 0x344
|
#define SE_RNG_SRC_CONFIG_REG_OFFSET 0x344
|
||||||
#define DRBG_RO_ENT_SRC_SHIFT 1
|
#define RNG_SRC_RO_ENT_SHIFT 1
|
||||||
#define DRBG_RO_ENT_SRC_ENABLE 1
|
#define RNG_SRC_RO_ENT_ENABLE 1
|
||||||
#define DRBG_RO_ENT_SRC_DISABLE 0
|
#define RNG_SRC_RO_ENT_DISABLE 0
|
||||||
#define SE_RNG_SRC_CONFIG_RO_ENT_SRC(x) (x << DRBG_RO_ENT_SRC_SHIFT)
|
#define SE_RNG_SRC_CONFIG_ENT_SRC(x) (x << RNG_SRC_RO_ENT_SHIFT)
|
||||||
#define DRBG_RO_ENT_SRC_LOCK_SHIFT 0
|
#define RNG_SRC_RO_ENT_LOCK_SHIFT 0
|
||||||
#define DRBG_RO_ENT_SRC_LOCK_ENABLE 1
|
#define RNG_SRC_RO_ENT_LOCK_ENABLE 1
|
||||||
#define DRBG_RO_ENT_SRC_LOCK_DISABLE 0
|
#define RNG_SRC_RO_ENT_LOCK_DISABLE 0
|
||||||
#define SE_RNG_SRC_CONFIG_RO_ENT_SRC_LOCK(x) (x << DRBG_RO_ENT_SRC_LOCK_SHIFT)
|
#define SE_RNG_SRC_CONFIG_ENT_SRC_LOCK(x) (x << RNG_SRC_RO_ENT_LOCK_SHIFT)
|
||||||
|
|
||||||
#define DRBG_SRC_SHIFT 2
|
|
||||||
#define DRBG_SRC_NONE 0
|
|
||||||
#define DRBG_SRC_ENTROPY 1
|
|
||||||
#define DRBG_SRC_LFSR 2
|
|
||||||
#define SE_RNG_CONFIG_SRC(x) (x << DRBG_SRC_SHIFT)
|
|
||||||
|
|
||||||
#define SE_RNG_RESEED_INTERVAL_REG_OFFSET 0x348
|
#define SE_RNG_RESEED_INTERVAL_REG_OFFSET 0x348
|
||||||
|
|
||||||
@@ -117,6 +118,8 @@
|
|||||||
#define OP_DONE 1
|
#define OP_DONE 1
|
||||||
#define SE_OP_DONE(x, y) ((x) && (y << SE_OP_DONE_SHIFT))
|
#define SE_OP_DONE(x, y) ((x) && (y << SE_OP_DONE_SHIFT))
|
||||||
|
|
||||||
|
#define SE_CRYPTO_LAST_BLOCK 0x080
|
||||||
|
|
||||||
#define SE_CRYPTO_REG_OFFSET 0x304
|
#define SE_CRYPTO_REG_OFFSET 0x304
|
||||||
#define SE_CRYPTO_HASH_SHIFT 0
|
#define SE_CRYPTO_HASH_SHIFT 0
|
||||||
#define HASH_DISABLE 0
|
#define HASH_DISABLE 0
|
||||||
@@ -189,6 +192,7 @@
|
|||||||
#define SRK 6
|
#define SRK 6
|
||||||
|
|
||||||
#define RSA_KEYTABLE 1
|
#define RSA_KEYTABLE 1
|
||||||
|
#define AES_KEYTABLE 2
|
||||||
#define SE_CONTEXT_SAVE_SRC(x) (x << SE_CONTEXT_SAVE_SRC_SHIFT)
|
#define SE_CONTEXT_SAVE_SRC(x) (x << SE_CONTEXT_SAVE_SRC_SHIFT)
|
||||||
|
|
||||||
#define SE_CONTEXT_SAVE_RSA_KEY_INDEX_SHIFT 16
|
#define SE_CONTEXT_SAVE_RSA_KEY_INDEX_SHIFT 16
|
||||||
@@ -209,8 +213,12 @@
|
|||||||
#define SE_INT_OP_DONE(x) (x << SE_INT_OP_DONE_SHIFT)
|
#define SE_INT_OP_DONE(x) (x << SE_INT_OP_DONE_SHIFT)
|
||||||
#define SE_INT_ERROR_SHIFT 16
|
#define SE_INT_ERROR_SHIFT 16
|
||||||
#define SE_INT_ERROR(x) (x << SE_INT_ERROR_SHIFT)
|
#define SE_INT_ERROR(x) (x << SE_INT_ERROR_SHIFT)
|
||||||
|
|
||||||
#define SE_STATUS_0 0x800
|
#define SE_STATUS_0 0x800
|
||||||
|
#define SE_STATUS_0_STATE_WAIT_IN 3
|
||||||
|
|
||||||
#define SE_ERR_STATUS_0 0x804
|
#define SE_ERR_STATUS_0 0x804
|
||||||
|
#define SE_ERR_STATUS_0_SE_NS_ACCESS_CLEAR 0
|
||||||
|
|
||||||
#define SE_CRYPTO_KEYTABLE_DST_REG_OFFSET 0X330
|
#define SE_CRYPTO_KEYTABLE_DST_REG_OFFSET 0X330
|
||||||
#define SE_CRYPTO_KEYTABLE_DST_WORD_QUAD_SHIFT 0
|
#define SE_CRYPTO_KEYTABLE_DST_WORD_QUAD_SHIFT 0
|
||||||
@@ -231,11 +239,17 @@
|
|||||||
#define SE_SPARE_0_REG_OFFSET 0x80c
|
#define SE_SPARE_0_REG_OFFSET 0x80c
|
||||||
|
|
||||||
#define SE_SHA_CONFIG_REG_OFFSET 0x200
|
#define SE_SHA_CONFIG_REG_OFFSET 0x200
|
||||||
#define SHA_DISABLE 0
|
#define SHA_CONTINUE 0
|
||||||
#define SHA_ENABLE 1
|
#define SHA_INIT_HASH 1
|
||||||
|
|
||||||
#define SE_SHA_MSG_LENGTH_REG_OFFSET 0x204
|
#define SE_SHA_MSG_LENGTH_0_REG_OFFSET 0x204
|
||||||
#define SE_SHA_MSG_LEFT_REG_OFFSET 0x214
|
#define SE_SHA_MSG_LENGTH_1_REG_OFFSET 0x208
|
||||||
|
#define SE_SHA_MSG_LENGTH_2_REG_OFFSET 0x20C
|
||||||
|
#define SE_SHA_MSG_LENGTH_3_REG_OFFSET 0x210
|
||||||
|
#define SE_SHA_MSG_LEFT_0_REG_OFFSET 0x214
|
||||||
|
#define SE_SHA_MSG_LEFT_1_REG_OFFSET 0x218
|
||||||
|
#define SE_SHA_MSG_LEFT_2_REG_OFFSET 0x21C
|
||||||
|
#define SE_SHA_MSG_LEFT_3_REG_OFFSET 0x220
|
||||||
|
|
||||||
#define SE_HASH_RESULT_REG_COUNT 16
|
#define SE_HASH_RESULT_REG_COUNT 16
|
||||||
#define SE_HASH_RESULT_REG_OFFSET 0x030
|
#define SE_HASH_RESULT_REG_OFFSET 0x030
|
||||||
@@ -260,7 +274,18 @@
|
|||||||
#define TEGRA_SE_RSA2048_DIGEST_SIZE 256
|
#define TEGRA_SE_RSA2048_DIGEST_SIZE 256
|
||||||
|
|
||||||
#define SE_KEY_TABLE_ACCESS_LOCK_OFFSET 0x280
|
#define SE_KEY_TABLE_ACCESS_LOCK_OFFSET 0x280
|
||||||
|
#define SE_KEY_TBL_DIS_KEY_LOCK_FLAG 0x80
|
||||||
|
|
||||||
#define SE_KEY_TABLE_ACCESS_REG_OFFSET 0x284
|
#define SE_KEY_TABLE_ACCESS_REG_OFFSET 0x284
|
||||||
|
#define SE_KEY_TBL_DIS_KEYREAD_FLAG (1 << 0)
|
||||||
|
#define SE_KEY_TBL_DIS_KEYUPDATE_FLAG (1 << 1)
|
||||||
|
#define SE_KEY_TBL_DIS_OIVREAD_FLAG (1 << 2)
|
||||||
|
#define SE_KEY_TBL_DIS_OIVUPDATE_FLAG (1 << 3)
|
||||||
|
#define SE_KEY_TBL_DIS_UIVREAD_FLAG (1 << 4)
|
||||||
|
#define SE_KEY_TBL_DIS_UIVUPDATE_FLAG (1 << 5)
|
||||||
|
#define SE_KEY_TBL_DIS_KEYUSE_FLAG (1 << 6)
|
||||||
|
#define SE_KEY_TBL_DIS_KEY_ACCESS_FLAG 0x7F
|
||||||
|
|
||||||
#define SE_KEY_READ_DISABLE_SHIFT 0
|
#define SE_KEY_READ_DISABLE_SHIFT 0
|
||||||
#define SE_KEY_UPDATE_DISABLE_SHIFT 1
|
#define SE_KEY_UPDATE_DISABLE_SHIFT 1
|
||||||
|
|
||||||
@@ -312,7 +337,16 @@
|
|||||||
#define TEGRA_SE_RSA_KEYSLOT_COUNT 2
|
#define TEGRA_SE_RSA_KEYSLOT_COUNT 2
|
||||||
|
|
||||||
#define SE_RSA_KEYTABLE_ACCESS_LOCK_OFFSET 0x40C
|
#define SE_RSA_KEYTABLE_ACCESS_LOCK_OFFSET 0x40C
|
||||||
|
#define SE_RSA_KEY_TBL_DIS_KEY_LOCK_FLAG 0x80
|
||||||
|
|
||||||
#define SE_RSA_KEYTABLE_ACCESS_REG_OFFSET 0x410
|
#define SE_RSA_KEYTABLE_ACCESS_REG_OFFSET 0x410
|
||||||
|
#define SE_RSA_KEY_TBL_DIS_KEYREAD_FLAG (1 << 0)
|
||||||
|
#define SE_RSA_KEY_TBL_DIS_KEYUPDATE_FLAG (1 << 1)
|
||||||
|
#define SE_RSA_KEY_TBL_DIS_KEY_READ_UPDATE_FLAG (SE_RSA_KEY_TBL_DIS_KEYREAD_FLAG | SE_RSA_KEY_TBL_DIS_KEYUPDATE_FLAG)
|
||||||
|
#define SE_RSA_KEY_TBL_DIS_KEYUSE_FLAG (1 << 2)
|
||||||
|
#define SE_RSA_KEY_TBL_DIS_KEYUSE_FLAG_SHIFT (1 << 2)
|
||||||
|
#define SE_RSA_KEY_TBL_DIS_KEY_ALL_COMMON_FLAG 7
|
||||||
|
#define SE_RSA_KEY_TBL_DIS_KEY_ALL_FLAG 0x7F
|
||||||
|
|
||||||
#define SE_RSA_KEYTABLE_ADDR 0x420
|
#define SE_RSA_KEYTABLE_ADDR 0x420
|
||||||
#define SE_RSA_KEYTABLE_DATA 0x424
|
#define SE_RSA_KEYTABLE_DATA 0x424
|
||||||
|
|||||||
@@ -21,12 +21,15 @@
|
|||||||
#include "../sec/tsec.h"
|
#include "../sec/tsec.h"
|
||||||
#include "../sec/tsec_t210.h"
|
#include "../sec/tsec_t210.h"
|
||||||
#include "../sec/se_t210.h"
|
#include "../sec/se_t210.h"
|
||||||
|
#include "../soc/bpmp.h"
|
||||||
#include "../soc/clock.h"
|
#include "../soc/clock.h"
|
||||||
|
#include "../soc/kfuse.h"
|
||||||
#include "../soc/smmu.h"
|
#include "../soc/smmu.h"
|
||||||
#include "../soc/t210.h"
|
#include "../soc/t210.h"
|
||||||
#include "../mem/heap.h"
|
#include "../mem/heap.h"
|
||||||
#include "../mem/mc.h"
|
#include "../mem/mc.h"
|
||||||
#include "../utils/util.h"
|
#include "../utils/util.h"
|
||||||
|
#include "../hos/hos.h"
|
||||||
|
|
||||||
// #include "../gfx/gfx.h"
|
// #include "../gfx/gfx.h"
|
||||||
|
|
||||||
@@ -64,15 +67,21 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt)
|
|||||||
u32 *pdir, *car, *fuse, *pmc, *flowctrl, *se, *mc, *iram, *evec;
|
u32 *pdir, *car, *fuse, *pmc, *flowctrl, *se, *mc, *iram, *evec;
|
||||||
u32 *pkg11_magic_off;
|
u32 *pkg11_magic_off;
|
||||||
|
|
||||||
//Enable clocks.
|
bpmp_mmu_disable();
|
||||||
|
bpmp_clk_rate_set(BPMP_CLK_NORMAL);
|
||||||
|
|
||||||
|
// Enable clocks.
|
||||||
clock_enable_host1x();
|
clock_enable_host1x();
|
||||||
|
usleep(2);
|
||||||
clock_enable_tsec();
|
clock_enable_tsec();
|
||||||
clock_enable_sor_safe();
|
clock_enable_sor_safe();
|
||||||
clock_enable_sor0();
|
clock_enable_sor0();
|
||||||
clock_enable_sor1();
|
clock_enable_sor1();
|
||||||
clock_enable_kfuse();
|
clock_enable_kfuse();
|
||||||
|
|
||||||
//Configure Falcon.
|
kfuse_wait_ready();
|
||||||
|
|
||||||
|
// Configure Falcon.
|
||||||
TSEC(TSEC_DMACTL) = 0;
|
TSEC(TSEC_DMACTL) = 0;
|
||||||
TSEC(TSEC_IRQMSET) =
|
TSEC(TSEC_IRQMSET) =
|
||||||
TSEC_IRQMSET_EXT(0xFF) |
|
TSEC_IRQMSET_EXT(0xFF) |
|
||||||
@@ -94,7 +103,7 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt)
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Load firmware or emulate memio environment for newer TSEC fw.
|
// Load firmware or emulate memio environment for newer TSEC fw.
|
||||||
if (kb == KB_FIRMWARE_VERSION_620)
|
if (kb == KB_FIRMWARE_VERSION_620)
|
||||||
TSEC(TSEC_DMATRFBASE) = (u32)tsec_ctxt->fw >> 8;
|
TSEC(TSEC_DMATRFBASE) = (u32)tsec_ctxt->fw >> 8;
|
||||||
else
|
else
|
||||||
@@ -118,7 +127,7 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt)
|
|||||||
{
|
{
|
||||||
// Init SMMU translation for TSEC.
|
// Init SMMU translation for TSEC.
|
||||||
pdir = smmu_init_for_tsec();
|
pdir = smmu_init_for_tsec();
|
||||||
smmu_init(0x4002B000);
|
smmu_init(tsec_ctxt->secmon_base);
|
||||||
// Enable SMMU
|
// Enable SMMU
|
||||||
if (!smmu_is_used())
|
if (!smmu_is_used())
|
||||||
smmu_enable();
|
smmu_enable();
|
||||||
@@ -161,7 +170,7 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt)
|
|||||||
iram = page_alloc(0x30);
|
iram = page_alloc(0x30);
|
||||||
memcpy(iram, tsec_ctxt->pkg1, 0x30000);
|
memcpy(iram, tsec_ctxt->pkg1, 0x30000);
|
||||||
// PKG1.1 magic offset.
|
// PKG1.1 magic offset.
|
||||||
pkg11_magic_off = (u32 *)(iram + (0x7000 / 4));
|
pkg11_magic_off = (u32 *)(iram + ((tsec_ctxt->pkg11_off + 0x20) / 4));
|
||||||
smmu_map(pdir, 0x40010000, (u32)iram, 0x30, _READABLE | _WRITABLE | _NONSECURE);
|
smmu_map(pdir, 0x40010000, (u32)iram, 0x30, _READABLE | _WRITABLE | _NONSECURE);
|
||||||
|
|
||||||
// Exception vectors
|
// Exception vectors
|
||||||
@@ -169,8 +178,8 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt)
|
|||||||
smmu_map(pdir, EXCP_VEC_BASE, (u32)evec, 1, _READABLE | _WRITABLE | _NONSECURE);
|
smmu_map(pdir, EXCP_VEC_BASE, (u32)evec, 1, _READABLE | _WRITABLE | _NONSECURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Execute firmware.
|
// Execute firmware.
|
||||||
HOST1X(0x3300) = 0x34C2E1DA;
|
HOST1X(HOST1X_CH0_SYNC_SYNCPT_160) = 0x34C2E1DA;
|
||||||
TSEC(TSEC_STATUS) = 0;
|
TSEC(TSEC_STATUS) = 0;
|
||||||
TSEC(TSEC_BOOTKEYVER) = 1; // HOS uses key version 1.
|
TSEC(TSEC_BOOTKEYVER) = 1; // HOS uses key version 1.
|
||||||
TSEC(TSEC_BOOTVEC) = 0;
|
TSEC(TSEC_BOOTVEC) = 0;
|
||||||
@@ -203,7 +212,7 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt)
|
|||||||
res = -6;
|
res = -6;
|
||||||
smmu_deinit_for_tsec();
|
smmu_deinit_for_tsec();
|
||||||
|
|
||||||
goto out;
|
goto out_free;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Give some extra time to make sure PKG1.1 is decrypted.
|
// Give some extra time to make sure PKG1.1 is decrypted.
|
||||||
@@ -246,8 +255,8 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt)
|
|||||||
goto out_free;
|
goto out_free;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Fetch result.
|
// Fetch result.
|
||||||
HOST1X(0x3300) = 0;
|
HOST1X(HOST1X_CH0_SYNC_SYNCPT_160) = 0;
|
||||||
u32 buf[4];
|
u32 buf[4];
|
||||||
buf[0] = SOR1(SOR_NV_PDISP_SOR_DP_HDCP_BKSV_LSB);
|
buf[0] = SOR1(SOR_NV_PDISP_SOR_DP_HDCP_BKSV_LSB);
|
||||||
buf[1] = SOR1(SOR_NV_PDISP_SOR_TMDS_HDCP_BKSV_LSB);
|
buf[1] = SOR1(SOR_NV_PDISP_SOR_TMDS_HDCP_BKSV_LSB);
|
||||||
@@ -266,13 +275,14 @@ out_free:;
|
|||||||
|
|
||||||
out:;
|
out:;
|
||||||
|
|
||||||
//Disable clocks.
|
// Disable clocks.
|
||||||
clock_disable_kfuse();
|
clock_disable_kfuse();
|
||||||
clock_disable_sor1();
|
clock_disable_sor1();
|
||||||
clock_disable_sor0();
|
clock_disable_sor0();
|
||||||
clock_disable_sor_safe();
|
clock_disable_sor_safe();
|
||||||
clock_disable_tsec();
|
clock_disable_tsec();
|
||||||
clock_disable_host1x();
|
bpmp_mmu_enable();
|
||||||
|
bpmp_clk_rate_set(BPMP_CLK_DEFAULT_BOOST);
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,6 +27,8 @@ typedef struct _tsec_ctxt_t
|
|||||||
void *fw;
|
void *fw;
|
||||||
u32 size;
|
u32 size;
|
||||||
void *pkg1;
|
void *pkg1;
|
||||||
|
u32 pkg11_off;
|
||||||
|
u32 secmon_base;
|
||||||
} tsec_ctxt_t;
|
} tsec_ctxt_t;
|
||||||
|
|
||||||
typedef struct _tsec_key_data_t
|
typedef struct _tsec_key_data_t
|
||||||
|
|||||||
308
source/soc/bpmp.c
Normal file
308
source/soc/bpmp.c
Normal file
@@ -0,0 +1,308 @@
|
|||||||
|
/*
|
||||||
|
* BPMP-Lite Cache/MMU and Frequency driver for Tegra X1
|
||||||
|
*
|
||||||
|
* Copyright (c) 2019-2020 CTCaer
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "bpmp.h"
|
||||||
|
#include "clock.h"
|
||||||
|
#include "t210.h"
|
||||||
|
#include "../../common/memory_map.h"
|
||||||
|
#include "../utils/util.h"
|
||||||
|
|
||||||
|
#define BPMP_MMU_CACHE_LINE_SIZE 0x20
|
||||||
|
|
||||||
|
#define BPMP_CACHE_CONFIG 0x0
|
||||||
|
#define CFG_ENABLE_CACHE (1 << 0)
|
||||||
|
#define CFG_ENABLE_SKEW_ASSOC (1 << 1)
|
||||||
|
#define CFG_DISABLE_RANDOM_ALLOC (1 << 2)
|
||||||
|
#define CFG_FORCE_WRITE_THROUGH (1 << 3)
|
||||||
|
#define CFG_NEVER_ALLOCATE (1 << 6)
|
||||||
|
#define CFG_ENABLE_INTERRUPT (1 << 7)
|
||||||
|
#define CFG_MMU_TAG_MODE(x) (x << 8)
|
||||||
|
#define TAG_MODE_PARALLEL 0
|
||||||
|
#define TAG_MODE_TAG_FIRST 1
|
||||||
|
#define TAG_MODE_MMU_FIRST 2
|
||||||
|
#define CFG_DISABLE_WRITE_BUFFER (1 << 10)
|
||||||
|
#define CFG_DISABLE_READ_BUFFER (1 << 11)
|
||||||
|
#define CFG_ENABLE_HANG_DETECT (1 << 12)
|
||||||
|
#define CFG_FULL_LINE_DIRTY (1 << 13)
|
||||||
|
#define CFG_TAG_CHK_ABRT_ON_ERR (1 << 14)
|
||||||
|
#define CFG_TAG_CHK_CLR_ERR (1 << 15)
|
||||||
|
#define CFG_DISABLE_SAMELINE (1 << 16)
|
||||||
|
#define CFG_OBS_BUS_EN (1 << 31)
|
||||||
|
|
||||||
|
#define BPMP_CACHE_LOCK 0x4
|
||||||
|
#define LOCK_LINE(x) (1 << x)
|
||||||
|
|
||||||
|
#define BPMP_CACHE_SIZE 0xC
|
||||||
|
#define BPMP_CACHE_LFSR 0x10
|
||||||
|
|
||||||
|
#define BPMP_CACHE_TAG_STATUS 0x14
|
||||||
|
#define TAG_STATUS_TAG_CHECK_ERROR (1 << 0)
|
||||||
|
#define TAG_STATUS_CONFLICT_ADDR_MASK 0xFFFFFFE0
|
||||||
|
|
||||||
|
#define BPMP_CACHE_CLKEN_OVERRIDE 0x18
|
||||||
|
#define CLKEN_OVERRIDE_WR_MCCIF_CLKEN (1 << 0)
|
||||||
|
#define CLKEN_OVERRIDE_RD_MCCIF_CLKEN (1 << 1)
|
||||||
|
|
||||||
|
#define BPMP_CACHE_MAINT_ADDR 0x20
|
||||||
|
#define BPMP_CACHE_MAINT_DATA 0x24
|
||||||
|
|
||||||
|
#define BPMP_CACHE_MAINT_REQ 0x28
|
||||||
|
#define MAINT_REQ_WAY_BITMAP(x) ((x) << 8)
|
||||||
|
|
||||||
|
#define BPMP_CACHE_INT_MASK 0x40
|
||||||
|
#define BPMP_CACHE_INT_CLEAR 0x44
|
||||||
|
#define BPMP_CACHE_INT_RAW_EVENT 0x48
|
||||||
|
#define BPMP_CACHE_INT_STATUS 0x4C
|
||||||
|
#define INT_MAINT_DONE (1 << 0)
|
||||||
|
#define INT_MAINT_ERROR (1 << 1)
|
||||||
|
|
||||||
|
#define BPMP_CACHE_RB_CFG 0x80
|
||||||
|
#define BPMP_CACHE_WB_CFG 0x84
|
||||||
|
|
||||||
|
#define BPMP_CACHE_MMU_FALLBACK_ENTRY 0xA0
|
||||||
|
#define BPMP_CACHE_MMU_SHADOW_COPY_MASK 0xA4
|
||||||
|
|
||||||
|
#define BPMP_CACHE_MMU_CFG 0xAC
|
||||||
|
#define MMU_CFG_BLOCK_MAIN_ENTRY_WR (1 << 0)
|
||||||
|
#define MMU_CFG_SEQ_EN (1 << 1)
|
||||||
|
#define MMU_CFG_TLB_EN (1 << 2)
|
||||||
|
#define MMU_CFG_SEG_CHECK_ALL_ENTRIES (1 << 3)
|
||||||
|
#define MMU_CFG_ABORT_STORE_LAST (1 << 4)
|
||||||
|
#define MMU_CFG_CLR_ABORT (1 << 5)
|
||||||
|
|
||||||
|
#define BPMP_CACHE_MMU_CMD 0xB0
|
||||||
|
#define MMU_CMD_NOP 0
|
||||||
|
#define MMU_CMD_INIT 1
|
||||||
|
#define MMU_CMD_COPY_SHADOW 2
|
||||||
|
|
||||||
|
#define BPMP_CACHE_MMU_ABORT_STAT 0xB4
|
||||||
|
#define ABORT_STAT_UNIT_MASK 0x7
|
||||||
|
#define ABORT_STAT_UNIT_NONE 0
|
||||||
|
#define ABORT_STAT_UNIT_CACHE 1
|
||||||
|
#define ABORT_STAT_UNIT_SEQ 2
|
||||||
|
#define ABORT_STAT_UNIT_TLB 3
|
||||||
|
#define ABORT_STAT_UNIT_SEG 4
|
||||||
|
#define ABORT_STAT_UNIT_FALLBACK 5
|
||||||
|
#define ABORT_STAT_OVERLAP (1 << 3)
|
||||||
|
#define ABORT_STAT_ENTRY (0x1F << 4)
|
||||||
|
#define ABORT_STAT_TYPE_MASK (3 << 16)
|
||||||
|
#define ABORT_STAT_TYPE_EXE (0 << 16)
|
||||||
|
#define ABORT_STAT_TYPE_RD (1 << 16)
|
||||||
|
#define ABORT_STAT_TYPE_WR (2 << 16)
|
||||||
|
#define ABORT_STAT_SIZE (3 << 18)
|
||||||
|
#define ABORT_STAT_SEQ (1 << 20)
|
||||||
|
#define ABORT_STAT_PROT (1 << 21)
|
||||||
|
|
||||||
|
#define BPMP_CACHE_MMU_ABORT_ADDR 0xB8
|
||||||
|
#define BPMP_CACHE_MMU_ACTIVE_ENTRIES 0xBC
|
||||||
|
|
||||||
|
#define BPMP_MMU_SHADOW_ENTRY_BASE (BPMP_CACHE_BASE + 0x400)
|
||||||
|
#define BPMP_MMU_MAIN_ENTRY_BASE (BPMP_CACHE_BASE + 0x800)
|
||||||
|
#define MMU_EN_CACHED (1 << 0)
|
||||||
|
#define MMU_EN_EXEC (1 << 1)
|
||||||
|
#define MMU_EN_READ (1 << 2)
|
||||||
|
#define MMU_EN_WRITE (1 << 3)
|
||||||
|
|
||||||
|
bpmp_mmu_entry_t mmu_entries[] =
|
||||||
|
{
|
||||||
|
{ DRAM_START, 0xFFFFFFFF, MMU_EN_READ | MMU_EN_WRITE | MMU_EN_EXEC | MMU_EN_CACHED, true },
|
||||||
|
{ IRAM_BASE, 0x4003FFFF, MMU_EN_READ | MMU_EN_WRITE | MMU_EN_EXEC | MMU_EN_CACHED, true }
|
||||||
|
};
|
||||||
|
|
||||||
|
void bpmp_mmu_maintenance(u32 op, bool force)
|
||||||
|
{
|
||||||
|
if (!force && !(BPMP_CACHE_CTRL(BPMP_CACHE_CONFIG) & CFG_ENABLE_CACHE))
|
||||||
|
return;
|
||||||
|
|
||||||
|
BPMP_CACHE_CTRL(BPMP_CACHE_INT_CLEAR) = INT_MAINT_DONE;
|
||||||
|
|
||||||
|
// This is a blocking operation.
|
||||||
|
BPMP_CACHE_CTRL(BPMP_CACHE_MAINT_REQ) = MAINT_REQ_WAY_BITMAP(0xF) | op;
|
||||||
|
|
||||||
|
while(!(BPMP_CACHE_CTRL(BPMP_CACHE_INT_RAW_EVENT) & INT_MAINT_DONE))
|
||||||
|
;
|
||||||
|
|
||||||
|
BPMP_CACHE_CTRL(BPMP_CACHE_INT_CLEAR) = BPMP_CACHE_CTRL(BPMP_CACHE_INT_RAW_EVENT);
|
||||||
|
}
|
||||||
|
|
||||||
|
void bpmp_mmu_set_entry(int idx, bpmp_mmu_entry_t *entry, bool apply)
|
||||||
|
{
|
||||||
|
if (idx > 31)
|
||||||
|
return;
|
||||||
|
|
||||||
|
volatile bpmp_mmu_entry_t *mmu_entry = (bpmp_mmu_entry_t *)(BPMP_MMU_SHADOW_ENTRY_BASE + sizeof(bpmp_mmu_entry_t) * idx);
|
||||||
|
|
||||||
|
if (entry->enable)
|
||||||
|
{
|
||||||
|
mmu_entry->start_addr = ALIGN(entry->start_addr, BPMP_MMU_CACHE_LINE_SIZE);
|
||||||
|
mmu_entry->end_addr = ALIGN_DOWN(entry->end_addr, BPMP_MMU_CACHE_LINE_SIZE);
|
||||||
|
mmu_entry->attr = entry->attr;
|
||||||
|
|
||||||
|
BPMP_CACHE_CTRL(BPMP_CACHE_MMU_SHADOW_COPY_MASK) |= (1 << idx);
|
||||||
|
|
||||||
|
if (apply)
|
||||||
|
BPMP_CACHE_CTRL(BPMP_CACHE_MMU_CMD) = MMU_CMD_COPY_SHADOW;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void bpmp_mmu_enable()
|
||||||
|
{
|
||||||
|
if (BPMP_CACHE_CTRL(BPMP_CACHE_CONFIG) & CFG_ENABLE_CACHE)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Init BPMP MMU.
|
||||||
|
BPMP_CACHE_CTRL(BPMP_CACHE_MMU_CMD) = MMU_CMD_INIT;
|
||||||
|
BPMP_CACHE_CTRL(BPMP_CACHE_MMU_FALLBACK_ENTRY) = MMU_EN_READ | MMU_EN_WRITE | MMU_EN_EXEC; // RWX for non-defined regions.
|
||||||
|
BPMP_CACHE_CTRL(BPMP_CACHE_MMU_CFG) = MMU_CFG_SEQ_EN | MMU_CFG_TLB_EN | MMU_CFG_ABORT_STORE_LAST;
|
||||||
|
|
||||||
|
// Init BPMP MMU entries.
|
||||||
|
BPMP_CACHE_CTRL(BPMP_CACHE_MMU_SHADOW_COPY_MASK) = 0;
|
||||||
|
for (u32 idx = 0; idx < (sizeof(mmu_entries) / sizeof(bpmp_mmu_entry_t)); idx++)
|
||||||
|
bpmp_mmu_set_entry(idx, &mmu_entries[idx], false);
|
||||||
|
|
||||||
|
BPMP_CACHE_CTRL(BPMP_CACHE_MMU_CMD) = MMU_CMD_COPY_SHADOW;
|
||||||
|
|
||||||
|
// Invalidate cache.
|
||||||
|
bpmp_mmu_maintenance(BPMP_MMU_MAINT_INVALID_WAY, true);
|
||||||
|
|
||||||
|
// Enable cache.
|
||||||
|
BPMP_CACHE_CTRL(BPMP_CACHE_CONFIG) = CFG_ENABLE_CACHE | CFG_FORCE_WRITE_THROUGH |
|
||||||
|
CFG_MMU_TAG_MODE(TAG_MODE_PARALLEL) | CFG_TAG_CHK_ABRT_ON_ERR;
|
||||||
|
|
||||||
|
// HW bug. Invalidate cache again.
|
||||||
|
bpmp_mmu_maintenance(BPMP_MMU_MAINT_INVALID_WAY, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void bpmp_mmu_disable()
|
||||||
|
{
|
||||||
|
if (!(BPMP_CACHE_CTRL(BPMP_CACHE_CONFIG) & CFG_ENABLE_CACHE))
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Clean and invalidate cache.
|
||||||
|
bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY, false);
|
||||||
|
|
||||||
|
// Disable cache.
|
||||||
|
BPMP_CACHE_CTRL(BPMP_CACHE_CONFIG) = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// APB clock affects RTC, PWM, MEMFETCH, APE, USB, SOR PWM,
|
||||||
|
// I2C host, DC/DSI/DISP. UART gives extra stress.
|
||||||
|
// 92: 100% success ratio. 93-94: 595-602MHz has 99% success ratio. 95: 608MHz less.
|
||||||
|
const u8 pll_divn[] = {
|
||||||
|
0, // BPMP_CLK_NORMAL: 408MHz 0% - 136MHz APB.
|
||||||
|
85, // BPMP_CLK_HIGH_BOOST: 544MHz 33% - 136MHz APB.
|
||||||
|
90, // BPMP_CLK_SUPER_BOOST: 576MHz 41% - 144MHz APB.
|
||||||
|
92 // BPMP_CLK_HYPER_BOOST: 589MHz 44% - 147MHz APB.
|
||||||
|
// Do not use for public releases!
|
||||||
|
//95 // BPMP_CLK_DEV_BOOST: 608MHz 49% - 152MHz APB.
|
||||||
|
};
|
||||||
|
|
||||||
|
bpmp_freq_t bpmp_clock_set = BPMP_CLK_NORMAL;
|
||||||
|
|
||||||
|
void bpmp_clk_rate_get()
|
||||||
|
{
|
||||||
|
bool clk_src_is_pllp = ((CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) >> 4) & 7) == 3;
|
||||||
|
|
||||||
|
if (clk_src_is_pllp)
|
||||||
|
bpmp_clock_set = BPMP_CLK_NORMAL;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bpmp_clock_set = BPMP_CLK_HIGH_BOOST;
|
||||||
|
|
||||||
|
u8 pll_divn_curr = (CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) >> 10) & 0xFF;
|
||||||
|
for (u32 i = 1; i < sizeof(pll_divn); i++)
|
||||||
|
{
|
||||||
|
if (pll_divn[i] == pll_divn_curr)
|
||||||
|
{
|
||||||
|
bpmp_clock_set = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void bpmp_clk_rate_set(bpmp_freq_t fid)
|
||||||
|
{
|
||||||
|
if (fid > (BPMP_CLK_MAX - 1))
|
||||||
|
fid = BPMP_CLK_MAX - 1;
|
||||||
|
|
||||||
|
if (bpmp_clock_set == fid)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (fid)
|
||||||
|
{
|
||||||
|
if (bpmp_clock_set)
|
||||||
|
{
|
||||||
|
// Restore to PLLP source during PLLC4 configuration.
|
||||||
|
CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = 0x20003333; // PLLP_OUT.
|
||||||
|
msleep(1); // Wait a bit for clock source change.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Configure and enable PLLC.
|
||||||
|
clock_enable_pllc(pll_divn[fid]);
|
||||||
|
|
||||||
|
// Set SCLK / HCLK / PCLK.
|
||||||
|
CLOCK(CLK_RST_CONTROLLER_CLK_SYSTEM_RATE) = 3; // PCLK = HCLK / (3 + 1). HCLK == SCLK.
|
||||||
|
CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = 0x20003310; // PLLC_OUT1 for active and CLKM for idle.
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = 0x20003330; // PLLP_OUT for active and CLKM for idle.
|
||||||
|
msleep(1); // Wait a bit for clock source change.
|
||||||
|
CLOCK(CLK_RST_CONTROLLER_CLK_SYSTEM_RATE) = 2; // PCLK = HCLK / (2 + 1). HCLK == SCLK.
|
||||||
|
|
||||||
|
// Disable PLLC to save power.
|
||||||
|
clock_disable_pllc();
|
||||||
|
}
|
||||||
|
bpmp_clock_set = fid;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The following functions halt BPMP to reduce power while sleeping.
|
||||||
|
// They are not as accurate as RTC at big values but they guarantee time+ delay.
|
||||||
|
void bpmp_usleep(u32 us)
|
||||||
|
{
|
||||||
|
u32 delay;
|
||||||
|
|
||||||
|
// Each iteration takes 1us.
|
||||||
|
while (us)
|
||||||
|
{
|
||||||
|
delay = (us > HALT_COP_MAX_CNT) ? HALT_COP_MAX_CNT : us;
|
||||||
|
us -= delay;
|
||||||
|
|
||||||
|
FLOW_CTLR(FLOW_CTLR_HALT_COP_EVENTS) = HALT_COP_WAIT_EVENT | HALT_COP_USEC | delay;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void bpmp_msleep(u32 ms)
|
||||||
|
{
|
||||||
|
u32 delay;
|
||||||
|
|
||||||
|
// Iteration time is variable. ~200 - 1000us.
|
||||||
|
while (ms)
|
||||||
|
{
|
||||||
|
delay = (ms > HALT_COP_MAX_CNT) ? HALT_COP_MAX_CNT : ms;
|
||||||
|
ms -= delay;
|
||||||
|
|
||||||
|
FLOW_CTLR(FLOW_CTLR_HALT_COP_EVENTS) = HALT_COP_WAIT_EVENT | HALT_COP_MSEC | delay;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void bpmp_halt()
|
||||||
|
{
|
||||||
|
FLOW_CTLR(FLOW_CTLR_HALT_COP_EVENTS) = HALT_COP_WAIT_EVENT | HALT_COP_JTAG;
|
||||||
|
}
|
||||||
68
source/soc/bpmp.h
Normal file
68
source/soc/bpmp.h
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
/*
|
||||||
|
* BPMP-Lite Cache/MMU and Frequency driver for Tegra X1
|
||||||
|
*
|
||||||
|
* Copyright (c) 2019-2020 CTCaer
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _BPMP_H_
|
||||||
|
#define _BPMP_H_
|
||||||
|
|
||||||
|
#include "../utils/types.h"
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
BPMP_MMU_MAINT_NOP = 0,
|
||||||
|
BPMP_MMU_MAINT_CLEAN_PHY = 1,
|
||||||
|
BPMP_MMU_MAINT_INVALID_PHY = 2,
|
||||||
|
BPMP_MMU_MAINT_CLEAN_INVALID_PHY = 3,
|
||||||
|
BPMP_MMU_MAINT_CLEAN_LINE = 9,
|
||||||
|
BPMP_MMU_MAINT_INVALID_LINE = 10,
|
||||||
|
BPMP_MMU_MAINT_CLEAN_INVALID_LINE = 11,
|
||||||
|
BPMP_MMU_MAINT_CLEAN_WAY = 17,
|
||||||
|
BPMP_MMU_MAINT_INVALID_WAY = 18,
|
||||||
|
BPMP_MMU_MAINT_CLN_INV_WAY = 19
|
||||||
|
} bpmp_maintenance_t;
|
||||||
|
|
||||||
|
typedef struct _bpmp_mmu_entry_t
|
||||||
|
{
|
||||||
|
u32 start_addr;
|
||||||
|
u32 end_addr;
|
||||||
|
u32 attr;
|
||||||
|
u32 enable;
|
||||||
|
} bpmp_mmu_entry_t;
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
BPMP_CLK_NORMAL, // 408MHz 0% - 136MHz APB.
|
||||||
|
BPMP_CLK_HIGH_BOOST, // 544MHz 33% - 136MHz APB.
|
||||||
|
BPMP_CLK_SUPER_BOOST, // 576MHz 41% - 144MHz APB.
|
||||||
|
BPMP_CLK_HYPER_BOOST, // 589MHz 44% - 147MHz APB.
|
||||||
|
//BPMP_CLK_DEV_BOOST, // 608MHz 49% - 152MHz APB.
|
||||||
|
BPMP_CLK_MAX
|
||||||
|
} bpmp_freq_t;
|
||||||
|
|
||||||
|
#define BPMP_CLK_DEFAULT_BOOST BPMP_CLK_HYPER_BOOST
|
||||||
|
|
||||||
|
void bpmp_mmu_maintenance(u32 op, bool force);
|
||||||
|
void bpmp_mmu_set_entry(int idx, bpmp_mmu_entry_t *entry, bool apply);
|
||||||
|
void bpmp_mmu_enable();
|
||||||
|
void bpmp_mmu_disable();
|
||||||
|
void bpmp_clk_rate_get();
|
||||||
|
void bpmp_clk_rate_set(bpmp_freq_t fid);
|
||||||
|
void bpmp_usleep(u32 us);
|
||||||
|
void bpmp_msleep(u32 ms);
|
||||||
|
void bpmp_halt();
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2018 naehrwert
|
* Copyright (c) 2018 naehrwert
|
||||||
|
* Copyright (c) 2018-2020 CTCaer
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
* under the terms and conditions of the GNU General Public License,
|
* under the terms and conditions of the GNU General Public License,
|
||||||
@@ -19,60 +20,77 @@
|
|||||||
#include "../utils/util.h"
|
#include "../utils/util.h"
|
||||||
#include "../storage/sdmmc.h"
|
#include "../storage/sdmmc.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* CLOCK Peripherals:
|
||||||
|
* L 0 - 31
|
||||||
|
* H 32 - 63
|
||||||
|
* U 64 - 95
|
||||||
|
* V 96 - 127
|
||||||
|
* W 128 - 159
|
||||||
|
* X 160 - 191
|
||||||
|
* Y 192 - 223
|
||||||
|
*/
|
||||||
|
|
||||||
/* clock_t: reset, enable, source, index, clk_src, clk_div */
|
/* clock_t: reset, enable, source, index, clk_src, clk_div */
|
||||||
|
|
||||||
static const clock_t _clock_uart[] = {
|
static const clock_t _clock_uart[] = {
|
||||||
/* UART A */ { CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_UARTA, 6, 0, 0 },
|
/* UART A */ { CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_UARTA, 6, 0, 2 },
|
||||||
/* UART B */ { CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_UARTB, 7, 0, 0 },
|
/* UART B */ { CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_UARTB, 7, 0, 2 },
|
||||||
/* UART C */ { CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_RST_CONTROLLER_CLK_SOURCE_UARTC, 0x17, 0, 0 },
|
/* UART C */ { CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_RST_CONTROLLER_CLK_SOURCE_UARTC, 23, 0, 2 },
|
||||||
/* UART D */ { 0 },
|
/* UART D */ { CLK_RST_CONTROLLER_RST_DEVICES_U, CLK_RST_CONTROLLER_CLK_OUT_ENB_U, CLK_RST_CONTROLLER_CLK_SOURCE_UARTD, 1, 0, 2 },
|
||||||
/* UART E */ { 0 }
|
/* UART E */ { CLK_RST_CONTROLLER_RST_DEVICES_Y, CLK_RST_CONTROLLER_CLK_OUT_ENB_Y, CLK_RST_CONTROLLER_CLK_SOURCE_UARTAPE, 20, 0, 2 }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//I2C default parameters - TLOW: 4, THIGH: 2, DEBOUNCE: 0, FM_DIV: 26.
|
||||||
static const clock_t _clock_i2c[] = {
|
static const clock_t _clock_i2c[] = {
|
||||||
/* I2C1 */ { CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_I2C1, 0xC, 6, 0 },
|
/* I2C1 */ { CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_I2C1, 12, 0, 19 }, //20.4MHz -> 100KHz
|
||||||
/* I2C2 */ { 0 },
|
/* I2C2 */ { CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_RST_CONTROLLER_CLK_SOURCE_I2C2, 22, 0, 4 }, //81.6MHz -> 400KHz
|
||||||
/* I2C3 */ { 0 },
|
/* I2C3 */ { CLK_RST_CONTROLLER_RST_DEVICES_U, CLK_RST_CONTROLLER_CLK_OUT_ENB_U, CLK_RST_CONTROLLER_CLK_SOURCE_I2C3, 3, 0, 4 }, //81.6MHz -> 400KHz
|
||||||
/* I2C4 */ { 0 },
|
/* I2C4 */ { CLK_RST_CONTROLLER_RST_DEVICES_V, CLK_RST_CONTROLLER_CLK_OUT_ENB_V, CLK_RST_CONTROLLER_CLK_SOURCE_I2C4, 7, 0, 19 }, //20.4MHz -> 100KHz
|
||||||
/* I2C5 */ { CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_RST_CONTROLLER_CLK_SOURCE_I2C5, 0xF, 6, 0 },
|
/* I2C5 */ { CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_RST_CONTROLLER_CLK_SOURCE_I2C5, 15, 0, 4 }, //81.6MHz -> 400KHz
|
||||||
/* I2C6 */ { 0 }
|
/* I2C6 */ { CLK_RST_CONTROLLER_RST_DEVICES_X, CLK_RST_CONTROLLER_CLK_OUT_ENB_X, CLK_RST_CONTROLLER_CLK_SOURCE_I2C6, 6, 0, 19 } //20.4MHz -> 100KHz
|
||||||
};
|
};
|
||||||
|
|
||||||
static clock_t _clock_se = {
|
static clock_t _clock_se = {
|
||||||
CLK_RST_CONTROLLER_RST_DEVICES_V, CLK_RST_CONTROLLER_CLK_OUT_ENB_V, CLK_RST_CONTROLLER_CLK_SOURCE_SE, 0x1F, 0, 0
|
CLK_RST_CONTROLLER_RST_DEVICES_V, CLK_RST_CONTROLLER_CLK_OUT_ENB_V, CLK_RST_CONTROLLER_CLK_SOURCE_SE, 31, 0, 0
|
||||||
};
|
};
|
||||||
static clock_t _clock_unk2 = {
|
|
||||||
CLK_RST_CONTROLLER_RST_DEVICES_V, CLK_RST_CONTROLLER_CLK_OUT_ENB_V, CLK_NO_SOURCE, 0x1E, 0, 0
|
static clock_t _clock_tzram = {
|
||||||
|
CLK_RST_CONTROLLER_RST_DEVICES_V, CLK_RST_CONTROLLER_CLK_OUT_ENB_V, CLK_NO_SOURCE, 30, 0, 0
|
||||||
};
|
};
|
||||||
|
|
||||||
static clock_t _clock_host1x = {
|
static clock_t _clock_host1x = {
|
||||||
CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_HOST1X, 0x1C, 4, 3
|
CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_HOST1X, 28, 4, 3
|
||||||
};
|
};
|
||||||
static clock_t _clock_tsec = {
|
static clock_t _clock_tsec = {
|
||||||
CLK_RST_CONTROLLER_RST_DEVICES_U, CLK_RST_CONTROLLER_CLK_OUT_ENB_U, CLK_RST_CONTROLLER_CLK_SOURCE_TSEC, 0x13, 0, 2
|
CLK_RST_CONTROLLER_RST_DEVICES_U, CLK_RST_CONTROLLER_CLK_OUT_ENB_U, CLK_RST_CONTROLLER_CLK_SOURCE_TSEC, 19, 0, 2
|
||||||
};
|
};
|
||||||
static clock_t _clock_sor_safe = {
|
static clock_t _clock_sor_safe = {
|
||||||
CLK_RST_CONTROLLER_RST_DEVICES_Y, CLK_RST_CONTROLLER_CLK_OUT_ENB_Y, CLK_NO_SOURCE, 0x1E, 0, 0
|
CLK_RST_CONTROLLER_RST_DEVICES_Y, CLK_RST_CONTROLLER_CLK_OUT_ENB_Y, CLK_NO_SOURCE, 30, 0, 0
|
||||||
};
|
};
|
||||||
static clock_t _clock_sor0 = {
|
static clock_t _clock_sor0 = {
|
||||||
CLK_RST_CONTROLLER_RST_DEVICES_X, CLK_RST_CONTROLLER_CLK_OUT_ENB_X, CLK_NO_SOURCE, 0x16, 0, 0
|
CLK_RST_CONTROLLER_RST_DEVICES_X, CLK_RST_CONTROLLER_CLK_OUT_ENB_X, CLK_NO_SOURCE, 22, 0, 0
|
||||||
};
|
};
|
||||||
static clock_t _clock_sor1 = {
|
static clock_t _clock_sor1 = {
|
||||||
CLK_RST_CONTROLLER_RST_DEVICES_X, CLK_RST_CONTROLLER_CLK_OUT_ENB_X, CLK_RST_CONTROLLER_CLK_SOURCE_SOR1, 0x17, 0, 2
|
CLK_RST_CONTROLLER_RST_DEVICES_X, CLK_RST_CONTROLLER_CLK_OUT_ENB_X, CLK_RST_CONTROLLER_CLK_SOURCE_SOR1, 23, 0, 2
|
||||||
};
|
};
|
||||||
static clock_t _clock_kfuse = {
|
static clock_t _clock_kfuse = {
|
||||||
CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_NO_SOURCE, 8, 0, 0
|
CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_NO_SOURCE, 8, 0, 0
|
||||||
};
|
};
|
||||||
|
|
||||||
static clock_t _clock_cl_dvfs = {
|
static clock_t _clock_cl_dvfs = {
|
||||||
CLK_RST_CONTROLLER_RST_DEVICES_W, CLK_RST_CONTROLLER_CLK_OUT_ENB_W, CLK_NO_SOURCE, 0x1B, 0, 0
|
CLK_RST_CONTROLLER_RST_DEVICES_W, CLK_RST_CONTROLLER_CLK_OUT_ENB_W, CLK_NO_SOURCE, 27, 0, 0
|
||||||
};
|
};
|
||||||
static clock_t _clock_coresight = {
|
static clock_t _clock_coresight = {
|
||||||
CLK_RST_CONTROLLER_RST_DEVICES_U, CLK_RST_CONTROLLER_CLK_OUT_ENB_U, CLK_RST_CONTROLLER_CLK_SOURCE_CSITE, 9, 0, 4
|
CLK_RST_CONTROLLER_RST_DEVICES_U, CLK_RST_CONTROLLER_CLK_OUT_ENB_U, CLK_RST_CONTROLLER_CLK_SOURCE_CSITE, 9, 0, 4
|
||||||
};
|
};
|
||||||
|
|
||||||
static clock_t _clock_pwm = {
|
static clock_t _clock_pwm = {
|
||||||
CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_PWM, 0x11, 6, 4
|
CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_PWM, 17, 6, 4 // Fref: 6.2MHz.
|
||||||
|
};
|
||||||
|
|
||||||
|
static clock_t _clock_sdmmc_legacy_tm = {
|
||||||
|
CLK_RST_CONTROLLER_RST_DEVICES_Y, CLK_RST_CONTROLLER_CLK_OUT_ENB_Y, CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC_LEGACY_TM, 1, 4, 66
|
||||||
};
|
};
|
||||||
|
|
||||||
void clock_enable(const clock_t *clk)
|
void clock_enable(const clock_t *clk)
|
||||||
@@ -86,6 +104,8 @@ void clock_enable(const clock_t *clk)
|
|||||||
CLOCK(clk->source) = clk->clk_div | (clk->clk_src << 29);
|
CLOCK(clk->source) = clk->clk_div | (clk->clk_src << 29);
|
||||||
// Enable.
|
// Enable.
|
||||||
CLOCK(clk->enable) = (CLOCK(clk->enable) & ~(1 << clk->index)) | (1 << clk->index);
|
CLOCK(clk->enable) = (CLOCK(clk->enable) & ~(1 << clk->index)) | (1 << clk->index);
|
||||||
|
usleep(2);
|
||||||
|
|
||||||
// Take clock off reset.
|
// Take clock off reset.
|
||||||
CLOCK(clk->reset) &= ~(1 << clk->index);
|
CLOCK(clk->reset) &= ~(1 << clk->index);
|
||||||
}
|
}
|
||||||
@@ -108,6 +128,29 @@ void clock_enable_uart(u32 idx)
|
|||||||
clock_enable(&_clock_uart[idx]);
|
clock_enable(&_clock_uart[idx]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void clock_disable_uart(u32 idx)
|
||||||
|
{
|
||||||
|
clock_disable(&_clock_uart[idx]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define UART_SRC_CLK_DIV_EN (1 << 24)
|
||||||
|
|
||||||
|
int clock_uart_use_src_div(u32 idx, u32 baud)
|
||||||
|
{
|
||||||
|
u32 clk_src_div = CLOCK(_clock_uart[idx].source) & 0xE0000000;
|
||||||
|
|
||||||
|
if (baud == 1000000)
|
||||||
|
CLOCK(_clock_uart[idx].source) = clk_src_div | UART_SRC_CLK_DIV_EN | 49;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CLOCK(_clock_uart[idx].source) = clk_src_div | 2;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
void clock_enable_i2c(u32 idx)
|
void clock_enable_i2c(u32 idx)
|
||||||
{
|
{
|
||||||
clock_enable(&_clock_i2c[idx]);
|
clock_enable(&_clock_i2c[idx]);
|
||||||
@@ -123,9 +166,9 @@ void clock_enable_se()
|
|||||||
clock_enable(&_clock_se);
|
clock_enable(&_clock_se);
|
||||||
}
|
}
|
||||||
|
|
||||||
void clock_enable_unk2()
|
void clock_enable_tzram()
|
||||||
{
|
{
|
||||||
clock_enable(&_clock_unk2);
|
clock_enable(&_clock_tzram);
|
||||||
}
|
}
|
||||||
|
|
||||||
void clock_enable_host1x()
|
void clock_enable_host1x()
|
||||||
@@ -224,6 +267,51 @@ void clock_disable_pwm()
|
|||||||
clock_disable(&_clock_pwm);
|
clock_disable(&_clock_pwm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void clock_enable_pllc(u32 divn)
|
||||||
|
{
|
||||||
|
u8 pll_divn_curr = (CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) >> 10) & 0xFF;
|
||||||
|
|
||||||
|
// Check if already enabled and configured.
|
||||||
|
if ((CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) & PLLCX_BASE_ENABLE) && (pll_divn_curr == divn))
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Take PLLC out of reset and set basic misc parameters.
|
||||||
|
CLOCK(CLK_RST_CONTROLLER_PLLC_MISC) =
|
||||||
|
((CLOCK(CLK_RST_CONTROLLER_PLLC_MISC) & 0xFFF0000F) & ~PLLC_MISC_RESET) | (0x80000 << 4); // PLLC_EXT_FRU.
|
||||||
|
CLOCK(CLK_RST_CONTROLLER_PLLC_MISC_2) |= 0xF0 << 8; // PLLC_FLL_LD_MEM.
|
||||||
|
|
||||||
|
// Disable PLL and IDDQ in case they are on.
|
||||||
|
CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) &= ~PLLCX_BASE_ENABLE;
|
||||||
|
CLOCK(CLK_RST_CONTROLLER_PLLC_MISC_1) &= ~PLLC_MISC1_IDDQ;
|
||||||
|
usleep(10);
|
||||||
|
|
||||||
|
// Set PLLC dividers.
|
||||||
|
CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) = (divn << 10) | 4; // DIVM: 4, DIVP: 1.
|
||||||
|
|
||||||
|
// Enable PLLC and wait for Phase and Frequency lock.
|
||||||
|
CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) |= PLLCX_BASE_ENABLE;
|
||||||
|
while (!(CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) & PLLCX_BASE_LOCK))
|
||||||
|
;
|
||||||
|
|
||||||
|
// Disable PLLC_OUT1, enable reset and set div to 1.5.
|
||||||
|
CLOCK(CLK_RST_CONTROLLER_PLLC_OUT) = (1 << 8);
|
||||||
|
|
||||||
|
// Enable PLLC_OUT1 and bring it out of reset.
|
||||||
|
CLOCK(CLK_RST_CONTROLLER_PLLC_OUT) |= (PLLC_OUT1_CLKEN | PLLC_OUT1_RSTN_CLR);
|
||||||
|
msleep(1); // Wait a bit for PLL to stabilize.
|
||||||
|
}
|
||||||
|
|
||||||
|
void clock_disable_pllc()
|
||||||
|
{
|
||||||
|
// Disable PLLC and PLLC_OUT1.
|
||||||
|
CLOCK(CLK_RST_CONTROLLER_PLLC_OUT) &= ~(PLLC_OUT1_CLKEN | PLLC_OUT1_RSTN_CLR);
|
||||||
|
CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) &= ~PLLCX_BASE_ENABLE;
|
||||||
|
CLOCK(CLK_RST_CONTROLLER_PLLC_BASE) |= PLLCX_BASE_REF_DIS;
|
||||||
|
CLOCK(CLK_RST_CONTROLLER_PLLC_MISC_1) |= PLLC_MISC1_IDDQ;
|
||||||
|
CLOCK(CLK_RST_CONTROLLER_PLLC_MISC) |= PLLC_MISC_RESET;
|
||||||
|
usleep(10);
|
||||||
|
}
|
||||||
|
|
||||||
#define L_SWR_SDMMC1_RST (1 << 14)
|
#define L_SWR_SDMMC1_RST (1 << 14)
|
||||||
#define L_SWR_SDMMC2_RST (1 << 9)
|
#define L_SWR_SDMMC2_RST (1 << 9)
|
||||||
#define L_SWR_SDMMC4_RST (1 << 15)
|
#define L_SWR_SDMMC4_RST (1 << 15)
|
||||||
@@ -362,57 +450,80 @@ static void _clock_sdmmc_clear_enable(u32 id)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static u32 _clock_sdmmc_table[8] = { 0 };
|
static void _clock_sdmmc_config_legacy_tm()
|
||||||
|
{
|
||||||
|
clock_t *clk = &_clock_sdmmc_legacy_tm;
|
||||||
|
if (!(CLOCK(clk->enable) & (1 << clk->index)))
|
||||||
|
clock_enable(clk);
|
||||||
|
}
|
||||||
|
|
||||||
#define PLLP_OUT0 0x0
|
typedef struct _clock_sdmmc_t
|
||||||
|
{
|
||||||
|
u32 clock;
|
||||||
|
u32 real_clock;
|
||||||
|
} clock_sdmmc_t;
|
||||||
|
|
||||||
static int _clock_sdmmc_config_clock_source_inner(u32 *pout, u32 id, u32 val)
|
static clock_sdmmc_t _clock_sdmmc_table[4] = { 0 };
|
||||||
|
|
||||||
|
#define SDMMC_CLOCK_SRC_PLLP_OUT0 0x0
|
||||||
|
#define SDMMC_CLOCK_SRC_PLLC4_OUT2 0x3
|
||||||
|
#define SDMMC4_CLOCK_SRC_PLLC4_OUT2_LJ 0x1
|
||||||
|
|
||||||
|
static int _clock_sdmmc_config_clock_host(u32 *pclock, u32 id, u32 val)
|
||||||
{
|
{
|
||||||
u32 divisor = 0;
|
u32 divisor = 0;
|
||||||
u32 source = PLLP_OUT0;
|
u32 source = SDMMC_CLOCK_SRC_PLLP_OUT0;
|
||||||
|
|
||||||
|
if (id > SDMMC_4)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// Get IO clock divisor.
|
||||||
switch (val)
|
switch (val)
|
||||||
{
|
{
|
||||||
case 25000:
|
case 25000:
|
||||||
*pout = 24728;
|
*pclock = 24728;
|
||||||
divisor = 31;
|
divisor = 31; // 16.5 div.
|
||||||
break;
|
break;
|
||||||
case 26000:
|
case 26000:
|
||||||
*pout = 25500;
|
*pclock = 25500;
|
||||||
divisor = 30;
|
divisor = 30; // 16 div.
|
||||||
break;
|
break;
|
||||||
case 40800:
|
case 40800:
|
||||||
*pout = 40800;
|
*pclock = 40800;
|
||||||
divisor = 18;
|
divisor = 18; // 10 div.
|
||||||
break;
|
break;
|
||||||
case 50000:
|
case 50000:
|
||||||
*pout = 48000;
|
*pclock = 48000;
|
||||||
divisor = 15;
|
divisor = 15; // 8.5 div.
|
||||||
break;
|
break;
|
||||||
case 52000:
|
case 52000:
|
||||||
*pout = 51000;
|
*pclock = 51000;
|
||||||
divisor = 14;
|
divisor = 14; // 8 div.
|
||||||
break;
|
break;
|
||||||
case 100000:
|
case 100000:
|
||||||
*pout = 90667;
|
*pclock = 90667;
|
||||||
divisor = 7;
|
divisor = 7; // 4.5 div.
|
||||||
|
break;
|
||||||
|
case 164000:
|
||||||
|
*pclock = 163200;
|
||||||
|
divisor = 3; // 2.5 div.
|
||||||
break;
|
break;
|
||||||
case 200000:
|
case 200000:
|
||||||
*pout = 163200;
|
*pclock = 204000;
|
||||||
divisor = 3;
|
divisor = 2; // 2 div.
|
||||||
break;
|
|
||||||
case 208000:
|
|
||||||
*pout = 204000;
|
|
||||||
divisor = 2;
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
*pout = 24728;
|
*pclock = 24728;
|
||||||
divisor = 31;
|
divisor = 31; // 16.5 div.
|
||||||
}
|
}
|
||||||
|
|
||||||
_clock_sdmmc_table[2 * id] = val;
|
_clock_sdmmc_table[id].clock = val;
|
||||||
_clock_sdmmc_table[2 * id + 1] = *pout;
|
_clock_sdmmc_table[id].real_clock = *pclock;
|
||||||
|
|
||||||
|
// Set SDMMC legacy timeout clock.
|
||||||
|
_clock_sdmmc_config_legacy_tm();
|
||||||
|
|
||||||
|
// Set SDMMC clock.
|
||||||
switch (id)
|
switch (id)
|
||||||
{
|
{
|
||||||
case SDMMC_1:
|
case SDMMC_1:
|
||||||
@@ -432,69 +543,75 @@ static int _clock_sdmmc_config_clock_source_inner(u32 *pout, u32 id, u32 val)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void clock_sdmmc_config_clock_source(u32 *pout, u32 id, u32 val)
|
void clock_sdmmc_config_clock_source(u32 *pclock, u32 id, u32 val)
|
||||||
{
|
{
|
||||||
if (_clock_sdmmc_table[2 * id] == val)
|
if (_clock_sdmmc_table[id].clock == val)
|
||||||
{
|
{
|
||||||
*pout = _clock_sdmmc_table[2 * id + 1];
|
*pclock = _clock_sdmmc_table[id].real_clock;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
int is_enabled = _clock_sdmmc_is_enabled(id);
|
int is_enabled = _clock_sdmmc_is_enabled(id);
|
||||||
if (is_enabled)
|
if (is_enabled)
|
||||||
_clock_sdmmc_clear_enable(id);
|
_clock_sdmmc_clear_enable(id);
|
||||||
_clock_sdmmc_config_clock_source_inner(pout, id, val);
|
_clock_sdmmc_config_clock_host(pclock, id, val);
|
||||||
if (is_enabled)
|
if (is_enabled)
|
||||||
_clock_sdmmc_set_enable(id);
|
_clock_sdmmc_set_enable(id);
|
||||||
_clock_sdmmc_is_reset(id);
|
_clock_sdmmc_is_reset(id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void clock_sdmmc_get_params(u32 *pout, u16 *pdivisor, u32 type)
|
void clock_sdmmc_get_card_clock_div(u32 *pclock, u16 *pdivisor, u32 type)
|
||||||
{
|
{
|
||||||
|
// Get Card clock divisor.
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
case 0:
|
case SDHCI_TIMING_MMC_ID: // Actual IO Freq: 380.59 KHz.
|
||||||
*pout = 26000;
|
*pclock = 26000;
|
||||||
*pdivisor = 66;
|
*pdivisor = 66;
|
||||||
break;
|
break;
|
||||||
case 1:
|
case SDHCI_TIMING_MMC_LS26:
|
||||||
*pout = 26000;
|
*pclock = 26000;
|
||||||
*pdivisor = 1;
|
*pdivisor = 1;
|
||||||
break;
|
break;
|
||||||
case 2:
|
case SDHCI_TIMING_MMC_HS52:
|
||||||
*pout = 52000;
|
*pclock = 52000;
|
||||||
*pdivisor = 1;
|
*pdivisor = 1;
|
||||||
break;
|
break;
|
||||||
case 3:
|
case SDHCI_TIMING_MMC_HS200:
|
||||||
case 4:
|
case SDHCI_TIMING_MMC_HS400:
|
||||||
case 11:
|
case SDHCI_TIMING_UHS_SDR104:
|
||||||
*pout = 200000;
|
*pclock = 200000;
|
||||||
*pdivisor = 1;
|
*pdivisor = 1;
|
||||||
break;
|
break;
|
||||||
case 5:
|
case SDHCI_TIMING_SD_ID: // Actual IO Freq: 380.43 KHz.
|
||||||
*pout = 25000;
|
*pclock = 25000;
|
||||||
*pdivisor = 64;
|
*pdivisor = 64;
|
||||||
break;
|
break;
|
||||||
case 6:
|
case SDHCI_TIMING_SD_DS12:
|
||||||
case 8:
|
case SDHCI_TIMING_UHS_SDR12:
|
||||||
*pout = 25000;
|
*pclock = 25000;
|
||||||
*pdivisor = 1;
|
*pdivisor = 1;
|
||||||
break;
|
break;
|
||||||
case 7:
|
case SDHCI_TIMING_SD_HS25:
|
||||||
*pout = 50000;
|
case SDHCI_TIMING_UHS_SDR25:
|
||||||
|
*pclock = 50000;
|
||||||
*pdivisor = 1;
|
*pdivisor = 1;
|
||||||
break;
|
break;
|
||||||
case 10:
|
case SDHCI_TIMING_UHS_SDR50:
|
||||||
*pout = 100000;
|
*pclock = 100000;
|
||||||
*pdivisor = 1;
|
*pdivisor = 1;
|
||||||
break;
|
break;
|
||||||
case 13:
|
case SDHCI_TIMING_UHS_SDR82:
|
||||||
*pout = 40800;
|
*pclock = 164000;
|
||||||
*pdivisor = 1;
|
*pdivisor = 1;
|
||||||
break;
|
break;
|
||||||
case 14:
|
case SDHCI_TIMING_UHS_DDR50:
|
||||||
*pout = 200000;
|
*pclock = 40800;
|
||||||
|
*pdivisor = 1;
|
||||||
|
break;
|
||||||
|
case SDHCI_TIMING_MMC_DDR52: // Actual IO Freq: 49.92 MHz.
|
||||||
|
*pclock = 200000;
|
||||||
*pdivisor = 2;
|
*pdivisor = 2;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -507,15 +624,15 @@ int clock_sdmmc_is_not_reset_and_enabled(u32 id)
|
|||||||
|
|
||||||
void clock_sdmmc_enable(u32 id, u32 val)
|
void clock_sdmmc_enable(u32 id, u32 val)
|
||||||
{
|
{
|
||||||
u32 div = 0;
|
u32 clock = 0;
|
||||||
|
|
||||||
if (_clock_sdmmc_is_enabled(id))
|
if (_clock_sdmmc_is_enabled(id))
|
||||||
_clock_sdmmc_clear_enable(id);
|
_clock_sdmmc_clear_enable(id);
|
||||||
_clock_sdmmc_set_reset(id);
|
_clock_sdmmc_set_reset(id);
|
||||||
_clock_sdmmc_config_clock_source_inner(&div, id, val);
|
_clock_sdmmc_config_clock_host(&clock, id, val);
|
||||||
_clock_sdmmc_set_enable(id);
|
_clock_sdmmc_set_enable(id);
|
||||||
_clock_sdmmc_is_reset(id);
|
_clock_sdmmc_is_reset(id);
|
||||||
usleep((100000 + div - 1) / div);
|
usleep((100000 + clock - 1) / clock);
|
||||||
_clock_sdmmc_clear_reset(id);
|
_clock_sdmmc_clear_reset(id);
|
||||||
_clock_sdmmc_is_reset(id);
|
_clock_sdmmc_is_reset(id);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2018 naehrwert
|
* Copyright (c) 2018 naehrwert
|
||||||
|
* Copyright (c) 2018-2020 CTCaer
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
* under the terms and conditions of the GNU General Public License,
|
* under the terms and conditions of the GNU General Public License,
|
||||||
@@ -35,21 +36,33 @@
|
|||||||
#define CLK_RST_CONTROLLER_MISC_CLK_ENB 0x48
|
#define CLK_RST_CONTROLLER_MISC_CLK_ENB 0x48
|
||||||
#define CLK_RST_CONTROLLER_OSC_CTRL 0x50
|
#define CLK_RST_CONTROLLER_OSC_CTRL 0x50
|
||||||
#define CLK_RST_CONTROLLER_PLLC_BASE 0x80
|
#define CLK_RST_CONTROLLER_PLLC_BASE 0x80
|
||||||
|
#define CLK_RST_CONTROLLER_PLLC_OUT 0x84
|
||||||
#define CLK_RST_CONTROLLER_PLLC_MISC 0x88
|
#define CLK_RST_CONTROLLER_PLLC_MISC 0x88
|
||||||
|
#define CLK_RST_CONTROLLER_PLLC_MISC_1 0x8C
|
||||||
#define CLK_RST_CONTROLLER_PLLM_BASE 0x90
|
#define CLK_RST_CONTROLLER_PLLM_BASE 0x90
|
||||||
#define CLK_RST_CONTROLLER_PLLM_MISC1 0x98
|
#define CLK_RST_CONTROLLER_PLLM_MISC1 0x98
|
||||||
#define CLK_RST_CONTROLLER_PLLM_MISC2 0x9C
|
#define CLK_RST_CONTROLLER_PLLM_MISC2 0x9C
|
||||||
#define CLK_RST_CONTROLLER_PLLP_BASE 0xA0
|
#define CLK_RST_CONTROLLER_PLLP_BASE 0xA0
|
||||||
|
#define CLK_RST_CONTROLLER_PLLA_BASE 0xB0
|
||||||
|
#define CLK_RST_CONTROLLER_PLLA_OUT 0xB4
|
||||||
|
#define CLK_RST_CONTROLLER_PLLA_MISC1 0xB8
|
||||||
|
#define CLK_RST_CONTROLLER_PLLA_MISC 0xBC
|
||||||
|
#define CLK_RST_CONTROLLER_PLLU_BASE 0xC0
|
||||||
|
#define CLK_RST_CONTROLLER_PLLU_MISC 0xCC
|
||||||
#define CLK_RST_CONTROLLER_PLLD_BASE 0xD0
|
#define CLK_RST_CONTROLLER_PLLD_BASE 0xD0
|
||||||
|
#define CLK_RST_CONTROLLER_PLLD_MISC1 0xD8
|
||||||
|
#define CLK_RST_CONTROLLER_PLLD_MISC 0xDC
|
||||||
#define CLK_RST_CONTROLLER_PLLX_BASE 0xE0
|
#define CLK_RST_CONTROLLER_PLLX_BASE 0xE0
|
||||||
#define CLK_RST_CONTROLLER_PLLX_MISC 0xE4
|
#define CLK_RST_CONTROLLER_PLLX_MISC 0xE4
|
||||||
#define CLK_RST_CONTROLLER_PLLE_BASE 0xE8
|
#define CLK_RST_CONTROLLER_PLLE_BASE 0xE8
|
||||||
#define CLK_RST_CONTROLLER_PLLE_MISC 0xEC
|
#define CLK_RST_CONTROLLER_PLLE_MISC 0xEC
|
||||||
#define CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRA 0xF8
|
#define CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRA 0xF8
|
||||||
#define CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRB 0xFC
|
#define CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRB 0xFC
|
||||||
|
#define CLK_RST_CONTROLLER_CLK_SOURCE_I2S2 0x100
|
||||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_PWM 0x110
|
#define CLK_RST_CONTROLLER_CLK_SOURCE_PWM 0x110
|
||||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_I2C1 0x124
|
#define CLK_RST_CONTROLLER_CLK_SOURCE_I2C1 0x124
|
||||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_I2C5 0x128
|
#define CLK_RST_CONTROLLER_CLK_SOURCE_I2C5 0x128
|
||||||
|
#define CLK_RST_CONTROLLER_CLK_SOURCE_DISP1 0x138
|
||||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_VI 0x148
|
#define CLK_RST_CONTROLLER_CLK_SOURCE_VI 0x148
|
||||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC1 0x150
|
#define CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC1 0x150
|
||||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC2 0x154
|
#define CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC2 0x154
|
||||||
@@ -57,11 +70,14 @@
|
|||||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_UARTA 0x178
|
#define CLK_RST_CONTROLLER_CLK_SOURCE_UARTA 0x178
|
||||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_UARTB 0x17C
|
#define CLK_RST_CONTROLLER_CLK_SOURCE_UARTB 0x17C
|
||||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_HOST1X 0x180
|
#define CLK_RST_CONTROLLER_CLK_SOURCE_HOST1X 0x180
|
||||||
|
#define CLK_RST_CONTROLLER_CLK_SOURCE_I2C2 0x198
|
||||||
|
#define CLK_RST_CONTROLLER_CLK_SOURCE_EMC 0x19C
|
||||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_UARTC 0x1A0
|
#define CLK_RST_CONTROLLER_CLK_SOURCE_UARTC 0x1A0
|
||||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_I2C3 0x1B8
|
#define CLK_RST_CONTROLLER_CLK_SOURCE_I2C3 0x1B8
|
||||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC3 0x1BC
|
#define CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC3 0x1BC
|
||||||
|
#define CLK_RST_CONTROLLER_CLK_SOURCE_UARTD 0x1C0
|
||||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_CSITE 0x1D4
|
#define CLK_RST_CONTROLLER_CLK_SOURCE_CSITE 0x1D4
|
||||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_EMC 0x19C
|
#define CLK_RST_CONTROLLER_CLK_SOURCE_I2S1 0x1D8
|
||||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_TSEC 0x1F4
|
#define CLK_RST_CONTROLLER_CLK_SOURCE_TSEC 0x1F4
|
||||||
#define CLK_RST_CONTROLLER_CLK_OUT_ENB_X 0x280
|
#define CLK_RST_CONTROLLER_CLK_OUT_ENB_X 0x280
|
||||||
#define CLK_RST_CONTROLLER_CLK_ENB_X_SET 0x284
|
#define CLK_RST_CONTROLLER_CLK_ENB_X_SET 0x284
|
||||||
@@ -95,29 +111,66 @@
|
|||||||
#define CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRC 0x3A0
|
#define CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRC 0x3A0
|
||||||
#define CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRD 0x3A4
|
#define CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRD 0x3A4
|
||||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_MSELECT 0x3B4
|
#define CLK_RST_CONTROLLER_CLK_SOURCE_MSELECT 0x3B4
|
||||||
|
#define CLK_RST_CONTROLLER_CLK_SOURCE_I2C4 0x3C4
|
||||||
|
#define CLK_RST_CONTROLLER_CLK_SOURCE_EXTPERIPH1 0x3EC
|
||||||
|
#define CLK_RST_CONTROLLER_CLK_SOURCE_SYS 0x400
|
||||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_SOR1 0x410
|
#define CLK_RST_CONTROLLER_CLK_SOURCE_SOR1 0x410
|
||||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_SE 0x42C
|
#define CLK_RST_CONTROLLER_CLK_SOURCE_SE 0x42C
|
||||||
|
#define CLK_RST_CONTROLLER_RST_DEV_V_SET 0x430
|
||||||
|
#define CLK_RST_CONTROLLER_RST_DEV_V_CLR 0x434
|
||||||
|
#define CLK_RST_CONTROLLER_RST_DEV_W_SET 0x438
|
||||||
|
#define CLK_RST_CONTROLLER_RST_DEV_W_CLR 0x43C
|
||||||
#define CLK_RST_CONTROLLER_CLK_ENB_V_SET 0x440
|
#define CLK_RST_CONTROLLER_CLK_ENB_V_SET 0x440
|
||||||
|
#define CLK_RST_CONTROLLER_CLK_ENB_V_CLR 0x444
|
||||||
#define CLK_RST_CONTROLLER_CLK_ENB_W_SET 0x448
|
#define CLK_RST_CONTROLLER_CLK_ENB_W_SET 0x448
|
||||||
#define CLK_RST_CONTROLLER_CLK_ENB_W_CLR 0x44C
|
#define CLK_RST_CONTROLLER_CLK_ENB_W_CLR 0x44C
|
||||||
#define CLK_RST_CONTROLLER_RST_CPUG_CMPLX_SET 0x450
|
#define CLK_RST_CONTROLLER_RST_CPUG_CMPLX_SET 0x450
|
||||||
#define CLK_RST_CONTROLLER_RST_CPUG_CMPLX_CLR 0x454
|
#define CLK_RST_CONTROLLER_RST_CPUG_CMPLX_CLR 0x454
|
||||||
|
#define CLK_RST_CONTROLLER_UTMIP_PLL_CFG0 0x480
|
||||||
|
#define CLK_RST_CONTROLLER_UTMIP_PLL_CFG1 0x484
|
||||||
#define CLK_RST_CONTROLLER_UTMIP_PLL_CFG2 0x488
|
#define CLK_RST_CONTROLLER_UTMIP_PLL_CFG2 0x488
|
||||||
#define CLK_RST_CONTROLLER_PLLE_AUX 0x48C
|
#define CLK_RST_CONTROLLER_PLLE_AUX 0x48C
|
||||||
#define CLK_RST_CONTROLLER_AUDIO_SYNC_CLK_I2S0 0x4A0
|
#define CLK_RST_CONTROLLER_AUDIO_SYNC_CLK_I2S0 0x4A0
|
||||||
#define CLK_RST_CONTROLLER_PLLX_MISC_3 0x518
|
#define CLK_RST_CONTROLLER_PLLX_MISC_3 0x518
|
||||||
|
#define CLK_RST_CONTROLLER_UTMIPLL_HW_PWRDN_CFG0 0x52C
|
||||||
#define CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRE 0x554
|
#define CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRE 0x554
|
||||||
#define CLK_RST_CONTROLLER_SPARE_REG0 0x55C
|
#define CLK_RST_CONTROLLER_SPARE_REG0 0x55C
|
||||||
|
#define CLK_RST_CONTROLLER_PLLC4_BASE 0x5A4
|
||||||
|
#define CLK_RST_CONTROLLER_PLLC4_MISC 0x5A8
|
||||||
|
#define CLK_RST_CONTROLLER_PLLC_MISC_2 0x5D0
|
||||||
|
#define CLK_RST_CONTROLLER_PLLC4_OUT 0x5E4
|
||||||
#define CLK_RST_CONTROLLER_PLLMB_BASE 0x5E8
|
#define CLK_RST_CONTROLLER_PLLMB_BASE 0x5E8
|
||||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_DSIA_LP 0x620
|
#define CLK_RST_CONTROLLER_CLK_SOURCE_DSIA_LP 0x620
|
||||||
|
#define CLK_RST_CONTROLLER_CLK_SOURCE_I2C6 0x65C
|
||||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_EMC_DLL 0x664
|
#define CLK_RST_CONTROLLER_CLK_SOURCE_EMC_DLL 0x664
|
||||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_UART_FST_MIP_CAL 0x66C
|
#define CLK_RST_CONTROLLER_CLK_SOURCE_UART_FST_MIPI_CAL 0x66C
|
||||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC_LEGACY_TM 0x694
|
#define CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC_LEGACY_TM 0x694
|
||||||
#define CLK_RST_CONTROLLER_CLK_SOURCE_NVENC 0x6A0
|
#define CLK_RST_CONTROLLER_CLK_SOURCE_NVENC 0x6A0
|
||||||
|
#define CLK_RST_CONTROLLER_CLK_SOURCE_USB2_HSIC_TRK 0x6CC
|
||||||
#define CLK_RST_CONTROLLER_SE_SUPER_CLK_DIVIDER 0x704
|
#define CLK_RST_CONTROLLER_SE_SUPER_CLK_DIVIDER 0x704
|
||||||
|
#define CLK_RST_CONTROLLER_CLK_SOURCE_UARTAPE 0x710
|
||||||
|
|
||||||
#define CLK_NO_SOURCE 0x0
|
#define CLK_NO_SOURCE 0x0
|
||||||
|
|
||||||
|
/*! PLL control and status bits */
|
||||||
|
#define PLLCX_BASE_ENABLE (1 << 30)
|
||||||
|
#define PLLCX_BASE_REF_DIS (1 << 29)
|
||||||
|
#define PLLCX_BASE_LOCK (1 << 27)
|
||||||
|
|
||||||
|
#define PLLA_BASE_IDDQ (1 << 25)
|
||||||
|
#define PLLA_OUT0_CLKEN (1 << 1)
|
||||||
|
#define PLLA_OUT0_RSTN_CLR (1 << 0)
|
||||||
|
|
||||||
|
#define PLLC_MISC_RESET (1 << 30)
|
||||||
|
#define PLLC_MISC1_IDDQ (1 << 27)
|
||||||
|
#define PLLC_OUT1_CLKEN (1 << 1)
|
||||||
|
#define PLLC_OUT1_RSTN_CLR (1 << 0)
|
||||||
|
|
||||||
|
#define PLLC4_MISC_EN_LCKDET (1 << 30)
|
||||||
|
#define PLLC4_BASE_IDDQ (1 << 18)
|
||||||
|
#define PLLC4_OUT3_CLKEN (1 << 1)
|
||||||
|
#define PLLC4_OUT3_RSTN_CLR (1 << 0)
|
||||||
|
|
||||||
/*! Generic clock descriptor. */
|
/*! Generic clock descriptor. */
|
||||||
typedef struct _clock_t
|
typedef struct _clock_t
|
||||||
{
|
{
|
||||||
@@ -136,10 +189,12 @@ void clock_disable(const clock_t *clk);
|
|||||||
/*! Clock control for specific hardware portions. */
|
/*! Clock control for specific hardware portions. */
|
||||||
void clock_enable_fuse(bool enable);
|
void clock_enable_fuse(bool enable);
|
||||||
void clock_enable_uart(u32 idx);
|
void clock_enable_uart(u32 idx);
|
||||||
|
void clock_disable_uart(u32 idx);
|
||||||
|
int clock_uart_use_src_div(u32 idx, u32 baud);
|
||||||
void clock_enable_i2c(u32 idx);
|
void clock_enable_i2c(u32 idx);
|
||||||
void clock_disable_i2c(u32 idx);
|
void clock_disable_i2c(u32 idx);
|
||||||
void clock_enable_se();
|
void clock_enable_se();
|
||||||
void clock_enable_unk2();
|
void clock_enable_tzram();
|
||||||
void clock_enable_host1x();
|
void clock_enable_host1x();
|
||||||
void clock_disable_host1x();
|
void clock_disable_host1x();
|
||||||
void clock_enable_tsec();
|
void clock_enable_tsec();
|
||||||
@@ -158,8 +213,10 @@ void clock_enable_coresight();
|
|||||||
void clock_disable_coresight();
|
void clock_disable_coresight();
|
||||||
void clock_enable_pwm();
|
void clock_enable_pwm();
|
||||||
void clock_disable_pwm();
|
void clock_disable_pwm();
|
||||||
void clock_sdmmc_config_clock_source(u32 *pout, u32 id, u32 val);
|
void clock_enable_pllc(u32 divn);
|
||||||
void clock_sdmmc_get_params(u32 *pout, u16 *pdivisor, u32 type);
|
void clock_disable_pllc();
|
||||||
|
void clock_sdmmc_config_clock_source(u32 *pclock, u32 id, u32 val);
|
||||||
|
void clock_sdmmc_get_card_clock_div(u32 *pclock, u16 *pdivisor, u32 type);
|
||||||
int clock_sdmmc_is_not_reset_and_enabled(u32 id);
|
int clock_sdmmc_is_not_reset_and_enabled(u32 id);
|
||||||
void clock_sdmmc_enable(u32 id, u32 val);
|
void clock_sdmmc_enable(u32 id, u32 val);
|
||||||
void clock_sdmmc_disable(u32 id);
|
void clock_sdmmc_disable(u32 id);
|
||||||
|
|||||||
@@ -32,18 +32,21 @@ void _cluster_enable_power()
|
|||||||
// Enable cores power.
|
// Enable cores power.
|
||||||
// 1-3.x: MAX77621_NFSR_ENABLE.
|
// 1-3.x: MAX77621_NFSR_ENABLE.
|
||||||
i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_CONTROL1_REG,
|
i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_CONTROL1_REG,
|
||||||
MAX77621_AD_ENABLE | MAX77621_NFSR_ENABLE | MAX77621_SNS_ENABLE);
|
MAX77621_AD_ENABLE | MAX77621_NFSR_ENABLE | MAX77621_SNS_ENABLE | MAX77621_RAMP_12mV_PER_US);
|
||||||
// 1.0.0-3.x: MAX77621_T_JUNCTION_120 | MAX77621_CKKADV_TRIP_DISABLE | MAX77621_INDUCTOR_NOMINAL.
|
// 1.0.0-3.x: MAX77621_T_JUNCTION_120 | MAX77621_CKKADV_TRIP_DISABLE | MAX77621_INDUCTOR_NOMINAL.
|
||||||
i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_CONTROL2_REG,
|
i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_CONTROL2_REG,
|
||||||
MAX77621_T_JUNCTION_120 | MAX77621_WDTMR_ENABLE | MAX77621_CKKADV_TRIP_75mV_PER_US| MAX77621_INDUCTOR_NOMINAL);
|
MAX77621_T_JUNCTION_120 | MAX77621_WDTMR_ENABLE | MAX77621_CKKADV_TRIP_75mV_PER_US| MAX77621_INDUCTOR_NOMINAL);
|
||||||
i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_VOUT_REG, MAX77621_VOUT_ENABLE | 0x37);
|
i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_VOUT_REG, MAX77621_VOUT_ENABLE | MAX77621_VOUT_0_95V);
|
||||||
i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_VOUT_DVC_REG, MAX77621_VOUT_ENABLE | 0x37);
|
i2c_send_byte(I2C_5, MAX77621_CPU_I2C_ADDR, MAX77621_VOUT_DVC_REG, MAX77621_VOUT_ENABLE | MAX77621_VOUT_0_95V);
|
||||||
}
|
}
|
||||||
|
|
||||||
int _cluster_pmc_enable_partition(u32 part, u32 toggle, bool enable)
|
int _cluster_pmc_enable_partition(u32 part, int enable)
|
||||||
{
|
{
|
||||||
// Check if the partition has already been turned on.
|
u32 part_mask = 1 << part;
|
||||||
if (enable && PMC(APBDEV_PMC_PWRGATE_STATUS) & part)
|
u32 desired_state = enable << part;
|
||||||
|
|
||||||
|
// Check if the partition has the state we want.
|
||||||
|
if ((PMC(APBDEV_PMC_PWRGATE_STATUS) & part_mask) == desired_state)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
u32 i = 5001;
|
u32 i = 5001;
|
||||||
@@ -55,12 +58,13 @@ int _cluster_pmc_enable_partition(u32 part, u32 toggle, bool enable)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
PMC(APBDEV_PMC_PWRGATE_TOGGLE) = toggle | (enable ? 0x100 : 0);
|
// Toggle power gating.
|
||||||
|
PMC(APBDEV_PMC_PWRGATE_TOGGLE) = part | 0x100;
|
||||||
|
|
||||||
i = 5001;
|
i = 5001;
|
||||||
while (i > 0)
|
while (i > 0)
|
||||||
{
|
{
|
||||||
if (PMC(APBDEV_PMC_PWRGATE_STATUS) & part)
|
if ((PMC(APBDEV_PMC_PWRGATE_STATUS) & part_mask) == desired_state)
|
||||||
break;
|
break;
|
||||||
usleep(1);
|
usleep(1);
|
||||||
i--;
|
i--;
|
||||||
@@ -76,9 +80,9 @@ void cluster_boot_cpu0(u32 entry)
|
|||||||
|
|
||||||
_cluster_enable_power();
|
_cluster_enable_power();
|
||||||
|
|
||||||
if (!(CLOCK(CLK_RST_CONTROLLER_PLLX_BASE) & 0x40000000))
|
if (!(CLOCK(CLK_RST_CONTROLLER_PLLX_BASE) & 0x40000000)) // PLLX_ENABLE.
|
||||||
{
|
{
|
||||||
CLOCK(CLK_RST_CONTROLLER_PLLX_MISC_3) &= 0xFFFFFFF7;
|
CLOCK(CLK_RST_CONTROLLER_PLLX_MISC_3) &= 0xFFFFFFF7; // Disable IDDQ.
|
||||||
usleep(2);
|
usleep(2);
|
||||||
CLOCK(CLK_RST_CONTROLLER_PLLX_BASE) = 0x80404E02;
|
CLOCK(CLK_RST_CONTROLLER_PLLX_BASE) = 0x80404E02;
|
||||||
CLOCK(CLK_RST_CONTROLLER_PLLX_BASE) = 0x404E02;
|
CLOCK(CLK_RST_CONTROLLER_PLLX_BASE) = 0x404E02;
|
||||||
@@ -103,11 +107,11 @@ void cluster_boot_cpu0(u32 entry)
|
|||||||
CLOCK(CLK_RST_CONTROLLER_CPU_SOFTRST_CTRL2) &= 0xFFFFF000;
|
CLOCK(CLK_RST_CONTROLLER_CPU_SOFTRST_CTRL2) &= 0xFFFFF000;
|
||||||
|
|
||||||
// Enable CPU rail.
|
// Enable CPU rail.
|
||||||
_cluster_pmc_enable_partition(1, 0, true);
|
_cluster_pmc_enable_partition(0, 1);
|
||||||
// Enable cluster 0 non-CPU.
|
// Enable cluster 0 non-CPU.
|
||||||
_cluster_pmc_enable_partition(0x8000, 15, true);
|
_cluster_pmc_enable_partition(15, 1);
|
||||||
// Enable CE0.
|
// Enable CE0.
|
||||||
_cluster_pmc_enable_partition(0x4000, 14, true);
|
_cluster_pmc_enable_partition(14, 1);
|
||||||
|
|
||||||
// Request and wait for RAM repair.
|
// Request and wait for RAM repair.
|
||||||
FLOW_CTLR(FLOW_CTLR_RAM_REPAIR) = 1;
|
FLOW_CTLR(FLOW_CTLR_RAM_REPAIR) = 1;
|
||||||
@@ -117,12 +121,15 @@ void cluster_boot_cpu0(u32 entry)
|
|||||||
EXCP_VEC(EVP_CPU_RESET_VECTOR) = 0;
|
EXCP_VEC(EVP_CPU_RESET_VECTOR) = 0;
|
||||||
|
|
||||||
// Set reset vector.
|
// Set reset vector.
|
||||||
SB(SB_AA64_RESET_LOW) = entry | 1;
|
SB(SB_AA64_RESET_LOW) = entry | SB_AA64_RST_AARCH64_MODE_EN;
|
||||||
SB(SB_AA64_RESET_HIGH) = 0;
|
SB(SB_AA64_RESET_HIGH) = 0;
|
||||||
// Non-secure reset vector write disable.
|
// Non-secure reset vector write disable.
|
||||||
SB(SB_CSR) = 2;
|
SB(SB_CSR) = SB_CSR_NS_RST_VEC_WR_DIS;
|
||||||
(void)SB(SB_CSR);
|
(void)SB(SB_CSR);
|
||||||
|
|
||||||
|
// Tighten up the security aperture.
|
||||||
|
// MC(MC_TZ_SECURITY_CTRL) = 1;
|
||||||
|
|
||||||
// Clear MSELECT reset.
|
// Clear MSELECT reset.
|
||||||
CLOCK(CLK_RST_CONTROLLER_RST_DEVICES_V) &= 0xFFFFFFF7;
|
CLOCK(CLK_RST_CONTROLLER_RST_DEVICES_V) &= 0xFFFFFFF7;
|
||||||
// Clear NONCPU reset.
|
// Clear NONCPU reset.
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user