Compare commits

...

84 commits

Author SHA1 Message Date
CTCaer
5e8b01f727 Bump hekate to v6.3.1 2025-05-28 04:54:14 +03:00
CTCaer
95fede4418 hos: bail if requested emummc patch is not applied 2025-05-28 04:53:58 +03:00
CTCaer
f27934388e hos: 20.1.0 FS support 2025-05-28 04:51:34 +03:00
CTCaer
47f8f3d6da Bump hekate to v6.3.0 and Nyx to v1.7.0 2025-04-30 09:28:34 +03:00
CTCaer
ff2b275794 Update readme
Add sys/l4t folder description, simplify some wording and also add `sld_type` key.
2025-04-30 09:28:24 +03:00
CTCaer
85fa62cafc l4t: use strtol for sld_type 2025-04-30 09:27:34 +03:00
CTCaer
75bac23d01 Change several makefile prints
Silence some, fix newline to others.
2025-04-30 09:24:42 +03:00
CTCaer
466beedb28 hos: add 20.0.0 support 2025-04-30 09:22:04 +03:00
CTCaer
57e31c09f9 nyx: info: move sd FAT info after showing errors 2025-04-30 09:15:52 +03:00
CTCaer
b3194f6379 bdk: mc: fix warning for arbiter check 2025-04-30 09:14:32 +03:00
CTCaer
129a70c32d bdk: se: heap is not used anymore 2025-04-30 09:13:55 +03:00
CTCaer
811971dfa0 bdk: als: no need to check above 255 with u8 2025-04-30 09:13:19 +03:00
CTCaer
f3b2d077e3 pkg3: actually skip if instructed 2025-04-30 09:12:39 +03:00
CTCaer
01b5876010 Add readme info about pkg3kip1skip 2025-04-30 08:58:49 +03:00
CTCaer
0981894416 Enable type limits warning 2025-04-30 08:58:26 +03:00
CTCaer
16428c259c hos: secmon exo: always set private debug mode
It should always be enabled for CFW mode.
2025-04-30 08:55:38 +03:00
CTCaer
ed816a44c9 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.
2024-06-19 21:54:14 +03:00
CTCaer
ef9a48033d nyx: switch to IRAM for stack 2025-04-30 08:44:27 +03:00
CTCaer
06f0d2b83f nyx: update some messaging 2025-04-30 08:43:26 +03:00
CTCaer
9e5860e00b nyx: update clock min year and about to 2025 2025-04-30 08:42:00 +03:00
CTCaer
a1b13214bd nyx: partition: correct android reserved size 2025-04-30 08:40:55 +03:00
CTCaer
51512a30bd nyx: improve Nyx reload and auto reload
Check that Nyx exists and also improve detection when SD is removed.
2025-04-30 08:40:25 +03:00
CTCaer
4fff346150 nyx: use the now exported window custom action 2025-04-30 08:38:58 +03:00
CTCaer
9f29f93078 nyx: emummc: guard for pointer arithmetics
And also explain what type of backup fails on errors.
2025-04-30 08:33:08 +03:00
CTCaer
0c8cd08b55 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-04-30 08:30:57 +03:00
CTCaer
f110f97099 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-04-30 08:27:36 +03:00
CTCaer
08872325c8 bdk: se: add 0 byte sha256 support 2025-04-30 08:15:15 +03:00
CTCaer
c07a155cc1 bdk: small refactoring 2025-04-30 08:14:32 +03:00
CTCaer
1d75c30c61 bdk: display: update color mode definitions 2025-04-30 08:11:51 +03:00
CTCaer
21ecb526af hos: update some comments
And remove unneeded checks.
2025-01-24 16:49:32 +02:00
CTCaer
571496d293 nyx: info: consider FST2 touch panel unknown 2025-01-24 16:46:31 +02:00
CTCaer
ea01782c80 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-01-24 16:45:36 +02:00
CTCaer
b9496f81b1 bdk: sdmmc: add extention regs read/parse 2025-01-24 16:42:14 +02:00
CTCaer
94b36f658c 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-01-24 16:33:51 +02:00
CTCaer
9fbdb39390 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-01-24 16:32:42 +02:00
CTCaer
855bf0ba01 nyx: info: use a more advanced ram detection 2025-01-24 16:26:27 +02:00
CTCaer
d27ba04077 nyx: info: use custom action for hw info window 2025-01-24 16:22:19 +02:00
CTCaer
36d415461e fatfs: set default year to 2025 2025-01-24 16:17:05 +02:00
CTCaer
96a2483aca l4t: allow SLD type to be changed or disabled 2025-01-24 16:15:53 +02:00
CTCaer
968528ebfd l4t: remove unchanged carveout config clear
Also allow wrong dram types to be mapped for T210B01.
The default table used is 0.
2025-01-24 16:15:13 +02:00
CTCaer
3630c2a099 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-01-24 16:11:36 +02:00
CTCaer
854df2c4e6 hos: config: exit the loop after matching cfg key 2025-01-24 16:02:31 +02:00
CTCaer
3f25cfba76 hos: rename atmosphere key to kernelprocid
So it reflects what it does.
2025-01-24 16:00:14 +02:00
CTCaer
29be544167 hos: small refactor
Also exiting hos_launch is considered always an error.
2025-01-24 15:53:52 +02:00
CTCaer
7ac47b9ffe bdk: dirlist: switch to alphabetical ordering 2025-01-24 15:46:27 +02:00
CTCaer
595ac2c11e bdk: sdmmc: refactor error checking on rw
And also check if card status is ok after a read/write.
2025-01-24 15:44:33 +02:00
CTCaer
dcd4e4c4ec 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-01-24 15:40:38 +02:00
CTCaer
018ed3f38a 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-01-24 15:39:17 +02:00
CTCaer
0e01a5caa9 nyx: info: use renamed sd storage member 2025-01-24 15:31:15 +02:00
CTCaer
e030a4ad6d bdk: sdmmc: small refactor 2025-01-24 15:30:10 +02:00
CTCaer
5ce22a67dc bdk: sdmmc: check for out bounds access 2025-01-24 15:21:20 +02:00
CTCaer
6c958f16b8 bdk: ff: check for cltbl malloc success 2025-01-24 15:18:35 +02:00
CTCaer
9ba94bae2d bdk: se: remove malloc usage 2025-01-24 15:15:03 +02:00
CTCaer
a47a6d32c6 bdk: display: remove malloc usage 2025-01-24 15:13:28 +02:00
CTCaer
3250b2e32a Bump hekate to v6.2.2 and Nyx to v1.6.4 2024-10-12 17:51:00 +03:00
CTCaer
e3eee73318 nyx: do not spam log on partition restore 2024-10-12 17:50:54 +03:00
CTCaer
81fb318f6b hos: add 19.0.0 support 2024-10-11 13:04:16 +03:00
CTCaer
84f3f7d92a nyx: add 400us sleep in lv task loop
Tiny power save.
2024-10-10 18:28:29 +03:00
CTCaer
788ecb60a3 l4t: bump api to 7 2024-10-10 18:26:19 +03:00
CTCaer
14413ae6bd bdk: timer: restore rtc timer spinlock 2024-10-10 18:22:03 +03:00
CTCaer
1849ac6667 nyx: optimize battery info
- Remove input voltage limit
- Add an extra PD profile
2024-10-10 15:21:32 +03:00
CTCaer
1bec721baf hos: add missing deinit 2024-10-10 15:21:32 +03:00
CTCaer
6fa844b031 hekate/nyx: use updated dirlist 2024-10-09 15:22:16 +03:00
CTCaer
d2fc6379c6 bdk: utils: improve dirlist
Stop doing unnecessary copies during reordering and use pointers for that.
2024-10-09 15:14:44 +03:00
CTCaer
f15af01727 readme: explain what stock basically is even more 2024-10-09 15:10:23 +03:00
CTCaer
69acef4db3 nyx: part manager: change GPT partition colour
Since many confuse that on MBR
2024-10-04 22:19:01 +03:00
CTCaer
cdc1012f50 nyx: part manager: add version on android button
Check partition scheme for android and add the version on the flash button
2024-10-04 22:18:20 +03:00
CTCaer
63c4bdd7d9 nyx: no need to double check for errors 2024-10-04 22:16:36 +03:00
CTCaer
0e23d0e0fd nyx: name button list object appropriately 2024-10-04 22:14:51 +03:00
CTCaer
9463f8aa7d nyx: fix memleak when 10 launcher items are shown 2024-10-04 22:14:23 +03:00
CTCaer
34f8692f5c nyx: do not use global cal0 buf name 2024-10-04 22:12:53 +03:00
CTCaer
9da5149394 minerva: correct init done type 2024-10-04 22:11:41 +03:00
CTCaer
75676a78ff hos: secmon name ini lists properly 2024-10-04 22:10:50 +03:00
CTCaer
66454b934c hos: no need to double check allocated eks 2024-10-04 22:09:54 +03:00
CTCaer
7b60c3d162 hekate/nyx: constify more args 2024-10-04 22:09:06 +03:00
CTCaer
c422d63b64 hekate: tools: fix menu memleak 2024-10-04 22:04:56 +03:00
CTCaer
0acdefb32a hekate: info: remove input voltage limit
It's a useless metric and in HOS it's used incorrectly.
2024-10-04 22:02:34 +03:00
CTCaer
edf00d8e51 bdk: bpmp: add state set function
Some states are controlled via software. So add a function for that.
2024-10-04 21:54:58 +03:00
CTCaer
1a98e3a702 bdk: irq: disable irq if handler error 2024-10-04 21:53:17 +03:00
CTCaer
8bf3bee08b bdk: uart: fix fifo clear
- Do not clear fifo for everything if not needed
- Correct fifo clear checks
2024-10-04 21:52:24 +03:00
CTCaer
f2be59888b bdk: add irq header to bdk header 2024-10-04 21:48:44 +03:00
CTCaer
5c77601f7a bdk: ums: always allow finish reply
Parse scsi cmd failures are handled internally.
2024-10-04 21:47:26 +03:00
CTCaer
9e239df39e bdk: constify various args 2024-10-04 21:45:57 +03:00
CTCaer
b1bc6ebdd8 bdk: joycon: utilize packet id per joycon
Also fix a possible infinite loop
2024-10-04 21:39:35 +03:00
84 changed files with 1632 additions and 1072 deletions

View file

