Compare commits

..

115 Commits

Author SHA1 Message Date
Christoph Baumann
e2968c69dc fix button map styling 2025-10-10 22:28:41 +02:00
Christoph Baumann
bc42579f01 boot_storage_mount: only deinitialize storage, if it wasnt initialized to begin with 2025-10-09 12:36:35 +02:00
Christoph Baumann
335b8b9a94 ensure sd/emmc get disabled 2025-09-12 23:08:38 +02:00
Christoph Baumann
e1e2366684 make sure both sd and emmc are deinitialized 2025-06-20 18:15:38 +02:00
CTCaer
b0690a7280 Bump hekate to v6.3.1 2025-06-14 18:52:51 +02:00
CTCaer
7f0835a548 hos: bail if requested emummc patch is not applied 2025-06-14 18:52:43 +02:00
CTCaer
5704004bc8 hos: 20.1.0 FS support 2025-06-14 18:52:33 +02:00
Christoph Baumann
c7e1f5c09f fix emmc end 2025-05-25 15:30:33 +02:00
Christoph Baumann
50170f7cf2 set legacy bootable flag on fat partition if android or l4t is enabled 2025-05-23 18:06:06 +02:00
Christoph Baumann
52dba9a5a5 use correct storage when checking if can flash android 2025-05-23 18:05:27 +02:00
Christoph Baumann
db519a454b fix partition set 2025-05-22 18:42:48 +02:00
Christoph Baumann
f8436d1247 fix mem_mode_auto config 2025-05-22 18:42:33 +02:00
Christoph Baumann
6340881f59 disable console 2025-05-21 23:04:33 +02:00
Christoph Baumann
8405a86937 make sure same fs version is set for emusd and emummc config 2025-05-21 20:32:34 +02:00
Christoph Baumann
a3f5e33625 init sd card when emusd inactive 2025-05-21 16:52:33 +02:00
Christoph Baumann
cfc2febc1b dont unmute console 2025-05-21 16:52:16 +02:00
Christoph Baumann
d6fda80057 remove prints, fix backup/restore 2025-05-21 12:31:17 +02:00
Christoph Baumann
37c8874930 add option to determine memory mode from physical memory 2025-05-21 01:17:44 +02:00
Christoph Baumann
37a016122c fix message 2025-05-21 00:04:44 +02:00
Christoph Baumann
9b95d026f3 support for file based and sd partition based emusd 2025-05-20 00:40:48 +02:00
Christoph Baumann
865b9dc1a4 Change some messages and other stuff 2025-05-19 01:27:30 +02:00
Christoph Baumann
7ebceb78bd add emusd.c 2025-05-14 02:51:21 +02:00
Christoph Baumann
154ed594fc Support for hekate to boot hos with emusd/emmc base emummc 2025-05-14 02:24:33 +02:00
Christoph Baumann
af39c76b3a Fix size partition indicators 2025-05-13 18:06:32 +02:00
Christoph Baumann
657b895aaf Fix Android partition size slider range 2025-05-13 17:02:36 +02:00
Christoph Baumann
52a1e0ba67 Correct android reserved size 2025-05-13 16:28:12 +02:00
CTCaer
f3b104e234 Bump hekate to v6.3.0 and Nyx to v1.7.0 2025-05-13 16:27:57 +02:00
CTCaer
a5a2235b9d Update readme
Add sys/l4t folder description, simplify some wording and also add `sld_type` key.
2025-05-13 16:27:52 +02:00
CTCaer
4c58708253 l4t: use strtol for sld_type 2025-05-13 16:27:49 +02:00
CTCaer
cbac787cff Change several makefile prints
Silence some, fix newline to others.
2025-05-13 16:27:44 +02:00
CTCaer
082490deda hos: add 20.0.0 support 2025-05-13 16:27:36 +02:00
CTCaer
72b0f42514 nyx: info: move sd FAT info after showing errors 2025-05-13 16:27:25 +02:00
CTCaer
8978ba9e54 bdk: mc: fix warning for arbiter check 2025-05-13 16:27:15 +02:00
CTCaer
74833e19e7 bdk: se: heap is not used anymore 2025-05-13 16:27:09 +02:00
CTCaer
d5d0f79c38 bdk: als: no need to check above 255 with u8 2025-05-13 16:27:04 +02:00
CTCaer
7927cfe818 pkg3: actually skip if instructed 2025-05-13 16:26:52 +02:00
CTCaer
a1f48e858e Add readme info about pkg3kip1skip 2025-05-13 16:26:42 +02:00
CTCaer
fa561b70a4 Enable type limits warning 2025-05-13 16:26:32 +02:00
CTCaer
567f0f66e1 hos: secmon exo: always set private debug mode
It should always be enabled for CFW mode.
2025-05-13 16:26:23 +02:00
CTCaer
b798dd1ef6 hos: secmon exo: fix system_settings.ini parsing
A previous change guarded the setting with exosphere.ini parsing succeeding.
Correct this, so it always gets parsed.
2025-05-13 16:26:01 +02:00
CTCaer
c91cf80f8b nyx: switch to IRAM for stack 2025-05-13 16:25:43 +02:00
CTCaer
dca5df653b nyx: update some messaging 2025-05-13 16:25:33 +02:00
CTCaer
db08fab876 nyx: update clock min year and about to 2025 2025-05-13 16:25:14 +02:00
CTCaer
9adca44fe4 nyx: use the now exported window custom action 2025-05-13 16:20:52 +02:00
CTCaer
c202b4afb1 nyx: emummc: guard for pointer arithmetics
And also explain what type of backup fails on errors.
2025-05-13 16:19:14 +02:00
CTCaer
814ef14f2d hos: add package3 kip skip option
By using `pkg3kip1skip`, any kip internal name that fully matches will be skipped from being loaded and the stock one will be used.

