Compare commits
115 Commits
6.5.1
...
hekate_hos
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e2968c69dc | ||
|
|
bc42579f01 | ||
|
|
335b8b9a94 | ||
|
|
e1e2366684 | ||
|
|
b0690a7280 | ||
|
|
7f0835a548 | ||
|
|
5704004bc8 | ||
|
|
c7e1f5c09f | ||
|
|
50170f7cf2 | ||
|
|
52dba9a5a5 | ||
|
|
db519a454b | ||
|
|
f8436d1247 | ||
|
|
6340881f59 | ||
|
|
8405a86937 | ||
|
|
a3f5e33625 | ||
|
|
cfc2febc1b | ||
|
|
d6fda80057 | ||
|
|
37c8874930 | ||
|
|
37a016122c | ||
|
|
9b95d026f3 | ||
|
|
865b9dc1a4 | ||
|
|
7ebceb78bd | ||
|
|
154ed594fc | ||
|
|
af39c76b3a | ||
|
|
657b895aaf | ||
|
|
52a1e0ba67 | ||
|
|
f3b104e234 | ||
|
|
a5a2235b9d | ||
|
|
4c58708253 | ||
|
|
cbac787cff | ||
|
|
082490deda | ||
|
|
72b0f42514 | ||
|
|
8978ba9e54 | ||
|
|
74833e19e7 | ||
|
|
d5d0f79c38 | ||
|
|
7927cfe818 | ||
|
|
a1f48e858e | ||
|
|
fa561b70a4 | ||
|
|
567f0f66e1 | ||
|
|
b798dd1ef6 | ||
|
|
c91cf80f8b | ||
|
|
dca5df653b | ||
|
|
db08fab876 | ||
|
|
9adca44fe4 | ||
|
|
c202b4afb1 | ||
|
|
814ef14f2d | ||
|
|
eaedec7b6e | ||
|
|
e8addedd2f | ||
|
|
3c6bb75267 | ||
|
|
169c551445 | ||
|
|
7dad628dfc | ||
|
|
8ba90ae55f | ||
|
|
fe61c1a374 | ||
|
|
3412714402 | ||
|
|
2b0591e2b0 | ||
|
|
03b30a23c4 | ||
|
|
4f0bba605f | ||
|
|
4cfbef5062 | ||
|
|
02281fccf1 | ||
|
|
84078e5469 | ||
|
|
805686105d | ||
|
|
eacb4f2844 | ||
|
|
c8da71229a | ||
|
|
1a157a33f6 | ||
|
|
f093c9368b | ||
|
|
9a755b895b | ||
|
|
4c4a63795e | ||
|
|
04dc8d2a86 | ||
|
|
ed4b638545 | ||
|
|
a8a67ee775 | ||
|
|
1e54d538fd | ||
|
|
20487cb8b9 | ||
|
|
8bc14f1043 | ||
|
|
c8acea7ad5 | ||
|
|
3ea4fd81f7 | ||
|
|
76508c74e8 | ||
|
|
79b6df64d6 | ||
|
|
0a7a004839 | ||
|
|
7521055bec | ||
|
|
39d99a77fe | ||
|
|
b0f0e9be47 | ||
|
|
55a4a814e0 | ||
|
|
4bfe1fe2cd | ||
|
|
6d09e65d85 | ||
|
|
59a173c994 | ||
|
|
e5ceb4a2de | ||
|
|
ea3dae672e | ||
|
|
2af1cc0b8c | ||
|
|
942e7defe3 | ||
|
|
39b74dd50d | ||
|
|
bbe8ddaf66 | ||
|
|
47e030c7fc | ||
|
|
4a127db80b | ||
|
|
241b0f2274 | ||
|
|
ba6073610c | ||
|
|
70cb99cd0c | ||
|
|
7941a3d4d6 | ||
|
|
1ddf9690b1 | ||
|
|
f4d8ee4efc | ||
|
|
4f72660603 | ||
|
|
2440318cb5 | ||
|
|
61e91f79c1 | ||
|
|
bad8566c58 | ||
|
|
28796b417b | ||
|
|
31c8ad0d88 | ||
|
|
0be3fd4f64 | ||
|
|
3e9def3608 | ||
|
|
678ce79a54 | ||
|
|
b11e8095ed | ||
|
|
849d533200 | ||
|
|
337f219ac6 | ||
|
|
4e9e21b3b1 | ||
|
|
fe5e4dc40a | ||
|
|
5798dcde0d | ||
|
|
9d2ec42a9f |
27
Makefile
27
Makefile
@@ -35,9 +35,9 @@ OBJS += $(addprefix $(BUILDDIR)/$(TARGET)/, \
|
||||
mc.o sdram.o minerva.o \
|
||||
gpio.o pinmux.o pmc.o se.o smmu.o tsec.o uart.o \
|
||||
fuse.o kfuse.o \
|
||||
sdmmc.o sdmmc_driver.o emmc.o sd.o emummc.o \
|
||||
sdmmc.o sdmmc_driver.o emmc.o sd.o emummc.o emummc_file_based.o emusd.o \
|
||||
bq24193.o max17050.o max7762x.o max77620-rtc.o \
|
||||
hw_init.o \
|
||||
hw_init.o boot_storage.o emusd.o file_based_storage.o \
|
||||
)
|
||||
|
||||
# Utilities.
|
||||
@@ -48,7 +48,7 @@ OBJS += $(addprefix $(BUILDDIR)/$(TARGET)/, \
|
||||
|
||||
# Horizon.
|
||||
OBJS += $(addprefix $(BUILDDIR)/$(TARGET)/, \
|
||||
hos.o hos_config.o pkg1.o pkg2.o pkg2_ini_kippatch.o fss.o secmon_exo.o \
|
||||
hos.o hos_config.o pkg1.o pkg2.o pkg3.o pkg2_ini_kippatch.o secmon_exo.o \
|
||||
)
|
||||
|
||||
# Libraries.
|
||||
@@ -76,15 +76,15 @@ CUSTOMDEFINES += -DGFX_INC=$(GFX_INC) -DFFCFG_INC=$(FFCFG_INC)
|
||||
|
||||
# UART Logging: Max baudrate 12.5M.
|
||||
# DEBUG_UART_PORT - 0: UART_A, 1: UART_B, 2: UART_C.
|
||||
#CUSTOMDEFINES += -DDEBUG_UART_BAUDRATE=115200 -DDEBUG_UART_INVERT=0 -DDEBUG_UART_PORT=0
|
||||
#CUSTOMDEFINES += -DDEBUG_UART_BAUDRATE=115200 -DDEBUG_UART_INVERT=0 -DDEBUG_UART_PORT=1
|
||||
|
||||
#TODO: Considering reinstating some of these when pointer warnings have been fixed.
|
||||
WARNINGS := -Wall -Wsign-compare -Wno-array-bounds -Wno-stringop-overread -Wno-stringop-overflow
|
||||
WARNINGS := -Wall -Wsign-compare -Wtype-limits -Wno-array-bounds -Wno-stringop-overread -Wno-stringop-overflow
|
||||
#-fno-delete-null-pointer-checks
|
||||
#-Wstack-usage=byte-size -fstack-usage
|
||||
|
||||
ARCH := -march=armv4t -mtune=arm7tdmi -mthumb -mthumb-interwork
|
||||
CFLAGS = $(ARCH) -O2 -g -gdwarf-4 -nostdlib -ffunction-sections -fdata-sections -fomit-frame-pointer -fno-inline -std=gnu11 $(WARNINGS) $(CUSTOMDEFINES)
|
||||
ARCH := -march=armv4t -mtune=arm7tdmi -mthumb -mthumb-interwork $(WARNINGS)
|
||||
CFLAGS = $(ARCH) -O2 -g -gdwarf-4 -nostdlib -ffunction-sections -fdata-sections -fomit-frame-pointer -fno-inline -std=gnu11 $(CUSTOMDEFINES)
|
||||
LDFLAGS = $(ARCH) -nostartfiles -lgcc -Wl,--nmagic,--gc-sections -Xlinker --defsym=IPL_LOAD_ADDR=$(IPL_LOAD_ADDR)
|
||||
|
||||
MODULEDIRS := $(wildcard modules/*)
|
||||
@@ -101,15 +101,14 @@ TOOLS := $(TOOLSLZ) $(TOOLSB2C)
|
||||
all: $(TARGET).bin $(LDRDIR)
|
||||
@printf ICTC49 >> $(OUTPUTDIR)/$(TARGET).bin
|
||||
@echo "--------------------------------------"
|
||||
@echo -n "Uncompr size: "
|
||||
@echo "$(TARGET) size:"
|
||||
@echo -n "Uncompr: "
|
||||
$(eval BIN_SIZE = $(shell wc -c < $(OUTPUTDIR)/$(TARGET)_unc.bin))
|
||||
@echo $(BIN_SIZE)" Bytes"
|
||||
@echo "Uncompr Max: 140288 Bytes + 3 KiB BSS"
|
||||
@if [ ${BIN_SIZE} -gt 140288 ]; then echo "\e[1;33mUncompr size exceeds limit!\e[0m"; fi
|
||||
@echo -n "Payload size: "
|
||||
@echo -n "Payload: "
|
||||
$(eval BIN_SIZE = $(shell wc -c < $(OUTPUTDIR)/$(TARGET).bin))
|
||||
@echo $(BIN_SIZE)" Bytes"
|
||||
@echo "Payload Max: 126296 Bytes"
|
||||
@if [ ${BIN_SIZE} -gt 126296 ]; then echo "\e[1;33mPayload size exceeds limit!\e[0m"; fi
|
||||
@echo "--------------------------------------"
|
||||
|
||||
@@ -126,7 +125,7 @@ $(NYXDIR):
|
||||
|
||||
$(LDRDIR): $(TARGET).bin
|
||||
@$(TOOLSLZ)/lz77 $(OUTPUTDIR)/$(TARGET).bin
|
||||
mv $(OUTPUTDIR)/$(TARGET).bin $(OUTPUTDIR)/$(TARGET)_unc.bin
|
||||
@mv $(OUTPUTDIR)/$(TARGET).bin $(OUTPUTDIR)/$(TARGET)_unc.bin
|
||||
@mv $(OUTPUTDIR)/$(TARGET).bin.00.lz payload_00
|
||||
@mv $(OUTPUTDIR)/$(TARGET).bin.01.lz payload_01
|
||||
@$(TOOLSB2C)/bin2c payload_00 > $(LDRDIR)/payload_00.h
|
||||
@@ -139,11 +138,11 @@ $(TOOLS):
|
||||
@$(MAKE) --no-print-directory -C $@ $(MAKECMDGOALS) -$(MAKEFLAGS)
|
||||
|
||||
$(TARGET).bin: $(BUILDDIR)/$(TARGET)/$(TARGET).elf $(MODULEDIRS) $(NYXDIR) $(TOOLS)
|
||||
$(OBJCOPY) -S -O binary $< $(OUTPUTDIR)/$@
|
||||
@$(OBJCOPY) -S -O binary $< $(OUTPUTDIR)/$@
|
||||
|
||||
$(BUILDDIR)/$(TARGET)/$(TARGET).elf: $(OBJS)
|
||||
@$(CC) $(LDFLAGS) -T $(SOURCEDIR)/link.ld $^ -o $@
|
||||
@echo "hekate was built with the following flags:\nCFLAGS: "$(CFLAGS)"\nLDFLAGS: "$(LDFLAGS)
|
||||
@printf "$(TARGET) was built with the following flags:\nCFLAGS: $(CFLAGS)\nLDFLAGS: $(LDFLAGS)\n"
|
||||
|
||||
$(BUILDDIR)/$(TARGET)/%.o: %.c
|
||||
@echo Building $@
|
||||
|
||||
46
README.md
46
README.md
@@ -50,13 +50,14 @@ Custom Graphical Nintendo Switch bootloader, firmware patcher, tools, and many m
|
||||
| \|__ background.bmp | Nyx - Custom background. User provided. |
|
||||
| \|__ icon_switch.bmp | Nyx - Default icon for CFWs. |
|
||||
| \|__ icon_payload.bmp | Nyx - Default icon for Payloads. |
|
||||
| bootloader/sys/ | hekate and Nyx system modules folder. |
|
||||
| \|__ emummc.kipm | emuMMC KIP1 module. !Important! |
|
||||
| \|__ libsys_lp0.bso | LP0 (sleep mode) module. Important! |
|
||||
| \|__ libsys_minerva.bso | Minerva Training Cell. Used for DRAM Frequency training. !Important! |
|
||||
| \|__ nyx.bin | Nyx - hekate's GUI. !Important! |
|
||||
| \|__ res.pak | Nyx resources package. !Important! |
|
||||
| \|__ thk.bin | Atmosphère Tsec Hovi Keygen. !Important! |
|
||||
| bootloader/sys/ | hekate and Nyx system modules folder. !Important! |
|
||||
| \|__ emummc.kipm | emuMMC KIP1 module. |
|
||||
| \|__ libsys_lp0.bso | LP0 (sleep mode) module. |
|
||||
| \|__ libsys_minerva.bso | Minerva Training Cell. Used for DRAM Frequency training. |
|
||||
| \|__ nyx.bin | Nyx - hekate's GUI. |
|
||||
| \|__ res.pak | Nyx resources package. |
|
||||
| \|__ thk.bin | Atmosphère Tsec Hovi Keygen. |
|
||||
| \|__ /l4t/ | Folder with firmware relevant to L4T (Linux/Android). |
|
||||
| bootloader/screenshots/ | Folder where Nyx screenshots are saved |
|
||||
| bootloader/payloads/ | For the `Payloads` menu. All CFW bootloaders, tools, Linux payloads are supported. Autoboot only supported by including them into an ini. |
|
||||
| bootloader/libtools/ | Reserved |
|
||||
@@ -76,9 +77,9 @@ There are four possible type of entries. "**[ ]**": Boot entry, "**{ }**": Capti
|
||||
|
||||
### hekate Global Configuration keys/values (when entry is *[config]*):
|
||||
|
||||
| Config option | Description |
|
||||
| ------------------ | ---------------------------------------------------------- |
|
||||
| autoboot=0 | 0: Disable, #: Boot entry number to auto boot. |
|
||||
| Config option | Description |
|
||||
| ------------------ | -------------------------------------------------------------- |
|
||||
| autoboot=0 | 0: Disable, #: Boot entry number to auto boot. |
|
||||
| autoboot_list=0 | 0: Read `autoboot` boot entry from hekate_ipl.ini, 1: Read from ini folder (ini files are ASCII ordered). |
|
||||
| bootwait=3 | 0: Disable (It also disables bootlogo. Having **VOL-** pressed since injection goes to menu.), #: Time to wait for **VOL-** to enter menu. Max: 20s. |
|
||||
| noticker=0 | 0: Animated line is drawn during custom bootlogo, signifying time left to skip to menu. 1: Disable. |
|
||||
@@ -86,7 +87,7 @@ There are four possible type of entries. "**[ ]**": Boot entry, "**{ }**": Capti
|
||||
| autonogc=1 | 0: Disable, 1: Automatically applies nogc patch if unburnt fuses found and a >= 4.0.0 HOS is booted. |
|
||||
| bootprotect=0 | 0: Disable, 1: Protect bootloader folder from being corrupted by disallowing reading or editing in HOS. |
|
||||
| updater2p=0 | 0: Disable, 1: Force updates (if needed) the reboot2payload binary to be hekate. |
|
||||
| backlight=100 | Screen backlight level. 0-255. |
|
||||
| backlight=100 | Screen backlight level. 0-255. |
|
||||
|
||||
|
||||
### Boot entry key/value combinations:
|
||||
@@ -98,18 +99,20 @@ There are four possible type of entries. "**[ ]**": Boot entry, "**{ }**": Capti
|
||||
| kernel={FILE path} | Replaces the kernel binary |
|
||||
| kip1={FILE path} | Replaces/Adds kernel initial process. Multiple can be set. |
|
||||
| kip1={FOLDER path}/* | Loads every .kip/.kip1 inside a folder. Compatible with single kip1 keys. |
|
||||
| fss0={FILE path} | Takes an Atmosphere `package3` binary (formerly fusee-secondary.bin) and `extracts` all needed parts from it. kips, exosphere, warmboot and mesophere if enabled. |
|
||||
| fss0experimental=1 | Enables loading of experimental content from a FSS0 storage |
|
||||
| pkg3={FILE path} | Takes an Atmosphere `package3` binary and `extracts` all needed parts from it. kips, exosphere, warmboot and mesophere. |
|
||||
| fss0={FILE path} | Same as above. !Deprecated! |
|
||||
| pkg3ex=1 | Enables loading of experimental content from a PKG3/FSS0 storage |
|
||||
| pkg3kip1skip={KIP name} | Skips loading a kip from `pkg3`/`fss0`. Allows multiple and `,` as separator. The name must exactly match the name in `PKG3`. |
|
||||
| exofatal={FILE path} | Replaces the exosphere fatal binary for Mariko |
|
||||
| ---------------------- | ---------------------------------------------------------- |
|
||||
| kip1patch=patchname | Enables a kip1 patch. Specify with multiple lines and/or in one line with `,` as separator. If actual patch is not found, a warning will show up |
|
||||
| kip1patch=patchname | Enables a kip1 patch. Allows multiple and `,` as separator. If actual patch is not found, a warning will show up. |
|
||||
| emupath={FOLDER path} | Forces emuMMC to use the selected one. (=emuMMC/RAW1, =emuMMC/SD00, etc). emuMMC must be created by hekate because it uses the raw_based/file_based files. |
|
||||
| emummcforce=1 | Forces the use of emuMMC. If emummc.ini is disabled or not found, then it causes an error. |
|
||||
| emummc_force_disable=1 | Disables emuMMC, if it's enabled. |
|
||||
| stock=1 | OFW via hekate bootloader. Disables unneeded kernel patching and CFW kips when running stock. `If emuMMC is enabled, emummc_force_disable=1` is required. emuMMC is not supported on stock. If additional KIPs are needed other than OFW's, you can define them with `kip1` key. No kip should be used that relies on Atmosphère patching, because it will hang. If `NOGC` is needed, use `kip1patch=nogc`. |
|
||||
| fullsvcperm=1 | Disables SVC verification (full services permission). Doesn't work with Mesosphere as kernel. |
|
||||
| debugmode=1 | Enables Debug mode. Obsolete when used with exosphere as secmon. |
|
||||
| atmosphere=1 | Enables Atmosphère patching. Not needed when `fss0` is used. |
|
||||
| kernelprocid=1 | Enables stock kernel process id send/recv patching. Not needed when `pkg3`/`fss0` is used. |
|
||||
| ---------------------- | ---------------------------------------------------------- |
|
||||
| payload={FILE path} | Payload launching. Tools, Android/Linux, CFW bootloaders, etc. Any key above when used with that, doesn't get into account. |
|
||||
| ---------------------- | ---------------------------------------------------------- |
|
||||
@@ -119,6 +122,7 @@ There are four possible type of entries. "**[ ]**": Boot entry, "**{ }**": Capti
|
||||
| ram_oc_vdd2=1100 | L4T RAM VDD2 Voltage. Set VDD2 (T210B01) or VDD2/VDDQ (T210) voltage. 1050-1175. |
|
||||
| ram_oc_vddq=600 | L4T RAM VDDQ Voltage. Set VDDQ (T210B01). 550-650. |
|
||||
| uart_port=0 | Enables logging on serial port for L4T uboot/kernel. |
|
||||
| sld_type=0x31444C53 | Controls the type of seamless display support. 0x0: Disable, 0x31444C53: L4T seamless display. |
|
||||
| Additional keys | Each distro supports more keys. Check README_CONFIG.txt for more info. |
|
||||
| ---------------------- | ---------------------------------------------------------- |
|
||||
| bootwait=3 | Overrides global bootwait from `[config]`. |
|
||||
@@ -129,11 +133,11 @@ There are four possible type of entries. "**[ ]**": Boot entry, "**{ }**": Capti
|
||||
|
||||
**Note1**: When using the wildcard (`/*`) with `kip1` you can still use the normal `kip1` after that to load extra single kips.
|
||||
|
||||
**Note2**: When using FSS0 it parses exosphere, warmboot and all core kips. You can override the first 2 by using `secmon`/`warmboot` after defining `fss0`.
|
||||
**Note2**: When using PKG3/FSS0 it parses exosphere, warmboot and all core kips. You can override the first 2 by using `secmon`/`warmboot` after defining `pkg3`/`fss0`.
|
||||
You can define `kip1` to load an extra kip or many via the wildcard (`/*`) usage.
|
||||
|
||||
**Warning**: Careful when you define *fss0 core* kips when using `fss0` or the folder (when using `/*`) includes them.
|
||||
This is in case the kips are incompatible between them. If compatible, you can override `fss0` kips with no issues (useful for testing with intermediate kip changes). In such cases, the `kip1` line must be under `fss0` line.
|
||||
**Warning**: Careful when you override *pkg3/fss core* kips with `kip1`.
|
||||
That's in case the kips are incompatible between them. If compatible, you can override `pkg3`/`fss0` kips with no issues (useful for testing with intermediate kip changes). In such cases, the `kip1` line must be **after** `pkg3`/`fss0` line.
|
||||
|
||||
|
||||
### Boot entry key/value combinations for Exosphère:
|
||||
@@ -155,7 +159,7 @@ This is in case the kips are incompatible between them. If compatible, you can o
|
||||
|
||||
### Payload storage:
|
||||
|
||||
hekate has a boot storage in the binary that helps it configure it outside of BPMP enviroment:
|
||||
hekate has a boot storage in the binary that helps it configure it outside of BPMP environment:
|
||||
|
||||
| Offset / Name | Description |
|
||||
| ----------------------- | ----------------------------------------------------------------- |
|
||||
@@ -188,9 +192,9 @@ hekate has a boot storage in the binary that helps it configure it outside of BP
|
||||
|
||||
```
|
||||
hekate (c) 2018, naehrwert, st4rk.
|
||||
(c) 2018-2024, CTCaer.
|
||||
(c) 2018-2025, CTCaer.
|
||||
|
||||
Nyx GUI (c) 2019-2024, CTCaer.
|
||||
Nyx GUI (c) 2019-2025, CTCaer.
|
||||
|
||||
Thanks to: derrek, nedwill, plutoo, shuffle2, smea, thexyz, yellows8.
|
||||
Greetings to: fincs, hexkyz, SciresM, Shiny Quagsire, WinterMute.
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
# IPL Version.
|
||||
BLVERSION_MAJOR := 6
|
||||
BLVERSION_MINOR := 2
|
||||
BLVERSION_HOTFX := 2
|
||||
BLVERSION_MINOR := 3
|
||||
BLVERSION_HOTFX := 1
|
||||
BLVERSION_REL := 0
|
||||
|
||||
# Nyx Version.
|
||||
NYXVERSION_MAJOR := 1
|
||||
NYXVERSION_MINOR := 6
|
||||
NYXVERSION_HOTFX := 4
|
||||
NYXVERSION_MINOR := 7
|
||||
NYXVERSION_HOTFX := 0
|
||||
NYXVERSION_REL := 0
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (c) 2018-2024 CTCaer
|
||||
* Copyright (c) 2018-2025 CTCaer
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
@@ -37,8 +37,8 @@
|
||||
extern volatile nyx_storage_t *nyx_str;
|
||||
|
||||
static u32 _display_id = 0;
|
||||
static u32 _dsi_bl = -1;
|
||||
static bool _nx_aula = false;
|
||||
static u32 _dsi_bl = -1;
|
||||
static bool _nx_aula = false;
|
||||
|
||||
static void _display_panel_and_hw_end(bool no_panel_deinit);
|
||||
|
||||
@@ -265,16 +265,9 @@ int display_dsi_vblank_read(u8 cmd, u32 len, void *data)
|
||||
|
||||
void display_dsi_write(u8 cmd, u32 len, void *data)
|
||||
{
|
||||
static u8 *fifo8 = NULL;
|
||||
static u32 *fifo32 = NULL;
|
||||
u32 host_control;
|
||||
|
||||
// Allocate fifo buffer.
|
||||
if (!fifo32)
|
||||
{
|
||||
fifo32 = malloc(DSI_STATUS_RX_FIFO_SIZE * 8 * sizeof(u32));
|
||||
fifo8 = (u8 *)fifo32;
|
||||
}
|
||||
u32 fifo32[DSI_STATUS_TX_FIFO_SIZE] = {0};
|
||||
u8 *fifo8 = (u8 *)fifo32;
|
||||
|
||||
// Prepare data for long write.
|
||||
if (len >= 2)
|
||||
@@ -319,15 +312,8 @@ void display_dsi_write(u8 cmd, u32 len, void *data)
|
||||
|
||||
void display_dsi_vblank_write(u8 cmd, u32 len, void *data)
|
||||
{
|
||||
static u8 *fifo8 = NULL;
|
||||
static u32 *fifo32 = NULL;
|
||||
|
||||
// Allocate fifo buffer.
|
||||
if (!fifo32)
|
||||
{
|
||||
fifo32 = malloc(DSI_STATUS_RX_FIFO_SIZE * 8 * sizeof(u32));
|
||||
fifo8 = (u8 *)fifo32;
|
||||
}
|
||||
u32 fifo32[DSI_STATUS_TX_FIFO_SIZE] = {0};
|
||||
u8 *fifo8 = (u8 *)fifo32;
|
||||
|
||||
// Prepare data for long write.
|
||||
if (len >= 2)
|
||||
@@ -571,7 +557,7 @@ void display_init()
|
||||
* When switching to the 16ff pad brick, the clock lane termination control
|
||||
* is separated from data lane termination. This change of the mipi cal
|
||||
* brings in a bug that the DSI pad clock termination code can't be loaded
|
||||
* in one time calibration. Trigger calibration twice.
|
||||
* in one time calibration on T210B01. Trigger calibration twice.
|
||||
*/
|
||||
reg_write_array((u32 *)MIPI_CAL_BASE, _di_mipi_pad_cal_config, ARRAY_SIZE(_di_mipi_pad_cal_config));
|
||||
for (u32 i = 0; i < 2; i++)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (c) 2018-2024 CTCaer
|
||||
* Copyright (c) 2018-2025 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,
|
||||
@@ -520,6 +520,7 @@
|
||||
|
||||
#define DSI_STATUS 0x15
|
||||
#define DSI_STATUS_RX_FIFO_SIZE 0x1F
|
||||
#define DSI_STATUS_TX_FIFO_SIZE 0x20 // Actual depth is 64.
|
||||
|
||||
#define DSI_INIT_SEQ_CONTROL 0x1A
|
||||
#define DSI_INIT_SEQ_DATA_0 0x1B
|
||||
@@ -717,7 +718,7 @@
|
||||
#define MIPI_DCS_READ_DDB_CONTINUE 0xA8 // 0x100 size.
|
||||
|
||||
/*! MIPI DCS Panel Private CMDs. */
|
||||
#define MIPI_DCS_PRIV_SM_SET_COLOR_MODE 0xA0
|
||||
#define MIPI_DCS_PRIV_SM_SET_COLOR_MODE 0xA0 // 43 bytes.
|
||||
#define MIPI_DCS_PRIV_SM_SET_REG_OFFSET 0xB0
|
||||
#define MIPI_DCS_PRIV_SM_SET_ELVSS 0xB1 // OLED backlight tuning. Byte7: PWM transition time in frames.
|
||||
#define MIPI_DCS_PRIV_SET_POWER_CONTROL 0xB1
|
||||
@@ -727,6 +728,7 @@
|
||||
#define MIPI_DCS_PRIV_UNK_D6 0xD6
|
||||
#define MIPI_DCS_PRIV_UNK_D8 0xD8
|
||||
#define MIPI_DCS_PRIV_UNK_D9 0xD9
|
||||
#define MIPI_DCS_PRIV_SM_DISPLAY_ID 0xDD
|
||||
// LVL1 LVL2 LVL3 UNK0 UNK1
|
||||
#define MIPI_DCS_PRIV_SM_SET_REGS_LOCK 0xE2 // Samsung: Lock (default): 5A5A A5A5 A5A5 A500 A500. Unlock: A5A5 5A5A 5A5A UNK UNK.
|
||||
#define MIPI_DCS_PRIV_READ_EXTC_CMD_SPI 0xFE // Read EXTC Command In SPI. 1 byte. 0-6: EXT_SPI_CNT, 7:EXT_SP.
|
||||
@@ -765,19 +767,21 @@
|
||||
|
||||
#define DCS_CONTROL_DISPLAY_SM_FLASHLIGHT BIT(2)
|
||||
#define DCS_CONTROL_DISPLAY_BACKLIGHT_CTRL BIT(2)
|
||||
#define DCS_CONTROL_DISPLAY_DIMMING_CTRL BIT(3)
|
||||
#define DCS_CONTROL_DISPLAY_DIMMING_CTRL BIT(3) // Transition fading.
|
||||
#define DCS_CONTROL_DISPLAY_BRIGHTNESS_CTRL BIT(5)
|
||||
#define DCS_CONTROL_DISPLAY_HBM_CTRL0 BIT(6)
|
||||
#define DCS_CONTROL_DISPLAY_HBM_CTRL1 BIT(7)
|
||||
|
||||
#define DCS_SM_COLOR_MODE_SATURATED 0x00 // Disabled. Similar to vivid but over-saturated. Wide gamut?
|
||||
#define DCS_SM_COLOR_MODE_SATURATED 0x00 // Disabled. Based on Vivid but over-saturated.
|
||||
#define DCS_SM_COLOR_MODE_WASHED 0x45
|
||||
#define DCS_SM_COLOR_MODE_BASIC 0x03
|
||||
#define DCS_SM_COLOR_MODE_BASIC 0x03 // Real natural profile.
|
||||
#define DCS_SM_COLOR_MODE_POR_RESET 0x20 // Reset value on power on.
|
||||
#define DCS_SM_COLOR_MODE_NATURAL 0x23 // Not actually natural..
|
||||
#define DCS_SM_COLOR_MODE_VIVID 0x65
|
||||
#define DCS_SM_COLOR_MODE_NIGHT0 0x43 // Based on washed out.
|
||||
#define DCS_SM_COLOR_MODE_NIGHT1 0x15 // Based on basic.
|
||||
#define DCS_SM_COLOR_MODE_NIGHT2 0x35 // Based on natural.
|
||||
#define DCS_SM_COLOR_MODE_NIGHT3 0x75 // Based on vivid.
|
||||
#define DCS_SM_COLOR_MODE_NATURAL 0x23 // Not actually natural.. Extra saturation.
|
||||
#define DCS_SM_COLOR_MODE_VIVID 0x65 // Saturated.
|
||||
#define DCS_SM_COLOR_MODE_NIGHT0 0x43 // Based on Washed Out.
|
||||
#define DCS_SM_COLOR_MODE_NIGHT1 0x15 // Based on Basic.
|
||||
#define DCS_SM_COLOR_MODE_NIGHT2 0x35 // Based on Natural.
|
||||
#define DCS_SM_COLOR_MODE_NIGHT3 0x75 // Based on Vivid.
|
||||
|
||||
#define DCS_SM_COLOR_MODE_ENABLE BIT(0)
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <storage/boot_storage.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "ianos.h"
|
||||
@@ -75,7 +76,7 @@ uintptr_t ianos_loader(char *path, elfType_t type, void *moduleConfig)
|
||||
uintptr_t epaddr = 0;
|
||||
|
||||
// Read library.
|
||||
fileBuf = sd_file_read(path, NULL);
|
||||
fileBuf = boot_storage_file_read(path, NULL);
|
||||
|
||||
if (!fileBuf)
|
||||
goto out;
|
||||
|
||||
@@ -70,8 +70,6 @@ void set_als_cfg(als_ctxt_t *als_ctxt, u8 gain, u8 cycle)
|
||||
|
||||
if (!cycle)
|
||||
cycle = 1;
|
||||
else if (cycle > 255)
|
||||
cycle = 255;
|
||||
|
||||
i2c_send_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(BH1730_GAIN_REG), gain);
|
||||
i2c_send_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(BH1730_TIMING_REG), (256 - cycle));
|
||||
|
||||
@@ -10,6 +10,7 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
#include <utils/types.h>
|
||||
#include <fatfs_cfg.h>
|
||||
|
||||
/* Status of Disk Functions */
|
||||
typedef BYTE DSTATUS;
|
||||
@@ -23,14 +24,6 @@ typedef enum {
|
||||
RES_PARERR /* 4: Invalid Parameter */
|
||||
} DRESULT;
|
||||
|
||||
typedef enum {
|
||||
DRIVE_SD = 0,
|
||||
DRIVE_RAM = 1,
|
||||
DRIVE_EMMC = 2,
|
||||
DRIVE_BIS = 3,
|
||||
DRIVE_EMU = 4
|
||||
} DDRIVE;
|
||||
|
||||
|
||||
/*---------------------------------------*/
|
||||
/* Prototypes for disk control functions */
|
||||
|
||||
@@ -41,8 +41,8 @@
|
||||
#include <storage/mbr_gpt.h>
|
||||
#include <gfx_utils.h>
|
||||
|
||||
#define EFSPRINTF(text, ...) print_error(); gfx_printf("%k"text"%k\n", 0xFFFFFF00, 0xFFFFFFFF);
|
||||
//#define EFSPRINTF(...)
|
||||
// #define EFSPRINTF(text, ...) print_error(); gfx_printf("%k"text"%k\n", 0xFFFFFF00, 0xFFFFFFFF);
|
||||
#define EFSPRINTF(...)
|
||||
|
||||
/*--------------------------------------------------------------------------
|
||||
|
||||
@@ -473,6 +473,10 @@ static const char* const VolumeStr[FF_VOLUMES] = {FF_VOLUME_STRS}; /* Pre-define
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if FF_SIMPLE_GPT
|
||||
static const BYTE GUID_MS_Basic[16] = {0xA2,0xA0,0xD0,0xEB,0xE5,0xB9,0x33,0x44,0x87,0xC0,0x68,0xB6,0xB7,0x26,0x99,0xC7};
|
||||
#endif
|
||||
|
||||
|
||||
/*--------------------------------*/
|
||||
/* LFN/Directory working buffer */
|
||||
@@ -3319,15 +3323,28 @@ static FRESULT find_volume ( /* FR_OK(0): successful, !=0: an error occurred */
|
||||
}
|
||||
#if FF_SIMPLE_GPT
|
||||
if (fmt >= 2) {
|
||||
/* If GPT Check the first partition */
|
||||
/* If GPT, iterate over all part entries and check MS Basic partitions */
|
||||
gpt_header_t *gpt_header = (gpt_header_t *)fs->win;
|
||||
if (move_window(fs, 1) != FR_OK) return FR_DISK_ERR;
|
||||
if (!mem_cmp(&gpt_header->signature, "EFI PART", 8)) {
|
||||
if (move_window(fs, gpt_header->part_ent_lba) != FR_OK) return FR_DISK_ERR;
|
||||
gpt_entry_t *gpt_entry = (gpt_entry_t *)fs->win;
|
||||
fs->part_type = 1;
|
||||
bsect = gpt_entry->lba_start;
|
||||
fmt = bsect ? check_fs(fs, bsect) : 3; /* Check the partition */
|
||||
DWORD cur_entry, ofs, part;
|
||||
part = LD2PT(vol);
|
||||
cur_entry = 0;
|
||||
for(i = 0; i < gpt_header->num_part_ents; i++){
|
||||
if (move_window(fs, gpt_header->part_ent_lba + i * sizeof(gpt_entry_t) / SS(fs))) return FR_DISK_ERR;
|
||||
ofs = i * sizeof(gpt_entry_t) % SS(fs);
|
||||
gpt_entry_t *gpt_entry = (gpt_entry_t *)fs->win + ofs;
|
||||
if (!mem_cmp(gpt_entry->type_guid, GUID_MS_Basic, 16)){
|
||||
cur_entry++;
|
||||
bsect = gpt_entry->lba_start;
|
||||
fmt = bsect ? check_fs(fs, bsect) : 3;
|
||||
if(part == 0 && fmt <= 1) break;
|
||||
if(part != 0 && cur_entry == part) break;
|
||||
}
|
||||
}
|
||||
if(part && part != cur_entry){
|
||||
fmt = 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -4698,13 +4715,20 @@ FRESULT f_lseek (
|
||||
|
||||
DWORD *f_expand_cltbl (
|
||||
FIL* fp, /* Pointer to the file object */
|
||||
UINT tblsz, /* Size of table */
|
||||
UINT tblsz, /* Size of table (2 DWORDs + 2 DWORDs per fragment) */
|
||||
FSIZE_t ofs /* File pointer from top of file */
|
||||
)
|
||||
{
|
||||
/*
|
||||
* Cluster table structure:
|
||||
* Size (DWORD)
|
||||
* Padding (DWORD)
|
||||
* (Cluster Offset (DWORD) + Sequential clusters (DWORD)) * Fragments
|
||||
*/
|
||||
if (fp->flag & FA_WRITE) f_lseek(fp, ofs); /* Expand file if write is enabled */
|
||||
if (!fp->cltbl) { /* Allocate memory for cluster link table */
|
||||
fp->cltbl = (DWORD *)ff_memalloc(tblsz);
|
||||
if (!fp->cltbl) return (void *)0;
|
||||
fp->cltbl[0] = tblsz;
|
||||
}
|
||||
if (f_lseek(fp, CREATE_LINKMAP)) { /* Create cluster link table */
|
||||
|
||||
@@ -29,127 +29,128 @@ int bq24193_get_property(enum BQ24193_reg_prop prop, int *value)
|
||||
{
|
||||
u8 data;
|
||||
|
||||
switch (prop) {
|
||||
case BQ24193_InputVoltageLimit: // Input voltage limit (mV).
|
||||
data = bq24193_get_reg(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;
|
||||
switch (prop)
|
||||
{
|
||||
case BQ24193_InputVoltageLimit: // Input voltage limit (mV).
|
||||
data = bq24193_get_reg(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 = bq24193_get_reg(BQ24193_InputSource);
|
||||
data &= BQ24193_INCONFIG_INLIMIT_MASK;
|
||||
switch (data)
|
||||
{
|
||||
case 0:
|
||||
*value = 100;
|
||||
break;
|
||||
case BQ24193_InputCurrentLimit: // Input current limit (mA).
|
||||
data = bq24193_get_reg(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;
|
||||
}
|
||||
case 1:
|
||||
*value = 150;
|
||||
break;
|
||||
case BQ24193_SystemMinimumVoltage: // Minimum system voltage limit (mV).
|
||||
data = bq24193_get_reg(BQ24193_PORConfig);
|
||||
*value = (data & BQ24193_PORCONFIG_SYSMIN_MASK) >> 1;
|
||||
*value *= 100;
|
||||
*value += 3000;
|
||||
case 2:
|
||||
*value = 500;
|
||||
break;
|
||||
case BQ24193_FastChargeCurrentLimit: // Fast charge current limit (mA).
|
||||
data = bq24193_get_reg(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 = bq24193_get_reg(BQ24193_ChrgCurr);
|
||||
data &= BQ24193_CHRGCURR_20PCT_MASK;
|
||||
if (data)
|
||||
*value = *value * 20 / 100; // Fast charge current limit is 20%.
|
||||
case 3:
|
||||
*value = 900;
|
||||
break;
|
||||
case BQ24193_ChargeVoltageLimit: // Charge voltage limit (mV).
|
||||
data = bq24193_get_reg(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;
|
||||
case 4:
|
||||
*value = 1200;
|
||||
break;
|
||||
case BQ24193_RechargeThreshold: // Recharge voltage threshold less than voltage limit (mV).
|
||||
data = bq24193_get_reg(BQ24193_ChrgVolt);
|
||||
data &= BQ24193_IRTHERMAL_THERM_MASK;
|
||||
if (data)
|
||||
*value = 300;
|
||||
else
|
||||
*value = 100;
|
||||
case 5:
|
||||
*value = 1500;
|
||||
break;
|
||||
case BQ24193_ThermalRegulation: // Thermal regulation threshold (oC).
|
||||
data = bq24193_get_reg(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;
|
||||
}
|
||||
case 6:
|
||||
*value = 2000;
|
||||
break;
|
||||
case BQ24193_ChargeStatus: // 0: Not charging, 1: Pre-charge, 2: Fast charging, 3: Charge termination done
|
||||
data = bq24193_get_reg(BQ24193_Status);
|
||||
*value = (data & BQ24193_STATUS_CHRG_MASK) >> 4;
|
||||
case 7:
|
||||
*value = 3000;
|
||||
break;
|
||||
case BQ24193_TempStatus: // 0: Normal, 2: Warm, 3: Cool, 5: Cold, 6: Hot.
|
||||
data = bq24193_get_reg(BQ24193_FaultReg);
|
||||
*value = data & BQ24193_FAULT_THERM_MASK;
|
||||
}
|
||||
break;
|
||||
case BQ24193_SystemMinimumVoltage: // Minimum system voltage limit (mV).
|
||||
data = bq24193_get_reg(BQ24193_PORConfig);
|
||||
*value = (data & BQ24193_PORCONFIG_SYSMIN_MASK) >> 1;
|
||||
*value *= 100;
|
||||
*value += 3000;
|
||||
break;
|
||||
case BQ24193_FastChargeCurrentLimit: // Fast charge current limit (mA).
|
||||
data = bq24193_get_reg(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 = bq24193_get_reg(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 = bq24193_get_reg(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 = bq24193_get_reg(BQ24193_ChrgVolt);
|
||||
data &= BQ24193_IRTHERMAL_THERM_MASK;
|
||||
if (data)
|
||||
*value = 300;
|
||||
else
|
||||
*value = 100;
|
||||
break;
|
||||
case BQ24193_ThermalRegulation: // Thermal regulation threshold (oC).
|
||||
data = bq24193_get_reg(BQ24193_IRCompThermal);
|
||||
data &= BQ24193_IRTHERMAL_THERM_MASK;
|
||||
switch (data)
|
||||
{
|
||||
case 0:
|
||||
*value = 60;
|
||||
break;
|
||||
case BQ24193_DevID: // Dev ID.
|
||||
data = bq24193_get_reg(BQ24193_VendorPart);
|
||||
*value = data & BQ24193_VENDORPART_DEV_MASK;
|
||||
case 1:
|
||||
*value = 80;
|
||||
break;
|
||||
case BQ24193_ProductNumber: // Product number.
|
||||
data = bq24193_get_reg(BQ24193_VendorPart);
|
||||
*value = (data & BQ24193_VENDORPART_PN_MASK) >> 3;
|
||||
case 2:
|
||||
*value = 100;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
case 3:
|
||||
*value = 120;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case BQ24193_ChargeStatus: // 0: Not charging, 1: Pre-charge, 2: Fast charging, 3: Charge termination done
|
||||
data = bq24193_get_reg(BQ24193_Status);
|
||||
*value = (data & BQ24193_STATUS_CHRG_MASK) >> 4;
|
||||
break;
|
||||
case BQ24193_TempStatus: // 0: Normal, 2: Warm, 3: Cool, 5: Cold, 6: Hot.
|
||||
data = bq24193_get_reg(BQ24193_FaultReg);
|
||||
*value = data & BQ24193_FAULT_THERM_MASK;
|
||||
break;
|
||||
case BQ24193_DevID: // Dev ID.
|
||||
data = bq24193_get_reg(BQ24193_VendorPart);
|
||||
*value = data & BQ24193_VENDORPART_DEV_MASK;
|
||||
break;
|
||||
case BQ24193_ProductNumber: // Product number.
|
||||
data = bq24193_get_reg(BQ24193_VendorPart);
|
||||
*value = (data & BQ24193_VENDORPART_PN_MASK) >> 3;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -327,7 +327,7 @@ void max77620_config_default()
|
||||
return;
|
||||
|
||||
// Set default voltages and enable regulators.
|
||||
for (u32 i = 1; i <= REGULATOR_LDO8; i++)
|
||||
for (u32 i = REGULATOR_SD1; i <= REGULATOR_LDO8; i++)
|
||||
{
|
||||
max77620_regulator_config_fps(i);
|
||||
max7762x_regulator_set_voltage(i, _pmic_regulators[i].uv_default);
|
||||
|
||||
41
bdk/sec/se.c
41
bdk/sec/se.c
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (c) 2018-2024 CTCaer
|
||||
* Copyright (c) 2018-2025 CTCaer
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
@@ -19,7 +19,6 @@
|
||||
|
||||
#include "se.h"
|
||||
#include <memory_map.h>
|
||||
#include <mem/heap.h>
|
||||
#include <soc/bpmp.h>
|
||||
#include <soc/hw_init.h>
|
||||
#include <soc/pmc.h>
|
||||
@@ -182,7 +181,7 @@ static int _se_execute_one_block(u32 op, void *dst, u32 dst_size, const void *sr
|
||||
if (!src || !dst)
|
||||
return 0;
|
||||
|
||||
u8 *block = (u8 *)zalloc(SE_AES_BLOCK_SIZE);
|
||||
u32 block[SE_AES_BLOCK_SIZE / sizeof(u32)] = {0};
|
||||
|
||||
SE(SE_CRYPTO_BLOCK_COUNT_REG) = 1 - 1;
|
||||
|
||||
@@ -190,7 +189,6 @@ static int _se_execute_one_block(u32 op, void *dst, u32 dst_size, const void *sr
|
||||
int res = _se_execute_oneshot(op, block, SE_AES_BLOCK_SIZE, block, SE_AES_BLOCK_SIZE);
|
||||
memcpy(dst, block, dst_size);
|
||||
|
||||
free(block);
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -389,7 +387,8 @@ int se_aes_crypt_ctr(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_s
|
||||
int se_aes_xts_crypt_sec(u32 tweak_ks, u32 crypt_ks, u32 enc, u64 sec, void *dst, void *src, u32 secsize)
|
||||
{
|
||||
int res = 0;
|
||||
u8 *tweak = (u8 *)malloc(SE_AES_BLOCK_SIZE);
|
||||
u32 tmp[SE_AES_BLOCK_SIZE / sizeof(u32)];
|
||||
u8 *tweak = (u8 *)tmp;
|
||||
u8 *pdst = (u8 *)dst;
|
||||
u8 *psrc = (u8 *)src;
|
||||
|
||||
@@ -418,8 +417,7 @@ int se_aes_xts_crypt_sec(u32 tweak_ks, u32 crypt_ks, u32 enc, u64 sec, void *dst
|
||||
|
||||
res = 1;
|
||||
|
||||
out:;
|
||||
free(tweak);
|
||||
out:
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -514,15 +512,15 @@ int se_calc_sha256(void *hash, u32 *msg_left, const void *src, u32 src_size, u64
|
||||
return 0;
|
||||
|
||||
// Src size of 0 is not supported, so return null string sha256.
|
||||
// if (!src_size)
|
||||
// {
|
||||
// const u8 null_hash[SE_SHA_256_SIZE] = {
|
||||
// 0xE3, 0xB0, 0xC4, 0x42, 0x98, 0xFC, 0x1C, 0x14, 0x9A, 0xFB, 0xF4, 0xC8, 0x99, 0x6F, 0xB9, 0x24,
|
||||
// 0x27, 0xAE, 0x41, 0xE4, 0x64, 0x9B, 0x93, 0x4C, 0xA4, 0x95, 0x99, 0x1B, 0x78, 0x52, 0xB8, 0x55
|
||||
// };
|
||||
// memcpy(hash, null_hash, SE_SHA_256_SIZE);
|
||||
// return 1;
|
||||
// }
|
||||
if (!src_size)
|
||||
{
|
||||
const u8 null_hash[SE_SHA_256_SIZE] = {
|
||||
0xE3, 0xB0, 0xC4, 0x42, 0x98, 0xFC, 0x1C, 0x14, 0x9A, 0xFB, 0xF4, 0xC8, 0x99, 0x6F, 0xB9, 0x24,
|
||||
0x27, 0xAE, 0x41, 0xE4, 0x64, 0x9B, 0x93, 0x4C, 0xA4, 0x95, 0x99, 0x1B, 0x78, 0x52, 0xB8, 0x55
|
||||
};
|
||||
memcpy(hash, null_hash, SE_SHA_256_SIZE);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Setup config for SHA256.
|
||||
SE(SE_CONFIG_REG) = SE_CONFIG_ENC_MODE(MODE_SHA256) | SE_CONFIG_ENC_ALG(ALG_SHA) | SE_CONFIG_DST(DST_HASHREG);
|
||||
@@ -657,8 +655,11 @@ void se_get_aes_keys(u8 *buf, u8 *keys, u32 keysize)
|
||||
int se_aes_cmac_128(u32 ks, void *dst, const void *src, u32 src_size)
|
||||
{
|
||||
int res = 0;
|
||||
u8 *key = (u8 *)zalloc(SE_KEY_128_SIZE);
|
||||
u8 *last_block = (u8 *)zalloc(SE_AES_BLOCK_SIZE);
|
||||
|
||||
u32 tmp1[SE_KEY_128_SIZE / sizeof(u32)] = {0};
|
||||
u32 tmp2[SE_AES_BLOCK_SIZE / sizeof(u32)] = {0};
|
||||
u8 *key = (u8 *)tmp1;
|
||||
u8 *last_block = (u8 *)tmp2;
|
||||
|
||||
se_aes_iv_clear(ks);
|
||||
se_aes_iv_updated_clear(ks);
|
||||
@@ -707,8 +708,6 @@ int se_aes_cmac_128(u32 ks, void *dst, const void *src, u32 src_size)
|
||||
for (u32 i = 0; i < (SE_KEY_128_SIZE / 4); i++)
|
||||
dst32[i] = SE(SE_HASH_RESULT_REG + (i * 4));
|
||||
|
||||
out:;
|
||||
free(key);
|
||||
free(last_block);
|
||||
out:
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -24,7 +24,9 @@
|
||||
#include <sec/se_t210.h>
|
||||
#include <soc/fuse.h>
|
||||
#include <soc/hw_init.h>
|
||||
#include <soc/pmc.h>
|
||||
#include <soc/t210.h>
|
||||
#include <soc/timer.h>
|
||||
#include <utils/types.h>
|
||||
|
||||
static const u32 evp_thunk_template[] = {
|
||||
|
||||
@@ -85,6 +85,7 @@
|
||||
#define AXBAR_BASE 0x702D0800
|
||||
#define I2S_BASE 0x702D1000
|
||||
#define ADMA_BASE 0x702E2000
|
||||
#define AMC_BASE 0x702EF000
|
||||
#define SE2_BASE 0x70412000
|
||||
#define SE_PKA1_BASE 0x70420000
|
||||
#define TZRAM_BASE 0x7C010000
|
||||
@@ -151,6 +152,7 @@
|
||||
#define CL_DVFS(off) MMIO_REG32(CL_DVFS_BASE, off)
|
||||
#define I2S(off) MMIO_REG32(I2S_BASE, off)
|
||||
#define ADMA(off) MMIO_REG32(ADMA_BASE, off)
|
||||
#define AMC(off) MMIO_REG32(AMC_BASE, off)
|
||||
#define SE2(off) MMIO_REG32(SE2_BASE, off)
|
||||
#define SE_PKA1(off) MMIO_REG32(SE_PKA1_BASE, off)
|
||||
#define USB(off) MMIO_REG32(USB_BASE, off)
|
||||
@@ -199,7 +201,7 @@
|
||||
/*! AHB Gizmo registers. */
|
||||
#define AHB_ARBITRATION_PRIORITY_CTRL 0x8
|
||||
#define PRIORITY_CTRL_WEIGHT(x) (((x) & 7) << 29)
|
||||
#define PRIORITY_SELECT_USB BIT(6) // USB-OTG.
|
||||
#define PRIORITY_SELECT_USB BIT(6) // USB-OTG.
|
||||
#define PRIORITY_SELECT_USB2 BIT(18) // USB-HSIC.
|
||||
#define PRIORITY_SELECT_USB3 BIT(17) // XUSB.
|
||||
#define AHB_GIZMO_AHB_MEM 0x10
|
||||
@@ -210,7 +212,7 @@
|
||||
#define AHB_GIZMO_USB 0x20
|
||||
#define AHB_GIZMO_SDMMC4 0x48
|
||||
#define AHB_GIZMO_USB2 0x7C
|
||||
#define AHB_GIZMO_USB3 0x80
|
||||
#define AHB_GIZMO_USB3 0x80 // Doesn't exist on T21x??
|
||||
#define AHB_GIZMO_IMMEDIATE BIT(18)
|
||||
#define AHB_ARBITRATION_XBAR_CTRL 0xE0
|
||||
#define AHB_AHB_MEM_PREFETCH_CFG3 0xE4
|
||||
@@ -219,9 +221,9 @@
|
||||
#define AHB_AHB_MEM_PREFETCH_CFG2 0xF4
|
||||
#define MST_ID(x) (((x) & 0x1F) << 26)
|
||||
#define MEM_PREFETCH_AHBDMA_MST_ID MST_ID(5)
|
||||
#define MEM_PREFETCH_USB_MST_ID MST_ID(6) // USB-OTG.
|
||||
#define MEM_PREFETCH_USB2_MST_ID MST_ID(18) // USB-HSIC.
|
||||
#define MEM_PREFETCH_USB3_MST_ID MST_ID(17) // XUSB.
|
||||
#define MEM_PREFETCH_USB_MST_ID MST_ID(6) // USB-OTG. Doesn't exist on T210B01.
|
||||
#define MEM_PREFETCH_USB2_MST_ID MST_ID(18) // USB-HSIC. Doesn't exist on T210B01.
|
||||
#define MEM_PREFETCH_USB3_MST_ID MST_ID(17) // XUSB. Doesn't exist on T210B01.
|
||||
#define MEM_PREFETCH_ADDR_BNDRY(x) (((x) & 0xF) << 21)
|
||||
#define MEM_PREFETCH_ENABLE BIT(31)
|
||||
#define AHB_ARBITRATION_AHB_MEM_WRQUE_MST_ID 0xFC
|
||||
|
||||
@@ -70,6 +70,8 @@
|
||||
#define UART_MCR_CTS_EN BIT(5)
|
||||
#define UART_MCR_RTS_EN BIT(6)
|
||||
|
||||
#define UART_FIFO_SIZE 36
|
||||
|
||||
typedef struct _uart_t
|
||||
{
|
||||
/* 0x00 */ vu32 UART_THR_DLAB;
|
||||
|
||||
275
bdk/storage/boot_storage.c
Normal file
275
bdk/storage/boot_storage.c
Normal file
@@ -0,0 +1,275 @@
|
||||
#include "boot_storage.h"
|
||||
#include <libs/fatfs/ff.h>
|
||||
#include <fatfs_cfg.h>
|
||||
#include <storage/sd.h>
|
||||
#include <storage/emmc.h>
|
||||
#include <utils/types.h>
|
||||
#include <gfx_utils.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define DEV_INVALID 0xff
|
||||
|
||||
static FATFS boot_storage_fs;
|
||||
static BYTE drive_cur = -1;
|
||||
static BYTE drive = -1;
|
||||
|
||||
static const char* drive_base_paths[] = {
|
||||
[DRIVE_SD] = "sd:",
|
||||
[DRIVE_BOOT1] = "boot1_:",
|
||||
[DRIVE_BOOT1_1MB] = "boot1_1mb:",
|
||||
[DRIVE_EMMC] = "emmc:",
|
||||
};
|
||||
|
||||
static bool _is_eligible(){
|
||||
if(f_stat(".no_boot_storage", NULL) == FR_OK){
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool boot_storage_get_mounted(){
|
||||
switch(drive_cur){
|
||||
case DRIVE_SD:
|
||||
return sd_get_card_mounted();
|
||||
case DRIVE_EMMC:
|
||||
return emmc_get_mounted();
|
||||
case DRIVE_BOOT1:
|
||||
case DRIVE_BOOT1_1MB:
|
||||
return drive_cur != DEV_INVALID;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool boot_storage_get_initialized(){
|
||||
switch(drive_cur){
|
||||
case DRIVE_BOOT1:
|
||||
case DRIVE_EMMC:
|
||||
case DRIVE_BOOT1_1MB:
|
||||
return emmc_get_initialized();
|
||||
case DRIVE_SD:
|
||||
return sd_get_card_initialized();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool _boot_storage_initialize(){
|
||||
switch(drive_cur){
|
||||
case DRIVE_BOOT1:
|
||||
case DRIVE_EMMC:
|
||||
case DRIVE_BOOT1_1MB:
|
||||
return emmc_initialize(false);
|
||||
case DRIVE_SD:
|
||||
return sd_initialize(false);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void _boot_storage_end(bool deinit){
|
||||
if(boot_storage_get_mounted()){
|
||||
switch(drive_cur){
|
||||
case DRIVE_SD:
|
||||
sd_unmount();
|
||||
break;
|
||||
case DRIVE_EMMC:
|
||||
emmc_unmount();
|
||||
break;
|
||||
case DRIVE_BOOT1:
|
||||
case DRIVE_BOOT1_1MB:
|
||||
f_mount(NULL, drive_base_paths[drive_cur], 0);
|
||||
}
|
||||
drive_cur = DEV_INVALID;
|
||||
}
|
||||
|
||||
if(deinit){
|
||||
switch(drive_cur){
|
||||
case DRIVE_SD:
|
||||
sd_end();
|
||||
break;
|
||||
case DRIVE_EMMC:
|
||||
case DRIVE_BOOT1:
|
||||
case DRIVE_BOOT1_1MB:
|
||||
emmc_end();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void boot_storage_unmount(){
|
||||
_boot_storage_end(false);
|
||||
}
|
||||
|
||||
void boot_storage_end(){
|
||||
_boot_storage_end(true);
|
||||
}
|
||||
|
||||
u8 boot_storage_get_drive(){
|
||||
return drive;
|
||||
}
|
||||
|
||||
static bool _boot_storage_mount(){
|
||||
// may want to check sd card first and prioritize it
|
||||
|
||||
FRESULT res;
|
||||
|
||||
bool prev_emmc_initialized = emmc_get_initialized();
|
||||
bool prev_sd_initialized = sd_get_card_initialized();
|
||||
|
||||
if(!prev_emmc_initialized && !emmc_initialize(false)){
|
||||
goto emmc_init_fail;
|
||||
}
|
||||
|
||||
static const BYTE emmc_drives[] = {DRIVE_BOOT1_1MB, DRIVE_BOOT1};
|
||||
|
||||
for(BYTE i = 0; i < ARRAY_SIZE(emmc_drives); i++){
|
||||
res = f_mount(&boot_storage_fs, drive_base_paths[emmc_drives[i]], true);
|
||||
if(res == FR_OK){
|
||||
res = f_chdrive(drive_base_paths[emmc_drives[i]]);
|
||||
if(res == FR_OK && _is_eligible()){
|
||||
drive_cur = emmc_drives[i];
|
||||
drive = drive_cur;
|
||||
break;
|
||||
}else{
|
||||
f_mount(NULL, drive_base_paths[emmc_drives[i]],false);
|
||||
res = FR_INVALID_DRIVE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(res != FR_OK){
|
||||
if(!prev_emmc_initialized) {
|
||||
emmc_end();
|
||||
}
|
||||
}
|
||||
|
||||
if(res == FR_OK){
|
||||
return true;
|
||||
}
|
||||
|
||||
emmc_init_fail:
|
||||
if(!emmc_initialize(false)){
|
||||
goto emmc_init_fail2;
|
||||
}
|
||||
|
||||
if(!emmc_mount()){
|
||||
if(!prev_emmc_initialized) {
|
||||
emmc_end();
|
||||
}
|
||||
goto emmc_init_fail2;
|
||||
}
|
||||
|
||||
res = f_chdrive(drive_base_paths[DRIVE_EMMC]);
|
||||
|
||||
if(res == FR_OK && _is_eligible()){
|
||||
drive_cur = DRIVE_EMMC;
|
||||
drive = drive_cur;
|
||||
return true;
|
||||
}
|
||||
|
||||
emmc_init_fail2:
|
||||
if(!sd_initialize(false)){
|
||||
goto out;
|
||||
}
|
||||
|
||||
if(!sd_mount()){
|
||||
if(!prev_sd_initialized) {
|
||||
sd_end();
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
|
||||
res = f_chdrive(drive_base_paths[DRIVE_SD]);
|
||||
|
||||
if(res == FR_OK && _is_eligible()){
|
||||
drive_cur = DRIVE_SD;
|
||||
drive = drive_cur;
|
||||
return true;
|
||||
}
|
||||
|
||||
if(!prev_sd_initialized) {
|
||||
sd_end();
|
||||
}
|
||||
|
||||
out:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool boot_storage_mount(){
|
||||
bool mounted = boot_storage_get_mounted();
|
||||
bool initialized = boot_storage_get_initialized();
|
||||
bool res = mounted && initialized;
|
||||
if(!mounted){
|
||||
// not mounted. mounting will also initialize.
|
||||
res = _boot_storage_mount();
|
||||
}else if(!initialized){
|
||||
res = _boot_storage_initialize();
|
||||
}
|
||||
|
||||
if(res){
|
||||
res = f_chdrive(drive_base_paths[drive_cur]) == FR_OK;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void *boot_storage_file_read(const char *path, u32 *fsize)
|
||||
{
|
||||
FIL fp;
|
||||
if (!boot_storage_get_mounted())
|
||||
return NULL;
|
||||
|
||||
if (f_open(&fp, path, FA_READ) != FR_OK)
|
||||
return NULL;
|
||||
|
||||
u32 size = f_size(&fp);
|
||||
if (fsize)
|
||||
*fsize = size;
|
||||
|
||||
void *buf = malloc(size);
|
||||
|
||||
if (f_read(&fp, buf, size, NULL) != FR_OK)
|
||||
{
|
||||
free(buf);
|
||||
f_close(&fp);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
f_close(&fp);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
int boot_storage_save_to_file(const void *buf, u32 size, const char *filename)
|
||||
{
|
||||
FIL fp;
|
||||
u32 res = 0;
|
||||
if (!boot_storage_get_mounted())
|
||||
return FR_DISK_ERR;
|
||||
|
||||
res = f_open(&fp, filename, FA_CREATE_ALWAYS | FA_WRITE);
|
||||
if (res)
|
||||
{
|
||||
EPRINTFARGS("Error (%d) creating file\n%s.\n", res, filename);
|
||||
return res;
|
||||
}
|
||||
|
||||
f_write(&fp, buf, size, NULL);
|
||||
f_close(&fp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
FATFS *boot_storage_get_fs() {
|
||||
switch(drive_cur){
|
||||
case DRIVE_BOOT1:
|
||||
return &boot_storage_fs;
|
||||
case DRIVE_EMMC:
|
||||
return &emmc_fs;
|
||||
case DRIVE_BOOT1_1MB:
|
||||
return &boot_storage_fs;
|
||||
case DRIVE_SD:
|
||||
return &sd_fs;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
24
bdk/storage/boot_storage.h
Normal file
24
bdk/storage/boot_storage.h
Normal file
@@ -0,0 +1,24 @@
|
||||
#ifndef _BOOT_STORAGE_H
|
||||
#define _BOOT_STORAGE_H
|
||||
|
||||
#include <libs/fatfs/ff.h>
|
||||
#include <utils/types.h>
|
||||
|
||||
// check if boot1 (1mb), boot1, gpp, sd (in that order) have fat32 partition,
|
||||
// mount the partition and set the current drive to it
|
||||
bool boot_storage_mount();
|
||||
|
||||
void boot_storage_unmount();
|
||||
void boot_storage_end();
|
||||
|
||||
bool boot_storage_get_mounted();
|
||||
bool boot_storage_get_initialized();
|
||||
|
||||
void *boot_storage_file_read(const char *path, u32 *fsize);
|
||||
int boot_storage_save_to_file(const void *buf, u32 size, const char *filename);
|
||||
|
||||
FATFS *boot_storage_get_fs();
|
||||
|
||||
u8 boot_storage_get_drive();
|
||||
|
||||
#endif
|
||||
@@ -21,10 +21,14 @@
|
||||
#include <mem/heap.h>
|
||||
#include <soc/fuse.h>
|
||||
#include <storage/mbr_gpt.h>
|
||||
#include <gfx_utils.h>
|
||||
#include <utils/list.h>
|
||||
#include <storage/emummc_file_based.h>
|
||||
|
||||
static u16 emmc_errors[3] = { 0 }; // Init and Read/Write errors.
|
||||
static u32 emmc_mode = EMMC_MMC_HS400;
|
||||
static bool emmc_init_done = false;
|
||||
static bool emmc_mounted = false;
|
||||
|
||||
sdmmc_t emmc_sdmmc;
|
||||
sdmmc_storage_t emmc_storage;
|
||||
@@ -61,7 +65,26 @@ u32 emmc_get_mode()
|
||||
return emmc_mode;
|
||||
}
|
||||
|
||||
void emmc_end() { sdmmc_storage_end(&emmc_storage); }
|
||||
static void _emmc_deinit(bool deinit){
|
||||
if(emmc_init_done){
|
||||
// TODO: Allow unmount even when not init'd?
|
||||
if(emmc_mounted){
|
||||
f_mount(NULL, "emmc:", 0);
|
||||
}
|
||||
|
||||
if(deinit){
|
||||
sdmmc_storage_end(&emmc_storage);
|
||||
emmc_init_done = false;
|
||||
}
|
||||
}
|
||||
emmc_mounted = false;
|
||||
}
|
||||
|
||||
void emmc_end() { _emmc_deinit(true); }
|
||||
|
||||
bool emmc_get_initialized(){
|
||||
return emmc_init_done;
|
||||
}
|
||||
|
||||
int emmc_init_retry(bool power_cycle)
|
||||
{
|
||||
@@ -97,7 +120,13 @@ int emmc_init_retry(bool power_cycle)
|
||||
emmc_mode = EMMC_MMC_HS400;
|
||||
}
|
||||
|
||||
return sdmmc_storage_init_mmc(&emmc_storage, &emmc_sdmmc, bus_width, type);
|
||||
int res = sdmmc_storage_init_mmc(&emmc_storage, &emmc_sdmmc, bus_width, type);
|
||||
if(res){
|
||||
emmc_init_done = true;
|
||||
}else{
|
||||
emmc_init_done = false;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
bool emmc_initialize(bool power_cycle)
|
||||
@@ -212,6 +241,14 @@ int emmc_part_write(emmc_part_t *part, u32 sector_off, u32 num_sectors, void *bu
|
||||
#endif
|
||||
}
|
||||
|
||||
sdmmc_storage_t *emmc_part_get_storage(){
|
||||
#ifdef BDK_EMUMMC_ENABLE
|
||||
return emummc_get_storage();
|
||||
#else
|
||||
return &emmc_storage;
|
||||
#endif
|
||||
}
|
||||
|
||||
void nx_emmc_get_autorcm_masks(u8 *mod0, u8 *mod1)
|
||||
{
|
||||
if (fuse_read_hw_state() == FUSE_NX_HW_STATE_PROD)
|
||||
@@ -225,3 +262,44 @@ void nx_emmc_get_autorcm_masks(u8 *mod0, u8 *mod1)
|
||||
*mod1 = 0x84;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool emmc_mount()
|
||||
{
|
||||
if (emmc_init_done && emmc_mounted)
|
||||
return true;
|
||||
|
||||
int res = 0;
|
||||
|
||||
if (!emmc_init_done)
|
||||
res = !emmc_initialize(false);
|
||||
|
||||
if (res)
|
||||
{
|
||||
gfx_con.mute = false;
|
||||
EPRINTF("Failed to init eMMC.");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!emmc_mounted)
|
||||
res = f_mount(&emmc_fs, "emmc:", 1); // Volume 0 is SD.
|
||||
if (res == FR_OK)
|
||||
{
|
||||
emmc_mounted = true;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
gfx_con.mute = false;
|
||||
EPRINTFARGS("Failed to mount eMMC (FatFS Error %d).\nMake sure that a FAT partition exists..", res);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool emmc_get_mounted(){
|
||||
return emmc_mounted;
|
||||
}
|
||||
|
||||
void emmc_unmount() { _emmc_deinit(false); }
|
||||
@@ -65,12 +65,17 @@ int emmc_init_retry(bool power_cycle);
|
||||
bool emmc_initialize(bool power_cycle);
|
||||
int emmc_set_partition(u32 partition);
|
||||
void emmc_end();
|
||||
bool emmc_mount();
|
||||
void emmc_unmount();
|
||||
bool emmc_get_initialized();
|
||||
bool emmc_get_mounted();
|
||||
|
||||
void emmc_gpt_parse(link_t *gpt);
|
||||
void emmc_gpt_free(link_t *gpt);
|
||||
emmc_part_t *emmc_part_find(link_t *gpt, const char *name);
|
||||
int emmc_part_read(emmc_part_t *part, u32 sector_off, u32 num_sectors, void *buf);
|
||||
int emmc_part_write(emmc_part_t *part, u32 sector_off, u32 num_sectors, void *buf);
|
||||
sdmmc_storage_t *emmc_part_get_storage();
|
||||
|
||||
void nx_emmc_get_autorcm_masks(u8 *mod0, u8 *mod1);
|
||||
|
||||
|
||||
233
bdk/storage/emummc_file_based.c
Normal file
233
bdk/storage/emummc_file_based.c
Normal file
@@ -0,0 +1,233 @@
|
||||
#include "emummc_file_based.h"
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <libs/fatfs/ff.h>
|
||||
#include <gfx_utils.h>
|
||||
|
||||
// TODO: fast read/writes
|
||||
|
||||
static FIL active_file;
|
||||
// -0xff: none, -1: boot 0, -2: boot1, 0+: gpp
|
||||
static s32 active_file_idx;
|
||||
static char file_based_base_path[0x80];
|
||||
static u32 file_part_sz_sct;
|
||||
static u32 active_part;
|
||||
static u32 file_based_base_path_len;
|
||||
|
||||
static int _emummc_storage_file_based_read_write_single(u32 sector, u32 num_sectors, void *buf, bool is_write){
|
||||
#if FF_FS_READONLY == 1
|
||||
if(is_write){
|
||||
return FR_WRITE_PROTECTED;
|
||||
}
|
||||
#endif
|
||||
|
||||
int res = f_lseek(&active_file, (u64)sector << 9);
|
||||
if(res != FR_OK){
|
||||
return res;
|
||||
}
|
||||
|
||||
if(is_write){
|
||||
res = f_write(&active_file, buf, (u64)num_sectors << 9, NULL);
|
||||
}else{
|
||||
res = f_read(&active_file, buf, (u64)num_sectors << 9, NULL);
|
||||
}
|
||||
|
||||
if(res != FR_OK){
|
||||
return res;
|
||||
}
|
||||
|
||||
return FR_OK;
|
||||
}
|
||||
|
||||
static int _emummc_storage_file_based_change_file(const char *name, s32 idx){
|
||||
int res;
|
||||
|
||||
if(active_file_idx == idx){
|
||||
return FR_OK;
|
||||
}
|
||||
|
||||
if(active_file_idx != -0xff){
|
||||
f_close(&active_file);
|
||||
active_file_idx = -0xff;
|
||||
}
|
||||
|
||||
strcpy(file_based_base_path + file_based_base_path_len, name);
|
||||
|
||||
|
||||
#if FF_FS_READONLY == 1
|
||||
res = f_open(&active_file, file_based_base_path, FA_READ);
|
||||
#else
|
||||
res = f_open(&active_file, file_based_base_path, FA_READ | FA_WRITE);
|
||||
#endif
|
||||
|
||||
if(res != FR_OK){
|
||||
return res;
|
||||
}
|
||||
active_file_idx = idx;
|
||||
|
||||
return FR_OK;
|
||||
}
|
||||
|
||||
static int _emummc_storage_file_based_read_write(u32 sector, u32 num_sectors, void *buf, bool is_write){
|
||||
#if FF_FS_READONLY == 1
|
||||
if(is_write){
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
if(file_part_sz_sct == 0){
|
||||
return 0;
|
||||
}
|
||||
|
||||
int res;
|
||||
|
||||
if(active_part == 1){
|
||||
// boot0
|
||||
res = _emummc_storage_file_based_change_file("BOOT0", -1);
|
||||
if(res != FR_OK){
|
||||
return 0;
|
||||
}
|
||||
res = _emummc_storage_file_based_read_write_single(sector, num_sectors, buf, is_write);
|
||||
if(res != FR_OK){
|
||||
return 0;
|
||||
}
|
||||
f_sync(&active_file);
|
||||
return 1;
|
||||
}else if(active_part == 2){
|
||||
// boot1
|
||||
res = _emummc_storage_file_based_change_file("BOOT1", -2);
|
||||
if(res != FR_OK){
|
||||
return 0;
|
||||
}
|
||||
res = _emummc_storage_file_based_read_write_single(sector, num_sectors, buf, is_write) == FR_OK;
|
||||
if(res != FR_OK){
|
||||
return 0;
|
||||
}
|
||||
f_sync(&active_file);
|
||||
return 1;
|
||||
}else if(active_part == 0){
|
||||
// GPP
|
||||
if(file_part_sz_sct == 0){
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
u32 scts_left = num_sectors;
|
||||
u32 cur_sct = sector;
|
||||
while(scts_left){
|
||||
// offset within file
|
||||
u32 offset = cur_sct % file_part_sz_sct;
|
||||
// read up to start of next file or sectors left, whatever is less
|
||||
u32 sct_cnt = file_part_sz_sct - offset;
|
||||
sct_cnt = MIN(sct_cnt, scts_left);
|
||||
|
||||
u32 file_idx = cur_sct / file_part_sz_sct;
|
||||
|
||||
if((s32)file_idx != active_file_idx){
|
||||
char name[3] = "";
|
||||
if(file_idx < 10){
|
||||
strcpy(name, "0");
|
||||
}
|
||||
itoa(file_idx, name + strlen(name), 10);
|
||||
|
||||
|
||||
res = _emummc_storage_file_based_change_file(name, file_idx);
|
||||
if(res != FR_OK){
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
res = _emummc_storage_file_based_read_write_single(offset, sct_cnt, buf + ((u64)(num_sectors - scts_left) << 9), is_write);
|
||||
|
||||
if(res != FR_OK){
|
||||
return 0;
|
||||
}
|
||||
|
||||
cur_sct += sct_cnt;
|
||||
scts_left -= sct_cnt;
|
||||
}
|
||||
if(res != FR_OK){
|
||||
return 0;
|
||||
}
|
||||
f_sync(&active_file);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int emummc_storage_file_base_set_partition(u32 partition){
|
||||
active_part = partition;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int emummc_storage_file_based_init(const char *path){
|
||||
strcpy(file_based_base_path, path);
|
||||
file_based_base_path_len = strlen(file_based_base_path);
|
||||
strcat(file_based_base_path + file_based_base_path_len, "00");
|
||||
|
||||
active_part = 0;
|
||||
|
||||
FILINFO fi;
|
||||
if(f_stat(file_based_base_path, &fi) != FR_OK){
|
||||
return 0;
|
||||
}
|
||||
|
||||
file_part_sz_sct = 0;
|
||||
if(fi.fsize){
|
||||
file_part_sz_sct = fi.fsize >> 9;
|
||||
}
|
||||
|
||||
active_file_idx = -0xff;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void emummc_storage_file_based_end(){
|
||||
if(active_file_idx != -0xff){
|
||||
f_close(&active_file);
|
||||
}
|
||||
active_file_idx = -0xff;
|
||||
file_based_base_path[0] = '\0';
|
||||
file_part_sz_sct = 0;
|
||||
}
|
||||
|
||||
#if FF_FS_READONLY == 0
|
||||
int emummc_storage_file_based_write(u32 sector, u32 num_sectors, void *buf){
|
||||
return _emummc_storage_file_based_read_write(sector, num_sectors, buf, true);
|
||||
}
|
||||
#endif
|
||||
|
||||
int emummc_storage_file_based_read(u32 sector, u32 num_sectors, void *buf){
|
||||
return _emummc_storage_file_based_read_write(sector, num_sectors, buf, false);
|
||||
}
|
||||
|
||||
u32 emummc_storage_file_based_get_total_gpp_size(const char *path){
|
||||
u32 path_len = strlen(path);
|
||||
u32 total_size_sct = 0;
|
||||
char file_path[0x80];
|
||||
u32 cur_idx = 0;
|
||||
int res;
|
||||
|
||||
strcpy(file_path, path);
|
||||
strcpy(file_path + path_len, "00");
|
||||
|
||||
FILINFO fi;
|
||||
res = f_stat(file_path, &fi);
|
||||
|
||||
while(res == FR_OK){
|
||||
cur_idx++;
|
||||
total_size_sct += fi.fsize >> 9;
|
||||
|
||||
char name[3] = "0";
|
||||
if(cur_idx >= 10){
|
||||
name[0] = '\0';
|
||||
}
|
||||
itoa(cur_idx, name + strlen(name), 10);
|
||||
|
||||
strcpy(file_path + path_len, name);
|
||||
|
||||
res = f_stat(file_path, &fi);
|
||||
}
|
||||
|
||||
return total_size_sct;
|
||||
}
|
||||
14
bdk/storage/emummc_file_based.h
Normal file
14
bdk/storage/emummc_file_based.h
Normal file
@@ -0,0 +1,14 @@
|
||||
#ifndef _EMUMMC_FILE_BASED_H
|
||||
#define _EMUMMC_FILE_BASED_H
|
||||
|
||||
#include <bdk.h>
|
||||
|
||||
int emummc_storage_file_base_set_partition(u32 partition);
|
||||
int emummc_storage_file_based_init(const char *path);
|
||||
void emummc_storage_file_based_end();
|
||||
int emummc_storage_file_based_write(u32 sector, u32 num_sectors, void *buf);
|
||||
int emummc_storage_file_based_read(u32 sector, u32 num_sectors, void *buf);
|
||||
u32 emummc_storage_file_based_get_total_gpp_size(const char *path);
|
||||
sdmmc_storage_t *emummc_get_storage();
|
||||
|
||||
#endif
|
||||
184
bdk/storage/file_based_storage.c
Normal file
184
bdk/storage/file_based_storage.c
Normal file
@@ -0,0 +1,184 @@
|
||||
#include "file_based_storage.h"
|
||||
#include <libs/fatfs/ff.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
typedef struct{
|
||||
FIL active_file;
|
||||
s32 active_file_idx;
|
||||
char base_path[0x80];
|
||||
u32 part_sz_sct;
|
||||
u32 base_path_len;
|
||||
}file_based_storage_ctxt_t;
|
||||
|
||||
static file_based_storage_ctxt_t ctx;
|
||||
|
||||
int file_based_storage_init(const char *base_path) {
|
||||
ctx.active_file_idx = -0xff;
|
||||
ctx.base_path_len = strlen(base_path);
|
||||
|
||||
strcpy(ctx.base_path, base_path);
|
||||
strcat(ctx.base_path, "00");
|
||||
|
||||
FILINFO fi;
|
||||
if(f_stat(ctx.base_path, &fi) != FR_OK) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(fi.fsize) {
|
||||
ctx.part_sz_sct = fi.fsize >> 9;
|
||||
}else{
|
||||
return 0;
|
||||
}
|
||||
ctx.part_sz_sct = fi.fsize;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void file_based_storage_end() {
|
||||
if(ctx.active_file_idx != -0xff) {
|
||||
f_close(&ctx.active_file);
|
||||
}
|
||||
ctx.active_file_idx = -0xff;
|
||||
ctx.part_sz_sct = 0;
|
||||
}
|
||||
|
||||
static int file_based_storage_change_file(const char *name, s32 idx) {
|
||||
int res;
|
||||
|
||||
if(ctx.active_file_idx == idx){
|
||||
return FR_OK;
|
||||
}
|
||||
|
||||
if(ctx.active_file_idx != -0xff){
|
||||
f_close(&ctx.active_file);
|
||||
ctx.active_file_idx = -0xff;
|
||||
}
|
||||
|
||||
strcpy(ctx.base_path + ctx.base_path_len, name);
|
||||
|
||||
#if FF_FS_READONLY == 1
|
||||
res = f_open(&ctx.active_file, ctx.base_path, FA_READ);
|
||||
#else
|
||||
res = f_open(&ctx.active_file, ctx.base_path, FA_READ | FA_WRITE);
|
||||
#endif
|
||||
|
||||
if(res != FR_OK){
|
||||
return res;
|
||||
}
|
||||
|
||||
ctx.active_file_idx = idx;
|
||||
|
||||
return FR_OK;
|
||||
}
|
||||
|
||||
static int file_based_storage_readwrite_single(u32 sector, u32 num_sectors, void *buf, bool is_write){
|
||||
#if FF_FS_READONLY == 1
|
||||
if(is_write){
|
||||
return FR_WRITE_PROTECTED;
|
||||
}
|
||||
#endif
|
||||
|
||||
int res = f_lseek(&ctx.active_file, (u64)sector << 9);
|
||||
if(res != FR_OK){
|
||||
return res;
|
||||
}
|
||||
|
||||
if(is_write){
|
||||
res = f_write(&ctx.active_file, buf, (u64)num_sectors << 9, NULL);
|
||||
}else{
|
||||
res = f_read(&ctx.active_file, buf, (u64)num_sectors << 9, NULL);
|
||||
}
|
||||
|
||||
if(res != FR_OK){
|
||||
return res;
|
||||
}
|
||||
|
||||
return FR_OK;
|
||||
}
|
||||
|
||||
int file_based_storage_readwrite(u32 sector, u32 num_sectors, void *buf, bool is_write) {
|
||||
#if FF_FS_READONLY == 1
|
||||
if(is_write){
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
if(ctx.part_sz_sct == 0){
|
||||
return 0;
|
||||
}
|
||||
|
||||
int res;
|
||||
|
||||
u32 scts_left = num_sectors;
|
||||
u32 cur_sct = sector;
|
||||
|
||||
while(scts_left){
|
||||
u32 offset = cur_sct % ctx.part_sz_sct;
|
||||
u32 sct_cnt = ctx.part_sz_sct - offset;
|
||||
sct_cnt = MIN(scts_left, sct_cnt);
|
||||
|
||||
u32 file_idx = cur_sct / ctx.part_sz_sct;
|
||||
|
||||
if((s32) file_idx != ctx.active_file_idx) {
|
||||
char name[3];
|
||||
if(file_idx < 10){
|
||||
strcpy(name, "0");
|
||||
}
|
||||
itoa(file_idx, name + strlen(name), 10);
|
||||
|
||||
res = file_based_storage_change_file(name, file_idx);
|
||||
if(res != FR_OK){
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
res = file_based_storage_readwrite_single(offset, sct_cnt, buf + ((u64)(num_sectors - scts_left) << 9), is_write);
|
||||
if(res != FR_OK){
|
||||
return 0;
|
||||
}
|
||||
|
||||
cur_sct += sct_cnt;
|
||||
scts_left -= sct_cnt;
|
||||
}
|
||||
|
||||
f_sync(&ctx.active_file);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int file_based_storage_read(u32 sector, u32 num_sectors, void *buf) {
|
||||
return file_based_storage_readwrite(sector, num_sectors, buf, false);
|
||||
}
|
||||
|
||||
int file_based_storage_write(u32 sector, u32 num_sectors, void *buf) {
|
||||
return file_based_storage_readwrite(sector, num_sectors, buf, true);
|
||||
}
|
||||
|
||||
u32 file_based_storage_get_total_size() {
|
||||
u32 total_size_sct = 0;
|
||||
char file_path[0x80];
|
||||
u32 cur_idx = 0;
|
||||
int res;
|
||||
|
||||
strcpy(file_path, ctx.base_path);
|
||||
strcpy(file_path + ctx.base_path_len, "00");
|
||||
|
||||
FILINFO fi;
|
||||
res = f_stat(file_path, &fi);
|
||||
|
||||
while(res == FR_OK){
|
||||
cur_idx++;
|
||||
total_size_sct += fi.fsize >> 9;
|
||||
|
||||
char name[3] = "0";
|
||||
if(cur_idx >= 10){
|
||||
name[0] = '\0';
|
||||
}
|
||||
itoa(cur_idx, name + strlen(name), 10);
|
||||
|
||||
strcpy(file_path + ctx.base_path_len, name);
|
||||
|
||||
res = f_stat(file_path, &fi);
|
||||
}
|
||||
|
||||
return total_size_sct;
|
||||
}
|
||||
15
bdk/storage/file_based_storage.h
Normal file
15
bdk/storage/file_based_storage.h
Normal file
@@ -0,0 +1,15 @@
|
||||
#ifndef _FILE_BASED_STORAGE_H
|
||||
#define _FILE_BASED_STORAGE_H
|
||||
|
||||
#include <bdk.h>
|
||||
|
||||
|
||||
int file_based_storage_init(const char *base_path);
|
||||
void file_based_storage_end();
|
||||
|
||||
int file_based_storage_read(u32 sector, u32 num_sectors, void *buf);
|
||||
int file_based_storage_write(u32 sector, u32 num_sectors, void *buf);
|
||||
|
||||
u32 file_based_storage_get_total_size();
|
||||
|
||||
#endif
|
||||
39
bdk/storage/mbr_gpt.c
Normal file
39
bdk/storage/mbr_gpt.c
Normal file
@@ -0,0 +1,39 @@
|
||||
#include "mbr_gpt.h"
|
||||
#include <utils/types.h>
|
||||
#include <string.h>
|
||||
|
||||
bool mbr_has_gpt(const mbr_t *mbr){
|
||||
for(u32 i = 0; i < 4; i++){
|
||||
if(mbr->partitions[i].type == 0xee){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void wctombs(const u16 *src, char *dest, u32 len_max){
|
||||
const u16 *cur = src;
|
||||
do{
|
||||
*dest++ = *cur & 0xff;
|
||||
len_max--;
|
||||
}while(*cur++ && len_max);
|
||||
}
|
||||
|
||||
void ctowcs(const char *src, u16 *dest, u32 len_max){
|
||||
const char *cur = src;
|
||||
do{
|
||||
*dest++ = *cur;
|
||||
len_max--;
|
||||
}while(*cur++ && len_max);
|
||||
}
|
||||
|
||||
s32 gpt_get_part_by_name(gpt_t *gpt, const char* name, s32 prev){
|
||||
u16 wc_name[36];
|
||||
ctowcs(name, wc_name, 36);
|
||||
for(s32 i = prev + 1; i < (s32)gpt->header.num_part_ents && i < 128; i++){
|
||||
if(!memcmp(wc_name, gpt->entries[i].name, strlen(name) * 2)){
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
@@ -81,4 +81,10 @@ typedef struct _gpt_t
|
||||
gpt_entry_t entries[128];
|
||||
} gpt_t;
|
||||
|
||||
bool mbr_has_gpt(const mbr_t *mbr);
|
||||
void wctombs(const u16 *src, char *dest, u32 len_max);
|
||||
void ctowcs(const char *src, u16 *dest, u32 len_max);
|
||||
s32 gpt_get_part_by_name(gpt_t *gpt, const char* name, s32 prev);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -17,6 +17,9 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <libs/fatfs/ff.h>
|
||||
#include <stdlib.h>
|
||||
#include <storage/nx_emmc_bis.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <memory_map.h>
|
||||
@@ -26,6 +29,7 @@
|
||||
#include <storage/emmc.h>
|
||||
#include <storage/sd.h>
|
||||
#include <storage/sdmmc.h>
|
||||
#include <storage/emummc_file_based.h>
|
||||
#include <utils/types.h>
|
||||
|
||||
#define BIS_CLUSTER_SECTORS 32
|
||||
@@ -56,6 +60,8 @@ static u32 emu_offset = 0;
|
||||
static emmc_part_t *system_part = NULL;
|
||||
static u32 *cache_lookup_tbl = (u32 *)NX_BIS_LOOKUP_ADDR;
|
||||
static bis_cache_t *bis_cache = (bis_cache_t *)NX_BIS_CACHE_ADDR;
|
||||
static sdmmc_storage_t *emu_storage = NULL;
|
||||
static bool file_based = false;
|
||||
|
||||
static int nx_emmc_bis_write_block(u32 sector, u32 count, void *buff, bool flush)
|
||||
{
|
||||
@@ -95,10 +101,14 @@ static int nx_emmc_bis_write_block(u32 sector, u32 count, void *buff, bool flush
|
||||
return 1; // Encryption error.
|
||||
|
||||
// If not reading from cache, do a regular read and decrypt.
|
||||
if (!emu_offset)
|
||||
if(emu_storage){
|
||||
res = sdmmc_storage_write(emu_storage, emu_offset + system_part->lba_start + sector, count, bis_cache->dma_buff);
|
||||
}else if(file_based){
|
||||
res = emummc_storage_file_based_write(system_part->lba_start + sector, count, bis_cache->dma_buff);
|
||||
}else{
|
||||
res = emmc_part_write(system_part, sector, count, bis_cache->dma_buff);
|
||||
else
|
||||
res = sdmmc_storage_write(&sd_storage, emu_offset + system_part->lba_start + sector, count, bis_cache->dma_buff);
|
||||
}
|
||||
|
||||
if (!res)
|
||||
return 1; // R/W error.
|
||||
|
||||
@@ -155,10 +165,13 @@ static int nx_emmc_bis_read_block_normal(u32 sector, u32 count, void *buff)
|
||||
u32 sector_in_cluster = sector % BIS_CLUSTER_SECTORS;
|
||||
|
||||
// If not reading from cache, do a regular read and decrypt.
|
||||
if (!emu_offset)
|
||||
if(emu_storage){
|
||||
res = sdmmc_storage_read(emu_storage, emu_offset + system_part->lba_start + sector, count, bis_cache->dma_buff);
|
||||
}else if(file_based){
|
||||
res = emummc_storage_file_based_read(system_part->lba_start + sector, count, bis_cache->dma_buff);
|
||||
}else{
|
||||
res = emmc_part_read(system_part, sector, count, bis_cache->dma_buff);
|
||||
else
|
||||
res = sdmmc_storage_read(&sd_storage, emu_offset + system_part->lba_start + sector, count, bis_cache->dma_buff);
|
||||
}
|
||||
if (!res)
|
||||
return 1; // R/W error.
|
||||
|
||||
@@ -212,10 +225,14 @@ static int nx_emmc_bis_read_block_cached(u32 sector, u32 count, void *buff)
|
||||
cache_lookup_tbl[cluster] = bis_cache->top_idx;
|
||||
|
||||
// Read the whole cluster the sector resides in.
|
||||
if (!emu_offset)
|
||||
if (emu_storage){
|
||||
res = sdmmc_storage_read(emu_storage, emu_offset + system_part->lba_start + cluster_sector, BIS_CLUSTER_SECTORS, bis_cache->dma_buff);
|
||||
}else if(file_based){
|
||||
res = emummc_storage_file_based_read(system_part->lba_start + cluster_sector, BIS_CLUSTER_SECTORS, bis_cache->dma_buff);
|
||||
}else{
|
||||
res = emmc_part_read(system_part, cluster_sector, BIS_CLUSTER_SECTORS, bis_cache->dma_buff);
|
||||
else
|
||||
res = sdmmc_storage_read(&sd_storage, emu_offset + system_part->lba_start + cluster_sector, BIS_CLUSTER_SECTORS, bis_cache->dma_buff);
|
||||
}
|
||||
|
||||
if (!res)
|
||||
return 1; // R/W error.
|
||||
|
||||
@@ -292,10 +309,11 @@ int nx_emmc_bis_write(u32 sector, u32 count, void *buff)
|
||||
return 1;
|
||||
}
|
||||
|
||||
void nx_emmc_bis_init(emmc_part_t *part, bool enable_cache, u32 emummc_offset)
|
||||
void nx_emmc_bis_init(emmc_part_t *part, bool enable_cache, sdmmc_storage_t *storage, u32 emummc_offset)
|
||||
{
|
||||
system_part = part;
|
||||
emu_offset = emummc_offset;
|
||||
emu_storage = storage;
|
||||
|
||||
_nx_emmc_bis_cluster_cache_init(enable_cache);
|
||||
|
||||
@@ -318,8 +336,31 @@ void nx_emmc_bis_init(emmc_part_t *part, bool enable_cache, u32 emummc_offset)
|
||||
system_part = NULL;
|
||||
}
|
||||
|
||||
void nx_emmc_bis_init_file_based(emmc_part_t *part, bool enable_cache, const char *base_path){
|
||||
emummc_storage_file_based_init(base_path);
|
||||
file_based = true;
|
||||
|
||||
nx_emmc_bis_init(part, enable_cache, NULL, 0);
|
||||
}
|
||||
|
||||
void nx_emmc_bis_end()
|
||||
{
|
||||
_nx_emmc_bis_flush_cache();
|
||||
|
||||
if(file_based){
|
||||
emummc_storage_file_based_end();
|
||||
}
|
||||
|
||||
system_part = NULL;
|
||||
emu_storage = NULL;
|
||||
emu_offset = 0;
|
||||
file_based = false;
|
||||
}
|
||||
|
||||
sdmmc_storage_t *nx_emmc_bis_get_storage(){
|
||||
if(emu_storage == &emmc_storage){
|
||||
return &emmc_storage;
|
||||
}else{
|
||||
return emmc_part_get_storage();
|
||||
}
|
||||
}
|
||||
@@ -229,7 +229,10 @@ typedef struct _nx_emmc_cal0_t
|
||||
|
||||
int nx_emmc_bis_read(u32 sector, u32 count, void *buff);
|
||||
int nx_emmc_bis_write(u32 sector, u32 count, void *buff);
|
||||
void nx_emmc_bis_init(emmc_part_t *part, bool enable_cache, u32 emummc_offset);
|
||||
// when storage == NULL, use active emummc config, otherwise, access storage at offset
|
||||
void nx_emmc_bis_init(emmc_part_t *part, bool enable_cache, sdmmc_storage_t *storage, u32 emummc_offset);
|
||||
void nx_emmc_bis_init_file_based(emmc_part_t *part, bool enable_cache, const char *base_path);
|
||||
void nx_emmc_bis_end();
|
||||
sdmmc_storage_t *nx_emmc_bis_get_storage();
|
||||
|
||||
#endif
|
||||
|
||||
@@ -199,7 +199,7 @@ bool sd_mount()
|
||||
else
|
||||
{
|
||||
if (!sd_mounted)
|
||||
res = f_mount(&sd_fs, "0:", 1); // Volume 0 is SD.
|
||||
res = f_mount(&sd_fs, "sd:", 1); // Volume 0 is SD.
|
||||
if (res == FR_OK)
|
||||
{
|
||||
sd_mounted = true;
|
||||
@@ -227,7 +227,7 @@ static void _sd_deinit(bool deinit)
|
||||
if (sd_init_done)
|
||||
{
|
||||
if (sd_mounted)
|
||||
f_mount(NULL, "0:", 1); // Volume 0 is SD.
|
||||
f_mount(NULL, "sd:", 1); // Volume 0 is SD.
|
||||
|
||||
if (deinit)
|
||||
{
|
||||
@@ -246,14 +246,30 @@ bool sd_is_gpt()
|
||||
return sd_fs.part_type;
|
||||
}
|
||||
|
||||
|
||||
void *sd_file_read(const char *path, u32 *fsize)
|
||||
{
|
||||
FIL fp;
|
||||
if (!sd_get_card_mounted())
|
||||
return NULL;
|
||||
|
||||
if (f_open(&fp, path, FA_READ) != FR_OK)
|
||||
char *cwd = (char*)malloc(0x200);
|
||||
|
||||
if(f_getcwd(cwd, 0x200) != FR_OK){
|
||||
free(cwd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(f_chdrive("sd:") != FR_OK){
|
||||
free(cwd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (f_open(&fp, path, FA_READ) != FR_OK){
|
||||
f_chdrive(cwd);
|
||||
free(cwd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
u32 size = f_size(&fp);
|
||||
if (fsize)
|
||||
@@ -263,13 +279,17 @@ void *sd_file_read(const char *path, u32 *fsize)
|
||||
|
||||
if (f_read(&fp, buf, size, NULL) != FR_OK)
|
||||
{
|
||||
f_chdrive(cwd);
|
||||
free(buf);
|
||||
free(cwd);
|
||||
f_close(&fp);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
f_chdrive(cwd);
|
||||
f_close(&fp);
|
||||
free(cwd);
|
||||
|
||||
return buf;
|
||||
}
|
||||
@@ -281,13 +301,33 @@ int sd_save_to_file(const void *buf, u32 size, const char *filename)
|
||||
if (!sd_get_card_mounted())
|
||||
return FR_DISK_ERR;
|
||||
|
||||
char *cwd = malloc(0x200);
|
||||
|
||||
res = f_getcwd(cwd, 0x200);
|
||||
|
||||
if(res != FR_OK){
|
||||
free(cwd);
|
||||
return res;
|
||||
}
|
||||
|
||||
res = f_chdrive("sd:");
|
||||
|
||||
if(res != FR_OK){
|
||||
free(cwd);
|
||||
return res;
|
||||
}
|
||||
|
||||
res = f_open(&fp, filename, FA_CREATE_ALWAYS | FA_WRITE);
|
||||
if (res)
|
||||
{
|
||||
EPRINTFARGS("Error (%d) creating file\n%s.\n", res, filename);
|
||||
f_chdrive(cwd);
|
||||
free(cwd);
|
||||
return res;
|
||||
}
|
||||
|
||||
f_chdrive(cwd);
|
||||
free(cwd);
|
||||
f_write(&fp, buf, size, NULL);
|
||||
f_close(&fp);
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2005-2007 Pierre Ossman, All Rights Reserved.
|
||||
* Copyright (c) 2018-2023 CTCaer
|
||||
* Copyright (c) 2018-2025 CTCaer
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -17,11 +17,16 @@
|
||||
#define SD_SEND_RELATIVE_ADDR 3 /* bcr R6 */
|
||||
#define SD_SEND_IF_COND 8 /* bcr [11:0] See below R7 */
|
||||
#define SD_SWITCH_VOLTAGE 11 /* ac R1 */
|
||||
/* Class 2 */
|
||||
#define SD_ADDR_EXT 22 /* ac [5:0] R1 */
|
||||
/* class 10 */
|
||||
#define SD_SWITCH 6 /* adtc [31:0] See below R1 */
|
||||
/* class 5 */
|
||||
#define SD_ERASE_WR_BLK_START 32 /* ac [31:0] data addr R1 */
|
||||
#define SD_ERASE_WR_BLK_END 33 /* ac [31:0] data addr R1 */
|
||||
/* class 11 */
|
||||
#define SD_READ_EXTR_SINGLE 48 /* adtc [31:0] R1 */
|
||||
#define SD_WRITE_EXTR_SINGLE 49 /* adtc [31:0] R1 */
|
||||
|
||||
/* Application commands */
|
||||
#define SD_APP_SET_BUS_WIDTH 6 /* ac [1:0] bus width R1 */
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (c) 2018-2023 CTCaer
|
||||
* Copyright (c) 2018-2025 CTCaer
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
@@ -18,6 +18,7 @@
|
||||
#include <string.h>
|
||||
|
||||
#include <mem/heap.h>
|
||||
#include <mem/mc.h>
|
||||
#include <soc/timer.h>
|
||||
#include <storage/emmc.h>
|
||||
#include <storage/sdmmc.h>
|
||||
@@ -27,14 +28,26 @@
|
||||
#include <memory_map.h>
|
||||
#include <gfx_utils.h>
|
||||
|
||||
//#define SDMMC_DEBUG_PRINT_SD_REGS
|
||||
//#define DPRINTF(...) gfx_printf(__VA_ARGS__)
|
||||
#define DPRINTF(...)
|
||||
|
||||
//#define SDMMC_DEBUG_PRINT_SD_REGS
|
||||
#ifdef SDMMC_DEBUG_PRINT_SD_REGS
|
||||
#define DREGPRINTF(...) gfx_printf(__VA_ARGS__)
|
||||
#else
|
||||
#define DREGPRINTF(...)
|
||||
#endif
|
||||
|
||||
#ifdef BDK_SDMMC_EXTRA_PRINT
|
||||
#define ERROR_EXTRA_PRINTING
|
||||
#endif
|
||||
|
||||
u32 sd_power_cycle_time_start;
|
||||
|
||||
static inline u32 unstuff_bits(const u32 *resp, u32 start, u32 size)
|
||||
{
|
||||
start %= 128;
|
||||
|
||||
const u32 mask = (size < 32 ? 1 << size : 0) - 1;
|
||||
const u32 off = 3 - ((start) / 32);
|
||||
const u32 shft = (start) & 31;
|
||||
@@ -52,7 +65,7 @@ static inline u32 unstuff_bits(const u32 *resp, u32 start, u32 size)
|
||||
static int _sdmmc_storage_check_card_status(u32 res)
|
||||
{
|
||||
//Error mask:
|
||||
//TODO: R1_SWITCH_ERROR can be skipped for certain card types.
|
||||
//!WARN: R1_SWITCH_ERROR is reserved on SD. The card isn't supposed to use it.
|
||||
if (res &
|
||||
(R1_OUT_OF_RANGE | R1_ADDRESS_ERROR | R1_BLOCK_LEN_ERROR |
|
||||
R1_ERASE_SEQ_ERROR | R1_ERASE_PARAM | R1_WP_VIOLATION |
|
||||
@@ -73,7 +86,7 @@ static int _sdmmc_storage_execute_cmd_type1_ex(sdmmc_storage_t *storage, u32 *re
|
||||
if (!sdmmc_execute_cmd(storage->sdmmc, &cmdbuf, NULL, NULL))
|
||||
return 0;
|
||||
|
||||
sdmmc_get_rsp(storage->sdmmc, resp, 4, SDMMC_RSP_TYPE_1);
|
||||
sdmmc_get_cached_rsp(storage->sdmmc, resp, SDMMC_RSP_TYPE_1);
|
||||
if (mask)
|
||||
*resp &= ~mask;
|
||||
|
||||
@@ -105,7 +118,7 @@ static int _sdmmc_storage_get_cid(sdmmc_storage_t *storage)
|
||||
if (!sdmmc_execute_cmd(storage->sdmmc, &cmdbuf, NULL, NULL))
|
||||
return 0;
|
||||
|
||||
sdmmc_get_rsp(storage->sdmmc, (u32 *)storage->raw_cid, 16, SDMMC_RSP_TYPE_2);
|
||||
sdmmc_get_cached_rsp(storage->sdmmc, (u32 *)storage->raw_cid, SDMMC_RSP_TYPE_2);
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -122,7 +135,7 @@ static int _sdmmc_storage_get_csd(sdmmc_storage_t *storage)
|
||||
if (!sdmmc_execute_cmd(storage->sdmmc, &cmdbuf, NULL, NULL))
|
||||
return 0;
|
||||
|
||||
sdmmc_get_rsp(storage->sdmmc, (u32 *)storage->raw_csd, 16, SDMMC_RSP_TYPE_2);
|
||||
sdmmc_get_cached_rsp(storage->sdmmc, (u32 *)storage->raw_csd, SDMMC_RSP_TYPE_2);
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -151,7 +164,7 @@ int sdmmc_storage_execute_vendor_cmd(sdmmc_storage_t *storage, u32 arg)
|
||||
return 0;
|
||||
|
||||
u32 resp;
|
||||
sdmmc_get_rsp(storage->sdmmc, &resp, 4, SDMMC_RSP_TYPE_1);
|
||||
sdmmc_get_cached_rsp(storage->sdmmc, &resp, SDMMC_RSP_TYPE_1);
|
||||
|
||||
resp = -1;
|
||||
u32 timeout = get_tmr_ms() + 1500;
|
||||
@@ -228,6 +241,10 @@ static int _sdmmc_storage_readwrite_ex(sdmmc_storage_t *storage, u32 *blkcnt_out
|
||||
return 0;
|
||||
}
|
||||
|
||||
sdmmc_get_cached_rsp(storage->sdmmc, &tmp, SDMMC_RSP_TYPE_1);
|
||||
if (!_sdmmc_storage_check_card_status(tmp))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -245,6 +262,43 @@ int sdmmc_storage_end(sdmmc_storage_t *storage)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _sdmmc_storage_handle_io_error(sdmmc_storage_t *storage, bool first_reinit)
|
||||
{
|
||||
int res = 0;
|
||||
|
||||
if (storage->sdmmc->id == SDMMC_1 || storage->sdmmc->id == SDMMC_4)
|
||||
{
|
||||
if (storage->sdmmc->id == SDMMC_1)
|
||||
{
|
||||
sd_error_count_increment(SD_ERROR_RW_FAIL);
|
||||
|
||||
if (first_reinit)
|
||||
res = sd_initialize(true);
|
||||
else
|
||||
{
|
||||
res = sd_init_retry(true);
|
||||
if (!res)
|
||||
sd_error_count_increment(SD_ERROR_INIT_FAIL);
|
||||
}
|
||||
}
|
||||
else if (storage->sdmmc->id == SDMMC_4)
|
||||
{
|
||||
emmc_error_count_increment(EMMC_ERROR_RW_FAIL);
|
||||
|
||||
if (first_reinit)
|
||||
res = emmc_initialize(true);
|
||||
else
|
||||
{
|
||||
res = emmc_init_retry(true);
|
||||
if (!res)
|
||||
emmc_error_count_increment(EMMC_ERROR_INIT_FAIL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int _sdmmc_storage_readwrite(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, void *buf, u32 is_write)
|
||||
{
|
||||
u8 *bbuf = (u8 *)buf;
|
||||
@@ -256,6 +310,15 @@ static int _sdmmc_storage_readwrite(sdmmc_storage_t *storage, u32 sector, u32 nu
|
||||
if (!storage->initialized)
|
||||
return 0;
|
||||
|
||||
// Check if out of bounds.
|
||||
if (((u64)sector + num_sectors) > storage->sec_cnt)
|
||||
{
|
||||
#ifdef ERROR_EXTRA_PRINTING
|
||||
EPRINTFARGS("SDMMC%d: Out of bounds!", storage->sdmmc->id + 1);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (sct_total)
|
||||
{
|
||||
u32 blkcnt = 0;
|
||||
@@ -275,51 +338,18 @@ reinit_try:
|
||||
} while (retries);
|
||||
|
||||
// Disk IO failure! Reinit SD/EMMC to a lower speed.
|
||||
if (storage->sdmmc->id == SDMMC_1 || storage->sdmmc->id == SDMMC_4)
|
||||
if (_sdmmc_storage_handle_io_error(storage, first_reinit))
|
||||
{
|
||||
int res = 0;
|
||||
|
||||
if (storage->sdmmc->id == SDMMC_1)
|
||||
{
|
||||
sd_error_count_increment(SD_ERROR_RW_FAIL);
|
||||
|
||||
if (first_reinit)
|
||||
res = sd_initialize(true);
|
||||
else
|
||||
{
|
||||
res = sd_init_retry(true);
|
||||
if (!res)
|
||||
sd_error_count_increment(SD_ERROR_INIT_FAIL);
|
||||
}
|
||||
}
|
||||
else if (storage->sdmmc->id == SDMMC_4)
|
||||
{
|
||||
emmc_error_count_increment(EMMC_ERROR_RW_FAIL);
|
||||
|
||||
if (first_reinit)
|
||||
res = emmc_initialize(true);
|
||||
else
|
||||
{
|
||||
res = emmc_init_retry(true);
|
||||
if (!res)
|
||||
emmc_error_count_increment(EMMC_ERROR_INIT_FAIL);
|
||||
}
|
||||
}
|
||||
|
||||
// Reset values for a retry.
|
||||
blkcnt = 0;
|
||||
retries = 3;
|
||||
first_reinit = false;
|
||||
|
||||
// If successful reinit, restart xfer.
|
||||
if (res)
|
||||
{
|
||||
bbuf = (u8 *)buf;
|
||||
sct_off = sector;
|
||||
sct_total = num_sectors;
|
||||
bbuf = (u8 *)buf;
|
||||
sct_off = sector;
|
||||
sct_total = num_sectors;
|
||||
|
||||
goto reinit_try;
|
||||
}
|
||||
goto reinit_try;
|
||||
}
|
||||
|
||||
// Failed.
|
||||
@@ -393,7 +423,7 @@ static int _mmc_storage_get_op_cond_inner(sdmmc_storage_t *storage, u32 *pout, u
|
||||
if (!sdmmc_execute_cmd(storage->sdmmc, &cmdbuf, NULL, NULL))
|
||||
return 0;
|
||||
|
||||
return sdmmc_get_rsp(storage->sdmmc, pout, 4, SDMMC_RSP_TYPE_3);
|
||||
return sdmmc_get_cached_rsp(storage->sdmmc, pout, SDMMC_RSP_TYPE_3);
|
||||
}
|
||||
|
||||
static int _mmc_storage_get_op_cond(sdmmc_storage_t *storage, u32 power)
|
||||
@@ -477,12 +507,12 @@ static void _mmc_storage_parse_csd(sdmmc_storage_t *storage)
|
||||
{
|
||||
u32 *raw_csd = (u32 *)storage->raw_csd;
|
||||
|
||||
storage->csd.mmca_vsn = unstuff_bits(raw_csd, 122, 4);
|
||||
storage->csd.structure = unstuff_bits(raw_csd, 126, 2);
|
||||
storage->csd.cmdclass = unstuff_bits(raw_csd, 84, 12);
|
||||
storage->csd.mmca_vsn = unstuff_bits(raw_csd, 122, 4);
|
||||
storage->csd.structure = unstuff_bits(raw_csd, 126, 2);
|
||||
storage->csd.cmdclass = unstuff_bits(raw_csd, 84, 12);
|
||||
storage->csd.read_blkbits = unstuff_bits(raw_csd, 80, 4);
|
||||
storage->csd.capacity = (1 + unstuff_bits(raw_csd, 62, 12)) << (unstuff_bits(raw_csd, 47, 3) + 2);
|
||||
storage->sec_cnt = storage->csd.capacity;
|
||||
storage->csd.capacity = (1 + unstuff_bits(raw_csd, 62, 12)) << (unstuff_bits(raw_csd, 47, 3) + 2);
|
||||
storage->sec_cnt = storage->csd.capacity;
|
||||
}
|
||||
|
||||
static void _mmc_storage_parse_ext_csd(sdmmc_storage_t *storage, u8 *buf)
|
||||
@@ -531,12 +561,40 @@ int mmc_storage_get_ext_csd(sdmmc_storage_t *storage, void *buf)
|
||||
return 0;
|
||||
|
||||
u32 tmp = 0;
|
||||
sdmmc_get_rsp(storage->sdmmc, &tmp, 4, SDMMC_RSP_TYPE_1);
|
||||
sdmmc_get_cached_rsp(storage->sdmmc, &tmp, SDMMC_RSP_TYPE_1);
|
||||
_mmc_storage_parse_ext_csd(storage, buf);
|
||||
|
||||
return _sdmmc_storage_check_card_status(tmp);
|
||||
}
|
||||
|
||||
int sd_storage_get_ext_reg(sdmmc_storage_t *storage, u8 fno, u8 page, u16 address, u32 len, void *buf)
|
||||
{
|
||||
if (!(storage->scr.cmds & BIT(2)))
|
||||
return 0;
|
||||
|
||||
sdmmc_cmd_t cmdbuf;
|
||||
|
||||
u32 arg = fno << 27 | page << 18 | address << 9 | (len - 1);
|
||||
|
||||
sdmmc_init_cmd(&cmdbuf, SD_READ_EXTR_SINGLE, arg, SDMMC_RSP_TYPE_1, 0);
|
||||
|
||||
sdmmc_req_t reqbuf;
|
||||
reqbuf.buf = buf;
|
||||
reqbuf.blksize = SDMMC_DAT_BLOCKSIZE;
|
||||
reqbuf.num_sectors = 1;
|
||||
reqbuf.is_write = 0;
|
||||
reqbuf.is_multi_block = 0;
|
||||
reqbuf.is_auto_stop_trn = 0;
|
||||
|
||||
if (!sdmmc_execute_cmd(storage->sdmmc, &cmdbuf, &reqbuf, NULL))
|
||||
return 0;
|
||||
|
||||
u32 tmp = 0;
|
||||
sdmmc_get_cached_rsp(storage->sdmmc, &tmp, SDMMC_RSP_TYPE_1);
|
||||
|
||||
return _sdmmc_storage_check_card_status(tmp);
|
||||
}
|
||||
|
||||
static int _mmc_storage_switch(sdmmc_storage_t *storage, u32 arg)
|
||||
{
|
||||
return _sdmmc_storage_execute_cmd_type1(storage, MMC_SWITCH, arg, 1, R1_SKIP_STATE_CHECK);
|
||||
@@ -813,7 +871,7 @@ void _sd_storage_debug_print_csd(const u32 *raw_csd)
|
||||
gfx_printf("WRITE_BLK_MISALIGN: %X\n", unstuff_bits(raw_csd, 78, 1));
|
||||
gfx_printf("READ_BLK_MISALIGN: %X\n", unstuff_bits(raw_csd, 77, 1));
|
||||
gfx_printf("DSR_IMP: %X\n", unstuff_bits(raw_csd, 76, 1));
|
||||
gfx_printf("C_SIZE: %06X\n", unstuff_bits(raw_csd, 48, 22));
|
||||
gfx_printf("C_SIZE: %06X\n", unstuff_bits(raw_csd, 48, 28)); // CSD 3 (SDUC).
|
||||
|
||||
gfx_printf("ERASE_BLK_LEN: %X\n", unstuff_bits(raw_csd, 46, 1));
|
||||
gfx_printf("SECTOR_SIZE: %02X\n", unstuff_bits(raw_csd, 39, 6));
|
||||
@@ -830,8 +888,8 @@ void _sd_storage_debug_print_csd(const u32 *raw_csd)
|
||||
gfx_printf("TMP_WRITE_PROTECT: %X\n", unstuff_bits(raw_csd, 12, 1));
|
||||
gfx_printf("FILE_FORMAT: %X\n", unstuff_bits(raw_csd, 10, 2));
|
||||
|
||||
gfx_printf("--RSVD-- %02X %02X %X %X %02X %X\n",
|
||||
unstuff_bits(raw_csd, 120, 6), unstuff_bits(raw_csd, 70, 6),
|
||||
gfx_printf("--RSVD-- %02X %X %X %02X %X\n",
|
||||
unstuff_bits(raw_csd, 120, 6),
|
||||
unstuff_bits(raw_csd, 47, 1), unstuff_bits(raw_csd, 29, 2),
|
||||
unstuff_bits(raw_csd, 16, 5), unstuff_bits(raw_csd, 8, 2));
|
||||
}
|
||||
@@ -870,39 +928,39 @@ void _sd_storage_debug_print_ssr(const u8 *raw_ssr)
|
||||
|
||||
gfx_printf("\nSD Status:\n");
|
||||
|
||||
gfx_printf("DAT_BUS_WIDTH: %X\n", unstuff_bits(raw_ssr0, 510 - 384, 2));
|
||||
gfx_printf("SECURED_MODE: %X\n", unstuff_bits(raw_ssr0, 509 - 384, 1));
|
||||
gfx_printf("SECURITY_FUNCTIONS: %02X\n", unstuff_bits(raw_ssr0, 502 - 384, 6));
|
||||
gfx_printf("SD_CARD_TYPE: %04X\n", unstuff_bits(raw_ssr0, 480 - 384, 16));
|
||||
gfx_printf("SZ_OF_PROTECTED_AREA: %08X\n", unstuff_bits(raw_ssr0, 448 - 384, 32));
|
||||
gfx_printf("SPEED_CLASS: %02X\n", unstuff_bits(raw_ssr0, 440 - 384, 8));
|
||||
gfx_printf("PERFORMANCE_MOVE: %02X\n", unstuff_bits(raw_ssr0, 432 - 384, 8));
|
||||
gfx_printf("AU_SIZE: %X\n", unstuff_bits(raw_ssr0, 428 - 384, 4));
|
||||
gfx_printf("ERAZE_SIZE: %04X\n", unstuff_bits(raw_ssr0, 408 - 384, 16));
|
||||
gfx_printf("ERASE_TIMEOUT: %02X\n", unstuff_bits(raw_ssr0, 402 - 384, 6));
|
||||
gfx_printf("ERASE_OFFSET: %X\n", unstuff_bits(raw_ssr0, 400 - 384, 2));
|
||||
gfx_printf("UHS_SPEED_GRADE: %X\n", unstuff_bits(raw_ssr0, 396 - 384, 4));
|
||||
gfx_printf("UHS_AU_SIZE: %X\n", unstuff_bits(raw_ssr0, 392 - 384, 4));
|
||||
gfx_printf("VIDEO_SPEED_CLASS: %02X\n", unstuff_bits(raw_ssr0, 384 - 384, 8));
|
||||
gfx_printf("DAT_BUS_WIDTH: %X\n", unstuff_bits(raw_ssr0, 510, 2));
|
||||
gfx_printf("SECURED_MODE: %X\n", unstuff_bits(raw_ssr0, 509, 1));
|
||||
gfx_printf("SECURITY_FUNCTIONS: %02X\n", unstuff_bits(raw_ssr0, 502, 6));
|
||||
gfx_printf("SD_CARD_TYPE: %04X\n", unstuff_bits(raw_ssr0, 480, 16));
|
||||
gfx_printf("SZ_OF_PROTECTED_AREA: %08X\n", unstuff_bits(raw_ssr0, 448, 32));
|
||||
gfx_printf("SPEED_CLASS: %02X\n", unstuff_bits(raw_ssr0, 440, 8));
|
||||
gfx_printf("PERFORMANCE_MOVE: %02X\n", unstuff_bits(raw_ssr0, 432, 8));
|
||||
gfx_printf("AU_SIZE: %X\n", unstuff_bits(raw_ssr0, 428, 4));
|
||||
gfx_printf("ERAZE_SIZE: %04X\n", unstuff_bits(raw_ssr0, 408, 16));
|
||||
gfx_printf("ERASE_TIMEOUT: %02X\n", unstuff_bits(raw_ssr0, 402, 6));
|
||||
gfx_printf("ERASE_OFFSET: %X\n", unstuff_bits(raw_ssr0, 400, 2));
|
||||
gfx_printf("UHS_SPEED_GRADE: %X\n", unstuff_bits(raw_ssr0, 396, 4));
|
||||
gfx_printf("UHS_AU_SIZE: %X\n", unstuff_bits(raw_ssr0, 392, 4));
|
||||
gfx_printf("VIDEO_SPEED_CLASS: %02X\n", unstuff_bits(raw_ssr0, 384, 8));
|
||||
|
||||
gfx_printf("VSC_AU_SIZE: %03X\n", unstuff_bits(raw_ssr1, 368 - 256, 10));
|
||||
gfx_printf("SUS_ADDR: %06X\n", unstuff_bits(raw_ssr1, 346 - 256, 22));
|
||||
gfx_printf("APP_PERF_CLASS: %X\n", unstuff_bits(raw_ssr1, 336 - 256, 4));
|
||||
gfx_printf("PERFORMANCE_ENHANCE: %02X\n", unstuff_bits(raw_ssr1, 328 - 256, 8));
|
||||
gfx_printf("DISCARD_SUPPORT: %X\n", unstuff_bits(raw_ssr1, 313 - 256, 1));
|
||||
gfx_printf("FULE_SUPPORT: %X\n", unstuff_bits(raw_ssr1, 312 - 256, 1));
|
||||
gfx_printf("VSC_AU_SIZE: %03X\n", unstuff_bits(raw_ssr1, 368, 10));
|
||||
gfx_printf("SUS_ADDR: %06X\n", unstuff_bits(raw_ssr1, 346, 22));
|
||||
gfx_printf("APP_PERF_CLASS: %X\n", unstuff_bits(raw_ssr1, 336, 4));
|
||||
gfx_printf("PERFORMANCE_ENHANCE: %02X\n", unstuff_bits(raw_ssr1, 328, 8));
|
||||
gfx_printf("DISCARD_SUPPORT: %X\n", unstuff_bits(raw_ssr1, 313, 1));
|
||||
gfx_printf("FULE_SUPPORT: %X\n", unstuff_bits(raw_ssr1, 312, 1));
|
||||
|
||||
gfx_printf("--RSVD-- %02X %X %02X %02X %04X\n",
|
||||
unstuff_bits(raw_ssr0, 496 - 384, 6), unstuff_bits(raw_ssr0, 424 - 384, 4),
|
||||
unstuff_bits(raw_ssr1, 378 - 256, 6), unstuff_bits(raw_ssr1, 340 - 256, 6),
|
||||
unstuff_bits(raw_ssr1, 314 - 256, 14));
|
||||
unstuff_bits(raw_ssr0, 496, 6), unstuff_bits(raw_ssr0, 424, 4),
|
||||
unstuff_bits(raw_ssr1, 378, 6), unstuff_bits(raw_ssr1, 340, 6),
|
||||
unstuff_bits(raw_ssr1, 314, 14));
|
||||
|
||||
gfx_printf("VENDOR_1: %06X %08X\n",
|
||||
unstuff_bits(raw_ssr1, 288 - 256, 24), unstuff_bits(raw_ssr1, 256 - 256, 32));
|
||||
unstuff_bits(raw_ssr1, 288, 24), unstuff_bits(raw_ssr1, 256, 32));
|
||||
|
||||
gfx_printf("VENDOR_2: %08X %08X %08X %08X\n",
|
||||
unstuff_bits(raw_ssr2, 224 - 128, 32), unstuff_bits(raw_ssr2, 192 - 128, 32),
|
||||
unstuff_bits(raw_ssr2, 160 - 128, 32), unstuff_bits(raw_ssr2, 128 - 128, 32));
|
||||
unstuff_bits(raw_ssr2, 224, 32), unstuff_bits(raw_ssr2, 192, 32),
|
||||
unstuff_bits(raw_ssr2, 160, 32), unstuff_bits(raw_ssr2, 128, 32));
|
||||
gfx_printf("VENDOR_3: %08X %08X %08X %08X\n",
|
||||
unstuff_bits(raw_ssr3, 96 - 0, 32), unstuff_bits(raw_ssr3, 64, 32),
|
||||
unstuff_bits(raw_ssr3, 32 - 0, 32), unstuff_bits(raw_ssr3, 0, 32));
|
||||
@@ -916,13 +974,19 @@ static int _sd_storage_send_if_cond(sdmmc_storage_t *storage, bool *is_sdsc)
|
||||
sdmmc_init_cmd(&cmdbuf, SD_SEND_IF_COND, vhd_pattern, SDMMC_RSP_TYPE_5, 0);
|
||||
if (!sdmmc_execute_cmd(storage->sdmmc, &cmdbuf, NULL, NULL))
|
||||
{
|
||||
*is_sdsc = 1; // The SD Card is version 1.X
|
||||
return 1;
|
||||
// The SD Card is version 1.X (SDSC) if there is no response.
|
||||
if (storage->sdmmc->error_sts == SDHCI_ERR_INT_CMD_TIMEOUT)
|
||||
{
|
||||
*is_sdsc = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// For Card version >= 2.0, parse results.
|
||||
u32 resp = 0;
|
||||
sdmmc_get_rsp(storage->sdmmc, &resp, 4, SDMMC_RSP_TYPE_5);
|
||||
sdmmc_get_cached_rsp(storage->sdmmc, &resp, SDMMC_RSP_TYPE_5);
|
||||
|
||||
// Check if VHD was accepted and pattern was properly returned.
|
||||
if ((resp & 0xFFF) == vhd_pattern)
|
||||
@@ -948,7 +1012,7 @@ static int _sd_storage_get_op_cond_once(sdmmc_storage_t *storage, u32 *cond, boo
|
||||
if (!_sd_storage_execute_app_cmd(storage, R1_SKIP_STATE_CHECK, is_sdsc ? R1_ILLEGAL_COMMAND : 0, &cmdbuf, NULL, NULL))
|
||||
return 0;
|
||||
|
||||
return sdmmc_get_rsp(storage->sdmmc, cond, 4, SDMMC_RSP_TYPE_3);
|
||||
return sdmmc_get_cached_rsp(storage->sdmmc, cond, SDMMC_RSP_TYPE_3);
|
||||
}
|
||||
|
||||
static int _sd_storage_get_op_cond(sdmmc_storage_t *storage, bool is_sdsc, int bus_uhs_support)
|
||||
@@ -971,7 +1035,7 @@ static int _sd_storage_get_op_cond(sdmmc_storage_t *storage, bool is_sdsc, int b
|
||||
storage->has_sector_access = 1;
|
||||
|
||||
// Check if card supports 1.8V signaling.
|
||||
if (cond & SD_ROCR_S18A && bus_uhs_support)
|
||||
if (cond & SD_ROCR_S18A && bus_uhs_support && !storage->is_low_voltage)
|
||||
{
|
||||
// Switch to 1.8V signaling.
|
||||
if (_sdmmc_storage_execute_cmd_type1(storage, SD_SWITCH_VOLTAGE, 0, 0, R1_STATE_READY))
|
||||
@@ -1015,7 +1079,7 @@ static int _sd_storage_get_rca(sdmmc_storage_t *storage)
|
||||
break;
|
||||
|
||||
u32 resp = 0;
|
||||
if (!sdmmc_get_rsp(storage->sdmmc, &resp, 4, SDMMC_RSP_TYPE_4))
|
||||
if (!sdmmc_get_cached_rsp(storage->sdmmc, &resp, SDMMC_RSP_TYPE_4))
|
||||
break;
|
||||
|
||||
if (resp >> 16)
|
||||
@@ -1046,11 +1110,17 @@ static void _sd_storage_parse_scr(sdmmc_storage_t *storage)
|
||||
storage->scr.sda_vsn = unstuff_bits(resp, 56, 4);
|
||||
storage->scr.bus_widths = unstuff_bits(resp, 48, 4);
|
||||
|
||||
/* If v2.0 is supported, check if Physical Layer Spec v3.0 is supported */
|
||||
// If v2.0 is supported, check if Physical Layer Spec v3.0 is supported.
|
||||
if (storage->scr.sda_vsn == SCR_SPEC_VER_2)
|
||||
storage->scr.sda_spec3 = unstuff_bits(resp, 47, 1);
|
||||
if (storage->scr.sda_spec3)
|
||||
storage->scr.cmds = unstuff_bits(resp, 32, 2);
|
||||
{
|
||||
u8 sda_spec4 = unstuff_bits(resp, 42, 1);
|
||||
if (sda_spec4)
|
||||
storage->scr.cmds = unstuff_bits(resp, 32, 4);
|
||||
else
|
||||
storage->scr.cmds = unstuff_bits(resp, 32, 2);
|
||||
}
|
||||
}
|
||||
|
||||
int sd_storage_get_scr(sdmmc_storage_t *storage, u8 *buf)
|
||||
@@ -1070,9 +1140,9 @@ int sd_storage_get_scr(sdmmc_storage_t *storage, u8 *buf)
|
||||
return 0;
|
||||
|
||||
u32 tmp = 0;
|
||||
sdmmc_get_rsp(storage->sdmmc, &tmp, 4, SDMMC_RSP_TYPE_1);
|
||||
sdmmc_get_cached_rsp(storage->sdmmc, &tmp, SDMMC_RSP_TYPE_1);
|
||||
//Prepare buffer for unstuff_bits
|
||||
for (int i = 0; i < 8; i+=4)
|
||||
for (u32 i = 0; i < 8; i+=4)
|
||||
{
|
||||
storage->raw_scr[i + 3] = buf[i];
|
||||
storage->raw_scr[i + 2] = buf[i + 1];
|
||||
@@ -1101,7 +1171,7 @@ static int _sd_storage_switch_get(sdmmc_storage_t *storage, void *buf)
|
||||
return 0;
|
||||
|
||||
u32 tmp = 0;
|
||||
sdmmc_get_rsp(storage->sdmmc, &tmp, 4, SDMMC_RSP_TYPE_1);
|
||||
sdmmc_get_cached_rsp(storage->sdmmc, &tmp, SDMMC_RSP_TYPE_1);
|
||||
return _sdmmc_storage_check_card_status(tmp);
|
||||
}
|
||||
|
||||
@@ -1125,7 +1195,7 @@ static int _sd_storage_switch(sdmmc_storage_t *storage, void *buf, int mode, int
|
||||
return 0;
|
||||
|
||||
u32 tmp = 0;
|
||||
sdmmc_get_rsp(storage->sdmmc, &tmp, 4, SDMMC_RSP_TYPE_1);
|
||||
sdmmc_get_cached_rsp(storage->sdmmc, &tmp, SDMMC_RSP_TYPE_1);
|
||||
return _sdmmc_storage_check_card_status(tmp);
|
||||
}
|
||||
|
||||
@@ -1241,7 +1311,7 @@ static int _sd_storage_enable_DDR200(sdmmc_storage_t *storage, u8 *buf)
|
||||
|
||||
u16 total_pwr_consumption = ((u16)buf[0] << 8) | buf[1];
|
||||
DPRINTF("[SD] max power: %d mW\n", total_pwr_consumption * 3600 / 1000);
|
||||
storage->card_power_limit = total_pwr_consumption;
|
||||
storage->max_power = total_pwr_consumption;
|
||||
|
||||
if (total_pwr_consumption <= 800)
|
||||
{
|
||||
@@ -1280,7 +1350,7 @@ static int _sd_storage_set_card_bus_speed(sdmmc_storage_t *storage, u32 hs_type,
|
||||
|
||||
u16 total_pwr_consumption = ((u16)buf[0] << 8) | buf[1];
|
||||
DPRINTF("[SD] max power: %d mW\n", total_pwr_consumption * 3600 / 1000);
|
||||
storage->card_power_limit = total_pwr_consumption;
|
||||
storage->max_power = total_pwr_consumption;
|
||||
|
||||
if (total_pwr_consumption <= 800)
|
||||
{
|
||||
@@ -1492,10 +1562,10 @@ static void _sd_storage_parse_ssr(sdmmc_storage_t *storage)
|
||||
_sd_storage_debug_print_ssr(storage->raw_ssr);
|
||||
#endif
|
||||
|
||||
storage->ssr.bus_width = (unstuff_bits(raw_ssr1, 510 - 384, 2) & SD_BUS_WIDTH_4) ? 4 : 1;
|
||||
storage->ssr.protected_size = unstuff_bits(raw_ssr1, 448 - 384, 32);
|
||||
storage->ssr.bus_width = (unstuff_bits(raw_ssr1, 510, 2) & SD_BUS_WIDTH_4) ? 4 : 1;
|
||||
storage->ssr.protected_size = unstuff_bits(raw_ssr1, 448, 32);
|
||||
|
||||
u32 speed_class = unstuff_bits(raw_ssr1, 440 - 384, 8);
|
||||
u32 speed_class = unstuff_bits(raw_ssr1, 440, 8);
|
||||
switch(speed_class)
|
||||
{
|
||||
case 0:
|
||||
@@ -1513,12 +1583,94 @@ static void _sd_storage_parse_ssr(sdmmc_storage_t *storage)
|
||||
storage->ssr.speed_class = speed_class;
|
||||
break;
|
||||
}
|
||||
storage->ssr.uhs_grade = unstuff_bits(raw_ssr1, 396 - 384, 4);
|
||||
storage->ssr.video_class = unstuff_bits(raw_ssr1, 384 - 384, 8);
|
||||
storage->ssr.app_class = unstuff_bits(raw_ssr2, 336 - 256, 4);
|
||||
storage->ssr.uhs_grade = unstuff_bits(raw_ssr1, 396, 4);
|
||||
storage->ssr.video_class = unstuff_bits(raw_ssr1, 384, 8);
|
||||
storage->ssr.app_class = unstuff_bits(raw_ssr2, 336, 4);
|
||||
|
||||
storage->ssr.au_size = unstuff_bits(raw_ssr1, 428 - 384, 4);
|
||||
storage->ssr.uhs_au_size = unstuff_bits(raw_ssr1, 392 - 384, 4);
|
||||
storage->ssr.au_size = unstuff_bits(raw_ssr1, 428, 4);
|
||||
storage->ssr.uhs_au_size = unstuff_bits(raw_ssr1, 392, 4);
|
||||
|
||||
storage->ssr.perf_enhance = unstuff_bits(raw_ssr2, 328, 8);
|
||||
}
|
||||
|
||||
int sd_storage_parse_perf_enhance(sdmmc_storage_t *storage, u8 fno, u8 page, u16 offset, u8 *buf)
|
||||
{
|
||||
// Check status reg for support.
|
||||
storage->ser.cache = (storage->ssr.perf_enhance >> 2) & BIT(0);
|
||||
storage->ser.cmdq = (storage->ssr.perf_enhance >> 3) & 0x1F;
|
||||
|
||||
if (!sd_storage_get_ext_reg(storage, fno, page, offset, 512, buf))
|
||||
{
|
||||
storage->ser.cache_ext = 0;
|
||||
storage->ser.cmdq_ext = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
storage->ser.cache_ext = buf[4] & BIT(0);
|
||||
storage->ser.cmdq_ext = buf[6] & 0x1F;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void _sd_storage_parse_ext_reg(sdmmc_storage_t *storage, u8 *buf, u16 *addr_next)
|
||||
{
|
||||
u16 addr = *addr_next;
|
||||
|
||||
// Address to the next extension.
|
||||
*addr_next = (buf[addr + 41] << 8) | buf[addr + 40];
|
||||
|
||||
u16 sfc = (buf[addr + 1] << 8) | buf[addr];
|
||||
|
||||
u32 reg_sets = buf[addr + 42];
|
||||
|
||||
#ifdef SDMMC_DEBUG_PRINT_SD_REGS
|
||||
for (u32 i = 0; i < reg_sets; i++)
|
||||
{
|
||||
u32 reg_set_addr;
|
||||
memcpy(®_set_addr, &buf[addr + 44 + 4 * i], 4);
|
||||
u16 off = reg_set_addr & 0x1FF;
|
||||
u8 page = reg_set_addr >> 9 & 0xFF;
|
||||
u8 fno = reg_set_addr >> 18 & 0xFF;
|
||||
gfx_printf("Addr: %04X sfc:%02X - fno:%02X, page:%02X, off:%04X\n", addr, sfc, fno, page, off);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Parse Performance Enhance.
|
||||
if (sfc == 2 && reg_sets == 1)
|
||||
{
|
||||
u32 reg_set0_addr;
|
||||
memcpy(®_set0_addr, &buf[addr + 44], 4);
|
||||
u16 off = reg_set0_addr & 0x1FF;
|
||||
u8 page = reg_set0_addr >> 9 & 0xFF;
|
||||
u8 fno = reg_set0_addr >> 18 & 0xFF;
|
||||
|
||||
if (sd_storage_parse_perf_enhance(storage, fno, page, off, buf))
|
||||
storage->ser.valid = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void sd_storage_get_ext_regs(sdmmc_storage_t *storage, u8 *buf)
|
||||
{
|
||||
DREGPRINTF("SD Extension Registers:\n\n");
|
||||
|
||||
if (!(storage->scr.cmds & BIT(2)))
|
||||
{
|
||||
DREGPRINTF("Not Supported!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!sd_storage_get_ext_reg(storage, 0, 0, 0, 512, buf))
|
||||
{
|
||||
DREGPRINTF("Failed to get general info!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
u16 size = (buf[3] << 8) | buf[2];
|
||||
u16 addr_next = 16;
|
||||
u32 num_ext = buf[4];
|
||||
for (u32 i = 0; i < num_ext && addr_next < size; i++)
|
||||
_sd_storage_parse_ext_reg(storage, buf, &addr_next);
|
||||
}
|
||||
|
||||
int sd_storage_get_ssr(sdmmc_storage_t *storage, u8 *buf)
|
||||
@@ -1544,10 +1696,10 @@ int sd_storage_get_ssr(sdmmc_storage_t *storage, u8 *buf)
|
||||
return 0;
|
||||
|
||||
u32 tmp = 0;
|
||||
sdmmc_get_rsp(storage->sdmmc, &tmp, 4, SDMMC_RSP_TYPE_1);
|
||||
sdmmc_get_cached_rsp(storage->sdmmc, &tmp, SDMMC_RSP_TYPE_1);
|
||||
|
||||
// Convert buffer to LE.
|
||||
for (int i = 0; i < SDMMC_CMD_BLOCKSIZE; i += 4)
|
||||
for (u32 i = 0; i < SDMMC_CMD_BLOCKSIZE; i += 4)
|
||||
{
|
||||
storage->raw_ssr[i + 3] = buf[i];
|
||||
storage->raw_ssr[i + 2] = buf[i + 1];
|
||||
@@ -1644,7 +1796,7 @@ void sdmmc_storage_init_wait_sd()
|
||||
int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 bus_width, u32 type)
|
||||
{
|
||||
u32 tmp = 0;
|
||||
int is_sdsc = 0;
|
||||
bool is_sdsc = 0;
|
||||
u8 *buf = (u8 *)SDMMC_UPPER_BUFFER;
|
||||
bool bus_uhs_support = _sdmmc_storage_get_bus_uhs_support(bus_width, type);
|
||||
|
||||
@@ -1789,7 +1941,7 @@ int _gc_storage_custom_cmd(sdmmc_storage_t *storage, void *buf)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!sdmmc_get_rsp(storage->sdmmc, &resp, 4, SDMMC_RSP_TYPE_1))
|
||||
if (!sdmmc_get_cached_rsp(storage->sdmmc, &resp, SDMMC_RSP_TYPE_1))
|
||||
return 0;
|
||||
if (!_sdmmc_storage_check_card_status(resp))
|
||||
return 0;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (c) 2018-2022 CTCaer
|
||||
* Copyright (c) 2018-2025 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,
|
||||
@@ -29,8 +29,13 @@ extern u32 sd_power_cycle_time_start;
|
||||
|
||||
typedef enum _sdmmc_type
|
||||
{
|
||||
MMC_SD = 0,
|
||||
MMC_EMMC = 1,
|
||||
MMC_SD = 0,
|
||||
MMC_EMMC = 1,
|
||||
MMC_EMUMMC_FILE = 2,
|
||||
MMC_EMUMMC_RAW_SD = 3,
|
||||
MMC_EMUMMC_RAW_EMMC = 4,
|
||||
MMC_EMUMMC_FILE_EMMC = 5,
|
||||
MMC_FILE_BASED = 6,
|
||||
|
||||
EMMC_GPP = 0,
|
||||
EMMC_BOOT0 = 1,
|
||||
@@ -174,20 +179,30 @@ typedef struct _sd_ssr
|
||||
u8 app_class;
|
||||
u8 au_size;
|
||||
u8 uhs_au_size;
|
||||
u8 perf_enhance;
|
||||
u32 protected_size;
|
||||
} sd_ssr_t;
|
||||
|
||||
typedef struct _sd_ext_reg_t
|
||||
{
|
||||
u8 cmdq;
|
||||
u8 cmdq_ext;
|
||||
u8 cache;
|
||||
u8 cache_ext;
|
||||
int valid;
|
||||
} sd_ext_reg_t;
|
||||
|
||||
/*! SDMMC storage context. */
|
||||
typedef struct _sdmmc_storage_t
|
||||
{
|
||||
sdmmc_t *sdmmc;
|
||||
u32 rca;
|
||||
int has_sector_access;
|
||||
u32 sec_cnt;
|
||||
int is_low_voltage;
|
||||
u32 partition;
|
||||
int initialized;
|
||||
u32 card_power_limit;
|
||||
int is_low_voltage;
|
||||
int has_sector_access;
|
||||
u32 rca;
|
||||
u32 sec_cnt;
|
||||
u32 partition;
|
||||
u32 max_power;
|
||||
u8 raw_cid[0x10];
|
||||
u8 raw_csd[0x10];
|
||||
u8 raw_scr[8];
|
||||
@@ -197,6 +212,7 @@ typedef struct _sdmmc_storage_t
|
||||
mmc_ext_csd_t ext_csd;
|
||||
sd_scr_t scr;
|
||||
sd_ssr_t ssr;
|
||||
sd_ext_reg_t ser;
|
||||
} sdmmc_storage_t;
|
||||
|
||||
typedef struct _sd_func_modes_t
|
||||
@@ -221,9 +237,13 @@ int sdmmc_storage_vendor_sandisk_report(sdmmc_storage_t *storage, void *buf);
|
||||
|
||||
int mmc_storage_get_ext_csd(sdmmc_storage_t *storage, void *buf);
|
||||
|
||||
int sd_storage_get_ext_reg(sdmmc_storage_t *storage, u8 fno, u8 page, u16 offset, u32 len, void *buf);
|
||||
int sd_storage_get_fmodes(sdmmc_storage_t *storage, u8 *buf, sd_func_modes_t *functions);
|
||||
int sd_storage_get_scr(sdmmc_storage_t *storage, u8 *buf);
|
||||
int sd_storage_get_ssr(sdmmc_storage_t *storage, u8 *buf);
|
||||
u32 sd_storage_get_ssr_au(sdmmc_storage_t *storage);
|
||||
|
||||
void sd_storage_get_ext_regs(sdmmc_storage_t *storage, u8 *buf);
|
||||
int sd_storage_parse_perf_enhance(sdmmc_storage_t *storage, u8 fno, u8 page, u16 offset, u8 *buf);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (c) 2018-2024 CTCaer
|
||||
* Copyright (c) 2018-2025 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,
|
||||
@@ -212,7 +212,7 @@ static void _sdmmc_autocal_execute(sdmmc_t *sdmmc, u32 power)
|
||||
// Use 0x1F mask for all.
|
||||
u8 autocal_pu_status = sdmmc->regs->autocalsts & 0x1F;
|
||||
if (!autocal_pu_status)
|
||||
EPRINTFARGS("SDMMC%d: Comp Pad open!", sdmmc->id + 1);
|
||||
EPRINTFARGS("SDMMC%d: Comp Pad open!", sdmmc->id + 1); // Or resistance is extreme.
|
||||
else if (autocal_pu_status == 0x1F)
|
||||
EPRINTFARGS("SDMMC%d: Comp Pad short to gnd!", sdmmc->id + 1);
|
||||
#endif
|
||||
@@ -394,8 +394,8 @@ int sdmmc_setup_clock(sdmmc_t *sdmmc, u32 type)
|
||||
|
||||
static void _sdmmc_card_clock_enable(sdmmc_t *sdmmc)
|
||||
{
|
||||
// Recalibrate conditionally.
|
||||
if (sdmmc->manual_cal && !sdmmc->powersave_enabled)
|
||||
// Recalibrate periodically if needed.
|
||||
if (sdmmc->periodic_calibration && !sdmmc->powersave_enabled)
|
||||
_sdmmc_autocal_execute(sdmmc, sdmmc_get_io_power(sdmmc));
|
||||
|
||||
if (!sdmmc->powersave_enabled)
|
||||
@@ -414,8 +414,8 @@ static void _sdmmc_card_clock_disable(sdmmc_t *sdmmc)
|
||||
|
||||
void sdmmc_card_clock_powersave(sdmmc_t *sdmmc, int powersave_enable)
|
||||
{
|
||||
// Recalibrate periodically for SDMMC1.
|
||||
if (sdmmc->manual_cal && !powersave_enable && sdmmc->card_clock_enabled)
|
||||
// Recalibrate periodically if needed.
|
||||
if (sdmmc->periodic_calibration && !powersave_enable && sdmmc->card_clock_enabled)
|
||||
_sdmmc_autocal_execute(sdmmc, sdmmc_get_io_power(sdmmc));
|
||||
|
||||
sdmmc->powersave_enabled = powersave_enable;
|
||||
@@ -431,7 +431,7 @@ void sdmmc_card_clock_powersave(sdmmc_t *sdmmc, int powersave_enable)
|
||||
sdmmc->regs->clkcon |= SDHCI_CLOCK_CARD_EN;
|
||||
}
|
||||
|
||||
static int _sdmmc_cache_rsp(sdmmc_t *sdmmc, u32 *rsp, u32 size, u32 type)
|
||||
static int _sdmmc_cache_rsp(sdmmc_t *sdmmc, u32 *rsp, u32 type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
@@ -439,33 +439,14 @@ static int _sdmmc_cache_rsp(sdmmc_t *sdmmc, u32 *rsp, u32 size, u32 type)
|
||||
case SDMMC_RSP_TYPE_3:
|
||||
case SDMMC_RSP_TYPE_4:
|
||||
case SDMMC_RSP_TYPE_5:
|
||||
if (size < 4)
|
||||
return 0;
|
||||
rsp[0] = sdmmc->regs->rspreg0;
|
||||
rsp[0] = sdmmc->regs->rspreg[0];
|
||||
break;
|
||||
|
||||
case SDMMC_RSP_TYPE_2:
|
||||
if (size < 0x10)
|
||||
return 0;
|
||||
// CRC is stripped, so shifting is needed.
|
||||
u32 tempreg;
|
||||
for (int i = 0; i < 4; i++)
|
||||
for (u32 i = 0; i < 4; i++)
|
||||
{
|
||||
switch(i)
|
||||
{
|
||||
case 0:
|
||||
tempreg = sdmmc->regs->rspreg3;
|
||||
break;
|
||||
case 1:
|
||||
tempreg = sdmmc->regs->rspreg2;
|
||||
break;
|
||||
case 2:
|
||||
tempreg = sdmmc->regs->rspreg1;
|
||||
break;
|
||||
case 3:
|
||||
tempreg = sdmmc->regs->rspreg0;
|
||||
break;
|
||||
}
|
||||
u32 tempreg = sdmmc->regs->rspreg[3 - i];
|
||||
rsp[i] = tempreg << 8;
|
||||
|
||||
if (i != 0)
|
||||
@@ -480,7 +461,7 @@ static int _sdmmc_cache_rsp(sdmmc_t *sdmmc, u32 *rsp, u32 size, u32 type)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int sdmmc_get_rsp(sdmmc_t *sdmmc, u32 *rsp, u32 size, u32 type)
|
||||
int sdmmc_get_cached_rsp(sdmmc_t *sdmmc, u32 *rsp, u32 type)
|
||||
{
|
||||
if (!rsp || sdmmc->expected_rsp_type != type)
|
||||
return 0;
|
||||
@@ -491,18 +472,12 @@ int sdmmc_get_rsp(sdmmc_t *sdmmc, u32 *rsp, u32 size, u32 type)
|
||||
case SDMMC_RSP_TYPE_3:
|
||||
case SDMMC_RSP_TYPE_4:
|
||||
case SDMMC_RSP_TYPE_5:
|
||||
if (size < 4)
|
||||
return 0;
|
||||
rsp[0] = sdmmc->rsp[0];
|
||||
break;
|
||||
|
||||
case SDMMC_RSP_TYPE_2:
|
||||
if (size < 16)
|
||||
return 0;
|
||||
rsp[0] = sdmmc->rsp[0];
|
||||
rsp[1] = sdmmc->rsp[1];
|
||||
rsp[2] = sdmmc->rsp[2];
|
||||
rsp[3] = sdmmc->rsp[3];
|
||||
for (u32 i = 0; i < 4; i++)
|
||||
rsp[i] = sdmmc->rsp[i];
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -915,6 +890,7 @@ static void _sdmmc_enable_interrupts(sdmmc_t *sdmmc)
|
||||
sdmmc->regs->errintstsen |= SDHCI_ERR_INT_ALL_EXCEPT_ADMA_BUSPWR;
|
||||
sdmmc->regs->norintsts = sdmmc->regs->norintsts;
|
||||
sdmmc->regs->errintsts = sdmmc->regs->errintsts;
|
||||
sdmmc->error_sts = 0;
|
||||
}
|
||||
|
||||
static void _sdmmc_mask_interrupts(sdmmc_t *sdmmc)
|
||||
@@ -937,8 +913,9 @@ static u32 _sdmmc_check_mask_interrupt(sdmmc_t *sdmmc, u16 *pout, u16 mask)
|
||||
if (norintsts & SDHCI_INT_ERROR)
|
||||
{
|
||||
#ifdef ERROR_EXTRA_PRINTING
|
||||
EPRINTFARGS("SDMMC%d: norintsts %08X, errintsts %08X", sdmmc->id + 1, norintsts, errintsts);
|
||||
EPRINTFARGS("SDMMC%d: intsts %08X, errintsts %08X", sdmmc->id + 1, norintsts, errintsts);
|
||||
#endif
|
||||
sdmmc->error_sts = errintsts;
|
||||
sdmmc->regs->errintsts = errintsts;
|
||||
return SDMMC_MASKINT_ERROR;
|
||||
}
|
||||
@@ -993,7 +970,7 @@ static int _sdmmc_stop_transmission_inner(sdmmc_t *sdmmc, u32 *rsp)
|
||||
if (!result)
|
||||
return 0;
|
||||
|
||||
_sdmmc_cache_rsp(sdmmc, rsp, 4, SDMMC_RSP_TYPE_1);
|
||||
_sdmmc_cache_rsp(sdmmc, rsp, SDMMC_RSP_TYPE_1);
|
||||
|
||||
return _sdmmc_wait_card_busy(sdmmc);
|
||||
}
|
||||
@@ -1003,8 +980,8 @@ int sdmmc_stop_transmission(sdmmc_t *sdmmc, u32 *rsp)
|
||||
if (!sdmmc->card_clock_enabled)
|
||||
return 0;
|
||||
|
||||
// Recalibrate periodically for SDMMC1.
|
||||
if (sdmmc->manual_cal && sdmmc->powersave_enabled)
|
||||
// Recalibrate periodically if needed.
|
||||
if (sdmmc->periodic_calibration && sdmmc->powersave_enabled)
|
||||
_sdmmc_autocal_execute(sdmmc, sdmmc_get_io_power(sdmmc));
|
||||
|
||||
bool should_disable_sd_clock = false;
|
||||
@@ -1120,7 +1097,7 @@ static int _sdmmc_update_sdma(sdmmc_t *sdmmc)
|
||||
|
||||
static int _sdmmc_execute_cmd_inner(sdmmc_t *sdmmc, sdmmc_cmd_t *cmd, sdmmc_req_t *req, u32 *blkcnt_out)
|
||||
{
|
||||
int has_req_or_check_busy = req || cmd->check_busy;
|
||||
bool has_req_or_check_busy = req || cmd->check_busy;
|
||||
if (!_sdmmc_wait_cmd_data_inhibit(sdmmc, has_req_or_check_busy))
|
||||
return 0;
|
||||
|
||||
@@ -1158,13 +1135,13 @@ static int _sdmmc_execute_cmd_inner(sdmmc_t *sdmmc, sdmmc_cmd_t *cmd, sdmmc_req_
|
||||
EPRINTFARGS("SDMMC%d: Transfer error!", sdmmc->id + 1);
|
||||
#endif
|
||||
DPRINTF("rsp(%d): %08X, %08X, %08X, %08X\n", result,
|
||||
sdmmc->regs->rspreg0, sdmmc->regs->rspreg1, sdmmc->regs->rspreg2, sdmmc->regs->rspreg3);
|
||||
sdmmc->regs->rspreg[0], sdmmc->regs->rspreg[1], sdmmc->regs->rspreg[2], sdmmc->regs->rspreg[3]);
|
||||
if (result)
|
||||
{
|
||||
if (cmd->rsp_type)
|
||||
{
|
||||
sdmmc->expected_rsp_type = cmd->rsp_type;
|
||||
result = _sdmmc_cache_rsp(sdmmc, sdmmc->rsp, 0x10, cmd->rsp_type);
|
||||
result = _sdmmc_cache_rsp(sdmmc, sdmmc->rsp, cmd->rsp_type);
|
||||
#ifdef ERROR_EXTRA_PRINTING
|
||||
if (!result)
|
||||
EPRINTFARGS("SDMMC%d: Unknown response type!", sdmmc->id + 1);
|
||||
@@ -1193,10 +1170,10 @@ static int _sdmmc_execute_cmd_inner(sdmmc_t *sdmmc, sdmmc_cmd_t *cmd, sdmmc_req_
|
||||
*blkcnt_out = blkcnt;
|
||||
|
||||
if (req->is_auto_stop_trn)
|
||||
sdmmc->rsp3 = sdmmc->regs->rspreg3;
|
||||
sdmmc->stop_trn_rsp = sdmmc->regs->rspreg[3];
|
||||
}
|
||||
|
||||
if (cmd->check_busy || req)
|
||||
if (has_req_or_check_busy)
|
||||
{
|
||||
result = _sdmmc_wait_card_busy(sdmmc);
|
||||
#ifdef ERROR_EXTRA_PRINTING
|
||||
@@ -1248,7 +1225,7 @@ static void _sdmmc_config_sdmmc1_pads(bool discharge)
|
||||
u32 level = GPIO_LOW;
|
||||
u32 output = GPIO_OUTPUT_DISABLE;
|
||||
|
||||
// Set values for dicharging.
|
||||
// Set values for discharging.
|
||||
if (discharge)
|
||||
{
|
||||
function = GPIO_MODE_GPIO;
|
||||
@@ -1304,7 +1281,7 @@ static int _sdmmc_config_sdmmc1(bool t210b01)
|
||||
// Enable SD card power. Powers LDO2 also.
|
||||
PINMUX_AUX(PINMUX_AUX_DMIC3_CLK) = PINMUX_PULL_DOWN | 2;
|
||||
gpio_direction_output(GPIO_PORT_E, GPIO_PIN_4, GPIO_HIGH);
|
||||
usleep(10000);
|
||||
usleep(10000); // Minimum 3 to 10 ms.
|
||||
|
||||
// Inform IO pads that voltage is gonna be 3.3V.
|
||||
PMC(APBDEV_PMC_PWR_DET_VAL) |= PMC_PWR_DET_33V_SDMMC1;
|
||||
@@ -1385,7 +1362,7 @@ int sdmmc_init(sdmmc_t *sdmmc, u32 id, u32 power, u32 bus_width, u32 type)
|
||||
if (sdmmc->t210b01)
|
||||
vref_sel = 0;
|
||||
else
|
||||
sdmmc->manual_cal = 1;
|
||||
sdmmc->periodic_calibration = 1;
|
||||
break;
|
||||
|
||||
case SDMMC_2:
|
||||
@@ -1419,6 +1396,8 @@ int sdmmc_init(sdmmc_t *sdmmc, u32 id, u32 power, u32 bus_width, u32 type)
|
||||
if (!_sdmmc_autocal_config_offset(sdmmc, power))
|
||||
return 0;
|
||||
|
||||
_sdmmc_commit_changes(sdmmc);
|
||||
|
||||
// Calibrate pads.
|
||||
_sdmmc_autocal_execute(sdmmc, power);
|
||||
|
||||
@@ -1506,8 +1485,8 @@ int sdmmc_execute_cmd(sdmmc_t *sdmmc, sdmmc_cmd_t *cmd, sdmmc_req_t *req, u32 *b
|
||||
if (!sdmmc->card_clock_enabled)
|
||||
return 0;
|
||||
|
||||
// Recalibrate periodically for SDMMC1.
|
||||
if (sdmmc->manual_cal && sdmmc->powersave_enabled)
|
||||
// Recalibrate periodically if needed.
|
||||
if (sdmmc->periodic_calibration && sdmmc->powersave_enabled)
|
||||
_sdmmc_autocal_execute(sdmmc, sdmmc_get_io_power(sdmmc));
|
||||
|
||||
int should_disable_sd_clock = 0;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (c) 2018-2023 CTCaer
|
||||
* Copyright (c) 2018-2025 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,
|
||||
@@ -101,6 +101,7 @@
|
||||
#define SDHCI_CMD_TYPE_SUSPEND (1U << 6)
|
||||
#define SDHCI_CMD_TYPE_RESUME (2U << 6)
|
||||
#define SDHCI_CMD_TYPE_ABORT (3U << 6)
|
||||
#define SDHCI_CMD_SPI_CS_LOW BIT(7)
|
||||
#define SDHCI_CMD_IDX(cmd) ((cmd) << 8)
|
||||
|
||||
|
||||
@@ -170,10 +171,10 @@
|
||||
#define SDHCI_INT_ERROR BIT(15)
|
||||
|
||||
/*! SDMMC error interrupt status and control. 0x32/0x36. */
|
||||
#define SDHCI_ERR_INT_TIMEOUT BIT(0)
|
||||
#define SDHCI_ERR_INT_CRC BIT(1)
|
||||
#define SDHCI_ERR_INT_END_BIT BIT(2)
|
||||
#define SDHCI_ERR_INT_INDEX BIT(3)
|
||||
#define SDHCI_ERR_INT_CMD_TIMEOUT BIT(0)
|
||||
#define SDHCI_ERR_INT_CMD_CRC BIT(1)
|
||||
#define SDHCI_ERR_INT_CMD_END_BIT BIT(2)
|
||||
#define SDHCI_ERR_INT_CMD_INDEX BIT(3)
|
||||
#define SDHCI_ERR_INT_DATA_TIMEOUT BIT(4)
|
||||
#define SDHCI_ERR_INT_DATA_CRC BIT(5)
|
||||
#define SDHCI_ERR_INT_DATA_END_BIT BIT(6)
|
||||
@@ -190,8 +191,8 @@
|
||||
#define SDHCI_ERR_INT_ALL_EXCEPT_ADMA_BUSPWR \
|
||||
(SDHCI_ERR_INT_AUTO_CMD12 | SDHCI_ERR_INT_DATA_END_BIT | \
|
||||
SDHCI_ERR_INT_DATA_CRC | SDHCI_ERR_INT_DATA_TIMEOUT | \
|
||||
SDHCI_ERR_INT_INDEX | SDHCI_ERR_INT_END_BIT | \
|
||||
SDHCI_ERR_INT_CRC | SDHCI_ERR_INT_TIMEOUT)
|
||||
SDHCI_ERR_INT_CMD_INDEX | SDHCI_ERR_INT_CMD_END_BIT | \
|
||||
SDHCI_ERR_INT_CMD_CRC | SDHCI_ERR_INT_CMD_TIMEOUT)
|
||||
|
||||
/*! Host Capability 1. 0x40. */
|
||||
#define SDHCI_CAP_TM_CLK_FREQ_MASK 0x3F
|
||||
@@ -285,14 +286,15 @@ typedef struct _sdmmc_t
|
||||
u32 card_clock;
|
||||
u32 clock_stopped;
|
||||
int powersave_enabled;
|
||||
int manual_cal;
|
||||
int periodic_calibration;
|
||||
int card_clock_enabled;
|
||||
int venclkctl_set;
|
||||
u32 venclkctl_tap;
|
||||
u32 expected_rsp_type;
|
||||
u32 dma_addr_next;
|
||||
u32 rsp[4];
|
||||
u32 rsp3;
|
||||
u32 stop_trn_rsp;
|
||||
u32 error_sts;
|
||||
int t210b01;
|
||||
} sdmmc_t;
|
||||
|
||||
@@ -323,7 +325,7 @@ void sdmmc_save_tap_value(sdmmc_t *sdmmc);
|
||||
void sdmmc_setup_drv_type(sdmmc_t *sdmmc, u32 type);
|
||||
int sdmmc_setup_clock(sdmmc_t *sdmmc, u32 type);
|
||||
void sdmmc_card_clock_powersave(sdmmc_t *sdmmc, int powersave_enable);
|
||||
int sdmmc_get_rsp(sdmmc_t *sdmmc, u32 *rsp, u32 size, u32 type);
|
||||
int sdmmc_get_cached_rsp(sdmmc_t *sdmmc, u32 *rsp, u32 type);
|
||||
int sdmmc_tuning_execute(sdmmc_t *sdmmc, u32 type, u32 cmd);
|
||||
int sdmmc_stop_transmission(sdmmc_t *sdmmc, u32 *rsp);
|
||||
bool sdmmc_get_sd_inserted();
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (c) 2018-2023 CTCaer
|
||||
* Copyright (c) 2018-2025 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,
|
||||
@@ -39,10 +39,7 @@ typedef struct _t210_sdmmc_t
|
||||
/* 0x08 */ vu32 argument;
|
||||
/* 0x0C */ vu16 trnmod;
|
||||
/* 0x0E */ vu16 cmdreg;
|
||||
/* 0x10 */ vu32 rspreg0;
|
||||
/* 0x14 */ vu32 rspreg1;
|
||||
/* 0x18 */ vu32 rspreg2;
|
||||
/* 0x1C */ vu32 rspreg3;
|
||||
/* 0x10 */ vu32 rspreg[4];
|
||||
/* 0x20 */ vu32 bdata; // Buffer data port.
|
||||
/* 0x24 */ vu32 prnsts;
|
||||
/* 0x28 */ vu8 hostctl;
|
||||
|
||||
@@ -99,7 +99,7 @@ typedef struct _usb_cfg_descr_t
|
||||
u8 bConfigurationValue; // Value of this configuration (1 based).
|
||||
u8 iConfiguration; // Index of String Descriptor describing the configuration.
|
||||
u8 bmAttributes; // Configuration characteristics.
|
||||
u8 bMaxPower; // Maximum power consumed by this configuration.
|
||||
u8 bMaxPower; // Maximum power consumed by this configuration. In 2mA (usb2) or 8mA (usb3).
|
||||
} __attribute__((packed)) usb_cfg_descr_t;
|
||||
|
||||
/* Interface descriptor structure */
|
||||
|
||||
@@ -19,6 +19,9 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <storage/emmc.h>
|
||||
#include <storage/emummc_file_based.h>
|
||||
#include <storage/file_based_storage.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <usb/usbd.h>
|
||||
@@ -495,8 +498,18 @@ static int _scsi_read(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt)
|
||||
}
|
||||
|
||||
// Do the SDMMC read.
|
||||
if (!sdmmc_storage_read(ums->lun.storage, ums->lun.offset + lba_offset, amount, sdmmc_buf))
|
||||
amount = 0;
|
||||
if(ums->lun.storage){
|
||||
if (!sdmmc_storage_read(ums->lun.storage, ums->lun.offset + lba_offset, amount, sdmmc_buf))
|
||||
amount = 0;
|
||||
}else if (ums->lun.type == MMC_FILE_BASED) {
|
||||
if(!file_based_storage_read(ums->lun.offset + lba_offset, amount, sdmmc_buf)){
|
||||
amount = 0;
|
||||
}
|
||||
}else{
|
||||
if(!emummc_storage_file_based_read(ums->lun.offset + lba_offset, amount, sdmmc_buf)){
|
||||
amount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Wait for the async USB transfer to finish.
|
||||
if (!first_read)
|
||||
@@ -650,9 +663,19 @@ static int _scsi_write(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt)
|
||||
goto empty_write;
|
||||
|
||||
// Perform the write.
|
||||
if (!sdmmc_storage_write(ums->lun.storage, ums->lun.offset + lba_offset,
|
||||
amount >> UMS_DISK_LBA_SHIFT, (u8 *)bulk_ctxt->bulk_out_buf))
|
||||
amount = 0;
|
||||
if(ums->lun.storage){
|
||||
if (!sdmmc_storage_write(ums->lun.storage, ums->lun.offset + lba_offset,
|
||||
amount >> UMS_DISK_LBA_SHIFT, (u8 *)bulk_ctxt->bulk_out_buf))
|
||||
amount = 0;
|
||||
}else if(ums->lun.type == MMC_FILE_BASED){
|
||||
if(!file_based_storage_write(ums->lun.offset + lba_offset, amount >> UMS_DISK_LBA_SHIFT, (u8*)bulk_ctxt->bulk_out_buf)){
|
||||
amount = 0;
|
||||
}
|
||||
}else{
|
||||
if(!emummc_storage_file_based_write(ums->lun.offset + lba_offset, amount >> UMS_DISK_LBA_SHIFT, (u8*)bulk_ctxt->bulk_out_buf)){
|
||||
amount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
DPRINTF("file write %X @ %X\n", amount, lba_offset);
|
||||
|
||||
@@ -722,8 +745,18 @@ static int _scsi_verify(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!sdmmc_storage_read(ums->lun.storage, ums->lun.offset + lba_offset, amount, bulk_ctxt->bulk_in_buf))
|
||||
amount = 0;
|
||||
if(ums->lun.storage){
|
||||
if (!sdmmc_storage_read(ums->lun.storage, ums->lun.offset + lba_offset, amount, bulk_ctxt->bulk_in_buf))
|
||||
amount = 0;
|
||||
}else if(ums->lun.type == MMC_FILE_BASED){
|
||||
if(!file_based_storage_read(ums->lun.offset + lba_offset, amount, bulk_ctxt->bulk_in_buf)){
|
||||
amount = 0;
|
||||
}
|
||||
}else{
|
||||
if(!emummc_storage_file_based_read(ums->lun.offset + lba_offset, amount, bulk_ctxt->bulk_in_buf)){
|
||||
amount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
DPRINTF("File read %X @ %X\n", amount, lba_offset);
|
||||
|
||||
@@ -756,8 +789,12 @@ static int _scsi_inquiry(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt)
|
||||
buf[3] = 20; // Additional length.
|
||||
|
||||
buf += 4;
|
||||
s_printf((char *)buf, "%04X%s",
|
||||
ums->lun.storage->cid.serial, ums->lun.type == MMC_SD ? " SD " : " eMMC ");
|
||||
if(ums->lun.storage){
|
||||
s_printf((char *)buf, "%04X%s",
|
||||
ums->lun.storage->cid.serial, ums->lun.type == MMC_SD ? " SD " : " eMMC ");
|
||||
}else{
|
||||
strcpy((char*)buf, "0000 emuMMC");
|
||||
}
|
||||
|
||||
switch (ums->lun.partition)
|
||||
{
|
||||
@@ -1861,7 +1898,7 @@ int usb_device_gadget_ums(usb_ctxt_t *usbs)
|
||||
if (usbs->type == MMC_SD)
|
||||
{
|
||||
sd_end();
|
||||
if (!sd_mount())
|
||||
if (!sd_mount() && !sd_get_card_initialized())
|
||||
{
|
||||
ums.set_text(ums.label, "#FFDD00 Failed to init SD!#");
|
||||
res = 1;
|
||||
@@ -1871,9 +1908,50 @@ int usb_device_gadget_ums(usb_ctxt_t *usbs)
|
||||
|
||||
ums.lun.sdmmc = &sd_sdmmc;
|
||||
ums.lun.storage = &sd_storage;
|
||||
}else if(usbs->type == MMC_EMUMMC_FILE){
|
||||
// sd must be already mounted and emummc file based initialized
|
||||
if(!sd_get_card_mounted()){
|
||||
ums.set_text(ums.label, "#FFDD00 Failed to init SD!#");
|
||||
res = 1;
|
||||
goto init_fail;
|
||||
}
|
||||
ums.lun.storage = NULL;
|
||||
ums.lun.sdmmc = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
else if(usbs->type == MMC_EMUMMC_RAW_EMMC){
|
||||
if (!emmc_initialize(false))
|
||||
{
|
||||
ums.set_text(ums.label, "#FFDD00 Failed to init eMMC!#");
|
||||
res = 1;
|
||||
goto init_fail;
|
||||
}
|
||||
emmc_set_partition(EMMC_GPP);
|
||||
|
||||
ums.lun.sdmmc = &emmc_sdmmc;
|
||||
ums.lun.storage = &emmc_storage;
|
||||
}else if(usbs->type == MMC_EMUMMC_RAW_SD){
|
||||
if (!sd_initialize(false))
|
||||
{
|
||||
ums.set_text(ums.label, "#FFDD00 Failed to init SD!#");
|
||||
res = 1;
|
||||
goto init_fail;
|
||||
}
|
||||
|
||||
ums.lun.sdmmc = &emmc_sdmmc;
|
||||
ums.lun.storage = &emmc_storage;
|
||||
}else if(usbs->type == MMC_EMUMMC_FILE_EMMC){
|
||||
if(!emmc_get_mounted()){
|
||||
ums.set_text(ums.label, "#FFDD00 Failed to init eMMC!#");
|
||||
res = 1;
|
||||
goto init_fail;
|
||||
}
|
||||
ums.lun.storage = NULL;
|
||||
ums.lun.sdmmc = NULL;
|
||||
}else if(usbs->type == MMC_FILE_BASED){
|
||||
// file based must be initialized at this point
|
||||
ums.lun.storage = NULL;
|
||||
ums.lun.sdmmc = NULL;
|
||||
} else{
|
||||
if (!emmc_initialize(false))
|
||||
{
|
||||
ums.set_text(ums.label, "#FFDD00 Failed to init eMMC!#");
|
||||
@@ -1902,10 +1980,27 @@ int usb_device_gadget_ums(usb_ctxt_t *usbs)
|
||||
// If partition sectors are not set get them from hardware.
|
||||
if (!ums.lun.num_sectors)
|
||||
{
|
||||
if (usbs->type == MMC_EMMC && (ums.lun.partition - 1)) // eMMC BOOT0/1.
|
||||
ums.lun.num_sectors = emmc_storage.ext_csd.boot_mult << 8;
|
||||
else
|
||||
ums.lun.num_sectors = ums.lun.storage->sec_cnt; // eMMC GPP or SD.
|
||||
switch(usbs->type){
|
||||
case MMC_EMMC:
|
||||
if(ums.lun.partition - 1){
|
||||
ums.lun.num_sectors = emmc_storage.ext_csd.boot_mult << 8;
|
||||
}else{
|
||||
ums.lun.num_sectors = ums.lun.storage->sec_cnt;
|
||||
}
|
||||
break;
|
||||
case MMC_SD:
|
||||
ums.lun.num_sectors = ums.lun.storage->sec_cnt;
|
||||
break;
|
||||
case MMC_EMUMMC_FILE:
|
||||
case MMC_EMUMMC_FILE_EMMC:
|
||||
case MMC_EMUMMC_RAW_SD:
|
||||
case MMC_EMUMMC_RAW_EMMC:
|
||||
ums.set_text(ums.label, "#FFDD00 No sector count set for emuMMC!#");
|
||||
break;
|
||||
case MMC_FILE_BASED:
|
||||
ums.set_text(ums.label, "#FFDD00 No sector count set for emuSD!#");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
do
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2024 CTCaer
|
||||
* Copyright (c) 2018-2025 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,
|
||||
@@ -82,12 +82,12 @@ dirlist_t *dirlist(const char *directory, const char *pattern, bool includeHidde
|
||||
// Terminate name list.
|
||||
dir_entries->name[k] = NULL;
|
||||
|
||||
// Reorder ini files by ASCII ordering.
|
||||
// Reorder ini files Alphabetically.
|
||||
for (u32 i = 0; i < k - 1 ; i++)
|
||||
{
|
||||
for (u32 j = i + 1; j < k; j++)
|
||||
{
|
||||
if (strcmp(dir_entries->name[i], dir_entries->name[j]) > 0)
|
||||
if (strcasecmp(dir_entries->name[i], dir_entries->name[j]) > 0)
|
||||
{
|
||||
char *tmp = dir_entries->name[i];
|
||||
dir_entries->name[i] = dir_entries->name[j];
|
||||
|
||||
@@ -172,14 +172,14 @@ parse_padding_dec:
|
||||
_s_putc(c);
|
||||
break;
|
||||
|
||||
case 's':
|
||||
_s_puts(va_arg(ap, char *), fill, fcnt);
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
_s_putn(va_arg(ap, u32), 10, fill, fcnt);
|
||||
break;
|
||||
|
||||
case 's':
|
||||
_s_puts(va_arg(ap, char *), fill, fcnt);
|
||||
break;
|
||||
|
||||
case 'p':
|
||||
case 'P':
|
||||
case 'x':
|
||||
@@ -261,14 +261,14 @@ parse_padding_dec:
|
||||
_s_putc(c);
|
||||
break;
|
||||
|
||||
case 's':
|
||||
_s_puts(va_arg(ap, char *), fill, fcnt);
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
_s_putn(va_arg(ap, u32), 10, fill, fcnt);
|
||||
break;
|
||||
|
||||
case 's':
|
||||
_s_puts(va_arg(ap, char *), fill, fcnt);
|
||||
break;
|
||||
|
||||
case 'p':
|
||||
case 'P':
|
||||
case 'x':
|
||||
|
||||
@@ -105,6 +105,9 @@ typedef unsigned long uptr;
|
||||
#define likely(x) (__builtin_expect((x) != 0, 1))
|
||||
#define unlikely(x) (__builtin_expect((x) != 0, 0))
|
||||
|
||||
#define XSTR(a) STR(a)
|
||||
#define STR(a) #a
|
||||
|
||||
/* Bootloader/Nyx */
|
||||
#define BOOT_CFG_AUTOBOOT_EN BIT(0)
|
||||
#define BOOT_CFG_FROM_LAUNCH BIT(1)
|
||||
@@ -126,7 +129,12 @@ typedef enum _nyx_ums_type
|
||||
NYX_UMS_EMMC_GPP,
|
||||
NYX_UMS_EMUMMC_BOOT0,
|
||||
NYX_UMS_EMUMMC_BOOT1,
|
||||
NYX_UMS_EMUMMC_GPP
|
||||
NYX_UMS_EMUMMC_GPP,
|
||||
NYX_UMS_BOOT_STRG_SD,
|
||||
NYX_UMS_BOOT_STRG_BOOT1,
|
||||
NYX_UMS_BOOT_STRG_BOOT1_1MB,
|
||||
NYX_UMS_BOOT_STRG_GPP,
|
||||
NYX_UMS_EMUSD,
|
||||
} nyx_ums_type;
|
||||
|
||||
typedef struct __attribute__((__packed__)) _boot_cfg_t
|
||||
|
||||
@@ -1,20 +1,21 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (c) 2018-2024 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/>.
|
||||
*/
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (c) 2018-2025 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 <storage/boot_storage.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <mem/heap.h>
|
||||
@@ -136,7 +137,7 @@ long strtol(const char *nptr, char **endptr, register int base)
|
||||
} else if (c == '+')
|
||||
c = *s++;
|
||||
if ((base == 0 || base == 16) &&
|
||||
c == '0' && (*s == 'x' || *s == 'X')) {
|
||||
c == '0' && (*s == 'x' || *s == 'X')) {
|
||||
c = s[1];
|
||||
s += 2;
|
||||
base = 16;
|
||||
@@ -239,6 +240,21 @@ u32 crc32_calc(u32 crc, const u8 *buf, u32 len)
|
||||
return ~crc;
|
||||
}
|
||||
|
||||
int qsort_compare_int(const void *a, const void *b)
|
||||
{
|
||||
return (*(int *)a - *(int *)b);
|
||||
}
|
||||
|
||||
int qsort_compare_char(const void *a, const void *b)
|
||||
{
|
||||
return strcmp(*(const char **)a, *(const char **)b);
|
||||
}
|
||||
|
||||
int qsort_compare_char_case(const void *a, const void *b)
|
||||
{
|
||||
return strcasecmp(*(const char **)a, *(const char **)b);
|
||||
}
|
||||
|
||||
void panic(u32 val)
|
||||
{
|
||||
// Set panic code.
|
||||
@@ -258,6 +274,7 @@ void power_set_state(power_state_t state)
|
||||
u8 reg;
|
||||
|
||||
// Unmount and power down sd card.
|
||||
boot_storage_end();
|
||||
sd_end();
|
||||
|
||||
// De-initialize and power down various hardware.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (c) 2018-2024 CTCaer
|
||||
* Copyright (c) 2018-2025 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,
|
||||
@@ -89,6 +89,10 @@ int atoi(const char *nptr);
|
||||
void reg_write_array(u32 *base, const reg_cfg_t *cfg, u32 num_cfg);
|
||||
u32 crc32_calc(u32 crc, const u8 *buf, u32 len);
|
||||
|
||||
int qsort_compare_int(const void *a, const void *b);
|
||||
int qsort_compare_char(const void *a, const void *b);
|
||||
int qsort_compare_char_case(const void *a, const void *b);
|
||||
|
||||
void panic(u32 val);
|
||||
void power_set_state(power_state_t state);
|
||||
void power_set_state_ex(void *param);
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <storage/sd.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <bdk.h>
|
||||
@@ -232,20 +233,19 @@ void print_sdcard_info()
|
||||
sd_storage.ssr.app_class, sd_storage.csd.write_protect,
|
||||
sd_errors[0], sd_errors[1], sd_errors[2]); // SD_ERROR_INIT_FAIL, SD_ERROR_RW_FAIL, SD_ERROR_RW_RETRY.
|
||||
|
||||
int res = f_mount(&sd_fs, "", 1);
|
||||
if (!res)
|
||||
if (sd_mount())
|
||||
{
|
||||
gfx_puts("Acquiring FAT volume info...\n\n");
|
||||
f_getfree("", &sd_fs.free_clst, NULL);
|
||||
f_getfree("sd:", &sd_fs.free_clst, NULL);
|
||||
gfx_printf("%kFound %s volume:%k\n Free: %d MiB\n Cluster: %d KiB\n",
|
||||
TXT_CLR_CYAN_L, sd_fs.fs_type == FS_EXFAT ? "exFAT" : "FAT32", TXT_CLR_DEFAULT,
|
||||
sd_fs.free_clst * sd_fs.csize >> SECTORS_TO_MIB_COEFF, (sd_fs.csize > 1) ? (sd_fs.csize >> 1) : 512);
|
||||
f_mount(NULL, "", 1);
|
||||
sd_end();
|
||||
}
|
||||
else
|
||||
{
|
||||
EPRINTFARGS("Failed to mount SD card (FatFS Error %d).\n"
|
||||
"Make sure that a FAT partition exists..", res);
|
||||
EPRINTF("Failed to mount SD card.\n"
|
||||
"Make sure that a FAT partition exists..");
|
||||
}
|
||||
|
||||
sd_end();
|
||||
|
||||
@@ -1,224 +0,0 @@
|
||||
/*
|
||||
* Atmosphère Fusée Secondary Storage (Package3) parser.
|
||||
*
|
||||
* Copyright (c) 2019-2024 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 <bdk.h>
|
||||
|
||||
#include "fss.h"
|
||||
#include "hos.h"
|
||||
#include "../config.h"
|
||||
#include <libs/fatfs/ff.h>
|
||||
#include "../storage/emummc.h"
|
||||
|
||||
//#define DPRINTF(...) gfx_printf(__VA_ARGS__)
|
||||
#define DPRINTF(...)
|
||||
|
||||
extern hekate_config h_cfg;
|
||||
|
||||
extern bool is_ipl_updated(void *buf, const char *path, bool force);
|
||||
|
||||
// FSS0 Magic and Meta header offset.
|
||||
#define FSS0_MAGIC 0x30535346
|
||||
#define FSS0_META_OFFSET 0x4
|
||||
#define FSS0_VERSION_0_17_0 0x110000
|
||||
|
||||
// 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.
|
||||
#define CNT_TYPE_EXF 11 // Exosphere Mariko fatal payload.
|
||||
#define CNT_TYPE_TKG 12 // Tsec Keygen.
|
||||
|
||||
// FSS0 Content Flags.
|
||||
#define CNT_FLAG0_EXPERIMENTAL BIT(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 _fss_update_r2p()
|
||||
{
|
||||
u8 *r2p_payload = sd_file_read("atmosphere/reboot_payload.bin", NULL);
|
||||
|
||||
is_ipl_updated(r2p_payload, "atmosphere/reboot_payload.bin", h_cfg.updater2p ? true : false);
|
||||
|
||||
free(r2p_payload);
|
||||
}
|
||||
|
||||
int parse_fss(launch_ctxt_t *ctxt, const char *path)
|
||||
{
|
||||
FIL fp;
|
||||
|
||||
bool stock = false;
|
||||
bool experimental = false;
|
||||
|
||||
// Skip if stock and Exosphere and warmboot are not needed.
|
||||
bool pkg1_old = ctxt->pkg1_id->kb <= HOS_KB_VERSION_620; // Should check if t210b01?
|
||||
bool emummc_disabled = !emu_cfg.enabled || h_cfg.emummc_force_disable;
|
||||
|
||||
LIST_FOREACH_ENTRY(ini_kv_t, kv, &ctxt->cfg->kvs, link)
|
||||
{
|
||||
if (!strcmp("stock", kv->key))
|
||||
if (kv->val[0] == '1')
|
||||
stock = true;
|
||||
|
||||
if (!strcmp("fss0experimental", kv->key))
|
||||
if (kv->val[0] == '1')
|
||||
experimental = true;
|
||||
}
|
||||
|
||||
#ifdef HOS_MARIKO_STOCK_SECMON
|
||||
if (stock && emummc_disabled && (pkg1_old || h_cfg.t210b01))
|
||||
return 1;
|
||||
#else
|
||||
if (stock && emummc_disabled && pkg1_old)
|
||||
return 1;
|
||||
#endif
|
||||
|
||||
// Try to open FSS0.
|
||||
if (f_open(&fp, path, FA_READ) != FR_OK)
|
||||
return 0;
|
||||
|
||||
void *fss = malloc(f_size(&fp));
|
||||
|
||||
// Read first 1024 bytes of the FSS0 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("Atmosphere %d.%d.%d-%08x via FSS0/PKG3\n"
|
||||
"Max HOS: %d.%d.%d\n"
|
||||
"Unpacking.. ",
|
||||
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);
|
||||
|
||||
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 config is not enabled, skip it.
|
||||
if ((curr_fss_cnt[i].flags0 & CNT_FLAG0_EXPERIMENTAL) && !experimental)
|
||||
continue;
|
||||
|
||||
// Prepare content.
|
||||
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_KRN:
|
||||
if (stock)
|
||||
continue;
|
||||
ctxt->kernel_size = curr_fss_cnt[i].size;
|
||||
ctxt->kernel = content;
|
||||
break;
|
||||
|
||||
case CNT_TYPE_EXO:
|
||||
ctxt->secmon_size = curr_fss_cnt[i].size;
|
||||
ctxt->secmon = content;
|
||||
break;
|
||||
|
||||
case CNT_TYPE_EXF:
|
||||
ctxt->exofatal_size = curr_fss_cnt[i].size;
|
||||
ctxt->exofatal = content;
|
||||
break;
|
||||
|
||||
case CNT_TYPE_WBT:
|
||||
if (h_cfg.t210b01)
|
||||
continue;
|
||||
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);
|
||||
}
|
||||
|
||||
gfx_printf("Done!\n");
|
||||
f_close(&fp);
|
||||
|
||||
ctxt->fss0 = fss;
|
||||
|
||||
// Update r2p if needed.
|
||||
_fss_update_r2p();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
f_close(&fp);
|
||||
free(fss);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (c) 2018 st4rk
|
||||
* Copyright (c) 2018 Ced2911
|
||||
* Copyright (c) 2018-2024 CTCaer
|
||||
* Copyright (c) 2018-2025 CTCaer
|
||||
* Copyright (c) 2018 balika011
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
@@ -28,6 +28,8 @@
|
||||
#include "../frontend/fe_tools.h"
|
||||
#include "../config.h"
|
||||
#include "../storage/emummc.h"
|
||||
#include "../storage/emusd.h"
|
||||
#include <storage/boot_storage.h>
|
||||
|
||||
extern hekate_config h_cfg;
|
||||
|
||||
@@ -124,6 +126,7 @@ static const u8 master_kekseed_t210_tsec_v4[HOS_KB_VERSION_MAX - HOS_KB_VERSION_
|
||||
{ 0x71, 0xB9, 0xA6, 0xC0, 0xFF, 0x97, 0x6B, 0x0C, 0xB4, 0x40, 0xB9, 0xD5, 0x81, 0x5D, 0x81, 0x90 }, // 17.0.0.
|
||||
{ 0x00, 0x04, 0x5D, 0xF0, 0x4D, 0xCD, 0x14, 0xA3, 0x1C, 0xBF, 0xDE, 0x48, 0x55, 0xBA, 0x35, 0xC1 }, // 18.0.0.
|
||||
{ 0xD7, 0x63, 0x74, 0x46, 0x4E, 0xBA, 0x78, 0x0A, 0x7C, 0x9D, 0xB3, 0xE8, 0x7A, 0x3D, 0x71, 0xE3 }, // 19.0.0.
|
||||
{ 0xA1, 0x7D, 0x34, 0xDB, 0x2D, 0x9D, 0xDA, 0xE5, 0xF8, 0x15, 0x63, 0x4C, 0x8F, 0xE7, 0x6C, 0xD8 }, // 20.0.0.
|
||||
};
|
||||
|
||||
//!TODO: Update on mkey changes.
|
||||
@@ -142,6 +145,7 @@ static const u8 master_kekseed_t210b01[HOS_KB_VERSION_MAX - HOS_KB_VERSION_600 +
|
||||
{ 0x8D, 0xEE, 0x9E, 0x11, 0x36, 0x3A, 0x9B, 0x0A, 0x6A, 0xC7, 0xBB, 0xE9, 0xD1, 0x03, 0xF7, 0x80 }, // 17.0.0.
|
||||
{ 0x4F, 0x41, 0x3C, 0x3B, 0xFB, 0x6A, 0x01, 0x2A, 0x68, 0x9F, 0x83, 0xE9, 0x53, 0xBD, 0x16, 0xD2 }, // 18.0.0.
|
||||
{ 0x31, 0xBE, 0x25, 0xFB, 0xDB, 0xB4, 0xEE, 0x49, 0x5C, 0x77, 0x05, 0xC2, 0x36, 0x9F, 0x34, 0x80 }, // 19.0.0.
|
||||
{ 0x1A, 0x31, 0x62, 0x87, 0xA8, 0x09, 0xCA, 0xF8, 0x69, 0x15, 0x45, 0xC2, 0x6B, 0xAA, 0x5A, 0x8A }, // 20.0.0.
|
||||
};
|
||||
|
||||
static const u8 console_keyseed[SE_KEY_128_SIZE] =
|
||||
@@ -194,7 +198,7 @@ static void _se_lock(bool lock_se)
|
||||
gfx_hexdump(SE_BASE, (void *)SE_BASE, 0x400);*/
|
||||
}
|
||||
|
||||
bool hos_eks_rw_try(u8 *buf, bool write)
|
||||
static bool _hos_eks_rw_try(u8 *buf, bool write)
|
||||
{
|
||||
for (u32 i = 0; i < 3; i++)
|
||||
{
|
||||
@@ -224,7 +228,7 @@ static void _hos_eks_get()
|
||||
{
|
||||
// Read EKS blob.
|
||||
u8 *mbr = zalloc(SD_BLOCKSIZE);
|
||||
if (!hos_eks_rw_try(mbr, false))
|
||||
if (!_hos_eks_rw_try(mbr, false))
|
||||
goto out;
|
||||
|
||||
// Decrypt EKS blob.
|
||||
@@ -262,7 +266,7 @@ static void _hos_eks_save()
|
||||
{
|
||||
// Read EKS blob.
|
||||
u8 *mbr = zalloc(SD_BLOCKSIZE);
|
||||
if (!hos_eks_rw_try(mbr, false))
|
||||
if (!_hos_eks_rw_try(mbr, false))
|
||||
{
|
||||
if (new_eks)
|
||||
{
|
||||
@@ -294,7 +298,7 @@ static void _hos_eks_save()
|
||||
|
||||
// Write EKS blob to SD.
|
||||
memcpy(mbr + 0x80, eks, sizeof(hos_eks_mbr_t));
|
||||
hos_eks_rw_try(mbr, true);
|
||||
_hos_eks_rw_try(mbr, true);
|
||||
|
||||
free(eks);
|
||||
free(keys);
|
||||
@@ -303,7 +307,7 @@ out:
|
||||
}
|
||||
}
|
||||
|
||||
void hos_eks_clear(u32 kb)
|
||||
static void _hos_eks_clear(u32 kb)
|
||||
{
|
||||
// Check if Erista based unit.
|
||||
if (h_cfg.t210b01)
|
||||
@@ -316,7 +320,7 @@ void hos_eks_clear(u32 kb)
|
||||
{
|
||||
// Read EKS blob.
|
||||
u8 *mbr = zalloc(SD_BLOCKSIZE);
|
||||
if (!hos_eks_rw_try(mbr, false))
|
||||
if (!_hos_eks_rw_try(mbr, false))
|
||||
goto out;
|
||||
|
||||
// Disable current Master key version.
|
||||
@@ -329,7 +333,7 @@ void hos_eks_clear(u32 kb)
|
||||
|
||||
// Write EKS blob to SD.
|
||||
memcpy(mbr + 0x80, eks, sizeof(hos_eks_mbr_t));
|
||||
hos_eks_rw_try(mbr, true);
|
||||
_hos_eks_rw_try(mbr, true);
|
||||
|
||||
free(eks);
|
||||
out:
|
||||
@@ -338,24 +342,9 @@ out:
|
||||
}
|
||||
}
|
||||
|
||||
int hos_keygen_t210b01(u32 kb)
|
||||
static int _hos_keygen(void *keyblob, u32 kb, tsec_ctxt_t *tsec_ctxt, bool stock, bool is_exo)
|
||||
{
|
||||
// Use SBK as Device key 4x unsealer and KEK for mkey in T210B01 units.
|
||||
se_aes_unwrap_key(10, 14, console_keyseed_4xx);
|
||||
|
||||
// Derive master key.
|
||||
se_aes_unwrap_key(7, 12, master_kekseed_t210b01[kb - HOS_KB_VERSION_600]);
|
||||
se_aes_unwrap_key(7, 7, master_keyseed_retail);
|
||||
|
||||
// Derive latest pkg2 key.
|
||||
se_aes_unwrap_key(8, 7, package2_keyseed);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int hos_keygen(void *keyblob, u32 kb, tsec_ctxt_t *tsec_ctxt, bool stock, bool is_exo)
|
||||
{
|
||||
static bool sbk_wiped = false;
|
||||
static bool sbk_is_set = true;
|
||||
|
||||
u32 retries = 0;
|
||||
bool use_tsec = false;
|
||||
@@ -365,16 +354,29 @@ int hos_keygen(void *keyblob, u32 kb, tsec_ctxt_t *tsec_ctxt, bool stock, bool i
|
||||
if (kb > HOS_KB_VERSION_MAX)
|
||||
return 0;
|
||||
|
||||
// Do Mariko keygen.
|
||||
if (h_cfg.t210b01)
|
||||
return hos_keygen_t210b01(kb);
|
||||
{
|
||||
// Use SBK as Device key 4x unsealer and KEK for mkey in T210B01 units.
|
||||
se_aes_unwrap_key(10, 14, console_keyseed_4xx);
|
||||
|
||||
// Derive master key.
|
||||
se_aes_unwrap_key(7, 12, master_kekseed_t210b01[kb - HOS_KB_VERSION_600]);
|
||||
se_aes_unwrap_key(7, 7, master_keyseed_retail);
|
||||
|
||||
// Derive latest pkg2 key.
|
||||
se_aes_unwrap_key(8, 7, package2_keyseed);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Do Erista keygen.
|
||||
|
||||
// SBK is wiped. Try to restore it from fuses.
|
||||
if (sbk_wiped)
|
||||
// Check if SBK is wiped and try to restore it from fuses.
|
||||
if (!sbk_is_set)
|
||||
{
|
||||
if (fuse_set_sbk())
|
||||
sbk_wiped = false;
|
||||
sbk_is_set = true;
|
||||
else
|
||||
return 1; // Continue with current SE keys.
|
||||
}
|
||||
@@ -409,10 +411,10 @@ int hos_keygen(void *keyblob, u32 kb, tsec_ctxt_t *tsec_ctxt, bool stock, bool i
|
||||
*/
|
||||
|
||||
// Use custom TSEC Hovi Keygen firmware.
|
||||
tsec_ctxt->fw = sd_file_read("bootloader/sys/thk.bin", NULL);
|
||||
tsec_ctxt->fw = boot_storage_file_read("bootloader/sys/thk.bin", NULL);
|
||||
if (!tsec_ctxt->fw)
|
||||
{
|
||||
_hos_crit_error("\nFailed to load thk.bin");
|
||||
_hos_crit_error("Failed to load thk.bin");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -436,7 +438,7 @@ int hos_keygen(void *keyblob, u32 kb, tsec_ctxt_t *tsec_ctxt, bool stock, bool i
|
||||
// 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.");
|
||||
_hos_crit_error("Failed to get TSEC keys.");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -570,7 +572,7 @@ int hos_keygen(void *keyblob, u32 kb, tsec_ctxt_t *tsec_ctxt, bool stock, bool i
|
||||
se_aes_unwrap_key(15, 15, console_keyseed);
|
||||
se_aes_unwrap_key(14, 12, master_keyseed_4xx);
|
||||
se_aes_unwrap_key(12, 12, master_keyseed_retail);
|
||||
sbk_wiped = true;
|
||||
sbk_is_set = false;
|
||||
break;
|
||||
case HOS_KB_VERSION_500:
|
||||
case HOS_KB_VERSION_600:
|
||||
@@ -578,7 +580,7 @@ int hos_keygen(void *keyblob, u32 kb, tsec_ctxt_t *tsec_ctxt, bool stock, bool i
|
||||
se_aes_unwrap_key(15, 15, console_keyseed);
|
||||
se_aes_unwrap_key(14, 12, master_keyseed_4xx);
|
||||
se_aes_unwrap_key(12, 12, master_keyseed_retail);
|
||||
sbk_wiped = true;
|
||||
sbk_is_set = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -700,7 +702,7 @@ out:
|
||||
static void _free_launch_components(launch_ctxt_t *ctxt)
|
||||
{
|
||||
// Free the malloc'ed guaranteed addresses.
|
||||
free(ctxt->fss0);
|
||||
free(ctxt->pkg3);
|
||||
free(ctxt->keyblob);
|
||||
free(ctxt->pkg1);
|
||||
free(ctxt->pkg2);
|
||||
@@ -750,7 +752,7 @@ static bool _get_fs_exfat_compatible(link_t *info, u32 *hos_revision)
|
||||
return true;
|
||||
}
|
||||
|
||||
int hos_launch(ini_sec_t *cfg)
|
||||
void hos_launch(ini_sec_t *cfg)
|
||||
{
|
||||
u8 kb;
|
||||
u32 secmon_base;
|
||||
@@ -758,7 +760,6 @@ int hos_launch(ini_sec_t *cfg)
|
||||
bool is_exo = false;
|
||||
launch_ctxt_t ctxt = {0};
|
||||
tsec_ctxt_t tsec_ctxt = {0};
|
||||
volatile secmon_mailbox_t *secmon_mailbox;
|
||||
|
||||
minerva_change_freq(FREQ_1600);
|
||||
sdram_src_pllc(true);
|
||||
@@ -776,23 +777,26 @@ int hos_launch(ini_sec_t *cfg)
|
||||
int res = emummc_storage_init_mmc();
|
||||
if (res)
|
||||
{
|
||||
if (res == 2)
|
||||
_hos_crit_error("Failed to init eMMC.");
|
||||
else
|
||||
_hos_crit_error("Failed to init emuMMC.");
|
||||
_hos_crit_error(res == 2 ? "Failed to init eMMC." : "Failed to init emuMMC.");
|
||||
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (emusd_storage_init_mmc() || !emusd_mount()) {
|
||||
_hos_crit_error("error: Failed to init emuSD.");
|
||||
|
||||
goto error;
|
||||
}
|
||||
|
||||
// Check if SD Card is GPT.
|
||||
if (sd_is_gpt())
|
||||
if (emusd_is_gpt())
|
||||
{
|
||||
_hos_crit_error("SD has GPT only!");
|
||||
_hos_crit_error("SD has GPT only! Run Fix Hybrid MBR!");
|
||||
goto error;
|
||||
}
|
||||
|
||||
// Try to parse config if present.
|
||||
if (ctxt.cfg && !parse_boot_config(&ctxt))
|
||||
if (!parse_boot_config(&ctxt))
|
||||
{
|
||||
_hos_crit_error("Wrong ini cfg or missing/corrupt files!");
|
||||
goto error;
|
||||
@@ -805,6 +809,8 @@ int hos_launch(ini_sec_t *cfg)
|
||||
if (ctxt.stock && (h_cfg.t210b01 || !tools_autorcm_enabled()))
|
||||
{
|
||||
sdram_src_pllc(false);
|
||||
emummc_storage_end();
|
||||
emusd_storage_end();
|
||||
emmc_end();
|
||||
|
||||
WPRINTF("\nRebooting to OFW in 5s...");
|
||||
@@ -817,7 +823,8 @@ int hos_launch(ini_sec_t *cfg)
|
||||
|
||||
kb = ctxt.pkg1_id->kb;
|
||||
|
||||
bool emummc_enabled = emu_cfg.enabled && !h_cfg.emummc_force_disable;
|
||||
// TODO: separate force_disable for emuSD?
|
||||
bool emummc_enabled = (emu_cfg.enabled || emu_sd_cfg.enabled) && !h_cfg.emummc_force_disable;
|
||||
|
||||
// Enable emummc patching.
|
||||
if (emummc_enabled)
|
||||
@@ -828,7 +835,7 @@ int hos_launch(ini_sec_t *cfg)
|
||||
goto error;
|
||||
}
|
||||
|
||||
ctxt.atmosphere = true; // Set atmosphere patching in case of no fss0.
|
||||
ctxt.patch_krn_proc_id = true; // Set kernel process id patching in case of no pkg3.
|
||||
config_kip1patch(&ctxt, "emummc");
|
||||
}
|
||||
else if (!emu_cfg.enabled && ctxt.emummc_forced)
|
||||
@@ -880,7 +887,7 @@ int hos_launch(ini_sec_t *cfg)
|
||||
tsec_ctxt.pkg11_off = ctxt.pkg1_id->pkg11_off;
|
||||
|
||||
// Generate keys.
|
||||
if (!hos_keygen(ctxt.keyblob, kb, &tsec_ctxt, ctxt.stock, is_exo))
|
||||
if (!_hos_keygen(ctxt.keyblob, kb, &tsec_ctxt, ctxt.stock, is_exo))
|
||||
goto error;
|
||||
gfx_puts("Generated keys\n");
|
||||
|
||||
@@ -982,7 +989,7 @@ int hos_launch(ini_sec_t *cfg)
|
||||
_hos_crit_error("Pkg2 decryption failed!\npkg1/pkg2 mismatch or old hekate!");
|
||||
|
||||
// Clear EKS slot, in case something went wrong with tsec keygen.
|
||||
hos_eks_clear(kb);
|
||||
_hos_eks_clear(kb);
|
||||
goto error;
|
||||
}
|
||||
|
||||
@@ -1001,7 +1008,7 @@ int hos_launch(ini_sec_t *cfg)
|
||||
ctxt.kernel = pkg2_hdr->data;
|
||||
ctxt.kernel_size = pkg2_hdr->sec_size[PKG2_SEC_KERNEL];
|
||||
|
||||
if (!ctxt.stock && (ctxt.svcperm || ctxt.debugmode || ctxt.atmosphere))
|
||||
if (!ctxt.stock && (ctxt.svcperm || ctxt.debugmode || ctxt.patch_krn_proc_id))
|
||||
{
|
||||
// Hash only Kernel when it embeds INI1.
|
||||
u8 kernel_hash[0x20];
|
||||
@@ -1028,10 +1035,10 @@ int hos_launch(ini_sec_t *cfg)
|
||||
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))
|
||||
|| (ctxt.debugmode && kernel_patchset[i].id == DEBUG_MODE_EN && !(ctxt.patch_krn_proc_id && ctxt.secmon))
|
||||
|| (ctxt.patch_krn_proc_id && 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)
|
||||
else if (ctxt.patch_krn_proc_id && kernel_patchset[i].id == ATM_ARR_PATCH)
|
||||
{
|
||||
temp = (u32 *)kernel_patchset[i].ptr;
|
||||
for (u32 j = 0; j < kernel_patchset[i].val; j++)
|
||||
@@ -1053,7 +1060,7 @@ int hos_launch(ini_sec_t *cfg)
|
||||
{
|
||||
bool exfat_compat = _get_fs_exfat_compatible(&kip1_info, &ctxt.exo_ctx.hos_revision);
|
||||
|
||||
if (sd_fs.fs_type == FS_EXFAT && !exfat_compat)
|
||||
if (emusd_get_fs_type() == FS_EXFAT && !exfat_compat)
|
||||
{
|
||||
_hos_crit_error("SD Card is exFAT but installed HOS driver\nonly supports FAT32!");
|
||||
|
||||
@@ -1086,6 +1093,9 @@ int hos_launch(ini_sec_t *cfg)
|
||||
config_exosphere(&ctxt, warmboot_base);
|
||||
|
||||
// Unmount SD card and eMMC.
|
||||
emummc_storage_end();
|
||||
emusd_storage_end();
|
||||
boot_storage_end();
|
||||
sd_end();
|
||||
emmc_end();
|
||||
|
||||
@@ -1151,6 +1161,7 @@ int hos_launch(ini_sec_t *cfg)
|
||||
//pmc_scratch_lock(PMC_SEC_LOCK_LP0_PARAMS);
|
||||
|
||||
// Set secmon mailbox address and clear it.
|
||||
volatile secmon_mailbox_t *secmon_mailbox;
|
||||
if (kb >= HOS_KB_VERSION_700 || is_exo)
|
||||
{
|
||||
memset((void *)SECMON7_MAILBOX_ADDR, 0, 0x200);
|
||||
@@ -1199,9 +1210,9 @@ int hos_launch(ini_sec_t *cfg)
|
||||
error:
|
||||
_free_launch_components(&ctxt);
|
||||
sdram_src_pllc(false);
|
||||
emummc_storage_end();
|
||||
emusd_storage_end();
|
||||
emmc_end();
|
||||
|
||||
EPRINTF("\nFailed to launch HOS!");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (c) 2018-2024 CTCaer
|
||||
* Copyright (c) 2018-2025 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,
|
||||
@@ -46,7 +46,8 @@ enum {
|
||||
HOS_KB_VERSION_1700 = 16,
|
||||
HOS_KB_VERSION_1800 = 17,
|
||||
HOS_KB_VERSION_1900 = 18,
|
||||
HOS_KB_VERSION_MAX = HOS_KB_VERSION_1900
|
||||
HOS_KB_VERSION_2000 = 19,
|
||||
HOS_KB_VERSION_MAX = HOS_KB_VERSION_2000
|
||||
};
|
||||
|
||||
#define HOS_TSEC_VERSION 4 //! TODO: Update on TSEC Root Key changes.
|
||||
@@ -104,16 +105,16 @@ typedef struct _launch_ctxt_t
|
||||
u32 kernel_size;
|
||||
|
||||
link_t kip1_list;
|
||||
char* kip1_patches;
|
||||
char *kip1_patches;
|
||||
|
||||
bool svcperm;
|
||||
bool debugmode;
|
||||
bool stock;
|
||||
bool emummc_forced;
|
||||
|
||||
void *fss0;
|
||||
u32 fss0_hosver;
|
||||
bool atmosphere;
|
||||
void *pkg3;
|
||||
u32 pkg3_hosver;
|
||||
bool patch_krn_proc_id;
|
||||
|
||||
int ucid;
|
||||
|
||||
@@ -128,8 +129,6 @@ typedef struct _merge_kip_t
|
||||
link_t link;
|
||||
} merge_kip_t;
|
||||
|
||||
void hos_eks_clear(u32 kb);
|
||||
int hos_launch(ini_sec_t *cfg);
|
||||
int hos_keygen(void *keyblob, u32 kb, tsec_ctxt_t *tsec_ctxt, bool stock, bool is_exo);
|
||||
void hos_launch(ini_sec_t *cfg);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (c) 2018-2024 CTCaer
|
||||
* Copyright (c) 2018-2025 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,
|
||||
@@ -15,13 +15,15 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <storage/boot_storage.h>
|
||||
#include "../storage/emusd.h"
|
||||
#include <string.h>
|
||||
|
||||
#include <bdk.h>
|
||||
|
||||
#include "hos.h"
|
||||
#include "hos_config.h"
|
||||
#include "fss.h"
|
||||
#include "pkg3.h"
|
||||
#include <libs/fatfs/ff.h>
|
||||
|
||||
//#define DPRINTF(...) gfx_printf(__VA_ARGS__)
|
||||
@@ -29,7 +31,7 @@
|
||||
|
||||
static int _config_warmboot(launch_ctxt_t *ctxt, const char *value)
|
||||
{
|
||||
ctxt->warmboot = sd_file_read(value, &ctxt->warmboot_size);
|
||||
ctxt->warmboot = emusd_file_read(value, &ctxt->warmboot_size);
|
||||
if (!ctxt->warmboot)
|
||||
return 0;
|
||||
|
||||
@@ -38,7 +40,7 @@ static int _config_warmboot(launch_ctxt_t *ctxt, const char *value)
|
||||
|
||||
static int _config_secmon(launch_ctxt_t *ctxt, const char *value)
|
||||
{
|
||||
ctxt->secmon = sd_file_read(value, &ctxt->secmon_size);
|
||||
ctxt->secmon = emusd_file_read(value, &ctxt->secmon_size);
|
||||
if (!ctxt->secmon)
|
||||
return 0;
|
||||
|
||||
@@ -47,7 +49,7 @@ static int _config_secmon(launch_ctxt_t *ctxt, const char *value)
|
||||
|
||||
static int _config_kernel(launch_ctxt_t *ctxt, const char *value)
|
||||
{
|
||||
ctxt->kernel = sd_file_read(value, &ctxt->kernel_size);
|
||||
ctxt->kernel = emusd_file_read(value, &ctxt->kernel_size);
|
||||
if (!ctxt->kernel)
|
||||
return 0;
|
||||
|
||||
@@ -58,10 +60,11 @@ static int _config_kip1(launch_ctxt_t *ctxt, const char *value)
|
||||
{
|
||||
u32 size;
|
||||
|
||||
if (!memcmp(value + strlen(value) - 1, "*", 1))
|
||||
if (value[strlen(value) - 1] == '*')
|
||||
{
|
||||
char *dir = (char *)malloc(256);
|
||||
strcpy(dir, value);
|
||||
strcpy(dir, "emusd:");
|
||||
strcat(dir, value);
|
||||
|
||||
u32 dirlen = 0;
|
||||
dir[strlen(dir) - 2] = 0;
|
||||
@@ -81,7 +84,7 @@ static int _config_kip1(launch_ctxt_t *ctxt, const char *value)
|
||||
strcpy(dir + dirlen, filelist->name[i]);
|
||||
|
||||
merge_kip_t *mkip1 = (merge_kip_t *)malloc(sizeof(merge_kip_t));
|
||||
mkip1->kip1 = sd_file_read(dir, &size);
|
||||
mkip1->kip1 = emusd_file_read(dir + 6, &size);
|
||||
if (!mkip1->kip1)
|
||||
{
|
||||
free(mkip1);
|
||||
@@ -103,7 +106,7 @@ static int _config_kip1(launch_ctxt_t *ctxt, const char *value)
|
||||
else
|
||||
{
|
||||
merge_kip_t *mkip1 = (merge_kip_t *)malloc(sizeof(merge_kip_t));
|
||||
mkip1->kip1 = sd_file_read(value, &size);
|
||||
mkip1->kip1 = emusd_file_read(value, &size);
|
||||
if (!mkip1->kip1)
|
||||
{
|
||||
free(mkip1);
|
||||
@@ -119,9 +122,6 @@ static int _config_kip1(launch_ctxt_t *ctxt, const char *value)
|
||||
|
||||
int config_kip1patch(launch_ctxt_t *ctxt, const char *value)
|
||||
{
|
||||
if (value == NULL)
|
||||
return 0;
|
||||
|
||||
int len = strlen(value);
|
||||
if (!len)
|
||||
return 0;
|
||||
@@ -188,12 +188,12 @@ static int _config_emummc_forced(launch_ctxt_t *ctxt, const char *value)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _config_atmosphere(launch_ctxt_t *ctxt, const char *value)
|
||||
static int _config_kernel_proc_id(launch_ctxt_t *ctxt, const char *value)
|
||||
{
|
||||
if (*value == '1')
|
||||
{
|
||||
DPRINTF("Enabled atmosphere patching\n");
|
||||
ctxt->atmosphere = true;
|
||||
DPRINTF("Enabled kernel process id send/recv patching\n");
|
||||
ctxt->patch_krn_proc_id = true;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
@@ -258,14 +258,14 @@ static int _config_exo_cal0_writes_enable(launch_ctxt_t *ctxt, const char *value
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _config_fss(launch_ctxt_t *ctxt, const char *value)
|
||||
static int _config_pkg3(launch_ctxt_t *ctxt, const char *value)
|
||||
{
|
||||
return parse_fss(ctxt, value);
|
||||
return parse_pkg3(ctxt, value);
|
||||
}
|
||||
|
||||
static int _config_exo_fatal_payload(launch_ctxt_t *ctxt, const char *value)
|
||||
{
|
||||
ctxt->exofatal = sd_file_read(value, &ctxt->exofatal_size);
|
||||
ctxt->exofatal = emusd_file_read(value, &ctxt->exofatal_size);
|
||||
if (!ctxt->exofatal)
|
||||
return 0;
|
||||
|
||||
@@ -287,6 +287,7 @@ typedef struct _cfg_handler_t
|
||||
} cfg_handler_t;
|
||||
|
||||
static const cfg_handler_t _config_handlers[] = {
|
||||
{ "stock", _config_stock },
|
||||
{ "warmboot", _config_warmboot },
|
||||
{ "secmon", _config_secmon },
|
||||
{ "kernel", _config_kernel },
|
||||
@@ -294,9 +295,12 @@ static const cfg_handler_t _config_handlers[] = {
|
||||
{ "kip1patch", config_kip1patch },
|
||||
{ "fullsvcperm", _config_svcperm },
|
||||
{ "debugmode", _config_debugmode },
|
||||
{ "stock", _config_stock },
|
||||
{ "atmosphere", _config_atmosphere },
|
||||
{ "fss0", _config_fss },
|
||||
{ "kernelprocid", _config_kernel_proc_id },
|
||||
|
||||
// To override elements from PKG3, it should be set before others.
|
||||
{ "pkg3", _config_pkg3 },
|
||||
{ "fss0", _config_pkg3 },
|
||||
|
||||
{ "exofatal", _config_exo_fatal_payload},
|
||||
{ "emummcforce", _config_emummc_forced },
|
||||
{ "nouserexceptions", _config_dis_exo_user_exceptions },
|
||||
@@ -310,10 +314,15 @@ static const cfg_handler_t _config_handlers[] = {
|
||||
|
||||
int parse_boot_config(launch_ctxt_t *ctxt)
|
||||
{
|
||||
if (!ctxt->cfg)
|
||||
return 1;
|
||||
|
||||
// Check each config key.
|
||||
LIST_FOREACH_ENTRY(ini_kv_t, kv, &ctxt->cfg->kvs, link)
|
||||
{
|
||||
for (u32 i = 0; _config_handlers[i].key; i++)
|
||||
{
|
||||
// If key matches, call its handler.
|
||||
if (!strcmp(_config_handlers[i].key, kv->key))
|
||||
{
|
||||
if (!_config_handlers[i].handler(ctxt, kv->val))
|
||||
@@ -323,6 +332,8 @@ int parse_boot_config(launch_ctxt_t *ctxt)
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (c) 2018 st4rk
|
||||
* Copyright (c) 2018-2024 CTCaer
|
||||
* Copyright (c) 2018-2025 CTCaer
|
||||
* Copyright (c) 2018 balika011
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
@@ -17,6 +17,8 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <storage/boot_storage.h>
|
||||
#include "../storage/emusd.h"
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
@@ -33,7 +35,7 @@ extern hekate_config h_cfg;
|
||||
#define SM_100_ADR 0x4002B020 // Original: 0x40014020.
|
||||
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)) },
|
||||
{ 0x1E0, _ADRP(0, TZRAM_BASE + 0x3000 - _PAGEOFF(SM_100_ADR)) },
|
||||
// Patch package2 signature/hash checks.
|
||||
{ 0x9F0 + 0xADC, _NOP() }
|
||||
);
|
||||
@@ -143,7 +145,7 @@ static const u8 sec_map_100[3] = { PK11_SECTION_SM, PK11_SECTION_LD, PK11_SECTIO
|
||||
static const u8 sec_map_2xx[3] = { PK11_SECTION_WB, PK11_SECTION_LD, PK11_SECTION_SM };
|
||||
static const u8 sec_map_4xx[3] = { PK11_SECTION_LD, PK11_SECTION_SM, PK11_SECTION_WB };
|
||||
|
||||
// ID (Timestamp), KB, Fuses, TSEC, PK11, SECMON, Warmboot.
|
||||
// Timestamp KB FU TSEC PK11 SECMON Warmboot
|
||||
static const pkg1_id_t _pkg1_ids[] = {
|
||||
{ "20161121", 0, 1, 0x1900, 0x3FE0, SM_100_ADR, 0x8000D000, _secmon_1_patchset }, // 1.0.0 (Patched relocator).
|
||||
{ "20170210", 0, 2, 0x1900, 0x3FE0, 0x4002D000, 0x8000D000, _secmon_2_patchset }, // 2.0.0 - 2.3.0.
|
||||
@@ -171,7 +173,8 @@ static const pkg1_id_t _pkg1_ids[] = {
|
||||
{ "20230111", 15, 18, 0x0E00, 0x6FE0, 0x40030000, 0x4003E000, NULL }, // 16.0.0 - 16.1.0.
|
||||
{ "20230906", 16, 19, 0x0E00, 0x6FE0, 0x40030000, 0x4003E000, NULL }, // 17.0.0 - 17.0.1.
|
||||
{ "20240207", 17, 19, 0x0E00, 0x6FE0, 0x40030000, 0x4003E000, NULL }, // 18.0.0 - 18.1.0.
|
||||
{ "20240808", 18, 20, 0x0E00, 0x6FE0, 0x40030000, 0x4003E000, NULL }, // 19.0.0+
|
||||
{ "20240808", 18, 20, 0x0E00, 0x6FE0, 0x40030000, 0x4003E000, NULL }, // 19.0.0 - 19.0.1.
|
||||
{ "20250206", 19, 21, 0x0E00, 0x6FE0, 0x40030000, 0x4003E000, NULL }, // 20.0.0+
|
||||
};
|
||||
|
||||
const pkg1_id_t *pkg1_get_latest()
|
||||
@@ -368,13 +371,13 @@ int pkg1_warmboot_config(void *hos_ctxt, u32 warmboot_base, u32 fuses_fw, u8 kb)
|
||||
if (!ctxt->warmboot)
|
||||
{
|
||||
char path[128];
|
||||
strcpy(path, "warmboot_mariko/wb_");
|
||||
strcpy(path, "emusd:warmboot_mariko/wb_");
|
||||
_warmboot_filename(path, fuses_fw);
|
||||
|
||||
// Check if warmboot fw exists and save it.
|
||||
if (ctxt->warmboot_size && f_stat(path, NULL))
|
||||
{
|
||||
f_mkdir("warmboot_mariko");
|
||||
f_mkdir("emusd:warmboot_mariko");
|
||||
sd_save_to_file((void *)warmboot_base, ctxt->warmboot_size, path);
|
||||
}
|
||||
|
||||
@@ -387,7 +390,7 @@ int pkg1_warmboot_config(void *hos_ctxt, u32 warmboot_base, u32 fuses_fw, u8 kb)
|
||||
_warmboot_filename(path, burnt_fuses);
|
||||
if (!f_stat(path, NULL))
|
||||
{
|
||||
ctxt->warmboot = sd_file_read(path, &ctxt->warmboot_size);
|
||||
ctxt->warmboot = emusd_file_read(path + 6, &ctxt->warmboot_size);
|
||||
burnt_fuses = tmp_fuses;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (c) 2018-2024 CTCaer
|
||||
* Copyright (c) 2018-2025 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,
|
||||
@@ -15,6 +15,7 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <storage/boot_storage.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <bdk.h>
|
||||
@@ -27,6 +28,7 @@
|
||||
#include <libs/compr/blz.h>
|
||||
#include <libs/fatfs/ff.h>
|
||||
#include "../storage/emummc.h"
|
||||
#include "../storage/emusd.h"
|
||||
|
||||
//#define DPRINTF(...) gfx_printf(__VA_ARGS__)
|
||||
#define DPRINTF(...)
|
||||
@@ -37,6 +39,7 @@ extern const u8 package2_keyseed[];
|
||||
u32 pkg2_newkern_ini1_info;
|
||||
u32 pkg2_newkern_ini1_start;
|
||||
u32 pkg2_newkern_ini1_end;
|
||||
u32 pkg2_newkern_ini1_rela;
|
||||
|
||||
enum kip_offset_section
|
||||
{
|
||||
@@ -74,6 +77,7 @@ static void parse_external_kip_patches()
|
||||
return;
|
||||
|
||||
LIST_INIT(ini_kip_sections);
|
||||
// TODO: load frome emusd?
|
||||
if (ini_patch_parse(&ini_kip_sections, "bootloader/patches.ini"))
|
||||
{
|
||||
// Copy ids into a new patchset.
|
||||
@@ -188,11 +192,12 @@ static u32 _pkg2_calc_kip1_size(pkg2_kip1_t *kip1)
|
||||
return size;
|
||||
}
|
||||
|
||||
void pkg2_get_newkern_info(u8 *kern_data)
|
||||
static void _pkg2_get_newkern_info(u8 *kern_data)
|
||||
{
|
||||
u32 crt_start = 0;
|
||||
u32 crt_start = 0;
|
||||
pkg2_newkern_ini1_info = 0;
|
||||
pkg2_newkern_ini1_start = 0;
|
||||
pkg2_newkern_ini1_rela = 0;
|
||||
|
||||
u32 first_op = *(u32 *)kern_data;
|
||||
if ((first_op & 0xFE000000) == 0x14000000)
|
||||
@@ -229,6 +234,7 @@ void pkg2_get_newkern_info(u8 *kern_data)
|
||||
// On v2 kernel with dynamic crt, values are relative to value address.
|
||||
if (crt_start)
|
||||
{
|
||||
pkg2_newkern_ini1_rela = pkg2_newkern_ini1_info;
|
||||
pkg2_newkern_ini1_start += pkg2_newkern_ini1_info;
|
||||
pkg2_newkern_ini1_end += pkg2_newkern_ini1_info + 0x8;
|
||||
}
|
||||
@@ -240,7 +246,7 @@ bool pkg2_parse_kips(link_t *info, pkg2_hdr_t *pkg2, bool *new_pkg2)
|
||||
// Check for new pkg2 type.
|
||||
if (!pkg2->sec_size[PKG2_SEC_INI1])
|
||||
{
|
||||
pkg2_get_newkern_info(pkg2->data);
|
||||
_pkg2_get_newkern_info(pkg2->data);
|
||||
|
||||
if (!pkg2_newkern_ini1_start)
|
||||
return false;
|
||||
@@ -382,7 +388,7 @@ static int _kipm_inject(const char *kipm_path, char *target_name, pkg2_kip1_info
|
||||
if (!strcmp((char *)ki->kip1->name, target_name))
|
||||
{
|
||||
u32 size = 0;
|
||||
u8 *kipm_data = (u8 *)sd_file_read(kipm_path, &size);
|
||||
u8 *kipm_data = (u8 *)boot_storage_file_read(kipm_path, &size);
|
||||
if (!kipm_data)
|
||||
return 1;
|
||||
|
||||
@@ -664,6 +670,8 @@ const char *pkg2_patch_kips(link_t *info, char *patch_names)
|
||||
if (kip_id_idx > 17)
|
||||
emu_cfg.fs_ver -= 2;
|
||||
|
||||
emu_sd_cfg.fs_ver = emu_cfg.fs_ver;
|
||||
|
||||
// Inject emuMMC code.
|
||||
gfx_printf("Injecting emuMMC. FS ID: %d\n", emu_cfg.fs_ver);
|
||||
if (_kipm_inject("bootloader/sys/emummc.kipm", "FS", ki))
|
||||
@@ -683,6 +691,10 @@ const char *pkg2_patch_kips(link_t *info, char *patch_names)
|
||||
return patches[i];
|
||||
}
|
||||
|
||||
// Check if emuMMC was applied.
|
||||
if (emummc_patch_selected)
|
||||
return "emummc";
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -845,10 +857,15 @@ DPRINTF("%s @ %08X (%08X)\n", is_meso ? "Mesosphere": "kernel",(u32)ctxt->kernel
|
||||
|
||||
// Set new INI1 offset to kernel.
|
||||
u32 meso_meta_offset = *(u32 *)(pdst + 8);
|
||||
if (is_meso && (meso_magic & 0xF000000)) // MSS1.
|
||||
if (is_meso && (meso_magic & 0x0F000000)) // MSS1.
|
||||
*(u32 *)(pdst + meso_meta_offset) = kernel_size - meso_meta_offset;
|
||||
else if (ini1_size)
|
||||
*(u32 *)(pdst + (is_meso ? 8 : pkg2_newkern_ini1_info)) = kernel_size;
|
||||
{
|
||||
if (is_meso) // MSS0.
|
||||
*(u32 *)(pdst + 8) = kernel_size;
|
||||
else
|
||||
*(u32 *)(pdst + pkg2_newkern_ini1_info) = kernel_size - pkg2_newkern_ini1_rela;
|
||||
}
|
||||
|
||||
kernel_size += ini1_size;
|
||||
}
|
||||
@@ -865,13 +882,13 @@ DPRINTF("INI1 encrypted\n");
|
||||
|
||||
if (!is_exo) // Not needed on Exosphere 1.0.0 and up.
|
||||
{
|
||||
// Calculate SHA256 over encrypted Kernel and INI1.
|
||||
// Calculate SHA256 over encrypted sections. Only 3 have valid hashes.
|
||||
u8 *pk2_hash_data = (u8 *)dst + 0x100 + sizeof(pkg2_hdr_t);
|
||||
se_calc_sha256_oneshot(&hdr->sec_sha256[SE_SHA_256_SIZE * PKG2_SEC_KERNEL],
|
||||
(void *)pk2_hash_data, hdr->sec_size[PKG2_SEC_KERNEL]);
|
||||
pk2_hash_data += hdr->sec_size[PKG2_SEC_KERNEL];
|
||||
se_calc_sha256_oneshot(&hdr->sec_sha256[SE_SHA_256_SIZE * PKG2_SEC_INI1],
|
||||
(void *)pk2_hash_data, hdr->sec_size[PKG2_SEC_INI1]);
|
||||
for (u32 i = PKG2_SEC_KERNEL; i <= PKG2_SEC_UNUSED; i++)
|
||||
{
|
||||
se_calc_sha256_oneshot(&hdr->sec_sha256[SE_SHA_256_SIZE * i], (void *)pk2_hash_data, hdr->sec_size[i]);
|
||||
pk2_hash_data += hdr->sec_size[i];
|
||||
}
|
||||
}
|
||||
|
||||
// Encrypt header.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (c) 2018-2024 CTCaer
|
||||
* Copyright (c) 2018-2025 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,
|
||||
@@ -20,16 +20,17 @@
|
||||
|
||||
#include <bdk.h>
|
||||
|
||||
#define PKG2_MAGIC 0x31324B50
|
||||
#define PKG2_SEC_BASE 0x80000000
|
||||
#define PKG2_MAGIC 0x31324B50
|
||||
#define PKG2_SEC_BASE 0x80000000
|
||||
#define PKG2_SEC_KERNEL 0
|
||||
#define PKG2_SEC_INI1 1
|
||||
#define PKG2_SEC_INI1 1
|
||||
#define PKG2_SEC_UNUSED 2
|
||||
|
||||
#define INI1_MAGIC 0x31494E49
|
||||
|
||||
//! TODO: Update on kernel change if needed.
|
||||
// Offset of OP + 12 is the INI1 offset. On v2 with dynamic crt0 it's + 16.
|
||||
#define PKG2_NEWKERN_GET_INI1_HEURISTIC 0xD2800015
|
||||
#define PKG2_NEWKERN_GET_INI1_HEURISTIC 0xD2800015 // MOV X21, #0.
|
||||
#define PKG2_NEWKERN_START 0x800
|
||||
|
||||
#define ATM_MESOSPHERE 0x3053534D
|
||||
@@ -67,18 +68,18 @@ enum
|
||||
|
||||
typedef struct _pkg2_hdr_t
|
||||
{
|
||||
u8 ctr[0x10];
|
||||
u8 sec_ctr[0x40];
|
||||
u32 magic;
|
||||
u32 base;
|
||||
u32 pad0;
|
||||
u8 pkg2_ver;
|
||||
u8 bl_ver;
|
||||
u16 pad1;
|
||||
u32 sec_size[4];
|
||||
u32 sec_off[4];
|
||||
u8 sec_sha256[0x80];
|
||||
u8 data[];
|
||||
/* 0x000 */ u8 ctr[0x10];
|
||||
/* 0x010 */ u8 sec_ctr[0x40];
|
||||
/* 0x050 */ u32 magic;
|
||||
/* 0x054 */ u32 base;
|
||||
/* 0x058 */ u32 pad0;
|
||||
/* 0x05C */ u8 pkg2_ver;
|
||||
/* 0x05D */ u8 bl_ver;
|
||||
/* 0x05E */ u16 pad1;
|
||||
/* 0x060 */ u32 sec_size[4];
|
||||
/* 0x070 */ u32 sec_off[4];
|
||||
/* 0x080 */ u8 sec_sha256[0x80];
|
||||
/* 0x100 */ u8 data[];
|
||||
} pkg2_hdr_t;
|
||||
|
||||
typedef struct _pkg2_ini1_t
|
||||
@@ -102,7 +103,7 @@ typedef struct _pkg2_kip1_sec_t
|
||||
typedef struct _pkg2_kip1_t
|
||||
{
|
||||
/* 0x000 */ u32 magic;
|
||||
/* 0x004*/ u8 name[12];
|
||||
/* 0x004 */ u8 name[12];
|
||||
/* 0x010 */ u64 tid;
|
||||
/* 0x018 */ u32 proc_cat;
|
||||
/* 0x01C */ u8 main_thrd_prio;
|
||||
@@ -150,7 +151,6 @@ typedef struct _kip1_id_t
|
||||
const 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);
|
||||
|
||||
@@ -818,6 +818,30 @@ static const kip1_patchset_t _fs_patches_1900_exfat[] = {
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
static const kip1_patch_t _fs_nogc_2000[] = {
|
||||
{ KPS(KIP_TEXT) | 0x17C150, 8, KIP1_PATCH_SRC_NO_CHECK, "\xE0\x03\x1F\x2A\xC0\x03\x5F\xD6" },
|
||||
{ KPS(KIP_TEXT) | 0x1A7D24, 4, KIP1_PATCH_SRC_NO_CHECK, "\x14\x80\x80\x52" },
|
||||
{ KPS(KIP_TEXT) | 0x1A7F24, 4, KIP1_PATCH_SRC_NO_CHECK, "\x16\x80\x80\x52" },
|
||||
{ 0, 0, NULL, NULL }
|
||||
};
|
||||
|
||||
static const kip1_patchset_t _fs_patches_2000[] = {
|
||||
{ "nogc", _fs_nogc_2000 },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
static const kip1_patch_t _fs_nogc_2000_exfat[] = {
|
||||
{ KPS(KIP_TEXT) | 0x187A70, 8, KIP1_PATCH_SRC_NO_CHECK, "\xE0\x03\x1F\x2A\xC0\x03\x5F\xD6" },
|
||||
{ KPS(KIP_TEXT) | 0x1B3644, 4, KIP1_PATCH_SRC_NO_CHECK, "\x14\x80\x80\x52" },
|
||||
{ KPS(KIP_TEXT) | 0x1B3844, 4, KIP1_PATCH_SRC_NO_CHECK, "\x16\x80\x80\x52" },
|
||||
{ 0, 0, NULL, NULL }
|
||||
};
|
||||
|
||||
static const kip1_patchset_t _fs_patches_2000_exfat[] = {
|
||||
{ "nogc", _fs_nogc_2000_exfat },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
// SHA256 hashes.
|
||||
static const kip1_id_t _kip_ids[] =
|
||||
{
|
||||
@@ -883,4 +907,8 @@ static const kip1_id_t _kip_ids[] =
|
||||
{ "FS", "\x20\x4C\xBA\x86\xDE\x08\x44\x6A", _fs_patches_1800_exfat }, // FS 18.1.0 exFAT
|
||||
{ "FS", "\xD9\x4C\x68\x15\xF8\xF5\x0A\x20", _fs_patches_1900 }, // FS 19.0.0
|
||||
{ "FS", "\xED\xA8\x78\x68\xA4\x49\x07\x50", _fs_patches_1900_exfat }, // FS 19.0.0 exFAT
|
||||
{ "FS", "\x63\x54\x96\x9E\x60\xA7\x97\x7B", _fs_patches_2000 }, // FS 20.0.0
|
||||
{ "FS", "\x47\x41\x07\x10\x65\x4F\xA4\x3F", _fs_patches_2000_exfat }, // FS 20.0.0 exFAT
|
||||
{ "FS", "\xED\x34\xB4\x50\x58\x4A\x5B\x43", _fs_patches_2000 }, // FS 20.1.0
|
||||
{ "FS", "\xA5\x1A\xA4\x92\x6C\x41\x87\x59", _fs_patches_2000_exfat }, // FS 20.1.0 exFAT
|
||||
};
|
||||
|
||||
298
bootloader/hos/pkg3.c
Normal file
298
bootloader/hos/pkg3.c
Normal file
@@ -0,0 +1,298 @@
|
||||
/*
|
||||
* Atmosphère Package 3 parser.
|
||||
*
|
||||
* Copyright (c) 2019-2025 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 <storage/boot_storage.h>
|
||||
#include "../storage/emusd.h"
|
||||
#include <string.h>
|
||||
|
||||
#include <bdk.h>
|
||||
|
||||
#include "pkg3.h"
|
||||
#include "hos.h"
|
||||
#include "../config.h"
|
||||
#include <libs/fatfs/ff.h>
|
||||
#include "../storage/emummc.h"
|
||||
|
||||
//#define DPRINTF(...) gfx_printf(__VA_ARGS__)
|
||||
#define DPRINTF(...)
|
||||
|
||||
extern hekate_config h_cfg;
|
||||
|
||||
extern bool is_ipl_updated(void *buf, const char *path, bool force);
|
||||
|
||||
#define PKG3_KIP_SKIP_MAX 16
|
||||
|
||||
// PKG3 Magic and Meta header offset.
|
||||
#define PKG3_MAGIC 0x30535346 // FSS0.
|
||||
#define PKG3_META_OFFSET 0x4
|
||||
#define PKG3_VERSION_0_17_0 0x110000
|
||||
|
||||
// PKG3 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.
|
||||
#define CNT_TYPE_EXF 11 // Exosphere Mariko fatal payload.
|
||||
#define CNT_TYPE_TKG 12 // Tsec Keygen.
|
||||
|
||||
// PKG3 Content Flags.
|
||||
#define CNT_FLAG0_EXPERIMENTAL BIT(0)
|
||||
|
||||
// PKG3 Meta Header.
|
||||
typedef struct _pkg3_meta_t
|
||||
{
|
||||
u32 magic;
|
||||
u32 size;
|
||||
u32 crt0_off;
|
||||
u32 cnt_off;
|
||||
u32 cnt_count;
|
||||
u32 hos_ver;
|
||||
u32 version;
|
||||
u32 git_rev;
|
||||
} pkg3_meta_t;
|
||||
|
||||
// PKG3 Content Header.
|
||||
typedef struct _pkg3_content_t
|
||||
{
|
||||
u32 offset;
|
||||
u32 size;
|
||||
u8 type;
|
||||
u8 flags0;
|
||||
u8 flags1;
|
||||
u8 flags2;
|
||||
u32 rsvd1;
|
||||
char name[0x10];
|
||||
} pkg3_content_t;
|
||||
|
||||
static void _pkg3_update_r2p()
|
||||
{
|
||||
u8 *r2p_payload = emusd_file_read("atmosphere/reboot_payload.bin", NULL);
|
||||
|
||||
is_ipl_updated(r2p_payload, "emusd:atmosphere/reboot_payload.bin", h_cfg.updater2p ? true : false);
|
||||
|
||||
free(r2p_payload);
|
||||
}
|
||||
|
||||
static int _pkg3_kip1_skip(char ***pkg3_kip1_skip, u32 *pkg3_kip1_skip_num, char *value)
|
||||
{
|
||||
int len = strlen(value);
|
||||
if (!len || (*pkg3_kip1_skip_num) >= PKG3_KIP_SKIP_MAX)
|
||||
return 0;
|
||||
|
||||
// Allocate pointer list memory.
|
||||
if (!(*pkg3_kip1_skip))
|
||||
(*pkg3_kip1_skip) = calloc(PKG3_KIP_SKIP_MAX, sizeof(char *));
|
||||
|
||||
// Set first kip name.
|
||||
(*pkg3_kip1_skip)[(*pkg3_kip1_skip_num)++] = value;
|
||||
|
||||
// Check if more names are set separated by comma.
|
||||
for (char *c = value; *c != 0; c++)
|
||||
{
|
||||
if (*c == ',')
|
||||
{
|
||||
*c = 0; // Null termination.
|
||||
|
||||
// Set next kip name to the list.
|
||||
(*pkg3_kip1_skip)[(*pkg3_kip1_skip_num)++] = c + 1;
|
||||
|
||||
if ((*pkg3_kip1_skip_num) >= PKG3_KIP_SKIP_MAX)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int parse_pkg3(launch_ctxt_t *ctxt, const char *path)
|
||||
{
|
||||
char *path1 = (char *)malloc(256);
|
||||
strcpy(path1, "emusd:");
|
||||
strcat(path1, path);
|
||||
|
||||
FIL fp;
|
||||
|
||||
char **pkg3_kip1_skip = NULL;
|
||||
u32 pkg3_kip1_skip_num = 0;
|
||||
|
||||
bool stock = false;
|
||||
bool experimental = false;
|
||||
|
||||
// Skip if stock and Exosphere and warmboot are not needed.
|
||||
bool pkg1_old = ctxt->pkg1_id->kb <= HOS_KB_VERSION_620; // Should check if t210b01?
|
||||
bool emummc_disabled = !emu_cfg.enabled || h_cfg.emummc_force_disable;
|
||||
|
||||
LIST_FOREACH_ENTRY(ini_kv_t, kv, &ctxt->cfg->kvs, link)
|
||||
{
|
||||
if (!strcmp("stock", kv->key))
|
||||
if (kv->val[0] == '1')
|
||||
stock = true;
|
||||
|
||||
if (!strcmp("pkg3ex", kv->key))
|
||||
if (kv->val[0] == '1')
|
||||
experimental = true;
|
||||
|
||||
if (!strcmp("pkg3kip1skip", kv->key))
|
||||
_pkg3_kip1_skip(&pkg3_kip1_skip, &pkg3_kip1_skip_num, kv->val);
|
||||
}
|
||||
|
||||
#ifdef HOS_MARIKO_STOCK_SECMON
|
||||
if (stock && emummc_disabled && (pkg1_old || h_cfg.t210b01)) {
|
||||
free(path1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
#else
|
||||
if (stock && emummc_disabled && pkg1_old) {
|
||||
free(path1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// Try to open PKG3.
|
||||
if (f_open(&fp, path1, FA_READ) != FR_OK) {
|
||||
free(path1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void *pkg3 = malloc(f_size(&fp));
|
||||
|
||||
// Read first 1024 bytes of the PKG3 file.
|
||||
f_read(&fp, pkg3, 1024, NULL);
|
||||
|
||||
// Get PKG3 Meta header offset.
|
||||
u32 pkg3_meta_addr = *(u32 *)(pkg3 + PKG3_META_OFFSET);
|
||||
pkg3_meta_t *pkg3_meta = (pkg3_meta_t *)(pkg3 + pkg3_meta_addr);
|
||||
|
||||
// Check if valid PKG3 and parse it.
|
||||
if (pkg3_meta->magic == PKG3_MAGIC)
|
||||
{
|
||||
gfx_printf("Atmosphere %d.%d.%d-%08x via PKG3\n"
|
||||
"Max HOS: %d.%d.%d\n"
|
||||
"Unpacking.. ",
|
||||
pkg3_meta->version >> 24, (pkg3_meta->version >> 16) & 0xFF, (pkg3_meta->version >> 8) & 0xFF, pkg3_meta->git_rev,
|
||||
pkg3_meta->hos_ver >> 24, (pkg3_meta->hos_ver >> 16) & 0xFF, (pkg3_meta->hos_ver >> 8) & 0xFF);
|
||||
|
||||
ctxt->patch_krn_proc_id = true;
|
||||
ctxt->pkg3_hosver = pkg3_meta->hos_ver;
|
||||
|
||||
// Parse PKG3 contents.
|
||||
pkg3_content_t *curr_pkg3_cnt = (pkg3_content_t *)(pkg3 + pkg3_meta->cnt_off);
|
||||
void *content;
|
||||
for (u32 i = 0; i < pkg3_meta->cnt_count; i++)
|
||||
{
|
||||
content = (void *)(pkg3 + curr_pkg3_cnt[i].offset);
|
||||
|
||||
// Check if offset is inside limits.
|
||||
if ((curr_pkg3_cnt[i].offset + curr_pkg3_cnt[i].size) > pkg3_meta->size)
|
||||
continue;
|
||||
|
||||
// If content is experimental and experimental config is not enabled, skip it.
|
||||
if ((curr_pkg3_cnt[i].flags0 & CNT_FLAG0_EXPERIMENTAL) && !experimental)
|
||||
continue;
|
||||
|
||||
// Prepare content.
|
||||
switch (curr_pkg3_cnt[i].type)
|
||||
{
|
||||
case CNT_TYPE_KIP:
|
||||
if (stock)
|
||||
continue;
|
||||
|
||||
bool should_skip = false;
|
||||
for (u32 k = 0; k < pkg3_kip1_skip_num; k++)
|
||||
{
|
||||
if (!strcmp(curr_pkg3_cnt[i].name, pkg3_kip1_skip[k]))
|
||||
{
|
||||
gfx_printf("Skipped %s.kip1 from PKG3\n", curr_pkg3_cnt[i].name);
|
||||
should_skip = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (should_skip)
|
||||
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 PKG3 (size %08X)\n", curr_pkg3_cnt[i].name, curr_pkg3_cnt[i].size);
|
||||
break;
|
||||
|
||||
case CNT_TYPE_KRN:
|
||||
if (stock)
|
||||
continue;
|
||||
ctxt->kernel_size = curr_pkg3_cnt[i].size;
|
||||
ctxt->kernel = content;
|
||||
break;
|
||||
|
||||
case CNT_TYPE_EXO:
|
||||
ctxt->secmon_size = curr_pkg3_cnt[i].size;
|
||||
ctxt->secmon = content;
|
||||
break;
|
||||
|
||||
case CNT_TYPE_EXF:
|
||||
ctxt->exofatal_size = curr_pkg3_cnt[i].size;
|
||||
ctxt->exofatal = content;
|
||||
break;
|
||||
|
||||
case CNT_TYPE_WBT:
|
||||
if (h_cfg.t210b01)
|
||||
continue;
|
||||
ctxt->warmboot_size = curr_pkg3_cnt[i].size;
|
||||
ctxt->warmboot = content;
|
||||
break;
|
||||
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
|
||||
// Load content to launch context.
|
||||
f_lseek(&fp, curr_pkg3_cnt[i].offset);
|
||||
f_read(&fp, content, curr_pkg3_cnt[i].size, NULL);
|
||||
}
|
||||
|
||||
gfx_printf("Done!\n");
|
||||
f_close(&fp);
|
||||
|
||||
ctxt->pkg3 = pkg3;
|
||||
|
||||
// Update r2p if needed.
|
||||
_pkg3_update_r2p();
|
||||
|
||||
free(pkg3_kip1_skip);
|
||||
free(path1);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Failed. Close and free all.
|
||||
f_close(&fp);
|
||||
|
||||
free(pkg3_kip1_skip);
|
||||
free(pkg3);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -14,11 +14,11 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _FSS_H_
|
||||
#define _FSS_H_
|
||||
#ifndef _PKG3_H_
|
||||
#define _PKG3_H_
|
||||
|
||||
#include "hos.h"
|
||||
|
||||
int parse_fss(launch_ctxt_t *ctxt, const char *path);
|
||||
int parse_pkg3(launch_ctxt_t *ctxt, const char *path);
|
||||
|
||||
#endif
|
||||
@@ -24,14 +24,17 @@
|
||||
#include "../config.h"
|
||||
#include <libs/fatfs/ff.h>
|
||||
#include "../storage/emummc.h"
|
||||
#include "../storage/emusd.h"
|
||||
|
||||
extern hekate_config h_cfg;
|
||||
|
||||
enum emuMMC_Type
|
||||
{
|
||||
emuMMC_None = 0,
|
||||
emuMMC_Partition,
|
||||
emuMMC_File,
|
||||
EmummcType_None = 0,
|
||||
EmummcType_Partition_Sd = 1,
|
||||
EmummcType_File_Sd = 2,
|
||||
EmummcType_Partition_Emmc = 3,
|
||||
EmummcType_File_Emmc = 4,
|
||||
emuMMC_MAX
|
||||
};
|
||||
|
||||
@@ -66,6 +69,22 @@ typedef struct
|
||||
emummc_file_config_t file_cfg;
|
||||
};
|
||||
char nintendo_path[EMUMMC_FILE_PATH_MAX];
|
||||
} emummc_emmc_config_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
emummc_base_config_t base_cfg;
|
||||
union
|
||||
{
|
||||
emummc_partition_config_t partition_cfg;
|
||||
emummc_file_config_t file_cfg;
|
||||
};
|
||||
} emummc_sd_config_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
emummc_emmc_config_t emmc_cfg;
|
||||
emummc_sd_config_t sd_cfg;
|
||||
} exo_emummc_config_t;
|
||||
|
||||
typedef struct _exo_cfg_t
|
||||
@@ -77,7 +96,8 @@ typedef struct _exo_cfg_t
|
||||
u8 uart_port;
|
||||
u8 uart_invert;
|
||||
u32 uart_baudrate;
|
||||
u32 rsvd1[2];
|
||||
u8 memory_mode_auto;
|
||||
u8 rsvd1[7];
|
||||
exo_emummc_config_t emummc_cfg;
|
||||
} exo_cfg_t;
|
||||
|
||||
@@ -199,7 +219,7 @@ void config_exosphere(launch_ctxt_t *ctxt, u32 warmboot_base)
|
||||
case 12:
|
||||
exo_fw_no = EXO_FW_VER(9, 1);
|
||||
break;
|
||||
case 13 ... 22: //!TODO: Update on API changes. 22: 19.0.0.
|
||||
case 13 ... 23: //!TODO: Update on API changes. 23: 20.0.0.
|
||||
exo_fw_no = EXO_FW_VER(exo_fw_no - 3, ctxt->exo_ctx.hos_revision);
|
||||
break;
|
||||
}
|
||||
@@ -208,7 +228,7 @@ void config_exosphere(launch_ctxt_t *ctxt, u32 warmboot_base)
|
||||
if (!ctxt->stock)
|
||||
{
|
||||
LIST_INIT(ini_exo_sections);
|
||||
if (ini_parse(&ini_exo_sections, "exosphere.ini", false))
|
||||
if (ini_parse(&ini_exo_sections, "emusd:exosphere.ini", false))
|
||||
{
|
||||
LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_exo_sections, link)
|
||||
{
|
||||
@@ -216,6 +236,7 @@ void config_exosphere(launch_ctxt_t *ctxt, u32 warmboot_base)
|
||||
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))
|
||||
@@ -226,12 +247,14 @@ void config_exosphere(launch_ctxt_t *ctxt, u32 warmboot_base)
|
||||
exo_cfg->uart_invert = atoi(kv->val);
|
||||
else if (!strcmp("log_baud_rate", kv->key))
|
||||
exo_cfg->uart_baudrate = atoi(kv->val);
|
||||
else if (!strcmp("memory_mode_auto", kv->key)) {
|
||||
exo_cfg->memory_mode_auto = 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
|
||||
} else
|
||||
{
|
||||
if (!strcmp("blank_prodinfo_sysmmc", kv->key))
|
||||
cal0_blanking = atoi(kv->val);
|
||||
@@ -241,36 +264,36 @@ void config_exosphere(launch_ctxt_t *ctxt, u32 warmboot_base)
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Parse usb mtim settings. Avoid parsing if it's overridden.
|
||||
if (!ctxt->exo_ctx.usb3_force)
|
||||
// Parse usb mtim settings. Avoid parsing if it's overridden.
|
||||
if (!ctxt->exo_ctx.usb3_force)
|
||||
{
|
||||
LIST_INIT(ini_sys_sections);
|
||||
if (ini_parse(&ini_sys_sections, "emusd:atmosphere/config/system_settings.ini", false))
|
||||
{
|
||||
LIST_INIT(ini_sys_sections);
|
||||
if (ini_parse(&ini_sys_sections, "atmosphere/config/system_settings.ini", false))
|
||||
LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_sys_sections, link)
|
||||
{
|
||||
LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_sys_sections, link)
|
||||
{
|
||||
// Only parse usb section.
|
||||
if (!(ini_sec->type == INI_CHOICE) || strcmp(ini_sec->name, "usb"))
|
||||
continue;
|
||||
// Only parse usb section.
|
||||
if (!(ini_sec->type == INI_CHOICE) || strcmp(ini_sec->name, "usb"))
|
||||
continue;
|
||||
|
||||
LIST_FOREACH_ENTRY(ini_kv_t, kv, &ini_sec->kvs, link)
|
||||
LIST_FOREACH_ENTRY(ini_kv_t, kv, &ini_sec->kvs, link)
|
||||
{
|
||||
if (!strcmp("usb30_force_enabled", kv->key))
|
||||
{
|
||||
if (!strcmp("usb30_force_enabled", kv->key))
|
||||
{
|
||||
usb3_force = !strcmp("u8!0x1", kv->val);
|
||||
break; // Only parse usb30_force_enabled key.
|
||||
}
|
||||
usb3_force = !strcmp("u8!0x1", kv->val);
|
||||
break; // Only parse usb30_force_enabled key.
|
||||
}
|
||||
break;
|
||||
}
|
||||
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))
|
||||
// Private debug mode always on for CFW mode.
|
||||
if (!ctxt->stock)
|
||||
exo_flags |= EXO_FLAG_DBG_PRIV;
|
||||
|
||||
// Enable user debug.
|
||||
@@ -316,22 +339,72 @@ void config_exosphere(launch_ctxt_t *ctxt, u32 warmboot_base)
|
||||
pkg1_warmboot_rsa_mod(warmboot_base);
|
||||
}
|
||||
|
||||
// By default, disable emuMMC
|
||||
exo_cfg->emummc_cfg.emmc_cfg.base_cfg.magic = EMUMMC_MAGIC;
|
||||
exo_cfg->emummc_cfg.emmc_cfg.base_cfg.type = EmummcType_None;
|
||||
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;
|
||||
exo_cfg->emummc_cfg.emmc_cfg.base_cfg.fs_ver = emu_cfg.fs_ver;
|
||||
exo_cfg->emummc_cfg.sd_cfg.base_cfg.fs_ver = emu_sd_cfg.fs_ver;
|
||||
|
||||
exo_cfg->emummc_cfg.emmc_cfg.base_cfg.id = emu_cfg.id;
|
||||
if (emu_cfg.enabled == 4 && emu_cfg.sector) {
|
||||
// emmc partition based
|
||||
exo_cfg->emummc_cfg.emmc_cfg.base_cfg.type = EmummcType_Partition_Emmc;
|
||||
} else if (emu_cfg.enabled == 4 && !emu_cfg.sector) {
|
||||
// emmc file based
|
||||
exo_cfg->emummc_cfg.emmc_cfg.base_cfg.type = EmummcType_File_Emmc;
|
||||
} else if (emu_cfg.enabled == 1 && emu_cfg.sector) {
|
||||
// sd partition based
|
||||
exo_cfg->emummc_cfg.emmc_cfg.base_cfg.type = EmummcType_Partition_Sd;
|
||||
} else if (emu_cfg.enabled == 1 && !emu_cfg.sector) {
|
||||
// sd file based
|
||||
exo_cfg->emummc_cfg.emmc_cfg.base_cfg.type = EmummcType_File_Sd;
|
||||
} else {
|
||||
// disabled
|
||||
exo_cfg->emummc_cfg.emmc_cfg.base_cfg.type = EmummcType_None;
|
||||
}
|
||||
|
||||
if (emu_cfg.sector)
|
||||
exo_cfg->emummc_cfg.partition_cfg.start_sector = emu_cfg.sector;
|
||||
exo_cfg->emummc_cfg.emmc_cfg.partition_cfg.start_sector = emu_cfg.sector;
|
||||
else
|
||||
strcpy((char *)exo_cfg->emummc_cfg.file_cfg.path, emu_cfg.path);
|
||||
strcpy((char *)exo_cfg->emummc_cfg.emmc_cfg.file_cfg.path, emu_cfg.path);
|
||||
|
||||
if (!ctxt->stock && emu_cfg.nintendo_path && emu_cfg.nintendo_path[0])
|
||||
strcpy((char *)exo_cfg->emummc_cfg.nintendo_path, emu_cfg.nintendo_path);
|
||||
strcpy((char *)exo_cfg->emummc_cfg.emmc_cfg.nintendo_path, emu_cfg.nintendo_path);
|
||||
else
|
||||
strcpy((char *)exo_cfg->emummc_cfg.nintendo_path, "Nintendo");
|
||||
strcpy((char *)exo_cfg->emummc_cfg.emmc_cfg.nintendo_path, "Nintendo");
|
||||
}
|
||||
|
||||
exo_cfg->emummc_cfg.sd_cfg.base_cfg.magic = EMUMMC_MAGIC;
|
||||
exo_cfg->emummc_cfg.sd_cfg.base_cfg.type = EmummcType_None;
|
||||
if (emu_sd_cfg.enabled)
|
||||
{
|
||||
exo_cfg->emummc_cfg.sd_cfg.base_cfg.fs_ver = emu_sd_cfg.fs_ver;
|
||||
exo_cfg->emummc_cfg.emmc_cfg.base_cfg.fs_ver = emu_sd_cfg.fs_ver;
|
||||
|
||||
exo_cfg->emummc_cfg.sd_cfg.base_cfg.id = emu_sd_cfg.id;
|
||||
if (emu_sd_cfg.enabled == 4 && emu_sd_cfg.sector) {
|
||||
// emmc partition based
|
||||
exo_cfg->emummc_cfg.sd_cfg.base_cfg.type = EmummcType_Partition_Emmc;
|
||||
} else if (emu_sd_cfg.enabled == 4 && !emu_sd_cfg.sector) {
|
||||
// emmc file based
|
||||
exo_cfg->emummc_cfg.sd_cfg.base_cfg.type = EmummcType_File_Emmc;
|
||||
} else if (emu_sd_cfg.enabled == 1 && emu_sd_cfg.sector) {
|
||||
// sd partition based
|
||||
exo_cfg->emummc_cfg.sd_cfg.base_cfg.type = EmummcType_Partition_Sd;
|
||||
} else if (emu_sd_cfg.enabled == 1 && !emu_sd_cfg.sector) {
|
||||
// sd file based
|
||||
exo_cfg->emummc_cfg.sd_cfg.base_cfg.type = EmummcType_File_Sd;
|
||||
} else {
|
||||
// disabled
|
||||
exo_cfg->emummc_cfg.sd_cfg.base_cfg.type = EmummcType_None;
|
||||
}
|
||||
|
||||
if (emu_sd_cfg.sector)
|
||||
exo_cfg->emummc_cfg.sd_cfg.partition_cfg.start_sector = emu_sd_cfg.sector;
|
||||
else
|
||||
strcpy((char *)exo_cfg->emummc_cfg.sd_cfg.file_cfg.path, emu_sd_cfg.path);
|
||||
}
|
||||
|
||||
// Copy over exosphere fatal for Mariko.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* L4T Loader for Tegra X1
|
||||
*
|
||||
* Copyright (c) 2020-2024 CTCaer
|
||||
* Copyright (c) 2020-2025 CTCaer
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
@@ -25,6 +25,7 @@
|
||||
#include "../hos/pkg1.h"
|
||||
#include "l4t.h"
|
||||
#include "l4t_config.inl"
|
||||
#include <storage/boot_storage.h>
|
||||
|
||||
/*
|
||||
* API Revision info
|
||||
@@ -272,6 +273,8 @@ typedef struct _l4t_ctxt_t
|
||||
int ram_oc_opt;
|
||||
|
||||
u32 serial_port;
|
||||
u32 sld_type;
|
||||
|
||||
u32 sc7entry_size;
|
||||
|
||||
emc_table_t *mtc_table;
|
||||
@@ -288,18 +291,22 @@ typedef struct _l4t_ctxt_t
|
||||
#define DRAM_VDDQ_OC_MAX_VOLTAGE 650
|
||||
#define DRAM_T210B01_TBL_MAX_FREQ 1600000
|
||||
|
||||
//! TODO: Update on dram config changes.
|
||||
#define NA 0 // Default to 0 for incorrect dram ids.
|
||||
|
||||
//!TODO: Update on dram config changes.
|
||||
static const u8 mtc_table_idx_t210b01[] = {
|
||||
/* 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 */
|
||||
-1, -1, -1, 7, -1, 7, 7, -1, 0, 1, 2, 3, 0, 1, 2, 3, -1, 4, 5, 4, 8, 8, 8, 5, 4, 6, 6, 6, 5, 9, 9, 9, 10, 10, 10
|
||||
NA, NA, NA, 7, NA, 7, 7, NA, 0, 1, 2, 3, 0, 1, 2, 3, NA, 4, 5, 4, 8, 8, 8, 5, 4, 6, 6, 6, 5, 9, 9, 9, 10, 10, 10
|
||||
};
|
||||
|
||||
#undef NA
|
||||
|
||||
static const l4t_fw_t l4t_fw[] = {
|
||||
{ TZDRAM_BASE, "bl31.bin" },
|
||||
{ BL33_LOAD_BASE, "bl33.bin" },
|
||||
{ SC7ENTRY_BASE, "sc7entry.bin" },
|
||||
{ SC7EXIT_BASE, "sc7exit.bin" },
|
||||
{ SC7EXIT_B01_BASE, "sc7exit_b01.bin" },
|
||||
{ SC7EXIT_B01_BASE, "sc7exit_b01.bin" }, //!TODO: Update on fuse burns.
|
||||
{ BPMPFW_BASE, "bpmpfw.bin" },
|
||||
{ BPMPFW_B01_BASE, "bpmpfw_b01.bin" },
|
||||
{ BPMPFW_B01_MTC_TABLE_BASE, "mtc_tbl_b01.bin" },
|
||||
@@ -380,7 +387,7 @@ static void _l4t_sdram_lp0_save_params(bool t210b01)
|
||||
s(MC_VIDEO_PROTECT_REG_CTRL, 1:0, secure_scratch14, 31:30);
|
||||
}
|
||||
|
||||
// TZD.
|
||||
// TZDRAM.
|
||||
s(MC_SEC_CARVEOUT_BOM, 31:20, secure_scratch53, 23:12);
|
||||
s(MC_SEC_CARVEOUT_SIZE_MB, 11:0, secure_scratch54, 11:0);
|
||||
if (!t210b01) {
|
||||
@@ -522,11 +529,6 @@ static void _l4t_mc_config_carveout(bool t210b01)
|
||||
MC(MC_SECURITY_CARVEOUT1_CLIENT_ACCESS2) = SEC_CARVEOUT_CA2_R_TSEC | SEC_CARVEOUT_CA2_W_TSEC;
|
||||
MC(MC_SECURITY_CARVEOUT1_CLIENT_ACCESS3) = SEC_CARVEOUT_CA3_R_NVDEC | SEC_CARVEOUT_CA3_W_NVDEC;
|
||||
MC(MC_SECURITY_CARVEOUT1_CLIENT_ACCESS4) = 0;
|
||||
MC(MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS0) = 0;
|
||||
MC(MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS1) = 0;
|
||||
MC(MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS2) = 0;
|
||||
MC(MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS3) = 0;
|
||||
MC(MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS4) = 0;
|
||||
MC(MC_SECURITY_CARVEOUT1_CFG0) = SEC_CARVEOUT_CFG_LOCKED |
|
||||
SEC_CARVEOUT_CFG_UNTRANSLATED_ONLY |
|
||||
SEC_CARVEOUT_CFG_RD_SEC |
|
||||
@@ -558,11 +560,6 @@ static void _l4t_mc_config_carveout(bool t210b01)
|
||||
MC(MC_SECURITY_CARVEOUT1_CLIENT_ACCESS2) = 0;
|
||||
MC(MC_SECURITY_CARVEOUT1_CLIENT_ACCESS3) = 0;
|
||||
MC(MC_SECURITY_CARVEOUT1_CLIENT_ACCESS4) = 0;
|
||||
MC(MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS0) = 0;
|
||||
MC(MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS1) = 0;
|
||||
MC(MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS2) = 0;
|
||||
MC(MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS3) = 0;
|
||||
MC(MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS4) = 0;
|
||||
MC(MC_SECURITY_CARVEOUT1_CFG0) = SEC_CARVEOUT_CFG_RD_NS |
|
||||
SEC_CARVEOUT_CFG_RD_SEC |
|
||||
SEC_CARVEOUT_CFG_WR_NS |
|
||||
@@ -599,11 +596,6 @@ static void _l4t_mc_config_carveout(bool t210b01)
|
||||
MC(MC_SECURITY_CARVEOUT2_CLIENT_ACCESS2) = SEC_CARVEOUT_CA2_R_GPU | SEC_CARVEOUT_CA2_W_GPU | SEC_CARVEOUT_CA2_R_TSEC;
|
||||
MC(MC_SECURITY_CARVEOUT2_CLIENT_ACCESS3) = 0;
|
||||
MC(MC_SECURITY_CARVEOUT2_CLIENT_ACCESS4) = SEC_CARVEOUT_CA4_R_GPU2 | SEC_CARVEOUT_CA4_W_GPU2;
|
||||
MC(MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS0) = 0;
|
||||
MC(MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS1) = 0;
|
||||
MC(MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS2) = 0;
|
||||
MC(MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS3) = 0;
|
||||
MC(MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS4) = 0;
|
||||
MC(MC_SECURITY_CARVEOUT2_CFG0) = SEC_CARVEOUT_CFG_LOCKED |
|
||||
SEC_CARVEOUT_CFG_UNTRANSLATED_ONLY |
|
||||
SEC_CARVEOUT_CFG_RD_NS |
|
||||
@@ -632,11 +624,6 @@ static void _l4t_mc_config_carveout(bool t210b01)
|
||||
MC(MC_SECURITY_CARVEOUT3_CLIENT_ACCESS2) = 0; // HOS: SEC_CARVEOUT_CA2_R_GPU | SEC_CARVEOUT_CA2_W_GPU
|
||||
MC(MC_SECURITY_CARVEOUT3_CLIENT_ACCESS3) = 0;
|
||||
MC(MC_SECURITY_CARVEOUT3_CLIENT_ACCESS4) = 0; // HOS: SEC_CARVEOUT_CA4_R_GPU2 | SEC_CARVEOUT_CA4_W_GPU2
|
||||
MC(MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS0) = 0;
|
||||
MC(MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS1) = 0;
|
||||
MC(MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS2) = 0;
|
||||
MC(MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS3) = 0;
|
||||
MC(MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS4) = 0;
|
||||
MC(MC_SECURITY_CARVEOUT3_CFG0) = SEC_CARVEOUT_CFG_LOCKED |
|
||||
SEC_CARVEOUT_CFG_UNTRANSLATED_ONLY |
|
||||
SEC_CARVEOUT_CFG_RD_NS |
|
||||
@@ -866,6 +853,9 @@ static void _l4t_set_config(l4t_ctxt_t *ctxt, const ini_sec_t *ini_sec, int entr
|
||||
bl33_env[0] = '\0';
|
||||
char val[4] = {0};
|
||||
|
||||
// Set default SLD type.
|
||||
ctxt->sld_type = BL_MAGIC_L4TLDR_SLD;
|
||||
|
||||
// Parse ini section and prepare BL33 env.
|
||||
LIST_FOREACH_ENTRY(ini_kv_t, kv, &ini_sec->kvs, link)
|
||||
{
|
||||
@@ -896,9 +886,11 @@ static void _l4t_set_config(l4t_ctxt_t *ctxt, const ini_sec_t *ini_sec, int entr
|
||||
ctxt->ram_oc_vddq = 0;
|
||||
}
|
||||
else if (!strcmp("ram_oc_opt", kv->key))
|
||||
ctxt->ram_oc_opt = atoi(kv->val);
|
||||
ctxt->ram_oc_opt = atoi(kv->val);
|
||||
else if (!strcmp("uart_port", kv->key))
|
||||
ctxt->serial_port = atoi(kv->val);
|
||||
else if (!strcmp("sld_type", kv->key))
|
||||
ctxt->sld_type = strtol(kv->val, NULL, 16);
|
||||
|
||||
// Set key/val to BL33 env.
|
||||
_l4t_bl33_cfg_set_key(bl33_env, kv->key, kv->val);
|
||||
@@ -1025,7 +1017,9 @@ void launch_l4t(const ini_sec_t *ini_sec, int entry_idx, int is_list, bool t210b
|
||||
return;
|
||||
|
||||
// Done loading bootloaders/firmware.
|
||||
boot_storage_end();
|
||||
sd_end();
|
||||
emmc_end();
|
||||
|
||||
// We don't need AHB aperture open.
|
||||
mc_disable_ahb_redirect();
|
||||
@@ -1165,7 +1159,7 @@ void launch_l4t(const ini_sec_t *ini_sec, int entry_idx, int is_list, bool t210b
|
||||
_l4t_mc_config_carveout(t210b01);
|
||||
|
||||
// Deinit any unneeded HW.
|
||||
hw_deinit(false, BL_MAGIC_L4TLDR_SLD);
|
||||
hw_deinit(false, ctxt->sld_type);
|
||||
|
||||
// Do late hardware config.
|
||||
_l4t_late_hw_config(t210b01);
|
||||
|
||||
@@ -7,11 +7,39 @@
|
||||
/* storage control modules to the FatFs module with a defined API. */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
#include <string.h>
|
||||
#include "../../storage/emusd.h"
|
||||
#include <storage/sd.h>
|
||||
#include <storage/sdmmc.h>
|
||||
|
||||
#include <bdk.h>
|
||||
|
||||
#include <libs/fatfs/diskio.h> /* FatFs lower layer API */
|
||||
#include <fatfs_cfg.h>
|
||||
|
||||
static bool ensure_partition(BYTE pdrv){
|
||||
u8 part;
|
||||
switch(pdrv){
|
||||
case DRIVE_SD:
|
||||
return true;
|
||||
case DRIVE_BOOT1:
|
||||
case DRIVE_BOOT1_1MB:
|
||||
part = EMMC_BOOT1;
|
||||
break;
|
||||
case DRIVE_EMMC:
|
||||
part = EMMC_GPP;
|
||||
break;
|
||||
case DRIVE_EMUSD:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
if(emmc_storage.partition != part){
|
||||
return emmc_set_partition(part);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Get Drive Status */
|
||||
@@ -43,7 +71,33 @@ DRESULT disk_read (
|
||||
UINT count /* Number of sectors to read */
|
||||
)
|
||||
{
|
||||
return sdmmc_storage_read(&sd_storage, sector, count, buff) ? RES_OK : RES_ERROR;
|
||||
if(!ensure_partition(pdrv)){
|
||||
return RES_ERROR;
|
||||
}
|
||||
|
||||
sdmmc_storage_t *storage = &sd_storage;
|
||||
u32 actual_sector = sector;
|
||||
switch(pdrv){
|
||||
case DRIVE_SD:
|
||||
break;
|
||||
case DRIVE_BOOT1:
|
||||
case DRIVE_EMMC:
|
||||
storage = &emmc_storage;
|
||||
break;
|
||||
case DRIVE_BOOT1_1MB:
|
||||
storage = &emmc_storage;
|
||||
actual_sector = sector + (0x100000 / 512);
|
||||
break;
|
||||
case DRIVE_EMUSD:
|
||||
return emusd_storage_read(sector, count, buff) ? RES_OK : RES_ERROR;
|
||||
break;
|
||||
default:
|
||||
return RES_ERROR;
|
||||
|
||||
}
|
||||
|
||||
|
||||
return sdmmc_storage_read(storage, actual_sector, count, buff) ? RES_OK : RES_ERROR;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
@@ -56,7 +110,32 @@ DRESULT disk_write (
|
||||
UINT count /* Number of sectors to write */
|
||||
)
|
||||
{
|
||||
return sdmmc_storage_write(&sd_storage, sector, count, (void *)buff) ? RES_OK : RES_ERROR;
|
||||
if(!ensure_partition(pdrv)){
|
||||
return RES_ERROR;
|
||||
}
|
||||
|
||||
sdmmc_storage_t *storage = &sd_storage;
|
||||
u32 actual_sector = sector;
|
||||
switch(pdrv){
|
||||
case DRIVE_SD:
|
||||
break;
|
||||
case DRIVE_BOOT1:
|
||||
case DRIVE_EMMC:
|
||||
storage = &emmc_storage;
|
||||
break;
|
||||
case DRIVE_BOOT1_1MB:
|
||||
storage = &emmc_storage;
|
||||
actual_sector = sector + (0x100000 / 512);
|
||||
break;
|
||||
case DRIVE_EMUSD:
|
||||
return emusd_storage_write(sector, count, (void*)buff) ? RES_OK : RES_ERROR;
|
||||
default:
|
||||
return RES_ERROR;
|
||||
|
||||
}
|
||||
|
||||
|
||||
return sdmmc_storage_write(storage, actual_sector, count, (void*)buff) ? RES_OK : RES_ERROR;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
@@ -166,7 +166,7 @@
|
||||
*/
|
||||
|
||||
|
||||
#define FF_FS_RPATH 0
|
||||
#define FF_FS_RPATH 2
|
||||
/* This option configures support for relative path.
|
||||
/
|
||||
/ 0: Disable relative path and remove related functions.
|
||||
@@ -179,12 +179,12 @@
|
||||
/ Drive/Volume Configurations
|
||||
/---------------------------------------------------------------------------*/
|
||||
|
||||
#define FF_VOLUMES 1
|
||||
#define FF_VOLUMES 5
|
||||
/* Number of volumes (logical drives) to be used. (1-10) */
|
||||
|
||||
|
||||
#define FF_STR_VOLUME_ID 0
|
||||
#define FF_VOLUME_STRS "sd"
|
||||
#define FF_STR_VOLUME_ID 1
|
||||
#define FF_VOLUME_STRS "sd", "boot1", "boot1_1mb", "emmc", "emusd"
|
||||
/* 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
|
||||
/ number in the path name. FF_VOLUME_STRS defines the volume ID strings for each
|
||||
@@ -256,7 +256,7 @@
|
||||
#define FF_FS_NORTC 1
|
||||
#define FF_NORTC_MON 1
|
||||
#define FF_NORTC_MDAY 1
|
||||
#define FF_NORTC_YEAR 2024
|
||||
#define FF_NORTC_YEAR 2025
|
||||
/* The option FF_FS_NORTC switches timestamp function. If the system does not have
|
||||
/ any RTC function or valid timestamp is not needed, set FF_FS_NORTC = 1 to disable
|
||||
/ the timestamp function. Every object modified by FatFs will have a fixed timestamp
|
||||
@@ -301,5 +301,12 @@
|
||||
/ included somewhere in the scope of ff.h. */
|
||||
|
||||
|
||||
typedef enum {
|
||||
DRIVE_SD = 0,
|
||||
DRIVE_BOOT1 = 1,
|
||||
DRIVE_BOOT1_1MB = 2,
|
||||
DRIVE_EMMC = 3,
|
||||
DRIVE_EMUSD = 4,
|
||||
} DDRIVE;
|
||||
|
||||
/*--- End of configuration options ---*/
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include <bdk.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "gfx/gfx.h"
|
||||
#include "gfx/logos.h"
|
||||
#include "gfx/tui.h"
|
||||
#include "hos/hos.h"
|
||||
@@ -31,9 +32,11 @@
|
||||
#include <libs/compr/blz.h>
|
||||
#include <libs/fatfs/ff.h>
|
||||
#include "storage/emummc.h"
|
||||
#include <storage/boot_storage.h>
|
||||
|
||||
#include "frontend/fe_tools.h"
|
||||
#include "frontend/fe_info.h"
|
||||
#include "storage/emusd.h"
|
||||
|
||||
hekate_config h_cfg;
|
||||
boot_cfg_t __attribute__((section ("._boot_cfg"))) b_cfg;
|
||||
@@ -205,7 +208,9 @@ static void _launch_payload(char *path, bool update, bool clear_screen)
|
||||
if (update && is_ipl_updated(buf, path, false))
|
||||
goto out;
|
||||
|
||||
boot_storage_end();
|
||||
sd_end();
|
||||
emmc_end();
|
||||
|
||||
if (size < 0x30000)
|
||||
{
|
||||
@@ -264,8 +269,8 @@ static void _launch_payloads()
|
||||
gfx_clear_grey(0x1B);
|
||||
gfx_con_setpos(0, 0);
|
||||
|
||||
if (!sd_mount())
|
||||
goto failed_sd_mount;
|
||||
if (!boot_storage_mount())
|
||||
goto failed_boot_storage_mount;
|
||||
|
||||
ments = (ment_t *)malloc(sizeof(ment_t) * (max_entries + 3));
|
||||
|
||||
@@ -308,7 +313,7 @@ static void _launch_payloads()
|
||||
free(ments);
|
||||
free(dir);
|
||||
free(filelist);
|
||||
sd_end();
|
||||
boot_storage_end();
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -324,11 +329,11 @@ static void _launch_payloads()
|
||||
_launch_payload(dir, false, true);
|
||||
}
|
||||
|
||||
failed_sd_mount:
|
||||
failed_boot_storage_mount:
|
||||
free(dir);
|
||||
free(ments);
|
||||
free(filelist);
|
||||
sd_end();
|
||||
boot_storage_end();
|
||||
|
||||
btn_wait();
|
||||
}
|
||||
@@ -338,6 +343,7 @@ static void _launch_ini_list()
|
||||
u8 max_entries = 61;
|
||||
char *special_path = NULL;
|
||||
char *emummc_path = NULL;
|
||||
char *emusd_path = NULL;
|
||||
ment_t *ments = NULL;
|
||||
ini_sec_t *cfg_sec = NULL;
|
||||
|
||||
@@ -346,7 +352,7 @@ static void _launch_ini_list()
|
||||
gfx_clear_grey(0x1B);
|
||||
gfx_con_setpos(0, 0);
|
||||
|
||||
if (!sd_mount())
|
||||
if (!boot_storage_mount())
|
||||
goto parse_failed;
|
||||
|
||||
// Check that ini files exist and parse them.
|
||||
@@ -402,13 +408,22 @@ static void _launch_ini_list()
|
||||
h_cfg.emummc_force_disable = atoi(kv->val);
|
||||
else if (!strcmp("emupath", kv->key))
|
||||
emummc_path = kv->val;
|
||||
else if (!strcmp("emusdpath", kv->key))
|
||||
emusd_path = kv->val;
|
||||
}
|
||||
|
||||
// TODO: also check emuSD path
|
||||
if (emummc_path && !emummc_set_path(emummc_path))
|
||||
{
|
||||
EPRINTF("emupath is wrong!");
|
||||
goto wrong_emupath;
|
||||
}
|
||||
|
||||
if (emusd_path && !emusd_set_path(emusd_path)){
|
||||
EPRINTFARGS("path: %s", emusd_path);
|
||||
EPRINTF("error: emusdpath is wrong!");
|
||||
goto wrong_emupath;
|
||||
}
|
||||
}
|
||||
|
||||
if (!cfg_sec)
|
||||
@@ -444,14 +459,22 @@ parse_failed:
|
||||
launch_l4t(cfg_sec, entry_idx, 1, h_cfg.t210b01);
|
||||
}
|
||||
}
|
||||
else if (!hos_launch(cfg_sec))
|
||||
else
|
||||
{
|
||||
hos_launch(cfg_sec);
|
||||
|
||||
wrong_emupath:
|
||||
if (emummc_path)
|
||||
{
|
||||
sd_mount();
|
||||
boot_storage_mount();
|
||||
emummc_load_cfg(); // Reload emuMMC config in case of emupath.
|
||||
}
|
||||
|
||||
if (emusd_path)
|
||||
{
|
||||
boot_storage_mount();
|
||||
emusd_load_cfg();
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
@@ -465,6 +488,7 @@ static void _launch_config()
|
||||
u8 max_entries = 61;
|
||||
char *special_path = NULL;
|
||||
char *emummc_path = NULL;
|
||||
char *emusd_path = NULL;
|
||||
|
||||
ment_t *ments = NULL;
|
||||
ini_sec_t *cfg_sec = NULL;
|
||||
@@ -474,11 +498,12 @@ static void _launch_config()
|
||||
gfx_clear_grey(0x1B);
|
||||
gfx_con_setpos(0, 0);
|
||||
|
||||
if (!sd_mount())
|
||||
if (!boot_storage_mount())
|
||||
goto parse_failed;
|
||||
|
||||
// Load emuMMC configuration.
|
||||
emummc_load_cfg();
|
||||
emusd_load_cfg();
|
||||
|
||||
// Parse main configuration.
|
||||
ini_parse(&ini_sections, "bootloader/hekate_ipl.ini", false);
|
||||
@@ -545,6 +570,8 @@ static void _launch_config()
|
||||
h_cfg.emummc_force_disable = atoi(kv->val);
|
||||
if (!strcmp("emupath", kv->key))
|
||||
emummc_path = kv->val;
|
||||
if (!strcmp("emusdpath", kv->key))
|
||||
emusd_path = kv->val;
|
||||
}
|
||||
|
||||
if (emummc_path && !emummc_set_path(emummc_path))
|
||||
@@ -552,12 +579,19 @@ static void _launch_config()
|
||||
EPRINTF("emupath is wrong!");
|
||||
goto wrong_emupath;
|
||||
}
|
||||
|
||||
if (emusd_path && !emusd_set_path(emusd_path))
|
||||
{
|
||||
EPRINTFARGS("path: %s", emusd_path);
|
||||
EPRINTF("error: emusdpath is wrong!");
|
||||
goto wrong_emupath;
|
||||
}
|
||||
}
|
||||
|
||||
if (!cfg_sec)
|
||||
{
|
||||
free(ments);
|
||||
sd_end();
|
||||
boot_storage_end();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -587,18 +621,26 @@ parse_failed:
|
||||
launch_l4t(cfg_sec, entry_idx, 0, h_cfg.t210b01);
|
||||
}
|
||||
}
|
||||
else if (!hos_launch(cfg_sec))
|
||||
else
|
||||
{
|
||||
hos_launch(cfg_sec);
|
||||
|
||||
wrong_emupath:
|
||||
if (emummc_path)
|
||||
{
|
||||
sd_mount();
|
||||
boot_storage_mount();
|
||||
emummc_load_cfg(); // Reload emuMMC config in case of emupath.
|
||||
}
|
||||
|
||||
if (emusd_path)
|
||||
{
|
||||
boot_storage_mount();
|
||||
emusd_load_cfg();
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
sd_end();
|
||||
boot_storage_end();
|
||||
|
||||
free(ments);
|
||||
|
||||
@@ -611,11 +653,13 @@ out:
|
||||
|
||||
static void _nyx_load_run()
|
||||
{
|
||||
u8 *nyx = sd_file_read("bootloader/sys/nyx.bin", NULL);
|
||||
u8 *nyx = boot_storage_file_read("bootloader/sys/nyx.bin", NULL);
|
||||
if (!nyx)
|
||||
return;
|
||||
|
||||
boot_storage_end();
|
||||
sd_end();
|
||||
emmc_end();
|
||||
|
||||
render_static_bootlogo();
|
||||
display_backlight_brightness(h_cfg.backlight, 1000);
|
||||
@@ -677,7 +721,7 @@ static void _nyx_load_run()
|
||||
(*nyx_ptr)();
|
||||
}
|
||||
|
||||
static ini_sec_t *_get_ini_sec_from_id(ini_sec_t *ini_sec, char **bootlogoCustomEntry, char **emummc_path)
|
||||
static ini_sec_t *_get_ini_sec_from_id(ini_sec_t *ini_sec, char **bootlogoCustomEntry, char **emummc_path, char **emusd_path)
|
||||
{
|
||||
ini_sec_t *cfg_sec = NULL;
|
||||
|
||||
@@ -696,10 +740,13 @@ static ini_sec_t *_get_ini_sec_from_id(ini_sec_t *ini_sec, char **bootlogoCustom
|
||||
*bootlogoCustomEntry = kv->val;
|
||||
else if (!strcmp("emummc_force_disable", kv->key))
|
||||
h_cfg.emummc_force_disable = atoi(kv->val);
|
||||
else if (!strcmp("emusdpath", kv->key))
|
||||
*emusd_path = kv->val;
|
||||
}
|
||||
if (!cfg_sec)
|
||||
{
|
||||
*emummc_path = NULL;
|
||||
*emusd_path = NULL;
|
||||
*bootlogoCustomEntry = NULL;
|
||||
h_cfg.emummc_force_disable = false;
|
||||
}
|
||||
@@ -754,6 +801,7 @@ static void _auto_launch()
|
||||
u32 boot_entry_id = 0;
|
||||
ini_sec_t *cfg_sec = NULL;
|
||||
char *emummc_path = NULL;
|
||||
char *emusd_path = NULL;
|
||||
char *bootlogoCustomEntry = NULL;
|
||||
bool config_entry_found = false;
|
||||
|
||||
@@ -771,6 +819,7 @@ static void _auto_launch()
|
||||
|
||||
// Load emuMMC configuration.
|
||||
emummc_load_cfg();
|
||||
emusd_load_cfg();
|
||||
|
||||
// Parse hekate main configuration.
|
||||
if (!ini_parse(&ini_sections, "bootloader/hekate_ipl.ini", false))
|
||||
@@ -826,7 +875,7 @@ static void _auto_launch()
|
||||
}
|
||||
|
||||
if (boot_from_id)
|
||||
cfg_sec = _get_ini_sec_from_id(ini_sec, &bootlogoCustomEntry, &emummc_path);
|
||||
cfg_sec = _get_ini_sec_from_id(ini_sec, &bootlogoCustomEntry, &emummc_path, &emusd_path);
|
||||
else if (h_cfg.autoboot == boot_entry_id && config_entry_found)
|
||||
{
|
||||
cfg_sec = ini_sec;
|
||||
@@ -836,6 +885,8 @@ static void _auto_launch()
|
||||
bootlogoCustomEntry = kv->val;
|
||||
else if (!strcmp("emupath", kv->key))
|
||||
emummc_path = kv->val;
|
||||
else if (!strcmp("emusdpath", kv->key))
|
||||
emusd_path = kv->val;
|
||||
else if (!strcmp("emummc_force_disable", kv->key))
|
||||
h_cfg.emummc_force_disable = atoi(kv->val);
|
||||
else if (!strcmp("bootwait", kv->key))
|
||||
@@ -872,7 +923,7 @@ static void _auto_launch()
|
||||
continue;
|
||||
|
||||
if (boot_from_id)
|
||||
cfg_sec = _get_ini_sec_from_id(ini_sec_list, &bootlogoCustomEntry, &emummc_path);
|
||||
cfg_sec = _get_ini_sec_from_id(ini_sec_list, &bootlogoCustomEntry, &emummc_path, &emusd_path);
|
||||
else if (h_cfg.autoboot == boot_entry_id)
|
||||
{
|
||||
h_cfg.emummc_force_disable = false;
|
||||
@@ -883,6 +934,8 @@ static void _auto_launch()
|
||||
bootlogoCustomEntry = kv->val;
|
||||
else if (!strcmp("emupath", kv->key))
|
||||
emummc_path = kv->val;
|
||||
else if (!strcmp("emusdpath", kv->key))
|
||||
emusd_path = kv->val;
|
||||
else if (!strcmp("emummc_force_disable", kv->key))
|
||||
h_cfg.emummc_force_disable = atoi(kv->val);
|
||||
else if (!strcmp("bootwait", kv->key))
|
||||
@@ -913,11 +966,11 @@ skip_list:
|
||||
|
||||
// Check if user set custom logo path at the boot entry.
|
||||
if (bootlogoCustomEntry)
|
||||
bitmap = (u8 *)sd_file_read(bootlogoCustomEntry, &fsize);
|
||||
bitmap = (u8 *)boot_storage_file_read(bootlogoCustomEntry, &fsize);
|
||||
|
||||
// Custom entry bootlogo not found, trying default custom one.
|
||||
if (!bitmap)
|
||||
bitmap = (u8 *)sd_file_read("bootloader/bootlogo.bmp", &fsize);
|
||||
bitmap = (u8 *)boot_storage_file_read("bootloader/bootlogo.bmp", &fsize);
|
||||
|
||||
if (bitmap)
|
||||
{
|
||||
@@ -996,6 +1049,7 @@ skip_list:
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: add boot_cfg for emusd
|
||||
if (b_cfg.boot_cfg & BOOT_CFG_TO_EMUMMC)
|
||||
emummc_set_path(b_cfg.emummc_path);
|
||||
else if (emummc_path && !emummc_set_path(emummc_path))
|
||||
@@ -1005,15 +1059,29 @@ skip_list:
|
||||
goto wrong_emupath;
|
||||
}
|
||||
|
||||
if (emusd_path && !emusd_set_path(emusd_path))
|
||||
{
|
||||
gfx_con.mute = false;
|
||||
EPRINTFARGS("path: %s", emusd_path);
|
||||
EPRINTF("error: emusdpath is wrong!");
|
||||
goto wrong_emupath;
|
||||
}
|
||||
|
||||
hos_launch(cfg_sec);
|
||||
|
||||
wrong_emupath:
|
||||
if (emummc_path || b_cfg.boot_cfg & BOOT_CFG_TO_EMUMMC)
|
||||
{
|
||||
sd_mount();
|
||||
boot_storage_mount();
|
||||
emummc_load_cfg(); // Reload emuMMC config in case of emupath.
|
||||
}
|
||||
|
||||
if (emusd_path)
|
||||
{
|
||||
boot_storage_mount();
|
||||
emusd_load_cfg();
|
||||
}
|
||||
|
||||
error:
|
||||
gfx_con.mute = false;
|
||||
gfx_printf("\nPress any key...\n");
|
||||
@@ -1350,7 +1418,7 @@ static void _about()
|
||||
{
|
||||
static const char credits[] =
|
||||
"\nhekate (c) 2018, naehrwert, st4rk\n\n"
|
||||
" (c) 2018-2024, CTCaer\n\n"
|
||||
" (c) 2018-2025, CTCaer\n\n"
|
||||
" ___________________________________________\n\n"
|
||||
"Thanks to: %kderrek, nedwill, plutoo,\n"
|
||||
" shuffle2, smea, thexyz, yellows8%k\n"
|
||||
@@ -1446,7 +1514,7 @@ ment_t ment_top[] = {
|
||||
MDEF_END()
|
||||
};
|
||||
|
||||
menu_t menu_top = { ment_top, "hekate v6.2.2", 0, 0 };
|
||||
menu_t menu_top = { ment_top, "hekate v6.3.1", 0, 0 };
|
||||
|
||||
extern void pivot_stack(u32 stack_top);
|
||||
|
||||
@@ -1482,7 +1550,8 @@ void ipl_main()
|
||||
bpmp_clk_rate_set(h_cfg.t210b01 ? BPMP_CLK_DEFAULT_BOOST : BPMP_CLK_LOWER_BOOST);
|
||||
|
||||
// Mount SD Card.
|
||||
h_cfg.errors |= !sd_mount() ? ERR_SD_BOOT_EN : 0;
|
||||
// TODO: boot storage may not be sd card -> set proper error
|
||||
h_cfg.errors |= !boot_storage_mount() ? ERR_SD_BOOT_EN : 0;
|
||||
|
||||
// Check if watchdog was fired previously.
|
||||
if (watchdog_fired())
|
||||
@@ -1525,7 +1594,7 @@ skip_lp0_minerva_config:
|
||||
_auto_launch();
|
||||
|
||||
// Failed to launch Nyx, unmount SD Card.
|
||||
sd_end();
|
||||
boot_storage_end();
|
||||
|
||||
// Set ram to a freq that doesn't need periodic training.
|
||||
minerva_change_freq(FREQ_800);
|
||||
|
||||
@@ -14,6 +14,9 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <storage/emmc.h>
|
||||
#include <storage/sd.h>
|
||||
#include <storage/sdmmc.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
@@ -22,6 +25,7 @@
|
||||
#include "emummc.h"
|
||||
#include "../config.h"
|
||||
#include <libs/fatfs/ff.h>
|
||||
#include <storage/emummc_file_based.h>
|
||||
|
||||
extern hekate_config h_cfg;
|
||||
emummc_cfg_t emu_cfg = { 0 };
|
||||
@@ -77,33 +81,68 @@ bool emummc_set_path(char *path)
|
||||
FIL fp;
|
||||
bool found = false;
|
||||
|
||||
strcpy(emu_cfg.emummc_file_based_path, path);
|
||||
// strcpy(emu_cfg.emummc_file_based_path, "sd:");
|
||||
strcpy(emu_cfg.emummc_file_based_path, "");
|
||||
strcat(emu_cfg.emummc_file_based_path, path);
|
||||
strcat(emu_cfg.emummc_file_based_path, "/raw_based");
|
||||
|
||||
if (!f_open(&fp, emu_cfg.emummc_file_based_path, FA_READ))
|
||||
{
|
||||
if (!f_read(&fp, &emu_cfg.sector, 4, NULL))
|
||||
if (emu_cfg.sector)
|
||||
if (!f_read(&fp, &emu_cfg.sector, 4, NULL)){
|
||||
if (emu_cfg.sector){
|
||||
found = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
strcpy(emu_cfg.emummc_file_based_path, path);
|
||||
strcat(emu_cfg.emummc_file_based_path, "/file_based");
|
||||
|
||||
if (!f_stat(emu_cfg.emummc_file_based_path, NULL))
|
||||
{
|
||||
emu_cfg.sector = 0;
|
||||
emu_cfg.path = path;
|
||||
|
||||
found = true;
|
||||
emu_cfg.enabled = 1;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (found)
|
||||
strcpy(emu_cfg.emummc_file_based_path, "");
|
||||
strcat(emu_cfg.emummc_file_based_path, path);
|
||||
strcat(emu_cfg.emummc_file_based_path, "/raw_emmc_based");
|
||||
if (!f_open(&fp, emu_cfg.emummc_file_based_path, FA_READ))
|
||||
{
|
||||
if (!f_read(&fp, &emu_cfg.sector, 4, NULL)){
|
||||
if (emu_cfg.sector){
|
||||
found = true;
|
||||
emu_cfg.enabled = 4;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// strcpy(emu_cfg.emummc_file_based_path, "sd:");
|
||||
strcpy(emu_cfg.emummc_file_based_path, "");
|
||||
strcat(emu_cfg.emummc_file_based_path, path);
|
||||
strcat(emu_cfg.emummc_file_based_path, "/file_based");
|
||||
if (!f_stat(emu_cfg.emummc_file_based_path, NULL))
|
||||
{
|
||||
emu_cfg.sector = 0;
|
||||
emu_cfg.path = path;
|
||||
emu_cfg.enabled = 1;
|
||||
|
||||
found = true;
|
||||
goto out;
|
||||
}
|
||||
|
||||
// strcpy(emu_cfg.emummc_file_based_path, "sd:");
|
||||
strcpy(emu_cfg.emummc_file_based_path, "");
|
||||
strcat(emu_cfg.emummc_file_based_path, path);
|
||||
strcat(emu_cfg.emummc_file_based_path, "/file_emmc_based");
|
||||
if (!f_stat(emu_cfg.emummc_file_based_path, NULL))
|
||||
{
|
||||
emu_cfg.sector = 0;
|
||||
emu_cfg.path = path;
|
||||
emu_cfg.enabled = 4;
|
||||
|
||||
found = true;
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
|
||||
if (found)
|
||||
{
|
||||
// Get ID from path.
|
||||
u32 id_from_path = 0;
|
||||
u32 path_size = strlen(path);
|
||||
@@ -134,7 +173,7 @@ static int emummc_raw_get_part_off(int part_idx)
|
||||
|
||||
int emummc_storage_init_mmc()
|
||||
{
|
||||
FILINFO fno;
|
||||
// FILINFO fno;
|
||||
emu_cfg.active_part = 0;
|
||||
|
||||
// Always init eMMC even when in emuMMC. eMMC is needed from the emuMMC driver anyway.
|
||||
@@ -144,86 +183,80 @@ int emummc_storage_init_mmc()
|
||||
if (!emu_cfg.enabled || h_cfg.emummc_force_disable)
|
||||
return 0;
|
||||
|
||||
if (!sd_mount())
|
||||
goto out;
|
||||
bool file_based = false;
|
||||
|
||||
if (!emu_cfg.sector)
|
||||
{
|
||||
strcpy(emu_cfg.emummc_file_based_path, emu_cfg.path);
|
||||
strcat(emu_cfg.emummc_file_based_path, "/eMMC");
|
||||
|
||||
if (f_stat(emu_cfg.emummc_file_based_path, &fno))
|
||||
{
|
||||
EPRINTF("Failed to open eMMC folder.");
|
||||
goto out;
|
||||
if(emu_cfg.enabled == 4){
|
||||
// emmc based
|
||||
if(!emu_cfg.sector){
|
||||
// file based
|
||||
if(!emmc_mount()){
|
||||
gfx_printf("emmc mount fail\n");
|
||||
return 1;
|
||||
}
|
||||
strcpy(emu_cfg.emummc_file_based_path, "emmc:");
|
||||
strcat(emu_cfg.emummc_file_based_path, emu_cfg.path);
|
||||
strcat(emu_cfg.emummc_file_based_path, "/eMMC/");
|
||||
file_based = true;
|
||||
}else{
|
||||
// raw based
|
||||
// emmc already initialized
|
||||
}
|
||||
f_chmod(emu_cfg.emummc_file_based_path, AM_ARC, AM_ARC);
|
||||
|
||||
strcat(emu_cfg.emummc_file_based_path, "/00");
|
||||
if (f_stat(emu_cfg.emummc_file_based_path, &fno))
|
||||
{
|
||||
EPRINTF("Failed to open emuMMC rawnand.");
|
||||
goto out;
|
||||
}else{
|
||||
// sd based
|
||||
if(!emu_cfg.sector){
|
||||
// file based
|
||||
if(!sd_mount()){
|
||||
return 1;
|
||||
}
|
||||
strcpy(emu_cfg.emummc_file_based_path, "sd:");
|
||||
strcat(emu_cfg.emummc_file_based_path, emu_cfg.path);
|
||||
strcat(emu_cfg.emummc_file_based_path, "/eMMC/");
|
||||
file_based = true;
|
||||
}else{
|
||||
// raw based
|
||||
if(!sd_initialize(false)){
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
emu_cfg.file_based_part_size = fno.fsize >> 9;
|
||||
}
|
||||
|
||||
if(file_based){
|
||||
gfx_printf("file based\n");
|
||||
return emummc_storage_file_based_init(emu_cfg.emummc_file_based_path) == 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
out:
|
||||
return 1;
|
||||
}
|
||||
|
||||
int emummc_storage_end()
|
||||
{
|
||||
if (!emu_cfg.enabled || h_cfg.emummc_force_disable)
|
||||
if(!h_cfg.emummc_force_disable && emu_cfg.enabled && !emu_cfg.sector){
|
||||
emummc_storage_file_based_end();
|
||||
}
|
||||
if(!emu_cfg.enabled || h_cfg.emummc_force_disable || emu_cfg.enabled == 4){
|
||||
emmc_end();
|
||||
else
|
||||
}else{
|
||||
sd_end();
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int emummc_storage_read(u32 sector, u32 num_sectors, void *buf)
|
||||
{
|
||||
FIL fp;
|
||||
sdmmc_storage_t *storage = emu_cfg.enabled == 4 ? &emmc_storage : &sd_storage;
|
||||
// FIL fp;
|
||||
if (!emu_cfg.enabled || h_cfg.emummc_force_disable)
|
||||
return sdmmc_storage_read(&emmc_storage, sector, num_sectors, buf);
|
||||
else if (emu_cfg.sector)
|
||||
{
|
||||
sector += emu_cfg.sector;
|
||||
sector += emummc_raw_get_part_off(emu_cfg.active_part) * 0x2000;
|
||||
return sdmmc_storage_read(&sd_storage, sector, num_sectors, buf);
|
||||
return sdmmc_storage_read(storage, sector, num_sectors, buf);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!emu_cfg.active_part)
|
||||
{
|
||||
u32 file_part = sector / emu_cfg.file_based_part_size;
|
||||
sector = sector % emu_cfg.file_based_part_size;
|
||||
if (file_part >= 10)
|
||||
itoa(file_part, emu_cfg.emummc_file_based_path + strlen(emu_cfg.emummc_file_based_path) - 2, 10);
|
||||
else
|
||||
{
|
||||
emu_cfg.emummc_file_based_path[strlen(emu_cfg.emummc_file_based_path) - 2] = '0';
|
||||
itoa(file_part, emu_cfg.emummc_file_based_path + strlen(emu_cfg.emummc_file_based_path) - 1, 10);
|
||||
}
|
||||
}
|
||||
if (f_open(&fp, emu_cfg.emummc_file_based_path, FA_READ))
|
||||
{
|
||||
EPRINTF("Failed to open emuMMC image.");
|
||||
return 0;
|
||||
}
|
||||
f_lseek(&fp, (u64)sector << 9);
|
||||
if (f_read(&fp, buf, (u64)num_sectors << 9, NULL))
|
||||
{
|
||||
EPRINTF("Failed to read emuMMC image.");
|
||||
f_close(&fp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
f_close(&fp);
|
||||
return 1;
|
||||
return emummc_storage_file_based_read(sector, num_sectors, buf);
|
||||
}
|
||||
|
||||
return 1;
|
||||
@@ -231,72 +264,44 @@ int emummc_storage_read(u32 sector, u32 num_sectors, void *buf)
|
||||
|
||||
int emummc_storage_write(u32 sector, u32 num_sectors, void *buf)
|
||||
{
|
||||
FIL fp;
|
||||
sdmmc_storage_t *storage = emu_cfg.enabled == 4 ? &emmc_storage : &sd_storage;
|
||||
// FIL fp;
|
||||
if (!emu_cfg.enabled || h_cfg.emummc_force_disable)
|
||||
return sdmmc_storage_write(&emmc_storage, sector, num_sectors, buf);
|
||||
else if (emu_cfg.sector)
|
||||
{
|
||||
sector += emu_cfg.sector;
|
||||
sector += emummc_raw_get_part_off(emu_cfg.active_part) * 0x2000;
|
||||
return sdmmc_storage_write(&sd_storage, sector, num_sectors, buf);
|
||||
return sdmmc_storage_write(storage, sector, num_sectors, buf);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!emu_cfg.active_part)
|
||||
{
|
||||
u32 file_part = sector / emu_cfg.file_based_part_size;
|
||||
sector = sector % emu_cfg.file_based_part_size;
|
||||
if (file_part >= 10)
|
||||
itoa(file_part, emu_cfg.emummc_file_based_path + strlen(emu_cfg.emummc_file_based_path) - 2, 10);
|
||||
else
|
||||
{
|
||||
emu_cfg.emummc_file_based_path[strlen(emu_cfg.emummc_file_based_path) - 2] = '0';
|
||||
itoa(file_part, emu_cfg.emummc_file_based_path + strlen(emu_cfg.emummc_file_based_path) - 1, 10);
|
||||
}
|
||||
}
|
||||
|
||||
if (f_open(&fp, emu_cfg.emummc_file_based_path, FA_WRITE))
|
||||
return 0;
|
||||
|
||||
f_lseek(&fp, (u64)sector << 9);
|
||||
if (f_write(&fp, buf, (u64)num_sectors << 9, NULL))
|
||||
{
|
||||
f_close(&fp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
f_close(&fp);
|
||||
return 1;
|
||||
return emummc_storage_file_based_write(sector, num_sectors, buf);
|
||||
}
|
||||
}
|
||||
|
||||
int emummc_storage_set_mmc_partition(u32 partition)
|
||||
{
|
||||
emu_cfg.active_part = partition;
|
||||
emmc_set_partition(partition);
|
||||
|
||||
if (!emu_cfg.enabled || h_cfg.emummc_force_disable || emu_cfg.sector)
|
||||
return 1;
|
||||
else
|
||||
{
|
||||
strcpy(emu_cfg.emummc_file_based_path, emu_cfg.path);
|
||||
strcat(emu_cfg.emummc_file_based_path, "/eMMC");
|
||||
|
||||
switch (partition)
|
||||
{
|
||||
case 0:
|
||||
strcat(emu_cfg.emummc_file_based_path, "/00");
|
||||
break;
|
||||
case 1:
|
||||
strcat(emu_cfg.emummc_file_based_path, "/BOOT0");
|
||||
break;
|
||||
case 2:
|
||||
strcat(emu_cfg.emummc_file_based_path, "/BOOT1");
|
||||
break;
|
||||
}
|
||||
|
||||
if(h_cfg.emummc_force_disable || !emu_cfg.enabled){
|
||||
emmc_set_partition(partition);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(!emu_cfg.sector){
|
||||
emummc_storage_file_base_set_partition(partition);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(emu_cfg.enabled != 4){
|
||||
emmc_set_partition(partition);
|
||||
}else{
|
||||
emmc_set_partition(EMMC_GPP);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
sdmmc_storage_t *emummc_get_storage(){
|
||||
return emu_cfg.enabled == 4 ? &emmc_storage : &sd_storage;
|
||||
}
|
||||
|
||||
@@ -19,19 +19,6 @@
|
||||
|
||||
#include <bdk.h>
|
||||
|
||||
typedef enum
|
||||
{
|
||||
EMUMMC_TYPE_NONE = 0,
|
||||
EMUMMC_TYPE_PARTITION = 1,
|
||||
EMUMMC_TYPE_FILES = 2,
|
||||
} emummc_type_t;
|
||||
|
||||
typedef enum {
|
||||
EMUMMC_MMC_NAND = 0,
|
||||
EMUMMC_MMC_SD = 1,
|
||||
EMUMMC_MMC_GC = 2,
|
||||
} emummc_mmc_t;
|
||||
|
||||
typedef struct _emummc_cfg_t
|
||||
{
|
||||
int enabled;
|
||||
@@ -55,5 +42,6 @@ int emummc_storage_end();
|
||||
int emummc_storage_read(u32 sector, u32 num_sectors, void *buf);
|
||||
int emummc_storage_write(u32 sector, u32 num_sectors, void *buf);
|
||||
int emummc_storage_set_mmc_partition(u32 partition);
|
||||
sdmmc_storage_t *emummc_get_storage();
|
||||
|
||||
#endif
|
||||
295
bootloader/storage/emusd.c
Normal file
295
bootloader/storage/emusd.c
Normal file
@@ -0,0 +1,295 @@
|
||||
#include "emusd.h"
|
||||
#include <bdk.h>
|
||||
#include <storage/boot_storage.h>
|
||||
#include <storage/emmc.h>
|
||||
#include <storage/file_based_storage.h>
|
||||
#include <storage/sd.h>
|
||||
#include <storage/sdmmc.h>
|
||||
#include <string.h>
|
||||
#include <utils/ini.h>
|
||||
#include <libs/fatfs/ff.h>
|
||||
#include "../config.h"
|
||||
#include "gfx_utils.h"
|
||||
|
||||
|
||||
FATFS emusd_fs;
|
||||
bool emusd_mounted = false;
|
||||
bool emusd_initialized = false;
|
||||
emusd_cfg_t emu_sd_cfg = {0};
|
||||
extern hekate_config h_cfg;
|
||||
|
||||
static bool emusd_get_mounted() {
|
||||
return emusd_mounted;
|
||||
}
|
||||
|
||||
void emusd_load_cfg()
|
||||
{
|
||||
emu_sd_cfg.enabled = 0;
|
||||
emu_sd_cfg.fs_ver = 0;
|
||||
emu_sd_cfg.id = 0;
|
||||
emu_sd_cfg.sector = 0;
|
||||
if(!emu_sd_cfg.path) {
|
||||
emu_sd_cfg.path = (char*)malloc(0x200);
|
||||
}
|
||||
if(!emu_sd_cfg.emummc_file_based_path){
|
||||
emu_sd_cfg.emummc_file_based_path = (char*)malloc(0x200);
|
||||
}
|
||||
|
||||
LIST_INIT(ini_sections);
|
||||
if(ini_parse(&ini_sections, "emuSD/emusd.ini", false))
|
||||
{
|
||||
LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_sections, link)
|
||||
{
|
||||
if(ini_sec->type == INI_CHOICE)
|
||||
{
|
||||
if(strcmp(ini_sec->name, "emusd")){
|
||||
continue;
|
||||
}
|
||||
|
||||
LIST_FOREACH_ENTRY(ini_kv_t, kv, &ini_sec->kvs, link)
|
||||
{
|
||||
if(!strcmp(kv->key, "enabled")){
|
||||
emu_sd_cfg.enabled = atoi(kv->val);
|
||||
} else if(!strcmp(kv->key, "sector")){
|
||||
emu_sd_cfg.sector = strtol(kv->val, NULL, 16);
|
||||
} else if(!strcmp(kv->key, "path")){
|
||||
emu_sd_cfg.path = kv->val;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool emusd_mount() {
|
||||
if (emusd_mounted) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (emusd_storage_init_mmc()){
|
||||
return false;
|
||||
}
|
||||
|
||||
int res = f_mount(&emusd_fs, "emusd:", 1);
|
||||
|
||||
if(res) {
|
||||
EPRINTFARGS("emusd mount fail %d", res);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool emusd_unmount() {
|
||||
f_mount(NULL, "emusd:", 1);
|
||||
emusd_mounted = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool emusd_set_path(char *path) {
|
||||
FIL fp;
|
||||
bool found = false;
|
||||
// TODO: use emu_sd.file_path instead
|
||||
strcat(emu_sd_cfg.emummc_file_based_path, "");
|
||||
strcpy(emu_sd_cfg.emummc_file_based_path, path);
|
||||
strcat(emu_sd_cfg.emummc_file_based_path, "/raw_emmc_based");
|
||||
if(!f_open(&fp, emu_sd_cfg.emummc_file_based_path, FA_READ))
|
||||
{
|
||||
if(!f_read(&fp, &emu_sd_cfg.sector, 4, NULL)){
|
||||
if(emu_sd_cfg.sector){
|
||||
found = true;
|
||||
emu_sd_cfg.enabled = 4;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
strcpy(emu_sd_cfg.emummc_file_based_path, "");
|
||||
strcat(emu_sd_cfg.emummc_file_based_path, path);
|
||||
strcat(emu_sd_cfg.emummc_file_based_path, "/raw_emmc_based");
|
||||
if (!f_open(&fp, emu_sd_cfg.emummc_file_based_path, FA_READ))
|
||||
{
|
||||
if (!f_read(&fp, &emu_sd_cfg.sector, 4, NULL)){
|
||||
if (emu_sd_cfg.sector){
|
||||
found = true;
|
||||
emu_sd_cfg.enabled = 4;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// strcpy(emu_sd_cfg.emummc_file_based_path, "sd:");
|
||||
strcpy(emu_sd_cfg.emummc_file_based_path, "");
|
||||
strcat(emu_sd_cfg.emummc_file_based_path, path);
|
||||
strcat(emu_sd_cfg.emummc_file_based_path, "/file_based");
|
||||
if (!f_stat(emu_sd_cfg.emummc_file_based_path, NULL))
|
||||
{
|
||||
emu_sd_cfg.sector = 0;
|
||||
emu_sd_cfg.path = path;
|
||||
emu_sd_cfg.enabled = 1;
|
||||
|
||||
found = true;
|
||||
goto out;
|
||||
}
|
||||
|
||||
// strcpy(emu_sd_cfg.emummc_file_based_path, "sd:");
|
||||
strcpy(emu_sd_cfg.emummc_file_based_path, "");
|
||||
strcat(emu_sd_cfg.emummc_file_based_path, path);
|
||||
strcat(emu_sd_cfg.emummc_file_based_path, "/file_emmc_based");
|
||||
if (!f_stat(emu_sd_cfg.emummc_file_based_path, NULL))
|
||||
{
|
||||
emu_sd_cfg.sector = 0;
|
||||
emu_sd_cfg.path = path;
|
||||
emu_sd_cfg.enabled = 4;
|
||||
|
||||
found = true;
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
return found;
|
||||
}
|
||||
|
||||
int emusd_storage_init_mmc() {
|
||||
if(!emusd_initialized) {
|
||||
if (!emu_sd_cfg.enabled || h_cfg.emummc_force_disable) {
|
||||
if(!sd_initialize(false)){
|
||||
return 1;
|
||||
}
|
||||
emusd_initialized = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool file_based = false;
|
||||
if(emu_sd_cfg.enabled == 4){
|
||||
if(!emu_sd_cfg.sector){
|
||||
//file based
|
||||
if(!emmc_mount()){
|
||||
return 1;
|
||||
}
|
||||
strcpy(emu_sd_cfg.emummc_file_based_path, "emmc:");
|
||||
strcat(emu_sd_cfg.emummc_file_based_path, emu_sd_cfg.path);
|
||||
strcat(emu_sd_cfg.emummc_file_based_path, "/SD/");
|
||||
file_based = true;
|
||||
}else{
|
||||
if(!emmc_initialize(false)){
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
if(!emu_sd_cfg.sector){
|
||||
//file based
|
||||
if(!sd_mount()){
|
||||
return 1;
|
||||
}
|
||||
strcpy(emu_sd_cfg.emummc_file_based_path, "sd:");
|
||||
strcat(emu_sd_cfg.emummc_file_based_path, emu_sd_cfg.path);
|
||||
strcat(emu_sd_cfg.emummc_file_based_path, "/SD/");
|
||||
file_based = true;
|
||||
}else{
|
||||
if(!sd_initialize(false)){
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(file_based){
|
||||
return file_based_storage_init(emu_sd_cfg.emummc_file_based_path) == 0;
|
||||
}
|
||||
|
||||
emusd_initialized = true;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int emusd_storage_end() {
|
||||
if(!h_cfg.emummc_force_disable && emu_sd_cfg.enabled && !emu_sd_cfg.sector){
|
||||
file_based_storage_end();
|
||||
}
|
||||
if(!emu_sd_cfg.enabled || h_cfg.emummc_force_disable || emu_sd_cfg.enabled == 1){
|
||||
sd_unmount();
|
||||
}else{
|
||||
emmc_unmount();
|
||||
}
|
||||
emusd_initialized = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int emusd_storage_write(u32 sector, u32 num_sectors, void *buf) {
|
||||
if(!emu_sd_cfg.enabled || h_cfg.emummc_force_disable){
|
||||
return sdmmc_storage_write(&sd_storage, sector, num_sectors, buf);
|
||||
}else if(emu_sd_cfg.sector){
|
||||
sdmmc_storage_t *storage = emu_sd_cfg.enabled == 1 ? &sd_storage : &emmc_storage;
|
||||
sector += emu_sd_cfg.sector;
|
||||
return sdmmc_storage_write(storage, sector, num_sectors, buf);
|
||||
}else{
|
||||
return file_based_storage_write(sector, num_sectors, buf);
|
||||
}
|
||||
}
|
||||
|
||||
int emusd_storage_read(u32 sector, u32 num_sectors, void *buf) {
|
||||
if(!emu_sd_cfg.enabled || h_cfg.emummc_force_disable){
|
||||
return sdmmc_storage_read(&sd_storage, sector, num_sectors, buf);
|
||||
}else if(emu_sd_cfg.sector){
|
||||
sdmmc_storage_t *storage = emu_sd_cfg.enabled == 1 ? &sd_storage : &emmc_storage;
|
||||
sector += emu_sd_cfg.sector;
|
||||
return sdmmc_storage_read(storage, sector, num_sectors, buf);
|
||||
}else{
|
||||
return file_based_storage_read(sector, num_sectors, buf);
|
||||
}
|
||||
}
|
||||
|
||||
sdmmc_storage_t *emusd_get_storage() {
|
||||
return emu_sd_cfg.enabled == 4 ? &emmc_storage : &sd_storage;
|
||||
}
|
||||
|
||||
|
||||
bool emusd_is_gpt() {
|
||||
if(emu_sd_cfg.enabled) {
|
||||
return emusd_fs.part_type;
|
||||
} else {
|
||||
return sd_fs.part_type;
|
||||
}
|
||||
}
|
||||
|
||||
int emusd_get_fs_type() {
|
||||
if(emu_sd_cfg.enabled) {
|
||||
return emusd_fs.fs_type;
|
||||
} else {
|
||||
return sd_fs.fs_type;
|
||||
}
|
||||
}
|
||||
|
||||
void *emusd_file_read(const char *path, u32 *fsize) {
|
||||
if(emu_sd_cfg.enabled) {
|
||||
char *path1 = malloc(0x100);
|
||||
strcpy(path1, "emusd:");
|
||||
strcat(path1, path);
|
||||
FIL fp;
|
||||
if (!emusd_get_mounted())
|
||||
return NULL;
|
||||
|
||||
if (f_open(&fp, path, FA_READ) != FR_OK)
|
||||
return NULL;
|
||||
|
||||
u32 size = f_size(&fp);
|
||||
if (fsize)
|
||||
*fsize = size;
|
||||
|
||||
void *buf = malloc(size);
|
||||
|
||||
if (f_read(&fp, buf, size, NULL) != FR_OK)
|
||||
{
|
||||
free(buf);
|
||||
f_close(&fp);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
f_close(&fp);
|
||||
|
||||
return buf;
|
||||
} else {
|
||||
return boot_storage_file_read(path, fsize);
|
||||
}
|
||||
}
|
||||
49
bootloader/storage/emusd.h
Normal file
49
bootloader/storage/emusd.h
Normal file
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (c) 2019-2021 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 _EMUSD_H
|
||||
#define _EMUSD_H
|
||||
|
||||
#include <bdk.h>
|
||||
|
||||
typedef struct _emusd_cfg_t
|
||||
{
|
||||
int enabled;
|
||||
u64 sector;
|
||||
u32 id;
|
||||
char *path;
|
||||
// Internal.
|
||||
int fs_ver;
|
||||
char *emummc_file_based_path;
|
||||
|
||||
} emusd_cfg_t;
|
||||
|
||||
extern emusd_cfg_t emu_sd_cfg;
|
||||
|
||||
void emusd_load_cfg();
|
||||
bool emusd_set_path(char *path);
|
||||
int emusd_storage_init_mmc();
|
||||
int emusd_storage_end();
|
||||
int emusd_storage_read(u32 sector, u32 num_sectors, void *buf);
|
||||
int emusd_storage_write(u32 sector, u32 num_sectors, void *buf);
|
||||
sdmmc_storage_t *emusd_get_storage();
|
||||
bool emusd_is_gpt();
|
||||
int emusd_get_fs_type();
|
||||
bool emusd_mount();
|
||||
bool emusd_unmount();
|
||||
void *emusd_file_read(const char *path, u32 *fsize);
|
||||
|
||||
#endif
|
||||
@@ -46,7 +46,7 @@ clean:
|
||||
@rm -rf $(OBJS)
|
||||
|
||||
$(TARGET).bin: $(BUILDDIR)/$(TARGET)/$(TARGET).elf
|
||||
$(OBJCOPY) -S -O binary $< $(OUTPUTDIR)/$(PAYLOAD_NAME).bin
|
||||
@$(OBJCOPY) -S -O binary $< $(OUTPUTDIR)/$(PAYLOAD_NAME).bin
|
||||
|
||||
$(BUILDDIR)/$(TARGET)/$(TARGET).elf: $(OBJS)
|
||||
@$(CC) $(LDFLAGS) -T link.ld $^ -o $@
|
||||
|
||||
18
nyx/Makefile
18
nyx/Makefile
@@ -27,8 +27,8 @@ OBJS = $(addprefix $(BUILDDIR)/$(TARGET)/, \
|
||||
start.o exception_handlers.o \
|
||||
nyx.o heap.o \
|
||||
gfx.o \
|
||||
gui.o gui_info.o gui_tools.o gui_options.o gui_emmc_tools.o gui_emummc_tools.o gui_tools_partition_manager.o \
|
||||
fe_emummc_tools.o fe_emmc_tools.o \
|
||||
gui.o gui_info.o gui_tools.o gui_options.o gui_emmc_tools.o gui_emummc_tools.o gui_tools_partition_manager.o gui_emu_tools.o gui_emusd_tools.o \
|
||||
fe_emummc_tools.o fe_emmc_tools.o fe_emusd_tools.o \
|
||||
)
|
||||
|
||||
# Hardware.
|
||||
@@ -41,7 +41,7 @@ OBJS += $(addprefix $(BUILDDIR)/$(TARGET)/, \
|
||||
bm92t36.o bq24193.o max17050.o max7762x.o max77620-rtc.o regulator_5v.o \
|
||||
touch.o joycon.o tmp451.o fan.o \
|
||||
usbd.o xusbd.o usb_descriptors.o usb_gadget_ums.o usb_gadget_hid.o \
|
||||
hw_init.o \
|
||||
hw_init.o boot_storage.o sfd.o mbr_gpt.o emummc_file_based.o file_based_storage.o \
|
||||
)
|
||||
|
||||
# Utilities.
|
||||
@@ -93,12 +93,12 @@ CUSTOMDEFINES += -DGFX_INC=$(GFX_INC) -DFFCFG_INC=$(FFCFG_INC)
|
||||
#CUSTOMDEFINES += -DDEBUG_UART_LV_LOG
|
||||
|
||||
#TODO: Considering reinstating some of these when pointer warnings have been fixed.
|
||||
WARNINGS := -Wall -Wsign-compare -Wno-array-bounds -Wno-stringop-overread -Wno-stringop-overflow
|
||||
WARNINGS := -Wall -Wsign-compare -Wtype-limits -Wno-array-bounds -Wno-stringop-overread -Wno-stringop-overflow
|
||||
#-fno-delete-null-pointer-checks
|
||||
#-Wstack-usage=byte-size -fstack-usage
|
||||
|
||||
ARCH := -march=armv4t -mtune=arm7tdmi -mthumb-interwork
|
||||
CFLAGS = $(ARCH) -O2 -g -gdwarf-4 -nostdlib -ffunction-sections -fdata-sections -fomit-frame-pointer -std=gnu11 $(WARNINGS) $(CUSTOMDEFINES)
|
||||
ARCH := -march=armv4t -mtune=arm7tdmi -mthumb-interwork $(WARNINGS)
|
||||
CFLAGS = $(ARCH) -O2 -g -gdwarf-4 -nostdlib -ffunction-sections -fdata-sections -fomit-frame-pointer -std=gnu11 $(CUSTOMDEFINES)
|
||||
LDFLAGS = $(ARCH) -nostartfiles -lgcc -Wl,--nmagic,--gc-sections -Xlinker --defsym=NYX_LOAD_ADDR=$(NYX_LOAD_ADDR)
|
||||
|
||||
################################################################################
|
||||
@@ -107,7 +107,7 @@ LDFLAGS = $(ARCH) -nostartfiles -lgcc -Wl,--nmagic,--gc-sections -Xlinker --defs
|
||||
|
||||
all: $(TARGET).bin
|
||||
@echo "--------------------------------------"
|
||||
@echo -n "Nyx size: "
|
||||
@echo -n "Nyx size: "
|
||||
$(eval BIN_SIZE = $(shell wc -c < $(OUTPUTDIR)/$(TARGET).bin))
|
||||
@echo $(BIN_SIZE)" Bytes"
|
||||
@echo "--------------------------------------"
|
||||
@@ -118,11 +118,11 @@ clean:
|
||||
@rm -rf $(OUTPUTDIR)
|
||||
|
||||
$(TARGET).bin: $(BUILDDIR)/$(TARGET)/$(TARGET).elf
|
||||
$(OBJCOPY) -S -O binary $< $(OUTPUTDIR)/$@
|
||||
@$(OBJCOPY) -S -O binary $< $(OUTPUTDIR)/$@
|
||||
|
||||
$(BUILDDIR)/$(TARGET)/$(TARGET).elf: $(OBJS)
|
||||
@$(CC) $(LDFLAGS) -T $(SOURCEDIR)/link.ld $^ -o $@
|
||||
@echo "Nyx was built with the following flags:\nCFLAGS: "$(CFLAGS)"\nLDFLAGS: "$(LDFLAGS)
|
||||
@printf "$(TARGET) was built with the following flags:\nCFLAGS: $(CFLAGS)\nLDFLAGS: $(LDFLAGS)\n"
|
||||
|
||||
$(BUILDDIR)/$(TARGET)/%.o: %.c
|
||||
@echo Building $@
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
|
||||
#include "config.h"
|
||||
#include <libs/fatfs/ff.h>
|
||||
#include <storage/boot_storage.h>
|
||||
|
||||
extern hekate_config h_cfg;
|
||||
extern nyx_config n_cfg;
|
||||
@@ -187,9 +188,9 @@ int create_config_entry()
|
||||
|
||||
int create_nyx_config_entry(bool force_unmount)
|
||||
{
|
||||
bool sd_mounted = sd_get_card_mounted();
|
||||
bool sd_mounted = boot_storage_get_mounted();
|
||||
|
||||
if (!sd_mount())
|
||||
if (!boot_storage_mount())
|
||||
return 1;
|
||||
|
||||
char lbuf[64];
|
||||
@@ -247,7 +248,7 @@ int create_nyx_config_entry(bool force_unmount)
|
||||
f_close(&fp);
|
||||
|
||||
if (force_unmount || !sd_mounted)
|
||||
sd_unmount();
|
||||
boot_storage_unmount();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
|
||||
//! fix the dram stuff and the pop ups
|
||||
|
||||
#include <storage/boot_storage.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
@@ -53,19 +54,19 @@ static void _get_valid_partition(u32 *sector_start, u32 *sector_size, u32 *part_
|
||||
*sector_start = mbr->partitions[i].start_sct;
|
||||
u8 type = mbr->partitions[i].type;
|
||||
u32 sector_size_safe = backup ? 0x400000 : (*sector_size) + 0x8000; // 2GB min safe size for backup.
|
||||
if ((curr_part_size >= sector_size_safe) && *sector_start && type != 0x83 && (!backup || type == 0xE0))
|
||||
if ((curr_part_size >= sector_size_safe) && (*sector_start) && type != 0x83 && (!backup || type == 0xE0))
|
||||
{
|
||||
if (backup)
|
||||
{
|
||||
u8 gpt_check[SD_BLOCKSIZE] = { 0 };
|
||||
sdmmc_storage_read(&sd_storage, *sector_start + 0xC001, 1, gpt_check);
|
||||
sdmmc_storage_read(&sd_storage, (*sector_start) + 0xC001, 1, gpt_check);
|
||||
if (!memcmp(gpt_check, "EFI PART", 8))
|
||||
{
|
||||
*sector_size = curr_part_size;
|
||||
*sector_start = *sector_start + 0x8000;
|
||||
*sector_start = (*sector_start) + 0x8000;
|
||||
break;
|
||||
}
|
||||
sdmmc_storage_read(&sd_storage, *sector_start + 0x4001, 1, gpt_check);
|
||||
sdmmc_storage_read(&sd_storage, (*sector_start) + 0x4001, 1, gpt_check);
|
||||
if (!memcmp(gpt_check, "EFI PART", 8))
|
||||
{
|
||||
*sector_size = curr_part_size;
|
||||
@@ -91,7 +92,7 @@ static void _get_valid_partition(u32 *sector_start, u32 *sector_size, u32 *part_
|
||||
if (backup && *part_idx && *sector_size)
|
||||
{
|
||||
gpt_t *gpt = (gpt_t *)zalloc(sizeof(gpt_t));
|
||||
sdmmc_storage_read(&sd_storage, *sector_start + 0x4001, 1, gpt);
|
||||
sdmmc_storage_read(&sd_storage, (*sector_start) + 0x4001, 1, gpt);
|
||||
|
||||
u32 new_size = gpt->header.alt_lba + 1;
|
||||
if (*sector_size > new_size)
|
||||
@@ -102,7 +103,7 @@ static void _get_valid_partition(u32 *sector_start, u32 *sector_size, u32 *part_
|
||||
free(gpt);
|
||||
}
|
||||
else if (!backup && *part_idx)
|
||||
*sector_start = *sector_start + 0x8000;
|
||||
*sector_start = (*sector_start) + 0x8000;
|
||||
}
|
||||
|
||||
static lv_obj_t *create_mbox_text(const char *text, bool button_ok)
|
||||
@@ -622,10 +623,20 @@ static int _dump_emmc_part(emmc_tool_gui_t *gui, char *sd_path, int active_part,
|
||||
|
||||
while (res_read)
|
||||
{
|
||||
s_printf(gui->txt_buf,
|
||||
"\n#FFDD00 Error reading %d blocks @ LBA %08X,#\n"
|
||||
"#FFDD00 from eMMC (try %d). #",
|
||||
num, lba_curr, ++retryCount);
|
||||
if (!gui->raw_emummc)
|
||||
{
|
||||
s_printf(gui->txt_buf,
|
||||
"\n#FFDD00 Error reading %d blocks @ LBA %08X,#\n"
|
||||
"#FFDD00 from eMMC (try %d). #",
|
||||
num, lba_curr, ++retryCount);
|
||||
}
|
||||
else
|
||||
{
|
||||
s_printf(gui->txt_buf,
|
||||
"\n#FFDD00 Error reading %d blocks @ LBA %08X,#\n"
|
||||
"#FFDD00 from emuMMC @ %08X (try %d). #",
|
||||
num, lba_curr + sd_sector_off, lba_curr, ++retryCount);
|
||||
}
|
||||
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);
|
||||
manual_system_maintenance(true);
|
||||
|
||||
@@ -759,14 +770,16 @@ void dump_emmc_selected(emmcPartType_t dumpType, emmc_tool_gui_t *gui)
|
||||
lv_label_set_text(gui->label_info, "Checking for available free space...");
|
||||
manual_system_maintenance(true);
|
||||
|
||||
if (!sd_mount())
|
||||
if (!boot_storage_mount())
|
||||
{
|
||||
lv_label_set_text(gui->label_info, "#FFDD00 Failed to init SD!#");
|
||||
lv_label_set_text(gui->label_info, "#FFDD00 Failed to storage!#");
|
||||
goto out;
|
||||
}
|
||||
|
||||
// Get SD Card free space for Partial Backup.
|
||||
f_getfree("", &sd_fs.free_clst, NULL);
|
||||
FATFS *fs = boot_storage_get_fs();
|
||||
|
||||
f_getfree("", &fs->free_clst, NULL);
|
||||
|
||||
if (!emmc_initialize(false))
|
||||
{
|
||||
@@ -932,11 +945,11 @@ out:
|
||||
free(txt_buf);
|
||||
free(gui->base_path);
|
||||
if (!partial_sd_full_unmount)
|
||||
sd_unmount();
|
||||
boot_storage_unmount();
|
||||
else
|
||||
{
|
||||
partial_sd_full_unmount = false;
|
||||
sd_end();
|
||||
boot_storage_end();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1361,7 +1374,7 @@ multipart_not_allowed:
|
||||
f_close(&fp_raw);
|
||||
|
||||
s_printf(sdPath, "emuMMC/RAW%d", part_idx);
|
||||
save_emummc_cfg(part_idx, sector_start, sdPath);
|
||||
save_emummc_cfg(part_idx, sector_start, sdPath, DRIVE_SD);
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -30,9 +30,9 @@ typedef struct _emummc_cfg_t
|
||||
} emummc_cfg_t;
|
||||
|
||||
void load_emummc_cfg(emummc_cfg_t *emu_info);
|
||||
void save_emummc_cfg(u32 part_idx, u32 sector_start, const char *path);
|
||||
void dump_emummc_file(emmc_tool_gui_t *gui);
|
||||
void dump_emummc_raw(emmc_tool_gui_t *gui, int part_idx, u32 sector_start, u32 resized_count);
|
||||
void save_emummc_cfg(u32 part_idx, u32 sector_start, const char *path, u8 drive);
|
||||
void dump_emummc_file(emmc_tool_gui_t *gui, u32 resized_cnt, u8 drive);
|
||||
void dump_emummc_raw(emmc_tool_gui_t *gui, int part_idx, u32 sector_start, u32 resized_count, u8 drive);
|
||||
void update_emummc_base_folder(char *outFilename, u32 sdPathLen, u32 currPartIdx);
|
||||
|
||||
#endif
|
||||
|
||||
276
nyx/nyx_gui/frontend/fe_emusd_tools.c
Normal file
276
nyx/nyx_gui/frontend/fe_emusd_tools.c
Normal file
@@ -0,0 +1,276 @@
|
||||
#include "fe_emusd_tools.h"
|
||||
#include "../storage/sfd.h"
|
||||
#include <sec/se.h>
|
||||
#include <storage/boot_storage.h>
|
||||
#include <libs/fatfs/ff.h>
|
||||
#include <storage/emmc.h>
|
||||
#include <storage/mbr_gpt.h>
|
||||
#include <storage/sd.h>
|
||||
#include <storage/sdmmc.h>
|
||||
#include <utils/list.h>
|
||||
#include <utils/ini.h>
|
||||
#include <string.h>
|
||||
#include "gfx_utils.h"
|
||||
#include <stdlib.h>
|
||||
#include <utils/sprintf.h>
|
||||
|
||||
void load_emusd_cfg(emusd_cfg_t *emu_info){
|
||||
memset(emu_info, 0, sizeof(emusd_cfg_t));
|
||||
|
||||
// Parse emuMMC configuration.
|
||||
LIST_INIT(ini_sections);
|
||||
if (!ini_parse(&ini_sections, "emuSD/emusd.ini", false))
|
||||
return;
|
||||
|
||||
LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_sections, link)
|
||||
{
|
||||
if (!strcmp(ini_sec->name, "emusd"))
|
||||
{
|
||||
LIST_FOREACH_ENTRY(ini_kv_t, kv, &ini_sec->kvs, link)
|
||||
{
|
||||
if (!strcmp("enabled", kv->key))
|
||||
emu_info->enabled = atoi(kv->val);
|
||||
else if(!strcmp("sector", kv->key))
|
||||
emu_info->sector = strtol(kv->val, NULL, 16);
|
||||
else if(!strcmp("path", kv->key)){
|
||||
emu_info->path =(char*)malloc(strlen(kv->val)+1);
|
||||
strcpy(emu_info->path, kv->val);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ini_free(&ini_sections);
|
||||
}
|
||||
|
||||
void save_emusd_cfg(u32 part_idx, u32 sector_start, const char *path, u8 drive){
|
||||
boot_storage_mount();
|
||||
|
||||
char lbuf[16];
|
||||
FIL fp;
|
||||
|
||||
f_mkdir("emuSD");
|
||||
|
||||
if (f_open(&fp, "emuSD/emusd.ini", FA_WRITE | FA_CREATE_ALWAYS) != FR_OK)
|
||||
return;
|
||||
|
||||
// Add config entry.
|
||||
f_puts("[emusd]\nenabled=", &fp);
|
||||
if((sector_start || path) && drive == DRIVE_SD) {
|
||||
f_puts("1", &fp);
|
||||
} else if((sector_start || path) && drive == DRIVE_EMMC){
|
||||
f_puts("4", &fp);
|
||||
}else{
|
||||
f_puts("0", &fp);
|
||||
}
|
||||
|
||||
if(!sector_start){
|
||||
f_puts("\nsector=0x0", &fp);
|
||||
}else{
|
||||
f_puts("\nsector=0x", &fp);
|
||||
itoa(sector_start, lbuf, 16);
|
||||
f_puts(lbuf, &fp);
|
||||
}
|
||||
|
||||
if(path){
|
||||
f_puts("\npath=", &fp);
|
||||
f_puts(path, &fp);
|
||||
}
|
||||
|
||||
f_puts("\n", &fp);
|
||||
f_close(&fp);
|
||||
}
|
||||
|
||||
static void update_base_path(char *path, int idx, int path_len) {
|
||||
if(idx < 10){
|
||||
path[path_len] = '0';
|
||||
itoa(idx, path + path_len + 1, 10);
|
||||
}else{
|
||||
itoa(idx, path + path_len, 10);
|
||||
}
|
||||
}
|
||||
|
||||
int create_emusd_file(u32 size_sct, u8 drive) {
|
||||
static const u32 file_max_scts = 0xfe000000 / 0x200;
|
||||
|
||||
char path[0x80];
|
||||
if (drive == DRIVE_SD){
|
||||
strcpy(path, "sd:emuSD/SD");
|
||||
f_mkdir("sd:emuSD");
|
||||
}else {
|
||||
strcpy(path, "emmc:emuSD/EMMC");
|
||||
f_mkdir("emmc:emuSD");
|
||||
}
|
||||
int path_len = strlen(path);
|
||||
|
||||
f_mkdir("emuSD");
|
||||
|
||||
for(int j = 0; j < 100; j++){
|
||||
update_base_path(path, j, path_len);
|
||||
if(f_stat(path, NULL) == FR_NO_FILE){
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
f_mkdir(path);
|
||||
f_mkdir(path + (drive == DRIVE_SD ? 3 : 5));
|
||||
|
||||
u32 base_path_len = strlen(path);
|
||||
|
||||
strcat(path, "/SD");
|
||||
f_mkdir(path);
|
||||
|
||||
strcat(path, "/");
|
||||
path_len = strlen(path);
|
||||
|
||||
// allocate files for emusd
|
||||
u32 sct_left = size_sct;
|
||||
u32 idx = 0;
|
||||
|
||||
gfx_printf("sct left 0x%x\n", sct_left);
|
||||
while(sct_left) {
|
||||
update_base_path(path, idx, path_len);
|
||||
|
||||
u32 scts = MIN(sct_left, file_max_scts);
|
||||
|
||||
FIL f;
|
||||
int res = f_open(&f, path, FA_CREATE_ALWAYS | FA_WRITE);
|
||||
if(res != FR_OK) {
|
||||
gfx_printf("open fail\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
FSIZE_t seek_bytes = (FSIZE_t)scts << 9;
|
||||
res = f_lseek(&f, seek_bytes);
|
||||
f_close(&f);
|
||||
|
||||
if(res != FR_OK){
|
||||
f_unlink(path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
sct_left -= scts;
|
||||
idx++;
|
||||
}
|
||||
|
||||
|
||||
path[path_len] = '\0';
|
||||
|
||||
sfd_file_based_init(path);
|
||||
|
||||
u8 *buf = malloc(SZ_4M);
|
||||
u32 cluster_size = 65536;
|
||||
|
||||
int res = f_mkfs("sfd:", FM_FAT32, cluster_size, buf, SZ_4M);
|
||||
|
||||
while (res != FR_OK && cluster_size > 4096){
|
||||
cluster_size /= 2;
|
||||
res = f_mkfs("sfd:", FM_FAT32, cluster_size, buf, SZ_4M);
|
||||
}
|
||||
|
||||
if(res == FR_OK){
|
||||
FATFS fs;
|
||||
res = f_mount(&fs, "sfd:", 1);
|
||||
|
||||
if(res == FR_OK){
|
||||
gfx_printf("mount fail %d\n", res);
|
||||
char label[0x30];
|
||||
strcpy(label, "sfd:emusd");
|
||||
res = f_setlabel(label);
|
||||
}
|
||||
|
||||
f_mount(NULL, "sfd:", 0);
|
||||
}
|
||||
|
||||
sfd_end();
|
||||
|
||||
free(buf);
|
||||
|
||||
if(res != FR_OK) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
path[base_path_len] = '\0';
|
||||
s_printf(path + base_path_len, drive == DRIVE_SD ? "/file_based" : "/file_emmc_based");
|
||||
FIL f;
|
||||
res = f_open(&f, path + (drive == DRIVE_SD ? 3 : 5), FA_WRITE | FA_CREATE_ALWAYS);
|
||||
f_close(&f);
|
||||
gfx_printf("%s %d\n", path, res);
|
||||
|
||||
path[base_path_len] = '\0';
|
||||
save_emusd_cfg(0, 0, path + (drive == DRIVE_SD ? 3 : 5), drive);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int create_emusd(int part_idx, u32 sector_mbr, u32 sector_start, u32 sector_size, const char *name, u8 drive){
|
||||
sdmmc_storage_t *storage = drive == DRIVE_SD ? &sd_storage : &emmc_storage;
|
||||
|
||||
sfd_init(storage, sector_start, sector_size);
|
||||
|
||||
u8 *buf = malloc(SZ_4M);
|
||||
FIL f;
|
||||
u32 cluster_size = 65536;
|
||||
|
||||
u32 mkfs_error = f_mkfs("sfd:", FM_FAT32 | FM_SFD, cluster_size, buf, SZ_4M);
|
||||
|
||||
while(mkfs_error != FR_OK && cluster_size > 4096){
|
||||
cluster_size /= 2;
|
||||
mkfs_error = f_mkfs("sfd:", FM_FAT32 | FM_SFD, cluster_size, buf, SZ_4M);
|
||||
}
|
||||
|
||||
if(mkfs_error == FR_OK){
|
||||
FATFS fs;
|
||||
mkfs_error = f_mount(&fs, "sfd:", 1);
|
||||
|
||||
if(mkfs_error == FR_OK){
|
||||
mkfs_error = f_open(&f, "sfd:.no_boot_storage", FA_CREATE_ALWAYS | FA_WRITE);
|
||||
f_close(&f);
|
||||
|
||||
if(mkfs_error == FR_OK){
|
||||
char label[0x30];
|
||||
strcpy(label, "sfd:");
|
||||
strcat(label, name);
|
||||
mkfs_error = f_setlabel(label);
|
||||
|
||||
if(mkfs_error == FR_OK){
|
||||
u8 random_number[16];
|
||||
mbr_t mbr = {0};
|
||||
se_gen_prng128(random_number);
|
||||
memcpy(&mbr.signature, random_number, 4);
|
||||
mbr.boot_signature = 0xaa55;
|
||||
mbr.partitions[0].start_sct = sector_start - sector_mbr;
|
||||
mbr.partitions[0].size_sct = sector_size;
|
||||
mbr.partitions[0].type = 0x0c;
|
||||
|
||||
mkfs_error = sdmmc_storage_write(storage, sector_mbr, 1, &mbr) ? FR_OK : FR_DISK_ERR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
f_mount(NULL, "sfd:", 0);
|
||||
}
|
||||
|
||||
sfd_end();
|
||||
|
||||
if(mkfs_error != FR_OK){
|
||||
return mkfs_error;
|
||||
}
|
||||
|
||||
char path[0x80];
|
||||
strcpy(path, "emuSD");
|
||||
f_mkdir(path);
|
||||
s_printf(path + strlen(path), "/RAW_%s%d", drive == DRIVE_SD ? "SD" : "EMMC", part_idx);
|
||||
f_mkdir(path);
|
||||
strcat(path, "/raw_emmc_based");
|
||||
|
||||
f_open(&f, path, FA_CREATE_ALWAYS | FA_WRITE);
|
||||
f_write(&f, §or_mbr, 4, NULL);
|
||||
f_close(&f);
|
||||
|
||||
save_emusd_cfg(part_idx, sector_mbr, NULL, drive);
|
||||
|
||||
return FR_OK;
|
||||
}
|
||||
17
nyx/nyx_gui/frontend/fe_emusd_tools.h
Normal file
17
nyx/nyx_gui/frontend/fe_emusd_tools.h
Normal file
@@ -0,0 +1,17 @@
|
||||
#ifndef _FE_EMUSD_TOOLS_H_
|
||||
#define _FE_EMUSD_TOOLS_H_
|
||||
|
||||
#include "gui.h"
|
||||
|
||||
typedef struct _emusd_cfg_t{
|
||||
// 0: disabled, 1: enabled
|
||||
int enabled;
|
||||
u32 sector;
|
||||
char *path;
|
||||
} emusd_cfg_t;
|
||||
|
||||
void load_emusd_cfg(emusd_cfg_t *emu_info);
|
||||
void save_emusd_cfg(u32 part_idx, u32 sector_start, const char *path, u8 drive);
|
||||
int create_emusd(int part_idx, u32 sector_mbr, u32 sector_start, u32 sector_size, const char *name, u8 drive);
|
||||
int create_emusd_file(u32 size_sct, u8 drive);
|
||||
#endif
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2024 CTCaer
|
||||
* Copyright (c) 2018-2025 CTCaer
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
@@ -19,6 +19,7 @@
|
||||
#include <bdk.h>
|
||||
|
||||
#include "gui.h"
|
||||
#include "gui_emu_tools.h"
|
||||
#include "gui_emummc_tools.h"
|
||||
#include "gui_tools.h"
|
||||
#include "gui_info.h"
|
||||
@@ -29,6 +30,7 @@
|
||||
|
||||
#include "../config.h"
|
||||
#include <libs/fatfs/ff.h>
|
||||
#include <storage/boot_storage.h>
|
||||
|
||||
extern hekate_config h_cfg;
|
||||
extern nyx_config n_cfg;
|
||||
@@ -187,7 +189,7 @@ static void _save_log_to_bmp(char *fname)
|
||||
char path[0x80];
|
||||
strcpy(path, "bootloader/screenshots");
|
||||
s_printf(path + strlen(path), "/nyx%s_log.bmp", fname);
|
||||
sd_save_to_file(bitmap, file_size, path);
|
||||
boot_storage_save_to_file(bitmap, file_size, path);
|
||||
|
||||
free(bitmap);
|
||||
free(fb);
|
||||
@@ -271,7 +273,7 @@ static void _save_fb_to_bmp()
|
||||
bmp->res_v = 2834;
|
||||
bmp->rsvd2 = 0;
|
||||
|
||||
sd_mount();
|
||||
boot_storage_mount();
|
||||
|
||||
char path[0x80];
|
||||
|
||||
@@ -288,7 +290,7 @@ static void _save_fb_to_bmp()
|
||||
s_printf(path + strlen(path), "/nyx%s.bmp", fname);
|
||||
|
||||
// Save screenshot and log.
|
||||
int res = sd_save_to_file(bitmap, file_size, path);
|
||||
int res = boot_storage_save_to_file(bitmap, file_size, path);
|
||||
if (!res)
|
||||
_save_log_to_bmp(fname);
|
||||
|
||||
@@ -651,7 +653,7 @@ void manual_system_maintenance(bool refresh)
|
||||
lv_img_dsc_t *bmp_to_lvimg_obj(const char *path)
|
||||
{
|
||||
u32 fsize;
|
||||
u8 *bitmap = sd_file_read(path, &fsize);
|
||||
u8 *bitmap = boot_storage_file_read(path, &fsize);
|
||||
if (!bitmap)
|
||||
return NULL;
|
||||
|
||||
@@ -815,7 +817,7 @@ bool nyx_emmc_check_battery_enough()
|
||||
return true;
|
||||
}
|
||||
|
||||
static void _nyx_sd_card_issues(void *param)
|
||||
static void _nyx_sd_card_issues_warning(void *param)
|
||||
{
|
||||
lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL);
|
||||
lv_obj_set_style(dark_bg, &mbox_darken);
|
||||
@@ -826,7 +828,7 @@ static void _nyx_sd_card_issues(void *param)
|
||||
lv_mbox_set_recolor_text(mbox, true);
|
||||
|
||||
lv_mbox_set_text(mbox,
|
||||
"#FF8000 SD Card Issues Check#\n\n"
|
||||
"#FF8000 SD Card Issues Warning#\n\n"
|
||||
"#FFDD00 The SD Card is initialized in 1-bit mode!#\n"
|
||||
"#FFDD00 This might mean detached or broken connector!#\n\n"
|
||||
"You might want to check\n#C7EA46 Console Info# -> #C7EA46 microSD#");
|
||||
@@ -866,7 +868,7 @@ void nyx_window_toggle_buttons(lv_obj_t *win, bool disable)
|
||||
}
|
||||
}
|
||||
|
||||
lv_res_t lv_win_close_action_custom(lv_obj_t * btn)
|
||||
lv_res_t nyx_win_close_action_custom(lv_obj_t * btn)
|
||||
{
|
||||
close_btn = NULL;
|
||||
|
||||
@@ -886,7 +888,7 @@ lv_obj_t *nyx_create_standard_window(const char *win_title)
|
||||
lv_win_set_style(win, LV_WIN_STYLE_BG, &win_bg_style);
|
||||
lv_obj_set_size(win, LV_HOR_RES, LV_VER_RES);
|
||||
|
||||
close_btn = lv_win_add_btn(win, NULL, SYMBOL_CLOSE" Close", lv_win_close_action_custom);
|
||||
close_btn = lv_win_add_btn(win, NULL, SYMBOL_CLOSE" Close", nyx_win_close_action_custom);
|
||||
|
||||
return win;
|
||||
}
|
||||
@@ -921,7 +923,9 @@ static void _launch_hos(u8 autoboot, u8 autoboot_list)
|
||||
|
||||
void (*main_ptr)() = (void *)nyx_str->hekate;
|
||||
|
||||
boot_storage_end();
|
||||
sd_end();
|
||||
emmc_end();
|
||||
|
||||
hw_deinit(false, 0);
|
||||
|
||||
@@ -937,6 +941,9 @@ void reload_nyx()
|
||||
|
||||
void (*main_ptr)() = (void *)nyx_str->hekate;
|
||||
|
||||
// TODO:
|
||||
boot_storage_end();
|
||||
emmc_end();
|
||||
sd_end();
|
||||
|
||||
hw_deinit(false, 0);
|
||||
@@ -981,7 +988,7 @@ static void _check_sd_card_removed(void *params)
|
||||
// The following checks if SDMMC_1 is initialized.
|
||||
// If yes and card was removed, shows a message box,
|
||||
// that will reload Nyx, when the card is inserted again.
|
||||
if (!do_reload && sd_get_card_removed())
|
||||
if (!do_reload && sd_get_card_removed() && boot_storage_get_drive() == DRIVE_SD)
|
||||
{
|
||||
lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL);
|
||||
lv_obj_set_style(dark_bg, &mbox_darken);
|
||||
@@ -1003,12 +1010,12 @@ static void _check_sd_card_removed(void *params)
|
||||
}
|
||||
|
||||
// If in reload state and card was inserted, reload nyx.
|
||||
if (do_reload && !sd_get_card_removed())
|
||||
if (do_reload && !sd_get_card_removed() && boot_storage_get_drive() == DRIVE_SD)
|
||||
reload_nyx();
|
||||
}
|
||||
|
||||
lv_task_t *task_emmc_errors;
|
||||
static void _nyx_emmc_issues(void *params)
|
||||
static void _nyx_emmc_issues_warning(void *params)
|
||||
{
|
||||
if (emmc_get_mode() < EMMC_MMC_HS400)
|
||||
{
|
||||
@@ -1024,8 +1031,8 @@ static void _nyx_emmc_issues(void *params)
|
||||
lv_mbox_set_recolor_text(mbox, true);
|
||||
|
||||
lv_mbox_set_text(mbox,
|
||||
"#FF8000 eMMC Issues Check#\n\n"
|
||||
"#FFDD00 Your eMMC is initialized in slower mode!#\n"
|
||||
"#FF8000 eMMC Issues Warning#\n\n"
|
||||
"#FFDD00 Your eMMC is initialized in a slower mode!#\n"
|
||||
"#FFDD00 This might mean hardware issues!#\n\n"
|
||||
"You might want to check\n#C7EA46 Console Info# -> #C7EA46 eMMC#");
|
||||
|
||||
@@ -1232,9 +1239,9 @@ static void _create_tab_about(lv_theme_t * th, lv_obj_t * parent)
|
||||
lv_label_set_recolor(lbl_credits, true);
|
||||
lv_label_set_static_text(lbl_credits,
|
||||
"#C7EA46 hekate# (c) 2018, #C7EA46 naehrwert#, #C7EA46 st4rk#\n"
|
||||
" (c) 2018-2024, #C7EA46 CTCaer#\n"
|
||||
" (c) 2018-2025, #C7EA46 CTCaer#\n"
|
||||
"\n"
|
||||
"#C7EA46 Nyx# (c) 2019-2024, #C7EA46 CTCaer#\n"
|
||||
"#C7EA46 Nyx# (c) 2019-2025, #C7EA46 CTCaer#\n"
|
||||
"\n"
|
||||
"Thanks to: #00CCFF derrek, nedwill, plutoo, #\n"
|
||||
" #00CCFF shuffle2, smea, thexyz, yellows8 #\n"
|
||||
@@ -1387,8 +1394,9 @@ static lv_res_t _create_mbox_payloads(lv_obj_t *btn)
|
||||
lv_obj_set_size(list, LV_HOR_RES * 3 / 7, LV_VER_RES * 3 / 7);
|
||||
lv_list_set_single_mode(list, true);
|
||||
|
||||
if (!sd_mount())
|
||||
if (!boot_storage_mount())
|
||||
{
|
||||
// TODO: may not be SD, change error
|
||||
lv_mbox_set_text(mbox, "#FFDD00 Failed to init SD!#");
|
||||
|
||||
goto out_end;
|
||||
@@ -1699,7 +1707,7 @@ static lv_res_t _create_window_home_launch(lv_obj_t *btn)
|
||||
u32 curr_btn_idx = 0; // Active buttons.
|
||||
LIST_INIT(ini_sections);
|
||||
|
||||
if (!sd_mount())
|
||||
if (!boot_storage_mount())
|
||||
goto failed_sd_mount;
|
||||
|
||||
// Check if we use custom system icons.
|
||||
@@ -1895,7 +1903,7 @@ failed_sd_mount:
|
||||
if (curr_btn_idx < 1)
|
||||
no_boot_entries = true;
|
||||
|
||||
sd_unmount();
|
||||
boot_storage_unmount();
|
||||
|
||||
free(tmp_path);
|
||||
|
||||
@@ -2026,7 +2034,7 @@ static void _create_tab_home(lv_theme_t *th, lv_obj_t *parent)
|
||||
label_btn = lv_label_create(btn_emummc, label_btn);
|
||||
s_printf(btn_colored_text, "%s%s", text_color, " "SYMBOL_LIST"#");
|
||||
lv_label_set_text(label_btn, btn_colored_text);
|
||||
lv_btn_set_action(btn_emummc, LV_BTN_ACTION_CLICK, create_win_emummc_tools);
|
||||
lv_btn_set_action(btn_emummc, LV_BTN_ACTION_CLICK, create_win_emu_tools);
|
||||
lv_btn_set_layout(btn_emummc, LV_LAYOUT_OFF);
|
||||
lv_obj_align(label_btn, NULL, LV_ALIGN_CENTER, 0, -28);
|
||||
lv_obj_set_pos(btn_emummc, 959, 160);
|
||||
@@ -2058,7 +2066,7 @@ static lv_res_t _save_options_action(lv_obj_t *btn)
|
||||
|
||||
int res = 0;
|
||||
|
||||
if (sd_mount())
|
||||
if (boot_storage_mount())
|
||||
res = !create_config_entry();
|
||||
|
||||
if (res)
|
||||
@@ -2070,7 +2078,7 @@ static lv_res_t _save_options_action(lv_obj_t *btn)
|
||||
|
||||
nyx_options_clear_ini_changes_made();
|
||||
|
||||
sd_unmount();
|
||||
boot_storage_unmount();
|
||||
|
||||
return LV_RES_OK;
|
||||
}
|
||||
@@ -2079,6 +2087,7 @@ static void _create_status_bar(lv_theme_t * th)
|
||||
{
|
||||
static lv_obj_t *status_bar_bg;
|
||||
status_bar_bg = lv_cont_create(lv_layer_top(), NULL);
|
||||
status_bar.bar_bg = status_bar_bg;
|
||||
|
||||
static lv_style_t status_bar_style;
|
||||
lv_style_copy(&status_bar_style, &lv_style_plain_color);
|
||||
@@ -2131,9 +2140,9 @@ static void _create_status_bar(lv_theme_t * th)
|
||||
lv_obj_set_size(btn_mid, LV_DPI * 5 / 2, LV_DPI / 2);
|
||||
lv_obj_align(btn_mid, NULL, LV_ALIGN_CENTER, 0, 0);
|
||||
status_bar.mid = btn_mid;
|
||||
lv_obj_set_opa_scale(status_bar.mid, LV_OPA_0);
|
||||
lv_obj_set_opa_scale_enable(status_bar.mid, true);
|
||||
lv_obj_set_click(status_bar.mid, false);
|
||||
lv_obj_set_opa_scale(btn_mid, LV_OPA_0);
|
||||
lv_obj_set_opa_scale_enable(btn_mid, true);
|
||||
lv_obj_set_click(btn_mid, false);
|
||||
lv_btn_set_action(btn_mid, LV_BTN_ACTION_CLICK, _save_options_action);
|
||||
}
|
||||
|
||||
@@ -2354,7 +2363,7 @@ static void _nyx_main_menu(lv_theme_t * th)
|
||||
|
||||
lv_task_create(_check_sd_card_removed, 2000, LV_TASK_PRIO_LOWEST, NULL);
|
||||
|
||||
task_emmc_errors = lv_task_create(_nyx_emmc_issues, 2000, LV_TASK_PRIO_LOWEST, NULL);
|
||||
task_emmc_errors = lv_task_create(_nyx_emmc_issues_warning, 2000, LV_TASK_PRIO_LOWEST, NULL);
|
||||
lv_task_ready(task_emmc_errors);
|
||||
|
||||
// Create top level global line separators.
|
||||
@@ -2454,7 +2463,7 @@ void nyx_load_and_run()
|
||||
// Check if sd card issues.
|
||||
if (sd_get_mode() == SD_1BIT_HS25)
|
||||
{
|
||||
lv_task_t *task_run_sd_errors = lv_task_create(_nyx_sd_card_issues, LV_TASK_ONESHOT, LV_TASK_PRIO_LOWEST, NULL);
|
||||
lv_task_t *task_run_sd_errors = lv_task_create(_nyx_sd_card_issues_warning, LV_TASK_ONESHOT, LV_TASK_PRIO_LOWEST, NULL);
|
||||
lv_task_once(task_run_sd_errors);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2019 CTCaer
|
||||
* Copyright (c) 2018-2025 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,
|
||||
@@ -36,6 +36,7 @@ typedef struct _emmc_tool_gui_t
|
||||
|
||||
typedef struct _gui_status_bar_ctx
|
||||
{
|
||||
lv_obj_t *bar_bg;
|
||||
lv_obj_t *mid;
|
||||
lv_obj_t *time_temp;
|
||||
lv_obj_t *temp_symbol;
|
||||
@@ -72,6 +73,7 @@ void reload_nyx();
|
||||
lv_img_dsc_t *bmp_to_lvimg_obj(const char *path);
|
||||
lv_res_t mbox_action(lv_obj_t * btns, const char * txt);
|
||||
bool nyx_emmc_check_battery_enough();
|
||||
lv_res_t nyx_win_close_action_custom(lv_obj_t * btn);
|
||||
void nyx_window_toggle_buttons(lv_obj_t *win, bool disable);
|
||||
lv_obj_t *nyx_create_standard_window(const char *win_title);
|
||||
lv_obj_t *nyx_create_window_custom_close_btn(const char *win_title, lv_action_t rel_action);
|
||||
|
||||
@@ -240,15 +240,15 @@ static lv_res_t _emmc_backup_buttons_raw_toggle(lv_obj_t *btn)
|
||||
else // Backup/Restore from and to emuMMC.
|
||||
{
|
||||
if (!emmc_btn_ctxt.restore)
|
||||
lv_label_set_static_text(lv_obj_get_child(emmc_btn_ctxt.emmc_boot, NULL), SYMBOL_UPLOAD" SD emuMMC BOOT0 & BOOT1");
|
||||
lv_label_set_static_text(lv_obj_get_child(emmc_btn_ctxt.emmc_boot, NULL), SYMBOL_UPLOAD" emuMMC BOOT0 & BOOT1");
|
||||
else
|
||||
lv_label_set_static_text(lv_obj_get_child(emmc_btn_ctxt.emmc_boot, NULL), SYMBOL_DOWNLOAD" SD emuMMC BOOT0 & BOOT1");
|
||||
lv_label_set_static_text(lv_obj_get_child(emmc_btn_ctxt.emmc_boot, NULL), SYMBOL_DOWNLOAD" emuMMC BOOT0 & BOOT1");
|
||||
lv_obj_realign(emmc_btn_ctxt.emmc_boot);
|
||||
|
||||
if (!emmc_btn_ctxt.restore)
|
||||
lv_label_set_static_text(lv_obj_get_child(emmc_btn_ctxt.emmc_raw_gpp, NULL), SYMBOL_UPLOAD" SD emuMMC RAW GPP");
|
||||
lv_label_set_static_text(lv_obj_get_child(emmc_btn_ctxt.emmc_raw_gpp, NULL), SYMBOL_UPLOAD" emuMMC RAW GPP");
|
||||
else
|
||||
lv_label_set_static_text(lv_obj_get_child(emmc_btn_ctxt.emmc_raw_gpp, NULL), SYMBOL_DOWNLOAD" SD emuMMC RAW GPP");
|
||||
lv_label_set_static_text(lv_obj_get_child(emmc_btn_ctxt.emmc_raw_gpp, NULL), SYMBOL_DOWNLOAD" emuMMC RAW GPP");
|
||||
lv_obj_realign(emmc_btn_ctxt.emmc_raw_gpp);
|
||||
|
||||
lv_obj_set_click(emmc_btn_ctxt.emmc_sys, false);
|
||||
@@ -454,7 +454,7 @@ lv_res_t create_window_backup_restore_tool(lv_obj_t *btn)
|
||||
|
||||
lv_obj_t *sd_emummc_raw = lv_btn_create(h3, NULL);
|
||||
nyx_create_onoff_button(lv_theme_get_current(), h3,
|
||||
sd_emummc_raw, SYMBOL_SD" SD emuMMC Raw Partition", _emmc_backup_buttons_raw_toggle, false);
|
||||
sd_emummc_raw, SYMBOL_SD" emuMMC Raw Partition", _emmc_backup_buttons_raw_toggle, false);
|
||||
emmc_btn_ctxt.raw_emummc = false;
|
||||
|
||||
return LV_RES_OK;
|
||||
|
||||
79
nyx/nyx_gui/frontend/gui_emu_tools.c
Normal file
79
nyx/nyx_gui/frontend/gui_emu_tools.c
Normal file
@@ -0,0 +1,79 @@
|
||||
#include "gui_emu_tools.h"
|
||||
#include "gui.h"
|
||||
#include "gui_emummc_tools.h"
|
||||
#include "gui_emusd_tools.h"
|
||||
#include <libs/lvgl/lv_core/lv_obj.h>
|
||||
#include <libs/lvgl/lv_core/lv_style.h>
|
||||
#include <libs/lvgl/lv_objx/lv_cont.h>
|
||||
#include <libs/lvgl/lv_objx/lv_label.h>
|
||||
#include <libs/lvgl/lv_objx/lv_line.h>
|
||||
#include <libs/lvgl/lv_objx/lv_page.h>
|
||||
#include <libs/lvgl/lv_objx/lv_tabview.h>
|
||||
#include <libs/lvgl/lv_objx/lv_win.h>
|
||||
#include <libs/lvgl/lv_themes/lv_theme.h>
|
||||
#include <gfx_utils.h>
|
||||
|
||||
static lv_obj_t *_create_container(lv_obj_t *parent){
|
||||
static lv_style_t h_style;
|
||||
lv_style_copy(&h_style, &lv_style_transp);
|
||||
h_style.body.padding.inner = 0;
|
||||
h_style.body.padding.hor = 0;
|
||||
h_style.body.padding.ver = 0;
|
||||
|
||||
lv_obj_t *h1 = lv_cont_create(parent, NULL);
|
||||
lv_cont_set_style(h1, &h_style);
|
||||
lv_cont_set_fit(h1, false, true);
|
||||
lv_obj_set_width(h1, LV_HOR_RES - 62);
|
||||
lv_obj_set_click(h1, false);
|
||||
lv_cont_set_layout(h1, LV_LAYOUT_OFF);
|
||||
|
||||
return h1;
|
||||
}
|
||||
|
||||
lv_res_t create_win_emu_tools(lv_obj_t *btn){
|
||||
lv_obj_t *win = nyx_create_standard_window(SYMBOL_EDIT " emuMMC Manage");
|
||||
|
||||
static lv_style_t win_style_no_pad;
|
||||
lv_style_copy(&win_style_no_pad, lv_win_get_style(win, LV_WIN_STYLE_CONTENT_BG));
|
||||
win_style_no_pad.body.padding.hor = 0;
|
||||
win_style_no_pad.body.padding.inner = 0;
|
||||
|
||||
lv_win_set_style(win, LV_WIN_STYLE_CONTENT_BG, &win_style_no_pad);
|
||||
|
||||
lv_obj_t *tv = lv_tabview_create(win, NULL);
|
||||
lv_obj_set_size(tv, LV_HOR_RES - 62, 572);
|
||||
|
||||
gfx_printf("w: %d\n",(u32)lv_obj_get_width(tv));
|
||||
|
||||
static lv_style_t tv_style;
|
||||
lv_style_copy(&tv_style, lv_theme_get_current()->tabview.btn.rel);
|
||||
tv_style.body.padding.ver = LV_DPI / 8;
|
||||
tv_style.body.padding.hor = 0;
|
||||
|
||||
lv_tabview_set_style(tv, LV_TABVIEW_STYLE_BTN_REL, &tv_style);
|
||||
|
||||
if(hekate_bg){
|
||||
lv_tabview_set_style(tv, LV_TABVIEW_STYLE_BTN_PR, &tabview_btn_pr);
|
||||
lv_tabview_set_style(tv, LV_TABVIEW_STYLE_BTN_TGL_PR, &tabview_btn_tgl_pr);
|
||||
}
|
||||
|
||||
lv_tabview_set_sliding(tv, false);
|
||||
lv_tabview_set_btns_pos(tv, LV_TABVIEW_BTNS_POS_BOTTOM);
|
||||
|
||||
lv_obj_t *tab_emummc = lv_tabview_add_tab(tv, SYMBOL_CHIP " emuMMC");
|
||||
lv_obj_t *tab_emusd = lv_tabview_add_tab(tv, SYMBOL_SD " emuSD");
|
||||
|
||||
lv_obj_t *line_sep = lv_line_create(tv, NULL);
|
||||
static const lv_point_t line_pp[] = {{0,0}, {0, LV_DPI / 4}};
|
||||
lv_line_set_points(line_sep, line_pp, 2);
|
||||
lv_line_set_style(line_sep, lv_theme_get_current()->line.decor);
|
||||
lv_obj_align(line_sep, tv, LV_ALIGN_IN_BOTTOM_MID, -1, -LV_DPI * 2 / 12);
|
||||
|
||||
create_tab_emummc_tools(_create_container(tab_emummc));
|
||||
create_tab_emusd_tools(_create_container(tab_emusd));
|
||||
|
||||
lv_tabview_set_tab_act(tv, 0, false);
|
||||
|
||||
return LV_RES_OK;
|
||||
}
|
||||
|
||||
8
nyx/nyx_gui/frontend/gui_emu_tools.h
Normal file
8
nyx/nyx_gui/frontend/gui_emu_tools.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#ifndef _GUI_EMU_TOOLS_H_
|
||||
#define _GUI_EMU_TOOLS_H_
|
||||
|
||||
#include <libs/lvgl/lvgl.h>
|
||||
|
||||
lv_res_t create_win_emu_tools(lv_obj_t *btn);
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -19,6 +19,6 @@
|
||||
|
||||
#include <libs/lvgl/lvgl.h>
|
||||
|
||||
lv_res_t create_win_emummc_tools(lv_obj_t *btn);
|
||||
lv_res_t create_tab_emummc_tools(lv_obj_t *parent);
|
||||
|
||||
#endif
|
||||
|
||||
1136
nyx/nyx_gui/frontend/gui_emusd_tools.c
Normal file
1136
nyx/nyx_gui/frontend/gui_emusd_tools.c
Normal file
File diff suppressed because it is too large
Load Diff
8
nyx/nyx_gui/frontend/gui_emusd_tools.h
Normal file
8
nyx/nyx_gui/frontend/gui_emusd_tools.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#ifndef _GUI_EMUSD_TOOLS_H_
|
||||
#define _GUI_EMUSD_TOOLS_H_
|
||||
|
||||
#include <libs/lvgl/lvgl.h>
|
||||
|
||||
lv_res_t create_tab_emusd_tools(lv_obj_t *parent);
|
||||
|
||||
#endif
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (c) 2018-2024 CTCaer
|
||||
* Copyright (c) 2018-2025 CTCaer
|
||||
* Copyright (c) 2018 balika011
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
@@ -23,6 +23,9 @@
|
||||
#include "../hos/hos.h"
|
||||
#include "../hos/pkg1.h"
|
||||
#include <libs/fatfs/ff.h>
|
||||
#include <storage/boot_storage.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#define SECTORS_TO_MIB_COEFF 11
|
||||
|
||||
@@ -72,15 +75,15 @@ static lv_res_t _cal0_dump_window_action(lv_obj_t *btns, const char * txt)
|
||||
|
||||
if (btn_idx == 1)
|
||||
{
|
||||
int error = !sd_mount();
|
||||
int error = !boot_storage_mount();
|
||||
|
||||
if (!error)
|
||||
{
|
||||
char path[64];
|
||||
emmcsn_path_impl(path, "/dumps", "cal0.bin", NULL);
|
||||
error = sd_save_to_file((u8 *)cal0_buf, SZ_32K, path);
|
||||
error = boot_storage_save_to_file((u8 *)cal0_buf, SZ_32K, path);
|
||||
|
||||
sd_unmount();
|
||||
boot_storage_unmount();
|
||||
}
|
||||
|
||||
_create_window_dump_done(error, "cal0.bin");
|
||||
@@ -92,7 +95,7 @@ static lv_res_t _cal0_dump_window_action(lv_obj_t *btns, const char * txt)
|
||||
|
||||
static lv_res_t _battery_dump_window_action(lv_obj_t * btn)
|
||||
{
|
||||
int error = !sd_mount();
|
||||
int error = !boot_storage_mount();
|
||||
|
||||
if (!error)
|
||||
{
|
||||
@@ -102,9 +105,9 @@ static lv_res_t _battery_dump_window_action(lv_obj_t * btn)
|
||||
max17050_dump_regs(buf);
|
||||
|
||||
emmcsn_path_impl(path, "/dumps", "fuel_gauge.bin", NULL);
|
||||
error = sd_save_to_file((u8 *)buf, 0x200, path);
|
||||
error = boot_storage_save_to_file((u8 *)buf, 0x200, path);
|
||||
|
||||
sd_unmount();
|
||||
boot_storage_unmount();
|
||||
}
|
||||
|
||||
_create_window_dump_done(error, "fuel_gauge.bin");
|
||||
@@ -116,7 +119,7 @@ static lv_res_t _bootrom_dump_window_action(lv_obj_t * btn)
|
||||
{
|
||||
static const u32 BOOTROM_SIZE = 0x18000;
|
||||
|
||||
int error = !sd_mount();
|
||||
int error = !boot_storage_mount();
|
||||
if (!error)
|
||||
{
|
||||
char path[64];
|
||||
@@ -126,13 +129,13 @@ static lv_res_t _bootrom_dump_window_action(lv_obj_t * btn)
|
||||
if (!error)
|
||||
{
|
||||
emmcsn_path_impl(path, "/dumps", "evp_thunks.bin", NULL);
|
||||
error = sd_save_to_file((u8 *)iram_evp_thunks, iram_evp_thunks_len, path);
|
||||
error = boot_storage_save_to_file((u8 *)iram_evp_thunks, iram_evp_thunks_len, path);
|
||||
}
|
||||
else
|
||||
error = 255;
|
||||
|
||||
emmcsn_path_impl(path, "/dumps", "bootrom_patched.bin", NULL);
|
||||
int res = sd_save_to_file((u8 *)IROM_BASE, BOOTROM_SIZE, path);
|
||||
int res = boot_storage_save_to_file((u8 *)IROM_BASE, BOOTROM_SIZE, path);
|
||||
if (!error)
|
||||
error = res;
|
||||
|
||||
@@ -141,13 +144,13 @@ static lv_res_t _bootrom_dump_window_action(lv_obj_t * btn)
|
||||
memset((void*)IPATCH_BASE, 0, sizeof(ipatch_cam)); // Zeroing valid entries is enough but zero everything.
|
||||
|
||||
emmcsn_path_impl(path, "/dumps", "bootrom_unpatched.bin", NULL);
|
||||
res = sd_save_to_file((u8 *)IROM_BASE, BOOTROM_SIZE, path);
|
||||
res = boot_storage_save_to_file((u8 *)IROM_BASE, BOOTROM_SIZE, path);
|
||||
if (!error)
|
||||
error = res;
|
||||
|
||||
memcpy((void*)IPATCH_BASE, ipatch_cam, sizeof(ipatch_cam));
|
||||
|
||||
sd_unmount();
|
||||
boot_storage_unmount();
|
||||
}
|
||||
_create_window_dump_done(error, "evp_thunks.bin, bootrom_patched.bin, bootrom_unpatched.bin");
|
||||
|
||||
@@ -158,22 +161,22 @@ static lv_res_t _fuse_dump_window_action(lv_obj_t * btn)
|
||||
{
|
||||
const u32 fuse_array_size = (h_cfg.t210b01 ? FUSE_ARRAY_WORDS_NUM_B01 : FUSE_ARRAY_WORDS_NUM) * sizeof(u32);
|
||||
|
||||
int error = !sd_mount();
|
||||
int error = !boot_storage_mount();
|
||||
if (!error)
|
||||
{
|
||||
char path[128];
|
||||
if (!h_cfg.t210b01)
|
||||
{
|
||||
emmcsn_path_impl(path, "/dumps", "fuse_cached_t210.bin", NULL);
|
||||
error = sd_save_to_file((u8 *)0x7000F900, 0x300, path);
|
||||
error = boot_storage_save_to_file((u8 *)0x7000F900, 0x300, path);
|
||||
}
|
||||
else
|
||||
{
|
||||
emmcsn_path_impl(path, "/dumps", "fuse_cached_t210b01_x898.bin", NULL);
|
||||
error = sd_save_to_file((u8 *)0x7000F898, 0x68, path);
|
||||
error = boot_storage_save_to_file((u8 *)0x7000F898, 0x68, path);
|
||||
emmcsn_path_impl(path, "/dumps", "fuse_cached_t210b01_x900.bin", NULL);
|
||||
if (!error)
|
||||
error = sd_save_to_file((u8 *)0x7000F900, 0x300, path);
|
||||
error = boot_storage_save_to_file((u8 *)0x7000F900, 0x300, path);
|
||||
}
|
||||
|
||||
u32 words[FUSE_ARRAY_WORDS_NUM_B01];
|
||||
@@ -182,11 +185,11 @@ static lv_res_t _fuse_dump_window_action(lv_obj_t * btn)
|
||||
emmcsn_path_impl(path, "/dumps", "fuse_array_raw_t210.bin", NULL);
|
||||
else
|
||||
emmcsn_path_impl(path, "/dumps", "fuse_array_raw_t210b01.bin", NULL);
|
||||
int res = sd_save_to_file((u8 *)words, fuse_array_size, path);
|
||||
int res = boot_storage_save_to_file((u8 *)words, fuse_array_size, path);
|
||||
if (!error)
|
||||
error = res;
|
||||
|
||||
sd_unmount();
|
||||
boot_storage_unmount();
|
||||
}
|
||||
|
||||
if (!h_cfg.t210b01)
|
||||
@@ -203,15 +206,15 @@ static lv_res_t _kfuse_dump_window_action(lv_obj_t * btn)
|
||||
int error = !kfuse_read(buf);
|
||||
|
||||
if (!error)
|
||||
error = !sd_mount();
|
||||
error = !boot_storage_mount();
|
||||
|
||||
if (!error)
|
||||
{
|
||||
char path[64];
|
||||
emmcsn_path_impl(path, "/dumps", "kfuses.bin", NULL);
|
||||
error = sd_save_to_file((u8 *)buf, KFUSE_NUM_WORDS * 4, path);
|
||||
error = boot_storage_save_to_file((u8 *)buf, KFUSE_NUM_WORDS * 4, path);
|
||||
|
||||
sd_unmount();
|
||||
boot_storage_unmount();
|
||||
}
|
||||
|
||||
_create_window_dump_done(error, "kfuses.bin");
|
||||
@@ -241,7 +244,7 @@ static lv_res_t _create_mbox_cal0(lv_obj_t *btn)
|
||||
lv_label_set_style(lb_desc, &monospace_text);
|
||||
lv_obj_set_width(lb_desc, LV_HOR_RES / 9 * 4);
|
||||
|
||||
sd_mount();
|
||||
boot_storage_mount();
|
||||
|
||||
// Dump CAL0.
|
||||
int cal0_res = hos_dump_cal0();
|
||||
@@ -341,7 +344,7 @@ static lv_res_t _create_mbox_cal0(lv_obj_t *btn)
|
||||
|
||||
out:
|
||||
free(txt_buf);
|
||||
sd_unmount();
|
||||
boot_storage_unmount();
|
||||
|
||||
lv_mbox_add_btns(mbox, mbox_btn_map, _cal0_dump_window_action);
|
||||
|
||||
@@ -351,9 +354,21 @@ out:
|
||||
return LV_RES_OK;
|
||||
}
|
||||
|
||||
static lv_res_t _create_window_fuses_info_status(lv_obj_t *btn)
|
||||
static lv_obj_t *hw_info_ver = NULL;
|
||||
static lv_res_t _action_win_hw_info_status_close(lv_obj_t *btn)
|
||||
{
|
||||
lv_obj_t *win = nyx_create_standard_window(SYMBOL_CHIP" HW & Fuses Info");
|
||||
if (hw_info_ver)
|
||||
{
|
||||
lv_obj_del(hw_info_ver);
|
||||
hw_info_ver = NULL;
|
||||
}
|
||||
|
||||
return nyx_win_close_action_custom(btn);
|
||||
}
|
||||
|
||||
static lv_res_t _create_window_hw_info_status(lv_obj_t *btn)
|
||||
{
|
||||
lv_obj_t *win = nyx_create_window_custom_close_btn(SYMBOL_CHIP" HW & Fuses Info", _action_win_hw_info_status_close);
|
||||
lv_win_add_btn(win, NULL, SYMBOL_DOWNLOAD" Dump fuses", _fuse_dump_window_action);
|
||||
lv_win_add_btn(win, NULL, SYMBOL_INFO" CAL0 Info", _create_mbox_cal0);
|
||||
|
||||
@@ -365,6 +380,14 @@ static lv_res_t _create_window_fuses_info_status(lv_obj_t *btn)
|
||||
lv_label_set_recolor(lb_desc, true);
|
||||
lv_label_set_style(lb_desc, &monospace_text);
|
||||
|
||||
char version[32];
|
||||
s_printf(version, "%s%d.%d.%d%c", NYX_VER_RL ? "v" : "", NYX_VER_MJ, NYX_VER_MN, NYX_VER_HF, NYX_VER_RL > 'A' ? NYX_VER_RL : 0);
|
||||
lv_obj_t * lbl_ver = lv_label_create(lv_scr_act(), NULL);
|
||||
lv_label_set_style(lbl_ver, &hint_small_style_white);
|
||||
lv_label_set_text(lbl_ver, version);
|
||||
lv_obj_align(lbl_ver, status_bar.bar_bg, LV_ALIGN_OUT_TOP_RIGHT, -LV_DPI * 9 / 23, -LV_DPI * 2 / 13);
|
||||
hw_info_ver = lbl_ver;
|
||||
|
||||
lv_label_set_static_text(lb_desc,
|
||||
"#FF8000 SoC:#\n"
|
||||
"#FF8000 SKU:#\n"
|
||||
@@ -590,7 +613,10 @@ static lv_res_t _create_window_fuses_info_status(lv_obj_t *btn)
|
||||
strcpy(fuses_hos_version, "17.0.0 - 18.1.0");
|
||||
break;
|
||||
case 20:
|
||||
strcpy(fuses_hos_version, "19.0.0+");
|
||||
strcpy(fuses_hos_version, "19.0.0 - 19.0.1");
|
||||
break;
|
||||
case 21:
|
||||
strcpy(fuses_hos_version, "20.0.0+");
|
||||
break;
|
||||
case 255:
|
||||
strcpy(fuses_hos_version, "#FFD000 Overburnt#");
|
||||
@@ -663,7 +689,7 @@ static lv_res_t _create_window_fuses_info_status(lv_obj_t *btn)
|
||||
u32 ranks = EMC(EMC_ADR_CFG) + 1;
|
||||
u32 channels = (EMC(EMC_FBIO_CFG7) >> 1) & 3;
|
||||
channels = (channels & 1) + ((channels & 2) >> 1);
|
||||
s_printf(txt_buf, "#00DDFF %s SDRAM ##FF8000 (Ch 0 | Ch 1):#\n#FF8000 Vendor:# ", h_cfg.t210b01 ? "LPDDR4X" : "LPDDR4");
|
||||
s_printf(txt_buf, "#00DDFF %s SDRAM ##FF8000 (Module 0 | 1):#\n#FF8000 Vendor:# ", h_cfg.t210b01 ? "LPDDR4X" : "LPDDR4");
|
||||
switch (ram_vendor.chip0.rank0_ch0)
|
||||
{
|
||||
case 1:
|
||||
@@ -735,49 +761,76 @@ static lv_res_t _create_window_fuses_info_status(lv_obj_t *btn)
|
||||
s_printf(txt_buf + strlen(txt_buf), "#FF8000 Unknown# (%d)", ram_vendor.chip1.rank0_ch0);
|
||||
break;
|
||||
}
|
||||
s_printf(txt_buf + strlen(txt_buf), "\n#FF8000 Rev ID:# %X.%02X #FF8000 |# %X.%02X\n#FF8000 Density:# %d",
|
||||
ram_rev0.chip0.rank0_ch0, ram_rev1.chip0.rank0_ch0, ram_rev0.chip1.rank0_ch0, ram_rev1.chip1.rank0_ch0, ranks * channels);
|
||||
|
||||
s_printf(txt_buf + strlen(txt_buf), "\n#FF8000 Rev ID:# %X.%02X #FF8000 |# %X.%02X\n#FF8000 Density:# ",
|
||||
ram_rev0.chip0.rank0_ch0, ram_rev1.chip0.rank0_ch0, ram_rev0.chip1.rank0_ch0, ram_rev1.chip1.rank0_ch0);
|
||||
|
||||
u32 actual_ranks = (ram_vendor.chip0.rank0_ch0 == ram_vendor.chip0.rank1_ch0 &&
|
||||
ram_vendor.chip0.rank0_ch1 == ram_vendor.chip0.rank1_ch1 &&
|
||||
ram_rev0.chip0.rank0_ch0 == ram_rev0.chip0.rank1_ch0 &&
|
||||
ram_rev0.chip0.rank0_ch1 == ram_rev0.chip0.rank1_ch1 &&
|
||||
ram_rev1.chip0.rank0_ch0 == ram_rev1.chip0.rank1_ch0 &&
|
||||
ram_rev1.chip0.rank0_ch1 == ram_rev1.chip0.rank1_ch1 &&
|
||||
ram_density.chip0.rank0_ch0 == ram_density.chip0.rank1_ch0 &&
|
||||
ram_density.chip0.rank0_ch1 == ram_density.chip0.rank1_ch1)
|
||||
? 2 : 1;
|
||||
bool rank_bad = ranks != actual_ranks;
|
||||
s_printf(txt_buf + strlen(txt_buf), "%s %d x %s", rank_bad ? "#FFDD00" : "", actual_ranks * channels, rank_bad ? "#" : "");
|
||||
|
||||
switch ((ram_density.chip0.rank0_ch0 & 0x3C) >> 2)
|
||||
{
|
||||
case 2:
|
||||
strcat(txt_buf, " x 512MB");
|
||||
strcat(txt_buf, "512MB");
|
||||
break;
|
||||
case 3:
|
||||
strcat(txt_buf, " x 768MB");
|
||||
strcat(txt_buf, "768MB");
|
||||
break;
|
||||
case 4:
|
||||
strcat(txt_buf, " x 1GB");
|
||||
strcat(txt_buf, "1GB");
|
||||
break;
|
||||
case 5:
|
||||
strcat(txt_buf, " x 1.5GB");
|
||||
strcat(txt_buf, "1.5GB");
|
||||
break;
|
||||
case 6:
|
||||
strcat(txt_buf, " x 2GB");
|
||||
strcat(txt_buf, "2GB");
|
||||
break;
|
||||
default:
|
||||
s_printf(txt_buf + strlen(txt_buf), " x Unk (%d)", (ram_density.chip0.rank0_ch0 & 0x3C) >> 2);
|
||||
s_printf(txt_buf + strlen(txt_buf), "Unk (%d)", (ram_density.chip0.rank0_ch0 & 0x3C) >> 2);
|
||||
break;
|
||||
}
|
||||
s_printf(txt_buf + strlen(txt_buf), " #FF8000 |# %d", ranks * channels);
|
||||
|
||||
actual_ranks = (ram_vendor.chip1.rank0_ch0 == ram_vendor.chip1.rank1_ch0 &&
|
||||
ram_vendor.chip1.rank0_ch1 == ram_vendor.chip1.rank1_ch1 &&
|
||||
ram_rev0.chip1.rank0_ch0 == ram_rev0.chip1.rank1_ch0 &&
|
||||
ram_rev0.chip1.rank0_ch1 == ram_rev0.chip1.rank1_ch1 &&
|
||||
ram_rev1.chip1.rank0_ch0 == ram_rev1.chip1.rank1_ch0 &&
|
||||
ram_rev1.chip1.rank0_ch1 == ram_rev1.chip1.rank1_ch1 &&
|
||||
ram_density.chip1.rank0_ch0 == ram_density.chip1.rank1_ch0 &&
|
||||
ram_density.chip1.rank0_ch1 == ram_density.chip1.rank1_ch1)
|
||||
? 2 : 1;
|
||||
rank_bad = ranks != actual_ranks;
|
||||
|
||||
s_printf(txt_buf + strlen(txt_buf), " #FF8000 |# %s %d x %s", rank_bad ? "#FFDD00" : "", actual_ranks * channels, rank_bad ? "#" : "");
|
||||
|
||||
switch ((ram_density.chip1.rank0_ch0 & 0x3C) >> 2)
|
||||
{
|
||||
case 2:
|
||||
strcat(txt_buf, " x 512MB");
|
||||
strcat(txt_buf, "512MB");
|
||||
break;
|
||||
case 3:
|
||||
strcat(txt_buf, " x 768MB");
|
||||
strcat(txt_buf, "768MB");
|
||||
break;
|
||||
case 4:
|
||||
strcat(txt_buf, " x 1GB");
|
||||
strcat(txt_buf, "1GB");
|
||||
break;
|
||||
case 5:
|
||||
strcat(txt_buf, " x 1.5GB");
|
||||
strcat(txt_buf, "1.5GB");
|
||||
break;
|
||||
case 6:
|
||||
strcat(txt_buf, " x 2GB");
|
||||
strcat(txt_buf, "2GB");
|
||||
break;
|
||||
default:
|
||||
s_printf(txt_buf + strlen(txt_buf), " x Unk (%d)", (ram_density.chip1.rank0_ch0 & 0x3C) >> 2);
|
||||
s_printf(txt_buf + strlen(txt_buf), "Unk (%d)", (ram_density.chip1.rank0_ch0 & 0x3C) >> 2);
|
||||
break;
|
||||
}
|
||||
strcat(txt_buf, "\n\n");
|
||||
@@ -940,13 +993,13 @@ static lv_res_t _create_window_fuses_info_status(lv_obj_t *btn)
|
||||
if (touch_panel)
|
||||
panel_ic_paired = touch_panel->idx == 0; // NISSHA NFT-K12D.
|
||||
break;
|
||||
case 0x98000004: // New 6.2" panel?
|
||||
case 0x50000001:
|
||||
case 0x50000002:
|
||||
strcat(txt_buf, "FST2 UNK");
|
||||
if (touch_panel)
|
||||
panel_ic_paired = touch_panel->idx == 0;
|
||||
break;
|
||||
// case 0x98000004: // New 6.2" panel?
|
||||
// case 0x50000001:
|
||||
// case 0x50000002:
|
||||
// strcat(txt_buf, "FST2 UNK");
|
||||
// if (touch_panel)
|
||||
// panel_ic_paired = touch_panel->idx == 0;
|
||||
// break;
|
||||
case 0x001A0300:
|
||||
case 0x32000102:
|
||||
strcat(txt_buf, "4CD60D/2");
|
||||
@@ -974,7 +1027,7 @@ static lv_res_t _create_window_fuses_info_status(lv_obj_t *btn)
|
||||
panel_ic_paired = touch_panel->idx == 4; // Samsung BH2109.
|
||||
break;
|
||||
default:
|
||||
strcat(txt_buf, "#FF8000 Unknown#");
|
||||
strcat(txt_buf, "#FF8000 Contact me#");
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -999,9 +1052,6 @@ static lv_res_t _create_window_fuses_info_status(lv_obj_t *btn)
|
||||
lv_obj_set_width(lb_desc2, lv_obj_get_width(desc2));
|
||||
lv_obj_align(desc2, val, LV_ALIGN_OUT_RIGHT_MID, LV_DPI / 4, 0);
|
||||
|
||||
if (!btn)
|
||||
_create_mbox_cal0(NULL);
|
||||
|
||||
return LV_RES_OK;
|
||||
}
|
||||
|
||||
@@ -1299,12 +1349,11 @@ static lv_res_t _create_mbox_benchmark(bool sd_bench)
|
||||
static const char * mbox_btn_map[] = { "\251", "\222OK", "\251", "" };
|
||||
lv_obj_t * mbox = lv_mbox_create(dark_bg, NULL);
|
||||
lv_mbox_set_recolor_text(mbox, true);
|
||||
lv_obj_set_width(mbox, LV_HOR_RES / 7 * 4);
|
||||
lv_obj_set_width(mbox, LV_HOR_RES * 3 / 7);
|
||||
|
||||
char *txt_buf = (char *)malloc(SZ_16K);
|
||||
|
||||
s_printf(txt_buf, "#FF8000 %s Benchmark#\n[Raw Reads] Abort: VOL- & VOL+",
|
||||
sd_bench ? "SD Card" : "eMMC");
|
||||
s_printf(txt_buf, "#FF8000 %s Benchmark#\n[Raw Reads] Abort: VOL- & VOL+", sd_bench ? "SD Card" : "eMMC");
|
||||
|
||||
lv_mbox_set_text(mbox, txt_buf);
|
||||
txt_buf[0] = 0;
|
||||
@@ -1353,30 +1402,60 @@ static lv_res_t _create_mbox_benchmark(bool sd_bench)
|
||||
goto out;
|
||||
}
|
||||
|
||||
// Set benchmark parameters.
|
||||
const u32 sct_blk_seq = 0x8000; // 16MB. A2 spec denotes 4MB, but using older big AU.
|
||||
const u32 sct_blk_4kb = 8; // 4KB.
|
||||
const u32 sct_rem_seq = 0x200000; // 1GB. A2 spec.
|
||||
const u32 sct_rem_4kb = 0x80000; // 256MB. A2 spec.
|
||||
const u32 sct_num_1mb = 0x800; // 1MB.
|
||||
const u32 size_bytes_seq = sct_rem_seq * SDMMC_DAT_BLOCKSIZE;
|
||||
const u32 size_bytes_4kb = sct_rem_4kb * SDMMC_DAT_BLOCKSIZE;
|
||||
|
||||
// Set calculation divider. 1000 or 1024. (Does not affect IOPS).
|
||||
u32 mb_div = 1000; // Unfortunately most software uses fake MB.
|
||||
|
||||
char *mbs_text;
|
||||
switch (mb_div)
|
||||
{
|
||||
case 1000:
|
||||
mbs_text = "MB/s";
|
||||
break;
|
||||
case 1024:
|
||||
mbs_text = "MiB/s";
|
||||
break;
|
||||
}
|
||||
|
||||
// Set actual div in MB/MiB.
|
||||
mb_div *= mb_div;
|
||||
|
||||
int error = 0;
|
||||
u32 iters = 3;
|
||||
u32 offset_chunk_start = ALIGN_DOWN(storage->sec_cnt / 3, 0x8000); // Align to 16MB.
|
||||
u32 offset_chunk_start = ALIGN_DOWN(storage->sec_cnt / 3, sct_blk_seq); // Align to block.
|
||||
if (storage->sec_cnt < 0xC00000)
|
||||
iters -= 2; // 4GB card.
|
||||
|
||||
u32 rnd_off_cnt = sct_rem_4kb / sct_blk_4kb;
|
||||
u32 *random_offsets = malloc(rnd_off_cnt * sizeof(u32));
|
||||
u32 *times_taken_4k = malloc(rnd_off_cnt * sizeof(u32));
|
||||
|
||||
for (u32 iter_curr = 0; iter_curr < iters; iter_curr++)
|
||||
{
|
||||
u32 pct = 0;
|
||||
u32 prevPct = 200;
|
||||
u32 timer = 0;
|
||||
u32 lba_curr = 0;
|
||||
u32 sector = offset_chunk_start * iter_curr;
|
||||
u32 sector_num = 0x8000; // 16MB chunks.
|
||||
u32 data_remaining = 0x200000; // 1GB.
|
||||
u32 sector_off = offset_chunk_start * iter_curr;
|
||||
u32 sector_num = sct_blk_seq;
|
||||
u32 data_remaining = sct_rem_seq;
|
||||
|
||||
s_printf(txt_buf + strlen(txt_buf), "#C7EA46 %d/3# - Sector Offset #C7EA46 %08X#:\n", iter_curr + 1, sector);
|
||||
s_printf(txt_buf + strlen(txt_buf), "#C7EA46 %d/3# - Sector Offset #C7EA46 %08X#:\n", iter_curr + 1, sector_off);
|
||||
|
||||
u32 render_min_ms = 66;
|
||||
u32 render_timer = get_tmr_ms() + render_min_ms;
|
||||
while (data_remaining)
|
||||
{
|
||||
u32 time_taken = get_tmr_us();
|
||||
error = !sdmmc_storage_read(storage, sector + lba_curr, sector_num, (u8 *)MIXD_BUF_ALIGNED);
|
||||
error = !sdmmc_storage_read(storage, sector_off + lba_curr, sector_num, (u8 *)MIXD_BUF_ALIGNED);
|
||||
time_taken = get_tmr_us() - time_taken;
|
||||
timer += time_taken;
|
||||
|
||||
@@ -1384,7 +1463,7 @@ static lv_res_t _create_mbox_benchmark(bool sd_bench)
|
||||
data_remaining -= sector_num;
|
||||
lba_curr += sector_num;
|
||||
|
||||
pct = (lba_curr * 100) / 0x200000;
|
||||
pct = (lba_curr * 100) / sct_rem_seq;
|
||||
if (pct != prevPct && render_timer < get_tmr_ms())
|
||||
{
|
||||
lv_bar_set_value(bar, pct);
|
||||
@@ -1402,10 +1481,10 @@ static lv_res_t _create_mbox_benchmark(bool sd_bench)
|
||||
}
|
||||
lv_bar_set_value(bar, 100);
|
||||
|
||||
u32 rate_1k = ((u64)1024 * 1000 * 1000 * 1000) / timer;
|
||||
s_printf(txt_buf + strlen(txt_buf),
|
||||
" Sequential 16MiB - Rate: #C7EA46 %3d.%02d MiB/s#\n",
|
||||
rate_1k / 1000, (rate_1k % 1000) / 10);
|
||||
// Calculate rate for transfer.
|
||||
u32 rate_1k = (u64)size_bytes_seq * 1000 * 1000 * 1000 / mb_div / timer;
|
||||
s_printf(txt_buf + strlen(txt_buf), " SEQ 16MB - Rate: #C7EA46 %3d.%02d %s#",
|
||||
rate_1k / 1000, (rate_1k % 1000) / 10, mbs_text);
|
||||
lv_label_set_text(lbl_status, txt_buf);
|
||||
lv_obj_align(lbl_status, NULL, LV_ALIGN_CENTER, 0, 0);
|
||||
lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);
|
||||
@@ -1415,22 +1494,25 @@ static lv_res_t _create_mbox_benchmark(bool sd_bench)
|
||||
prevPct = 200;
|
||||
timer = 0;
|
||||
lba_curr = 0;
|
||||
sector_num = 8; // 4KB chunks.
|
||||
data_remaining = 0x100000; // 512MB.
|
||||
sector_num = sct_blk_4kb;
|
||||
data_remaining = sct_rem_4kb;
|
||||
|
||||
u32 loop_idx = 0;
|
||||
render_timer = get_tmr_ms() + render_min_ms;
|
||||
while (data_remaining)
|
||||
{
|
||||
u32 time_taken = get_tmr_us();
|
||||
error = !sdmmc_storage_read(storage, sector + lba_curr, sector_num, (u8 *)MIXD_BUF_ALIGNED);
|
||||
error = !sdmmc_storage_read(storage, sector_off + lba_curr, sector_num, (u8 *)MIXD_BUF_ALIGNED);
|
||||
time_taken = get_tmr_us() - time_taken;
|
||||
|
||||
timer += time_taken;
|
||||
times_taken_4k[loop_idx++] = time_taken;
|
||||
|
||||
manual_system_maintenance(false);
|
||||
data_remaining -= sector_num;
|
||||
lba_curr += sector_num;
|
||||
|
||||
pct = (lba_curr * 100) / 0x100000;
|
||||
pct = (lba_curr * 100) / sct_rem_4kb;
|
||||
if (pct != prevPct && render_timer < get_tmr_ms())
|
||||
{
|
||||
lv_bar_set_value(bar, pct);
|
||||
@@ -1448,49 +1530,64 @@ static lv_res_t _create_mbox_benchmark(bool sd_bench)
|
||||
}
|
||||
lv_bar_set_value(bar, 100);
|
||||
|
||||
rate_1k = ((u64)512 * 1000 * 1000 * 1000) / timer;
|
||||
u32 iops_1k = ((u64)512 * 1024 * 1000 * 1000 * 1000) / (4096 / 1024) / timer / 1000;
|
||||
s_printf(txt_buf + strlen(txt_buf),
|
||||
" Sequential 4KiB - Rate: #C7EA46 %3d.%02d MiB/s#, IOPS: #C7EA46 %4d#\n",
|
||||
rate_1k / 1000, (rate_1k % 1000) / 10, iops_1k);
|
||||
qsort(times_taken_4k, loop_idx, sizeof(u32), qsort_compare_int); // Use int for faster compare. Value can't exceed 2s.
|
||||
|
||||
u32 pct95 = 0;
|
||||
for (u32 i = 0; i < loop_idx * 95 / 100; i++)
|
||||
pct95 += times_taken_4k[i];
|
||||
pct95 /= loop_idx * 95 / 100;
|
||||
|
||||
u32 pct05 = 0;
|
||||
for (u32 i = 0; i < loop_idx * 5 / 100; i++)
|
||||
pct05 += times_taken_4k[loop_idx - 1 - i];
|
||||
pct05 /= loop_idx * 5 / 100;
|
||||
|
||||
// Calculate rate and IOPS for transfer.
|
||||
rate_1k = (u64)size_bytes_4kb * 1000 * 1000 * 1000 / mb_div / timer;
|
||||
u32 iops = ((u64)(sct_rem_4kb / sct_num_1mb) * 1024 * 1000 * 1000 * 1000) / (4096 / 1024) / timer / 1000;
|
||||
s_printf(txt_buf + strlen(txt_buf), " AVG #C7EA46 95th# #FF3C28 5th#\n");
|
||||
s_printf(txt_buf + strlen(txt_buf), " SEQ 4KB - Rate: #C7EA46 %3d.%02d %s# IOPS: #C7EA46 %4d# %4d %4d \n",
|
||||
rate_1k / 1000, (rate_1k % 1000) / 10, mbs_text, iops, 1000000 / pct95, 1000000 / pct05);
|
||||
lv_label_set_text(lbl_status, txt_buf);
|
||||
lv_obj_align(lbl_status, NULL, LV_ALIGN_CENTER, 0, 0);
|
||||
lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);
|
||||
manual_system_maintenance(true);
|
||||
|
||||
u32 lba_idx = 0;
|
||||
u32 *random_offsets = malloc(0x20000 * sizeof(u32));
|
||||
u32 random_numbers[4];
|
||||
for (u32 i = 0; i < 0x20000; i += 4)
|
||||
u32 random_numbers[4];
|
||||
for (u32 i = 0; i < rnd_off_cnt; i += 4)
|
||||
{
|
||||
// Generate new random numbers.
|
||||
while (!se_gen_prng128(random_numbers))
|
||||
;
|
||||
// Clamp offsets to 512MB range.
|
||||
random_offsets[i + 0] = random_numbers[0] % 0x100000;
|
||||
random_offsets[i + 1] = random_numbers[1] % 0x100000;
|
||||
random_offsets[i + 2] = random_numbers[2] % 0x100000;
|
||||
random_offsets[i + 3] = random_numbers[3] % 0x100000;
|
||||
// Clamp offsets to 256MB range.
|
||||
random_offsets[i + 0] = random_numbers[0] % sct_rem_4kb;
|
||||
random_offsets[i + 1] = random_numbers[1] % sct_rem_4kb;
|
||||
random_offsets[i + 2] = random_numbers[2] % sct_rem_4kb;
|
||||
random_offsets[i + 3] = random_numbers[3] % sct_rem_4kb;
|
||||
}
|
||||
|
||||
pct = 0;
|
||||
prevPct = 200;
|
||||
timer = 0;
|
||||
data_remaining = 0x100000; // 512MB.
|
||||
data_remaining = sct_rem_4kb;
|
||||
|
||||
loop_idx = 0;
|
||||
render_timer = get_tmr_ms() + render_min_ms;
|
||||
while (data_remaining)
|
||||
{
|
||||
u32 time_taken = get_tmr_us();
|
||||
error = !sdmmc_storage_read(storage, sector + random_offsets[lba_idx], sector_num, (u8 *)MIXD_BUF_ALIGNED);
|
||||
error = !sdmmc_storage_read(storage, sector_off + random_offsets[lba_idx], sector_num, (u8 *)MIXD_BUF_ALIGNED);
|
||||
time_taken = get_tmr_us() - time_taken;
|
||||
|
||||
timer += time_taken;
|
||||
times_taken_4k[loop_idx++] = time_taken;
|
||||
|
||||
manual_system_maintenance(false);
|
||||
data_remaining -= sector_num;
|
||||
lba_idx++;
|
||||
|
||||
pct = (lba_idx * 100) / 0x20000;
|
||||
pct = (lba_idx * 100) / rnd_off_cnt;
|
||||
if (pct != prevPct && render_timer < get_tmr_ms())
|
||||
{
|
||||
lv_bar_set_value(bar, pct);
|
||||
@@ -1504,29 +1601,39 @@ static lv_res_t _create_mbox_benchmark(bool sd_bench)
|
||||
}
|
||||
|
||||
if (error)
|
||||
{
|
||||
free(random_offsets);
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
lv_bar_set_value(bar, 100);
|
||||
|
||||
// Calculate rate and IOPS for 512MB transfer.
|
||||
rate_1k = ((u64)512 * 1000 * 1000 * 1000) / timer;
|
||||
iops_1k = ((u64)512 * 1024 * 1000 * 1000 * 1000) / (4096 / 1024) / timer / 1000;
|
||||
s_printf(txt_buf + strlen(txt_buf),
|
||||
" Random 4KiB - Rate: #C7EA46 %3d.%02d MiB/s#, IOPS: #C7EA46 %4d#\n",
|
||||
rate_1k / 1000, (rate_1k % 1000) / 10, iops_1k);
|
||||
qsort(times_taken_4k, loop_idx, sizeof(u32), qsort_compare_int); // Use int for faster compare. Value can't exceed 2s.
|
||||
|
||||
pct95 = 0;
|
||||
for (u32 i = 0; i < loop_idx * 95 / 100; i++)
|
||||
pct95 += times_taken_4k[i];
|
||||
pct95 /= loop_idx * 95 / 100;
|
||||
|
||||
pct05 = 0;
|
||||
for (u32 i = 0; i < loop_idx * 5 / 100; i++)
|
||||
pct05 += times_taken_4k[loop_idx - 1 - i];
|
||||
pct05 /= loop_idx * 5 / 100;
|
||||
|
||||
// Calculate rate and IOPS for transfer.
|
||||
rate_1k = (u64)size_bytes_4kb * 1000 * 1000 * 1000 / mb_div / timer;
|
||||
iops = ((u64)(sct_rem_4kb / sct_num_1mb) * 1024 * 1000 * 1000 * 1000) / (4096 / 1024) / timer / 1000;
|
||||
s_printf(txt_buf + strlen(txt_buf), " RND 4KB - Rate: #C7EA46 %3d.%02d %s# IOPS: #C7EA46 %4d# %4d %4d \n",
|
||||
rate_1k / 1000, (rate_1k % 1000) / 10, mbs_text, iops, 1000000 / pct95, 1000000 / pct05);
|
||||
if (iter_curr == iters - 1)
|
||||
txt_buf[strlen(txt_buf) - 1] = 0; // Cut off last line change.
|
||||
txt_buf[strlen(txt_buf) - 1] = 0; // Cut off last new line.
|
||||
lv_label_set_text(lbl_status, txt_buf);
|
||||
lv_obj_align(lbl_status, NULL, LV_ALIGN_CENTER, 0, 0);
|
||||
lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);
|
||||
manual_system_maintenance(true);
|
||||
free(random_offsets);
|
||||
}
|
||||
|
||||
error:
|
||||
free(random_offsets);
|
||||
free(times_taken_4k);
|
||||
|
||||
if (error)
|
||||
{
|
||||
if (error == -1)
|
||||
@@ -1553,6 +1660,8 @@ error:
|
||||
emmc_end();
|
||||
|
||||
out:
|
||||
s_printf(txt_buf, "#FF8000 %s Benchmark#\n[Raw Reads]", sd_bench ? "SD Card" : "eMMC");
|
||||
lv_mbox_set_text(mbox, txt_buf);
|
||||
free(txt_buf);
|
||||
|
||||
lv_mbox_add_btns(mbox, mbox_btn_map, mbox_action); // Important. After set_text.
|
||||
@@ -1811,8 +1920,8 @@ out_error:
|
||||
lv_mbox_set_recolor_text(mbox, true);
|
||||
|
||||
s_printf(txt_buf,
|
||||
"#FF8000 eMMC Issues Check#\n\n"
|
||||
"#FFDD00 Your eMMC is initialized in slower mode,#\n"
|
||||
"#FF8000 eMMC Issues Warning#\n\n"
|
||||
"#FFDD00 Your eMMC is initialized in a slower mode,#\n"
|
||||
"#FFDD00 or init/read/write errors occurred!#\n"
|
||||
"#FFDD00 This might mean hardware issues!#\n\n"
|
||||
"#00DDFF Bus Speed:# %d MB/s\n\n"
|
||||
@@ -1844,7 +1953,7 @@ static lv_res_t _create_window_sdcard_info_status(lv_obj_t *btn)
|
||||
lv_win_add_btn(win, NULL, SYMBOL_SD" Benchmark", _create_mbox_sd_bench);
|
||||
|
||||
lv_obj_t *desc = lv_cont_create(win, NULL);
|
||||
lv_obj_set_size(desc, LV_HOR_RES / 2 / 5 * 2, LV_VER_RES - (LV_DPI * 11 / 8) * 5 / 2);
|
||||
lv_obj_set_size(desc, LV_HOR_RES / 2 / 6 * 2, LV_VER_RES - (LV_DPI * 11 / 8) * 5 / 2);
|
||||
|
||||
lv_obj_t * lb_desc = lv_label_create(desc, NULL);
|
||||
lv_label_set_long_mode(lb_desc, LV_LABEL_LONG_BREAK);
|
||||
@@ -1865,7 +1974,7 @@ static lv_res_t _create_window_sdcard_info_status(lv_obj_t *btn)
|
||||
}
|
||||
|
||||
lv_label_set_text(lb_desc,
|
||||
"#00DDFF Card IDentification:#\n"
|
||||
"#00DDFF Card ID:#\n"
|
||||
"Vendor ID:\n"
|
||||
"Model:\n"
|
||||
"OEM ID:\n"
|
||||
@@ -1874,11 +1983,11 @@ static lv_res_t _create_window_sdcard_info_status(lv_obj_t *btn)
|
||||
"S/N:\n"
|
||||
"Month/Year:\n\n"
|
||||
"Max Power:\n"
|
||||
"Bootloader bus:"
|
||||
"Initial bus:"
|
||||
);
|
||||
|
||||
lv_obj_t *val = lv_cont_create(win, NULL);
|
||||
lv_obj_set_size(val, LV_HOR_RES / 9 * 2, LV_VER_RES - (LV_DPI * 11 / 8) * 5 / 2);
|
||||
lv_obj_set_size(val, LV_HOR_RES / 12 * 3, LV_VER_RES - (LV_DPI * 11 / 8) * 5 / 2);
|
||||
|
||||
lv_obj_t * lb_val = lv_label_create(val, lb_desc);
|
||||
|
||||
@@ -1985,7 +2094,7 @@ static lv_res_t _create_window_sdcard_info_status(lv_obj_t *btn)
|
||||
}
|
||||
|
||||
// UHS-I max power limit is 400mA, no matter what the card says.
|
||||
u32 card_power_limit_nominal = sd_storage.card_power_limit > 400 ? 400 : sd_storage.card_power_limit;
|
||||
u32 max_power_nominal = sd_storage.max_power > 400 ? 400 : sd_storage.max_power;
|
||||
|
||||
s_printf(txt_buf + strlen(txt_buf), "(%02X)\n%c%c%c%c%c\n%c%c (%04X)\n%X\n%X\n%08x\n%02d/%04d\n\n%d mW (%d mA)\n",
|
||||
sd_storage.cid.manfid,
|
||||
@@ -1994,7 +2103,7 @@ static lv_res_t _create_window_sdcard_info_status(lv_obj_t *btn)
|
||||
(sd_storage.cid.oemid >> 8) & 0xFF, sd_storage.cid.oemid & 0xFF, sd_storage.cid.oemid,
|
||||
sd_storage.cid.hwrev, sd_storage.cid.fwrev, sd_storage.cid.serial,
|
||||
sd_storage.cid.month, sd_storage.cid.year,
|
||||
card_power_limit_nominal * 3600 / 1000, sd_storage.card_power_limit);
|
||||
max_power_nominal * 3600 / 1000, sd_storage.max_power);
|
||||
|
||||
switch (nyx_str->info.sd_init)
|
||||
{
|
||||
@@ -2020,7 +2129,7 @@ static lv_res_t _create_window_sdcard_info_status(lv_obj_t *btn)
|
||||
lv_obj_align(val, desc, LV_ALIGN_OUT_RIGHT_MID, 0, 0);
|
||||
|
||||
lv_obj_t *desc2 = lv_cont_create(win, NULL);
|
||||
lv_obj_set_size(desc2, LV_HOR_RES / 2 / 4 * 2, LV_VER_RES - (LV_DPI * 11 / 8) * 5 / 2);
|
||||
lv_obj_set_size(desc2, LV_HOR_RES / 2 / 11 * 5, LV_VER_RES - (LV_DPI * 11 / 8) * 5 / 2);
|
||||
|
||||
lv_obj_t * lb_desc2 = lv_label_create(desc2, lb_desc);
|
||||
|
||||
@@ -2037,10 +2146,10 @@ static lv_res_t _create_window_sdcard_info_status(lv_obj_t *btn)
|
||||
"Write Protect:"
|
||||
);
|
||||
lv_obj_set_width(lb_desc2, lv_obj_get_width(desc2));
|
||||
lv_obj_align(desc2, val, LV_ALIGN_OUT_RIGHT_MID, LV_DPI / 2, 0);
|
||||
lv_obj_align(desc2, val, LV_ALIGN_OUT_RIGHT_MID, LV_DPI / 5 * 3, 0);
|
||||
|
||||
lv_obj_t *val2 = lv_cont_create(win, NULL);
|
||||
lv_obj_set_size(val2, LV_HOR_RES / 13 * 3, LV_VER_RES - (LV_DPI * 11 / 8) * 5 / 2);
|
||||
lv_obj_set_size(val2, LV_HOR_RES / 4, LV_VER_RES - (LV_DPI * 11 / 8) * 5 / 2);
|
||||
|
||||
lv_obj_t * lb_val2 = lv_label_create(val2, lb_desc);
|
||||
|
||||
@@ -2084,15 +2193,64 @@ static lv_res_t _create_window_sdcard_info_status(lv_obj_t *btn)
|
||||
else
|
||||
bus_speed = "SDR12";
|
||||
|
||||
char *cpe = NULL;
|
||||
if (sd_storage.ssr.app_class == 2)
|
||||
{
|
||||
u8 *buf = zalloc(512);
|
||||
|
||||
// Directly get and parse ext reg for performance enhance.
|
||||
sd_storage_parse_perf_enhance(&sd_storage, 2, 0, 0, buf);
|
||||
|
||||
bool has_perf_enhance = sd_storage.ser.cache &&
|
||||
sd_storage.ser.cmdq &&
|
||||
sd_storage.ser.cache == sd_storage.ser.cache_ext &&
|
||||
sd_storage.ser.cmdq == sd_storage.ser.cmdq_ext;
|
||||
if (has_perf_enhance)
|
||||
cpe = "#FFDD00 "; // CMDQ/CACHE support via a quirk.
|
||||
else
|
||||
cpe = "#FF3C28 "; // Broken.
|
||||
|
||||
// Get and parse ext reg for performance enhance in spec.
|
||||
sd_storage_get_ext_regs(&sd_storage, buf);
|
||||
|
||||
if (sd_storage.ser.valid)
|
||||
{
|
||||
has_perf_enhance = sd_storage.ser.cache &&
|
||||
sd_storage.ser.cmdq &&
|
||||
sd_storage.ser.cache == sd_storage.ser.cache_ext &&
|
||||
sd_storage.ser.cmdq == sd_storage.ser.cmdq_ext;
|
||||
|
||||
if (has_perf_enhance)
|
||||
cpe = NULL; // CMDQ/CACHE support in spec.
|
||||
else
|
||||
cpe = "#FF3C28 "; // Broken.
|
||||
}
|
||||
|
||||
free(buf);
|
||||
}
|
||||
|
||||
s_printf(txt_buf,
|
||||
"#00DDFF v%d.0#\n%02X\n%d MiB\n%X (CP %X)\n%d\n%d MB/s (%d MHz)\n%d (AU: %d %s\nU%d V%d A%d\n%s\n\n%s",
|
||||
sd_storage.csd.structure + 1, sd_storage.csd.cmdclass,
|
||||
sd_storage.sec_cnt >> 11, sd_storage.sec_cnt, sd_storage.ssr.protected_size >> 9,
|
||||
sd_storage.ssr.bus_width, sd_storage.csd.busspeed,
|
||||
"#00DDFF v%d.0#\n"
|
||||
"%02X\n"
|
||||
"%d MiB\n"
|
||||
"%X (CP %X)\n"
|
||||
"%d\n"
|
||||
"%d MB/s (%d MHz)\n"
|
||||
"%d (AU: %d %s\n"
|
||||
"U%d V%d %sA%d%s\n"
|
||||
"%s\n\n"
|
||||
"%s",
|
||||
sd_storage.csd.structure + 1,
|
||||
sd_storage.csd.cmdclass,
|
||||
sd_storage.sec_cnt >> 11,
|
||||
sd_storage.sec_cnt, sd_storage.ssr.protected_size >> 9,
|
||||
sd_storage.ssr.bus_width,
|
||||
sd_storage.csd.busspeed,
|
||||
(sd_storage.csd.busspeed > 10) ? (sd_storage.csd.busspeed * 2) : 50,
|
||||
sd_storage.ssr.speed_class, uhs_au_size, uhs_au_mb ? "MiB)" : "KiB)",
|
||||
sd_storage.ssr.uhs_grade, sd_storage.ssr.video_class, sd_storage.ssr.app_class,
|
||||
bus_speed, wp_info);
|
||||
sd_storage.ssr.uhs_grade, sd_storage.ssr.video_class, cpe ? cpe : "", sd_storage.ssr.app_class, cpe ? "#" : "",
|
||||
bus_speed,
|
||||
wp_info);
|
||||
|
||||
lv_label_set_text(lb_val2, txt_buf);
|
||||
|
||||
@@ -2109,47 +2267,29 @@ static lv_res_t _create_window_sdcard_info_status(lv_obj_t *btn)
|
||||
lv_obj_set_size(desc3, LV_HOR_RES / 2 / 2 * 2, LV_VER_RES - (LV_DPI * 11 / 8) * 4);
|
||||
|
||||
lv_obj_t * lb_desc3 = lv_label_create(desc3, lb_desc);
|
||||
lv_label_set_text(lb_desc3, "#D4FF00 Acquiring FAT volume info...#");
|
||||
lv_label_set_text(lb_desc3, "#D4FF00 Acquiring info...#");
|
||||
lv_obj_set_width(lb_desc3, lv_obj_get_width(desc3));
|
||||
|
||||
lv_obj_align(desc3, desc, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 2);
|
||||
|
||||
manual_system_maintenance(true);
|
||||
|
||||
f_getfree("", &sd_fs.free_clst, NULL);
|
||||
|
||||
lv_label_set_text(lb_desc3,
|
||||
"#00DDFF Found FAT volume:#\n"
|
||||
"Filesystem:\n"
|
||||
"Cluster:\n"
|
||||
"Size free/total:"
|
||||
);
|
||||
lv_obj_set_size(desc3, LV_HOR_RES / 2 / 5 * 2, LV_VER_RES - (LV_DPI * 11 / 8) * 4);
|
||||
lv_obj_set_width(lb_desc3, lv_obj_get_width(desc3));
|
||||
lv_obj_set_size(desc3, LV_HOR_RES / 2 / 6 * 2, LV_VER_RES - (LV_DPI * 11 / 8) * 4);
|
||||
lv_obj_align(desc3, desc, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 2);
|
||||
|
||||
lv_obj_t *val3 = lv_cont_create(win, NULL);
|
||||
lv_obj_set_size(val3, LV_HOR_RES / 13 * 3, LV_VER_RES - (LV_DPI * 11 / 8) * 4);
|
||||
lv_obj_set_size(val3, LV_HOR_RES / 12 * 3, LV_VER_RES - (LV_DPI * 11 / 8) * 4);
|
||||
|
||||
lv_obj_t * lb_val3 = lv_label_create(val3, lb_desc);
|
||||
lv_label_set_text(lb_val3, "");
|
||||
|
||||
s_printf(txt_buf, "\n%s\n%d %s\n%d/%d MiB",
|
||||
sd_fs.fs_type == FS_EXFAT ? ("exFAT "SYMBOL_SHRK) : ("FAT32"),
|
||||
(sd_fs.csize > 1) ? (sd_fs.csize >> 1) : SD_BLOCKSIZE,
|
||||
(sd_fs.csize > 1) ? "KiB" : "B",
|
||||
(u32)(sd_fs.free_clst * sd_fs.csize >> SECTORS_TO_MIB_COEFF),
|
||||
(u32)(sd_fs.n_fatent * sd_fs.csize >> SECTORS_TO_MIB_COEFF));
|
||||
|
||||
lv_label_set_text(lb_val3, txt_buf);
|
||||
|
||||
lv_obj_set_width(lb_val3, lv_obj_get_width(val3));
|
||||
lv_obj_align(val3, desc3, LV_ALIGN_OUT_RIGHT_MID, 0, 0);
|
||||
|
||||
lv_obj_t *desc4 = lv_cont_create(win, NULL);
|
||||
lv_obj_set_size(desc4, LV_HOR_RES / 2 / 2 * 2, LV_VER_RES - (LV_DPI * 11 / 8) * 4);
|
||||
|
||||
lv_obj_t * lb_desc4 = lv_label_create(desc4, lb_desc);
|
||||
lv_label_set_text(lb_desc4, "#D4FF00 Acquiring FAT volume info...#");
|
||||
lv_label_set_text(lb_desc4, " ");
|
||||
lv_obj_set_width(lb_desc4, lv_obj_get_width(desc4));
|
||||
|
||||
lv_label_set_text(lb_desc4,
|
||||
@@ -2158,12 +2298,12 @@ static lv_res_t _create_window_sdcard_info_status(lv_obj_t *btn)
|
||||
"Read/Write fails:\n"
|
||||
"Read/Write errors:"
|
||||
);
|
||||
lv_obj_set_size(desc4, LV_HOR_RES / 2 / 5 * 2, LV_VER_RES - (LV_DPI * 11 / 8) * 4);
|
||||
lv_obj_set_size(desc4, LV_HOR_RES / 2 / 11 * 5, LV_VER_RES - (LV_DPI * 11 / 8) * 4);
|
||||
lv_obj_set_width(lb_desc4, lv_obj_get_width(desc4));
|
||||
lv_obj_align(desc4, val3, LV_ALIGN_OUT_RIGHT_MID, LV_DPI / 2, 0);
|
||||
lv_obj_align(desc4, val3, LV_ALIGN_OUT_RIGHT_MID, LV_DPI / 5 * 3, 0);
|
||||
|
||||
lv_obj_t *val4 = lv_cont_create(win, NULL);
|
||||
lv_obj_set_size(val4, LV_HOR_RES / 13 * 3, LV_VER_RES - (LV_DPI * 11 / 8) * 4);
|
||||
lv_obj_set_size(val4, LV_HOR_RES / 4, LV_VER_RES - (LV_DPI * 11 / 8) * 4);
|
||||
|
||||
lv_obj_t * lb_val4 = lv_label_create(val4, lb_desc);
|
||||
|
||||
@@ -2176,7 +2316,31 @@ static lv_res_t _create_window_sdcard_info_status(lv_obj_t *btn)
|
||||
lv_label_set_text(lb_val4, txt_buf);
|
||||
|
||||
lv_obj_set_width(lb_val4, lv_obj_get_width(val4));
|
||||
lv_obj_align(val4, desc4, LV_ALIGN_OUT_RIGHT_MID, LV_DPI / 2, 0);
|
||||
lv_obj_align(val4, desc4, LV_ALIGN_OUT_RIGHT_MID, 0, 0);
|
||||
|
||||
manual_system_maintenance(true);
|
||||
|
||||
f_getfree("", &sd_fs.free_clst, NULL);
|
||||
|
||||
lv_label_set_text(lb_desc3,
|
||||
"#00DDFF Found FAT FS:#\n"
|
||||
"Filesystem:\n"
|
||||
"Cluster:\n"
|
||||
"Size free/total:"
|
||||
);
|
||||
|
||||
lv_obj_set_width(lb_desc3, lv_obj_get_width(desc3));
|
||||
|
||||
s_printf(txt_buf, "\n%s\n%d %s\n%d/%d MiB",
|
||||
sd_fs.fs_type == FS_EXFAT ? ("exFAT "SYMBOL_SHRK) : ("FAT32"),
|
||||
(sd_fs.csize > 1) ? (sd_fs.csize >> 1) : SD_BLOCKSIZE,
|
||||
(sd_fs.csize > 1) ? "KiB" : "B",
|
||||
(u32)(sd_fs.free_clst * sd_fs.csize >> SECTORS_TO_MIB_COEFF),
|
||||
(u32)(sd_fs.n_fatent * sd_fs.csize >> SECTORS_TO_MIB_COEFF));
|
||||
|
||||
lv_label_set_text(lb_val3, txt_buf);
|
||||
|
||||
lv_obj_set_width(lb_val3, lv_obj_get_width(val3));
|
||||
|
||||
free(txt_buf);
|
||||
sd_unmount();
|
||||
@@ -2432,7 +2596,7 @@ static bool _lockpick_exists_check()
|
||||
|
||||
bool found = false;
|
||||
void *buf = malloc(0x200);
|
||||
if (sd_mount())
|
||||
if (boot_storage_mount())
|
||||
{
|
||||
FIL fp;
|
||||
if (f_open(&fp, "bootloader/payloads/Lockpick_RCM.bin", FA_READ))
|
||||
@@ -2457,7 +2621,7 @@ static bool _lockpick_exists_check()
|
||||
|
||||
out:
|
||||
free(buf);
|
||||
sd_unmount();
|
||||
boot_storage_unmount();
|
||||
|
||||
return found;
|
||||
}
|
||||
@@ -2551,7 +2715,7 @@ void create_tab_info(lv_theme_t *th, lv_obj_t *parent)
|
||||
lv_btn_set_fit(btn3, true, true);
|
||||
lv_label_set_static_text(label_btn, SYMBOL_CIRCUIT" HW & Fuses");
|
||||
lv_obj_align(btn3, line_sep, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI / 4, LV_DPI / 2);
|
||||
lv_btn_set_action(btn3, LV_BTN_ACTION_CLICK, _create_window_fuses_info_status);
|
||||
lv_btn_set_action(btn3, LV_BTN_ACTION_CLICK, _create_window_hw_info_status);
|
||||
|
||||
// Create KFuses button.
|
||||
lv_obj_t *btn4 = lv_btn_create(h1, btn);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2024 CTCaer
|
||||
* Copyright (c) 2018-2025 CTCaer
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
@@ -23,10 +23,11 @@
|
||||
#include "../config.h"
|
||||
#include <libs/lvgl/lv_themes/lv_theme_hekate.h>
|
||||
#include <libs/lvgl/lvgl.h>
|
||||
#include <storage/boot_storage.h>
|
||||
|
||||
#define CLOCK_MIN_YEAR 2024
|
||||
#define CLOCK_MIN_YEAR 2025
|
||||
#define CLOCK_MAX_YEAR (CLOCK_MIN_YEAR + 10)
|
||||
#define CLOCK_YEARLIST "2024\n2025\n2026\n2027\n2028\n2029\n2030\n2031\n2032\n2033\n2034"
|
||||
#define CLOCK_YEARLIST "2025\n2026\n2027\n2028\n2029\n2030\n2031\n2032\n2033\n2034\n2035"
|
||||
|
||||
extern hekate_config h_cfg;
|
||||
extern nyx_config n_cfg;
|
||||
@@ -227,7 +228,7 @@ static void _create_autoboot_window()
|
||||
lv_obj_set_size(list_main, LV_HOR_RES * 4 / 10, LV_VER_RES * 4 / 7);
|
||||
lv_list_set_single_mode(list_main, true);
|
||||
|
||||
sd_mount();
|
||||
boot_storage_mount();
|
||||
|
||||
// Parse hekate main configuration.
|
||||
LIST_INIT(ini_sections);
|
||||
@@ -288,7 +289,7 @@ static void _create_autoboot_window()
|
||||
ini_free(&ini_list_sections);
|
||||
}
|
||||
|
||||
sd_unmount();
|
||||
boot_storage_unmount();
|
||||
}
|
||||
|
||||
static lv_res_t _autoboot_hide_delay_action(lv_obj_t *btn)
|
||||
@@ -882,7 +883,7 @@ static lv_res_t _joycon_info_dump_action(lv_obj_t * btn)
|
||||
jc_pad->bt_conn_r.type = is_r_hos ? jc_pad->bt_conn_r.type : 0;
|
||||
|
||||
save_data:
|
||||
error = !sd_mount() ? 5 : 0;
|
||||
error = !boot_storage_mount() ? 5 : 0;
|
||||
|
||||
if (!error)
|
||||
{
|
||||
@@ -896,7 +897,8 @@ save_data:
|
||||
memcpy(data, &jc_pad->bt_conn_l, sizeof(jc_bt_conn_t));
|
||||
memcpy(data + sizeof(jc_bt_conn_t), &jc_pad->bt_conn_r, sizeof(jc_bt_conn_t));
|
||||
|
||||
error = sd_save_to_file((u8 *)data, sizeof(jc_bt_conn_t) * 2, "switchroot/joycon_mac.bin") ? 4 : 0;
|
||||
// TODO: JC dump should probably go to sd?
|
||||
error = boot_storage_save_to_file((u8 *)data, sizeof(jc_bt_conn_t) * 2, "switchroot/joycon_mac.bin") ? 4 : 0;
|
||||
|
||||
// Save readable dump.
|
||||
jc_bt_conn_t *bt = &jc_pad->bt_conn_l;
|
||||
@@ -1024,7 +1026,7 @@ save_data:
|
||||
}
|
||||
}
|
||||
|
||||
sd_unmount();
|
||||
boot_storage_unmount();
|
||||
}
|
||||
|
||||
disabled_or_cal0_issue:;
|
||||
@@ -1168,13 +1170,11 @@ static lv_res_t _action_win_nyx_options_close(lv_obj_t *btn)
|
||||
lv_obj_set_opa_scale(status_bar.mid, LV_OPA_0);
|
||||
lv_obj_set_click(status_bar.mid, false);
|
||||
|
||||
lv_win_close_action(btn);
|
||||
|
||||
close_btn = NULL;
|
||||
lv_res_t res = nyx_win_close_action_custom(btn);
|
||||
|
||||
_check_nyx_changes();
|
||||
|
||||
return LV_RES_INV;
|
||||
return res;
|
||||
}
|
||||
|
||||
lv_res_t create_win_nyx_options(lv_obj_t *parrent_btn)
|
||||
|
||||
@@ -15,10 +15,16 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <fatfs_cfg.h>
|
||||
#include <libs/lvgl/lv_core/lv_obj.h>
|
||||
#include <libs/lvgl/lv_objx/lv_btn.h>
|
||||
#include <libs/lvgl/lv_objx/lv_btnm.h>
|
||||
#include <libs/lvgl/lv_objx/lv_label.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <bdk.h>
|
||||
|
||||
#include "../frontend/fe_emusd_tools.h"
|
||||
#include "gui.h"
|
||||
#include "gui_tools.h"
|
||||
#include "gui_tools_partition_manager.h"
|
||||
@@ -29,6 +35,16 @@
|
||||
#include "../hos/pkg2.h"
|
||||
#include "../hos/hos.h"
|
||||
#include <libs/fatfs/ff.h>
|
||||
#include <storage/boot_storage.h>
|
||||
#include <storage/emmc.h>
|
||||
#include <storage/emummc_file_based.h>
|
||||
#include <storage/file_based_storage.h>
|
||||
#include <storage/mbr_gpt.h>
|
||||
#include <storage/sd.h>
|
||||
#include <storage/sdmmc.h>
|
||||
#include <string.h>
|
||||
#include <usb/usbd.h>
|
||||
#include <utils/types.h>
|
||||
|
||||
extern volatile boot_cfg_t *b_cfg;
|
||||
extern hekate_config h_cfg;
|
||||
@@ -218,7 +234,7 @@ static lv_res_t _create_mbox_hid(usb_ctxt_t *usbs)
|
||||
return LV_RES_OK;
|
||||
}
|
||||
|
||||
static lv_res_t _create_mbox_ums(usb_ctxt_t *usbs)
|
||||
static lv_res_t _create_mbox_ums(usb_ctxt_t *usbs, u32 part)
|
||||
{
|
||||
lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL);
|
||||
lv_obj_set_style(dark_bg, &mbox_darken);
|
||||
@@ -233,38 +249,41 @@ static lv_res_t _create_mbox_ums(usb_ctxt_t *usbs)
|
||||
|
||||
s_printf(txt_buf, "#FF8000 USB Mass Storage#\n\n#C7EA46 Device:# ");
|
||||
|
||||
if (usbs->type == MMC_SD)
|
||||
{
|
||||
switch (usbs->partition)
|
||||
{
|
||||
case 0:
|
||||
strcat(txt_buf, "SD Card");
|
||||
break;
|
||||
case EMMC_GPP + 1:
|
||||
strcat(txt_buf, "emuMMC GPP");
|
||||
break;
|
||||
case EMMC_BOOT0 + 1:
|
||||
strcat(txt_buf, "emuMMC BOOT0");
|
||||
break;
|
||||
case EMMC_BOOT1 + 1:
|
||||
strcat(txt_buf, "emuMMC BOOT1");
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (usbs->partition)
|
||||
{
|
||||
case EMMC_GPP + 1:
|
||||
strcat(txt_buf, "eMMC GPP");
|
||||
break;
|
||||
case EMMC_BOOT0 + 1:
|
||||
switch(part){
|
||||
case NYX_UMS_EMMC_BOOT0:
|
||||
strcat(txt_buf, "eMMC BOOT0");
|
||||
break;
|
||||
case EMMC_BOOT1 + 1:
|
||||
case NYX_UMS_EMMC_BOOT1:
|
||||
strcat(txt_buf, "eMMC BOOT1");
|
||||
break;
|
||||
}
|
||||
case NYX_UMS_EMMC_GPP:
|
||||
strcat(txt_buf, "eMMC GPP");
|
||||
break;
|
||||
case NYX_UMS_EMUMMC_GPP:
|
||||
strcat(txt_buf, "emuMMC GPP");
|
||||
break;
|
||||
case NYX_UMS_EMUMMC_BOOT0:
|
||||
strcat(txt_buf, "emuMMC BOOT0");
|
||||
break;
|
||||
case NYX_UMS_EMUMMC_BOOT1:
|
||||
strcat(txt_buf, "emuMMC BOOT1");
|
||||
break;
|
||||
case NYX_UMS_SD_CARD:
|
||||
strcat(txt_buf, "SD Card");
|
||||
break;
|
||||
case NYX_UMS_BOOT_STRG_GPP:
|
||||
strcat(txt_buf, "Boot drive (eMMC GPP)");
|
||||
break;
|
||||
case NYX_UMS_BOOT_STRG_BOOT1:
|
||||
case NYX_UMS_BOOT_STRG_BOOT1_1MB:
|
||||
strcat(txt_buf, "Boot drive (eMMC BOOT1)");
|
||||
break;
|
||||
case NYX_UMS_BOOT_STRG_SD:
|
||||
strcat(txt_buf, "Boot drive (SD Card)");
|
||||
break;
|
||||
case NYX_UMS_EMUSD:
|
||||
strcat(txt_buf, "emuSD");
|
||||
break;
|
||||
}
|
||||
|
||||
lv_mbox_set_text(mbox, txt_buf);
|
||||
@@ -326,6 +345,13 @@ static lv_res_t _create_mbox_ums_error(int error)
|
||||
lv_obj_set_style(dark_bg, &mbox_darken);
|
||||
lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES);
|
||||
|
||||
|
||||
// 1: boot storage fail
|
||||
// 2: no emu active
|
||||
// 3: emmc fail
|
||||
// 4: sd fail
|
||||
// 5: file based
|
||||
|
||||
static const char *mbox_btn_map[] = { "\251", "\222OK", "\251", "" };
|
||||
lv_obj_t * mbox = lv_mbox_create(dark_bg, NULL);
|
||||
lv_mbox_set_recolor_text(mbox, true);
|
||||
@@ -333,14 +359,35 @@ static lv_res_t _create_mbox_ums_error(int error)
|
||||
switch (error)
|
||||
{
|
||||
case 1:
|
||||
lv_mbox_set_text(mbox, "#FF8000 USB Mass Storage#\n\n#FFFF00 Error mounting SD Card!#");
|
||||
lv_mbox_set_text(mbox, "#FF8000 USB Mass Storage#\n\n#FFFF00 Error mounting boot drive!#");
|
||||
break;
|
||||
case 2:
|
||||
lv_mbox_set_text(mbox, "#FF8000 USB Mass Storage#\n\n#FFFF00 No emuMMC found active!#");
|
||||
break;
|
||||
case 3:
|
||||
lv_mbox_set_text(mbox, "#FF8000 USB Mass Storage#\n\n#FFFF00 Failed to initialize eMMC!#");
|
||||
break;
|
||||
case 4:
|
||||
lv_mbox_set_text(mbox, "#FF8000 USB Mass Storage#\n\n#FFFF00 Failed to initialize SD Card!#");
|
||||
break;
|
||||
case 5:
|
||||
lv_mbox_set_text(mbox, "#FF8000 USB Mass Storage#\n\n#FFFF00 Active emuMMC is not partition based!#");
|
||||
break;
|
||||
case 6:
|
||||
lv_mbox_set_text(mbox, "#FF8000 USB Mass Storage#\n\n#FFFF00 Corrupt emuMMC partition!#");
|
||||
break;
|
||||
case 7:
|
||||
lv_mbox_set_text(mbox, "#FF8000 USB Mass Storage#\n\n#FFFF00 No emuSD found active!#");
|
||||
break;
|
||||
case 8:
|
||||
lv_mbox_set_text(mbox, "#FF8000 USB Mass Storage#\n\n#FFFF00 Failed to initialize file based emuMMC!#");
|
||||
break;
|
||||
case 9:
|
||||
lv_mbox_set_text(mbox, "#FF8000 USB Mass Storage#\n\n#FFFF00 Failed to initialize file based emuSD!#");
|
||||
break;
|
||||
case 10:
|
||||
lv_mbox_set_text(mbox, "#FF8000 USB Mass Storage#\n\n#FFFF00 No emuSD found active!#");
|
||||
break;
|
||||
}
|
||||
|
||||
lv_mbox_add_btns(mbox, mbox_btn_map, mbox_action);
|
||||
@@ -417,216 +464,378 @@ lv_res_t action_ums_sd(lv_obj_t *btn)
|
||||
usbs.system_maintenance = &manual_system_maintenance;
|
||||
usbs.set_text = &usb_gadget_set_text;
|
||||
|
||||
_create_mbox_ums(&usbs);
|
||||
_create_mbox_ums(&usbs, NYX_UMS_SD_CARD);
|
||||
|
||||
return LV_RES_OK;
|
||||
}
|
||||
|
||||
static lv_res_t _action_ums_boot_storage(lv_obj_t *btn){
|
||||
if(!nyx_emmc_check_battery_enough()){
|
||||
return LV_RES_OK;
|
||||
}
|
||||
|
||||
boot_storage_mount();
|
||||
|
||||
u8 drive = boot_storage_get_drive();
|
||||
|
||||
u32 part;
|
||||
|
||||
usb_ctxt_t usbs;
|
||||
usbs.type = drive == DRIVE_SD ? MMC_SD : MMC_EMMC;
|
||||
switch(drive){
|
||||
case DRIVE_EMMC:
|
||||
part = NYX_UMS_BOOT_STRG_GPP;
|
||||
usbs.partition = EMMC_GPP + 1;
|
||||
break;
|
||||
case DRIVE_BOOT1:
|
||||
part = NYX_UMS_BOOT_STRG_BOOT1;
|
||||
usbs.partition = EMMC_BOOT1 + 1;
|
||||
break;
|
||||
case DRIVE_BOOT1_1MB:
|
||||
part = NYX_UMS_BOOT_STRG_BOOT1_1MB;
|
||||
usbs.partition = EMMC_BOOT1 + 1;
|
||||
break;
|
||||
case DRIVE_SD:
|
||||
part = NYX_UMS_BOOT_STRG_SD;
|
||||
usbs.partition = 0;
|
||||
break;
|
||||
default:
|
||||
boot_storage_unmount();
|
||||
return LV_RES_OK;
|
||||
}
|
||||
|
||||
usbs.offset = drive == DRIVE_BOOT1_1MB ? (0x100000 / 0x200) : 0;
|
||||
usbs.sectors = 0;
|
||||
usbs.ro = false;
|
||||
usbs.system_maintenance = &manual_system_maintenance;
|
||||
usbs.set_text = &usb_gadget_set_text;
|
||||
|
||||
_create_mbox_ums(&usbs, part);
|
||||
|
||||
boot_storage_unmount();
|
||||
|
||||
return LV_RES_OK;
|
||||
}
|
||||
|
||||
static lv_res_t _ums_emmc(u32 part){
|
||||
if (!nyx_emmc_check_battery_enough())
|
||||
return LV_RES_OK;
|
||||
|
||||
usb_ctxt_t usbs;
|
||||
usbs.type = MMC_EMMC;
|
||||
|
||||
switch(part){
|
||||
case NYX_UMS_EMMC_BOOT0:
|
||||
usbs.partition = EMMC_BOOT0 + 1;
|
||||
break;
|
||||
case NYX_UMS_EMMC_BOOT1:
|
||||
usbs.partition = EMMC_BOOT1 + 1;
|
||||
break;
|
||||
case NYX_UMS_EMMC_GPP:
|
||||
usbs.partition = EMMC_GPP + 1;
|
||||
break;
|
||||
}
|
||||
|
||||
usbs.offset = 0;
|
||||
usbs.sectors = 0;
|
||||
usbs.ro = usb_msc_emmc_read_only;
|
||||
usbs.system_maintenance = &manual_system_maintenance;
|
||||
usbs.set_text = &usb_gadget_set_text;
|
||||
|
||||
return _create_mbox_ums(&usbs, part);
|
||||
}
|
||||
|
||||
static lv_res_t _action_ums_emmc_boot0(lv_obj_t *btn)
|
||||
{
|
||||
if (!nyx_emmc_check_battery_enough())
|
||||
return LV_RES_OK;
|
||||
|
||||
usb_ctxt_t usbs;
|
||||
usbs.type = MMC_EMMC;
|
||||
usbs.partition = EMMC_BOOT0 + 1;
|
||||
usbs.offset = 0;
|
||||
usbs.sectors = 0;
|
||||
usbs.ro = usb_msc_emmc_read_only;
|
||||
usbs.system_maintenance = &manual_system_maintenance;
|
||||
usbs.set_text = &usb_gadget_set_text;
|
||||
|
||||
_create_mbox_ums(&usbs);
|
||||
|
||||
return LV_RES_OK;
|
||||
return _ums_emmc(NYX_UMS_EMMC_BOOT0);
|
||||
}
|
||||
|
||||
static lv_res_t _action_ums_emmc_boot1(lv_obj_t *btn)
|
||||
{
|
||||
if (!nyx_emmc_check_battery_enough())
|
||||
return _ums_emmc(NYX_UMS_EMMC_BOOT1);
|
||||
}
|
||||
|
||||
lv_res_t action_ums_emmc_gpp(lv_obj_t *btn)
|
||||
{
|
||||
return _ums_emmc(NYX_UMS_EMMC_GPP);
|
||||
}
|
||||
|
||||
static lv_res_t _action_ums_emusd(lv_obj_t * btn){
|
||||
if(!nyx_emmc_check_battery_enough()){
|
||||
return LV_RES_OK;
|
||||
}
|
||||
|
||||
usb_ctxt_t usbs;
|
||||
usbs.type = MMC_EMMC;
|
||||
usbs.partition = EMMC_BOOT1 + 1;
|
||||
usbs.offset = 0;
|
||||
usbs.sectors = 0;
|
||||
usbs.ro = usb_msc_emmc_read_only;
|
||||
usbs.system_maintenance = &manual_system_maintenance;
|
||||
usbs.set_text = &usb_gadget_set_text;
|
||||
sdmmc_storage_t *storage;
|
||||
emusd_cfg_t emu_info;
|
||||
|
||||
_create_mbox_ums(&usbs);
|
||||
bool file_based = false;
|
||||
int error = !boot_storage_mount();
|
||||
char path[0x80];
|
||||
|
||||
if(!error){
|
||||
load_emusd_cfg(&emu_info);
|
||||
if(emu_info.enabled){
|
||||
error = 0;
|
||||
if(emu_info.enabled == 4 && emu_info.sector){
|
||||
if(!emmc_initialize(false)){
|
||||
error = 3;
|
||||
}
|
||||
storage = &emmc_storage;
|
||||
}else if(emu_info.enabled == 1 && emu_info.sector){
|
||||
if(!sd_initialize(false)){
|
||||
error = 4;
|
||||
}
|
||||
storage = &sd_storage;
|
||||
}else if((emu_info.enabled == 1 || emu_info.enabled == 4) && !emu_info.sector){
|
||||
if(emu_info.enabled == 1){
|
||||
if(!sd_mount()){
|
||||
error = 4;
|
||||
}
|
||||
}else{
|
||||
if(!emmc_mount()){
|
||||
error = 3;
|
||||
}
|
||||
}
|
||||
if(error == 0){
|
||||
file_based = true;
|
||||
if(emu_info.enabled ==1){
|
||||
strcpy(path, "sd:");
|
||||
}else{
|
||||
strcpy(path, "emmc:");
|
||||
}
|
||||
strcat(path, emu_info.path);
|
||||
strcat(path, "/SD/");
|
||||
if(!file_based_storage_init(path)){
|
||||
error = 9;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
error = 10;
|
||||
}
|
||||
}else{
|
||||
error = 10;
|
||||
}
|
||||
|
||||
if(error == 0 && emu_info.enabled){
|
||||
error = 6;
|
||||
if(file_based){
|
||||
usbs.offset = 0;
|
||||
}else{
|
||||
usbs.offset = emu_info.sector;
|
||||
}
|
||||
|
||||
if(file_based){
|
||||
error = 9;
|
||||
u32 sz = file_based_storage_get_total_size();
|
||||
if(sz){
|
||||
error = 0;
|
||||
}
|
||||
usbs.sectors = sz;
|
||||
}else{
|
||||
error = 3;
|
||||
mbr_t mbr;
|
||||
if(sdmmc_storage_read(storage, emu_info.sector, 1, &mbr)){
|
||||
error = 0;
|
||||
usbs.sectors = mbr.partitions[0].size_sct + mbr.partitions[0].start_sct;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(emu_info.path){
|
||||
free(emu_info.path);
|
||||
}
|
||||
|
||||
if(error){
|
||||
_create_mbox_ums_error(error);
|
||||
}else{
|
||||
if(file_based){
|
||||
usbs.type = MMC_FILE_BASED;
|
||||
}else{
|
||||
usbs.type = emu_info.enabled == 1 ? MMC_SD : MMC_EMMC;
|
||||
}
|
||||
usbs.partition = EMMC_GPP + 1;
|
||||
usbs.ro = false;
|
||||
usbs.system_maintenance = &manual_system_maintenance;
|
||||
usbs.set_text = &usb_gadget_set_text;
|
||||
_create_mbox_ums(&usbs, NYX_UMS_EMUSD);
|
||||
}
|
||||
|
||||
file_based_storage_end();
|
||||
boot_storage_unmount();
|
||||
|
||||
return LV_RES_OK;
|
||||
}
|
||||
|
||||
static lv_res_t _action_ums_emmc_gpp(lv_obj_t *btn)
|
||||
{
|
||||
static lv_res_t _ums_emummc(u32 part){
|
||||
if (!nyx_emmc_check_battery_enough())
|
||||
return LV_RES_OK;
|
||||
|
||||
usb_ctxt_t usbs;
|
||||
usbs.type = MMC_EMMC;
|
||||
usbs.partition = EMMC_GPP + 1;
|
||||
usbs.offset = 0;
|
||||
usbs.sectors = 0;
|
||||
usbs.ro = usb_msc_emmc_read_only;
|
||||
usbs.system_maintenance = &manual_system_maintenance;
|
||||
usbs.set_text = &usb_gadget_set_text;
|
||||
sdmmc_storage_t *storage;
|
||||
emummc_cfg_t emu_info;
|
||||
|
||||
_create_mbox_ums(&usbs);
|
||||
int error = !boot_storage_mount();
|
||||
bool file_based = false;
|
||||
char path[0x80];
|
||||
|
||||
if(!error){
|
||||
load_emummc_cfg(&emu_info);
|
||||
if(emu_info.enabled){
|
||||
error = 0;
|
||||
if(emu_info.enabled == 4 && emu_info.sector){
|
||||
// emmc raw based
|
||||
if(!emmc_initialize(false)){
|
||||
error = 3;
|
||||
}
|
||||
storage = &emmc_storage;
|
||||
}else if(emu_info.enabled == 1 && emu_info.sector){
|
||||
// sd raw based
|
||||
if(!sd_initialize(false)){
|
||||
error = 4;
|
||||
}
|
||||
storage = &sd_storage;
|
||||
}else if((emu_info.enabled == 1 || emu_info.enabled == 4) && !emu_info.sector){
|
||||
// sd file based
|
||||
if(emu_info.enabled == 1){
|
||||
if(!sd_mount()){
|
||||
error = 4;
|
||||
}
|
||||
}else{
|
||||
if(!emmc_mount()){
|
||||
error = 3;
|
||||
}
|
||||
}
|
||||
if(error == 0){
|
||||
file_based = true;
|
||||
if(emu_info.enabled == 1){
|
||||
strcpy(path, "sd:");
|
||||
}else{
|
||||
strcpy(path, "emmc:");
|
||||
}
|
||||
strcat(path, emu_info.path);
|
||||
strcat(path, "/eMMC/");
|
||||
if(!emummc_storage_file_based_init(path)){
|
||||
error = 8;
|
||||
}else{
|
||||
switch(part){
|
||||
case NYX_UMS_EMUMMC_BOOT0:
|
||||
emummc_storage_file_base_set_partition(1);
|
||||
break;
|
||||
case NYX_UMS_EMUMMC_BOOT1:
|
||||
emummc_storage_file_base_set_partition(2);
|
||||
break;
|
||||
case NYX_UMS_EMUMMC_GPP:
|
||||
emummc_storage_file_base_set_partition(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}else{
|
||||
error = 2;
|
||||
}
|
||||
}else{
|
||||
error = 2;
|
||||
}
|
||||
|
||||
if(error == 0 && emu_info.enabled){
|
||||
error = 6;
|
||||
if(file_based){
|
||||
usbs.offset = 0;
|
||||
}else{
|
||||
usbs.offset = emu_info.sector;
|
||||
switch(part){
|
||||
case NYX_UMS_EMUMMC_BOOT0:
|
||||
usbs.offset += 0;
|
||||
break;
|
||||
case NYX_UMS_EMUMMC_BOOT1:
|
||||
usbs.offset += 0x2000;
|
||||
break;
|
||||
case NYX_UMS_EMUMMC_GPP:
|
||||
usbs.offset += 0x4000;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(part == NYX_UMS_EMUMMC_GPP){
|
||||
if(file_based){
|
||||
error = 8;
|
||||
u32 sz = emummc_storage_file_based_get_total_gpp_size(path);
|
||||
if(sz){
|
||||
error = 0;
|
||||
}
|
||||
usbs.sectors = sz;
|
||||
}else{
|
||||
int res;
|
||||
gpt_header_t *gpt_hdr = malloc(sizeof(*gpt_hdr));
|
||||
res = sdmmc_storage_read(storage, usbs.offset + 1, 1, gpt_hdr);
|
||||
if(res){
|
||||
if(!memcmp(&gpt_hdr->signature, "EFI PART", 8)){
|
||||
error = 0;
|
||||
usbs.sectors = gpt_hdr->alt_lba + 1;
|
||||
}
|
||||
}
|
||||
free(gpt_hdr);
|
||||
}
|
||||
}else{
|
||||
error = 0;
|
||||
usbs.sectors = 0x2000;
|
||||
}
|
||||
}
|
||||
|
||||
if(emu_info.path){
|
||||
free(emu_info.path);
|
||||
}
|
||||
if(emu_info.nintendo_path){
|
||||
free(emu_info.nintendo_path);
|
||||
}
|
||||
}
|
||||
|
||||
if(error){
|
||||
_create_mbox_ums_error(error);
|
||||
}else{
|
||||
if(file_based){
|
||||
usbs.type = emu_info.enabled == 4 ? MMC_EMUMMC_FILE_EMMC : MMC_EMUMMC_FILE;
|
||||
}else{
|
||||
usbs.type = emu_info.enabled == 4 ? MMC_EMUMMC_RAW_EMMC : MMC_EMUMMC_RAW_SD;
|
||||
}
|
||||
switch(part){
|
||||
case NYX_UMS_EMUMMC_BOOT0:
|
||||
usbs.partition = EMMC_GPP + 1;
|
||||
break;
|
||||
case NYX_UMS_EMUMMC_BOOT1:
|
||||
usbs.partition = EMMC_BOOT1 + 1;
|
||||
break;
|
||||
case NYX_UMS_EMUMMC_GPP:
|
||||
usbs.partition = EMMC_BOOT0 + 1;
|
||||
break;
|
||||
}
|
||||
usbs.ro = usb_msc_emmc_read_only;
|
||||
usbs.system_maintenance = &manual_system_maintenance;
|
||||
usbs.set_text = &usb_gadget_set_text;
|
||||
_create_mbox_ums(&usbs, part);
|
||||
}
|
||||
|
||||
emummc_storage_file_based_end();
|
||||
boot_storage_unmount();
|
||||
|
||||
return LV_RES_OK;
|
||||
}
|
||||
|
||||
static lv_res_t _action_ums_emuemmc_boot0(lv_obj_t *btn)
|
||||
{
|
||||
if (!nyx_emmc_check_battery_enough())
|
||||
return LV_RES_OK;
|
||||
|
||||
usb_ctxt_t usbs;
|
||||
|
||||
int error = !sd_mount();
|
||||
if (!error)
|
||||
{
|
||||
emummc_cfg_t emu_info;
|
||||
load_emummc_cfg(&emu_info);
|
||||
|
||||
error = 2;
|
||||
if (emu_info.enabled)
|
||||
{
|
||||
error = 3;
|
||||
if (emu_info.sector)
|
||||
{
|
||||
error = 0;
|
||||
usbs.offset = emu_info.sector;
|
||||
}
|
||||
}
|
||||
|
||||
if (emu_info.path)
|
||||
free(emu_info.path);
|
||||
if (emu_info.nintendo_path)
|
||||
free(emu_info.nintendo_path);
|
||||
}
|
||||
sd_unmount();
|
||||
|
||||
if (error)
|
||||
_create_mbox_ums_error(error);
|
||||
else
|
||||
{
|
||||
usbs.type = MMC_SD;
|
||||
usbs.partition = EMMC_BOOT0 + 1;
|
||||
usbs.sectors = 0x2000; // Forced 4MB.
|
||||
usbs.ro = usb_msc_emmc_read_only;
|
||||
usbs.system_maintenance = &manual_system_maintenance;
|
||||
usbs.set_text = &usb_gadget_set_text;
|
||||
_create_mbox_ums(&usbs);
|
||||
}
|
||||
|
||||
return LV_RES_OK;
|
||||
return _ums_emummc(NYX_UMS_EMUMMC_BOOT0);
|
||||
}
|
||||
|
||||
static lv_res_t _action_ums_emuemmc_boot1(lv_obj_t *btn)
|
||||
{
|
||||
if (!nyx_emmc_check_battery_enough())
|
||||
return LV_RES_OK;
|
||||
|
||||
usb_ctxt_t usbs;
|
||||
|
||||
int error = !sd_mount();
|
||||
if (!error)
|
||||
{
|
||||
emummc_cfg_t emu_info;
|
||||
load_emummc_cfg(&emu_info);
|
||||
|
||||
error = 2;
|
||||
if (emu_info.enabled)
|
||||
{
|
||||
error = 3;
|
||||
if (emu_info.sector)
|
||||
{
|
||||
error = 0;
|
||||
usbs.offset = emu_info.sector + 0x2000;
|
||||
}
|
||||
}
|
||||
|
||||
if (emu_info.path)
|
||||
free(emu_info.path);
|
||||
if (emu_info.nintendo_path)
|
||||
free(emu_info.nintendo_path);
|
||||
}
|
||||
sd_unmount();
|
||||
|
||||
if (error)
|
||||
_create_mbox_ums_error(error);
|
||||
else
|
||||
{
|
||||
usbs.type = MMC_SD;
|
||||
usbs.partition = EMMC_BOOT1 + 1;
|
||||
usbs.sectors = 0x2000; // Forced 4MB.
|
||||
usbs.ro = usb_msc_emmc_read_only;
|
||||
usbs.system_maintenance = &manual_system_maintenance;
|
||||
usbs.set_text = &usb_gadget_set_text;
|
||||
_create_mbox_ums(&usbs);
|
||||
}
|
||||
|
||||
return LV_RES_OK;
|
||||
return _ums_emummc(NYX_UMS_EMUMMC_BOOT1);
|
||||
}
|
||||
|
||||
static lv_res_t _action_ums_emuemmc_gpp(lv_obj_t *btn)
|
||||
{
|
||||
if (!nyx_emmc_check_battery_enough())
|
||||
return LV_RES_OK;
|
||||
|
||||
usb_ctxt_t usbs;
|
||||
|
||||
int error = !sd_mount();
|
||||
if (!error)
|
||||
{
|
||||
emummc_cfg_t emu_info;
|
||||
load_emummc_cfg(&emu_info);
|
||||
|
||||
error = 2;
|
||||
if (emu_info.enabled)
|
||||
{
|
||||
error = 3;
|
||||
if (emu_info.sector)
|
||||
{
|
||||
error = 1;
|
||||
usbs.offset = emu_info.sector + 0x4000;
|
||||
|
||||
u8 *gpt = malloc(SD_BLOCKSIZE);
|
||||
if (sdmmc_storage_read(&sd_storage, usbs.offset + 1, 1, gpt))
|
||||
{
|
||||
if (!memcmp(gpt, "EFI PART", 8))
|
||||
{
|
||||
error = 0;
|
||||
usbs.sectors = *(u32 *)(gpt + 0x20) + 1; // Backup LBA + 1.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (emu_info.path)
|
||||
free(emu_info.path);
|
||||
if (emu_info.nintendo_path)
|
||||
free(emu_info.nintendo_path);
|
||||
}
|
||||
sd_unmount();
|
||||
|
||||
if (error)
|
||||
_create_mbox_ums_error(error);
|
||||
else
|
||||
{
|
||||
usbs.type = MMC_SD;
|
||||
usbs.partition = EMMC_GPP + 1;
|
||||
usbs.ro = usb_msc_emmc_read_only;
|
||||
usbs.system_maintenance = &manual_system_maintenance;
|
||||
usbs.set_text = &usb_gadget_set_text;
|
||||
_create_mbox_ums(&usbs);
|
||||
}
|
||||
|
||||
return LV_RES_OK;
|
||||
return _ums_emummc(NYX_UMS_EMUMMC_GPP);
|
||||
}
|
||||
|
||||
void nyx_run_ums(void *param)
|
||||
@@ -651,7 +860,7 @@ void nyx_run_ums(void *param)
|
||||
_action_ums_emmc_boot1(NULL);
|
||||
break;
|
||||
case NYX_UMS_EMMC_GPP:
|
||||
_action_ums_emmc_gpp(NULL);
|
||||
action_ums_emmc_gpp(NULL);
|
||||
break;
|
||||
case NYX_UMS_EMUMMC_BOOT0:
|
||||
_action_ums_emuemmc_boot0(NULL);
|
||||
@@ -718,18 +927,40 @@ static lv_res_t _create_window_usb_tools(lv_obj_t *parent)
|
||||
lv_obj_t *label_txt2 = lv_label_create(h1, NULL);
|
||||
lv_label_set_recolor(label_txt2, true);
|
||||
lv_label_set_static_text(label_txt2,
|
||||
"Allows you to mount the SD Card to a PC/Phone.\n"
|
||||
"Allows you to mount the SD Card or boot drive to a PC/Phone.\n"
|
||||
"#C7EA46 All operating systems are supported. Access is# #FF8000 Read/Write.#");
|
||||
|
||||
lv_obj_set_style(label_txt2, &hint_small_style);
|
||||
lv_obj_align(label_txt2, btn1, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3);
|
||||
|
||||
// Create emuSD button
|
||||
lv_obj_t *btn_emusd = lv_btn_create(h1, btn1);
|
||||
label_btn = lv_label_create(btn_emusd, NULL);
|
||||
lv_label_set_text(label_btn, SYMBOL_MODULES_ALT " emuSD");
|
||||
lv_obj_align(btn_emusd, btn1, LV_ALIGN_OUT_RIGHT_MID, LV_DPI / 10, 0);
|
||||
lv_btn_set_action(btn_emusd, LV_BTN_ACTION_CLICK, _action_ums_emusd);
|
||||
|
||||
// Create Boot Storage UMS button
|
||||
lv_obj_t *btn_boot_strg = lv_btn_create(h1, btn1);
|
||||
label_btn = lv_label_create(btn_boot_strg, NULL);
|
||||
lv_label_set_text(label_btn, boot_storage_get_drive() == DRIVE_SD ? SYMBOL_SD " Boot Drive" : SYMBOL_CHIP " Boot Drive");
|
||||
lv_obj_align(btn_boot_strg, btn_emusd, LV_ALIGN_OUT_RIGHT_MID, LV_DPI / 10, 0);
|
||||
lv_btn_set_action(btn_boot_strg, LV_BTN_ACTION_CLICK, _action_ums_boot_storage);
|
||||
|
||||
if(!boot_storage_mount()){
|
||||
lv_obj_set_click(btn_boot_strg, false);
|
||||
lv_btn_set_state(btn_boot_strg, LV_BTN_STATE_INA);
|
||||
}
|
||||
boot_storage_unmount();
|
||||
|
||||
|
||||
|
||||
// Create RAW GPP button.
|
||||
lv_obj_t *btn_gpp = lv_btn_create(h1, btn1);
|
||||
label_btn = lv_label_create(btn_gpp, NULL);
|
||||
lv_label_set_static_text(label_btn, SYMBOL_CHIP" eMMC RAW GPP");
|
||||
lv_obj_align(btn_gpp, label_txt2, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 2);
|
||||
lv_btn_set_action(btn_gpp, LV_BTN_ACTION_CLICK, _action_ums_emmc_gpp);
|
||||
lv_btn_set_action(btn_gpp, LV_BTN_ACTION_CLICK, action_ums_emmc_gpp);
|
||||
|
||||
// Create BOOT0 button.
|
||||
lv_obj_t *btn_boot0 = lv_btn_create(h1, btn1);
|
||||
@@ -927,6 +1158,8 @@ out:
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
// TODO: emusd
|
||||
static lv_res_t _create_window_unset_abit_tool(lv_obj_t *btn)
|
||||
{
|
||||
lv_obj_t *win = nyx_create_standard_window(SYMBOL_COPY" Fix Archive Bit (All folders)");
|
||||
@@ -957,7 +1190,8 @@ static lv_res_t _create_window_unset_abit_tool(lv_obj_t *btn)
|
||||
lv_obj_t * lb_val = lv_label_create(val, lb_desc);
|
||||
|
||||
char *path = malloc(0x1000);
|
||||
path[0] = 0;
|
||||
strcpy(path, "sd:");
|
||||
// path[0] = 0;
|
||||
|
||||
lv_label_set_text(lb_val, "");
|
||||
lv_obj_set_width(lb_val, lv_obj_get_width(val));
|
||||
@@ -1135,8 +1369,9 @@ static lv_res_t _create_window_dump_pk12_tool(lv_obj_t *btn)
|
||||
lv_label_set_recolor(lb_desc, true);
|
||||
lv_obj_set_width(lb_desc, lv_obj_get_width(desc));
|
||||
|
||||
if (!sd_mount())
|
||||
if (!boot_storage_mount())
|
||||
{
|
||||
// may not be sd, fix error
|
||||
lv_label_set_text(lb_desc, "#FFDD00 Failed to init SD!#");
|
||||
|
||||
goto out_end;
|
||||
@@ -1180,7 +1415,7 @@ static lv_res_t _create_window_dump_pk12_tool(lv_obj_t *btn)
|
||||
|
||||
// Dump package1 in its encrypted state.
|
||||
emmcsn_path_impl(path, "/pkg1", "pkg1_enc.bin", &emmc_storage);
|
||||
bool res = sd_save_to_file(pkg1, BOOTLOADER_SIZE, path);
|
||||
bool res = boot_storage_save_to_file(pkg1, BOOTLOADER_SIZE, path);
|
||||
|
||||
// Exit if unknown.
|
||||
if (!pkg1_id)
|
||||
@@ -1245,7 +1480,7 @@ static lv_res_t _create_window_dump_pk12_tool(lv_obj_t *btn)
|
||||
|
||||
// Dump package1.1.
|
||||
emmcsn_path_impl(path, "/pkg1", "pkg1_decr.bin", &emmc_storage);
|
||||
if (sd_save_to_file(pkg1, SZ_256K, path))
|
||||
if (boot_storage_save_to_file(pkg1, SZ_256K, path))
|
||||
goto out_free;
|
||||
strcat(txt_buf, "pkg1 dumped to pkg1_decr.bin\n");
|
||||
lv_label_set_text(lb_desc, txt_buf);
|
||||
@@ -1253,7 +1488,7 @@ static lv_res_t _create_window_dump_pk12_tool(lv_obj_t *btn)
|
||||
|
||||
// Dump nxbootloader.
|
||||
emmcsn_path_impl(path, "/pkg1", "nxloader.bin", &emmc_storage);
|
||||
if (sd_save_to_file(loader, hdr_pk11->ldr_size, path))
|
||||
if (boot_storage_save_to_file(loader, hdr_pk11->ldr_size, path))
|
||||
goto out_free;
|
||||
strcat(txt_buf, "NX Bootloader dumped to nxloader.bin\n");
|
||||
lv_label_set_text(lb_desc, txt_buf);
|
||||
@@ -1261,7 +1496,7 @@ static lv_res_t _create_window_dump_pk12_tool(lv_obj_t *btn)
|
||||
|
||||
// Dump secmon.
|
||||
emmcsn_path_impl(path, "/pkg1", "secmon.bin", &emmc_storage);
|
||||
if (sd_save_to_file(secmon, hdr_pk11->sm_size, path))
|
||||
if (boot_storage_save_to_file(secmon, hdr_pk11->sm_size, path))
|
||||
goto out_free;
|
||||
strcat(txt_buf, "Secure Monitor dumped to secmon.bin\n");
|
||||
lv_label_set_text(lb_desc, txt_buf);
|
||||
@@ -1269,7 +1504,7 @@ static lv_res_t _create_window_dump_pk12_tool(lv_obj_t *btn)
|
||||
|
||||
// Dump warmboot.
|
||||
emmcsn_path_impl(path, "/pkg1", "warmboot.bin", &emmc_storage);
|
||||
if (sd_save_to_file(warmboot, hdr_pk11->wb_size, path))
|
||||
if (boot_storage_save_to_file(warmboot, hdr_pk11->wb_size, path))
|
||||
goto out_free;
|
||||
// If T210B01, save a copy of decrypted warmboot binary also.
|
||||
if (h_cfg.t210b01)
|
||||
@@ -1279,7 +1514,7 @@ static lv_res_t _create_window_dump_pk12_tool(lv_obj_t *btn)
|
||||
se_aes_crypt_cbc(13, DECRYPT, warmboot + 0x330, hdr_pk11->wb_size - 0x330,
|
||||
warmboot + 0x330, hdr_pk11->wb_size - 0x330);
|
||||
emmcsn_path_impl(path, "/pkg1", "warmboot_dec.bin", &emmc_storage);
|
||||
if (sd_save_to_file(warmboot, hdr_pk11->wb_size, path))
|
||||
if (boot_storage_save_to_file(warmboot, hdr_pk11->wb_size, path))
|
||||
goto out_free;
|
||||
}
|
||||
strcat(txt_buf, "Warmboot dumped to warmboot.bin\n\n");
|
||||
@@ -1311,7 +1546,7 @@ static lv_res_t _create_window_dump_pk12_tool(lv_obj_t *btn)
|
||||
|
||||
// Dump encrypted package2.
|
||||
emmcsn_path_impl(path, "/pkg2", "pkg2_encr.bin", &emmc_storage);
|
||||
res = sd_save_to_file(pkg2, pkg2_size, path);
|
||||
res = boot_storage_save_to_file(pkg2, pkg2_size, path);
|
||||
|
||||
// Decrypt package2 and parse KIP1 blobs in INI1 section.
|
||||
pkg2_hdr_t *pkg2_hdr = pkg2_decrypt(pkg2, kb);
|
||||
@@ -1345,7 +1580,7 @@ static lv_res_t _create_window_dump_pk12_tool(lv_obj_t *btn)
|
||||
|
||||
// Dump pkg2.1.
|
||||
emmcsn_path_impl(path, "/pkg2", "pkg2_decr.bin", &emmc_storage);
|
||||
if (sd_save_to_file(pkg2, pkg2_hdr->sec_size[PKG2_SEC_KERNEL] + pkg2_hdr->sec_size[PKG2_SEC_INI1], path))
|
||||
if (boot_storage_save_to_file(pkg2, pkg2_hdr->sec_size[PKG2_SEC_KERNEL] + pkg2_hdr->sec_size[PKG2_SEC_INI1], path))
|
||||
goto out;
|
||||
strcat(txt_buf, "pkg2 dumped to pkg2_decr.bin\n");
|
||||
lv_label_set_text(lb_desc, txt_buf);
|
||||
@@ -1353,7 +1588,7 @@ static lv_res_t _create_window_dump_pk12_tool(lv_obj_t *btn)
|
||||
|
||||
// Dump kernel.
|
||||
emmcsn_path_impl(path, "/pkg2", "kernel.bin", &emmc_storage);
|
||||
if (sd_save_to_file(pkg2_hdr->data, pkg2_hdr->sec_size[PKG2_SEC_KERNEL], path))
|
||||
if (boot_storage_save_to_file(pkg2_hdr->data, pkg2_hdr->sec_size[PKG2_SEC_KERNEL], path))
|
||||
goto out;
|
||||
strcat(txt_buf, "Kernel dumped to kernel.bin\n");
|
||||
lv_label_set_text(lb_desc, txt_buf);
|
||||
@@ -1377,7 +1612,7 @@ static lv_res_t _create_window_dump_pk12_tool(lv_obj_t *btn)
|
||||
|
||||
pkg2_ini1_t *ini1 = (pkg2_ini1_t *)(pkg2_hdr->data + ini1_off);
|
||||
emmcsn_path_impl(path, "/pkg2", "ini1.bin", &emmc_storage);
|
||||
if (sd_save_to_file(ini1, ini1_size, path))
|
||||
if (boot_storage_save_to_file(ini1, ini1_size, path))
|
||||
goto out;
|
||||
|
||||
strcat(txt_buf, "INI1 dumped to ini1.bin\n\n");
|
||||
@@ -1404,7 +1639,7 @@ static lv_res_t _create_window_dump_pk12_tool(lv_obj_t *btn)
|
||||
}
|
||||
|
||||
emmcsn_path_impl(path, "/pkg2/ini1", filename, &emmc_storage);
|
||||
if (sd_save_to_file(kip1, kip1_size, path))
|
||||
if (boot_storage_save_to_file(kip1, kip1_size, path))
|
||||
{
|
||||
free(kip_buffer);
|
||||
goto out;
|
||||
@@ -1429,6 +1664,7 @@ out_free:
|
||||
free(txt_buf);
|
||||
emmc_end();
|
||||
sd_unmount();
|
||||
boot_storage_unmount();
|
||||
|
||||
if (kb >= HOS_KB_VERSION_620)
|
||||
se_aes_key_clear(8);
|
||||
@@ -1439,6 +1675,26 @@ out_end:
|
||||
return LV_RES_OK;
|
||||
}
|
||||
|
||||
lv_res_t _partition_action(lv_obj_t *btnm, const char *txt){
|
||||
u8 drive;
|
||||
switch(lv_btnm_get_pressed(btnm)){
|
||||
case 0:
|
||||
// SD
|
||||
drive = DRIVE_SD;
|
||||
break;
|
||||
case 1:
|
||||
// eMMC
|
||||
drive = DRIVE_EMMC;
|
||||
break;
|
||||
default:
|
||||
return LV_RES_OK;
|
||||
}
|
||||
|
||||
create_window_partition_manager(btnm, drive);
|
||||
|
||||
return LV_RES_OK;
|
||||
}
|
||||
|
||||
static void _create_tab_tools_emmc_pkg12(lv_theme_t *th, lv_obj_t *parent)
|
||||
{
|
||||
lv_page_set_scrl_layout(parent, LV_LAYOUT_PRETTY);
|
||||
@@ -1508,41 +1764,58 @@ static void _create_tab_tools_emmc_pkg12(lv_theme_t *th, lv_obj_t *parent)
|
||||
lv_label_set_static_text(label_sep, "");
|
||||
|
||||
lv_obj_t *label_txt3 = lv_label_create(h2, NULL);
|
||||
lv_label_set_static_text(label_txt3, "SD Partitions & USB");
|
||||
lv_label_set_static_text(label_txt3, "Partitions & USB");
|
||||
lv_obj_set_style(label_txt3, th->label.prim);
|
||||
lv_obj_align(label_txt3, label_sep, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI / 4, -LV_DPI * 3 / 10);
|
||||
|
||||
line_sep = lv_line_create(h2, line_sep);
|
||||
lv_obj_align(line_sep, label_txt3, LV_ALIGN_OUT_BOTTOM_LEFT, -(LV_DPI / 4), LV_DPI / 8);
|
||||
|
||||
// Create Partition SD Card button.
|
||||
lv_obj_t *btn3 = lv_btn_create(h2, NULL);
|
||||
// Create Partition SD/eMMC Card button.
|
||||
// TODO: Boot 1 partition option
|
||||
static const char* btn_map[] = {"\222" SYMBOL_SD " SD", "\222" SYMBOL_CHIP " eMMC", ""};
|
||||
|
||||
lv_obj_t *btnm = lv_btnm_create(h2, NULL);
|
||||
lv_btnm_set_style(btnm, LV_BTNM_STYLE_BG, th->bg);
|
||||
lv_btnm_set_style(btnm, LV_BTNM_STYLE_BTN_REL, th->btn.rel);
|
||||
lv_btnm_set_style(btnm, LV_BTNM_STYLE_BTN_PR, th->btn.pr);
|
||||
lv_btnm_set_style(btnm, LV_BTNM_STYLE_BTN_TGL_REL, th->btn.tgl_rel);
|
||||
lv_btnm_set_style(btnm, LV_BTNM_STYLE_BTN_TGL_PR, th->btn.tgl_pr);
|
||||
lv_btnm_set_style(btnm, LV_BTNM_STYLE_BTN_INA, th->btn.ina);
|
||||
if (hekate_bg)
|
||||
{
|
||||
lv_btn_set_style(btn3, LV_BTN_STYLE_REL, &btn_transp_rel);
|
||||
lv_btn_set_style(btn3, LV_BTN_STYLE_PR, &btn_transp_pr);
|
||||
lv_btnm_set_style(btnm, LV_BTNM_STYLE_BTN_REL, &btn_transp_rel);
|
||||
lv_btnm_set_style(btnm, LV_BTNM_STYLE_BTN_PR, &btn_transp_pr);
|
||||
}
|
||||
label_btn = lv_label_create(btn3, NULL);
|
||||
lv_btn_set_fit(btn3, true, true);
|
||||
lv_label_set_static_text(label_btn, SYMBOL_SD" Partition SD Card");
|
||||
lv_obj_align(btn3, line_sep, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI / 4, LV_DPI / 4);
|
||||
lv_btn_set_action(btn3, LV_BTN_ACTION_CLICK, create_window_partition_manager);
|
||||
lv_coord_t font_h = lv_font_get_height(th->btn.rel->text.font);
|
||||
lv_obj_set_size(btnm, 400, font_h + 2 * th->btn.rel->body.padding.ver + 2 * th->bg->body.padding.ver);
|
||||
lv_obj_align(btnm, line_sep, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI / 4, LV_DPI / 4 - th->bg->body.padding.ver);
|
||||
lv_btnm_set_map(btnm, btn_map);
|
||||
lv_btnm_set_action(btnm, _partition_action);
|
||||
|
||||
|
||||
lv_obj_t *label_txt4 = lv_label_create(h2, NULL);
|
||||
lv_label_set_recolor(label_txt4, true);
|
||||
lv_label_set_static_text(label_txt4,
|
||||
"Allows you to partition the SD Card for using it with #C7EA46 emuMMC#,\n"
|
||||
"#C7EA46 Android# and #C7EA46 Linux#. You can also flash Linux and Android.\n");
|
||||
"Allows you to partition the SD Card or the eMMC \n"
|
||||
"for using it with #C7EA46 emuMMC#, #C7EA46 Android# and #C7EA46 Linux#."
|
||||
"\nYou can also flash Linux and Android.");
|
||||
lv_obj_set_style(label_txt4, &hint_small_style);
|
||||
lv_obj_align(label_txt4, btn3, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3);
|
||||
lv_obj_align(label_txt4, btnm, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3 - th->bg->body.padding.ver);
|
||||
|
||||
label_sep = lv_label_create(h2, NULL);
|
||||
lv_label_set_static_text(label_sep, "");
|
||||
lv_obj_align(label_sep, label_txt4, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI * 11 / 7);
|
||||
|
||||
// Create USB Tools button.
|
||||
lv_obj_t *btn4 = lv_btn_create(h2, btn3);
|
||||
lv_obj_t *btn4 = lv_btn_create(h2, NULL);
|
||||
label_btn = lv_label_create(btn4, NULL);
|
||||
if (hekate_bg)
|
||||
{
|
||||
lv_btn_set_style(btn4, LV_BTN_STYLE_REL, &btn_transp_rel);
|
||||
lv_btn_set_style(btn4, LV_BTN_STYLE_PR, &btn_transp_pr);
|
||||
}
|
||||
lv_btn_set_fit(btn4, true, true);
|
||||
lv_label_set_static_text(label_btn, SYMBOL_USB" USB Tools");
|
||||
lv_obj_align(btn4, label_txt4, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 2);
|
||||
lv_btn_set_action(btn4, LV_BTN_ACTION_CLICK, _create_window_usb_tools);
|
||||
|
||||
@@ -25,5 +25,6 @@ void create_tab_tools(lv_theme_t *th, lv_obj_t *parent);
|
||||
void nyx_run_ums(void *param);
|
||||
bool get_set_autorcm_status(bool change);
|
||||
lv_res_t action_ums_sd(lv_obj_t *btn);
|
||||
lv_res_t action_ums_emmc_gpp(lv_obj_t *btn);
|
||||
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -17,6 +17,6 @@
|
||||
#ifndef _GUI_TOOLS_PART_MANAGER_H_
|
||||
#define _GUI_TOOLS_PART_MANAGER_H_
|
||||
|
||||
lv_res_t create_window_partition_manager(lv_obj_t *btn);
|
||||
lv_res_t create_window_partition_manager(lv_obj_t *btn, u8 drive);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (c) 2018 st4rk
|
||||
* Copyright (c) 2018 Ced2911
|
||||
* Copyright (c) 2018-2024 CTCaer
|
||||
* Copyright (c) 2018-2025 CTCaer
|
||||
* Copyright (c) 2018 balika011
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <bdk.h>
|
||||
|
||||
#include "hos.h"
|
||||
#include <storage/boot_storage.h>
|
||||
#include "../config.h"
|
||||
|
||||
extern hekate_config h_cfg;
|
||||
@@ -76,7 +77,7 @@ static const u8 master_kekseed_620[SE_KEY_128_SIZE] =
|
||||
|
||||
//!TODO: Update on mkey changes.
|
||||
static const u8 master_kekseed_t210_max[SE_KEY_128_SIZE] =
|
||||
{ 0xD7, 0x63, 0x74, 0x46, 0x4E, 0xBA, 0x78, 0x0A, 0x7C, 0x9D, 0xB3, 0xE8, 0x7A, 0x3D, 0x71, 0xE3 }; // 19.0.0.
|
||||
{ 0xA1, 0x7D, 0x34, 0xDB, 0x2D, 0x9D, 0xDA, 0xE5, 0xF8, 0x15, 0x63, 0x4C, 0x8F, 0xE7, 0x6C, 0xD8 }; // 20.0.0.
|
||||
|
||||
//!TODO: Update on mkey changes.
|
||||
static const u8 master_kekseed_t210b01[HOS_KB_VERSION_MAX - HOS_KB_VERSION_600 + 1][SE_KEY_128_SIZE] = {
|
||||
@@ -94,6 +95,7 @@ static const u8 master_kekseed_t210b01[HOS_KB_VERSION_MAX - HOS_KB_VERSION_600 +
|
||||
{ 0x8D, 0xEE, 0x9E, 0x11, 0x36, 0x3A, 0x9B, 0x0A, 0x6A, 0xC7, 0xBB, 0xE9, 0xD1, 0x03, 0xF7, 0x80 }, // 17.0.0.
|
||||
{ 0x4F, 0x41, 0x3C, 0x3B, 0xFB, 0x6A, 0x01, 0x2A, 0x68, 0x9F, 0x83, 0xE9, 0x53, 0xBD, 0x16, 0xD2 }, // 18.0.0.
|
||||
{ 0x31, 0xBE, 0x25, 0xFB, 0xDB, 0xB4, 0xEE, 0x49, 0x5C, 0x77, 0x05, 0xC2, 0x36, 0x9F, 0x34, 0x80 }, // 19.0.0.
|
||||
{ 0x1A, 0x31, 0x62, 0x87, 0xA8, 0x09, 0xCA, 0xF8, 0x69, 0x15, 0x45, 0xC2, 0x6B, 0xAA, 0x5A, 0x8A }, // 20.0.0.
|
||||
};
|
||||
|
||||
static const u8 console_keyseed[SE_KEY_128_SIZE] =
|
||||
@@ -126,6 +128,7 @@ static const u8 mkey_vectors[HOS_KB_VERSION_MAX + 1][SE_KEY_128_SIZE] = {
|
||||
{ 0x25, 0x12, 0x8B, 0xCB, 0xB5, 0x46, 0xA1, 0xF8, 0xE0, 0x52, 0x15, 0xB7, 0x0B, 0x57, 0x00, 0xBD }, // Mkey 15 encrypted with mkey 16.
|
||||
{ 0x58, 0x15, 0xD2, 0xF6, 0x8A, 0xE8, 0x19, 0xAB, 0xFB, 0x2D, 0x52, 0x9D, 0xE7, 0x55, 0xF3, 0x93 }, // Mkey 16 encrypted with mkey 17.
|
||||
{ 0x4A, 0x01, 0x3B, 0xC7, 0x44, 0x6E, 0x45, 0xBD, 0xE6, 0x5E, 0x2B, 0xEC, 0x07, 0x37, 0x52, 0x86 }, // Mkey 17 encrypted with mkey 18.
|
||||
{ 0x97, 0xE4, 0x11, 0xAB, 0x22, 0x72, 0x1A, 0x1F, 0x70, 0x5C, 0x00, 0xB3, 0x96, 0x30, 0x05, 0x28 }, // Mkey 18 encrypted with mkey 19.
|
||||
};
|
||||
|
||||
//!TODO: Update on mkey changes.
|
||||
@@ -146,6 +149,7 @@ static const u8 new_console_keyseed[HOS_KB_VERSION_MAX - HOS_KB_VERSION_400 + 1]
|
||||
{ 0xDA, 0xB9, 0xD6, 0x77, 0x52, 0x2D, 0x1F, 0x78, 0x73, 0xC9, 0x98, 0x5B, 0x06, 0xFE, 0xA0, 0x52 }, // 17.0.0 New Device Key Source.
|
||||
{ 0x14, 0xF5, 0xA5, 0xD0, 0x73, 0x6D, 0x44, 0x80, 0x5F, 0x31, 0x5A, 0x8F, 0x1E, 0xD4, 0x0D, 0x63 }, // 18.0.0 New Device Key Source.
|
||||
{ 0x07, 0x38, 0x9A, 0xEC, 0x9C, 0xBD, 0x50, 0x4A, 0x4C, 0x1F, 0x04, 0xDA, 0x40, 0x68, 0x29, 0xE3 }, // 19.0.0 New Device Key Source.
|
||||
{ 0xA3, 0x6B, 0x0A, 0xB5, 0x6F, 0x57, 0x4C, 0x5E, 0x00, 0xFD, 0x56, 0x21, 0xF5, 0x06, 0x6B, 0xD1 }, // 20.0.0 New Device Key Source.
|
||||
};
|
||||
|
||||
//!TODO: Update on mkey changes.
|
||||
@@ -166,6 +170,7 @@ static const u8 new_console_kekseed[HOS_KB_VERSION_MAX - HOS_KB_VERSION_400 + 1]
|
||||
{ 0x21, 0xD6, 0x35, 0xF1, 0x0F, 0x7A, 0xF0, 0x5D, 0xDF, 0x79, 0x1C, 0x7A, 0xE4, 0x32, 0x82, 0x9E }, // 17.0.0 New Device Keygen Source.
|
||||
{ 0xE7, 0x85, 0x8C, 0xA2, 0xF4, 0x49, 0xCB, 0x07, 0xD1, 0x8E, 0x48, 0x1B, 0xE8, 0x1E, 0x28, 0x3B }, // 18.0.0 New Device Keygen Source.
|
||||
{ 0x9B, 0xA5, 0xFD, 0x74, 0x7F, 0xCD, 0x23, 0xD1, 0xD9, 0xBD, 0x6C, 0x51, 0x72, 0x5F, 0x3D, 0x1F }, // 19.0.0 New Device Keygen Source.
|
||||
{ 0xDA, 0xFB, 0x61, 0x39, 0x48, 0x2D, 0xC2, 0x7E, 0x0D, 0x8E, 0x8F, 0x98, 0x57, 0x20, 0xB8, 0x15 }, // 20.0.0 New Device Keygen Source.
|
||||
};
|
||||
|
||||
static const u8 gen_keyseed[SE_KEY_128_SIZE] =
|
||||
@@ -269,7 +274,7 @@ static void _hos_eks_save()
|
||||
}
|
||||
|
||||
// Get keys.
|
||||
u8 *keys = (u8 *)calloc(2, SZ_4K);
|
||||
u8 *keys = (u8 *)zalloc(SZ_8K);
|
||||
se_get_aes_keys(keys + SZ_4K, keys, SE_KEY_128_SIZE);
|
||||
|
||||
// Set magic and personalized info.
|
||||
@@ -333,21 +338,6 @@ out:
|
||||
}
|
||||
}
|
||||
|
||||
int hos_keygen_t210b01(u32 kb)
|
||||
{
|
||||
// Use SBK as Device key 4x unsealer and KEK for mkey in T210B01 units.
|
||||
se_aes_unwrap_key(10, 14, console_keyseed_4xx);
|
||||
|
||||
// Derive master key.
|
||||
se_aes_unwrap_key(7, 12, master_kekseed_t210b01[kb - HOS_KB_VERSION_600]);
|
||||
se_aes_unwrap_key(7, 7, master_keyseed_retail);
|
||||
|
||||
// Derive latest pkg2 key.
|
||||
se_aes_unwrap_key(8, 7, package2_keyseed);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int hos_keygen(void *keyblob, u32 kb, tsec_ctxt_t *tsec_ctxt)
|
||||
{
|
||||
u32 retries = 0;
|
||||
@@ -358,8 +348,21 @@ int hos_keygen(void *keyblob, u32 kb, tsec_ctxt_t *tsec_ctxt)
|
||||
if (kb > HOS_KB_VERSION_MAX)
|
||||
return 0;
|
||||
|
||||
// Do Mariko keygen.
|
||||
if (h_cfg.t210b01)
|
||||
return hos_keygen_t210b01(kb);
|
||||
{
|
||||
// Use SBK as Device key 4x unsealer and KEK for mkey in T210B01 units.
|
||||
se_aes_unwrap_key(10, 14, console_keyseed_4xx);
|
||||
|
||||
// Derive master key.
|
||||
se_aes_unwrap_key(7, 12, master_kekseed_t210b01[kb - HOS_KB_VERSION_600]);
|
||||
se_aes_unwrap_key(7, 7, master_keyseed_retail);
|
||||
|
||||
// Derive latest pkg2 key.
|
||||
se_aes_unwrap_key(8, 7, package2_keyseed);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Do Erista keygen.
|
||||
|
||||
@@ -393,7 +396,7 @@ int hos_keygen(void *keyblob, u32 kb, tsec_ctxt_t *tsec_ctxt)
|
||||
*/
|
||||
|
||||
// Use custom TSEC Hovi Keygen firmware.
|
||||
tsec_ctxt->fw = sd_file_read("bootloader/sys/thk.bin", NULL);
|
||||
tsec_ctxt->fw = boot_storage_file_read("bootloader/sys/thk.bin", NULL);
|
||||
if (!tsec_ctxt->fw)
|
||||
{
|
||||
EPRINTF("\nFailed to load thk.bin");
|
||||
@@ -699,7 +702,7 @@ int hos_dump_cal0()
|
||||
LIST_INIT(gpt);
|
||||
emmc_gpt_parse(&gpt);
|
||||
emmc_part_t *cal0_part = emmc_part_find(&gpt, "PRODINFO"); // check if null
|
||||
nx_emmc_bis_init(cal0_part, false, 0);
|
||||
nx_emmc_bis_init(cal0_part, false, NULL, 0);
|
||||
nx_emmc_bis_read(0, 0x40, cal0_buf);
|
||||
nx_emmc_bis_end();
|
||||
emmc_gpt_free(&gpt);
|
||||
|
||||
@@ -46,7 +46,8 @@ enum {
|
||||
HOS_KB_VERSION_1700 = 16,
|
||||
HOS_KB_VERSION_1800 = 17,
|
||||
HOS_KB_VERSION_1900 = 18,
|
||||
HOS_KB_VERSION_MAX = HOS_KB_VERSION_1900
|
||||
HOS_KB_VERSION_2000 = 19,
|
||||
HOS_KB_VERSION_MAX = HOS_KB_VERSION_2000
|
||||
};
|
||||
|
||||
#define HOS_TSEC_VERSION 4 //! TODO: Update on TSEC Root Key changes.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (c) 2018 st4rk
|
||||
* Copyright (c) 2018-2024 CTCaer
|
||||
* Copyright (c) 2018-2025 CTCaer
|
||||
* Copyright (c) 2018 balika011
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
@@ -39,7 +39,7 @@ static const u8 sec_map_100[3] = { PK11_SECTION_SM, PK11_SECTION_LD, PK11_SECTIO
|
||||
static const u8 sec_map_2xx[3] = { PK11_SECTION_WB, PK11_SECTION_LD, PK11_SECTION_SM };
|
||||
static const u8 sec_map_4xx[3] = { PK11_SECTION_LD, PK11_SECTION_SM, PK11_SECTION_WB };
|
||||
|
||||
// ID (Timestamp), KB, TSEC, PK11, SECMON, Warmboot.
|
||||
// Timestamp KB TSEC PK11 SECMON Warmboot
|
||||
static const pkg1_id_t _pkg1_ids[] = {
|
||||
{ "20161121", 0, 0x1900, 0x3FE0, 0x40014020, 0x8000D000 }, // 1.0.0.
|
||||
{ "20170210", 0, 0x1900, 0x3FE0, 0x4002D000, 0x8000D000 }, // 2.0.0 - 2.3.0.
|
||||
@@ -67,7 +67,8 @@ static const pkg1_id_t _pkg1_ids[] = {
|
||||
{ "20230111", 15, 0x0E00, 0x6FE0, 0x40030000, 0x4003E000 }, // 16.0.0 - 16.1.0.
|
||||
{ "20230906", 16, 0x0E00, 0x6FE0, 0x40030000, 0x4003E000 }, // 17.0.0 - 17.0.1.
|
||||
{ "20240207", 17, 0x0E00, 0x6FE0, 0x40030000, 0x4003E000 }, // 18.0.0 - 18.1.0.
|
||||
{ "20240808", 18, 0x0E00, 0x6FE0, 0x40030000, 0x4003E000 }, // 19.0.0+
|
||||
{ "20240808", 18, 0x0E00, 0x6FE0, 0x40030000, 0x4003E000 }, // 19.0.0 - 19.0.1.
|
||||
{ "20250206", 19, 0x0E00, 0x6FE0, 0x40030000, 0x4003E000 }, // 20.0.0+
|
||||
};
|
||||
|
||||
const pkg1_id_t *pkg1_identify(u8 *pkg1, char *build_date)
|
||||
@@ -124,7 +125,7 @@ const u8 *pkg1_unpack(void *wm_dst, void *sm_dst, void *ldr_dst, const pkg1_id_t
|
||||
// Get correct header mapping.
|
||||
if (id->kb == HOS_KB_VERSION_100 && !memcmp(id->id, "20161121", 8))
|
||||
sec_map = sec_map_100;
|
||||
else if (id->kb >= HOS_KB_VERSION_100 && id->kb <= HOS_KB_VERSION_301)
|
||||
else if (id->kb <= HOS_KB_VERSION_301)
|
||||
sec_map = sec_map_2xx;
|
||||
else
|
||||
sec_map = sec_map_4xx;
|
||||
|
||||
@@ -115,6 +115,8 @@ static const u8 mkey_vector_7xx[HOS_KB_VERSION_MAX - HOS_KB_VERSION_810 + 1][SE_
|
||||
{ 0x58, 0x15, 0xD2, 0xF6, 0x8A, 0xE8, 0x19, 0xAB, 0xFB, 0x2D, 0x52, 0x9D, 0xE7, 0x55, 0xF3, 0x93 },
|
||||
// Master key 17 encrypted with 18. (18.0.0 with 19.0.0)
|
||||
{ 0x4A, 0x01, 0x3B, 0xC7, 0x44, 0x6E, 0x45, 0xBD, 0xE6, 0x5E, 0x2B, 0xEC, 0x07, 0x37, 0x52, 0x86 },
|
||||
// Master key 18 encrypted with 19. (19.0.0 with 20.0.0)
|
||||
{ 0x97, 0xE4, 0x11, 0xAB, 0x22, 0x72, 0x1A, 0x1F, 0x70, 0x5C, 0x00, 0xB3, 0x96, 0x30, 0x05, 0x28 },
|
||||
};
|
||||
|
||||
static bool _pkg2_key_unwrap_validate(pkg2_hdr_t *tmp_test, pkg2_hdr_t *hdr, u8 src_slot, u8 *mkey, const u8 *key_seed)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
* Copyright (c) 2018-2023 CTCaer
|
||||
* Copyright (c) 2018-2025 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,
|
||||
@@ -20,16 +20,17 @@
|
||||
|
||||
#include <bdk.h>
|
||||
|
||||
#define PKG2_MAGIC 0x31324B50
|
||||
#define PKG2_SEC_BASE 0x80000000
|
||||
#define PKG2_MAGIC 0x31324B50
|
||||
#define PKG2_SEC_BASE 0x80000000
|
||||
#define PKG2_SEC_KERNEL 0
|
||||
#define PKG2_SEC_INI1 1
|
||||
#define PKG2_SEC_INI1 1
|
||||
#define PKG2_SEC_UNUSED 2
|
||||
|
||||
#define INI1_MAGIC 0x31494E49
|
||||
|
||||
//! TODO: Update on kernel change if needed.
|
||||
// Offset of OP + 12 is the INI1 offset. On v2 with dynamic crt0 it's + 16.
|
||||
#define PKG2_NEWKERN_GET_INI1_HEURISTIC 0xD2800015
|
||||
#define PKG2_NEWKERN_GET_INI1_HEURISTIC 0xD2800015 // MOV X21, #0.
|
||||
#define PKG2_NEWKERN_START 0x800
|
||||
|
||||
extern u32 pkg2_newkern_ini1_start;
|
||||
|
||||
@@ -9,15 +9,113 @@
|
||||
/* storage control modules to the FatFs module with a defined API. */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
#include <storage/emmc.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <bdk.h>
|
||||
|
||||
#include <libs/fatfs/diskio.h> /* FatFs lower layer API */
|
||||
#include <fatfs_cfg.h>
|
||||
#include "../../storage/sfd.h"
|
||||
|
||||
static u32 sd_rsvd_sectors = 0;
|
||||
static u32 ramdisk_sectors = 0;
|
||||
static u32 emummc_sectors = 0;
|
||||
static u32 sfd_sectors = 0;
|
||||
|
||||
static u32 cur_partition;
|
||||
|
||||
static void save_cur_partition(BYTE pdrv){
|
||||
bool save = false;
|
||||
switch(pdrv){
|
||||
case DRIVE_BOOT1:
|
||||
case DRIVE_BOOT1_1MB:
|
||||
case DRIVE_EMMC:
|
||||
save = true;
|
||||
break;
|
||||
case DRIVE_SD:
|
||||
case DRIVE_RAM:
|
||||
break;
|
||||
case DRIVE_BIS:
|
||||
case DRIVE_EMU:
|
||||
if(nx_emmc_bis_get_storage() == &emmc_storage){
|
||||
save = true;
|
||||
}
|
||||
break;
|
||||
case DRIVE_SFD:
|
||||
if(sfd_get_storage() == &emmc_storage){
|
||||
save = true;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if(save){
|
||||
cur_partition = emmc_storage.partition;
|
||||
}
|
||||
}
|
||||
|
||||
static void restore_cur_partition(BYTE pdrv){
|
||||
bool restore = false;
|
||||
switch(pdrv){
|
||||
case DRIVE_BOOT1:
|
||||
case DRIVE_BOOT1_1MB:
|
||||
case DRIVE_EMMC:
|
||||
restore = true;
|
||||
break;
|
||||
case DRIVE_SD:
|
||||
case DRIVE_RAM:
|
||||
break;
|
||||
case DRIVE_BIS:
|
||||
case DRIVE_EMU:
|
||||
if(nx_emmc_bis_get_storage() == &emmc_storage){
|
||||
restore = true;
|
||||
}
|
||||
break;
|
||||
case DRIVE_SFD:
|
||||
if(sfd_get_storage() == &emmc_storage){
|
||||
restore = true;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if(restore){
|
||||
if(emmc_storage.partition != cur_partition){
|
||||
emmc_set_partition(cur_partition);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool ensure_partition(BYTE pdrv){
|
||||
u8 part;
|
||||
switch(pdrv){
|
||||
case DRIVE_BOOT1:
|
||||
case DRIVE_BOOT1_1MB:
|
||||
part = EMMC_BOOT1;
|
||||
break;
|
||||
case DRIVE_EMMC:
|
||||
part = EMMC_GPP;
|
||||
break;
|
||||
case DRIVE_SD:
|
||||
case DRIVE_RAM:
|
||||
return true;
|
||||
case DRIVE_BIS:
|
||||
case DRIVE_EMU:
|
||||
case DRIVE_SFD:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
if(emmc_storage.partition != part){
|
||||
return emmc_set_partition(part);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Get Drive Status */
|
||||
@@ -49,20 +147,45 @@ DRESULT disk_read (
|
||||
UINT count /* Number of sectors to read */
|
||||
)
|
||||
{
|
||||
switch (pdrv)
|
||||
{
|
||||
case DRIVE_SD:
|
||||
return sdmmc_storage_read(&sd_storage, sector, count, (void *)buff) ? RES_OK : RES_ERROR;
|
||||
case DRIVE_RAM:
|
||||
return ram_disk_read(sector, count, (void *)buff);
|
||||
case DRIVE_EMMC:
|
||||
return sdmmc_storage_read(&emmc_storage, sector, count, (void *)buff) ? RES_OK : RES_ERROR;
|
||||
case DRIVE_BIS:
|
||||
case DRIVE_EMU:
|
||||
return nx_emmc_bis_read(sector, count, (void *)buff) ? RES_OK : RES_ERROR;
|
||||
DRESULT res = RES_OK;
|
||||
|
||||
save_cur_partition(pdrv);
|
||||
|
||||
if(!ensure_partition(pdrv)){
|
||||
res = RES_ERROR;
|
||||
}
|
||||
|
||||
return RES_ERROR;
|
||||
if(res == RES_OK){
|
||||
switch (pdrv)
|
||||
{
|
||||
case DRIVE_SD:
|
||||
res = sdmmc_storage_read(&sd_storage, sector, count, (void *)buff) ? RES_OK : RES_ERROR;
|
||||
break;
|
||||
case DRIVE_RAM:
|
||||
res = ram_disk_read(sector, count, (void *)buff);
|
||||
break;
|
||||
case DRIVE_EMMC:
|
||||
res = sdmmc_storage_read(&emmc_storage, sector, count, (void *)buff) ? RES_OK : RES_ERROR;
|
||||
break;
|
||||
case DRIVE_BIS:
|
||||
case DRIVE_EMU:
|
||||
res = nx_emmc_bis_read(sector, count, (void *)buff) ? RES_OK : RES_ERROR;
|
||||
break;
|
||||
case DRIVE_BOOT1_1MB:
|
||||
res = sdmmc_storage_read(&emmc_storage, sector + (0x100000 / 512), count, buff) ? RES_OK : RES_ERROR;
|
||||
break;
|
||||
case DRIVE_BOOT1:
|
||||
res = sdmmc_storage_read(&emmc_storage, sector, count, buff) ? RES_OK : RES_ERROR;
|
||||
break;
|
||||
case DRIVE_SFD:
|
||||
res = sfd_read(sector, count, buff) ? RES_OK : RES_ERROR;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
restore_cur_partition(pdrv);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
@@ -75,20 +198,47 @@ DRESULT disk_write (
|
||||
UINT count /* Number of sectors to write */
|
||||
)
|
||||
{
|
||||
switch (pdrv)
|
||||
{
|
||||
case DRIVE_SD:
|
||||
return sdmmc_storage_write(&sd_storage, sector, count, (void *)buff) ? RES_OK : RES_ERROR;
|
||||
case DRIVE_RAM:
|
||||
return ram_disk_write(sector, count, (void *)buff);
|
||||
case DRIVE_EMMC:
|
||||
case DRIVE_BIS:
|
||||
return RES_WRPRT;
|
||||
case DRIVE_EMU:
|
||||
return nx_emmc_bis_write(sector, count, (void *)buff) ? RES_OK : RES_ERROR;
|
||||
DRESULT res = RES_OK;
|
||||
|
||||
save_cur_partition(pdrv);
|
||||
|
||||
if(!ensure_partition(pdrv)){
|
||||
res = RES_ERROR;
|
||||
}
|
||||
|
||||
return RES_ERROR;
|
||||
if(res == RES_OK){
|
||||
switch (pdrv)
|
||||
{
|
||||
case DRIVE_SD:
|
||||
res = sdmmc_storage_write(&sd_storage, sector, count, (void *)buff) ? RES_OK : RES_ERROR;
|
||||
break;
|
||||
case DRIVE_RAM:
|
||||
res = ram_disk_write(sector, count, (void *)buff);
|
||||
break;
|
||||
case DRIVE_EMMC:
|
||||
res = sdmmc_storage_write(&emmc_storage, sector, count, (void*)buff) ? RES_OK : RES_ERROR;
|
||||
break;
|
||||
case DRIVE_BIS:
|
||||
res = RES_WRPRT;
|
||||
break;
|
||||
case DRIVE_EMU:
|
||||
res = nx_emmc_bis_write(sector, count, (void *)buff) ? RES_OK : RES_ERROR;
|
||||
break;
|
||||
case DRIVE_BOOT1_1MB:
|
||||
res = sdmmc_storage_write(&emmc_storage, sector + (0x100000 / 512), count, (void*)buff) ? RES_OK : RES_ERROR;
|
||||
break;
|
||||
case DRIVE_BOOT1:
|
||||
res = sdmmc_storage_write(&emmc_storage, sector, count, (void*)buff) ? RES_OK : RES_ERROR;
|
||||
break;
|
||||
case DRIVE_SFD:
|
||||
res = sfd_write(sector, count, (void*)buff) ? RES_OK : RES_ERROR;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
restore_cur_partition(pdrv);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
@@ -137,8 +287,16 @@ DRESULT disk_ioctl (
|
||||
*buf = 32768; // Align to 16MB.
|
||||
break;
|
||||
}
|
||||
}
|
||||
else // Catch all for unknown devices.
|
||||
}else if(pdrv == DRIVE_SFD){
|
||||
switch(cmd){
|
||||
case GET_SECTOR_COUNT:
|
||||
*buf = sfd_sectors;
|
||||
break;
|
||||
case GET_BLOCK_SIZE:
|
||||
*buf = 32768;
|
||||
break;
|
||||
}
|
||||
}else // Catch all for unknown devices.
|
||||
{
|
||||
switch (cmd)
|
||||
{
|
||||
@@ -175,6 +333,9 @@ DRESULT disk_set_info (
|
||||
case DRIVE_EMU:
|
||||
emummc_sectors = *buf;
|
||||
break;
|
||||
case DRIVE_SFD:
|
||||
sfd_sectors = *buf;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -166,7 +166,7 @@
|
||||
*/
|
||||
|
||||
|
||||
#define FF_FS_RPATH 1
|
||||
#define FF_FS_RPATH 2
|
||||
/* This option configures support for relative path.
|
||||
/
|
||||
/ 0: Disable relative path and remove related functions.
|
||||
@@ -179,13 +179,13 @@
|
||||
/ Drive/Volume Configurations
|
||||
/---------------------------------------------------------------------------*/
|
||||
|
||||
#define FF_VOLUMES 5
|
||||
#define FF_VOLUMES 8
|
||||
/* Number of volumes (logical drives) to be used. (1-10) */
|
||||
|
||||
|
||||
#define FF_STR_VOLUME_ID 1
|
||||
// Order is important. Any change to order, must also be reflected to diskio drive enum.
|
||||
#define FF_VOLUME_STRS "sd","ram","emmc","bis","emu"
|
||||
#define FF_VOLUME_STRS "sd","ram","emmc","bis","emu", "boot1", "boot1_1mb", "sfd"
|
||||
/* 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
|
||||
/ number in the path name. FF_VOLUME_STRS defines the volume ID strings for each
|
||||
@@ -301,6 +301,15 @@
|
||||
/ SemaphoreHandle_t and etc. A header file for O/S definitions needs to be
|
||||
/ included somewhere in the scope of ff.h. */
|
||||
|
||||
|
||||
typedef enum {
|
||||
DRIVE_SD = 0,
|
||||
DRIVE_RAM = 1,
|
||||
DRIVE_EMMC = 2,
|
||||
DRIVE_BIS = 3,
|
||||
DRIVE_EMU = 4,
|
||||
DRIVE_BOOT1 = 5,
|
||||
DRIVE_BOOT1_1MB = 6,
|
||||
DRIVE_SFD = 7,
|
||||
} DDRIVE;
|
||||
|
||||
/*--- End of configuration options ---*/
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include <ianos/ianos.h>
|
||||
#include <libs/compr/blz.h>
|
||||
#include <libs/fatfs/ff.h>
|
||||
#include <storage/boot_storage.h>
|
||||
|
||||
#include "frontend/fe_emmc_tools.h"
|
||||
#include "frontend/gui.h"
|
||||
@@ -34,10 +35,10 @@ nyx_config n_cfg;
|
||||
hekate_config h_cfg;
|
||||
|
||||
const volatile ipl_ver_meta_t __attribute__((section ("._ipl_version"))) ipl_ver = {
|
||||
.magic = NYX_MAGIC,
|
||||
.magic = NYX_MAGIC,
|
||||
.version = (NYX_VER_MJ + '0') | ((NYX_VER_MN + '0') << 8) | ((NYX_VER_HF + '0') << 16) | ((NYX_VER_RL) << 24),
|
||||
.rsvd0 = 0,
|
||||
.rsvd1 = 0
|
||||
.rsvd0 = 0,
|
||||
.rsvd1 = 0
|
||||
};
|
||||
|
||||
volatile nyx_storage_t *nyx_str = (nyx_storage_t *)NYX_STORAGE_ADDR;
|
||||
@@ -134,7 +135,7 @@ lv_res_t launch_payload(lv_obj_t *list)
|
||||
strcpy(path,"bootloader/payloads/");
|
||||
strcat(path, filename);
|
||||
|
||||
if (!sd_mount())
|
||||
if (!boot_storage_mount())
|
||||
goto out;
|
||||
|
||||
FIL fp;
|
||||
@@ -174,7 +175,7 @@ lv_res_t launch_payload(lv_obj_t *list)
|
||||
|
||||
f_close(&fp);
|
||||
|
||||
sd_end();
|
||||
boot_storage_end();
|
||||
|
||||
if (size < 0x30000)
|
||||
{
|
||||
@@ -351,8 +352,8 @@ static void _show_errors(int sd_error)
|
||||
|
||||
if (*excp_enabled == EXCP_MAGIC || sd_error)
|
||||
{
|
||||
gfx_clear_grey(0);
|
||||
gfx_con_setpos(0, 0, 0);
|
||||
// gfx_clear_grey(0);
|
||||
// gfx_con_setpos(0, 0, 0);
|
||||
display_backlight_brightness(150, 1000);
|
||||
display_init_window_d_console();
|
||||
display_window_d_console_enable();
|
||||
@@ -440,13 +441,13 @@ void nyx_init_load_res()
|
||||
_show_errors(SD_NO_ERROR);
|
||||
|
||||
// Try 2 times to mount SD card.
|
||||
if (!sd_mount())
|
||||
if (!boot_storage_mount())
|
||||
{
|
||||
// Restore speed to SDR104.
|
||||
sd_end();
|
||||
boot_storage_end();
|
||||
|
||||
// Retry.
|
||||
if (!sd_mount())
|
||||
if (!boot_storage_mount())
|
||||
_show_errors(SD_MOUNT_ERROR); // Fatal.
|
||||
}
|
||||
|
||||
@@ -496,7 +497,7 @@ void nyx_init_load_res()
|
||||
nyx_load_bg_icons();
|
||||
|
||||
// Unmount FAT partition.
|
||||
sd_unmount();
|
||||
boot_storage_unmount();
|
||||
}
|
||||
|
||||
void ipl_main()
|
||||
|
||||
@@ -61,7 +61,7 @@ _reloc_ipl:
|
||||
|
||||
_real_start:
|
||||
/* We place our stack in SDRAM. */
|
||||
LDR SP, =0x83100000
|
||||
LDR SP, =0x4003F000
|
||||
LDR R0, =__bss_start
|
||||
EOR R1, R1, R1
|
||||
LDR R2, =__bss_end
|
||||
|
||||
86
nyx/nyx_gui/storage/sfd.c
Normal file
86
nyx/nyx_gui/storage/sfd.c
Normal file
@@ -0,0 +1,86 @@
|
||||
#include "sfd.h"
|
||||
#include <storage/emmc.h>
|
||||
#include <storage/sdmmc.h>
|
||||
#include <storage/file_based_storage.h>
|
||||
#include <libs/fatfs/diskio.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
static bool file_based;
|
||||
static sdmmc_storage_t *_storage;
|
||||
static u32 _offset;
|
||||
static u32 _size;
|
||||
|
||||
static void ensure_partition(){
|
||||
if(_storage == &emmc_storage){
|
||||
emmc_set_partition(EMMC_GPP);
|
||||
}
|
||||
}
|
||||
|
||||
sdmmc_storage_t *sfd_get_storage(){
|
||||
if(file_based){
|
||||
return NULL;
|
||||
}else{
|
||||
return _storage;
|
||||
}
|
||||
}
|
||||
|
||||
int sfd_read(u32 sector, u32 count, void *buff){
|
||||
int res;
|
||||
if(sector + count > _size){
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(file_based){
|
||||
res = file_based_storage_read(sector, count, buff);
|
||||
}else{
|
||||
ensure_partition();
|
||||
res = sdmmc_storage_read(_storage, sector + _offset, count, buff);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
int sfd_write(u32 sector, u32 count, void *buff){
|
||||
int res;
|
||||
if(sector + count > _size){
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(file_based){
|
||||
res = file_based_storage_write(sector, count, buff);
|
||||
}else{
|
||||
ensure_partition();
|
||||
res = sdmmc_storage_write(_storage, sector + _offset, count, buff);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
bool sfd_init(sdmmc_storage_t *storage, u32 offset, u32 size){
|
||||
_storage = storage;
|
||||
_offset = offset;
|
||||
_size = size;
|
||||
disk_set_info(DRIVE_SFD, SET_SECTOR_COUNT, &size);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool sfd_file_based_init(const char *base_path) {
|
||||
file_based = true;
|
||||
if(!file_based_storage_init(base_path)){
|
||||
gfx_printf("file based init fail\n");
|
||||
return 0;
|
||||
}
|
||||
_size = file_based_storage_get_total_size();
|
||||
disk_set_info(DRIVE_SFD, SET_SECTOR_COUNT, &_size);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void sfd_end(){
|
||||
_storage = NULL;
|
||||
_offset = 0;
|
||||
_size = 0;
|
||||
u32 size = 0;
|
||||
file_based = false;
|
||||
disk_set_info(DRIVE_SFD, SET_SECTOR_COUNT, &size);
|
||||
}
|
||||
16
nyx/nyx_gui/storage/sfd.h
Normal file
16
nyx/nyx_gui/storage/sfd.h
Normal file
@@ -0,0 +1,16 @@
|
||||
#ifndef _SFD_H
|
||||
#define _SFD_H
|
||||
|
||||
#include <storage/sdmmc.h>
|
||||
#include <utils/types.h>
|
||||
|
||||
int sfd_read(u32 sector, u32 count, void *buff);
|
||||
int sfd_write(u32 sector, u32 count, void *buff);
|
||||
|
||||
bool sfd_file_based_init(const char *base_path);
|
||||
bool sfd_init(sdmmc_storage_t *storage, u32 offset, u32 size);
|
||||
void sfd_end();
|
||||
|
||||
sdmmc_storage_t *sfd_get_storage();
|
||||
|
||||
#endif
|
||||
@@ -9,10 +9,13 @@ autonogc=1
|
||||
updater2p=1
|
||||
bootprotect=0
|
||||
|
||||
# Only include above what you want to change from defaults.
|
||||
# config.c in bootloader and Nyx have all the defaults.
|
||||
|
||||
|
||||
{-------- Stock -------}
|
||||
[Stock]
|
||||
fss0=atmosphere/package3
|
||||
pkg3=atmosphere/package3
|
||||
stock=1
|
||||
emummc_force_disable=1
|
||||
|
||||
@@ -26,7 +29,7 @@ emummc_force_disable=1
|
||||
|
||||
{-- Custom Firmwares --}
|
||||
[Atmo Vanilla]
|
||||
fss0=atmosphere/package3
|
||||
pkg3=atmosphere/package3
|
||||
kip1=atmosphere/kips/*
|
||||
|
||||
# Note:
|
||||
@@ -36,11 +39,11 @@ kip1=atmosphere/kips/*
|
||||
|
||||
|
||||
[Atmo EMU]
|
||||
fss0=atmosphere/package3
|
||||
pkg3=atmosphere/package3
|
||||
emummcforce=1
|
||||
|
||||
[Atmo SYS]
|
||||
fss0=atmosphere/package3
|
||||
pkg3=atmosphere/package3
|
||||
emummc_force_disable=1
|
||||
|
||||
# Note:
|
||||
@@ -55,7 +58,7 @@ emummc_force_disable=1
|
||||
|
||||
|
||||
[Atmo EMU2]
|
||||
fss0=atmosphere/package3
|
||||
pkg3=atmosphere/package3
|
||||
emupath=emuMMC/SD02
|
||||
emummcforce=1
|
||||
|
||||
@@ -68,26 +71,26 @@ emummcforce=1
|
||||
|
||||
|
||||
[Atmo with extra kips]
|
||||
fss0=atmosphere/package3
|
||||
pkg3=atmosphere/package3
|
||||
kip1=cfw/mods/mods_extra/*
|
||||
kip1=cfw/mods/mods_extra/single/extra.kip
|
||||
|
||||
# Note:
|
||||
# The above can be used with any fss0 entry. Like the ones above.
|
||||
# You can even override atmosphere (fss0) kips with this.
|
||||
# The above can be used with any pkg3 entry. Like the ones above.
|
||||
# You can even override atmosphere (pkg3) kips with this.
|
||||
# The wildcard '*' like above can be used to load all kips from a selected directory.
|
||||
|
||||
|
||||
{-- Custom Firmwares Old methods --}
|
||||
[CFW FSS0 extra kips & patches]
|
||||
fss0=atmosphere/package3
|
||||
[CFW PKG3 extra kips & patches]
|
||||
pkg3=atmosphere/package3
|
||||
kip1patch=name_of_patch
|
||||
kip1=cfw/mods/mods_extra/*
|
||||
kip1=cfw/mods/mods_extra/single/extra.kip
|
||||
|
||||
# Note:
|
||||
# Both options for kip1 can be used. Wildcard and single.
|
||||
# You can override kips loaded from FSS0/PKG3 if you define them after the fss0 key.
|
||||
# You can override kips loaded from PKG3/FSS0 if you define them after the pkg3 key.
|
||||
# If kip1 patch resides in patches.ini and that file OR the patch for
|
||||
# current HOS version does not exist, it will error out.
|
||||
|
||||
@@ -106,7 +109,7 @@ atmosphere=1
|
||||
|
||||
# Note:
|
||||
# All kips defined method. This can be changed to what is below also.
|
||||
# atmosphere=1 key is IMPORTANT when no FFS0 is defined.
|
||||
# atmosphere=1 key is IMPORTANT when no PKG3/FSS0 is defined.
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user