diff --git a/Makefile b/Makefile index f2ba8bb..be95d5c 100755 --- a/Makefile +++ b/Makefile @@ -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 $@ diff --git a/README.md b/README.md index f8f5a29..6101ca1 100644 --- a/README.md +++ b/README.md @@ -50,13 +50,14 @@ Custom Graphical Nintendo Switch bootloader, firmware patcher, tools, and many m | \|__ background.bmp | Nyx - Custom background. User provided. | | \|__ icon_switch.bmp | Nyx - Default icon for CFWs. | | \|__ icon_payload.bmp | Nyx - Default icon for Payloads. | -| bootloader/sys/ | hekate and Nyx system modules folder. | -| \|__ emummc.kipm | emuMMC KIP1 module. !Important! | -| \|__ libsys_lp0.bso | LP0 (sleep mode) module. Important! | -| \|__ libsys_minerva.bso | Minerva Training Cell. Used for DRAM Frequency training. !Important! | -| \|__ nyx.bin | Nyx - hekate's GUI. !Important! | -| \|__ res.pak | Nyx resources package. !Important! | -| \|__ thk.bin | Atmosphère Tsec Hovi Keygen. !Important! | +| bootloader/sys/ | hekate and Nyx system modules folder. !Important! | +| \|__ emummc.kipm | emuMMC KIP1 module. | +| \|__ libsys_lp0.bso | LP0 (sleep mode) module. | +| \|__ libsys_minerva.bso | Minerva Training Cell. Used for DRAM Frequency training. | +| \|__ nyx.bin | Nyx - hekate's GUI. | +| \|__ res.pak | Nyx resources package. | +| \|__ thk.bin | Atmosphère Tsec Hovi Keygen. | +| \|__ /l4t/ | Folder with firmware relevant to L4T (Linux/Android). | | bootloader/screenshots/ | Folder where Nyx screenshots are saved | | bootloader/payloads/ | For the `Payloads` menu. All CFW bootloaders, tools, Linux payloads are supported. Autoboot only supported by including them into an ini. | | bootloader/libtools/ | Reserved | @@ -76,9 +77,9 @@ There are four possible type of entries. "**[ ]**": Boot entry, "**{ }**": Capti ### hekate Global Configuration keys/values (when entry is *[config]*): -| Config option | Description | -| ------------------ | ---------------------------------------------------------- | -| autoboot=0 | 0: Disable, #: Boot entry number to auto boot. | +| Config option | Description | +| ------------------ | -------------------------------------------------------------- | +| autoboot=0 | 0: Disable, #: Boot entry number to auto boot. | | autoboot_list=0 | 0: Read `autoboot` boot entry from hekate_ipl.ini, 1: Read from ini folder (ini files are ASCII ordered). | | bootwait=3 | 0: Disable (It also disables bootlogo. Having **VOL-** pressed since injection goes to menu.), #: Time to wait for **VOL-** to enter menu. Max: 20s. | | noticker=0 | 0: Animated line is drawn during custom bootlogo, signifying time left to skip to menu. 1: Disable. | @@ -86,7 +87,7 @@ There are four possible type of entries. "**[ ]**": Boot entry, "**{ }**": Capti | autonogc=1 | 0: Disable, 1: Automatically applies nogc patch if unburnt fuses found and a >= 4.0.0 HOS is booted. | | bootprotect=0 | 0: Disable, 1: Protect bootloader folder from being corrupted by disallowing reading or editing in HOS. | | updater2p=0 | 0: Disable, 1: Force updates (if needed) the reboot2payload binary to be hekate. | -| backlight=100 | Screen backlight level. 0-255. | +| backlight=100 | Screen backlight level. 0-255. | ### Boot entry key/value combinations: @@ -98,18 +99,20 @@ There are four possible type of entries. "**[ ]**": Boot entry, "**{ }**": Capti | kernel={FILE path} | Replaces the kernel binary | | kip1={FILE path} | Replaces/Adds kernel initial process. Multiple can be set. | | kip1={FOLDER path}/* | Loads every .kip/.kip1 inside a folder. Compatible with single kip1 keys. | -| fss0={FILE path} | Takes an Atmosphere `package3` binary (formerly fusee-secondary.bin) and `extracts` all needed parts from it. kips, exosphere, warmboot and mesophere if enabled. | -| fss0experimental=1 | Enables loading of experimental content from a FSS0 storage | +| pkg3={FILE path} | Takes an Atmosphere `package3` binary and `extracts` all needed parts from it. kips, exosphere, warmboot and mesophere. | +| fss0={FILE path} | Same as above. !Deprecated! | +| pkg3ex=1 | Enables loading of experimental content from a PKG3/FSS0 storage | +| pkg3kip1skip={KIP name} | Skips loading a kip from `pkg3`/`fss0`. Allows multiple and `,` as separator. The name must exactly match the name in `PKG3`. | | exofatal={FILE path} | Replaces the exosphere fatal binary for Mariko | | ---------------------- | ---------------------------------------------------------- | -| kip1patch=patchname | Enables a kip1 patch. Specify with multiple lines and/or in one line with `,` as separator. If actual patch is not found, a warning will show up | +| kip1patch=patchname | Enables a kip1 patch. Allows multiple and `,` as separator. If actual patch is not found, a warning will show up. | | emupath={FOLDER path} | Forces emuMMC to use the selected one. (=emuMMC/RAW1, =emuMMC/SD00, etc). emuMMC must be created by hekate because it uses the raw_based/file_based files. | | emummcforce=1 | Forces the use of emuMMC. If emummc.ini is disabled or not found, then it causes an error. | | emummc_force_disable=1 | Disables emuMMC, if it's enabled. | -| stock=1 | 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. diff --git a/Versions.inc b/Versions.inc index 8788f68..c2278c1 100644 --- a/Versions.inc +++ b/Versions.inc @@ -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 diff --git a/bdk/bdk.h b/bdk/bdk.h index 1cb315c..1d8a05e 100644 --- a/bdk/bdk.h +++ b/bdk/bdk.h @@ -49,6 +49,7 @@ #include #include #include +#include #include #include #include @@ -76,4 +77,4 @@ #include -#endif \ No newline at end of file +#endif diff --git a/bdk/display/di.c b/bdk/display/di.c index 33e0aed..3eaf922 100644 --- a/bdk/display/di.c +++ b/bdk/display/di.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2018 naehrwert - * Copyright (c) 2018-2024 CTCaer + * Copyright (c) 2018-2025 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -37,8 +37,8 @@ extern volatile nyx_storage_t *nyx_str; static u32 _display_id = 0; -static u32 _dsi_bl = -1; -static bool _nx_aula = false; +static u32 _dsi_bl = -1; +static bool _nx_aula = false; static void _display_panel_and_hw_end(bool no_panel_deinit); @@ -265,16 +265,9 @@ int display_dsi_vblank_read(u8 cmd, u32 len, void *data) void display_dsi_write(u8 cmd, u32 len, void *data) { - static u8 *fifo8 = NULL; - static u32 *fifo32 = NULL; u32 host_control; - - // Allocate fifo buffer. - if (!fifo32) - { - fifo32 = malloc(DSI_STATUS_RX_FIFO_SIZE * 8 * sizeof(u32)); - fifo8 = (u8 *)fifo32; - } + u32 fifo32[DSI_STATUS_TX_FIFO_SIZE] = {0}; + u8 *fifo8 = (u8 *)fifo32; // Prepare data for long write. if (len >= 2) @@ -319,15 +312,8 @@ void display_dsi_write(u8 cmd, u32 len, void *data) void display_dsi_vblank_write(u8 cmd, u32 len, void *data) { - static u8 *fifo8 = NULL; - static u32 *fifo32 = NULL; - - // Allocate fifo buffer. - if (!fifo32) - { - fifo32 = malloc(DSI_STATUS_RX_FIFO_SIZE * 8 * sizeof(u32)); - fifo8 = (u8 *)fifo32; - } + u32 fifo32[DSI_STATUS_TX_FIFO_SIZE] = {0}; + u8 *fifo8 = (u8 *)fifo32; // Prepare data for long write. if (len >= 2) @@ -571,7 +557,7 @@ void display_init() * When switching to the 16ff pad brick, the clock lane termination control * is separated from data lane termination. This change of the mipi cal * brings in a bug that the DSI pad clock termination code can't be loaded - * in one time calibration. Trigger calibration twice. + * in one time calibration on T210B01. Trigger calibration twice. */ reg_write_array((u32 *)MIPI_CAL_BASE, _di_mipi_pad_cal_config, ARRAY_SIZE(_di_mipi_pad_cal_config)); for (u32 i = 0; i < 2; i++) @@ -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); diff --git a/bdk/display/di.h b/bdk/display/di.h index a44e730..9a35d4f 100644 --- a/bdk/display/di.h +++ b/bdk/display/di.h @@ -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) diff --git a/bdk/display/vic.c b/bdk/display/vic.c index 4611eb4..1044448 100644 --- a/bdk/display/vic.c +++ b/bdk/display/vic.c @@ -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; diff --git a/bdk/display/vic.h b/bdk/display/vic.h index 54a3007..20fbe6c 100644 --- a/bdk/display/vic.h +++ b/bdk/display/vic.h @@ -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(); diff --git a/bdk/input/als.c b/bdk/input/als.c index acb0ac2..277f0d5 100644 --- a/bdk/input/als.c +++ b/bdk/input/als.c @@ -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)); diff --git a/bdk/input/joycon.c b/bdk/input/joycon.c index 37d3086..5e3243e 100644 --- a/bdk/input/joycon.c +++ b/bdk/input/joycon.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include #include @@ -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(); + hid_pkt->cmd = JC_HID_RUMBLE_RPT; 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); } } diff --git a/bdk/libs/fatfs/ff.c b/bdk/libs/fatfs/ff.c index 4cae990..109e87b 100644 --- a/bdk/libs/fatfs/ff.c +++ b/bdk/libs/fatfs/ff.c @@ -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 */ diff --git a/bdk/mem/minerva.h b/bdk/mem/minerva.h index de32c78..e78bb41 100644 --- a/bdk/mem/minerva.h +++ b/bdk/mem/minerva.h @@ -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 diff --git a/bdk/power/bm92t36.c b/bdk/power/bm92t36.c index faa1db5..371ed04 100644 --- a/bdk/power/bm92t36.c +++ b/bdk/power/bm92t36.c @@ -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) diff --git a/bdk/power/bq24193.c b/bdk/power/bq24193.c index 2b2e744..5194279 100644 --- a/bdk/power/bq24193.c +++ b/bdk/power/bq24193.c @@ -29,127 +29,128 @@ int bq24193_get_property(enum BQ24193_reg_prop prop, int *value) { u8 data; - switch (prop) { - case BQ24193_InputVoltageLimit: // Input voltage limit (mV). - data = bq24193_get_reg(BQ24193_InputSource); - data = (data & BQ24193_INCONFIG_VINDPM_MASK) >> 3; - *value = 0; - *value += ((data >> 0) & 1) ? 80 : 0; - *value += ((data >> 1) & 1) ? 160 : 0; - *value += ((data >> 2) & 1) ? 320 : 0; - *value += ((data >> 3) & 1) ? 640 : 0; - *value += 3880; + switch (prop) + { + case BQ24193_InputVoltageLimit: // Input voltage limit (mV). + data = bq24193_get_reg(BQ24193_InputSource); + data = (data & BQ24193_INCONFIG_VINDPM_MASK) >> 3; + *value = 0; + *value += ((data >> 0) & 1) ? 80 : 0; + *value += ((data >> 1) & 1) ? 160 : 0; + *value += ((data >> 2) & 1) ? 320 : 0; + *value += ((data >> 3) & 1) ? 640 : 0; + *value += 3880; + break; + case BQ24193_InputCurrentLimit: // Input current limit (mA). + data = bq24193_get_reg(BQ24193_InputSource); + data &= BQ24193_INCONFIG_INLIMIT_MASK; + switch (data) + { + case 0: + *value = 100; break; - case BQ24193_InputCurrentLimit: // Input current limit (mA). - data = bq24193_get_reg(BQ24193_InputSource); - data &= BQ24193_INCONFIG_INLIMIT_MASK; - switch (data) - { - case 0: - *value = 100; - break; - case 1: - *value = 150; - break; - case 2: - *value = 500; - break; - case 3: - *value = 900; - break; - case 4: - *value = 1200; - break; - case 5: - *value = 1500; - break; - case 6: - *value = 2000; - break; - case 7: - *value = 3000; - break; - } + case 1: + *value = 150; break; - case BQ24193_SystemMinimumVoltage: // Minimum system voltage limit (mV). - data = bq24193_get_reg(BQ24193_PORConfig); - *value = (data & BQ24193_PORCONFIG_SYSMIN_MASK) >> 1; - *value *= 100; - *value += 3000; + case 2: + *value = 500; break; - case BQ24193_FastChargeCurrentLimit: // Fast charge current limit (mA). - data = bq24193_get_reg(BQ24193_ChrgCurr); - data = (data & BQ24193_CHRGCURR_ICHG_MASK) >> 2; - *value = 0; - *value += ((data >> 0) & 1) ? 64 : 0; - *value += ((data >> 1) & 1) ? 128 : 0; - *value += ((data >> 2) & 1) ? 256 : 0; - *value += ((data >> 3) & 1) ? 512 : 0; - *value += ((data >> 4) & 1) ? 1024 : 0; - *value += ((data >> 5) & 1) ? 2048 : 0; - *value += 512; - data = bq24193_get_reg(BQ24193_ChrgCurr); - data &= BQ24193_CHRGCURR_20PCT_MASK; - if (data) - *value = *value * 20 / 100; // Fast charge current limit is 20%. + case 3: + *value = 900; break; - case BQ24193_ChargeVoltageLimit: // Charge voltage limit (mV). - data = bq24193_get_reg(BQ24193_ChrgVolt); - data = (data & BQ24193_CHRGVOLT_VREG) >> 2; - *value = 0; - *value += ((data >> 0) & 1) ? 16 : 0; - *value += ((data >> 1) & 1) ? 32 : 0; - *value += ((data >> 2) & 1) ? 64 : 0; - *value += ((data >> 3) & 1) ? 128 : 0; - *value += ((data >> 4) & 1) ? 256 : 0; - *value += ((data >> 5) & 1) ? 512 : 0; - *value += 3504; + case 4: + *value = 1200; break; - case BQ24193_RechargeThreshold: // Recharge voltage threshold less than voltage limit (mV). - data = bq24193_get_reg(BQ24193_ChrgVolt); - data &= BQ24193_IRTHERMAL_THERM_MASK; - if (data) - *value = 300; - else - *value = 100; + case 5: + *value = 1500; break; - case BQ24193_ThermalRegulation: // Thermal regulation threshold (oC). - data = bq24193_get_reg(BQ24193_IRCompThermal); - data &= BQ24193_IRTHERMAL_THERM_MASK; - switch (data) - { - case 0: - *value = 60; - break; - case 1: - *value = 80; - break; - case 2: - *value = 100; - break; - case 3: - *value = 120; - break; - } + case 6: + *value = 2000; break; - case BQ24193_ChargeStatus: // 0: Not charging, 1: Pre-charge, 2: Fast charging, 3: Charge termination done - data = bq24193_get_reg(BQ24193_Status); - *value = (data & BQ24193_STATUS_CHRG_MASK) >> 4; + case 7: + *value = 3000; break; - case BQ24193_TempStatus: // 0: Normal, 2: Warm, 3: Cool, 5: Cold, 6: Hot. - data = bq24193_get_reg(BQ24193_FaultReg); - *value = data & BQ24193_FAULT_THERM_MASK; + } + break; + case BQ24193_SystemMinimumVoltage: // Minimum system voltage limit (mV). + data = bq24193_get_reg(BQ24193_PORConfig); + *value = (data & BQ24193_PORCONFIG_SYSMIN_MASK) >> 1; + *value *= 100; + *value += 3000; + break; + case BQ24193_FastChargeCurrentLimit: // Fast charge current limit (mA). + data = bq24193_get_reg(BQ24193_ChrgCurr); + data = (data & BQ24193_CHRGCURR_ICHG_MASK) >> 2; + *value = 0; + *value += ((data >> 0) & 1) ? 64 : 0; + *value += ((data >> 1) & 1) ? 128 : 0; + *value += ((data >> 2) & 1) ? 256 : 0; + *value += ((data >> 3) & 1) ? 512 : 0; + *value += ((data >> 4) & 1) ? 1024 : 0; + *value += ((data >> 5) & 1) ? 2048 : 0; + *value += 512; + data = bq24193_get_reg(BQ24193_ChrgCurr); + data &= BQ24193_CHRGCURR_20PCT_MASK; + if (data) + *value = *value * 20 / 100; // Fast charge current limit is 20%. + break; + case BQ24193_ChargeVoltageLimit: // Charge voltage limit (mV). + data = bq24193_get_reg(BQ24193_ChrgVolt); + data = (data & BQ24193_CHRGVOLT_VREG) >> 2; + *value = 0; + *value += ((data >> 0) & 1) ? 16 : 0; + *value += ((data >> 1) & 1) ? 32 : 0; + *value += ((data >> 2) & 1) ? 64 : 0; + *value += ((data >> 3) & 1) ? 128 : 0; + *value += ((data >> 4) & 1) ? 256 : 0; + *value += ((data >> 5) & 1) ? 512 : 0; + *value += 3504; + break; + case BQ24193_RechargeThreshold: // Recharge voltage threshold less than voltage limit (mV). + data = bq24193_get_reg(BQ24193_ChrgVolt); + data &= BQ24193_IRTHERMAL_THERM_MASK; + if (data) + *value = 300; + else + *value = 100; + break; + case BQ24193_ThermalRegulation: // Thermal regulation threshold (oC). + data = bq24193_get_reg(BQ24193_IRCompThermal); + data &= BQ24193_IRTHERMAL_THERM_MASK; + switch (data) + { + case 0: + *value = 60; break; - case BQ24193_DevID: // Dev ID. - data = bq24193_get_reg(BQ24193_VendorPart); - *value = data & BQ24193_VENDORPART_DEV_MASK; + case 1: + *value = 80; break; - case BQ24193_ProductNumber: // Product number. - data = bq24193_get_reg(BQ24193_VendorPart); - *value = (data & BQ24193_VENDORPART_PN_MASK) >> 3; + case 2: + *value = 100; break; - default: - return -1; + case 3: + *value = 120; + break; + } + break; + case BQ24193_ChargeStatus: // 0: Not charging, 1: Pre-charge, 2: Fast charging, 3: Charge termination done + data = bq24193_get_reg(BQ24193_Status); + *value = (data & BQ24193_STATUS_CHRG_MASK) >> 4; + break; + case BQ24193_TempStatus: // 0: Normal, 2: Warm, 3: Cool, 5: Cold, 6: Hot. + data = bq24193_get_reg(BQ24193_FaultReg); + *value = data & BQ24193_FAULT_THERM_MASK; + break; + case BQ24193_DevID: // Dev ID. + data = bq24193_get_reg(BQ24193_VendorPart); + *value = data & BQ24193_VENDORPART_DEV_MASK; + break; + case BQ24193_ProductNumber: // Product number. + data = bq24193_get_reg(BQ24193_VendorPart); + *value = (data & BQ24193_VENDORPART_PN_MASK) >> 3; + break; + default: + return -1; } return 0; } diff --git a/bdk/power/max7762x.c b/bdk/power/max7762x.c index 70756c4..f0aefb5 100644 --- a/bdk/power/max7762x.c +++ b/bdk/power/max7762x.c @@ -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); diff --git a/bdk/sec/se.c b/bdk/sec/se.c index b6a2841..4ed04ec 100644 --- a/bdk/sec/se.c +++ b/bdk/sec/se.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2018 naehrwert - * Copyright (c) 2018-2024 CTCaer + * Copyright (c) 2018-2025 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -19,7 +19,6 @@ #include "se.h" #include -#include #include #include #include @@ -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; } diff --git a/bdk/sec/se.h b/bdk/sec/se.h index 7c8c38b..36b057b 100644 --- a/bdk/sec/se.h +++ b/bdk/sec/se.h @@ -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); diff --git a/bdk/soc/bpmp.c b/bdk/soc/bpmp.c index e563d45..3979c2a 100644 --- a/bdk/soc/bpmp.c +++ b/bdk/soc/bpmp.c @@ -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) diff --git a/bdk/soc/bpmp.h b/bdk/soc/bpmp.h index 129ea57..ace1290 100644 --- a/bdk/soc/bpmp.h +++ b/bdk/soc/bpmp.h @@ -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(); diff --git a/bdk/soc/clock.c b/bdk/soc/clock.c index 6b2870c..b3a48fa 100644 --- a/bdk/soc/clock.c +++ b/bdk/soc/clock.c @@ -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); } diff --git a/bdk/soc/clock.h b/bdk/soc/clock.h index 4bceb24..14d1df7 100644 --- a/bdk/soc/clock.h +++ b/bdk/soc/clock.h @@ -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 diff --git a/bdk/soc/fuse.c b/bdk/soc/fuse.c index 60e2fe7..9668196 100644 --- a/bdk/soc/fuse.c +++ b/bdk/soc/fuse.c @@ -24,7 +24,9 @@ #include #include #include +#include #include +#include #include 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; diff --git a/bdk/soc/i2c.c b/bdk/soc/i2c.c index 81f783c..c38e952 100644 --- a/bdk/soc/i2c.c +++ b/bdk/soc/i2c.c @@ -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]; diff --git a/bdk/soc/i2c.h b/bdk/soc/i2c.h index a04eec1..ab3078e 100644 --- a/bdk/soc/i2c.h +++ b/bdk/soc/i2c.h @@ -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); diff --git a/bdk/soc/irq.c b/bdk/soc/irq.c index f100dba..f39774e 100644 --- a/bdk/soc/irq.c +++ b/bdk/soc/irq.c @@ -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) diff --git a/bdk/soc/t210.h b/bdk/soc/t210.h index 6690114..eaf59df 100644 --- a/bdk/soc/t210.h +++ b/bdk/soc/t210.h @@ -85,6 +85,7 @@ #define AXBAR_BASE 0x702D0800 #define I2S_BASE 0x702D1000 #define ADMA_BASE 0x702E2000 +#define AMC_BASE 0x702EF000 #define SE2_BASE 0x70412000 #define SE_PKA1_BASE 0x70420000 #define TZRAM_BASE 0x7C010000 @@ -151,6 +152,7 @@ #define CL_DVFS(off) MMIO_REG32(CL_DVFS_BASE, off) #define I2S(off) MMIO_REG32(I2S_BASE, off) #define ADMA(off) MMIO_REG32(ADMA_BASE, off) +#define AMC(off) MMIO_REG32(AMC_BASE, off) #define SE2(off) MMIO_REG32(SE2_BASE, off) #define SE_PKA1(off) MMIO_REG32(SE_PKA1_BASE, off) #define USB(off) MMIO_REG32(USB_BASE, off) @@ -199,7 +201,7 @@ /*! AHB Gizmo registers. */ #define AHB_ARBITRATION_PRIORITY_CTRL 0x8 #define PRIORITY_CTRL_WEIGHT(x) (((x) & 7) << 29) -#define PRIORITY_SELECT_USB BIT(6) // USB-OTG. +#define PRIORITY_SELECT_USB BIT(6) // USB-OTG. #define PRIORITY_SELECT_USB2 BIT(18) // USB-HSIC. #define PRIORITY_SELECT_USB3 BIT(17) // XUSB. #define AHB_GIZMO_AHB_MEM 0x10 @@ -210,7 +212,7 @@ #define AHB_GIZMO_USB 0x20 #define AHB_GIZMO_SDMMC4 0x48 #define AHB_GIZMO_USB2 0x7C -#define AHB_GIZMO_USB3 0x80 +#define AHB_GIZMO_USB3 0x80 // Doesn't exist on T21x?? #define AHB_GIZMO_IMMEDIATE BIT(18) #define AHB_ARBITRATION_XBAR_CTRL 0xE0 #define AHB_AHB_MEM_PREFETCH_CFG3 0xE4 @@ -219,9 +221,9 @@ #define AHB_AHB_MEM_PREFETCH_CFG2 0xF4 #define MST_ID(x) (((x) & 0x1F) << 26) #define MEM_PREFETCH_AHBDMA_MST_ID MST_ID(5) -#define MEM_PREFETCH_USB_MST_ID MST_ID(6) // USB-OTG. -#define MEM_PREFETCH_USB2_MST_ID MST_ID(18) // USB-HSIC. -#define MEM_PREFETCH_USB3_MST_ID MST_ID(17) // XUSB. +#define MEM_PREFETCH_USB_MST_ID MST_ID(6) // USB-OTG. Doesn't exist on T210B01. +#define MEM_PREFETCH_USB2_MST_ID MST_ID(18) // USB-HSIC. Doesn't exist on T210B01. +#define MEM_PREFETCH_USB3_MST_ID MST_ID(17) // XUSB. Doesn't exist on T210B01. #define MEM_PREFETCH_ADDR_BNDRY(x) (((x) & 0xF) << 21) #define MEM_PREFETCH_ENABLE BIT(31) #define AHB_ARBITRATION_AHB_MEM_WRQUE_MST_ID 0xFC diff --git a/bdk/soc/timer.c b/bdk/soc/timer.c index c6c5b83..786f123 100644 --- a/bdk/soc/timer.c +++ b/bdk/soc/timer.c @@ -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); @@ -118,4 +120,4 @@ bool watchdog_fired() { // Return if watchdog got fired. User handles clearing. return (*(u32 *)EXCP_TYPE_ADDR == EXCP_TYPE_WDT); -} \ No newline at end of file +} diff --git a/bdk/soc/uart.c b/bdk/soc/uart.c index a2efaab..c76c66e 100644 --- a/bdk/soc/uart.c +++ b/bdk/soc/uart.c @@ -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); diff --git a/bdk/soc/uart.h b/bdk/soc/uart.h index c25973c..a24d5c9 100644 --- a/bdk/soc/uart.h +++ b/bdk/soc/uart.h @@ -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; diff --git a/bdk/storage/sd.c b/bdk/storage/sd.c index f2a22ed..3ad31fa 100644 --- a/bdk/storage/sd.c +++ b/bdk/storage/sd.c @@ -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; diff --git a/bdk/storage/sd.h b/bdk/storage/sd.h index 1008b65..1153996 100644 --- a/bdk/storage/sd.h +++ b/bdk/storage/sd.h @@ -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 \ No newline at end of file diff --git a/bdk/storage/sd_def.h b/bdk/storage/sd_def.h index 14782bf..898ac46 100644 --- a/bdk/storage/sd_def.h +++ b/bdk/storage/sd_def.h @@ -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 */ diff --git a/bdk/storage/sdmmc.c b/bdk/storage/sdmmc.c index 6fcdd5e..747c28d 100644 --- a/bdk/storage/sdmmc.c +++ b/bdk/storage/sdmmc.c @@ -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 #include +#include #include #include #include @@ -27,14 +28,26 @@ #include #include -//#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,6 +262,43 @@ int sdmmc_storage_end(sdmmc_storage_t *storage) return 1; } +static int _sdmmc_storage_handle_io_error(sdmmc_storage_t *storage, bool first_reinit) +{ + int res = 0; + + if (storage->sdmmc->id == SDMMC_1 || storage->sdmmc->id == SDMMC_4) + { + if (storage->sdmmc->id == SDMMC_1) + { + sd_error_count_increment(SD_ERROR_RW_FAIL); + + if (first_reinit) + res = sd_initialize(true); + else + { + res = sd_init_retry(true); + if (!res) + sd_error_count_increment(SD_ERROR_INIT_FAIL); + } + } + else if (storage->sdmmc->id == SDMMC_4) + { + emmc_error_count_increment(EMMC_ERROR_RW_FAIL); + + if (first_reinit) + res = emmc_initialize(true); + else + { + res = emmc_init_retry(true); + if (!res) + emmc_error_count_increment(EMMC_ERROR_INIT_FAIL); + } + } + } + + return res; +} + static int _sdmmc_storage_readwrite(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, void *buf, u32 is_write) { u8 *bbuf = (u8 *)buf; @@ -256,6 +310,15 @@ static int _sdmmc_storage_readwrite(sdmmc_storage_t *storage, u32 sector, u32 nu if (!storage->initialized) return 0; + // Check if out of bounds. + if (((u64)sector + num_sectors) > storage->sec_cnt) + { +#ifdef ERROR_EXTRA_PRINTING + EPRINTFARGS("SDMMC%d: Out of bounds!", storage->sdmmc->id + 1); +#endif + return 0; + } + while (sct_total) { u32 blkcnt = 0; @@ -275,51 +338,18 @@ reinit_try: } while (retries); // Disk IO failure! Reinit SD/EMMC to a lower speed. - if (storage->sdmmc->id == SDMMC_1 || storage->sdmmc->id == SDMMC_4) + if (_sdmmc_storage_handle_io_error(storage, first_reinit)) { - int res = 0; - - if (storage->sdmmc->id == SDMMC_1) - { - sd_error_count_increment(SD_ERROR_RW_FAIL); - - if (first_reinit) - res = sd_initialize(true); - else - { - res = sd_init_retry(true); - if (!res) - sd_error_count_increment(SD_ERROR_INIT_FAIL); - } - } - else if (storage->sdmmc->id == SDMMC_4) - { - emmc_error_count_increment(EMMC_ERROR_RW_FAIL); - - if (first_reinit) - res = emmc_initialize(true); - else - { - res = emmc_init_retry(true); - if (!res) - emmc_error_count_increment(EMMC_ERROR_INIT_FAIL); - } - } - // Reset values for a retry. blkcnt = 0; retries = 3; first_reinit = false; - // If successful reinit, restart xfer. - if (res) - { - bbuf = (u8 *)buf; - sct_off = sector; - sct_total = num_sectors; + bbuf = (u8 *)buf; + sct_off = sector; + sct_total = num_sectors; - goto reinit_try; - } + goto reinit_try; } // Failed. @@ -393,7 +423,7 @@ static int _mmc_storage_get_op_cond_inner(sdmmc_storage_t *storage, u32 *pout, u if (!sdmmc_execute_cmd(storage->sdmmc, &cmdbuf, NULL, NULL)) return 0; - return sdmmc_get_rsp(storage->sdmmc, pout, 4, SDMMC_RSP_TYPE_3); + return sdmmc_get_cached_rsp(storage->sdmmc, pout, SDMMC_RSP_TYPE_3); } static int _mmc_storage_get_op_cond(sdmmc_storage_t *storage, u32 power) @@ -477,12 +507,12 @@ static void _mmc_storage_parse_csd(sdmmc_storage_t *storage) { u32 *raw_csd = (u32 *)storage->raw_csd; - storage->csd.mmca_vsn = unstuff_bits(raw_csd, 122, 4); - storage->csd.structure = unstuff_bits(raw_csd, 126, 2); - storage->csd.cmdclass = unstuff_bits(raw_csd, 84, 12); + storage->csd.mmca_vsn = unstuff_bits(raw_csd, 122, 4); + storage->csd.structure = unstuff_bits(raw_csd, 126, 2); + storage->csd.cmdclass = unstuff_bits(raw_csd, 84, 12); storage->csd.read_blkbits = unstuff_bits(raw_csd, 80, 4); - storage->csd.capacity = (1 + unstuff_bits(raw_csd, 62, 12)) << (unstuff_bits(raw_csd, 47, 3) + 2); - storage->sec_cnt = storage->csd.capacity; + storage->csd.capacity = (1 + unstuff_bits(raw_csd, 62, 12)) << (unstuff_bits(raw_csd, 47, 3) + 2); + storage->sec_cnt = storage->csd.capacity; } static void _mmc_storage_parse_ext_csd(sdmmc_storage_t *storage, u8 *buf) @@ -531,12 +561,40 @@ int mmc_storage_get_ext_csd(sdmmc_storage_t *storage, void *buf) return 0; u32 tmp = 0; - sdmmc_get_rsp(storage->sdmmc, &tmp, 4, SDMMC_RSP_TYPE_1); + sdmmc_get_cached_rsp(storage->sdmmc, &tmp, SDMMC_RSP_TYPE_1); _mmc_storage_parse_ext_csd(storage, buf); return _sdmmc_storage_check_card_status(tmp); } +int sd_storage_get_ext_reg(sdmmc_storage_t *storage, u8 fno, u8 page, u16 address, u32 len, void *buf) +{ + if (!(storage->scr.cmds & BIT(2))) + return 0; + + sdmmc_cmd_t cmdbuf; + + u32 arg = fno << 27 | page << 18 | address << 9 | (len - 1); + + sdmmc_init_cmd(&cmdbuf, SD_READ_EXTR_SINGLE, arg, SDMMC_RSP_TYPE_1, 0); + + sdmmc_req_t reqbuf; + reqbuf.buf = buf; + reqbuf.blksize = SDMMC_DAT_BLOCKSIZE; + reqbuf.num_sectors = 1; + reqbuf.is_write = 0; + reqbuf.is_multi_block = 0; + reqbuf.is_auto_stop_trn = 0; + + if (!sdmmc_execute_cmd(storage->sdmmc, &cmdbuf, &reqbuf, NULL)) + return 0; + + u32 tmp = 0; + sdmmc_get_cached_rsp(storage->sdmmc, &tmp, SDMMC_RSP_TYPE_1); + + return _sdmmc_storage_check_card_status(tmp); +} + static int _mmc_storage_switch(sdmmc_storage_t *storage, u32 arg) { return _sdmmc_storage_execute_cmd_type1(storage, MMC_SWITCH, arg, 1, R1_SKIP_STATE_CHECK); @@ -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 - return 1; + // The SD Card is version 1.X (SDSC) if there is no response. + if (storage->sdmmc->error_sts == SDHCI_ERR_INT_CMD_TIMEOUT) + { + *is_sdsc = 1; + return 1; + } + + return 0; } // For Card version >= 2.0, parse results. u32 resp = 0; - sdmmc_get_rsp(storage->sdmmc, &resp, 4, SDMMC_RSP_TYPE_5); + sdmmc_get_cached_rsp(storage->sdmmc, &resp, SDMMC_RSP_TYPE_5); // Check if VHD was accepted and pattern was properly returned. if ((resp & 0xFFF) == vhd_pattern) @@ -948,7 +1012,7 @@ static int _sd_storage_get_op_cond_once(sdmmc_storage_t *storage, u32 *cond, boo if (!_sd_storage_execute_app_cmd(storage, R1_SKIP_STATE_CHECK, is_sdsc ? R1_ILLEGAL_COMMAND : 0, &cmdbuf, NULL, NULL)) return 0; - return sdmmc_get_rsp(storage->sdmmc, cond, 4, SDMMC_RSP_TYPE_3); + return sdmmc_get_cached_rsp(storage->sdmmc, cond, SDMMC_RSP_TYPE_3); } static int _sd_storage_get_op_cond(sdmmc_storage_t *storage, bool is_sdsc, int bus_uhs_support) @@ -971,7 +1035,7 @@ static int _sd_storage_get_op_cond(sdmmc_storage_t *storage, bool is_sdsc, int b storage->has_sector_access = 1; // Check if card supports 1.8V signaling. - if (cond & SD_ROCR_S18A && bus_uhs_support) + if (cond & SD_ROCR_S18A && bus_uhs_support && !storage->is_low_voltage) { // Switch to 1.8V signaling. if (_sdmmc_storage_execute_cmd_type1(storage, SD_SWITCH_VOLTAGE, 0, 0, R1_STATE_READY)) @@ -1015,7 +1079,7 @@ static int _sd_storage_get_rca(sdmmc_storage_t *storage) break; u32 resp = 0; - if (!sdmmc_get_rsp(storage->sdmmc, &resp, 4, SDMMC_RSP_TYPE_4)) + if (!sdmmc_get_cached_rsp(storage->sdmmc, &resp, SDMMC_RSP_TYPE_4)) break; if (resp >> 16) @@ -1046,11 +1110,17 @@ static void _sd_storage_parse_scr(sdmmc_storage_t *storage) storage->scr.sda_vsn = unstuff_bits(resp, 56, 4); storage->scr.bus_widths = unstuff_bits(resp, 48, 4); - /* If v2.0 is supported, check if Physical Layer Spec v3.0 is supported */ + // If v2.0 is supported, check if Physical Layer Spec v3.0 is supported. if (storage->scr.sda_vsn == SCR_SPEC_VER_2) storage->scr.sda_spec3 = unstuff_bits(resp, 47, 1); if (storage->scr.sda_spec3) - storage->scr.cmds = unstuff_bits(resp, 32, 2); + { + u8 sda_spec4 = unstuff_bits(resp, 42, 1); + if (sda_spec4) + storage->scr.cmds = unstuff_bits(resp, 32, 4); + else + storage->scr.cmds = unstuff_bits(resp, 32, 2); + } } int sd_storage_get_scr(sdmmc_storage_t *storage, u8 *buf) @@ -1070,9 +1140,9 @@ int sd_storage_get_scr(sdmmc_storage_t *storage, u8 *buf) return 0; u32 tmp = 0; - sdmmc_get_rsp(storage->sdmmc, &tmp, 4, SDMMC_RSP_TYPE_1); + sdmmc_get_cached_rsp(storage->sdmmc, &tmp, SDMMC_RSP_TYPE_1); //Prepare buffer for unstuff_bits - for (int i = 0; i < 8; i+=4) + for (u32 i = 0; i < 8; i+=4) { storage->raw_scr[i + 3] = buf[i]; storage->raw_scr[i + 2] = buf[i + 1]; @@ -1101,7 +1171,7 @@ static int _sd_storage_switch_get(sdmmc_storage_t *storage, void *buf) return 0; u32 tmp = 0; - sdmmc_get_rsp(storage->sdmmc, &tmp, 4, SDMMC_RSP_TYPE_1); + sdmmc_get_cached_rsp(storage->sdmmc, &tmp, SDMMC_RSP_TYPE_1); return _sdmmc_storage_check_card_status(tmp); } @@ -1125,7 +1195,7 @@ static int _sd_storage_switch(sdmmc_storage_t *storage, void *buf, int mode, int return 0; u32 tmp = 0; - sdmmc_get_rsp(storage->sdmmc, &tmp, 4, SDMMC_RSP_TYPE_1); + sdmmc_get_cached_rsp(storage->sdmmc, &tmp, SDMMC_RSP_TYPE_1); return _sdmmc_storage_check_card_status(tmp); } @@ -1241,7 +1311,7 @@ static int _sd_storage_enable_DDR200(sdmmc_storage_t *storage, u8 *buf) u16 total_pwr_consumption = ((u16)buf[0] << 8) | buf[1]; DPRINTF("[SD] max power: %d mW\n", total_pwr_consumption * 3600 / 1000); - storage->card_power_limit = total_pwr_consumption; + storage->max_power = total_pwr_consumption; if (total_pwr_consumption <= 800) { @@ -1280,7 +1350,7 @@ static int _sd_storage_set_card_bus_speed(sdmmc_storage_t *storage, u32 hs_type, u16 total_pwr_consumption = ((u16)buf[0] << 8) | buf[1]; DPRINTF("[SD] max power: %d mW\n", total_pwr_consumption * 3600 / 1000); - storage->card_power_limit = total_pwr_consumption; + storage->max_power = total_pwr_consumption; if (total_pwr_consumption <= 800) { @@ -1492,10 +1562,10 @@ static void _sd_storage_parse_ssr(sdmmc_storage_t *storage) _sd_storage_debug_print_ssr(storage->raw_ssr); #endif - storage->ssr.bus_width = (unstuff_bits(raw_ssr1, 510 - 384, 2) & SD_BUS_WIDTH_4) ? 4 : 1; - storage->ssr.protected_size = unstuff_bits(raw_ssr1, 448 - 384, 32); + storage->ssr.bus_width = (unstuff_bits(raw_ssr1, 510, 2) & SD_BUS_WIDTH_4) ? 4 : 1; + storage->ssr.protected_size = unstuff_bits(raw_ssr1, 448, 32); - u32 speed_class = unstuff_bits(raw_ssr1, 440 - 384, 8); + u32 speed_class = unstuff_bits(raw_ssr1, 440, 8); switch(speed_class) { case 0: @@ -1513,12 +1583,94 @@ static void _sd_storage_parse_ssr(sdmmc_storage_t *storage) storage->ssr.speed_class = speed_class; break; } - storage->ssr.uhs_grade = unstuff_bits(raw_ssr1, 396 - 384, 4); - storage->ssr.video_class = unstuff_bits(raw_ssr1, 384 - 384, 8); - storage->ssr.app_class = unstuff_bits(raw_ssr2, 336 - 256, 4); + storage->ssr.uhs_grade = unstuff_bits(raw_ssr1, 396, 4); + storage->ssr.video_class = unstuff_bits(raw_ssr1, 384, 8); + storage->ssr.app_class = unstuff_bits(raw_ssr2, 336, 4); - storage->ssr.au_size = unstuff_bits(raw_ssr1, 428 - 384, 4); - storage->ssr.uhs_au_size = unstuff_bits(raw_ssr1, 392 - 384, 4); + storage->ssr.au_size = unstuff_bits(raw_ssr1, 428, 4); + storage->ssr.uhs_au_size = unstuff_bits(raw_ssr1, 392, 4); + + storage->ssr.perf_enhance = unstuff_bits(raw_ssr2, 328, 8); +} + +int sd_storage_parse_perf_enhance(sdmmc_storage_t *storage, u8 fno, u8 page, u16 offset, u8 *buf) +{ + // Check status reg for support. + storage->ser.cache = (storage->ssr.perf_enhance >> 2) & BIT(0); + storage->ser.cmdq = (storage->ssr.perf_enhance >> 3) & 0x1F; + + if (!sd_storage_get_ext_reg(storage, fno, page, offset, 512, buf)) + { + storage->ser.cache_ext = 0; + storage->ser.cmdq_ext = 0; + + return 0; + } + + storage->ser.cache_ext = buf[4] & BIT(0); + storage->ser.cmdq_ext = buf[6] & 0x1F; + + return 1; +} + +static void _sd_storage_parse_ext_reg(sdmmc_storage_t *storage, u8 *buf, u16 *addr_next) +{ + u16 addr = *addr_next; + + // Address to the next extension. + *addr_next = (buf[addr + 41] << 8) | buf[addr + 40]; + + u16 sfc = (buf[addr + 1] << 8) | buf[addr]; + + u32 reg_sets = buf[addr + 42]; + +#ifdef SDMMC_DEBUG_PRINT_SD_REGS + for (u32 i = 0; i < reg_sets; i++) + { + u32 reg_set_addr; + memcpy(®_set_addr, &buf[addr + 44 + 4 * i], 4); + u16 off = reg_set_addr & 0x1FF; + u8 page = reg_set_addr >> 9 & 0xFF; + u8 fno = reg_set_addr >> 18 & 0xFF; + gfx_printf("Addr: %04X sfc:%02X - fno:%02X, page:%02X, off:%04X\n", addr, sfc, fno, page, off); + } +#endif + + // Parse Performance Enhance. + if (sfc == 2 && reg_sets == 1) + { + u32 reg_set0_addr; + memcpy(®_set0_addr, &buf[addr + 44], 4); + u16 off = reg_set0_addr & 0x1FF; + u8 page = reg_set0_addr >> 9 & 0xFF; + u8 fno = reg_set0_addr >> 18 & 0xFF; + + if (sd_storage_parse_perf_enhance(storage, fno, page, off, buf)) + storage->ser.valid = 1; + } +} + +void sd_storage_get_ext_regs(sdmmc_storage_t *storage, u8 *buf) +{ + DREGPRINTF("SD Extension Registers:\n\n"); + + if (!(storage->scr.cmds & BIT(2))) + { + DREGPRINTF("Not Supported!\n"); + return; + } + + if (!sd_storage_get_ext_reg(storage, 0, 0, 0, 512, buf)) + { + DREGPRINTF("Failed to get general info!\n"); + return; + } + + u16 size = (buf[3] << 8) | buf[2]; + u16 addr_next = 16; + u32 num_ext = buf[4]; + for (u32 i = 0; i < num_ext && addr_next < size; i++) + _sd_storage_parse_ext_reg(storage, buf, &addr_next); } int sd_storage_get_ssr(sdmmc_storage_t *storage, u8 *buf) @@ -1544,10 +1696,10 @@ int sd_storage_get_ssr(sdmmc_storage_t *storage, u8 *buf) return 0; u32 tmp = 0; - sdmmc_get_rsp(storage->sdmmc, &tmp, 4, SDMMC_RSP_TYPE_1); + sdmmc_get_cached_rsp(storage->sdmmc, &tmp, SDMMC_RSP_TYPE_1); // Convert buffer to LE. - for (int i = 0; i < SDMMC_CMD_BLOCKSIZE; i += 4) + for (u32 i = 0; i < SDMMC_CMD_BLOCKSIZE; i += 4) { storage->raw_ssr[i + 3] = buf[i]; storage->raw_ssr[i + 2] = buf[i + 1]; @@ -1644,7 +1796,7 @@ void sdmmc_storage_init_wait_sd() int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 bus_width, u32 type) { u32 tmp = 0; - int is_sdsc = 0; + bool is_sdsc = 0; u8 *buf = (u8 *)SDMMC_UPPER_BUFFER; bool bus_uhs_support = _sdmmc_storage_get_bus_uhs_support(bus_width, type); @@ -1789,7 +1941,7 @@ int _gc_storage_custom_cmd(sdmmc_storage_t *storage, void *buf) return 0; } - if (!sdmmc_get_rsp(storage->sdmmc, &resp, 4, SDMMC_RSP_TYPE_1)) + if (!sdmmc_get_cached_rsp(storage->sdmmc, &resp, SDMMC_RSP_TYPE_1)) return 0; if (!_sdmmc_storage_check_card_status(resp)) return 0; diff --git a/bdk/storage/sdmmc.h b/bdk/storage/sdmmc.h index 8a98dc3..6da130a 100644 --- a/bdk/storage/sdmmc.h +++ b/bdk/storage/sdmmc.h @@ -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 diff --git a/bdk/storage/sdmmc_driver.c b/bdk/storage/sdmmc_driver.c index 3697692..b6e3c8e 100644 --- a/bdk/storage/sdmmc_driver.c +++ b/bdk/storage/sdmmc_driver.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2018 naehrwert - * Copyright (c) 2018-2024 CTCaer + * Copyright (c) 2018-2025 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -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; diff --git a/bdk/storage/sdmmc_driver.h b/bdk/storage/sdmmc_driver.h index ee62eaf..fe09c5a 100644 --- a/bdk/storage/sdmmc_driver.h +++ b/bdk/storage/sdmmc_driver.h @@ -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(); diff --git a/bdk/storage/sdmmc_t210.h b/bdk/storage/sdmmc_t210.h index dfea7d5..26c1e49 100644 --- a/bdk/storage/sdmmc_t210.h +++ b/bdk/storage/sdmmc_t210.h @@ -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; diff --git a/bdk/usb/usb_descriptor_types.h b/bdk/usb/usb_descriptor_types.h index 9f86e9d..cb58abc 100644 --- a/bdk/usb/usb_descriptor_types.h +++ b/bdk/usb/usb_descriptor_types.h @@ -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 */ diff --git a/bdk/usb/usb_gadget_hid.c b/bdk/usb/usb_gadget_hid.c index 591649a..dc7681a 100644 --- a/bdk/usb/usb_gadget_hid.c +++ b/bdk/usb/usb_gadget_hid.c @@ -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) diff --git a/bdk/usb/usb_gadget_ums.c b/bdk/usb/usb_gadget_ums.c index bb0c973..1655bd5 100644 --- a/bdk/usb/usb_gadget_ums.c +++ b/bdk/usb/usb_gadget_ums.c @@ -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); diff --git a/bdk/usb/xusbd.c b/bdk/usb/xusbd.c index 38578e7..87df551 100644 --- a/bdk/usb/xusbd.c +++ b/bdk/usb/xusbd.c @@ -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; diff --git a/bdk/utils/dirlist.c b/bdk/utils/dirlist.c index 5197c01..b1de140 100644 --- a/bdk/utils/dirlist.c +++ b/bdk/utils/dirlist.c @@ -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 #include +#include "dirlist.h" #include #include #include -#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++) + // Terminate name list. + dir_entries->name[k] = NULL; + + // Reorder ini files Alphabetically. + for (u32 i = 0; i < k - 1 ; i++) { - for (j = i + 1; j < k; j++) + for (u32 j = i + 1; j < k; j++) { - if (strcmp(&dir_entries[i * 256], &dir_entries[j * 256]) > 0) + if (strcasecmp(dir_entries->name[i], dir_entries->name[j]) > 0) { - strcpy(temp, &dir_entries[i * 256]); - strcpy(&dir_entries[i * 256], &dir_entries[j * 256]); - strcpy(&dir_entries[j * 256], temp); + char *tmp = dir_entries->name[i]; + dir_entries->name[i] = dir_entries->name[j]; + dir_entries->name[j] = tmp; } } } - free(temp); - return dir_entries; } diff --git a/bdk/utils/dirlist.h b/bdk/utils/dirlist.h index 32197f3..cb250c3 100644 --- a/bdk/utils/dirlist.h +++ b/bdk/utils/dirlist.h @@ -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 -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); diff --git a/bdk/utils/ini.c b/bdk/utils/ini.c index 104b261..6832bdc 100644 --- a/bdk/utils/ini.c +++ b/bdk/utils/ini.c @@ -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 diff --git a/bdk/utils/ini.h b/bdk/utils/ini.h index 929a850..35c13c8 100644 --- a/bdk/utils/ini.h +++ b/bdk/utils/ini.h @@ -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); diff --git a/bdk/utils/sprintf.c b/bdk/utils/sprintf.c index d21c5be..b86b96c 100644 --- a/bdk/utils/sprintf.c +++ b/bdk/utils/sprintf.c @@ -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': diff --git a/bdk/utils/util.c b/bdk/utils/util.c index 878214f..69498ac 100644 --- a/bdk/utils/util.c +++ b/bdk/utils/util.c @@ -1,19 +1,19 @@ /* -* Copyright (c) 2018 naehrwert -* Copyright (c) 2018-2024 CTCaer -* -* This program is free software; you can redistribute it and/or modify it -* under the terms and conditions of the GNU General Public License, -* version 2, as published by the Free Software Foundation. -* -* This program is distributed in the hope it will be useful, but WITHOUT -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -* more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see . -*/ + * Copyright (c) 2018 naehrwert + * Copyright (c) 2018-2025 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ #include @@ -29,8 +29,6 @@ #include #include -#define USE_RTC_TIMER - u8 bit_count(u32 val) { u8 cnt = 0; @@ -138,7 +136,7 @@ long strtol(const char *nptr, char **endptr, register int base) } else if (c == '+') c = *s++; if ((base == 0 || base == 16) && - c == '0' && (*s == 'x' || *s == 'X')) { + c == '0' && (*s == 'x' || *s == 'X')) { c = s[1]; s += 2; base = 16; @@ -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. diff --git a/bdk/utils/util.h b/bdk/utils/util.h index 2372b8c..2d8d9bd 100644 --- a/bdk/utils/util.h +++ b/bdk/utils/util.h @@ -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); diff --git a/bootloader/frontend/fe_info.c b/bootloader/frontend/fe_info.c index d1beaba..67bcfba 100644 --- a/bootloader/frontend/fe_info.c +++ b/bootloader/frontend/fe_info.c @@ -313,23 +313,20 @@ 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); + 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); + gfx_printf("Charge voltage limit: %4d mV\n", value); bq24193_get_property(BQ24193_ChargeStatus, &value); - gfx_printf("Charge status: "); + gfx_printf("Charge status: "); switch (value) { case 0: @@ -349,7 +346,7 @@ void print_battery_charger_info() break; } bq24193_get_property(BQ24193_TempStatus, &value); - gfx_printf("Temperature status: "); + gfx_printf("Temperature status: "); switch (value) { case 0: diff --git a/bootloader/frontend/fe_tools.c b/bootloader/frontend/fe_tools.c index 61b6174..eb47fb0 100644 --- a/bootloader/frontend/fe_tools.c +++ b/bootloader/frontend/fe_tools.c @@ -155,6 +155,8 @@ void menu_autorcm() tui_do_menu(&menu); emmc_end(); + + free(ments); } #pragma GCC pop_options diff --git a/bootloader/hos/hos.c b/bootloader/hos/hos.c index 3c6c2d9..4504a4a 100644 --- a/bootloader/hos/hos.c +++ b/bootloader/hos/hos.c @@ -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,24 +340,9 @@ out: } } -int hos_keygen_t210b01(u32 kb) +static int _hos_keygen(void *keyblob, u32 kb, tsec_ctxt_t *tsec_ctxt, bool stock, bool is_exo) { - // Use SBK as Device key 4x unsealer and KEK for mkey in T210B01 units. - se_aes_unwrap_key(10, 14, console_keyseed_4xx); - - // Derive master key. - se_aes_unwrap_key(7, 12, master_kekseed_t210b01[kb - HOS_KB_VERSION_600]); - se_aes_unwrap_key(7, 7, master_keyseed_retail); - - // Derive latest pkg2 key. - se_aes_unwrap_key(8, 7, package2_keyseed); - - return 1; -} - -int hos_keygen(void *keyblob, u32 kb, tsec_ctxt_t *tsec_ctxt, bool stock, bool is_exo) -{ - static bool sbk_wiped = false; + static bool sbk_is_set = true; u32 retries = 0; bool use_tsec = false; @@ -363,16 +352,29 @@ int hos_keygen(void *keyblob, u32 kb, tsec_ctxt_t *tsec_ctxt, bool stock, bool i if (kb > HOS_KB_VERSION_MAX) return 0; + // Do Mariko keygen. if (h_cfg.t210b01) - return hos_keygen_t210b01(kb); + { + // Use SBK as Device key 4x unsealer and KEK for mkey in T210B01 units. + se_aes_unwrap_key(10, 14, console_keyseed_4xx); + + // Derive master key. + se_aes_unwrap_key(7, 12, master_kekseed_t210b01[kb - HOS_KB_VERSION_600]); + se_aes_unwrap_key(7, 7, master_keyseed_retail); + + // Derive latest pkg2 key. + se_aes_unwrap_key(8, 7, package2_keyseed); + + return 1; + } // Do Erista keygen. - // SBK is wiped. Try to restore it from fuses. - if (sbk_wiped) + // Check if SBK is wiped and try to restore it from fuses. + if (!sbk_is_set) { if (fuse_set_sbk()) - sbk_wiped = false; + sbk_is_set = true; else return 1; // Continue with current SE keys. } @@ -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; } diff --git a/bootloader/hos/hos.h b/bootloader/hos/hos.h index ba520ec..a04f650 100644 --- a/bootloader/hos/hos.h +++ b/bootloader/hos/hos.h @@ -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. @@ -103,16 +105,16 @@ typedef struct _launch_ctxt_t u32 kernel_size; link_t kip1_list; - char* kip1_patches; + char *kip1_patches; bool svcperm; bool debugmode; bool stock; bool emummc_forced; - void *fss0; - u32 fss0_hosver; - bool atmosphere; + void *pkg3; + u32 pkg3_hosver; + bool patch_krn_proc_id; int ucid; @@ -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 diff --git a/bootloader/hos/hos_config.c b/bootloader/hos/hos_config.c index f272f33..6bfb4a7 100644 --- a/bootloader/hos/hos_config.c +++ b/bootloader/hos/hos_config.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2018 naehrwert - * Copyright (c) 2018-2024 CTCaer + * Copyright (c) 2018-2025 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -21,7 +21,7 @@ #include "hos.h" #include "hos_config.h" -#include "fss.h" +#include "pkg3.h" #include //#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; } } } diff --git a/bootloader/hos/pkg1.c b/bootloader/hos/pkg1.c index 89b92a1..9d6b783 100644 --- a/bootloader/hos/pkg1.c +++ b/bootloader/hos/pkg1.c @@ -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() diff --git a/bootloader/hos/pkg2.c b/bootloader/hos/pkg2.c index 290b6b6..4ad838c 100644 --- a/bootloader/hos/pkg2.c +++ b/bootloader/hos/pkg2.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2018 naehrwert - * Copyright (c) 2018-2024 CTCaer + * Copyright (c) 2018-2025 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -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; + 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. diff --git a/bootloader/hos/pkg2.h b/bootloader/hos/pkg2.h index 7bd2449..551e46e 100644 --- a/bootloader/hos/pkg2.h +++ b/bootloader/hos/pkg2.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2018 naehrwert - * Copyright (c) 2018-2024 CTCaer + * Copyright (c) 2018-2025 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -20,16 +20,17 @@ #include -#define PKG2_MAGIC 0x31324B50 -#define PKG2_SEC_BASE 0x80000000 +#define PKG2_MAGIC 0x31324B50 +#define PKG2_SEC_BASE 0x80000000 #define PKG2_SEC_KERNEL 0 -#define PKG2_SEC_INI1 1 +#define PKG2_SEC_INI1 1 +#define PKG2_SEC_UNUSED 2 #define INI1_MAGIC 0x31494E49 //! TODO: Update on kernel change if needed. // Offset of OP + 12 is the INI1 offset. On v2 with dynamic crt0 it's + 16. -#define PKG2_NEWKERN_GET_INI1_HEURISTIC 0xD2800015 +#define PKG2_NEWKERN_GET_INI1_HEURISTIC 0xD2800015 // MOV X21, #0. #define PKG2_NEWKERN_START 0x800 #define ATM_MESOSPHERE 0x3053534D @@ -67,18 +68,18 @@ enum typedef struct _pkg2_hdr_t { - u8 ctr[0x10]; - u8 sec_ctr[0x40]; - u32 magic; - u32 base; - u32 pad0; - u8 pkg2_ver; - u8 bl_ver; - u16 pad1; - u32 sec_size[4]; - u32 sec_off[4]; - u8 sec_sha256[0x80]; - u8 data[]; +/* 0x000 */ u8 ctr[0x10]; +/* 0x010 */ u8 sec_ctr[0x40]; +/* 0x050 */ u32 magic; +/* 0x054 */ u32 base; +/* 0x058 */ u32 pad0; +/* 0x05C */ u8 pkg2_ver; +/* 0x05D */ u8 bl_ver; +/* 0x05E */ u16 pad1; +/* 0x060 */ u32 sec_size[4]; +/* 0x070 */ u32 sec_off[4]; +/* 0x080 */ u8 sec_sha256[0x80]; +/* 0x100 */ u8 data[]; } pkg2_hdr_t; typedef struct _pkg2_ini1_t @@ -102,7 +103,7 @@ typedef struct _pkg2_kip1_sec_t typedef struct _pkg2_kip1_t { /* 0x000 */ u32 magic; -/* 0x004*/ u8 name[12]; +/* 0x004 */ u8 name[12]; /* 0x010 */ u64 tid; /* 0x018 */ u32 proc_cat; /* 0x01C */ u8 main_thrd_prio; @@ -150,7 +151,6 @@ typedef struct _kip1_id_t const kip1_patchset_t *patchset; } kip1_id_t; -void pkg2_get_newkern_info(u8 *kern_data); bool pkg2_parse_kips(link_t *info, pkg2_hdr_t *pkg2, bool *new_pkg2); int pkg2_has_kip(link_t *info, u64 tid); void pkg2_replace_kip(link_t *info, u64 tid, pkg2_kip1_t *kip1); @@ -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); diff --git a/bootloader/hos/pkg2_ini_kippatch.c b/bootloader/hos/pkg2_ini_kippatch.c index 08aa5ad..9567eef 100644 --- a/bootloader/hos/pkg2_ini_kippatch.c +++ b/bootloader/hos/pkg2_ini_kippatch.c @@ -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); diff --git a/bootloader/hos/pkg2_ini_kippatch.h b/bootloader/hos/pkg2_ini_kippatch.h index e32f040..07881c1 100644 --- a/bootloader/hos/pkg2_ini_kippatch.h +++ b/bootloader/hos/pkg2_ini_kippatch.h @@ -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 diff --git a/bootloader/hos/pkg2_patches.inl b/bootloader/hos/pkg2_patches.inl index a44b9aa..075df1b 100644 --- a/bootloader/hos/pkg2_patches.inl +++ b/bootloader/hos/pkg2_patches.inl @@ -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 }; diff --git a/bootloader/hos/fss.c b/bootloader/hos/pkg3.c similarity index 51% rename from bootloader/hos/fss.c rename to bootloader/hos/pkg3.c index 6bb66f0..6752063 100644 --- a/bootloader/hos/fss.c +++ b/bootloader/hos/pkg3.c @@ -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 -#include "fss.h" +#include "pkg3.h" #include "hos.h" #include "../config.h" #include @@ -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; } diff --git a/bootloader/hos/fss.h b/bootloader/hos/pkg3.h similarity index 88% rename from bootloader/hos/fss.h rename to bootloader/hos/pkg3.h index e7e23bb..8d230ab 100644 --- a/bootloader/hos/fss.h +++ b/bootloader/hos/pkg3.h @@ -14,11 +14,11 @@ * along with this program. If not, see . */ -#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 diff --git a/bootloader/hos/secmon_exo.c b/bootloader/hos/secmon_exo.c index f060f3a..5b2d9f1 100644 --- a/bootloader/hos/secmon_exo.c +++ b/bootloader/hos/secmon_exo.c @@ -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,36 +241,36 @@ void config_exosphere(launch_ctxt_t *ctxt, u32 warmboot_base) } break; } + } - // Parse usb mtim settings. Avoid parsing if it's overridden. - if (!ctxt->exo_ctx.usb3_force) + // Parse usb mtim settings. Avoid parsing if it's overridden. + if (!ctxt->exo_ctx.usb3_force) + { + LIST_INIT(ini_sys_sections); + if (ini_parse(&ini_sys_sections, "atmosphere/config/system_settings.ini", false)) { - LIST_INIT(ini_sections); - if (ini_parse(&ini_sections, "atmosphere/config/system_settings.ini", false)) + LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_sys_sections, link) { - LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_sections, link) - { - // Only parse usb section. - if (!(ini_sec->type == INI_CHOICE) || strcmp(ini_sec->name, "usb")) - continue; + // Only parse usb section. + if (!(ini_sec->type == INI_CHOICE) || strcmp(ini_sec->name, "usb")) + continue; - LIST_FOREACH_ENTRY(ini_kv_t, kv, &ini_sec->kvs, link) + LIST_FOREACH_ENTRY(ini_kv_t, kv, &ini_sec->kvs, link) + { + if (!strcmp("usb30_force_enabled", kv->key)) { - if (!strcmp("usb30_force_enabled", kv->key)) - { - usb3_force = !strcmp("u8!0x1", kv->val); - break; // Only parse usb30_force_enabled key. - } + usb3_force = !strcmp("u8!0x1", kv->val); + break; // Only parse usb30_force_enabled key. } - break; } + break; } } } } - // To avoid problems, make private debug mode always on if not semi-stock. - if (!ctxt->stock || (emu_cfg.enabled && !h_cfg.emummc_force_disable)) + // Private debug mode always on for CFW mode. + if (!ctxt->stock) exo_flags |= EXO_FLAG_DBG_PRIV; // Enable user debug. diff --git a/bootloader/l4t/l4t.c b/bootloader/l4t/l4t.c index bcc025c..5c84825 100644 --- a/bootloader/l4t/l4t.c +++ b/bootloader/l4t/l4t.c @@ -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 @@ -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 -//! TODO: Update on dram config changes. +#define NA 0 // Default to 0 for incorrect dram ids. + +//!TODO: Update on dram config changes. static const u8 mtc_table_idx_t210b01[] = { /* 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 */ - -1, -1, -1, 7, -1, 7, 7, -1, 0, 1, 2, 3, 0, 1, 2, 3, -1, 4, 5, 4, 8, 8, 8, 5, 4, 6, 6, 6, 5, 9, 9, 9, 10, 10, 10 + NA, NA, NA, 7, NA, 7, 7, NA, 0, 1, 2, 3, 0, 1, 2, 3, NA, 4, 5, 4, 8, 8, 8, 5, 4, 6, 6, 6, 5, 9, 9, 9, 10, 10, 10 }; +#undef NA + static const l4t_fw_t l4t_fw[] = { { TZDRAM_BASE, "bl31.bin" }, { BL33_LOAD_BASE, "bl33.bin" }, { SC7ENTRY_BASE, "sc7entry.bin" }, { SC7EXIT_BASE, "sc7exit.bin" }, - { SC7EXIT_B01_BASE, "sc7exit_b01.bin" }, + { SC7EXIT_B01_BASE, "sc7exit_b01.bin" }, //!TODO: Update on fuse burns. { BPMPFW_BASE, "bpmpfw.bin" }, { BPMPFW_B01_BASE, "bpmpfw_b01.bin" }, { BPMPFW_B01_MTC_TABLE_BASE, "mtc_tbl_b01.bin" }, @@ -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) { @@ -895,9 +885,11 @@ static void _l4t_set_config(l4t_ctxt_t *ctxt, const ini_sec_t *ini_sec, int entr ctxt->ram_oc_vddq = 0; } else if (!strcmp("ram_oc_opt", kv->key)) - ctxt->ram_oc_opt = atoi(kv->val); + ctxt->ram_oc_opt = atoi(kv->val); else if (!strcmp("uart_port", kv->key)) ctxt->serial_port = atoi(kv->val); + else if (!strcmp("sld_type", kv->key)) + ctxt->sld_type = strtol(kv->val, NULL, 16); // Set key/val to BL33 env. _l4t_bl33_cfg_set_key(bl33_env, kv->key, kv->val); @@ -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); diff --git a/bootloader/libs/fatfs/ffconf.h b/bootloader/libs/fatfs/ffconf.h index 33516fe..c6b94bc 100644 --- a/bootloader/libs/fatfs/ffconf.h +++ b/bootloader/libs/fatfs/ffconf.h @@ -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 diff --git a/bootloader/main.c b/bootloader/main.c index d3e0cf9..4ec3eab 100644 --- a/bootloader/main.c +++ b/bootloader/main.c @@ -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); diff --git a/loader/Makefile b/loader/Makefile index f66a0e0..c2a12c0 100644 --- a/loader/Makefile +++ b/loader/Makefile @@ -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 $@ diff --git a/modules/hekate_libsys_minerva/mtc.h b/modules/hekate_libsys_minerva/mtc.h index 3a80e2c..860c7d7 100644 --- a/modules/hekate_libsys_minerva/mtc.h +++ b/modules/hekate_libsys_minerva/mtc.h @@ -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 diff --git a/nyx/Makefile b/nyx/Makefile index af7ab34..71709c5 100644 --- a/nyx/Makefile +++ b/nyx/Makefile @@ -93,12 +93,12 @@ CUSTOMDEFINES += -DGFX_INC=$(GFX_INC) -DFFCFG_INC=$(FFCFG_INC) #CUSTOMDEFINES += -DDEBUG_UART_LV_LOG #TODO: Considering reinstating some of these when pointer warnings have been fixed. -WARNINGS := -Wall -Wsign-compare -Wno-array-bounds -Wno-stringop-overread -Wno-stringop-overflow +WARNINGS := -Wall -Wsign-compare -Wtype-limits -Wno-array-bounds -Wno-stringop-overread -Wno-stringop-overflow #-fno-delete-null-pointer-checks #-Wstack-usage=byte-size -fstack-usage -ARCH := -march=armv4t -mtune=arm7tdmi -mthumb-interwork -CFLAGS = $(ARCH) -O2 -g -gdwarf-4 -nostdlib -ffunction-sections -fdata-sections -fomit-frame-pointer -std=gnu11 $(WARNINGS) $(CUSTOMDEFINES) +ARCH := -march=armv4t -mtune=arm7tdmi -mthumb-interwork $(WARNINGS) +CFLAGS = $(ARCH) -O2 -g -gdwarf-4 -nostdlib -ffunction-sections -fdata-sections -fomit-frame-pointer -std=gnu11 $(CUSTOMDEFINES) LDFLAGS = $(ARCH) -nostartfiles -lgcc -Wl,--nmagic,--gc-sections -Xlinker --defsym=NYX_LOAD_ADDR=$(NYX_LOAD_ADDR) ################################################################################ @@ -107,7 +107,7 @@ LDFLAGS = $(ARCH) -nostartfiles -lgcc -Wl,--nmagic,--gc-sections -Xlinker --defs all: $(TARGET).bin @echo "--------------------------------------" - @echo -n "Nyx size: " + @echo -n "Nyx size: " $(eval BIN_SIZE = $(shell wc -c < $(OUTPUTDIR)/$(TARGET).bin)) @echo $(BIN_SIZE)" Bytes" @echo "--------------------------------------" @@ -118,11 +118,11 @@ clean: @rm -rf $(OUTPUTDIR) $(TARGET).bin: $(BUILDDIR)/$(TARGET)/$(TARGET).elf - $(OBJCOPY) -S -O binary $< $(OUTPUTDIR)/$@ + @$(OBJCOPY) -S -O binary $< $(OUTPUTDIR)/$@ $(BUILDDIR)/$(TARGET)/$(TARGET).elf: $(OBJS) @$(CC) $(LDFLAGS) -T $(SOURCEDIR)/link.ld $^ -o $@ - @echo "Nyx was built with the following flags:\nCFLAGS: "$(CFLAGS)"\nLDFLAGS: "$(LDFLAGS) + @printf "$(TARGET) was built with the following flags:\nCFLAGS: $(CFLAGS)\nLDFLAGS: $(LDFLAGS)\n" $(BUILDDIR)/$(TARGET)/%.o: %.c @echo Building $@ diff --git a/nyx/nyx_gui/frontend/fe_emmc_tools.c b/nyx/nyx_gui/frontend/fe_emmc_tools.c index 3562594..2264f8a 100644 --- a/nyx/nyx_gui/frontend/fe_emmc_tools.c +++ b/nyx/nyx_gui/frontend/fe_emmc_tools.c @@ -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; @@ -622,10 +622,20 @@ static int _dump_emmc_part(emmc_tool_gui_t *gui, char *sd_path, int active_part, while (res_read) { - s_printf(gui->txt_buf, - "\n#FFDD00 Error reading %d blocks @ LBA %08X,#\n" - "#FFDD00 from eMMC (try %d). #", - num, lba_curr, ++retryCount); + if (!gui->raw_emummc) + { + s_printf(gui->txt_buf, + "\n#FFDD00 Error reading %d blocks @ LBA %08X,#\n" + "#FFDD00 from eMMC (try %d). #", + num, lba_curr, ++retryCount); + } + else + { + s_printf(gui->txt_buf, + "\n#FFDD00 Error reading %d blocks @ LBA %08X,#\n" + "#FFDD00 from emuMMC @ %08X (try %d). #", + num, lba_curr + sd_sector_off, lba_curr, ++retryCount); + } lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf); manual_system_maintenance(true); @@ -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"); - lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, txt_buf); + 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"); - lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, txt_buf); + 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"); - lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, txt_buf); + if (res >= 0) + lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, txt_buf); + else + res = 0; manual_system_maintenance(true); } } diff --git a/nyx/nyx_gui/frontend/fe_emummc_tools.c b/nyx/nyx_gui/frontend/fe_emummc_tools.c index 929a936..2fd7006 100644 --- a/nyx/nyx_gui/frontend/fe_emummc_tools.c +++ b/nyx/nyx_gui/frontend/fe_emummc_tools.c @@ -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) { diff --git a/nyx/nyx_gui/frontend/gui.c b/nyx/nyx_gui/frontend/gui.c index 9ba72fe..47bef3b 100644 --- a/nyx/nyx_gui/frontend/gui.c +++ b/nyx/nyx_gui/frontend/gui.c @@ -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 { diff --git a/nyx/nyx_gui/frontend/gui.h b/nyx/nyx_gui/frontend/gui.h index d2007b8..3f13444 100644 --- a/nyx/nyx_gui/frontend/gui.h +++ b/nyx/nyx_gui/frontend/gui.h @@ -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); diff --git a/nyx/nyx_gui/frontend/gui_emummc_tools.c b/nyx/nyx_gui/frontend/gui_emummc_tools.c index 62a5947..4182b22 100644 --- a/nyx/nyx_gui/frontend/gui_emummc_tools.c +++ b/nyx/nyx_gui/frontend/gui_emummc_tools.c @@ -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); diff --git a/nyx/nyx_gui/frontend/gui_info.c b/nyx/nyx_gui/frontend/gui_info.c index b464bfe..d7351ab 100644 --- a/nyx/nyx_gui/frontend/gui_info.c +++ b/nyx/nyx_gui/frontend/gui_info.c @@ -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 +#include + #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) + u32 random_numbers[4]; + for (u32 i = 0; i < rnd_off_cnt; i += 4) { // Generate new random numbers. while (!se_gen_prng128(random_numbers)) ; - // Clamp offsets to 512MB range. - random_offsets[i + 0] = random_numbers[0] % 0x100000; - random_offsets[i + 1] = random_numbers[1] % 0x100000; - random_offsets[i + 2] = random_numbers[2] % 0x100000; - random_offsets[i + 3] = random_numbers[3] % 0x100000; + // Clamp offsets to 256MB range. + random_offsets[i + 0] = random_numbers[0] % sct_rem_4kb; + random_offsets[i + 1] = random_numbers[1] % sct_rem_4kb; + random_offsets[i + 2] = random_numbers[2] % sct_rem_4kb; + random_offsets[i + 3] = random_numbers[3] % sct_rem_4kb; } pct = 0; prevPct = 200; timer = 0; - data_remaining = 0x100000; // 512MB. + data_remaining = sct_rem_4kb; + loop_idx = 0; render_timer = get_tmr_ms() + render_min_ms; while (data_remaining) { u32 time_taken = get_tmr_us(); - error = !sdmmc_storage_read(storage, sector + random_offsets[lba_idx], sector_num, (u8 *)MIXD_BUF_ALIGNED); + error = !sdmmc_storage_read(storage, sector_off + random_offsets[lba_idx], sector_num, (u8 *)MIXD_BUF_ALIGNED); time_taken = get_tmr_us() - time_taken; + timer += time_taken; + times_taken_4k[loop_idx++] = time_taken; manual_system_maintenance(false); data_remaining -= sector_num; lba_idx++; - pct = (lba_idx * 100) / 0x20000; + pct = (lba_idx * 100) / rnd_off_cnt; if (pct != prevPct && render_timer < get_tmr_ms()) { lv_bar_set_value(bar, pct); @@ -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); diff --git a/nyx/nyx_gui/frontend/gui_options.c b/nyx/nyx_gui/frontend/gui_options.c index 3d78007..15feeac 100644 --- a/nyx/nyx_gui/frontend/gui_options.c +++ b/nyx/nyx_gui/frontend/gui_options.c @@ -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 #include -#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,8 +954,8 @@ 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; + + error = f_open(&fp, "switchroot/switch.cal", FA_WRITE | FA_CREATE_ALWAYS) ? 4 : 0; if (!error) { f_puts(data, &fp); @@ -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) diff --git a/nyx/nyx_gui/frontend/gui_tools_partition_manager.c b/nyx/nyx_gui/frontend/gui_tools_partition_manager.c index 114035c..3ea91cb 100644 --- a/nyx/nyx_gui/frontend/gui_tools_partition_manager.c +++ b/nyx/nyx_gui/frontend/gui_tools_partition_manager.c @@ -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) { - free(gpt); + 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; - return true; + if (found) + { + free(gpt); + + 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); diff --git a/nyx/nyx_gui/hos/hos.c b/nyx/nyx_gui/hos/hos.c index 94dd00b..cef7bbe 100644 --- a/nyx/nyx_gui/hos/hos.c +++ b/nyx/nyx_gui/hos/hos.c @@ -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,21 +337,6 @@ out: } } -int hos_keygen_t210b01(u32 kb) -{ - // Use SBK as Device key 4x unsealer and KEK for mkey in T210B01 units. - se_aes_unwrap_key(10, 14, console_keyseed_4xx); - - // Derive master key. - se_aes_unwrap_key(7, 12, master_kekseed_t210b01[kb - HOS_KB_VERSION_600]); - se_aes_unwrap_key(7, 7, master_keyseed_retail); - - // Derive latest pkg2 key. - se_aes_unwrap_key(8, 7, package2_keyseed); - - return 1; -} - int hos_keygen(void *keyblob, u32 kb, tsec_ctxt_t *tsec_ctxt) { u32 retries = 0; @@ -354,8 +347,21 @@ int hos_keygen(void *keyblob, u32 kb, tsec_ctxt_t *tsec_ctxt) if (kb > HOS_KB_VERSION_MAX) return 0; + // Do Mariko keygen. if (h_cfg.t210b01) - return hos_keygen_t210b01(kb); + { + // Use SBK as Device key 4x unsealer and KEK for mkey in T210B01 units. + se_aes_unwrap_key(10, 14, console_keyseed_4xx); + + // Derive master key. + se_aes_unwrap_key(7, 12, master_kekseed_t210b01[kb - HOS_KB_VERSION_600]); + se_aes_unwrap_key(7, 7, master_keyseed_retail); + + // Derive latest pkg2 key. + se_aes_unwrap_key(8, 7, package2_keyseed); + + return 1; + } // Do Erista keygen. @@ -363,7 +369,7 @@ int hos_keygen(void *keyblob, u32 kb, tsec_ctxt_t *tsec_ctxt) _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) diff --git a/nyx/nyx_gui/hos/hos.h b/nyx/nyx_gui/hos/hos.h index c702a32..bdc82b9 100644 --- a/nyx/nyx_gui/hos/hos.h +++ b/nyx/nyx_gui/hos/hos.h @@ -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. diff --git a/nyx/nyx_gui/hos/pkg1.c b/nyx/nyx_gui/hos/pkg1.c index e0c8137..f0a4d53 100644 --- a/nyx/nyx_gui/hos/pkg1.c +++ b/nyx/nyx_gui/hos/pkg1.c @@ -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; diff --git a/nyx/nyx_gui/hos/pkg2.c b/nyx/nyx_gui/hos/pkg2.c index 4fb4c3e..7b6d6cb 100644 --- a/nyx/nyx_gui/hos/pkg2.c +++ b/nyx/nyx_gui/hos/pkg2.c @@ -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) diff --git a/nyx/nyx_gui/hos/pkg2.h b/nyx/nyx_gui/hos/pkg2.h index 619d01c..df24639 100644 --- a/nyx/nyx_gui/hos/pkg2.h +++ b/nyx/nyx_gui/hos/pkg2.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2018 naehrwert - * Copyright (c) 2018-2023 CTCaer + * Copyright (c) 2018-2025 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -20,16 +20,17 @@ #include -#define PKG2_MAGIC 0x31324B50 -#define PKG2_SEC_BASE 0x80000000 +#define PKG2_MAGIC 0x31324B50 +#define PKG2_SEC_BASE 0x80000000 #define PKG2_SEC_KERNEL 0 -#define PKG2_SEC_INI1 1 +#define PKG2_SEC_INI1 1 +#define PKG2_SEC_UNUSED 2 #define INI1_MAGIC 0x31494E49 //! TODO: Update on kernel change if needed. // Offset of OP + 12 is the INI1 offset. On v2 with dynamic crt0 it's + 16. -#define PKG2_NEWKERN_GET_INI1_HEURISTIC 0xD2800015 +#define PKG2_NEWKERN_GET_INI1_HEURISTIC 0xD2800015 // MOV X21, #0. #define PKG2_NEWKERN_START 0x800 extern u32 pkg2_newkern_ini1_start; diff --git a/nyx/nyx_gui/nyx.c b/nyx/nyx_gui/nyx.c index 86d90cd..05275a2 100644 --- a/nyx/nyx_gui/nyx.c +++ b/nyx/nyx_gui/nyx.c @@ -402,7 +402,7 @@ error_occured: msleep(1000); btn_wait(); - reload_nyx(); + reload_nyx(NULL, true); } } diff --git a/nyx/nyx_gui/start.S b/nyx/nyx_gui/start.S index 0d1eebf..c2333f7 100644 --- a/nyx/nyx_gui/start.S +++ b/nyx/nyx_gui/start.S @@ -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 diff --git a/res/hekate_ipl_template.ini b/res/hekate_ipl_template.ini index b717c44..fcb886a 100644 --- a/res/hekate_ipl_template.ini +++ b/res/hekate_ipl_template.ini @@ -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.