Multiple can be set by setting more lines with it or by using a comma separator.

Only for advanced users.
2025-05-13 16:18:29 +02:00
CTCaer
eaedec7b6e hos: refactor fss to pkg3
To `fss0` config is now renamed to `pkg3`.
`fss0` still works but is deprecated.
Additionally `fss0experimental` key is now renamed to `pkg3ex`
2025-05-13 16:18:10 +02:00
CTCaer
e8addedd2f bdk: se: add 0 byte sha256 support 2025-05-13 16:17:40 +02:00
CTCaer
3c6bb75267 bdk: small refactoring 2025-05-13 16:17:31 +02:00
CTCaer
169c551445 bdk: display: update color mode definitions 2025-05-13 16:17:18 +02:00
CTCaer
7dad628dfc hos: update some comments
And remove unneeded checks.
2025-05-13 16:17:10 +02:00
CTCaer
8ba90ae55f nyx: info: consider FST2 touch panel unknown 2025-05-13 16:16:58 +02:00
CTCaer
fe61c1a374 nyx: info: validate A2 support
Show info about A2 support.
Color coded A2 list:
White: No support
Green: Fully supported
Yellow: CMDQ/Cache needs a quirk
Red: Broken
2025-05-13 16:16:53 +02:00
CTCaer
3412714402 bdk: sdmmc: add extention regs read/parse 2025-05-13 16:16:45 +02:00
CTCaer
2b0591e2b0 bdk: utils: added qsort compare functions
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);
2025-05-13 16:16:30 +02:00
CTCaer
03b30a23c4 nyx: info: fully update sdmmc benchmark
- Changed to relevant A2 spec testing sizes
- Added 95th and 5th percentile IOPS for random test
 Standard numbers in the industry and also helps with pinpointing latency issues
- Size of info and benchmark adjusted so important info underneath is still showing
- Refactored
2025-05-13 16:16:24 +02:00
CTCaer
4f0bba605f nyx: info: use a more advanced ram detection 2025-05-13 16:15:51 +02:00
CTCaer
4cfbef5062 nyx: info: use custom action for hw info window 2025-05-13 16:15:35 +02:00
CTCaer
02281fccf1 fatfs: set default year to 2025 2025-05-13 16:14:54 +02:00
CTCaer
84078e5469 l4t: allow SLD type to be changed or disabled 2025-05-13 16:14:28 +02:00
CTCaer
805686105d l4t: remove unchanged carveout config clear
Also allow wrong dram types to be mapped for T210B01.
The default table used is 0.
2025-05-13 16:14:11 +02:00
CTCaer
eacb4f2844 pkg2: fix ini size when not using mesosphere
Important in case the same ini1 space is used and stock kernel is new.