@ -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 |
@ -77,7 +78,7 @@ 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. |
| 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. |
@ -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 | Disables unneeded kernel patching and CFW kips when running stock or semi-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`. |
| 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_MINOR := 3
BLVERSION_HOTFX := 1
BLVERSION_REL := 0
# Nyx Version.
NYXVERSION_MAJOR := 1
NYXVERSION_MINOR := 6
NYXVERSION_HOTFX := 3
NYXVERSION_MINOR := 7
NYXVERSION_HOTFX := 0
NYXVERSION_REL := 0

View file

@ -49,6 +49,7 @@
#include <soc/gpio.h>
#include <soc/hw_init.h>
#include <soc/i2c.h>
#include <soc/irq.h>
#include <soc/kfuse.h>
#include <soc/pinmux.h>
#include <soc/pmc.h>

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,
@ -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++)
@ -935,7 +921,7 @@ void display_move_framebuffer(u32 window, void *fb)
DISPLAY_A(_DIREG(DC_CMD_DISPLAY_WINDOW_HEADER)) = BIT(WINDOW_SELECT + window);
// Get current framebuffer address.
void *fb_curr = (void *)DISPLAY_A(_DIREG(DC_WINBUF_START_ADDR));
const void *fb_curr = (void *)DISPLAY_A(_DIREG(DC_WINBUF_START_ADDR));
u32 win_size = DISPLAY_A(_DIREG(DC_WIN_PRESCALED_SIZE));
win_size = (win_size & 0x7FFF) * ((win_size >> 16) & 0x1FFF);

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

@ -390,7 +390,7 @@ static int _vic_wait_idle()
return 0;
}
void vic_set_surface(vic_surface_t *sfc)
void vic_set_surface(const vic_surface_t *sfc)
{
u32 flip_x = 0;
u32 flip_y = 0;

View file

@ -58,7 +58,7 @@ typedef struct _vic_surface_t
u32 rotation;
} vic_surface_t;
void vic_set_surface(vic_surface_t *sfc);
void vic_set_surface(const vic_surface_t *sfc);
int vic_compose();
int vic_init();
void vic_end();

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

@ -22,7 +22,6 @@
#include <gfx_utils.h>
#include <power/max17050.h>
#include <power/regulator_5v.h>
#include <soc/bpmp.h>
#include <soc/clock.h>
#include <soc/fuse.h>
#include <soc/gpio.h>
@ -223,8 +222,8 @@ typedef struct _jc_hid_in_rpt_t
{
u8 cmd;
u8 pkt_id;
u8 conn_info:4;
u8 batt_info:4;
u8 conn_info:4; // Connection detect.
u8 batt_info:4; // Power info.
u8 btn_right;
u8 btn_shared;
u8 btn_left;
@ -317,9 +316,10 @@ typedef struct _joycon_ctxt_t
u8 uart;
u8 type;
u8 state;
u8 mac[6];
u32 last_received_time;
u32 last_status_req_time;
u8 mac[6];
u8 pkt_id;
u8 rumble_sent;
u8 connected;
u8 detected;
@ -330,11 +330,10 @@ static joycon_ctxt_t jc_l = {0};
static joycon_ctxt_t jc_r = {0};
static bool jc_init_done = false;
static u32 hid_pkt_inc = 0;
static jc_gamepad_rpt_t jc_gamepad;
static u8 _jc_crc(u8 *data, u16 len, u8 init)
static u8 _jc_crc(const u8 *data, u16 len, u8 init)
{
u8 crc = init;
for (u16 i = 0; i < len; i++)
@ -448,7 +447,7 @@ static void _jc_conn_check()
if (jc_l.connected)
_jc_power_supply(UART_C, false);
hid_pkt_inc = 0;
jc_l.pkt_id = 0;
jc_l.connected = false;
jc_l.rumble_sent = false;
@ -465,7 +464,7 @@ static void _jc_conn_check()
if (jc_r.connected)
_jc_power_supply(UART_B, false);
hid_pkt_inc = 0;
jc_r.pkt_id = 0;
jc_r.connected = false;
jc_r.rumble_sent = false;
@ -484,7 +483,7 @@ static void _joycon_send_raw(u8 uart_port, const u8 *buf, u16 size)
uart_wait_xfer(uart_port, UART_TX_IDLE);
}
static u16 _jc_packet_add_uart_hdr(jc_wired_hdr_t *out, u8 wired_cmd, u8 *data, u16 size, bool crc)
static u16 _jc_packet_add_uart_hdr(jc_wired_hdr_t *out, u8 wired_cmd, const u8 *data, u16 size, bool crc)
{
out->uart_hdr.magic[0] = 0x19;
out->uart_hdr.magic[1] = 0x01;
@ -504,7 +503,7 @@ static u16 _jc_packet_add_uart_hdr(jc_wired_hdr_t *out, u8 wired_cmd, u8 *data,
return sizeof(jc_wired_hdr_t);
}
static u16 _jc_hid_output_rpt_craft(jc_wired_hdr_t *rpt, u8 *payload, u16 size, bool crc)
static u16 _jc_hid_output_rpt_craft(jc_wired_hdr_t *rpt, const u8 *payload, u16 size, bool crc)
{
u16 pkt_size = _jc_packet_add_uart_hdr(rpt, JC_WIRED_HID, NULL, 0, crc);
pkt_size += size;
@ -519,22 +518,18 @@ static u16 _jc_hid_output_rpt_craft(jc_wired_hdr_t *rpt, u8 *payload, u16 size,
return pkt_size;
}
static void _jc_send_hid_output_rpt(u8 uart, u8 *payload, u16 size, bool crc)
static void _jc_send_hid_output_rpt(joycon_ctxt_t *jc, jc_hid_out_rpt_t *hid_pkt, u16 size, bool crc)
{
u8 rpt[0x50];
memset(rpt, 0, sizeof(rpt));
u32 rpt_size = _jc_hid_output_rpt_craft((jc_wired_hdr_t *)rpt, payload, size, crc);
hid_pkt->pkt_id = (jc->pkt_id++ & 0xF);
u32 rpt_size = _jc_hid_output_rpt_craft((jc_wired_hdr_t *)rpt, (u8 *)hid_pkt, size, crc);
_joycon_send_raw(uart, rpt, rpt_size);
_joycon_send_raw(jc->uart, rpt, rpt_size);
}
static u8 _jc_hid_pkt_id_incr()
{
return (hid_pkt_inc++ & 0xF);
}
static void _jc_send_hid_cmd(u8 uart, u8 subcmd, u8 *data, u16 size)
static void _jc_send_hid_cmd(joycon_ctxt_t *jc, u8 subcmd, const u8 *data, u16 size)
{
static const u8 rumble_neutral[8] = { 0x00, 0x01, 0x40, 0x40, 0x00, 0x01, 0x40, 0x40 };
static const u8 rumble_init[8] = { 0xc2, 0xc8, 0x03, 0x72, 0xc2, 0xc8, 0x03, 0x72 };
@ -551,47 +546,43 @@ static void _jc_send_hid_cmd(u8 uart, u8 subcmd, u8 *data, u16 size)
// Enable rumble.
hid_pkt->cmd = JC_HID_OUTPUT_RPT;
hid_pkt->pkt_id = _jc_hid_pkt_id_incr();
hid_pkt->subcmd = JC_HID_SUBCMD_RUMBLE_CTL;
hid_pkt->subcmd_data[0] = 1;
if (send_r_rumble)
_jc_send_hid_output_rpt(UART_B, (u8 *)hid_pkt, 0x10, false);
_jc_send_hid_output_rpt(&jc_r, hid_pkt, 0x10, false);
if (send_l_rumble)
_jc_send_hid_output_rpt(UART_C, (u8 *)hid_pkt, 0x10, false);
_jc_send_hid_output_rpt(&jc_l, hid_pkt, 0x10, false);
// Send rumble.
hid_pkt->cmd = JC_HID_RUMBLE_RPT;
hid_pkt->pkt_id = _jc_hid_pkt_id_incr();
memcpy(hid_pkt->rumble, rumble_init, sizeof(rumble_init));
if (send_r_rumble)
_jc_send_hid_output_rpt(UART_B, (u8 *)hid_pkt, 10, false);
_jc_send_hid_output_rpt(&jc_r, hid_pkt, 10, false);
if (send_l_rumble)
_jc_send_hid_output_rpt(UART_C, (u8 *)hid_pkt, 10, false);
_jc_send_hid_output_rpt(&jc_l, hid_pkt, 10, false);
msleep(15);
// Disable rumble.
hid_pkt->cmd = JC_HID_OUTPUT_RPT;
hid_pkt->pkt_id = _jc_hid_pkt_id_incr();
hid_pkt->subcmd = JC_HID_SUBCMD_RUMBLE_CTL;
hid_pkt->subcmd_data[0] = 0;
memcpy(hid_pkt->rumble, rumble_neutral, sizeof(rumble_neutral));
if (send_r_rumble)
_jc_send_hid_output_rpt(UART_B, (u8 *)hid_pkt, 0x10, false);
_jc_send_hid_output_rpt(&jc_r, hid_pkt, 0x10, false);
if (send_l_rumble)
_jc_send_hid_output_rpt(UART_C, (u8 *)hid_pkt, 0x10, false);
_jc_send_hid_output_rpt(&jc_l, hid_pkt, 0x10, false);
}
else
{
bool crc_needed = (jc_l.uart == uart) ? (jc_l.type & JC_ID_HORI) : (jc_r.type & JC_ID_HORI);
bool crc_needed = jc->type & JC_ID_HORI;
hid_pkt->cmd = JC_HID_OUTPUT_RPT;
hid_pkt->pkt_id = _jc_hid_pkt_id_incr();
hid_pkt->subcmd = subcmd;
if (data)
memcpy(hid_pkt->subcmd_data, data, size);
_jc_send_hid_output_rpt(uart, (u8 *)hid_pkt, sizeof(jc_hid_out_rpt_t) + size, crc_needed);
_jc_send_hid_output_rpt(jc, hid_pkt, sizeof(jc_hid_out_rpt_t) + size, crc_needed);
}
}
@ -823,7 +814,7 @@ static bool _jc_send_init_rumble(joycon_ctxt_t *jc)
// Send init rumble or request nx pad status report.
if ((jc_r.connected && !jc_r.rumble_sent) || (jc_l.connected && !jc_l.rumble_sent))
{
_jc_send_hid_cmd(jc->uart, JC_HID_SUBCMD_SND_RUMBLE, NULL, 0);
_jc_send_hid_cmd(jc, JC_HID_SUBCMD_SND_RUMBLE, NULL, 0);
if (jc_l.connected)
jc_l.rumble_sent = true;
@ -864,7 +855,7 @@ static void _jc_req_nx_pad_status(joycon_ctxt_t *jc)
jc->last_status_req_time = get_tmr_ms() + (!jc->sio_mode ? 15 : 7);
}
static bool _jc_validate_pairing_info(u8 *buf, bool *is_hos)
static bool _jc_validate_pairing_info(const u8 *buf, bool *is_hos)
{
u8 crc = 0;
for (u32 i = 0; i < 0x22; i++)
@ -933,13 +924,13 @@ retry:
{
if (!jc_l_found)
{
_jc_send_hid_cmd(jc_l.uart, JC_HID_SUBCMD_SPI_READ, (u8 *)&subcmd_data_l, 5);
_jc_send_hid_cmd(&jc_l, JC_HID_SUBCMD_SPI_READ, (u8 *)&subcmd_data_l, 5);
jc_l.last_status_req_time = get_tmr_ms() + 15;
}
if (!jc_r_found)
{
_jc_send_hid_cmd(jc_r.uart, JC_HID_SUBCMD_SPI_READ, (u8 *)&subcmd_data_r, 5);
_jc_send_hid_cmd(&jc_r, JC_HID_SUBCMD_SPI_READ, (u8 *)&subcmd_data_r, 5);
jc_r.last_status_req_time = get_tmr_ms() + 15;
}
@ -1130,7 +1121,7 @@ static void _jc_init_conn(joycon_ctxt_t *jc)
// Initialize the controller.
u32 retries = 10;
while (!jc->connected)
while (!jc->connected && retries)
{
_joycon_send_raw(jc->uart, sio_init, sizeof(sio_init));
msleep(5);
@ -1239,12 +1230,12 @@ void jc_deinit()
u8 data = HCI_STATE_SLEEP;
if (jc_r.connected && !(jc_r.type & JC_ID_HORI))
{
_jc_send_hid_cmd(UART_B, JC_HID_SUBCMD_HCI_STATE, &data, 1);
_jc_send_hid_cmd(&jc_r, JC_HID_SUBCMD_HCI_STATE, &data, 1);
_jc_rcv_pkt(&jc_r);
}
if (jc_l.connected && !(jc_l.type & JC_ID_HORI))
{
_jc_send_hid_cmd(UART_C, JC_HID_SUBCMD_HCI_STATE, &data, 1);
_jc_send_hid_cmd(&jc_l, JC_HID_SUBCMD_HCI_STATE, &data, 1);
_jc_rcv_pkt(&jc_l);
}
}

View file

@ -4698,13 +4698,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

@ -38,7 +38,7 @@ typedef struct
bool emc_2X_clk_src_is_pllmb;
bool fsp_for_src_freq;
bool train_ram_patterns;
bool init_done;
u32 init_done;
} mtc_config_t;
enum train_mode_t

View file

@ -75,7 +75,7 @@ void bm92t36_get_sink_info(bool *inserted, usb_pd_objects_t *usb_pd)
{
memset(buf, 0, sizeof(buf));
_bm92t36_read_reg(buf, 2, STATUS1_REG);
*inserted = buf[0] & STATUS1_INSERT ? true : false;
*inserted = (buf[0] & STATUS1_INSERT) ? true : false;
}
if (usb_pd)

View file

@ -29,7 +29,8 @@ int bq24193_get_property(enum BQ24193_reg_prop prop, int *value)
{
u8 data;
switch (prop) {
switch (prop)
{
case BQ24193_InputVoltageLimit: // Input voltage limit (mV).
data = bq24193_get_reg(BQ24193_InputSource);
data = (data & BQ24193_INCONFIG_VINDPM_MASK) >> 3;

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,11 +189,10 @@ 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;
}
static void _se_aes_ctr_set(void *ctr)
static void _se_aes_ctr_set(const void *ctr)
{
u32 data[SE_AES_IV_SIZE / 4];
memcpy(data, ctr, SE_AES_IV_SIZE);
@ -226,7 +224,7 @@ u32 se_key_acc_ctrl_get(u32 ks)
return SE(SE_CRYPTO_KEYTABLE_ACCESS_REG + 4 * ks);
}
void se_aes_key_set(u32 ks, void *key, u32 size)
void se_aes_key_set(u32 ks, const void *key, u32 size)
{
u32 data[SE_AES_MAX_KEY_SIZE / 4];
memcpy(data, key, size);
@ -238,7 +236,7 @@ void se_aes_key_set(u32 ks, void *key, u32 size)
}
}
void se_aes_iv_set(u32 ks, void *iv)
void se_aes_iv_set(u32 ks, const void *iv)
{
u32 data[SE_AES_IV_SIZE / 4];
memcpy(data, iv, SE_AES_IV_SIZE);
@ -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

@ -25,8 +25,8 @@ void se_rsa_acc_ctrl(u32 rs, u32 flags);
void se_key_acc_ctrl(u32 ks, u32 flags);
u32 se_key_acc_ctrl_get(u32 ks);
void se_get_aes_keys(u8 *buf, u8 *keys, u32 keysize);
void se_aes_key_set(u32 ks, void *key, u32 size);
void se_aes_iv_set(u32 ks, void *iv);
void se_aes_key_set(u32 ks, const void *key, u32 size);
void se_aes_iv_set(u32 ks, const void *iv);
void se_aes_key_get(u32 ks, void *key, u32 size);
void se_aes_key_clear(u32 ks);
void se_aes_iv_clear(u32 ks);

View file

@ -237,6 +237,7 @@ void bpmp_clk_rate_relaxed(bool enable)
// APB clock affects RTC, PWM, MEMFETCH, APE, USB, SOR PWM,
// I2C host, DC/DSI/DISP. UART gives extra stress.
// 92: 100% success ratio. 93-94: 595-602MHz has 99% success ratio. 95: 608MHz less.
// APB clock max is supposed to be 204 MHz though.
static const u8 pll_divn[] = {
0, // BPMP_CLK_NORMAL: 408MHz 0% - 136MHz APB.
85, // BPMP_CLK_HIGH_BOOST: 544MHz 33% - 136MHz APB.
@ -300,6 +301,13 @@ void bpmp_clk_rate_set(bpmp_freq_t fid)
}
}
// State is reset to RUN on any clock or source set via SW.
void bpmp_state_set(bpmp_state_t state)
{
u32 cfg = CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) & ~0xF0000000u;
CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = cfg | (state << 28u);
}
// The following functions halt BPMP to reduce power while sleeping.
// They are not as accurate as RTC at big values but they guarantee time+ delay.
void bpmp_usleep(u32 us)

View file

@ -54,6 +54,16 @@ typedef enum
BPMP_CLK_MAX
} bpmp_freq_t;
typedef enum
{
BPMP_STATE_STANDBY = 0, // 32KHz.
BPMP_STATE_IDLE = 1,
BPMP_STATE_RUN = 2,
BPMP_STATE_IRQ = BIT(2),
BPMP_STATE_FIQ = BIT(3),
} bpmp_state_t;
#define BPMP_CLK_LOWEST_BOOST BPMP_CLK_HIGH2_BOOST
#define BPMP_CLK_LOWER_BOOST BPMP_CLK_SUPER_BOOST
#define BPMP_CLK_DEFAULT_BOOST BPMP_CLK_HYPER_BOOST
@ -65,6 +75,7 @@ void bpmp_mmu_disable();
void bpmp_clk_rate_relaxed(bool enable);
void bpmp_clk_rate_get();
void bpmp_clk_rate_set(bpmp_freq_t fid);
void bpmp_state_set(bpmp_state_t state);
void bpmp_usleep(u32 us);
void bpmp_msleep(u32 ms);
void bpmp_halt();

View file

@ -701,7 +701,7 @@ static void _clock_sdmmc_clear_enable(u32 id)
static void _clock_sdmmc_config_legacy_tm()
{
clk_rst_t *clk = &_clock_sdmmc_legacy_tm;
const clk_rst_t *clk = &_clock_sdmmc_legacy_tm;
if (!(CLOCK(clk->enable) & BIT(clk->index)))
clock_enable(clk);
}

View file

@ -150,6 +150,7 @@
#define CLK_RST_CONTROLLER_PLLC_MISC_2 0x5D0
#define CLK_RST_CONTROLLER_PLLC4_OUT 0x5E4
#define CLK_RST_CONTROLLER_PLLMB_BASE 0x5E8
#define CLK_RST_CONTROLLER_PLLMB_MISC1 0x5EC
#define CLK_RST_CONTROLLER_CLK_SOURCE_XUSB_FS 0x608
#define CLK_RST_CONTROLLER_CLK_SOURCE_XUSB_CORE_DEV 0x60C
#define CLK_RST_CONTROLLER_CLK_SOURCE_XUSB_SS 0x610

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[] = {
@ -189,7 +191,7 @@ void fuse_read_array(u32 *words)
words[i] = fuse_read(i);
}
static u32 _parity32_even(u32 *words, u32 count)
static u32 _parity32_even(const u32 *words, u32 count)
{
u32 acc = words[0];
for (u32 i = 1; i < count; i++)
@ -303,7 +305,7 @@ int fuse_read_ipatch(void (*ipatch)(u32 offset, u32 value))
u32 words[80];
u32 word_count;
u32 word_addr;
u32 word0 = 0;
u32 word0;
u32 total_read = 0;
word_count = FUSE(FUSE_FIRST_BOOTROM_PATCH_SIZE);
@ -363,7 +365,7 @@ int fuse_read_evp_thunk(u32 *iram_evp_thunks, u32 *iram_evp_thunks_len)
u32 words[80];
u32 word_count;
u32 word_addr;
u32 word0 = 0;
u32 word0;
u32 total_read = 0;
int evp_thunk_written = 0;
void *evp_thunk_dst_addr = 0;

View file

@ -96,7 +96,7 @@ static void _i2c_load_cfg_wait(vu32 *base)
}
}
static int _i2c_send_single(u32 i2c_idx, u32 dev_addr, u8 *buf, u32 size)
static int _i2c_send_single(u32 i2c_idx, u32 dev_addr, const u8 *buf, u32 size)
{
if (size > 8)
return 0;
@ -384,7 +384,7 @@ int i2c_recv_buf_big(u8 *buf, u32 size, u32 i2c_idx, u32 dev_addr, u32 reg)
return _i2c_recv_pkt(i2c_idx, buf, size, dev_addr, reg);
}
int i2c_send_buf_small(u32 i2c_idx, u32 dev_addr, u32 reg, u8 *buf, u32 size)
int i2c_send_buf_small(u32 i2c_idx, u32 dev_addr, u32 reg, const u8 *buf, u32 size)
{
u8 tmp[8];

View file

@ -31,7 +31,7 @@ void i2c_init(u32 i2c_idx);
int i2c_recv_buf(u8 *buf, u32 size, u32 i2c_idx, u32 dev_addr);
int i2c_send_buf_big(u32 i2c_idx, u32 dev_addr, u8 *buf, u32 size);
int i2c_recv_buf_big(u8 *buf, u32 size, u32 i2c_idx, u32 dev_addr, u32 reg);
int i2c_send_buf_small(u32 i2c_idx, u32 dev_addr, u32 reg, u8 *buf, u32 size);
int i2c_send_buf_small(u32 i2c_idx, u32 dev_addr, u32 reg, const u8 *buf, u32 size);
int i2c_recv_buf_small(u8 *buf, u32 size, u32 i2c_idx, u32 dev_addr, u32 reg);
int i2c_send_byte(u32 i2c_idx, u32 dev_addr, u32 reg, u8 val);
u8 i2c_recv_byte(u32 i2c_idx, u32 dev_addr, u32 reg);

View file

@ -124,8 +124,8 @@ static irq_status_t _irq_handle_source(u32 irq)
}
}
// Do not re-enable if not handled.
if (status == IRQ_NONE)
// Do not re-enable if not handled or error.
if (status != IRQ_HANDLED)
return status;
if (irqs[idx].flags & IRQ_FLAG_ONE_OFF)

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

@ -25,6 +25,8 @@
#define EXCP_TYPE_ADDR 0x4003FFF8
#define EXCP_TYPE_WDT 0x544457 // "WDT".
#define USE_RTC_TIMER
u32 get_tmr_s()
{
(void)RTC(APBDEV_RTC_MILLI_SECONDS);

View file

@ -174,14 +174,14 @@ void uart_empty_fifo(u32 idx, u32 which)
(void)uart->UART_SPR;
usleep(96);
uart->UART_IIR_FCR = UART_IIR_FCR_EN_FIFO | UART_IIR_FCR_TX_CLR | UART_IIR_FCR_RX_CLR;
uart->UART_IIR_FCR = UART_IIR_FCR_EN_FIFO | which;
(void)uart->UART_SPR;
usleep(18);
u32 tries = 0;
if (UART_IIR_FCR_TX_CLR & which)
{
while (tries < 10 && uart->UART_LSR & UART_LSR_TMTY)
while (tries < 10 && !(uart->UART_LSR & UART_LSR_TMTY))
{
tries++;
usleep(100);
@ -191,7 +191,7 @@ void uart_empty_fifo(u32 idx, u32 which)
if (UART_IIR_FCR_RX_CLR & which)
{
while (tries < 10 && !uart->UART_LSR & UART_LSR_RDR)
while (tries < 10 && (uart->UART_LSR & UART_LSR_RDR))
{
tries++;
usleep(100);

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;

View file

@ -274,7 +274,7 @@ void *sd_file_read(const char *path, u32 *fsize)
return buf;
}
int sd_save_to_file(void *buf, u32 size, const char *filename)
int sd_save_to_file(const void *buf, u32 size, const char *filename)
{
FIL fp;
u32 res = 0;

View file

@ -61,6 +61,6 @@ void sd_unmount();
void sd_end();
bool sd_is_gpt();
void *sd_file_read(const char *path, u32 *fsize);
int sd_save_to_file(void *buf, u32 size, const char *filename);
int sd_save_to_file(const void *buf, u32 size, const char *filename);
#endif

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(u32 *resp, u32 start, u32 size)
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(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,40 +262,12 @@ int sdmmc_storage_end(sdmmc_storage_t *storage)
return 1;
}
static int _sdmmc_storage_readwrite(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, void *buf, u32 is_write)
{
u8 *bbuf = (u8 *)buf;
u32 sct_off = sector;
u32 sct_total = num_sectors;
bool first_reinit = true;
// Exit if not initialized.
if (!storage->initialized)
return 0;
while (sct_total)
{
u32 blkcnt = 0;
// Retry 5 times if failed.
u32 retries = 5;
do
{
reinit_try:
if (_sdmmc_storage_readwrite_ex(storage, &blkcnt, sct_off, MIN(sct_total, 0xFFFF), bbuf, is_write))
goto out;
else
retries--;
sd_error_count_increment(SD_ERROR_RW_RETRY);
msleep(50);
} while (retries);
// Disk IO failure! Reinit SD/EMMC to a lower speed.
if (storage->sdmmc->id == SDMMC_1 || storage->sdmmc->id == SDMMC_4)
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);
@ -305,22 +294,63 @@ reinit_try:
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;
u32 sct_off = sector;
u32 sct_total = num_sectors;
bool first_reinit = true;
// Exit if not initialized.
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;
// Retry 5 times if failed.
u32 retries = 5;
do
{
reinit_try:
if (_sdmmc_storage_readwrite_ex(storage, &blkcnt, sct_off, MIN(sct_total, 0xFFFF), bbuf, is_write))
goto out;
else
retries--;
sd_error_count_increment(SD_ERROR_RW_RETRY);
msleep(50);
} while (retries);
// Disk IO failure! Reinit SD/EMMC to a lower speed.
if (_sdmmc_storage_handle_io_error(storage, first_reinit))
{
// 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;
goto reinit_try;
}
}
// Failed.
return 0;
@ -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)
@ -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);
@ -783,7 +841,7 @@ static int _sd_storage_execute_app_cmd_type1(sdmmc_storage_t *storage, u32 *resp
}
#ifdef SDMMC_DEBUG_PRINT_SD_REGS
void _sd_storage_debug_print_cid(u32 *raw_cid)
void _sd_storage_debug_print_cid(const u32 *raw_cid)
{
gfx_printf("Card Identification\n");
@ -799,7 +857,7 @@ void _sd_storage_debug_print_cid(u32 *raw_cid)
gfx_printf("--RSVD-- %X\n", unstuff_bits(raw_cid, 20, 4));
}
void _sd_storage_debug_print_csd(u32 *raw_csd)
void _sd_storage_debug_print_csd(const u32 *raw_csd)
{
gfx_printf("\n");
@ -813,7 +871,7 @@ void _sd_storage_debug_print_csd(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,13 +888,13 @@ void _sd_storage_debug_print_csd(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));
}
void _sd_storage_debug_print_scr(u32 *raw_scr)
void _sd_storage_debug_print_scr(const u32 *raw_scr)
{
u32 resp[4];
memcpy(&resp[2], raw_scr, 8);
@ -857,7 +915,7 @@ void _sd_storage_debug_print_scr(u32 *raw_scr)
gfx_printf("--RSVD-- %X\n", unstuff_bits(resp, 36, 2));
}
void _sd_storage_debug_print_ssr(u8 *raw_ssr)
void _sd_storage_debug_print_ssr(const u8 *raw_ssr)
{
u32 raw_ssr0[4]; // 511:384.
u32 raw_ssr1[4]; // 383:256.
@ -870,39 +928,39 @@ void _sd_storage_debug_print_ssr(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
// 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,12 +1110,18 @@ 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)
{
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,
@ -174,20 +174,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 +207,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 +232,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:
@ -575,7 +550,7 @@ static int _sdmmc_setup_read_small_block(sdmmc_t *sdmmc)
return 1;
}
static int _sdmmc_send_cmd(sdmmc_t *sdmmc, sdmmc_cmd_t *cmd, bool is_data_present)
static int _sdmmc_send_cmd(sdmmc_t *sdmmc, const sdmmc_cmd_t *cmd, bool is_data_present)
{
u16 cmdflags = 0;
@ -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;
@ -1025,7 +1002,7 @@ int sdmmc_stop_transmission(sdmmc_t *sdmmc, u32 *rsp)
return result;
}
static int _sdmmc_config_sdma(sdmmc_t *sdmmc, u32 *blkcnt_out, sdmmc_req_t *req)
static int _sdmmc_config_sdma(sdmmc_t *sdmmc, u32 *blkcnt_out, const sdmmc_req_t *req)
{
if (!req->blksize || !req->num_sectors)
return 0;
@ -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

@ -80,7 +80,7 @@ enum {
static jc_cal_t jc_cal_ctx;
static usb_ops_t usb_ops;
static bool _jc_calibration(jc_gamepad_rpt_t *jc_pad)
static bool _jc_calibration(const jc_gamepad_rpt_t *jc_pad)
{
// Calibrate left stick.
if (jc_cal_ctx.cl_step != JC_CAL_MAX_STEPS)

View file

@ -1936,7 +1936,9 @@ int usb_device_gadget_ums(usb_ctxt_t *usbs)
_handle_ep0_ctrl(&ums);
if (_parse_scsi_cmd(&ums, &ums.bulk_ctxt) || (ums.state > UMS_STATE_NORMAL))
_parse_scsi_cmd(&ums, &ums.bulk_ctxt);
if (ums.state > UMS_STATE_NORMAL)
continue;
_handle_ep0_ctrl(&ums);

View file

@ -1011,7 +1011,7 @@ static void _xusb_device_power_down()
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_W_CLR) = BIT(CLK_W_XUSB);
}
static int _xusb_queue_trb(u32 ep_idx, void *trb, bool ring_doorbell)
static int _xusb_queue_trb(u32 ep_idx, const void *trb, bool ring_doorbell)
{
int res = USB_RES_OK;
data_trb_t *next_trb;
@ -1226,7 +1226,7 @@ static int _xusb_wait_ep_stopped(u32 endpoint)
return USB_RES_OK;
}
static int _xusb_handle_transfer_event(transfer_event_trb_t *trb)
static int _xusb_handle_transfer_event(const transfer_event_trb_t *trb)
{
// Advance dequeue list.
data_trb_t *next_trb;
@ -1461,7 +1461,7 @@ static int _xusb_handle_get_ep_status(u32 ep_idx)
return _xusb_issue_data_trb(xusb_ep_status_descriptor, 2, USB_DIR_IN);
}
static int _xusb_handle_get_class_request(usb_ctrl_setup_t *ctrl_setup)
static int _xusb_handle_get_class_request(const usb_ctrl_setup_t *ctrl_setup)
{
u8 _bRequest = ctrl_setup->bRequest;
u16 _wIndex = ctrl_setup->wIndex;
@ -1492,7 +1492,7 @@ stall:
return USB_RES_OK;
}
static int _xusb_handle_get_descriptor(usb_ctrl_setup_t *ctrl_setup)
static int _xusb_handle_get_descriptor(const usb_ctrl_setup_t *ctrl_setup)
{
u32 size;
void *descriptor;
@ -1621,7 +1621,7 @@ static int _xusb_handle_get_descriptor(usb_ctrl_setup_t *ctrl_setup)
return _xusb_issue_data_trb(descriptor, size, USB_DIR_IN);
}
static void _xusb_handle_set_request_dev_address(usb_ctrl_setup_t *ctrl_setup)
static void _xusb_handle_set_request_dev_address(const usb_ctrl_setup_t *ctrl_setup)
{
u32 addr = ctrl_setup->wValue & 0xFF;
@ -1633,7 +1633,7 @@ static void _xusb_handle_set_request_dev_address(usb_ctrl_setup_t *ctrl_setup)
usbd_xotg->device_state = XUSB_ADDRESSED_STS_WAIT;
}
static void _xusb_handle_set_request_configuration(usb_ctrl_setup_t *ctrl_setup)
static void _xusb_handle_set_request_configuration(const usb_ctrl_setup_t *ctrl_setup)
{
usbd_xotg->config_num = ctrl_setup->wValue;

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,
@ -17,21 +17,23 @@
#include <string.h>
#include <stdlib.h>
#include "dirlist.h"
#include <libs/fatfs/ff.h>
#include <mem/heap.h>
#include <utils/types.h>
#define MAX_ENTRIES 64
char *dirlist(const char *directory, const char *pattern, bool includeHiddenFiles, bool parse_dirs)
dirlist_t *dirlist(const char *directory, const char *pattern, bool includeHiddenFiles, bool parse_dirs)
{
int res = 0;
u32 i = 0, j = 0, k = 0;
u32 k = 0;
DIR dir;
FILINFO fno;
char *dir_entries = (char *)zalloc(MAX_ENTRIES * 256);
char *temp = (char *)zalloc(256);
dirlist_t *dir_entries = (dirlist_t *)malloc(sizeof(dirlist_t));
// Setup pointer tree.
for (u32 i = 0; i < DIR_MAX_ENTRIES; i++)
dir_entries->name[i] = &dir_entries->data[i * 256];
if (!pattern && !f_opendir(&dir, directory))
{
@ -47,9 +49,8 @@ char *dirlist(const char *directory, const char *pattern, bool includeHiddenFile
{
if ((fno.fname[0] != '.') && (includeHiddenFiles || !(fno.fattrib & AM_HID)))
{
strcpy(dir_entries + (k * 256), fno.fname);
k++;
if (k > (MAX_ENTRIES - 1))
strcpy(&dir_entries->data[k * 256], fno.fname);
if (++k >= DIR_MAX_ENTRIES)
break;
}
}
@ -62,9 +63,8 @@ char *dirlist(const char *directory, const char *pattern, bool includeHiddenFile
{
if (!(fno.fattrib & AM_DIR) && (fno.fname[0] != '.') && (includeHiddenFiles || !(fno.fattrib & AM_HID)))
{
strcpy(dir_entries + (k * 256), fno.fname);
k++;
if (k > (MAX_ENTRIES - 1))
strcpy(&dir_entries->data[k * 256], fno.fname);
if (++k >= DIR_MAX_ENTRIES)
break;
}
res = f_findnext(&dir, &fno);
@ -74,27 +74,27 @@ char *dirlist(const char *directory, const char *pattern, bool includeHiddenFile
if (!k)
{
free(temp);
free(dir_entries);
return NULL;
}
// Reorder ini files by ASCII ordering.
for (i = 0; i < k - 1 ; i++)
{
for (j = i + 1; j < k; j++)
{
if (strcmp(&dir_entries[i * 256], &dir_entries[j * 256]) > 0)
{
strcpy(temp, &dir_entries[i * 256]);
strcpy(&dir_entries[i * 256], &dir_entries[j * 256]);
strcpy(&dir_entries[j * 256], temp);
}
}
}
// Terminate name list.
dir_entries->name[k] = NULL;
free(temp);
// Reorder ini files Alphabetically.
for (u32 i = 0; i < k - 1 ; i++)
{
for (u32 j = i + 1; j < k; j++)
{
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];
dir_entries->name[j] = tmp;
}
}
}
return dir_entries;
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2018 CTCaer
* 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,
@ -16,4 +16,12 @@
#include <utils/types.h>
char *dirlist(const char *directory, const char *pattern, bool includeHiddenFiles, bool parse_dirs);
#define DIR_MAX_ENTRIES 64
typedef struct _dirlist_t
{
char *name[DIR_MAX_ENTRIES];
char data[DIR_MAX_ENTRIES * 256];
} dirlist_t;
dirlist_t *dirlist(const char *directory, const char *pattern, bool includeHiddenFiles, bool parse_dirs);

View file

@ -53,7 +53,7 @@ ini_sec_t *_ini_create_section(link_t *dst, ini_sec_t *csec, char *name, u8 type
return csec;
}
int ini_parse(link_t *dst, char *ini_path, bool is_dir)
int ini_parse(link_t *dst, const char *ini_path, bool is_dir)
{
FIL fp;
u32 lblen;
@ -62,7 +62,7 @@ int ini_parse(link_t *dst, char *ini_path, bool is_dir)
ini_sec_t *csec = NULL;
char *lbuf = NULL;
char *filelist = NULL;
dirlist_t *filelist = NULL;
char *filename = (char *)malloc(256);
strcpy(filename, ini_path);
@ -85,9 +85,9 @@ int ini_parse(link_t *dst, char *ini_path, bool is_dir)
// Copy ini filename in path string.
if (is_dir)
{
if (filelist[k * 256])
if (filelist->name[k])
{
strcpy(filename + pathlen, &filelist[k * 256]);
strcpy(filename + pathlen, filelist->name[k]);
k++;
}
else

View file

@ -43,7 +43,7 @@ typedef struct _ini_sec_t
u32 color;
} ini_sec_t;
int ini_parse(link_t *dst, char *ini_path, bool is_dir);
int ini_parse(link_t *dst, const char *ini_path, bool is_dir);
char *ini_check_special_section(ini_sec_t *cfg);
void ini_free(link_t *src);

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

@ -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,
@ -29,8 +29,6 @@
#include <storage/sd.h>
#include <utils/util.h>
#define USE_RTC_TIMER
u8 bit_count(u32 val)
{
u8 cnt = 0;
@ -241,6 +239,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.

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

@ -313,17 +313,14 @@ void print_battery_charger_info()
gfx_printf("%k\n\nBattery Charger Info:\n%k", TXT_CLR_CYAN_L, TXT_CLR_DEFAULT);
bq24193_get_property(BQ24193_InputVoltageLimit, &value);
gfx_printf("Input voltage limit: %4d mV\n", value);
bq24193_get_property(BQ24193_InputCurrentLimit, &value);
gfx_printf("Input current limit: %4d mA\n", value);
bq24193_get_property(BQ24193_SystemMinimumVoltage, &value);
gfx_printf("Min voltage limit: %4d mV\n", value);
gfx_printf("System voltage limit: %4d mV\n", value);
bq24193_get_property(BQ24193_FastChargeCurrentLimit, &value);
gfx_printf("Fast charge current limit: %4d mA\n", value);
gfx_printf("Charge current limit: %4d mA\n", value);
bq24193_get_property(BQ24193_ChargeVoltageLimit, &value);
gfx_printf("Charge voltage limit: %4d mV\n", value);

View file

@ -155,6 +155,8 @@ void menu_autorcm()
tui_do_menu(&menu);
emmc_end();
free(ments);
}
#pragma GCC pop_options

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
@ -123,6 +123,8 @@ static const u8 master_kekseed_t210_tsec_v4[HOS_KB_VERSION_MAX - HOS_KB_VERSION_
{ 0x99, 0x22, 0x09, 0x57, 0xA7, 0xF9, 0x5E, 0x94, 0xFE, 0x78, 0x7F, 0x41, 0xD6, 0xE7, 0x56, 0xE6 }, // 16.0.0.
{ 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.
@ -140,6 +142,8 @@ static const u8 master_kekseed_t210b01[HOS_KB_VERSION_MAX - HOS_KB_VERSION_600 +
{ 0xA5, 0xEC, 0x16, 0x39, 0x1A, 0x30, 0x16, 0x08, 0x2E, 0xCF, 0x09, 0x6F, 0x5E, 0x7C, 0xEE, 0xA9 }, // 16.0.0.
{ 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] =
@ -192,7 +196,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++)
{
@ -222,7 +226,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.
@ -260,7 +264,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)
{
@ -292,7 +296,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);
@ -301,7 +305,7 @@ out:
}
}
void hos_eks_clear(u32 kb)
static void _hos_eks_clear(u32 kb)
{
// Check if Erista based unit.
if (h_cfg.t210b01)
@ -314,7 +318,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.
@ -327,7 +331,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:
@ -336,7 +340,20 @@ 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)
{
static bool sbk_is_set = true;
u32 retries = 0;
bool use_tsec = false;
tsec_keys_t tsec_keys;
kb_t *kb_data = (kb_t *)keyblob;
if (kb > HOS_KB_VERSION_MAX)
return 0;
// Do Mariko keygen.
if (h_cfg.t210b01)
{
// Use SBK as Device key 4x unsealer and KEK for mkey in T210B01 units.
se_aes_unwrap_key(10, 14, console_keyseed_4xx);
@ -351,28 +368,13 @@ int hos_keygen_t210b01(u32 kb)
return 1;
}
int hos_keygen(void *keyblob, u32 kb, tsec_ctxt_t *tsec_ctxt, bool stock, bool is_exo)
{
static bool sbk_wiped = false;
u32 retries = 0;
bool use_tsec = false;
tsec_keys_t tsec_keys;
kb_t *kb_data = (kb_t *)keyblob;
if (kb > HOS_KB_VERSION_MAX)
return 0;
if (h_cfg.t210b01)
return hos_keygen_t210b01(kb);
// 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.
}
@ -381,7 +383,7 @@ int hos_keygen(void *keyblob, u32 kb, tsec_ctxt_t *tsec_ctxt, bool stock, bool i
_hos_eks_get();
// Use tsec keygen for old firmware or if EKS keys does not exist for newer.
if (kb <= HOS_KB_VERSION_620 || !h_cfg.eks || (h_cfg.eks && h_cfg.eks->enabled != HOS_EKS_TSEC_VER))
if (kb <= HOS_KB_VERSION_620 || !h_cfg.eks || (h_cfg.eks->enabled != HOS_EKS_TSEC_VER))
use_tsec = true;
if (kb <= HOS_KB_VERSION_600)
@ -410,7 +412,7 @@ int hos_keygen(void *keyblob, u32 kb, tsec_ctxt_t *tsec_ctxt, bool stock, bool i
tsec_ctxt->fw = sd_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;
}
@ -434,7 +436,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;
}
}
@ -568,7 +570,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:
@ -576,7 +578,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;
}
}
@ -698,7 +700,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);
@ -748,7 +750,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;
@ -756,7 +758,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);
@ -774,10 +775,7 @@ 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;
}
@ -785,12 +783,12 @@ int hos_launch(ini_sec_t *cfg)
// Check if SD Card is GPT.
if (sd_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;
@ -802,6 +800,7 @@ int hos_launch(ini_sec_t *cfg)
// Check if stock is enabled and device can boot in OFW.
if (ctxt.stock && (h_cfg.t210b01 || !tools_autorcm_enabled()))
{
sdram_src_pllc(false);
emmc_end();
WPRINTF("\nRebooting to OFW in 5s...");
@ -825,7 +824,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)
@ -877,7 +876,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");
@ -979,7 +978,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;
}
@ -998,7 +997,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];
@ -1025,10 +1024,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++)
@ -1148,6 +1147,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,6 +1199,4 @@ error:
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,
@ -45,7 +45,9 @@ enum {
HOS_KB_VERSION_1600 = 15,
HOS_KB_VERSION_1700 = 16,
HOS_KB_VERSION_1800 = 17,
HOS_KB_VERSION_MAX = HOS_KB_VERSION_1800
HOS_KB_VERSION_1900 = 18,
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.
@ -110,9 +112,9 @@ typedef struct _launch_ctxt_t
bool stock;
bool emummc_forced;
void *fss0;
u32 fss0_hosver;
bool atmosphere;
void *pkg3;
u32 pkg3_hosver;
bool patch_krn_proc_id;
int ucid;
@ -127,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,
@ -21,7 +21,7 @@
#include "hos.h"
#include "hos_config.h"
#include "fss.h"
#include "pkg3.h"
#include <libs/fatfs/ff.h>
//#define DPRINTF(...) gfx_printf(__VA_ARGS__)
@ -58,14 +58,14 @@ 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);
u32 dirlen = 0;
dir[strlen(dir) - 2] = 0;
char *filelist = dirlist(dir, "*.kip*", false, false);
dirlist_t *filelist = dirlist(dir, "*.kip*", false, false);
strcat(dir, "/");
dirlen = strlen(dir);
@ -75,10 +75,10 @@ static int _config_kip1(launch_ctxt_t *ctxt, const char *value)
{
while (true)
{
if (!filelist[i * 256])
if (!filelist->name[i])
break;
strcpy(dir + dirlen, &filelist[i * 256]);
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);
@ -119,9 +119,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 +185,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,9 +255,9 @@ 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)
@ -287,6 +284,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 +292,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 +311,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 +329,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
@ -33,7 +33,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 +143,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.
@ -170,7 +170,9 @@ static const pkg1_id_t _pkg1_ids[] = {
{ "20220801", 14, 17, 0x0E00, 0x6FE0, 0x40030000, 0x4003E000, NULL }, // 15.0.0 - 15.0.1.
{ "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+
{ "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 - 19.0.1.
{ "20250206", 19, 21, 0x0E00, 0x6FE0, 0x40030000, 0x4003E000, NULL }, // 20.0.0+
};
const pkg1_id_t *pkg1_get_latest()

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,6 +37,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
{
@ -170,7 +171,7 @@ static void parse_external_kip_patches()
ext_patches_parsed = true;
}
const pkg2_kernel_id_t *pkg2_identify(u8 *hash)
const pkg2_kernel_id_t *pkg2_identify(const u8 *hash)
{
for (u32 i = 0; i < ARRAY_SIZE(_pkg2_kernel_ids); i++)
{
@ -188,11 +189,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;
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 +231,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 +243,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;
@ -683,6 +686,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 +852,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 +877,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,
@ -24,12 +24,13 @@
#define PKG2_SEC_BASE 0x80000000
#define PKG2_SEC_KERNEL 0
#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
@ -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);
@ -159,7 +159,7 @@ void pkg2_merge_kip(link_t *info, pkg2_kip1_t *kip1);
void pkg2_get_ids(kip1_id_t **ids, u32 *entries);
const char *pkg2_patch_kips(link_t *info, char *patch_names);
const pkg2_kernel_id_t *pkg2_identify(u8 *hash);
const pkg2_kernel_id_t *pkg2_identify(const u8 *hash);
pkg2_hdr_t *pkg2_decrypt(void *data, u8 kb, bool is_exo);
void pkg2_build_encrypt(void *dst, void *hos_ctxt, link_t *kips_info, bool is_exo);

View file

@ -95,7 +95,7 @@ static ini_kip_sec_t *_ini_create_kip_section(link_t *dst, ini_kip_sec_t *ksec,
return ksec;
}
int ini_patch_parse(link_t *dst, char *ini_path)
int ini_patch_parse(link_t *dst, const char *ini_path)
{
FIL fp;
u32 lblen;
@ -154,15 +154,15 @@ int ini_patch_parse(link_t *dst, char *ini_path)
pt->length = strtol(&lbuf[pos], NULL, 16);
pos += str_start + 1;
u8 *buf = malloc(pt->length * 2);
u8 *data = malloc(pt->length * 2);
// Set patch source data.
str_start = _find_patch_section_name(&lbuf[pos], lblen - pos, ',');
pt->src_data = _htoa(NULL, &lbuf[pos], pt->length, buf);
pt->src_data = _htoa(NULL, &lbuf[pos], pt->length, data);
pos += str_start + 1;
// Set patch destination data.
pt->dst_data = _htoa(NULL, &lbuf[pos], pt->length, buf + pt->length);
pt->dst_data = _htoa(NULL, &lbuf[pos], pt->length, data + pt->length);
}
list_append(&ksec->pts, &pt->link);

View file

@ -37,6 +37,6 @@ typedef struct _ini_kip_sec_t
link_t link;
} ini_kip_sec_t;
int ini_patch_parse(link_t *dst, char *ini_path);
int ini_patch_parse(link_t *dst, const char *ini_path);
#endif

View file

@ -794,6 +794,54 @@ static const kip1_patchset_t _fs_patches_1800_exfat[] = {
{ NULL, NULL }
};
static const kip1_patch_t _fs_nogc_1900[] = {
{ KPS(KIP_TEXT) | 0x16F070, 8, KIP1_PATCH_SRC_NO_CHECK, "\xE0\x03\x1F\x2A\xC0\x03\x5F\xD6" },
{ KPS(KIP_TEXT) | 0x195B74, 4, KIP1_PATCH_SRC_NO_CHECK, "\x14\x80\x80\x52" },
{ KPS(KIP_TEXT) | 0x195D74, 4, KIP1_PATCH_SRC_NO_CHECK, "\x16\x80\x80\x52" },
{ 0, 0, NULL, NULL }
};
static const kip1_patchset_t _fs_patches_1900[] = {
{ "nogc", _fs_nogc_1900 },
{ NULL, NULL }
};
static const kip1_patch_t _fs_nogc_1900_exfat[] = {
{ KPS(KIP_TEXT) | 0x17A8A0, 8, KIP1_PATCH_SRC_NO_CHECK, "\xE0\x03\x1F\x2A\xC0\x03\x5F\xD6" },
{ KPS(KIP_TEXT) | 0x1A13A4, 4, KIP1_PATCH_SRC_NO_CHECK, "\x14\x80\x80\x52" },
{ KPS(KIP_TEXT) | 0x1A15A4, 4, KIP1_PATCH_SRC_NO_CHECK, "\x16\x80\x80\x52" },
{ 0, 0, NULL, NULL }
};
static const kip1_patchset_t _fs_patches_1900_exfat[] = {
{ "nogc", _fs_nogc_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[] =
{
@ -857,4 +905,10 @@ static const kip1_id_t _kip_ids[] =
{ "FS", "\x1E\x2C\x64\xB1\xCC\xE2\x78\x24", _fs_patches_1800_exfat }, // FS 18.0.0 exFAT
{ "FS", "\xA3\x39\xF0\x1C\x95\xBF\xA7\x68", _fs_patches_1800 }, // FS 18.1.0
{ "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
};

View file

@ -1,7 +1,7 @@
/*
* Atmosphère Fusée Secondary Storage (Package3) parser.
* Atmosphère Package 3 parser.
*
* Copyright (c) 2019-2024 CTCaer
* 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,
@ -20,7 +20,7 @@
#include <bdk.h>
#include "fss.h"
#include "pkg3.h"
#include "hos.h"
#include "../config.h"
#include <libs/fatfs/ff.h>
@ -31,14 +31,16 @@
extern hekate_config h_cfg;
extern bool is_ipl_updated(void *buf, char *path, bool force);
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
#define PKG3_KIP_SKIP_MAX 16
// FSS0 Content Types.
// 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).
@ -53,11 +55,11 @@ extern bool is_ipl_updated(void *buf, char *path, bool force);
#define CNT_TYPE_EXF 11 // Exosphere Mariko fatal payload.
#define CNT_TYPE_TKG 12 // Tsec Keygen.
// FSS0 Content Flags.
// PKG3 Content Flags.
#define CNT_FLAG0_EXPERIMENTAL BIT(0)
// FSS0 Meta Header.
typedef struct _fss_meta_t
// PKG3 Meta Header.
typedef struct _pkg3_meta_t
{
u32 magic;
u32 size;
@ -67,10 +69,10 @@ typedef struct _fss_meta_t
u32 hos_ver;
u32 version;
u32 git_rev;
} fss_meta_t;
} pkg3_meta_t;
// FSS0 Content Header.
typedef struct _fss_content_t
// PKG3 Content Header.
typedef struct _pkg3_content_t
{
u32 offset;
u32 size;
@ -80,9 +82,9 @@ typedef struct _fss_content_t
u8 flags2;
u32 rsvd1;
char name[0x10];
} fss_content_t;
} pkg3_content_t;
static void _fss_update_r2p()
static void _pkg3_update_r2p()
{
u8 *r2p_payload = sd_file_read("atmosphere/reboot_payload.bin", NULL);
@ -91,10 +93,44 @@ static void _fss_update_r2p()
free(r2p_payload);
}
int parse_fss(launch_ctxt_t *ctxt, const char *path)
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)
{
FIL fp;
char **pkg3_kip1_skip = NULL;
u32 pkg3_kip1_skip_num = 0;
bool stock = false;
bool experimental = false;
@ -108,9 +144,12 @@ int parse_fss(launch_ctxt_t *ctxt, const char *path)
if (kv->val[0] == '1')
stock = true;
if (!strcmp("fss0experimental", kv->key))
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
@ -121,79 +160,93 @@ int parse_fss(launch_ctxt_t *ctxt, const char *path)
return 1;
#endif
// Try to open FSS0.
// Try to open PKG3.
if (f_open(&fp, path, FA_READ) != FR_OK)
return 0;
void *fss = malloc(f_size(&fp));
void *pkg3 = malloc(f_size(&fp));
// Read first 1024 bytes of the FSS0 file.
f_read(&fp, fss, 1024, NULL);
// Read first 1024 bytes of the PKG3 file.
f_read(&fp, pkg3, 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);
// 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 FSS0 and parse it.
if (fss_meta->magic == FSS0_MAGIC)
// Check if valid PKG3 and parse it.
if (pkg3_meta->magic == PKG3_MAGIC)
{
gfx_printf("Atmosphere %d.%d.%d-%08x via FSS0/PKG3\n"
gfx_printf("Atmosphere %d.%d.%d-%08x via 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);
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->atmosphere = true;
ctxt->fss0_hosver = fss_meta->hos_ver;
ctxt->patch_krn_proc_id = true;
ctxt->pkg3_hosver = pkg3_meta->hos_ver;
// Parse FSS0 contents.
fss_content_t *curr_fss_cnt = (fss_content_t *)(fss + fss_meta->cnt_off);
// Parse PKG3 contents.
pkg3_content_t *curr_pkg3_cnt = (pkg3_content_t *)(pkg3 + pkg3_meta->cnt_off);
void *content;
for (u32 i = 0; i < fss_meta->cnt_count; i++)
for (u32 i = 0; i < pkg3_meta->cnt_count; i++)
{
content = (void *)(fss + curr_fss_cnt[i].offset);
content = (void *)(pkg3 + curr_pkg3_cnt[i].offset);
// Check if offset is inside limits.
if ((curr_fss_cnt[i].offset + curr_fss_cnt[i].size) > fss_meta->size)
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_fss_cnt[i].flags0 & CNT_FLAG0_EXPERIMENTAL) && !experimental)
if ((curr_pkg3_cnt[i].flags0 & CNT_FLAG0_EXPERIMENTAL) && !experimental)
continue;
// Prepare content.
switch (curr_fss_cnt[i].type)
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 FSS0 (size %08X)\n", curr_fss_cnt[i].name, curr_fss_cnt[i].size);
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_fss_cnt[i].size;
ctxt->kernel_size = curr_pkg3_cnt[i].size;
ctxt->kernel = content;
break;
case CNT_TYPE_EXO:
ctxt->secmon_size = curr_fss_cnt[i].size;
ctxt->secmon_size = curr_pkg3_cnt[i].size;
ctxt->secmon = content;
break;
case CNT_TYPE_EXF:
ctxt->exofatal_size = curr_fss_cnt[i].size;
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_fss_cnt[i].size;
ctxt->warmboot_size = curr_pkg3_cnt[i].size;
ctxt->warmboot = content;
break;
@ -202,23 +255,28 @@ int parse_fss(launch_ctxt_t *ctxt, const char *path)
}
// Load content to launch context.
f_lseek(&fp, curr_fss_cnt[i].offset);
f_read(&fp, content, curr_fss_cnt[i].size, NULL);
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->fss0 = fss;
ctxt->pkg3 = pkg3;
// Update r2p if needed.
_fss_update_r2p();
_pkg3_update_r2p();
free(pkg3_kip1_skip);
return 1;
}
// Failed. Close and free all.
f_close(&fp);
free(fss);
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

@ -199,7 +199,7 @@ void config_exosphere(launch_ctxt_t *ctxt, u32 warmboot_base)
case 12:
exo_fw_no = EXO_FW_VER(9, 1);
break;
case 13 ... 21: //!TODO: Update on API changes. 21: 18.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;
}
@ -207,10 +207,10 @@ void config_exosphere(launch_ctxt_t *ctxt, u32 warmboot_base)
// Parse exosphere.ini.
if (!ctxt->stock)
{
LIST_INIT(ini_sections);
if (ini_parse(&ini_sections, "exosphere.ini", false))
LIST_INIT(ini_exo_sections);
if (ini_parse(&ini_exo_sections, "exosphere.ini", false))
{
LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_sections, link)
LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_exo_sections, link)
{
// Only parse exosphere section.
if (!(ini_sec->type == INI_CHOICE) || strcmp(ini_sec->name, "exosphere"))
@ -241,14 +241,15 @@ 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)
{
LIST_INIT(ini_sections);
if (ini_parse(&ini_sections, "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_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"))
@ -267,10 +268,9 @@ void config_exosphere(launch_ctxt_t *ctxt, u32 warmboot_base)
}
}
}
}
// 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.

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,
@ -36,10 +36,11 @@
* 4: Arachne Register Cell v3. DRAM OPT and DDR200 changes.
* 5: Arachne Register Cell v4. DRAM FREQ and DDR200 changes.
* 6: Arachne Register Cell v5. Signal quality and performance changes. TZ param changes.
* 7: Arachne Register Cell v6. Decouple of rd/wr latencies.
*/
#define L4T_LOADER_API_REV 6
#define L4T_FIRMWARE_REV 0x36524556 // REV6.
#define L4T_LOADER_API_REV 7
#define L4T_FIRMWARE_REV 0x37524556 // REV7.
#ifdef DEBUG_UART_PORT
#include <soc/uart.h>
@ -271,6 +272,8 @@ typedef struct _l4t_ctxt_t
int ram_oc_opt;
u32 serial_port;
u32 sld_type;
u32 sc7entry_size;
emc_table_t *mtc_table;
@ -287,18 +290,22 @@ typedef struct _l4t_ctxt_t
#define DRAM_VDDQ_OC_MAX_VOLTAGE 650
#define DRAM_T210B01_TBL_MAX_FREQ 1600000
#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" },
@ -379,7 +386,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) {
@ -521,11 +528,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 |
@ -557,11 +559,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 |
@ -598,11 +595,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 |
@ -631,11 +623,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 |
@ -851,7 +838,7 @@ static int _l4t_sc7_exit_config(bool t210b01)
return 1;
}
static void _l4t_bl33_cfg_set_key(char *env, char *key, char *val)
static void _l4t_bl33_cfg_set_key(char *env, const char *key, const char *val)
{
strcat(env, key);
strcat(env, "=");
@ -865,6 +852,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)
{
@ -898,6 +888,8 @@ static void _l4t_set_config(l4t_ctxt_t *ctxt, const ini_sec_t *ini_sec, int entr
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);
@ -1164,7 +1156,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

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

View file

@ -120,7 +120,7 @@ static void _reloc_patcher(u32 payload_dst, u32 payload_src, u32 payload_size)
}
}
bool is_ipl_updated(void *buf, char *path, bool force)
bool is_ipl_updated(void *buf, const char *path, bool force)
{
ipl_ver_meta_t *update_ft = (ipl_ver_meta_t *)(buf + PATCHED_RELOC_SZ + sizeof(boot_cfg_t));
@ -257,9 +257,9 @@ static void _launch_payloads()
{
u8 max_entries = 61;
ment_t *ments = NULL;
char *filelist = NULL;
char *file_sec = NULL;
char *dir = NULL;
dirlist_t *filelist = NULL;
gfx_clear_grey(0x1B);
gfx_con_setpos(0, 0);
@ -286,11 +286,11 @@ static void _launch_payloads()
while (true)
{
if (i > max_entries || !filelist[i * 256])
if (i > max_entries || !filelist->name[i])
break;
ments[i + 2].type = INI_CHOICE;
ments[i + 2].caption = &filelist[i * 256];
ments[i + 2].data = &filelist[i * 256];
ments[i + 2].caption = filelist->name[i];
ments[i + 2].data = filelist->name[i];
i++;
}
@ -444,8 +444,10 @@ 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)
{
@ -587,8 +589,10 @@ 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)
{
@ -1350,7 +1354,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 +1450,7 @@ ment_t ment_top[] = {
MDEF_END()
};
menu_t menu_top = { ment_top, "hekate v6.2.1", 0, 0 };
menu_t menu_top = { ment_top, "hekate v6.3.1", 0, 0 };
extern void pivot_stack(u32 stack_top);

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

@ -85,7 +85,7 @@ typedef struct
bool emc_2X_clk_src_is_pllmb;
bool fsp_for_src_freq;
bool train_ram_patterns;
bool init_done;
u32 init_done;
} mtc_config_t;
enum train_mode_t

View file

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

@ -53,19 +53,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 +91,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,10 +102,10 @@ 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(char *text, bool button_ok)
static lv_obj_t *create_mbox_text(const char *text, bool button_ok)
{
lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL);
lv_obj_set_style(dark_bg, &mbox_darken);
@ -137,7 +137,7 @@ static void _update_filename(char *outFilename, u32 sdPathLen, u32 currPartIdx)
itoa(currPartIdx, &outFilename[sdPathLen], 10);
}
static int _dump_emmc_verify(emmc_tool_gui_t *gui, sdmmc_storage_t *storage, u32 lba_curr, char *outFilename, emmc_part_t *part)
static int _dump_emmc_verify(emmc_tool_gui_t *gui, sdmmc_storage_t *storage, u32 lba_curr, const char *outFilename, const emmc_part_t *part)
{
FIL fp;
FIL hashFp;
@ -621,11 +621,21 @@ static int _dump_emmc_part(emmc_tool_gui_t *gui, char *sd_path, int active_part,
res_read = !sdmmc_storage_read(&sd_storage, lba_curr + sd_sector_off, num, buf);
while (res_read)
{
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);
@ -1118,7 +1128,7 @@ multipart_not_allowed:
manual_system_maintenance(true);
}
return 0;
return -1;
}
else if (!use_multipart && (((u32)((u64)f_size(&fp) >> (u64)9)) != totalSectors)) // Check total restore size vs emmc size.
{
@ -1475,10 +1485,13 @@ void restore_emmc_selected(emmcPartType_t restoreType, emmc_tool_gui_t *gui)
if (!res)
s_printf(txt_buf, "#FFDD00 Failed!#\n");
else
else if (res > 0)
s_printf(txt_buf, "Done!\n");
if (res >= 0)
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, txt_buf);
else
res = 0;
manual_system_maintenance(true);
}
}
@ -1508,10 +1521,13 @@ void restore_emmc_selected(emmcPartType_t restoreType, emmc_tool_gui_t *gui)
if (!res)
s_printf(txt_buf, "#FFDD00 Failed!#\n");
else
else if (res > 0)
s_printf(txt_buf, "Done!\n");
if (res >= 0)
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, txt_buf);
else
res = 0;
manual_system_maintenance(true);
}
emmc_gpt_free(&gpt);
@ -1544,10 +1560,13 @@ void restore_emmc_selected(emmcPartType_t restoreType, emmc_tool_gui_t *gui)
if (!res)
s_printf(txt_buf, "#FFDD00 Failed!#\n");
else
else if (res > 0)
s_printf(txt_buf, "Done!\n");
if (res >= 0)
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, txt_buf);
else
res = 0;
manual_system_maintenance(true);
}
}

View file

@ -143,7 +143,7 @@ void update_emummc_base_folder(char *outFilename, u32 sdPathLen, u32 currPartIdx
itoa(currPartIdx, &outFilename[sdPathLen], 10);
}
static int _dump_emummc_file_part(emmc_tool_gui_t *gui, char *sd_path, sdmmc_storage_t *storage, emmc_part_t *part)
static int _dump_emummc_file_part(emmc_tool_gui_t *gui, char *sd_path, sdmmc_storage_t *storage, const emmc_part_t *part)
{
static const u32 FAT32_FILESIZE_LIMIT = 0xFFFFFFFF;
static const u32 SECTORS_TO_MIB_COEFF = 11;
@ -779,7 +779,7 @@ static int _emummc_raw_derive_bis_keys(emmc_tool_gui_t *gui, u32 resized_count)
// Generate BIS keys.
hos_bis_keygen();
u8 *cal0_buf = malloc(SZ_64K);
u8 *cal0_buff = malloc(SZ_64K);
// Read and decrypt CAL0 for validation of working BIS keys.
emmc_set_partition(EMMC_GPP);
@ -787,11 +787,11 @@ static int _emummc_raw_derive_bis_keys(emmc_tool_gui_t *gui, u32 resized_count)
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_read(0, 0x40, cal0_buf);
nx_emmc_bis_read(0, 0x40, cal0_buff);
nx_emmc_bis_end();
emmc_gpt_free(&gpt);
nx_emmc_cal0_t *cal0 = (nx_emmc_cal0_t *)cal0_buf;
nx_emmc_cal0_t *cal0 = (nx_emmc_cal0_t *)cal0_buff;
// Check keys validity.
if (memcmp(&cal0->magic, "CAL0", 4))
@ -803,7 +803,7 @@ static int _emummc_raw_derive_bis_keys(emmc_tool_gui_t *gui, u32 resized_count)
error = true;
}
free(cal0_buf);
free(cal0_buff);
if (error)
{

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,
@ -38,7 +38,7 @@ extern volatile nyx_storage_t *nyx_str;
extern lv_res_t launch_payload(lv_obj_t *list);
static bool disp_init_done = false;
static bool do_reload = false;
static bool do_auto_reload = false;
lv_style_t hint_small_style;
lv_style_t hint_small_style_white;
@ -200,8 +200,8 @@ static void _save_fb_to_bmp()
if (get_tmr_ms() < timer)
return;
if (do_reload)
return;
if (do_auto_reload)
goto exit;
// Invalidate data.
bpmp_mmu_maintenance(BPMP_MMU_MAINT_INVALID_WAY, false);
@ -304,6 +304,7 @@ static void _save_fb_to_bmp()
manual_system_maintenance(true);
lv_mbox_start_auto_close(mbox, 4000);
exit:
// Set timer to 2s.
timer = get_tmr_ms() + 2000;
}
@ -694,7 +695,7 @@ lv_img_dsc_t *bmp_to_lvimg_obj(const char *path)
img_desc->header.always_zero = 0;
img_desc->header.w = bmpData.size_x;
img_desc->header.h = bmpData.size_y;
img_desc->header.cf = (bitmap[28] == 32) ? LV_IMG_CF_TRUE_COLOR_ALPHA : LV_IMG_CF_TRUE_COLOR;
img_desc->header.cf = (bitmap[28] == 32) ? LV_IMG_CF_TRUE_COLOR_ALPHA : LV_IMG_CF_TRUE_COLOR; // Only LV_IMG_CF_TRUE_COLOR_ALPHA is actually allowed.
img_desc->data_size = bmpData.size - bmpData.offset;
img_desc->data = (u8 *)offset_copy;
@ -815,7 +816,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 +827,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 +867,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 +887,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;
}
@ -928,8 +929,27 @@ static void _launch_hos(u8 autoboot, u8 autoboot_list)
(*main_ptr)();
}
void reload_nyx()
void reload_nyx(lv_obj_t *obj, bool force)
{
if (!force)
{
sd_mount();
// Check that Nyx still exists.
if (f_stat("bootloader/sys/nyx.bin", NULL))
{
sd_unmount();
// Remove lvgl object in case of being invoked from a window.
if (obj)
lv_obj_del(obj);
do_auto_reload = false;
return;
}
}
b_cfg->boot_cfg = BOOT_CFG_AUTOBOOT_EN;
b_cfg->autoboot = 0;
b_cfg->autoboot_list = 0;
@ -947,7 +967,7 @@ void reload_nyx()
static lv_res_t reload_action(lv_obj_t *btns, const char *txt)
{
if (!lv_btnm_get_pressed(btns))
reload_nyx();
reload_nyx(NULL, false);
return mbox_action(btns, txt);
}
@ -969,7 +989,7 @@ static lv_res_t _removed_sd_action(lv_obj_t *btns, const char *txt)
break;
case 2:
sd_end();
do_reload = false;
do_auto_reload = false;
break;
}
@ -978,12 +998,14 @@ static lv_res_t _removed_sd_action(lv_obj_t *btns, const char *txt)
static void _check_sd_card_removed(void *params)
{
static lv_obj_t *dark_bg = NULL;
// 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_auto_reload && sd_get_card_removed())
{
lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL);
dark_bg = lv_obj_create(lv_scr_act(), NULL);
lv_obj_set_style(dark_bg, &mbox_darken);
lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES);
@ -999,16 +1021,16 @@ static void _check_sd_card_removed(void *params)
lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);
lv_obj_set_top(mbox, true);
do_reload = true;
do_auto_reload = true;
}
// If in reload state and card was inserted, reload nyx.
if (do_reload && !sd_get_card_removed())
reload_nyx();
if (do_auto_reload && !sd_get_card_removed())
reload_nyx(dark_bg, false);
}
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 +1046,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 +1254,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"
@ -1394,7 +1416,7 @@ static lv_res_t _create_mbox_payloads(lv_obj_t *btn)
goto out_end;
}
char *filelist = dirlist("bootloader/payloads", NULL, false, false);
dirlist_t *filelist = dirlist("bootloader/payloads", NULL, false, false);
sd_unmount();
u32 i = 0;
@ -1402,9 +1424,9 @@ static lv_res_t _create_mbox_payloads(lv_obj_t *btn)
{
while (true)
{
if (!filelist[i * 256])
if (!filelist->name[i])
break;
lv_list_add(list, NULL, &filelist[i * 256], launch_payload);
lv_list_add(list, NULL, filelist->name[i], launch_payload);
i++;
}
free(filelist);
@ -1440,15 +1462,15 @@ static lv_res_t _launch_more_cfg_action(lv_obj_t *btn)
static lv_res_t _win_launch_close_action(lv_obj_t * btn)
{
// Cleanup icons.
for (u32 i = 0; i < 8; i++)
for (u32 i = 0; i < (n_cfg.entries_5_col ? 10 : 8); i++)
{
lv_obj_t *btn = launch_ctxt.btn[i];
lv_btn_ext_t *ext = lv_obj_get_ext_attr(btn);
lv_obj_t *btns = launch_ctxt.btn[i];
lv_btn_ext_t *ext = lv_obj_get_ext_attr(btns);
if (ext->idx)
{
// This gets latest object, which is the button overlay. So iterate 2 times.
lv_obj_t * img = lv_obj_get_child(btn, NULL);
img = lv_obj_get_child(btn, img);
lv_obj_t * img = lv_obj_get_child(btns, NULL);
img = lv_obj_get_child(btns, img);
lv_img_dsc_t *src = (lv_img_dsc_t *)lv_img_get_src(img);
@ -1832,7 +1854,7 @@ ini_parsing:
}
// Add button mask/radius and align icon.
lv_obj_t *btn = lv_btn_create(launch_ctxt.btn[curr_btn_idx], NULL);
lv_obj_t *btns = lv_btn_create(launch_ctxt.btn[curr_btn_idx], NULL);
u32 btn_width = 200;
u32 btn_height = 200;
if (img_noborder)
@ -1848,25 +1870,25 @@ ini_parsing:
lv_btn_set_style(launch_ctxt.btn[curr_btn_idx], LV_BTN_STYLE_REL, &btn_home_noborder_rel);
lv_btn_set_style(launch_ctxt.btn[curr_btn_idx], LV_BTN_STYLE_PR, &btn_home_noborder_rel);
}
lv_obj_set_size(btn, btn_width, btn_height);
lv_btn_set_style(btn, LV_BTN_STYLE_REL, img_noborder ? &btn_home_noborder_rel : &btn_home_transp_rel);
lv_btn_set_style(btn, LV_BTN_STYLE_PR, &btn_home_transp_pr);
lv_obj_set_size(btns, btn_width, btn_height);
lv_btn_set_style(btns, LV_BTN_STYLE_REL, img_noborder ? &btn_home_noborder_rel : &btn_home_transp_rel);
lv_btn_set_style(btns, LV_BTN_STYLE_PR, &btn_home_transp_pr);
if (img)
lv_obj_align(img, NULL, LV_ALIGN_CENTER, 0, 0);
if (img_noborder)
lv_obj_align(btn, NULL, LV_ALIGN_CENTER, 0, 0);
lv_obj_align(btns, NULL, LV_ALIGN_CENTER, 0, 0);
// Set autoboot index.
ext = lv_obj_get_ext_attr(btn);
ext = lv_obj_get_ext_attr(btns);
ext->idx = entry_idx;
ext = lv_obj_get_ext_attr(launch_ctxt.btn[curr_btn_idx]); // Redundancy.
ext->idx = entry_idx;
// Set action.
if (!more_cfg)
lv_btn_set_action(btn, LV_BTN_ACTION_CLICK, _launch_action);
lv_btn_set_action(btns, LV_BTN_ACTION_CLICK, _launch_action);
else
lv_btn_set_action(btn, LV_BTN_ACTION_CLICK, _launch_more_cfg_action);
lv_btn_set_action(btns, LV_BTN_ACTION_CLICK, _launch_more_cfg_action);
// Set button's label text.
lv_label_set_text(launch_ctxt.label[curr_btn_idx], ini_sec->name);
@ -2079,6 +2101,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 +2154,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 +2377,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,16 +2477,19 @@ 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);
}
// Gui loop.
if (h_cfg.t210b01)
{
// Minerva not supported on T210B01 yet. No power saving.
// Minerva not supported on T210B01 yet. Slight power saving via spinlock.
while (true)
{
lv_task_handler();
usleep(400);
}
}
else
{

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

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019-2022 CTCaer
* 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,
@ -42,8 +42,7 @@ static lv_res_t (*emummc_tools)(lv_obj_t *btn);
static lv_res_t _action_emummc_window_close(lv_obj_t *btn)
{
lv_win_close_action(btn);
close_btn = NULL;
nyx_win_close_action_custom(btn);
// Delete and relaunch main emuMMC window.
lv_obj_del(emummc_manage_window);
@ -749,7 +748,7 @@ static lv_res_t _create_emummc_migrate_action(lv_obj_t * btns, const char * txt)
typedef struct _emummc_images_t
{
char *dirlist;
dirlist_t *dirlist;
u32 part_sector[3];
u32 part_type[3];
u32 part_end[3];
@ -1009,9 +1008,9 @@ static lv_res_t _create_change_emummc_window(lv_obj_t *btn_caller)
FIL fp;
// Check for sd raw partitions, based on the folders in /emuMMC.
while (emummc_img->dirlist[emummc_idx * 256])
while (emummc_img->dirlist->name[emummc_idx])
{
s_printf(path, "emuMMC/%s/raw_based", &emummc_img->dirlist[emummc_idx * 256]);
s_printf(path, "emuMMC/%s/raw_based", emummc_img->dirlist->name[emummc_idx]);
if (!f_stat(path, NULL))
{
@ -1024,21 +1023,21 @@ static lv_res_t _create_change_emummc_window(lv_obj_t *btn_caller)
if ((curr_list_sector == 2) || (emummc_img->part_sector[0] && curr_list_sector >= emummc_img->part_sector[0] &&
curr_list_sector < emummc_img->part_end[0] && emummc_img->part_type[0] != 0x83))
{
s_printf(&emummc_img->part_path[0], "emuMMC/%s", &emummc_img->dirlist[emummc_idx * 256]);
s_printf(&emummc_img->part_path[0], "emuMMC/%s", emummc_img->dirlist->name[emummc_idx]);
emummc_img->part_sector[0] = curr_list_sector;
emummc_img->part_end[0] = 0;
}
else if (emummc_img->part_sector[1] && curr_list_sector >= emummc_img->part_sector[1] &&
curr_list_sector < emummc_img->part_end[1] && emummc_img->part_type[1] != 0x83)
{
s_printf(&emummc_img->part_path[1 * 128], "emuMMC/%s", &emummc_img->dirlist[emummc_idx * 256]);
s_printf(&emummc_img->part_path[1 * 128], "emuMMC/%s", emummc_img->dirlist->name[emummc_idx]);
emummc_img->part_sector[1] = curr_list_sector;
emummc_img->part_end[1] = 0;
}
else if (emummc_img->part_sector[2] && curr_list_sector >= emummc_img->part_sector[2] &&
curr_list_sector < emummc_img->part_end[2] && emummc_img->part_type[2] != 0x83)
{
s_printf(&emummc_img->part_path[2 * 128], "emuMMC/%s", &emummc_img->dirlist[emummc_idx * 256]);
s_printf(&emummc_img->part_path[2 * 128], "emuMMC/%s", emummc_img->dirlist->name[emummc_idx]);
emummc_img->part_sector[2] = curr_list_sector;
emummc_img->part_end[2] = 0;
}
@ -1050,19 +1049,19 @@ static lv_res_t _create_change_emummc_window(lv_obj_t *btn_caller)
u32 file_based_idx = 0;
// Sanitize the directory list with sd file based ones.
while (emummc_img->dirlist[emummc_idx * 256])
while (emummc_img->dirlist->name[emummc_idx])
{
s_printf(path, "emuMMC/%s/file_based", &emummc_img->dirlist[emummc_idx * 256]);
s_printf(path, "emuMMC/%s/file_based", emummc_img->dirlist->name[emummc_idx]);
if (!f_stat(path, NULL))
{
char *tmp = &emummc_img->dirlist[emummc_idx * 256];
memcpy(&emummc_img->dirlist[file_based_idx * 256], tmp, strlen(tmp) + 1);
char *tmp = emummc_img->dirlist->name[emummc_idx];
memcpy(emummc_img->dirlist->name[file_based_idx], tmp, strlen(tmp) + 1);
file_based_idx++;
}
emummc_idx++;
}
emummc_img->dirlist[file_based_idx * 256] = 0;
emummc_img->dirlist->name[file_based_idx] = NULL;
out0:;
static lv_style_t h_style;
@ -1179,9 +1178,9 @@ out0:;
emummc_idx = 0;
// Add file based to the list.
while (emummc_img->dirlist[emummc_idx * 256])
while (emummc_img->dirlist->name[emummc_idx])
{
s_printf(path, "emuMMC/%s", &emummc_img->dirlist[emummc_idx * 256]);
s_printf(path, "emuMMC/%s", emummc_img->dirlist->name[emummc_idx]);
lv_list_add(list_sd_based, NULL, path, _save_file_emummc_cfg_action);

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
@ -24,6 +24,8 @@
#include "../hos/pkg1.h"
#include <libs/fatfs/ff.h>
#include <stdlib.h>
#define SECTORS_TO_MIB_COEFF 11
extern hekate_config h_cfg;
@ -351,9 +353,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 +379,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"
@ -587,7 +609,13 @@ static lv_res_t _create_window_fuses_info_status(lv_obj_t *btn)
strcpy(fuses_hos_version, "16.0.0 - 16.1.0");
break;
case 19:
strcpy(fuses_hos_version, "17.0.0+");
strcpy(fuses_hos_version, "17.0.0 - 18.1.0");
break;
case 20:
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#");
@ -660,7 +688,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:
@ -732,49 +760,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");
@ -937,13 +992,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");
@ -971,7 +1026,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;
}
@ -996,9 +1051,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;
}
@ -1296,12 +1348,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;
@ -1350,30 +1401,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;
@ -1381,7 +1462,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);
@ -1399,10 +1480,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);
@ -1412,22 +1493,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);
@ -1445,49 +1529,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)
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);
@ -1501,29 +1600,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)
@ -1550,6 +1659,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.
@ -1756,7 +1867,7 @@ static lv_res_t _create_window_emmc_info_status(lv_obj_t *btn)
emmc_gpt_parse(&gpt);
u32 idx = 0;
u32 lines_left = 20;
int lines_left = 20;
s_printf(txt_buf + strlen(txt_buf), "#FFBA00 Idx Name Size Offset Sectors#\n");
LIST_FOREACH_ENTRY(emmc_part_t, part, &gpt, link)
{
@ -1808,8 +1919,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"
@ -1841,7 +1952,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);
@ -1862,7 +1973,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"
@ -1871,11 +1982,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);
@ -1982,7 +2093,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,
@ -1991,7 +2102,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)
{
@ -2017,7 +2128,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);
@ -2034,10 +2145,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);
@ -2081,15 +2192,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);
@ -2106,47 +2266,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,
@ -2155,12 +2297,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);
@ -2173,7 +2315,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();
@ -2304,10 +2470,9 @@ static lv_res_t _create_window_battery_status(lv_obj_t *btn)
lv_label_set_static_text(lb_desc2,
"#00DDFF Battery Charger IC Info:#\n"
"Input voltage limit:\n"
"Input current limit:\n"
"Min voltage limit:\n"
"Fast charge current limit:\n"
"System voltage limit:\n"
"Charge current limit:\n"
"Charge voltage limit:\n"
"Charge status:\n"
"Temperature status:\n\n"
@ -2325,12 +2490,9 @@ static lv_res_t _create_window_battery_status(lv_obj_t *btn)
lv_obj_t * lb_val2 = lv_label_create(val2, lb_desc);
// Charger IC info.
bq24193_get_property(BQ24193_InputVoltageLimit, &value);
s_printf(txt_buf, "\n%d mV\n", value);
int iinlim = 0;
bq24193_get_property(BQ24193_InputCurrentLimit, &iinlim);
s_printf(txt_buf + strlen(txt_buf), "%d mA\n", iinlim);
s_printf(txt_buf, "\n%d mA\n", iinlim);
bq24193_get_property(BQ24193_SystemMinimumVoltage, &value);
s_printf(txt_buf + strlen(txt_buf), "%d mV\n", value);
@ -2400,8 +2562,8 @@ static lv_res_t _create_window_battery_status(lv_obj_t *btn)
if (!usb_pd.pdo_no)
strcat(txt_buf, "\nNon PD");
// Limit to 5 profiles so it can fit.
usb_pd.pdo_no = MIN(usb_pd.pdo_no, 5);
// Limit to 6 profiles so it can fit.
usb_pd.pdo_no = MIN(usb_pd.pdo_no, 6);
for (u32 i = 0; i < usb_pd.pdo_no; i++)
{
@ -2552,7 +2714,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,
@ -24,9 +24,9 @@
#include <libs/lvgl/lv_themes/lv_theme_hekate.h>
#include <libs/lvgl/lvgl.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;
@ -432,7 +432,7 @@ static lv_res_t _save_theme_color_action(lv_obj_t *btn)
// Save nyx config.
create_nyx_config_entry(true);
reload_nyx();
reload_nyx(NULL, false);
return LV_RES_OK;
}
@ -954,7 +954,7 @@ save_data:
cal0->gyro_offset[0], cal0->gyro_offset[1], cal0->gyro_offset[2],
cal0->gyro_scale[0], cal0->gyro_scale[1], cal0->gyro_scale[2],
cal0->bd_mac[0], cal0->bd_mac[1], cal0->bd_mac[2], cal0->bd_mac[3], cal0->bd_mac[4], cal0->bd_mac[5]);
if (!error)
error = f_open(&fp, "switchroot/switch.cal", FA_WRITE | FA_CREATE_ALWAYS) ? 4 : 0;
if (!error)
{
@ -1168,13 +1168,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

@ -85,7 +85,7 @@ l4t_flasher_ctxt_t l4t_flash_ctxt;
lv_obj_t *btn_flash_l4t;
lv_obj_t *btn_flash_android;
int _copy_file(const char *src, const char *dst, char *path)
int _copy_file(const char *src, const char *dst, const char *path)
{
FIL fp_src;
FIL fp_dst;
@ -265,7 +265,7 @@ out:
return res;
}
static void _create_gpt_partition(gpt_t *gpt, u8 *gpt_idx, u32 *curr_part_lba, u32 size_lba, char *name, int name_size)
static void _create_gpt_partition(gpt_t *gpt, u8 *gpt_idx, u32 *curr_part_lba, u32 size_lba, const char *name, int name_size)
{
static const u8 linux_part_guid[] = { 0xAF, 0x3D, 0xC6, 0x0F, 0x83, 0x84, 0x72, 0x47, 0x8E, 0x79, 0x3D, 0x69, 0xD8, 0x47, 0x7D, 0xE4 };
u8 random_number[16];
@ -813,7 +813,7 @@ static u32 _get_available_l4t_partition()
return size_sct;
}
static bool _get_available_android_partition()
static int _get_available_android_partition()
{
gpt_t *gpt = zalloc(sizeof(gpt_t));
@ -827,11 +827,17 @@ static bool _get_available_android_partition()
// Find kernel partition.
for (u32 i = 0; i < gpt->header.num_part_ents; i++)
{
if (gpt->entries[i].lba_start && (!memcmp(gpt->entries[i].name, (char[]) { 'L', 0, 'N', 0, 'X', 0 }, 6) || !memcmp(gpt->entries[i].name, (char[]) { 'b', 0, 'o', 0, 'o', 0, 't', 0 }, 8)))
if (gpt->entries[i].lba_start)
{
int found = !memcmp(gpt->entries[i].name, (char[]) { 'b', 0, 'o', 0, 'o', 0, 't', 0 }, 8) ? 2 : 0;
found |= !memcmp(gpt->entries[i].name, (char[]) { 'L', 0, 'N', 0, 'X', 0 }, 6) ? 1 : 0;
if (found)
{
free(gpt);
return true;
return found;
}
}
if (i > 126)
@ -882,7 +888,7 @@ static lv_res_t _action_check_flash_linux(lv_obj_t *btn)
// Find an applicable partition for L4T.
u32 size_sct = _get_available_l4t_partition();
if (!l4t_flash_ctxt.offset_sct || !size_sct || size_sct < 0x800000)
if (!l4t_flash_ctxt.offset_sct || size_sct < 0x800000)
{
lv_label_set_text(lbl_status, "#FFDD00 Error:# No partition found!");
goto error;
@ -2051,9 +2057,9 @@ static void _create_mbox_check_files_total_size()
bar_l4t_ind.body.main_color = LV_COLOR_HEX(0x00DDFF);
bar_l4t_ind.body.grad_color = bar_l4t_ind.body.main_color;
// Set Android bar style.
// Set GPT bar style.
lv_style_copy(&bar_and_ind, lv_theme_get_current()->bar.indic);
bar_and_ind.body.main_color = LV_COLOR_HEX(0xFF8000);
bar_and_ind.body.main_color = LV_COLOR_HEX(0xC000FF);
bar_and_ind.body.grad_color = bar_and_ind.body.main_color;
// Set separator styles.
@ -2065,7 +2071,7 @@ static void _create_mbox_check_files_total_size()
sep_l4t_bg.body.main_color = LV_COLOR_HEX(0x00DDFF);
sep_l4t_bg.body.grad_color = sep_l4t_bg.body.main_color;
lv_style_copy(&sep_and_bg, &sep_emu_bg);
sep_and_bg.body.main_color = LV_COLOR_HEX(0xFF8000);
sep_and_bg.body.main_color = LV_COLOR_HEX(0xC000FF);
sep_and_bg.body.grad_color = sep_and_bg.body.main_color;
char *txt_buf = malloc(SZ_8K);
@ -2685,7 +2691,7 @@ lv_res_t create_window_partition_manager(lv_obj_t *btn)
// Create Android size slider.
lv_obj_t *slider_and = lv_slider_create(h1, NULL);
lv_obj_set_size(slider_and, LV_DPI * 7, LV_DPI / 3);
lv_slider_set_range(slider_and, 0, (part_info.total_sct - extra_sct) / SECTORS_PER_GB - 4); // Subtract android reserved size.
lv_slider_set_range(slider_and, 0, (part_info.total_sct - extra_sct) / SECTORS_PER_GB - (ANDROID_SYSTEM_SIZE_MB / 1024)); // Subtract android reserved size.
lv_slider_set_value(slider_and, 0);
lv_slider_set_style(slider_and, LV_SLIDER_STYLE_BG, &bar_and_bg);
lv_slider_set_style(slider_and, LV_SLIDER_STYLE_INDIC, &bar_and_ind);
@ -2748,26 +2754,34 @@ lv_res_t create_window_partition_manager(lv_obj_t *btn)
// Disable Flash Linux button if partition not found.
u32 size_sct = _get_available_l4t_partition();
if (!l4t_flash_ctxt.offset_sct || !size_sct || size_sct < 0x800000)
if (!l4t_flash_ctxt.offset_sct || size_sct < 0x800000)
{
lv_obj_set_click(btn_flash_l4t, false);
lv_btn_set_state(btn_flash_l4t, LV_BTN_STATE_INA);
}
int part_type_and = _get_available_android_partition();
// Create Flash Android button.
btn_flash_android = lv_btn_create(h1, NULL);
label_btn = lv_label_create(btn_flash_android, NULL);
lv_btn_set_fit(btn_flash_android, true, true);
lv_label_set_static_text(label_btn, SYMBOL_DOWNLOAD" Flash Android");
lv_obj_align(btn_flash_android, btn_flash_l4t, LV_ALIGN_OUT_RIGHT_MID, LV_DPI / 3, 0);
lv_btn_set_action(btn_flash_android, LV_BTN_ACTION_CLICK, _action_flash_android);
// Disable Flash Android button if partition not found.
if (!_get_available_android_partition())
switch (part_type_and)
{
case 0: // Disable Flash Android button if partition not found.
lv_label_set_static_text(label_btn, SYMBOL_DOWNLOAD" Flash Android");
lv_obj_set_click(btn_flash_android, false);
lv_btn_set_state(btn_flash_android, LV_BTN_STATE_INA);
break;
case 1: // Android 10/11.
lv_label_set_static_text(label_btn, SYMBOL_DOWNLOAD" Flash Android 10/11");
break;
case 2: // Android 13+
lv_label_set_static_text(label_btn, SYMBOL_DOWNLOAD" Flash Android 13+");
break;
}
lv_obj_align(btn_flash_android, btn_flash_l4t, LV_ALIGN_OUT_RIGHT_MID, LV_DPI / 3, 0);
lv_btn_set_action(btn_flash_android, LV_BTN_ACTION_CLICK, _action_flash_android);
// Create next step button.
btn1 = lv_btn_create(h1, NULL);

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
@ -76,7 +76,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] =
{ 0x00, 0x04, 0x5D, 0xF0, 0x4D, 0xCD, 0x14, 0xA3, 0x1C, 0xBF, 0xDE, 0x48, 0x55, 0xBA, 0x35, 0xC1 }; // 18.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] = {
@ -93,6 +93,8 @@ static const u8 master_kekseed_t210b01[HOS_KB_VERSION_MAX - HOS_KB_VERSION_600 +
{ 0xA5, 0xEC, 0x16, 0x39, 0x1A, 0x30, 0x16, 0x08, 0x2E, 0xCF, 0x09, 0x6F, 0x5E, 0x7C, 0xEE, 0xA9 }, // 16.0.0.
{ 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] =
@ -124,6 +126,8 @@ static const u8 mkey_vectors[HOS_KB_VERSION_MAX + 1][SE_KEY_128_SIZE] = {
{ 0xAF, 0x11, 0x4C, 0x67, 0x17, 0x7A, 0x52, 0x43, 0xF7, 0x70, 0x2F, 0xC7, 0xEF, 0x81, 0x72, 0x16 }, // Mkey 14 encrypted with mkey 15.
{ 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.
@ -143,6 +147,8 @@ static const u8 new_console_keyseed[HOS_KB_VERSION_MAX - HOS_KB_VERSION_400 + 1]
{ 0xEA, 0x90, 0x6E, 0xA8, 0xAE, 0x92, 0x99, 0x64, 0x36, 0xC1, 0xF3, 0x1C, 0xC6, 0x32, 0x83, 0x8C }, // 16.0.0 New Device Key Source.
{ 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.
@ -162,6 +168,8 @@ static const u8 new_console_kekseed[HOS_KB_VERSION_MAX - HOS_KB_VERSION_400 + 1]
{ 0xF0, 0xF3, 0xFF, 0x52, 0x75, 0x2F, 0xBA, 0x4D, 0x09, 0x72, 0x30, 0x89, 0xA9, 0xDF, 0xFE, 0x1F }, // 16.0.0 New Device Keygen Source.
{ 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] =
@ -265,7 +273,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.
@ -329,7 +337,18 @@ out:
}
}
int hos_keygen_t210b01(u32 kb)
int hos_keygen(void *keyblob, u32 kb, tsec_ctxt_t *tsec_ctxt)
{
u32 retries = 0;
bool use_tsec = false;
tsec_keys_t tsec_keys;
kb_t *kb_data = (kb_t *)keyblob;
if (kb > HOS_KB_VERSION_MAX)
return 0;
// Do Mariko keygen.
if (h_cfg.t210b01)
{
// Use SBK as Device key 4x unsealer and KEK for mkey in T210B01 units.
se_aes_unwrap_key(10, 14, console_keyseed_4xx);
@ -344,26 +363,13 @@ int hos_keygen_t210b01(u32 kb)
return 1;
}
int hos_keygen(void *keyblob, u32 kb, tsec_ctxt_t *tsec_ctxt)
{
u32 retries = 0;
bool use_tsec = false;
tsec_keys_t tsec_keys;
kb_t *kb_data = (kb_t *)keyblob;
if (kb > HOS_KB_VERSION_MAX)
return 0;
if (h_cfg.t210b01)
return hos_keygen_t210b01(kb);
// Do Erista keygen.
// Use HOS EKS if it exists.
_hos_eks_get();
// Use tsec keygen for old firmware or if EKS keys does not exist for newer.
if (kb <= HOS_KB_VERSION_620 || !h_cfg.eks || (h_cfg.eks && h_cfg.eks->enabled != HOS_EKS_TSEC_VER))
if (kb <= HOS_KB_VERSION_620 || !h_cfg.eks || (h_cfg.eks->enabled != HOS_EKS_TSEC_VER))
use_tsec = true;
if (kb <= HOS_KB_VERSION_600)

View file

@ -1,6 +1,6 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (c) 2018-2023 CTCaer
* 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,
@ -45,7 +45,9 @@ enum {
HOS_KB_VERSION_1600 = 15,
HOS_KB_VERSION_1700 = 16,
HOS_KB_VERSION_1800 = 17,
HOS_KB_VERSION_MAX = HOS_KB_VERSION_1800
HOS_KB_VERSION_1900 = 18,
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-2023 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.
@ -66,7 +66,9 @@ static const pkg1_id_t _pkg1_ids[] = {
{ "20220801", 14, 0x0E00, 0x6FE0, 0x40030000, 0x4003E000 }, // 15.0.0 - 15.0.1.
{ "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+
{ "20240207", 17, 0x0E00, 0x6FE0, 0x40030000, 0x4003E000 }, // 18.0.0 - 18.1.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)
@ -123,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

@ -1,6 +1,6 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (c) 2018-2023 CTCaer
* 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,
@ -113,6 +113,10 @@ static const u8 mkey_vector_7xx[HOS_KB_VERSION_MAX - HOS_KB_VERSION_810 + 1][SE_
{ 0x25, 0x12, 0x8B, 0xCB, 0xB5, 0x46, 0xA1, 0xF8, 0xE0, 0x52, 0x15, 0xB7, 0x0B, 0x57, 0x00, 0xBD },
// Master key 16 encrypted with 17. (17.0.0 with 18.0.0)
{ 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,
@ -24,12 +24,13 @@
#define PKG2_SEC_BASE 0x80000000
#define PKG2_SEC_KERNEL 0
#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

@ -402,7 +402,7 @@ error_occured:
msleep(1000);
btn_wait();
reload_nyx();
reload_nyx(NULL, true);
}
}

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

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.