Additionally, also set the hash for the 3rd section, even if empty.
2025-05-13 16:13:49 +02:00
CTCaer
c8da71229a hos: config: exit the loop after matching cfg key 2025-05-13 16:13:06 +02:00
CTCaer
1a157a33f6 hos: rename atmosphere key to kernelprocid
So it reflects what it does.
2025-05-13 16:12:46 +02:00
CTCaer
f093c9368b hos: small refactor
Also exiting hos_launch is considered always an error.
2025-05-13 16:12:10 +02:00
CTCaer
9a755b895b bdk: dirlist: switch to alphabetical ordering 2025-05-13 16:11:20 +02:00
CTCaer
4c4a63795e bdk: sdmmc: refactor error checking on rw
And also check if card status is ok after a read/write.
2025-05-13 16:11:13 +02:00
CTCaer
04dc8d2a86 bdk: sdmmc: check that cmd timed out if SDSC
Instead of assuming that, check it.
This fix will make SDUC not to be assumed as SDSC.
2025-05-13 16:10:59 +02:00
CTCaer
ed4b638545 bdk: sdmmc: update unstuff_bits to use mod
Since unstuff_bits only supports 128bits, instead of subtracting the correct amount of bits with the offset array, use % 128.
2025-05-13 16:10:48 +02:00
CTCaer
a8a67ee775 nyx: info: use renamed sd storage member 2025-05-13 16:10:27 +02:00
CTCaer
1e54d538fd bdk: sdmmc: small refactor 2025-05-13 16:10:13 +02:00
CTCaer
20487cb8b9 bdk: sdmmc: check for out bounds access 2025-05-13 16:09:06 +02:00
CTCaer
8bc14f1043 bdk: ff: check for cltbl malloc success 2025-05-13 16:08:53 +02:00
CTCaer
c8acea7ad5 bdk: se: remove malloc usage 2025-05-13 16:08:42 +02:00
CTCaer
3ea4fd81f7 bdk: display: remove malloc usage 2025-05-13 16:08:21 +02:00
Christoph Baumann
76508c74e8 file based emmc emummc, some other stuff 2025-05-12 01:24:01 +02:00
Christoph Baumann
79b6df64d6 fix emummc status 2025-05-08 01:52:05 +02:00
Christoph Baumann
0a7a004839 file based emummc on emmc 2025-05-08 01:48:04 +02:00
Christoph Baumann
7521055bec fix name 2025-05-07 17:29:04 +02:00
Christoph Baumann
39d99a77fe remove debug prtint 2025-05-07 17:28:56 +02:00
Christoph Baumann
b0f0e9be47 get actual size of file based emummc instead of reading from gpt 2025-05-07 17:28:47 +02:00
Christoph Baumann
55a4a814e0 fix emummc ums writes 2025-05-07 17:28:11 +02:00
Christoph Baumann
4bfe1fe2cd add missing fsync 2025-05-07 17:27:58 +02:00
Christoph Baumann
6d09e65d85 fix emummc bis 2025-05-07 16:46:48 +02:00
Christoph Baumann
59a173c994 add support for emummc ums, this is terrible plz fix 2025-05-07 16:46:36 +02:00
Christoph Baumann
e5ceb4a2de add mmc types for emummc, used only for emummc ums 2025-05-07 16:45:26 +02:00
Christoph Baumann
ea3dae672e allow configuring size for file based emummc 2025-05-07 16:44:51 +02:00
Christoph Baumann
2af1cc0b8c ums support for file based emummc 2025-05-07 16:42:57 +02:00
Christoph Baumann
942e7defe3 add methods to access file based emummc 2025-05-07 16:42:36 +02:00
Christoph Baumann
39b74dd50d file based bis support 2025-05-07 12:17:13 +02:00
Christoph Baumann
bbe8ddaf66 ask to resize, if emu partition is larger than required 2025-05-06 17:40:53 +02:00
Christoph Baumann
47e030c7fc fix boot drive name 2025-05-06 12:58:44 +02:00
Christoph Baumann
4a127db80b add emusd ums 2025-05-06 12:57:40 +02:00
Christoph Baumann
241b0f2274 . 2025-05-06 12:37:46 +02:00
Christoph Baumann
ba6073610c support for android emmc 2025-05-02 17:08:49 +02:00
Christoph Baumann
70cb99cd0c add symbol to boot storage ums 2025-05-02 17:08:16 +02:00
Christoph Baumann
7941a3d4d6 fix boot storage selection 2025-05-02 17:07:42 +02:00
Christoph Baumann
1ddf9690b1 l4t flashing for emmc 2025-05-02 11:38:44 +02:00
Christoph Baumann
f4d8ee4efc fix ums storage after partitioning 2025-05-02 11:15:52 +02:00
Christoph Baumann
4f72660603 fuck 2025-05-02 01:43:51 +02:00
Christoph Baumann
2440318cb5 emmc bis storage 2025-04-30 11:29:06 +02:00
Christoph Baumann
61e91f79c1 emmc partitioning mostly fixed 2025-04-30 01:36:55 +02:00
Christoph Baumann
bad8566c58 account for 1mb for backup gpt 2025-04-29 12:48:44 +02:00
Christoph Baumann
28796b417b fix indicators, add emmc_mount, various fixes 2025-04-29 12:36:32 +02:00
Christoph Baumann
31c8ad0d88 add drive to access an area on emmc/sd as disk 2025-04-27 01:05:09 +02:00
Christoph Baumann
0be3fd4f64 only show remaining bar when it has non negligible size 2025-04-26 23:42:37 +02:00
Christoph Baumann
3e9def3608 Add emuSD to partition manager, finer emuMMC partition size control, allow double android 2025-04-26 23:37:45 +02:00
Christoph Baumann
678ce79a54 emmc partition layout selection, adjusted emummc partition size steps 2025-04-26 02:34:43 +02:00
Christoph Baumann
b11e8095ed . 2025-04-25 15:29:22 +02:00
Christoph Baumann
849d533200 UMS: check if successfully initialized, don't care about fat mounted 2025-04-24 18:29:24 +02:00
Christoph Baumann
337f219ac6 Support for NYX to load from BOOT1/GPP/SD in that order, UMS option to mount whatever volume is selected as boot storage 2025-04-24 12:06:15 +02:00
Christoph Baumann
4e9e21b3b1 move boot_storage.h/.c to bdk/storage, check result of ensure_partition 2025-04-22 14:25:14 +02:00
Christoph Baumann
fe5e4dc40a use enum for drive numbers 2025-04-22 14:15:45 +02:00
Christoph Baumann
5798dcde0d Add support for reading boot files from FAT partition on BOOT1/GPP/SD in that order
Emummc config is read from boot partition, file based files still read from SD
2025-04-22 13:42:20 +02:00
Christoph Baumann
9d2ec42a9f fatfs: extend gpt support 2025-04-20 19:52:15 +02:00
96 changed files with 9625 additions and 3068 deletions

View File

@@ -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 $@

View File

@@ -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.

View File

@@ -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

View File

@@ -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++)

View File

@@ -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)

View File

@@ -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;

View File

@@ -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));

View File

@@ -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 */

View File

@@ -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 */

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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;
}

View File

@@ -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[] = {

View File

@@ -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

View File

@@ -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
View 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;
}

View 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

View File

@@ -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); }

View File

@@ -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);

View 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;
}

View 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

View 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;
}

View 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
View 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;
}

View File

@@ -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

View File

@@ -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();
}
}

View File

@@ -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

View File

@@ -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);

View File

@@ -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 */

View File

@@ -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(&reg_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(&reg_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;

View File

@@ -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

View File

@@ -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;

View File

@@ -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();

View File

@@ -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;

View File

@@ -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 */

View File

@@ -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

View File

@@ -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];

View File

@@ -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':

View File

@@ -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

View File

@@ -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.

View File

@@ -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);

View File

@@ -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();

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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;
}
}
}

View File

@@ -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;
}

View File

@@ -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.

View File

@@ -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);

View File

@@ -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
View 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;
}

View File

@@ -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

View File

@@ -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.

View File

@@ -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);

View File

@@ -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;
}
/*-----------------------------------------------------------------------*/

View File

@@ -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 ---*/

View File

@@ -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);

View File

@@ -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;
}

View File

@@ -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
View 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);
}
}

View 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

View File

@@ -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 $@

View File

@@ -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 $@

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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

View 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, &sector_mbr, 4, NULL);
f_close(&f);
save_emusd_cfg(part_idx, sector_mbr, NULL, drive);
return FR_OK;
}

View 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

View File

@@ -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);
}

View File

@@ -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);

View File

@@ -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;

View 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;
}

View 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

View File

@@ -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

File diff suppressed because it is too large Load Diff

View 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

View File

@@ -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);

View File

@@ -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)

View File

@@ -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);

View File

@@ -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

View File

@@ -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

View File

@@ -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);

View File

@@ -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.

View File

@@ -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;

View File

@@ -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)

View File

@@ -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;

View File

@@ -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;
}
}

View File

@@ -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 ---*/

View File

@@ -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()

View File

@@ -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
View 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
View 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

View File

@@ -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.