Compare commits

..

26 Commits

Author SHA1 Message Date
ctcaer@gmail.com
03268c4655 Bump version to v4.10.1 2019-04-23 18:23:17 +03:00
ctcaer@gmail.com
072bbcabf4 [HOS] Use sha256 for kernel hashing 2019-04-23 18:17:55 +03:00
ctcaer@gmail.com
7c877c5bce [HOS] Normalize new pkg2 identification 2019-04-23 03:41:07 +03:00
ctcaer@gmail.com
6aa1bdd1c6 [HOS] Fix pk2 decr after running 2nd time on 7.x+
This could happen after a pkg1/2 dump or a failed hos launch.

The 2nd time a dump or launch would be attempted, it would fail.
2019-04-23 03:38:35 +03:00
ctcaer@gmail.com
91606334c4 [sdmmc] Revert 204MHz sd device clock
Again some Sandisk U1 cards do not behave at all at speeds like that (204MHz / 102MB/s).

Revert back to 163.2MHz / 81.6MB/s.
2019-04-23 03:34:39 +03:00
ctcaer@gmail.com
25f6e91677 [sdmmc] Fix Sandisk U1 fast power cycle
Some Sandisk U1 sd cards do not behave nicely if they power cycle too fast. A min 100ms wait, is enough to mitigate that.

Fortunately, because of how the code paths are structured, this was never hit.
2019-04-23 03:31:16 +03:00
ctcaer@gmail.com
36d2da5d79 Bump version to v4.10.0 2019-04-21 17:38:29 +03:00
ctcaer@gmail.com
fd0dc04953 [HOS] Add full 8.0.0 support
Additionally, allow pkg1 to be dumped if unknown fw version.
2019-04-21 17:37:12 +03:00
ctcaer@gmail.com
8eb5ee867d [GFX] Finish ctxt global usage
Plus:
- Some whitespace fixes
- Allow UHS bus to reach max 102MB/s from 81.6MB/s
2019-04-21 17:33:39 +03:00
CTCaer
5d99f2fcf7 Merge pull request #208 from shchmue/master
[TSEC] Fix tsec timeout
2019-04-19 19:08:19 +03:00
shchmue
e34a7543b1 [TSEC] Fix tsec timeout
Without increasing probability of a race condition
2019-04-19 11:54:09 -04:00
ctcaer@gmail.com
c80fecd080 [main] Add brick protection for RCM patched units
- If AutoRCM was found enabled, force disable it.
 (In case of chainloading.)
- Additionally disable AutoRCM function.
2019-04-16 20:09:04 +03:00
ctcaer@gmail.com
ed047ef5f5 [Tool] Support AutoRCM on devkits 2019-04-16 20:05:35 +03:00
ctcaer@gmail.com
a2ba2ecf26 Battery "desync" fix is now applied on boot 2019-04-16 19:58:12 +03:00
ctcaer@gmail.com
07fe94b6d4 [exo] Add exosphere panic report save to sd 2019-04-14 04:24:37 +03:00
ctcaer@gmail.com
ca0c0f786c [Tools] Add status bar update while fixing arc bit 2019-04-14 02:41:29 +03:00
ctcaer@gmail.com
b0af57f98a [GFX] Refactor gfx to utilize global contexts 2019-04-14 02:30:14 +03:00
ctcaer@gmail.com
5ba4848571 Various bugfixes
- Add error msg for what fails in a particular ini boot entry
- Fix wrongly defined s8 type
- Change raw fuse dump to correct size
2019-04-14 02:19:04 +03:00
TehPsychedelic
2a2db6cb2f Added autoboot_list to README (#205)
* Added autoboot_list to README
2019-03-30 19:10:49 +02:00
CTCaer
361f8a3085 Correct byte offsets for boot cfg. Thanks @WerWolv 2019-03-21 08:45:33 +02:00
ctcaer@gmail.com
961768e14e [sd tools] Utilize sd_file_read better
Additionally fix a long standing fread/fwrite bug, via a FatFS fix.
(Doesn't affect Tegra arch though)
2019-03-16 23:35:43 +02:00
Kostas Missos
491c4efe9c [FatFS] Update to R0.13c (p3) 2019-03-13 12:27:43 +02:00
Kostas Missos
ff9671c481 Bump version to v4.9.1 2019-03-10 00:38:18 +02:00
CTCaer
da1bb77d8e Modernize hekate_ipl.ini for 4.9.1 and HOS7 2019-03-09 21:10:16 +02:00
Kostas Missos
14c50ed7f8 [Stock] Add cleaner stock
[Stock]
fss0={sd path}
stock=1

Can now work for both older and new HOS versions.

- <= 6.2.0 loads nothing and removes kernel patching.
- >= 7.0.0 loads exo, wb and removes kernel patching.

This requires that fss0 {sd path} is valid. Otherwise it will fail on ini cfg parsing.

If <= 6.2.0 and no FSS0
[Stock]
stock=1

will provide a cleaner stock with no kernel patching.
2019-03-09 20:49:00 +02:00
Kostas Missos
61401d733e [eMMC Tools] Fix verif file offset and print alignment 2019-03-09 20:39:54 +02:00
50 changed files with 1512 additions and 1101 deletions

View File

@@ -9,8 +9,8 @@ include $(DEVKITARM)/base_rules
IPL_LOAD_ADDR := 0x40008000
IPL_MAGIC := 0x43544349 #"ICTC"
BLVERSION_MAJOR := 4
BLVERSION_MINOR := 9
BLVERSION_HOTFX := 0
BLVERSION_MINOR := 10
BLVERSION_HOTFX := 1
BL_RESERVED := 0
@@ -94,7 +94,7 @@ $(MODULEDIRS):
$(TARGET).bin: $(BUILDDIR)/$(TARGET)/$(TARGET).elf $(MODULEDIRS)
$(OBJCOPY) -S -O binary $< $(OUTPUTDIR)/$@
@printf ICTC$(BLVERSION_MAJOR)$(BLVERSION_MINOR) >> $(OUTPUTDIR)/$@
@printf ICTC49 >> $(OUTPUTDIR)/$@
$(BUILDDIR)/$(TARGET)/$(TARGET).elf: $(OBJS)
$(CC) $(LDFLAGS) -T $(SOURCEDIR)/link.ld $^ -o $@

View File

@@ -36,6 +36,7 @@ There are four possible type of entries. "**[ ]**": Boot entry, "**{ }**": Capti
| 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. |
| verification=2 | 0: Disable Backup/Restore verification, 1: Sparse (block based, fast and not 100% reliable), 2: Full (sha256 based, slow and 100% reliable). |
| autohosoff=1 | 0: Disable, 1: If woke up from HOS via an RTC alarm, shows logo, then powers off completely, 2: No logo, immediately powers off.|
@@ -58,9 +59,10 @@ There are four possible type of entries. "**[ ]**": Boot entry, "**{ }**": Capti
| fullsvcperm=1 | Disables SVC verification (full services permission) |
| debugmode=1 | Enables Debug mode. Obsolete when used with exosphere as secmon. |
| atmosphere=1 | Enables Atmosphère patching |
| stock=1 | Disables unneeded kernel patching when running stock or semi-stock. |
| payload={SD path} | Payload launching. Tools, Linux, CFW bootloaders, etc. |
**Note1**: When using the wildcard (`/*`) with `kip1` you can still use the normal `kip1` after that to load extra signle kips.
**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`.
You can define `kip1` to load an extra kip or many via the wildcard (`/*`) usage.
@@ -75,10 +77,10 @@ Hekate now has a new storage in the binary that helps it configure it outside of
| Offset / Name | Description |
| -------------------- | ----------------------------------------------------------------- |
| '0x94' boot_cfg | bit0: Force AutoBoot, bit1: Show launch log, bit2: sept run. |
| '0x98' autoboot | If `Force AutoBoot`: 0: Force go to menu, else boot that entry. |
| '0x9C' autoboot_list | If `Force AutoBoot` and `autoboot` then it boots from ini folder. |
| '0xA0' extra_cfg | Reserved. |
| '0xA4' rsvd[128] | Reserved. |
| '0x95' autoboot | If `Force AutoBoot`: 0: Force go to menu, else boot that entry. |
| '0x96' autoboot_list | If `Force AutoBoot` and `autoboot` then it boots from ini folder. |
| '0x97' extra_cfg | Reserved. |
| '0x98' rsvd[128] | Reserved. |
You can find a template [Here](./res/hekate_ipl_template.ini)

View File

@@ -44,6 +44,8 @@ void set_default_configuration()
h_cfg.errors = 0;
h_cfg.autonogc = 1;
h_cfg.sept_run = EMC(EMC_SCRATCH0) & EMC_SEPT_RUN;
h_cfg.rcm_patched = true;
h_cfg.sd_timeoff = 0;
}
int create_config_entry()
@@ -154,20 +156,20 @@ int create_config_entry()
static void _save_config()
{
gfx_clear_grey(&gfx_ctxt, 0x1B);
gfx_con_setpos(&gfx_con, 0, 0);
gfx_clear_grey(0x1B);
gfx_con_setpos(0, 0);
if (!create_config_entry())
gfx_puts(&gfx_con, "\nConfiguration was saved!\n");
gfx_puts("\nConfiguration was saved!\n");
else
EPRINTF("\nConfiguration saving failed!");
gfx_puts(&gfx_con, "\nPress any key...");
gfx_puts("\nPress any key...");
}
static void _config_autoboot_list(void *ent)
{
gfx_clear_grey(&gfx_ctxt, 0x1B);
gfx_con_setpos(&gfx_con, 0, 0);
gfx_clear_grey(0x1B);
gfx_con_setpos(0, 0);
u32 *temp_autoboot = NULL;
@@ -225,7 +227,7 @@ static void _config_autoboot_list(void *ent)
memset(&ments[i], 0, sizeof(ment_t));
menu_t menu = {ments, "Select an entry to auto boot", 0, 0};
temp_autoboot = (u32 *)tui_do_menu(&gfx_con, &menu);
temp_autoboot = (u32 *)tui_do_menu(&menu);
if (temp_autoboot != NULL)
{
h_cfg.autoboot = *(u32 *)temp_autoboot;
@@ -258,8 +260,8 @@ out2:;
void config_autoboot()
{
gfx_clear_grey(&gfx_ctxt, 0x1B);
gfx_con_setpos(&gfx_con, 0, 0);
gfx_clear_grey(0x1B);
gfx_con_setpos(0, 0);
u32 *temp_autoboot = NULL;
@@ -341,7 +343,7 @@ void config_autoboot()
memset(&ments[i], 0, sizeof(ment_t));
menu_t menu = {ments, "Disable or select entry to auto boot", 0, 0};
temp_autoboot = (u32 *)tui_do_menu(&gfx_con, &menu);
temp_autoboot = (u32 *)tui_do_menu(&menu);
if (temp_autoboot != NULL)
{
h_cfg.autoboot = *(u32 *)temp_autoboot;
@@ -374,8 +376,8 @@ out2:;
void config_bootdelay()
{
gfx_clear_grey(&gfx_ctxt, 0x1B);
gfx_con_setpos(&gfx_con, 0, 0);
gfx_clear_grey(0x1B);
gfx_con_setpos(0, 0);
u32 delay_entries = 6;
@@ -416,7 +418,7 @@ void config_bootdelay()
memset(&ments[i + 2], 0, sizeof(ment_t));
menu_t menu = {ments, "Time delay for entering bootloader menu", 0, 0};
u32 *temp_bootwait = (u32 *)tui_do_menu(&gfx_con, &menu);
u32 *temp_bootwait = (u32 *)tui_do_menu(&menu);
if (temp_bootwait != NULL)
{
h_cfg.bootwait = *(u32 *)temp_bootwait;
@@ -434,8 +436,8 @@ void config_bootdelay()
void config_verification()
{
gfx_clear_grey(&gfx_ctxt, 0x1B);
gfx_con_setpos(&gfx_con, 0, 0);
gfx_clear_grey(0x1B);
gfx_con_setpos(0, 0);
ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * 6);
u32 *vr_values = (u32 *)malloc(sizeof(u32) * 3);
@@ -469,7 +471,7 @@ void config_verification()
memset(&ments[5], 0, sizeof(ment_t));
menu_t menu = {ments, "Backup & Restore verification", 0, 0};
u32 *temp_verification = (u32 *)tui_do_menu(&gfx_con, &menu);
u32 *temp_verification = (u32 *)tui_do_menu(&menu);
if (temp_verification != NULL)
{
h_cfg.verification = *(u32 *)temp_verification;
@@ -487,8 +489,8 @@ void config_verification()
void config_backlight()
{
gfx_clear_grey(&gfx_ctxt, 0x1B);
gfx_con_setpos(&gfx_con, 0, 0);
gfx_clear_grey(0x1B);
gfx_con_setpos(0, 0);
u32 bri_entries = 11;
@@ -528,7 +530,7 @@ void config_backlight()
memset(&ments[i + 1], 0, sizeof(ment_t));
menu_t menu = {ments, "Backlight brightness", 0, 0};
u32 *temp_backlight = (u32 *)tui_do_menu(&gfx_con, &menu);
u32 *temp_backlight = (u32 *)tui_do_menu(&menu);
if (temp_backlight != NULL)
{
h_cfg.backlight = (*(u32 *)temp_backlight) * 2;
@@ -546,8 +548,8 @@ void config_backlight()
void config_auto_hos_poweroff()
{
gfx_clear_grey(&gfx_ctxt, 0x1B);
gfx_con_setpos(&gfx_con, 0, 0);
gfx_clear_grey(0x1B);
gfx_con_setpos(0, 0);
ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * 6);
u32 *hp_values = (u32 *)malloc(sizeof(u32) * 3);
@@ -586,7 +588,7 @@ void config_auto_hos_poweroff()
memset(&ments[5], 0, sizeof(ment_t));
menu_t menu = {ments, "Power off if woke up from HOS", 0, 0};
u32 *temp_autohosoff = (u32 *)tui_do_menu(&gfx_con, &menu);
u32 *temp_autohosoff = (u32 *)tui_do_menu(&menu);
if (temp_autohosoff != NULL)
{
h_cfg.autohosoff = *(u32 *)temp_autohosoff;
@@ -603,8 +605,8 @@ void config_auto_hos_poweroff()
void config_nogc()
{
gfx_clear_grey(&gfx_ctxt, 0x1B);
gfx_con_setpos(&gfx_con, 0, 0);
gfx_clear_grey(0x1B);
gfx_con_setpos(0, 0);
ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * 5);
u32 *cb_values = (u32 *)malloc(sizeof(u32) * 2);
@@ -635,7 +637,7 @@ void config_nogc()
memset(&ments[4], 0, sizeof(ment_t));
menu_t menu = {ments, "No Gamecard", 0, 0};
u32 *temp_nogc = (u32 *)tui_do_menu(&gfx_con, &menu);
u32 *temp_nogc = (u32 *)tui_do_menu(&menu);
if (temp_nogc != NULL)
{
h_cfg.autonogc = *(u32 *)temp_nogc;

View File

@@ -30,10 +30,12 @@ typedef struct _hekate_config
u32 autohosoff;
u32 autonogc;
// Global temporary config.
int se_keygen_done;
bool se_keygen_done;
u32 sbar_time_keeping;
u32 errors;
int sept_run;
bool rcm_patched;
u32 sd_timeoff;
} hekate_config;
typedef enum

View File

@@ -1,7 +1,7 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (c) 2018 Rajko Stojadinovic
* Copyright (c) 2018 CTCaer
* Copyright (c) 2018-2019 CTCaer
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@@ -35,6 +35,8 @@
#define SDXC_BUF_ALIGNED 0xB6000000
#define MIXD_BUF_ALIGNED 0xB7000000
#define NUM_SECTORS_PER_ITER 8192 // 4MB Cache.
extern sdmmc_t sd_sdmmc;
extern sdmmc_storage_t sd_storage;
extern FATFS sd_fs;
@@ -47,11 +49,11 @@ extern void emmcsn_path_impl(char *path, char *sub_dir, char *filename, sdmmc_st
static int _dump_emmc_verify(sdmmc_storage_t *storage, u32 lba_curr, char *outFilename, emmc_part_t *part)
{
FIL fp;
u8 sparseShouldVerify = 0;
u8 sparseShouldVerify = 4;
u32 btn = 0;
u32 prevPct = 200;
int res = 0;
u32 sdFileSector = 0;
int res = 0;
u8 hashEm[0x20];
u8 hashSd[0x20];
@@ -60,13 +62,11 @@ static int _dump_emmc_verify(sdmmc_storage_t *storage, u32 lba_curr, char *outFi
{
u32 totalSectorsVer = (u32)((u64)f_size(&fp) >> (u64)9);
const u32 NUM_SECTORS_PER_ITER = 8192; // 4MB Cache.
u8 *bufEm = (u8 *)EMMC_BUF_ALIGNED;
u8 *bufSd = (u8 *)SDXC_BUF_ALIGNED;
u32 pct = (u64)((u64)(lba_curr - part->lba_start) * 100u) / (u64)(part->lba_end - part->lba_start);
tui_pbar(&gfx_con, 0, gfx_con.y, pct, 0xFF96FF00, 0xFF155500);
tui_pbar(0, gfx_con.y, pct, 0xFF96FF00, 0xFF155500);
u32 num = 0;
while (totalSectorsVer > 0)
@@ -87,7 +87,7 @@ static int _dump_emmc_verify(sdmmc_storage_t *storage, u32 lba_curr, char *outFi
f_close(&fp);
return 1;
}
f_lseek(&fp, sdFileSector);
f_lseek(&fp, (u64)sdFileSector << (u64)9);
if (f_read(&fp, bufSd, num << 9, NULL))
{
gfx_con.fntsz = 16;
@@ -111,25 +111,24 @@ static int _dump_emmc_verify(sdmmc_storage_t *storage, u32 lba_curr, char *outFi
}
}
sparseShouldVerify++;
sdFileSector += NUM_SECTORS_PER_ITER << 9;
pct = (u64)((u64)(lba_curr - part->lba_start) * 100u) / (u64)(part->lba_end - part->lba_start);
if (pct != prevPct)
{
tui_pbar(&gfx_con, 0, gfx_con.y, pct, 0xFF96FF00, 0xFF155500);
tui_pbar(0, gfx_con.y, pct, 0xFF96FF00, 0xFF155500);
prevPct = pct;
}
lba_curr += num;
totalSectorsVer -= num;
sdFileSector += num;
sparseShouldVerify++;
btn = btn_wait_timeout(0, BTN_VOL_DOWN | BTN_VOL_UP);
if ((btn & BTN_VOL_DOWN) && (btn & BTN_VOL_UP))
{
gfx_con.fntsz = 16;
WPRINTF("\n\nVerification was cancelled!");
EPRINTF("\nPress any key...\n");
gfx_con.fntsz = 8;
msleep(1000);
f_close(&fp);
@@ -139,7 +138,7 @@ static int _dump_emmc_verify(sdmmc_storage_t *storage, u32 lba_curr, char *outFi
}
f_close(&fp);
tui_pbar(&gfx_con, 0, gfx_con.y, pct, 0xFFCCCCCC, 0xFF555555);
tui_pbar(0, gfx_con.y, pct, 0xFFCCCCCC, 0xFF555555);
return 0;
}
@@ -184,7 +183,7 @@ static int _dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t
memcpy(partialIdxFilename, "partial.idx", 12);
gfx_con.fntsz = 8;
gfx_printf(&gfx_con, "\nSD Card free space: %d MiB, Total backup size %d MiB\n\n",
gfx_printf("\nSD Card free space: %d MiB, Total backup size %d MiB\n\n",
sd_fs.free_clst * sd_fs.csize >> SECTORS_TO_MIB_COEFF,
totalSectors >> SECTORS_TO_MIB_COEFF);
@@ -199,7 +198,7 @@ static int _dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t
{
isSmallSdCard = true;
gfx_printf(&gfx_con, "%k\nSD card free space is smaller than total backup size.%k\n", 0xFFFFBA00, 0xFFCCCCCC);
gfx_printf("%k\nSD card free space is smaller than total backup size.%k\n", 0xFFFFBA00, 0xFFCCCCCC);
if (!maxSplitParts)
{
@@ -212,7 +211,7 @@ static int _dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t
// Check if we are continuing a previous raw eMMC or USER partition backup in progress.
if (f_open(&partialIdxFp, partialIdxFilename, FA_READ) == FR_OK && totalSectors > (FAT32_FILESIZE_LIMIT / NX_EMMC_BLOCKSIZE))
{
gfx_printf(&gfx_con, "%kFound Partial Backup in progress. Continuing...%k\n\n", 0xFFAEFD14, 0xFFCCCCCC);
gfx_printf("%kFound Partial Backup in progress. Continuing...%k\n\n", 0xFFAEFD14, 0xFFCCCCCC);
partialDumpInProgress = true;
// Force partial dumping, even if the card is larger.
@@ -233,7 +232,7 @@ static int _dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t
maxSplitParts += currPartIdx;
}
else if (isSmallSdCard)
gfx_printf(&gfx_con, "%kPartial Backup enabled (with %d MiB parts)...%k\n\n", 0xFFFFBA00, multipartSplitSize >> 20, 0xFFCCCCCC);
gfx_printf("%kPartial Backup enabled (with %d MiB parts)...%k\n\n", 0xFFFFBA00, multipartSplitSize >> 20, 0xFFCCCCCC);
// Check if filesystem is FAT32 or the free space is smaller and backup in parts.
if (((sd_fs.fs_type != FS_EXFAT) && totalSectors > (FAT32_FILESIZE_LIMIT / NX_EMMC_BLOCKSIZE)) | isSmallSdCard)
@@ -248,7 +247,7 @@ static int _dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t
}
FIL fp;
gfx_con_getpos(&gfx_con, &gfx_con.savedx, &gfx_con.savedy);
gfx_con_getpos(&gfx_con.savedx, &gfx_con.savedy);
if (!f_open(&fp, outFilename, FA_READ))
{
f_close(&fp);
@@ -261,10 +260,10 @@ static int _dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t
if (!(btn_wait() & BTN_POWER))
return 0;
gfx_con.fntsz = 8;
gfx_clear_partial_grey(&gfx_ctxt, 0x1B, gfx_con.savedy, 48);
gfx_clear_partial_grey(0x1B, gfx_con.savedy, 48);
}
gfx_con_setpos(&gfx_con, gfx_con.savedx, gfx_con.savedy);
gfx_printf(&gfx_con, "Filename: %s\n\n", outFilename);
gfx_con_setpos(gfx_con.savedx, gfx_con.savedy);
gfx_printf("Filename: %s\n\n", outFilename);
res = f_open(&fp, outFilename, FA_CREATE_ALWAYS | FA_WRITE);
if (res)
{
@@ -274,8 +273,6 @@ static int _dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t
return 0;
}
const u32 NUM_SECTORS_PER_ITER = 8192;
u8 *buf = (u8 *)MIXD_BUF_ALIGNED;
u32 lba_curr = part->lba_start;
@@ -292,7 +289,7 @@ static int _dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t
lbaStartPart = lba_curr; // Update the start LBA for verification.
}
u64 totalSize = (u64)((u64)totalSectors << 9);
if (!isSmallSdCard && sd_fs.fs_type == FS_EXFAT)
if (!isSmallSdCard && (sd_fs.fs_type == FS_EXFAT || totalSize <= FAT32_FILESIZE_LIMIT))
f_lseek(&fp, totalSize);
else
f_lseek(&fp, MIN(totalSize, multipartSplitSize));
@@ -341,7 +338,7 @@ static int _dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t
// More parts to backup that do not currently fit the sd card free space or fatal error.
if (currPartIdx >= maxSplitParts)
{
gfx_puts(&gfx_con, "\n\n1. Press any key to unmount SD Card.\n\
gfx_puts("\n\n1. Press any key to unmount SD Card.\n\
2. Remove SD Card and move files to free space.\n\
Don\'t move the partial.idx file!\n\
3. Re-insert SD Card.\n\
@@ -353,8 +350,8 @@ static int _dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t
}
// Create next part.
gfx_con_setpos(&gfx_con, gfx_con.savedx, gfx_con.savedy);
gfx_printf(&gfx_con, "Filename: %s\n\n", outFilename);
gfx_con_setpos(gfx_con.savedx, gfx_con.savedy);
gfx_printf("Filename: %s\n\n", outFilename);
lbaStartPart = lba_curr;
res = f_open(&fp, outFilename, FA_CREATE_ALWAYS | FA_WRITE);
if (res)
@@ -407,7 +404,7 @@ static int _dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t
pct = (u64)((u64)(lba_curr - part->lba_start) * 100u) / (u64)(part->lba_end - part->lba_start);
if (pct != prevPct)
{
tui_pbar(&gfx_con, 0, gfx_con.y, pct, 0xFFCCCCCC, 0xFF555555);
tui_pbar(0, gfx_con.y, pct, 0xFFCCCCCC, 0xFF555555);
prevPct = pct;
}
@@ -436,7 +433,7 @@ static int _dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t
return 0;
}
}
tui_pbar(&gfx_con, 0, gfx_con.y, 100, 0xFFCCCCCC, 0xFF555555);
tui_pbar(0, gfx_con.y, 100, 0xFFCCCCCC, 0xFF555555);
// Backup operation ended successfully.
f_close(&fp);
@@ -451,7 +448,7 @@ static int _dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t
return 0;
}
else
tui_pbar(&gfx_con, 0, gfx_con.y, 100, 0xFF96FF00, 0xFF155500);
tui_pbar(0, gfx_con.y, 100, 0xFF96FF00, 0xFF155500);
}
gfx_con.fntsz = 16;
@@ -459,9 +456,9 @@ static int _dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t
if (isSmallSdCard)
{
f_unlink(partialIdxFilename);
gfx_printf(&gfx_con, "%k\n\nYou can now join the files\nand get the complete eMMC RAW GPP backup.", 0xFFCCCCCC);
gfx_printf("%k\n\nYou can now join the files\nand get the complete eMMC RAW GPP backup.", 0xFFCCCCCC);
}
gfx_puts(&gfx_con, "\n\n");
gfx_puts("\n\n");
return 1;
}
@@ -479,14 +476,14 @@ static void _dump_emmc_selected(emmcPartType_t dumpType)
{
int res = 0;
u32 timer = 0;
gfx_clear_partial_grey(&gfx_ctxt, 0x1B, 0, 1256);
tui_sbar(&gfx_con, true);
gfx_con_setpos(&gfx_con, 0, 0);
gfx_clear_partial_grey(0x1B, 0, 1256);
tui_sbar(true);
gfx_con_setpos(0, 0);
if (!sd_mount())
goto out;
gfx_puts(&gfx_con, "Checking for available free space...\n\n");
gfx_puts("Checking for available free space...\n\n");
// Get SD Card free space for Partial Backup.
f_getfree("", &sd_fs.free_clst, NULL);
@@ -519,7 +516,7 @@ static void _dump_emmc_selected(emmcPartType_t dumpType)
bootPart.name[4] = (u8)('0' + i);
bootPart.name[5] = 0;
gfx_printf(&gfx_con, "%k%02d: %s (%07X-%07X)%k\n", 0xFF00DDFF, i,
gfx_printf("%k%02d: %s (%07X-%07X)%k\n", 0xFF00DDFF, i,
bootPart.name, bootPart.lba_start, bootPart.lba_end, 0xFFCCCCCC);
sdmmc_storage_set_mmc_partition(&storage, i + 1);
@@ -544,7 +541,7 @@ static void _dump_emmc_selected(emmcPartType_t dumpType)
if ((dumpType & PART_SYSTEM) == 0 && strcmp(part->name, "USER"))
continue;
gfx_printf(&gfx_con, "%k%02d: %s (%07X-%07X)%k\n", 0xFF00DDFF, i++,
gfx_printf("%k%02d: %s (%07X-%07X)%k\n", 0xFF00DDFF, i++,
part->name, part->lba_start, part->lba_end, 0xFFCCCCCC);
emmcsn_path_impl(sdPath, "/partitions", part->name, &storage);
@@ -567,7 +564,7 @@ static void _dump_emmc_selected(emmcPartType_t dumpType)
rawPart.lba_end = RAW_AREA_NUM_SECTORS - 1;
strcpy(rawPart.name, "rawnand.bin");
{
gfx_printf(&gfx_con, "%k%02d: %s (%07X-%07X)%k\n", 0xFF00DDFF, i++,
gfx_printf("%k%02d: %s (%07X-%07X)%k\n", 0xFF00DDFF, i++,
rawPart.name, rawPart.lba_start, rawPart.lba_end, 0xFFCCCCCC);
emmcsn_path_impl(sdPath, "", rawPart.name, &storage);
@@ -576,14 +573,14 @@ static void _dump_emmc_selected(emmcPartType_t dumpType)
}
}
gfx_putc(&gfx_con, '\n');
gfx_putc('\n');
timer = get_tmr_s() - timer;
gfx_printf(&gfx_con, "Time taken: %dm %ds.\n", timer / 60, timer % 60);
gfx_printf("Time taken: %dm %ds.\n", timer / 60, timer % 60);
sdmmc_storage_end(&storage);
if (res && h_cfg.verification)
gfx_printf(&gfx_con, "\n%kFinished and verified!%k\nPress any key...\n", 0xFF96FF00, 0xFFCCCCCC);
gfx_printf("\n%kFinished and verified!%k\nPress any key...\n", 0xFF96FF00, 0xFFCCCCCC);
else if (res)
gfx_printf(&gfx_con, "\nFinished! Press any key...\n");
gfx_printf("\nFinished! Press any key...\n");
out:
sd_unmount();
@@ -612,9 +609,10 @@ static int _restore_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part
FIL fp;
FILINFO fno;
gfx_printf(&gfx_con, "\nFilename: %s\n", outFilename);
bool use_multipart = false;
gfx_con_getpos(&gfx_con.savedx, &gfx_con.savedy);
bool use_multipart = false;
if (allow_multi_part)
{
@@ -622,10 +620,7 @@ static int _restore_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part
if (f_stat(outFilename, &fno))
{
// If not, check if there are partial files and the total size matches.
gfx_printf(&gfx_con, "\nFile not found, checking for part files.\n");
// Store console pos, so we dont take too much room.
gfx_con_getpos(&gfx_con, &gfx_con.savedx, &gfx_con.savedy);
gfx_printf("No single file, checking for part files...\n");
outFilename[sdPathLen++] = '.';
@@ -634,8 +629,8 @@ static int _restore_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part
{
_update_filename(outFilename, sdPathLen, 99, numSplitParts);
gfx_con_setpos(&gfx_con, gfx_con.savedx, gfx_con.savedy);
gfx_printf(&gfx_con, "\nFilename: %s\n", outFilename);
gfx_con_setpos(gfx_con.savedx, gfx_con.savedy);
gfx_printf("\nFilename: %s\n", outFilename);
if (f_stat(outFilename, &fno))
{
@@ -648,7 +643,7 @@ static int _restore_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part
numSplitParts++;
}
gfx_printf(&gfx_con, "\n%X sectors total.\n", (u32)((u64)totalCheckFileSize >> (u64)9));
gfx_printf("\n%X sectors total.\n", (u32)((u64)totalCheckFileSize >> (u64)9));
if ((u32)((u64)totalCheckFileSize >> (u64)9) != totalSectors)
{
@@ -665,9 +660,9 @@ static int _restore_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part
}
}
gfx_con_setpos(&gfx_con, gfx_con.savedx, gfx_con.savedy);
res = f_open(&fp, outFilename, FA_READ);
gfx_con_setpos(gfx_con.savedx, gfx_con.savedy);
gfx_printf("\nFilename: %s\n", outFilename);
if (res)
{
if (res != FR_NO_FILE)
@@ -689,12 +684,10 @@ static int _restore_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part
else
{
fileSize = (u64)f_size(&fp);
gfx_printf(&gfx_con, "\nTotal restore size: %d MiB.\n\n",
((u32)((use_multipart ? ((u64)totalCheckFileSize >> (u64)9) : fileSize) >> (u64)9)) >> SECTORS_TO_MIB_COEFF);
gfx_printf("\nTotal restore size: %d MiB.\n\n",
(u32)((use_multipart ? (u64)totalCheckFileSize : fileSize) >> (u64)9) >> SECTORS_TO_MIB_COEFF);
}
const u32 NUM_SECTORS_PER_ITER = 8192; // 4MB Cache.
u8 *buf = (u8 *)MIXD_BUF_ALIGNED;
u32 lba_curr = part->lba_start;
@@ -705,7 +698,7 @@ static int _restore_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part
u32 num = 0;
u32 pct = 0;
gfx_con_getpos(&gfx_con, &gfx_con.savedx, &gfx_con.savedy);
gfx_con_getpos(&gfx_con.savedx, &gfx_con.savedy);
while (totalSectors > 0)
{
@@ -731,8 +724,8 @@ static int _restore_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part
_update_filename(outFilename, sdPathLen, numSplitParts, currPartIdx);
// Read from next part.
gfx_con_setpos(&gfx_con, gfx_con.savedx, gfx_con.savedy);
gfx_printf(&gfx_con, "Filename: %s\n\n", outFilename);
gfx_con_setpos(gfx_con.savedx, gfx_con.savedy);
gfx_printf("Filename: %s\n\n", outFilename);
lbaStartPart = lba_curr;
@@ -782,7 +775,7 @@ static int _restore_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part
pct = (u64)((u64)(lba_curr - part->lba_start) * 100u) / (u64)(part->lba_end - part->lba_start);
if (pct != prevPct)
{
tui_pbar(&gfx_con, 0, gfx_con.y, pct, 0xFFCCCCCC, 0xFF555555);
tui_pbar(0, gfx_con.y, pct, 0xFFCCCCCC, 0xFF555555);
prevPct = pct;
}
@@ -790,7 +783,7 @@ static int _restore_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part
totalSectors -= num;
bytesWritten += num * NX_EMMC_BLOCKSIZE;
}
tui_pbar(&gfx_con, 0, gfx_con.y, 100, 0xFFCCCCCC, 0xFF555555);
tui_pbar(0, gfx_con.y, 100, 0xFFCCCCCC, 0xFF555555);
// Restore operation ended successfully.
f_close(&fp);
@@ -805,11 +798,11 @@ static int _restore_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part
return 0;
}
else
tui_pbar(&gfx_con, 0, gfx_con.y, 100, 0xFF96FF00, 0xFF155500);
tui_pbar(0, gfx_con.y, 100, 0xFF96FF00, 0xFF155500);
}
gfx_con.fntsz = 16;
gfx_puts(&gfx_con, "\n\n");
gfx_puts("\n\n");
return 1;
}
@@ -818,33 +811,33 @@ static void _restore_emmc_selected(emmcPartType_t restoreType)
{
int res = 0;
u32 timer = 0;
gfx_clear_partial_grey(&gfx_ctxt, 0x1B, 0, 1256);
tui_sbar(&gfx_con, true);
gfx_con_setpos(&gfx_con, 0, 0);
gfx_clear_partial_grey(0x1B, 0, 1256);
tui_sbar(true);
gfx_con_setpos(0, 0);
gfx_printf(&gfx_con, "%kThis may render your device inoperative!\n\n", 0xFFFFDD00);
gfx_printf(&gfx_con, "Are you really sure?\n\n%k", 0xFFCCCCCC);
gfx_printf("%kThis may render your device inoperative!\n\n", 0xFFFFDD00);
gfx_printf("Are you really sure?\n\n%k", 0xFFCCCCCC);
if ((restoreType & PART_BOOT) || (restoreType & PART_GP_ALL))
{
gfx_puts(&gfx_con, "The mode you selected will only restore\nthe ");
gfx_puts("The mode you selected will only restore\nthe ");
if (restoreType & PART_BOOT)
gfx_puts(&gfx_con, "boot ");
gfx_puts(&gfx_con, "partitions that it can find.\n");
gfx_puts(&gfx_con, "If it is not found, it will be skipped\nand continue with the next.\n\n");
gfx_puts("boot ");
gfx_puts("partitions that it can find.\n");
gfx_puts("If it is not found, it will be skipped\nand continue with the next.\n\n");
}
gfx_con_getpos(&gfx_con, &gfx_con.savedx, &gfx_con.savedy);
gfx_con_getpos(&gfx_con.savedx, &gfx_con.savedy);
u8 failsafe_wait = 10;
while (failsafe_wait > 0)
{
gfx_con_setpos(&gfx_con, gfx_con.savedx, gfx_con.savedy);
gfx_printf(&gfx_con, "%kWait... (%ds) %k", 0xFF888888, failsafe_wait, 0xFFCCCCCC);
gfx_con_setpos(gfx_con.savedx, gfx_con.savedy);
gfx_printf("%kWait... (%ds) %k", 0xFF888888, failsafe_wait, 0xFFCCCCCC);
msleep(1000);
failsafe_wait--;
}
gfx_con_setpos(&gfx_con, gfx_con.savedx, gfx_con.savedy);
gfx_con_setpos(gfx_con.savedx, gfx_con.savedy);
gfx_puts(&gfx_con, "Press POWER to Continue.\nPress VOL to go to the menu.\n\n\n");
gfx_puts("Press POWER to Continue.\nPress VOL to go to the menu.\n\n\n");
u32 btn = btn_wait();
if (!(btn & BTN_POWER))
@@ -879,7 +872,7 @@ static void _restore_emmc_selected(emmcPartType_t restoreType)
bootPart.name[4] = (u8)('0' + i);
bootPart.name[5] = 0;
gfx_printf(&gfx_con, "%k%02d: %s (%07X-%07X)%k\n", 0xFF00DDFF, i,
gfx_printf("%k%02d: %s (%07X-%07X)%k\n", 0xFF00DDFF, i,
bootPart.name, bootPart.lba_start, bootPart.lba_end, 0xFFCCCCCC);
sdmmc_storage_set_mmc_partition(&storage, i + 1);
@@ -897,7 +890,7 @@ static void _restore_emmc_selected(emmcPartType_t restoreType)
nx_emmc_gpt_parse(&gpt, &storage);
LIST_FOREACH_ENTRY(emmc_part_t, part, &gpt, link)
{
gfx_printf(&gfx_con, "%k%02d: %s (%07X-%07X)%k\n", 0xFF00DDFF, i++,
gfx_printf("%k%02d: %s (%07X-%07X)%k\n", 0xFF00DDFF, i++,
part->name, part->lba_start, part->lba_end, 0xFFCCCCCC);
emmcsn_path_impl(sdPath, "/restore/partitions/", part->name, &storage);
@@ -917,7 +910,7 @@ static void _restore_emmc_selected(emmcPartType_t restoreType)
rawPart.lba_end = RAW_AREA_NUM_SECTORS - 1;
strcpy(rawPart.name, "rawnand.bin");
{
gfx_printf(&gfx_con, "%k%02d: %s (%07X-%07X)%k\n", 0xFF00DDFF, i++,
gfx_printf("%k%02d: %s (%07X-%07X)%k\n", 0xFF00DDFF, i++,
rawPart.name, rawPart.lba_start, rawPart.lba_end, 0xFFCCCCCC);
emmcsn_path_impl(sdPath, "/restore", rawPart.name, &storage);
@@ -925,14 +918,14 @@ static void _restore_emmc_selected(emmcPartType_t restoreType)
}
}
gfx_putc(&gfx_con, '\n');
gfx_putc('\n');
timer = get_tmr_s() - timer;
gfx_printf(&gfx_con, "Time taken: %dm %ds.\n", timer / 60, timer % 60);
gfx_printf("Time taken: %dm %ds.\n", timer / 60, timer % 60);
sdmmc_storage_end(&storage);
if (res && h_cfg.verification)
gfx_printf(&gfx_con, "\n%kFinished and verified!%k\nPress any key...\n", 0xFF96FF00, 0xFFCCCCCC);
gfx_printf("\n%kFinished and verified!%k\nPress any key...\n", 0xFF96FF00, 0xFFCCCCCC);
else if (res)
gfx_printf(&gfx_con, "\nFinished! Press any key...\n");
gfx_printf("\nFinished! Press any key...\n");
out:
sd_unmount();

View File

@@ -48,8 +48,8 @@ extern void emmcsn_path_impl(char *path, char *sub_dir, char *filename, sdmmc_st
void print_fuseinfo()
{
gfx_clear_partial_grey(&gfx_ctxt, 0x1B, 0, 1256);
gfx_con_setpos(&gfx_con, 0, 0);
gfx_clear_partial_grey(0x1B, 0, 1256);
gfx_con_setpos(0, 0);
u32 burntFuses = 0;
for (u32 i = 0; i < 32; i++)
@@ -58,26 +58,26 @@ void print_fuseinfo()
burntFuses++;
}
gfx_printf(&gfx_con, "\nSKU: %X - ", FUSE(FUSE_SKU_INFO));
gfx_printf("\nSKU: %X - ", FUSE(FUSE_SKU_INFO));
switch (fuse_read_odm(4) & 3)
{
case 0:
gfx_printf(&gfx_con, "Retail\n");
gfx_printf("Retail\n");
break;
case 3:
gfx_printf(&gfx_con, "Dev\n");
gfx_printf("Dev\n");
break;
}
gfx_printf(&gfx_con, "Sdram ID: %d\n", (fuse_read_odm(4) >> 3) & 0x1F);
gfx_printf(&gfx_con, "Burnt fuses: %d / 64\n", burntFuses);
gfx_printf(&gfx_con, "Secure key: %08X%08X%08X%08X\n\n\n",
gfx_printf("Sdram ID: %d\n", (fuse_read_odm(4) >> 3) & 0x1F);
gfx_printf("Burnt fuses: %d / 64\n", burntFuses);
gfx_printf("Secure key: %08X%08X%08X%08X\n\n\n",
byte_swap_32(FUSE(FUSE_PRIVATE_KEY0)), byte_swap_32(FUSE(FUSE_PRIVATE_KEY1)),
byte_swap_32(FUSE(FUSE_PRIVATE_KEY2)), byte_swap_32(FUSE(FUSE_PRIVATE_KEY3)));
gfx_printf(&gfx_con, "%k(Unlocked) fuse cache:\n\n%k", 0xFF00DDFF, 0xFFCCCCCC);
gfx_hexdump(&gfx_con, 0x7000F900, (u8 *)0x7000F900, 0x2FC);
gfx_printf("%k(Unlocked) fuse cache:\n\n%k", 0xFF00DDFF, 0xFFCCCCCC);
gfx_hexdump(0x7000F900, (u8 *)0x7000F900, 0x2FC);
gfx_puts(&gfx_con, "\nPress POWER to dump them to SD Card.\nPress VOL to go to the menu.\n");
gfx_puts("\nPress POWER to dump them to SD Card.\nPress VOL to go to the menu.\n");
u32 btn = btn_wait();
if (btn & BTN_POWER)
@@ -87,7 +87,7 @@ void print_fuseinfo()
char path[64];
emmcsn_path_impl(path, "/dumps", "fuses.bin", NULL);
if (!sd_save_to_file((u8 *)0x7000F900, 0x2FC, path))
gfx_puts(&gfx_con, "\nDone!\n");
gfx_puts("\nDone!\n");
sd_unmount();
}
@@ -97,17 +97,17 @@ void print_fuseinfo()
void print_kfuseinfo()
{
gfx_clear_partial_grey(&gfx_ctxt, 0x1B, 0, 1256);
gfx_con_setpos(&gfx_con, 0, 0);
gfx_clear_partial_grey(0x1B, 0, 1256);
gfx_con_setpos(0, 0);
gfx_printf(&gfx_con, "%kKFuse contents:\n\n%k", 0xFF00DDFF, 0xFFCCCCCC);
gfx_printf("%kKFuse contents:\n\n%k", 0xFF00DDFF, 0xFFCCCCCC);
u32 buf[KFUSE_NUM_WORDS];
if (!kfuse_read(buf))
EPRINTF("CRC fail.");
else
gfx_hexdump(&gfx_con, 0, (u8 *)buf, KFUSE_NUM_WORDS * 4);
gfx_hexdump(0, (u8 *)buf, KFUSE_NUM_WORDS * 4);
gfx_puts(&gfx_con, "\nPress POWER to dump them to SD Card.\nPress VOL to go to the menu.\n");
gfx_puts("\nPress POWER to dump them to SD Card.\nPress VOL to go to the menu.\n");
u32 btn = btn_wait();
if (btn & BTN_POWER)
@@ -117,7 +117,7 @@ void print_kfuseinfo()
char path[64];
emmcsn_path_impl(path, "/dumps", "kfuses.bin", NULL);
if (!sd_save_to_file((u8 *)buf, KFUSE_NUM_WORDS * 4, path))
gfx_puts(&gfx_con, "\nDone!\n");
gfx_puts("\nDone!\n");
sd_unmount();
}
@@ -127,8 +127,8 @@ void print_kfuseinfo()
void print_mmc_info()
{
gfx_clear_partial_grey(&gfx_ctxt, 0x1B, 0, 1256);
gfx_con_setpos(&gfx_con, 0, 0);
gfx_clear_partial_grey(0x1B, 0, 1256);
gfx_con_setpos(0, 0);
static const u32 SECTORS_TO_MIB_COEFF = 11;
@@ -145,12 +145,12 @@ void print_mmc_info()
u16 card_type;
u32 speed = 0;
gfx_printf(&gfx_con, "%kCID:%k\n", 0xFF00DDFF, 0xFFCCCCCC);
gfx_printf("%kCID:%k\n", 0xFF00DDFF, 0xFFCCCCCC);
switch (storage.csd.mmca_vsn)
{
case 0: /* MMC v1.0 - v1.2 */
case 1: /* MMC v1.4 */
gfx_printf(&gfx_con,
gfx_printf(
" Vendor ID: %03X\n"
" Model: %c%c%c%c%c%c%c\n"
" HW rev: %X\n"
@@ -166,7 +166,7 @@ void print_mmc_info()
case 2: /* MMC v2.0 - v2.2 */
case 3: /* MMC v3.1 - v3.3 */
case 4: /* MMC v4 */
gfx_printf(&gfx_con,
gfx_printf(
" Vendor ID: %X\n"
" Card/BGA: %X\n"
" OEM ID: %02X\n"
@@ -188,7 +188,7 @@ void print_mmc_info()
EPRINTF("Unknown CSD structure.");
else
{
gfx_printf(&gfx_con, "%kExtended CSD V1.%d:%k\n",
gfx_printf("%kExtended CSD V1.%d:%k\n",
0xFF00DDFF, storage.ext_csd.ext_struct, 0xFFCCCCCC);
card_type = storage.ext_csd.card_type;
u8 card_type_support[96];
@@ -226,7 +226,7 @@ void print_mmc_info()
}
card_type_support[pos_type] = 0;
gfx_printf(&gfx_con,
gfx_printf(
" Spec Version: %02X\n"
" Extended Rev: 1.%d\n"
" Dev Version: %d\n"
@@ -239,26 +239,26 @@ void print_mmc_info()
storage.csd.capacity == (4096 * 512) ? "High" : "Low", speed & 0xFFFF, (speed >> 16) & 0xFFFF,
storage.csd.busspeed);
gfx_con.fntsz = 8;
gfx_printf(&gfx_con, "%s", card_type_support);
gfx_printf("%s", card_type_support);
gfx_con.fntsz = 16;
gfx_printf(&gfx_con, "\n\n", card_type_support);
gfx_printf("\n\n", card_type_support);
u32 boot_size = storage.ext_csd.boot_mult << 17;
u32 rpmb_size = storage.ext_csd.rpmb_mult << 17;
gfx_printf(&gfx_con, "%keMMC Partitions:%k\n", 0xFF00DDFF, 0xFFCCCCCC);
gfx_printf(&gfx_con, " 1: %kBOOT0 %k\n Size: %5d KiB (LBA Sectors: 0x%07X)\n", 0xFF96FF00, 0xFFCCCCCC,
gfx_printf("%keMMC Partitions:%k\n", 0xFF00DDFF, 0xFFCCCCCC);
gfx_printf(" 1: %kBOOT0 %k\n Size: %5d KiB (LBA Sectors: 0x%07X)\n", 0xFF96FF00, 0xFFCCCCCC,
boot_size / 1024, boot_size / 1024 / 512);
gfx_put_small_sep(&gfx_con);
gfx_printf(&gfx_con, " 2: %kBOOT1 %k\n Size: %5d KiB (LBA Sectors: 0x%07X)\n", 0xFF96FF00, 0xFFCCCCCC,
gfx_put_small_sep();
gfx_printf(" 2: %kBOOT1 %k\n Size: %5d KiB (LBA Sectors: 0x%07X)\n", 0xFF96FF00, 0xFFCCCCCC,
boot_size / 1024, boot_size / 1024 / 512);
gfx_put_small_sep(&gfx_con);
gfx_printf(&gfx_con, " 3: %kRPMB %k\n Size: %5d KiB (LBA Sectors: 0x%07X)\n", 0xFF96FF00, 0xFFCCCCCC,
gfx_put_small_sep();
gfx_printf(" 3: %kRPMB %k\n Size: %5d KiB (LBA Sectors: 0x%07X)\n", 0xFF96FF00, 0xFFCCCCCC,
rpmb_size / 1024, rpmb_size / 1024 / 512);
gfx_put_small_sep(&gfx_con);
gfx_printf(&gfx_con, " 0: %kGPP (USER) %k\n Size: %5d MiB (LBA Sectors: 0x%07X)\n\n", 0xFF96FF00, 0xFFCCCCCC,
gfx_put_small_sep();
gfx_printf(" 0: %kGPP (USER) %k\n Size: %5d MiB (LBA Sectors: 0x%07X)\n\n", 0xFF96FF00, 0xFFCCCCCC,
storage.sec_cnt >> SECTORS_TO_MIB_COEFF, storage.sec_cnt);
gfx_put_small_sep(&gfx_con);
gfx_printf(&gfx_con, "%kGPP (eMMC USER) partition table:%k\n", 0xFF00DDFF, 0xFFCCCCCC);
gfx_put_small_sep();
gfx_printf("%kGPP (eMMC USER) partition table:%k\n", 0xFF00DDFF, 0xFFCCCCCC);
sdmmc_storage_set_mmc_partition(&storage, 0);
LIST_INIT(gpt);
@@ -266,10 +266,10 @@ void print_mmc_info()
int gpp_idx = 0;
LIST_FOREACH_ENTRY(emmc_part_t, part, &gpt, link)
{
gfx_printf(&gfx_con, " %02d: %k%s%k\n Size: % 5d MiB (LBA Sectors 0x%07X)\n LBA Range: %08X-%08X\n",
gfx_printf(" %02d: %k%s%k\n Size: % 5d MiB (LBA Sectors 0x%07X)\n LBA Range: %08X-%08X\n",
gpp_idx++, 0xFFAEFD14, part->name, 0xFFCCCCCC, (part->lba_end - part->lba_start + 1) >> SECTORS_TO_MIB_COEFF,
part->lba_end - part->lba_start + 1, part->lba_start, part->lba_end);
gfx_put_small_sep(&gfx_con);
gfx_put_small_sep();
}
nx_emmc_gpt_free(&gpt);
}
@@ -285,15 +285,15 @@ void print_sdcard_info()
{
static const u32 SECTORS_TO_MIB_COEFF = 11;
gfx_clear_partial_grey(&gfx_ctxt, 0x1B, 0, 1256);
gfx_con_setpos(&gfx_con, 0, 0);
gfx_clear_partial_grey(0x1B, 0, 1256);
gfx_con_setpos(0, 0);
if (sd_mount())
{
u32 capacity;
gfx_printf(&gfx_con, "%kCard IDentification:%k\n", 0xFF00DDFF, 0xFFCCCCCC);
gfx_printf(&gfx_con,
gfx_printf("%kCard IDentification:%k\n", 0xFF00DDFF, 0xFFCCCCCC);
gfx_printf(
" Vendor ID: %02x\n"
" OEM ID: %c%c\n"
" Model: %c%c%c%c%c\n"
@@ -307,9 +307,9 @@ void print_sdcard_info()
sd_storage.cid.hwrev, sd_storage.cid.fwrev, sd_storage.cid.serial,
sd_storage.cid.month, sd_storage.cid.year);
gfx_printf(&gfx_con, "%kCard-Specific Data V%d.0:%k\n", 0xFF00DDFF, sd_storage.csd.structure + 1, 0xFFCCCCCC);
gfx_printf("%kCard-Specific Data V%d.0:%k\n", 0xFF00DDFF, sd_storage.csd.structure + 1, 0xFFCCCCCC);
capacity = sd_storage.csd.capacity >> (20 - sd_storage.csd.read_blkbits);
gfx_printf(&gfx_con,
gfx_printf(
" Cmd Classes: %02X\n"
" Capacity: %d MiB\n"
" Bus Width: %d\n"
@@ -324,9 +324,9 @@ void print_sdcard_info()
sd_storage.ssr.speed_class, sd_storage.ssr.uhs_grade, sd_storage.ssr.video_class,
sd_storage.ssr.app_class, sd_storage.csd.write_protect);
gfx_puts(&gfx_con, "Acquiring FAT volume info...\n\n");
gfx_puts("Acquiring FAT volume info...\n\n");
f_getfree("", &sd_fs.free_clst, NULL);
gfx_printf(&gfx_con, "%kFound %s volume:%k\n Free: %d MiB\n Cluster: %d KiB\n",
gfx_printf("%kFound %s volume:%k\n Free: %d MiB\n Cluster: %d KiB\n",
0xFF00DDFF, sd_fs.fs_type == FS_EXFAT ? "exFAT" : "FAT32", 0xFFCCCCCC,
sd_fs.free_clst * sd_fs.csize >> SECTORS_TO_MIB_COEFF, (sd_fs.csize > 1) ? (sd_fs.csize >> 1) : 512);
sd_unmount();
@@ -337,8 +337,8 @@ void print_sdcard_info()
void print_tsec_key()
{
gfx_clear_partial_grey(&gfx_ctxt, 0x1B, 0, 1256);
gfx_con_setpos(&gfx_con, 0, 0);
gfx_clear_partial_grey(0x1B, 0, 1256);
gfx_con_setpos(0, 0);
u32 retries = 0;
@@ -401,25 +401,25 @@ void print_tsec_key()
}
}
gfx_printf(&gfx_con, "%kTSEC key: %k", 0xFF00DDFF, 0xFFCCCCCC);
gfx_printf("%kTSEC key: %k", 0xFF00DDFF, 0xFFCCCCCC);
if (res >= 0)
{
for (u32 j = 0; j < 0x10; j++)
gfx_printf(&gfx_con, "%02X", keys[j]);
gfx_printf("%02X", keys[j]);
if (pkg1_id->kb == KB_FIRMWARE_VERSION_620)
{
gfx_printf(&gfx_con, "\n%kTSEC root: %k", 0xFF00DDFF, 0xFFCCCCCC);
gfx_printf("\n%kTSEC root: %k", 0xFF00DDFF, 0xFFCCCCCC);
for (u32 j = 0; j < 0x10; j++)
gfx_printf(&gfx_con, "%02X", keys[0x10 + j]);
gfx_printf("%02X", keys[0x10 + j]);
}
}
else
EPRINTFARGS("ERROR %X\n", res);
gfx_puts(&gfx_con, "\n\nPress POWER to dump them to SD Card.\nPress VOL to go to the menu.\n");
gfx_puts("\n\nPress POWER to dump them to SD Card.\nPress VOL to go to the menu.\n");
u32 btn = btn_wait();
if (btn & BTN_POWER)
@@ -429,7 +429,7 @@ void print_tsec_key()
char path[64];
emmcsn_path_impl(path, "/dumps", "tsec_keys.bin", NULL);
if (!sd_save_to_file(keys, 0x10 * 2, path))
gfx_puts(&gfx_con, "\nDone!\n");
gfx_puts("\nDone!\n");
sd_unmount();
}
}
@@ -447,127 +447,124 @@ void print_fuel_gauge_info()
{
int value = 0;
gfx_printf(&gfx_con, "%kFuel Gauge IC Info:\n%k", 0xFF00DDFF, 0xFFCCCCCC);
max17050_get_property(MAX17050_Age, &value);
gfx_printf(&gfx_con, "Age: %3d%\n", value);
gfx_printf("%kFuel Gauge IC Info:\n%k", 0xFF00DDFF, 0xFFCCCCCC);
max17050_get_property(MAX17050_RepSOC, &value);
gfx_printf(&gfx_con, "Capacity now: %3d%\n", value >> 8);
gfx_printf("Capacity now: %3d%\n", value >> 8);
max17050_get_property(MAX17050_RepCap, &value);
gfx_printf(&gfx_con, "Capacity now: %4d mAh\n", value);
gfx_printf("Capacity now: %4d mAh\n", value);
max17050_get_property(MAX17050_FullCAP, &value);
gfx_printf(&gfx_con, "Capacity full: %4d mAh\n", value);
gfx_printf("Capacity full: %4d mAh\n", value);
max17050_get_property(MAX17050_DesignCap, &value);
gfx_printf(&gfx_con, "Capacity (design): %4d mAh\n", value);
gfx_printf("Capacity (design): %4d mAh\n", value);
max17050_get_property(MAX17050_Current, &value);
if (value >= 0)
gfx_printf(&gfx_con, "Current now: %d mA\n", value / 1000);
gfx_printf("Current now: %d mA\n", value / 1000);
else
gfx_printf(&gfx_con, "Current now: -%d mA\n", ~value / 1000);
gfx_printf("Current now: -%d mA\n", ~value / 1000);
max17050_get_property(MAX17050_AvgCurrent, &value);
if (value >= 0)
gfx_printf(&gfx_con, "Current average: %d mA\n", value / 1000);
gfx_printf("Current average: %d mA\n", value / 1000);
else
gfx_printf(&gfx_con, "Current average: -%d mA\n", ~value / 1000);
gfx_printf("Current average: -%d mA\n", ~value / 1000);
max17050_get_property(MAX17050_VCELL, &value);
gfx_printf(&gfx_con, "Voltage now: %4d mV\n", value);
gfx_printf("Voltage now: %4d mV\n", value);
max17050_get_property(MAX17050_OCVInternal, &value);
gfx_printf(&gfx_con, "Voltage open-circuit: %4d mV\n", value);
gfx_printf("Voltage open-circuit: %4d mV\n", value);
max17050_get_property(MAX17050_MinVolt, &value);
gfx_printf(&gfx_con, "Min voltage reached: %4d mV\n", value);
gfx_printf("Min voltage reached: %4d mV\n", value);
max17050_get_property(MAX17050_MaxVolt, &value);
gfx_printf(&gfx_con, "Max voltage reached: %4d mV\n", value);
gfx_printf("Max voltage reached: %4d mV\n", value);
max17050_get_property(MAX17050_V_empty, &value);
gfx_printf(&gfx_con, "Empty voltage (design): %4d mV\n", value);
gfx_printf("Empty voltage (design): %4d mV\n", value);
max17050_get_property(MAX17050_TEMP, &value);
if (value >= 0)
gfx_printf(&gfx_con, "Battery temperature: %d.%d oC\n", value / 10, value % 10);
gfx_printf("Battery temperature: %d.%d oC\n", value / 10, value % 10);
else
gfx_printf(&gfx_con, "Battery temperature: -%d.%d oC\n", ~value / 10, (~value) % 10);
gfx_printf("Battery temperature: -%d.%d oC\n", ~value / 10, (~value) % 10);
}
void print_battery_charger_info()
{
int value = 0;
gfx_printf(&gfx_con, "%k\n\nBattery Charger IC Info:\n%k", 0xFF00DDFF, 0xFFCCCCCC);
gfx_printf("%k\n\nBattery Charger IC Info:\n%k", 0xFF00DDFF, 0xFFCCCCCC);
bq24193_get_property(BQ24193_InputVoltageLimit, &value);
gfx_printf(&gfx_con, "Input voltage limit: %4d mV\n", value);
gfx_printf("Input voltage limit: %4d mV\n", value);
bq24193_get_property(BQ24193_InputCurrentLimit, &value);
gfx_printf(&gfx_con, "Input current limit: %4d mA\n", value);
gfx_printf("Input current limit: %4d mA\n", value);
bq24193_get_property(BQ24193_SystemMinimumVoltage, &value);
gfx_printf(&gfx_con, "Min voltage limit: %4d mV\n", value);
gfx_printf("Min voltage limit: %4d mV\n", value);
bq24193_get_property(BQ24193_FastChargeCurrentLimit, &value);
gfx_printf(&gfx_con, "Fast charge current limit: %4d mA\n", value);
gfx_printf("Fast charge current limit: %4d mA\n", value);
bq24193_get_property(BQ24193_ChargeVoltageLimit, &value);
gfx_printf(&gfx_con, "Charge voltage limit: %4d mV\n", value);
gfx_printf("Charge voltage limit: %4d mV\n", value);
bq24193_get_property(BQ24193_ChargeStatus, &value);
gfx_printf(&gfx_con, "Charge status: ");
gfx_printf("Charge status: ");
switch (value)
{
case 0:
gfx_printf(&gfx_con, "Not charging\n");
gfx_printf("Not charging\n");
break;
case 1:
gfx_printf(&gfx_con, "Pre-charging\n");
gfx_printf("Pre-charging\n");
break;
case 2:
gfx_printf(&gfx_con, "Fast charging\n");
gfx_printf("Fast charging\n");
break;
case 3:
gfx_printf(&gfx_con, "Charge terminated\n");
gfx_printf("Charge terminated\n");
break;
default:
gfx_printf(&gfx_con, "Unknown (%d)\n", value);
gfx_printf("Unknown (%d)\n", value);
break;
}
bq24193_get_property(BQ24193_TempStatus, &value);
gfx_printf(&gfx_con, "Temperature status: ");
gfx_printf("Temperature status: ");
switch (value)
{
case 0:
gfx_printf(&gfx_con, "Normal\n");
gfx_printf("Normal\n");
break;
case 2:
gfx_printf(&gfx_con, "Warm\n");
gfx_printf("Warm\n");
break;
case 3:
gfx_printf(&gfx_con, "Cool\n");
gfx_printf("Cool\n");
break;
case 5:
gfx_printf(&gfx_con, "Cold\n");
gfx_printf("Cold\n");
break;
case 6:
gfx_printf(&gfx_con, "Hot\n");
gfx_printf("Hot\n");
break;
default:
gfx_printf(&gfx_con, "Unknown (%d)\n", value);
gfx_printf("Unknown (%d)\n", value);
break;
}
}
void print_battery_info()
{
gfx_clear_partial_grey(&gfx_ctxt, 0x1B, 0, 1256);
gfx_con_setpos(&gfx_con, 0, 0);
gfx_clear_partial_grey(0x1B, 0, 1256);
gfx_con_setpos(0, 0);
print_fuel_gauge_info();
@@ -575,7 +572,7 @@ void print_battery_info()
u8 *buf = (u8 *)malloc(0x100 * 2);
gfx_printf(&gfx_con, "%k\n\nBattery Fuel Gauge Registers:\n%k", 0xFF00DDFF, 0xFFCCCCCC);
gfx_printf("%k\n\nBattery Fuel Gauge Registers:\n%k", 0xFF00DDFF, 0xFFCCCCCC);
for (int i = 0; i < 0x200; i += 2)
{
@@ -583,9 +580,9 @@ void print_battery_info()
usleep(2500);
}
gfx_hexdump(&gfx_con, 0, (u8 *)buf, 0x200);
gfx_hexdump(0, (u8 *)buf, 0x200);
gfx_puts(&gfx_con, "\nPress POWER to dump them to SD Card.\nPress VOL to go to the menu.\n");
gfx_puts("\nPress POWER to dump them to SD Card.\nPress VOL to go to the menu.\n");
u32 btn = btn_wait();
@@ -598,7 +595,7 @@ void print_battery_info()
if (sd_save_to_file((u8 *)buf, 0x200, path))
EPRINTF("\nError creating fuel.bin file.");
else
gfx_puts(&gfx_con, "\nDone!\n");
gfx_puts("\nDone!\n");
sd_unmount();
}
@@ -609,24 +606,24 @@ void print_battery_info()
void _ipatch_process(u32 offset, u32 value)
{
gfx_printf(&gfx_con, "%8x %8x", BOOTROM_BASE + offset, value);
gfx_printf("%8x %8x", BOOTROM_BASE + offset, value);
u8 lo = value & 0xff;
switch (value >> 8)
{
case 0x20:
gfx_printf(&gfx_con, " MOVS R0, #0x%02X", lo);
gfx_printf(" MOVS R0, #0x%02X", lo);
break;
case 0xDF:
gfx_printf(&gfx_con, " SVC #0x%02X", lo);
gfx_printf(" SVC #0x%02X", lo);
break;
}
gfx_puts(&gfx_con, "\n");
gfx_puts("\n");
}
void bootrom_ipatches_info()
{
gfx_clear_partial_grey(&gfx_ctxt, 0x1B, 0, 1256);
gfx_con_setpos(&gfx_con, 0, 0);
gfx_clear_partial_grey(0x1B, 0, 1256);
gfx_con_setpos(0, 0);
static const u32 BOOTROM_SIZE = 0x18000;
@@ -634,7 +631,7 @@ void bootrom_ipatches_info()
if (res != 0)
EPRINTFARGS("Failed to read ipatches. Error: %d", res);
gfx_puts(&gfx_con, "\nPress POWER to dump them to SD Card.\nPress VOL to go to the menu.\n");
gfx_puts("\nPress POWER to dump them to SD Card.\nPress VOL to go to the menu.\n");
u32 btn = btn_wait();
if (btn & BTN_POWER)
@@ -649,20 +646,20 @@ void bootrom_ipatches_info()
{
emmcsn_path_impl(path, "/dumps", "evp_thunks.bin", NULL);
if (!sd_save_to_file((u8 *)iram_evp_thunks, iram_evp_thunks_len, path))
gfx_puts(&gfx_con, "\nevp_thunks.bin saved!\n");
gfx_puts("\nevp_thunks.bin saved!\n");
}
else
EPRINTFARGS("Failed to read evp_thunks. Error: %d", res);
u32 words[0x100];
read_raw_ipatch_fuses(words);
emmcsn_path_impl(path, "/dumps", "ipatches.bin", NULL);
u32 words[192];
fuse_read_array(words);
emmcsn_path_impl(path, "/dumps", "raw_fuses.bin", NULL);
if (!sd_save_to_file((u8 *)words, sizeof(words), path))
gfx_puts(&gfx_con, "\nipatches.bin saved!\n");
gfx_puts("\nipatches.bin saved!\n");
emmcsn_path_impl(path, "/dumps", "bootrom_patched.bin", NULL);
if (!sd_save_to_file((u8 *)BOOTROM_BASE, BOOTROM_SIZE, path))
gfx_puts(&gfx_con, "\nbootrom_patched.bin saved!\n");
gfx_puts("\nbootrom_patched.bin saved!\n");
u32 ipatch_backup[14];
memcpy(ipatch_backup, (void *)IPATCH_BASE, sizeof(ipatch_backup));
@@ -670,7 +667,7 @@ void bootrom_ipatches_info()
emmcsn_path_impl(path, "/dumps", "bootrom_unpatched.bin", NULL);
if (!sd_save_to_file((u8 *)BOOTROM_BASE, BOOTROM_SIZE, path))
gfx_puts(&gfx_con, "\nbootrom_unpatched.bin saved!\n");
gfx_puts("\nbootrom_unpatched.bin saved!\n");
memcpy((void*)IPATCH_BASE, ipatch_backup, sizeof(ipatch_backup));

View File

@@ -33,6 +33,7 @@
#include "../sec/se.h"
#include "../storage/nx_emmc.h"
#include "../storage/sdmmc.h"
#include "../soc/fuse.h"
#include "../utils/btn.h"
#include "../utils/util.h"
@@ -49,6 +50,8 @@ void dump_packages12()
if (!sd_mount())
return;
char path[64];
u8 *pkg1 = (u8 *)calloc(1, 0x40000);
u8 *warmboot = (u8 *)calloc(1, 0x40000);
u8 *secmon = (u8 *)calloc(1, 0x40000);
@@ -58,8 +61,8 @@ void dump_packages12()
tsec_ctxt_t tsec_ctxt;
gfx_clear_partial_grey(&gfx_ctxt, 0x1B, 0, 1256);
gfx_con_setpos(&gfx_con, 0, 0);
gfx_clear_partial_grey(0x1B, 0, 1256);
gfx_con_setpos(0, 0);
sdmmc_storage_t storage;
sdmmc_t sdmmc;
@@ -73,17 +76,22 @@ void dump_packages12()
// Read package1.
sdmmc_storage_read(&storage, 0x100000 / NX_EMMC_BLOCKSIZE, 0x40000 / NX_EMMC_BLOCKSIZE, pkg1);
const pkg1_id_t *pkg1_id = pkg1_identify(pkg1);
const pk11_hdr_t *hdr = (pk11_hdr_t *)(pkg1 + pkg1_id->pkg11_off + 0x20);
if (!pkg1_id)
{
gfx_con.fntsz = 8;
EPRINTF("Unknown pkg1 version for reading\nTSEC firmware.");
// Dump package1.
emmcsn_path_impl(path, "/pkg1", "pkg1_enc.bin", &storage);
if (sd_save_to_file(pkg1, 0x40000, path))
goto out_free;
gfx_puts("\nEnc pkg1 dumped to pkg1_enc.bin\n");
goto out_free;
}
const pk11_hdr_t *hdr = (pk11_hdr_t *)(pkg1 + pkg1_id->pkg11_off + 0x20);
kb = pkg1_id->kb;
if (!h_cfg.se_keygen_done || kb == KB_FIRMWARE_VERSION_620)
if (!h_cfg.se_keygen_done)
{
tsec_ctxt.fw = (void *)pkg1 + pkg1_id->tsec_off;
tsec_ctxt.pkg1 = (void *)pkg1;
@@ -95,12 +103,12 @@ void dump_packages12()
b_cfg.autoboot = 0;
b_cfg.autoboot_list = 0;
gfx_printf(&gfx_con, "sept will run to get the keys.\nThen rerun this option.");
gfx_printf("sept will run to get the keys.\nThen rerun this option.");
btn_wait();
if (!reboot_to_sept((u8 *)tsec_ctxt.fw))
{
gfx_printf(&gfx_con, "Failed to run sept\n");
gfx_printf("Failed to run sept\n");
goto out_free;
}
}
@@ -111,52 +119,50 @@ void dump_packages12()
// Decrypt.
keygen(keyblob, kb, &tsec_ctxt);
h_cfg.se_keygen_done = 1;
if (kb <= KB_FIRMWARE_VERSION_600)
h_cfg.se_keygen_done = 1;
free(keyblob);
}
if (kb <= KB_FIRMWARE_VERSION_600)
pkg1_decrypt(pkg1_id, pkg1);
char path[64];
if (kb <= KB_FIRMWARE_VERSION_620)
{
pkg1_unpack(warmboot, secmon, loader, pkg1_id, pkg1);
// Display info.
gfx_printf(&gfx_con, "%kNX Bootloader size: %k0x%05X\n\n", 0xFFC7EA46, 0xFFCCCCCC, hdr->ldr_size);
gfx_printf("%kNX Bootloader size: %k0x%05X\n\n", 0xFFC7EA46, 0xFFCCCCCC, hdr->ldr_size);
gfx_printf(&gfx_con, "%kSecure monitor addr: %k0x%05X\n", 0xFFC7EA46, 0xFFCCCCCC, pkg1_id->secmon_base);
gfx_printf(&gfx_con, "%kSecure monitor size: %k0x%05X\n\n", 0xFFC7EA46, 0xFFCCCCCC, hdr->sm_size);
gfx_printf("%kSecure monitor addr: %k0x%05X\n", 0xFFC7EA46, 0xFFCCCCCC, pkg1_id->secmon_base);
gfx_printf("%kSecure monitor size: %k0x%05X\n\n", 0xFFC7EA46, 0xFFCCCCCC, hdr->sm_size);
gfx_printf(&gfx_con, "%kWarmboot addr: %k0x%05X\n", 0xFFC7EA46, 0xFFCCCCCC, pkg1_id->warmboot_base);
gfx_printf(&gfx_con, "%kWarmboot size: %k0x%05X\n\n", 0xFFC7EA46, 0xFFCCCCCC, hdr->wb_size);
gfx_printf("%kWarmboot addr: %k0x%05X\n", 0xFFC7EA46, 0xFFCCCCCC, pkg1_id->warmboot_base);
gfx_printf("%kWarmboot size: %k0x%05X\n\n", 0xFFC7EA46, 0xFFCCCCCC, hdr->wb_size);
// Dump package1.1.
emmcsn_path_impl(path, "/pkg1", "pkg1_decr.bin", &storage);
if (sd_save_to_file(pkg1, 0x40000, path))
goto out_free;
gfx_puts(&gfx_con, "\npkg1 dumped to pkg1_decr.bin\n");
gfx_puts("\npkg1 dumped to pkg1_decr.bin\n");
// Dump nxbootloader.
emmcsn_path_impl(path, "/pkg1", "nxloader.bin", &storage);
if (sd_save_to_file(loader, hdr->ldr_size, path))
goto out_free;
gfx_puts(&gfx_con, "NX Bootloader dumped to nxloader.bin\n");
gfx_puts("NX Bootloader dumped to nxloader.bin\n");
// Dump secmon.
emmcsn_path_impl(path, "/pkg1", "secmon.bin", &storage);
if (sd_save_to_file(secmon, hdr->sm_size, path))
goto out_free;
gfx_puts(&gfx_con, "Secure Monitor dumped to secmon.bin\n");
gfx_puts("Secure Monitor dumped to secmon.bin\n");
// Dump warmboot.
emmcsn_path_impl(path, "/pkg1", "warmboot.bin", &storage);
if (sd_save_to_file(warmboot, hdr->wb_size, path))
goto out_free;
gfx_puts(&gfx_con, "Warmboot dumped to warmboot.bin\n\n\n");
gfx_puts("Warmboot dumped to warmboot.bin\n\n\n");
}
// Dump package2.1.
@@ -182,33 +188,42 @@ void dump_packages12()
pkg2_size_aligned / NX_EMMC_BLOCKSIZE, pkg2);
// Decrypt package2 and parse KIP1 blobs in INI1 section.
pkg2_hdr_t *pkg2_hdr = pkg2_decrypt(pkg2);
if (!pkg2_hdr)
{
gfx_printf("Pkg2 decryption failed!\n");
goto out;
}
// Display info.
u32 kernel_crc32 = crc32c(pkg2_hdr->data, pkg2_hdr->sec_size[PKG2_SEC_KERNEL]);
gfx_printf(&gfx_con, "\n%kKernel CRC32C: %k0x%08X\n\n", 0xFFC7EA46, 0xFFCCCCCC, kernel_crc32);
gfx_printf(&gfx_con, "%kKernel size: %k0x%05X\n\n", 0xFFC7EA46, 0xFFCCCCCC, pkg2_hdr->sec_size[PKG2_SEC_KERNEL]);
gfx_printf(&gfx_con, "%kINI1 size: %k0x%05X\n\n", 0xFFC7EA46, 0xFFCCCCCC, pkg2_hdr->sec_size[PKG2_SEC_INI1]);
gfx_printf("%kKernel size: %k0x%05X\n\n", 0xFFC7EA46, 0xFFCCCCCC, pkg2_hdr->sec_size[PKG2_SEC_KERNEL]);
gfx_printf("%kINI1 size: %k0x%05X\n\n", 0xFFC7EA46, 0xFFCCCCCC, pkg2_hdr->sec_size[PKG2_SEC_INI1]);
// Dump pkg2.1.
emmcsn_path_impl(path, "/pkg2", "pkg2_decr.bin", &storage);
if (sd_save_to_file(pkg2, pkg2_hdr->sec_size[PKG2_SEC_KERNEL] + pkg2_hdr->sec_size[PKG2_SEC_INI1], path))
goto out;
gfx_puts(&gfx_con, "\npkg2 dumped to pkg2_decr.bin\n");
gfx_puts("\npkg2 dumped to pkg2_decr.bin\n");
// Dump kernel.
emmcsn_path_impl(path, "/pkg2", "kernel.bin", &storage);
if (sd_save_to_file(pkg2_hdr->data, pkg2_hdr->sec_size[PKG2_SEC_KERNEL], path))
goto out;
gfx_puts(&gfx_con, "Kernel dumped to kernel.bin\n");
gfx_puts("Kernel dumped to kernel.bin\n");
// Dump INI1.
emmcsn_path_impl(path, "/pkg2", "ini1.bin", &storage);
if (sd_save_to_file(pkg2_hdr->data + pkg2_hdr->sec_size[PKG2_SEC_KERNEL],
pkg2_hdr->sec_size[PKG2_SEC_INI1], path))
u32 ini1_off = pkg2_hdr->sec_size[PKG2_SEC_KERNEL];
u32 ini1_size = pkg2_hdr->sec_size[PKG2_SEC_INI1];
if (!ini1_size)
{
ini1_off = *(u32 *)(pkg2_hdr->data + PKG2_NEWKERN_INI1_START);
ini1_size = *(u32 *)(pkg2_hdr->data + PKG2_NEWKERN_INI1_END) - *(u32 *)(pkg2_hdr->data + PKG2_NEWKERN_INI1_START);
}
if (sd_save_to_file(pkg2_hdr->data + ini1_off, ini1_size, path))
goto out;
gfx_puts(&gfx_con, "INI1 dumped to ini1.bin\n");
gfx_puts("INI1 dumped to ini1.bin\n");
gfx_puts(&gfx_con, "\nDone. Press any key...\n");
gfx_puts("\nDone. Press any key...\n");
out:
nx_emmc_gpt_free(&gpt);
@@ -234,8 +249,8 @@ void _toggle_autorcm(bool enable)
u8 randomXor = 0;
gfx_clear_partial_grey(&gfx_ctxt, 0x1B, 0, 1256);
gfx_con_setpos(&gfx_con, 0, 0);
gfx_clear_partial_grey(0x1B, 0, 1256);
gfx_con_setpos(0, 0);
if (!sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4))
{
@@ -247,6 +262,12 @@ void _toggle_autorcm(bool enable)
sdmmc_storage_set_mmc_partition(&storage, 1);
int i, sect = 0;
u8 corr_mod_byte0;
if ((fuse_read_odm(4) & 3) != 3)
corr_mod_byte0 = 0xF7;
else
corr_mod_byte0 = 0x37;
for (i = 0; i < 4; i++)
{
sect = (0x200 + (0x4000 * i)) / NX_EMMC_BLOCKSIZE;
@@ -262,7 +283,7 @@ void _toggle_autorcm(bool enable)
tempbuf[0x10] ^= randomXor;
}
else
tempbuf[0x10] = 0xF7;
tempbuf[0x10] = corr_mod_byte0;
sdmmc_storage_write(&storage, sect, 1, tempbuf);
}
@@ -270,10 +291,10 @@ void _toggle_autorcm(bool enable)
sdmmc_storage_end(&storage);
if (enable)
gfx_printf(&gfx_con, "%kAutoRCM mode enabled!%k", 0xFFFFBA00, 0xFFCCCCCC);
gfx_printf("%kAutoRCM mode enabled!%k", 0xFFFFBA00, 0xFFCCCCCC);
else
gfx_printf(&gfx_con, "%kAutoRCM mode disabled!%k", 0xFF96FF00, 0xFFCCCCCC);
gfx_printf(&gfx_con, "\n\nPress any key...\n");
gfx_printf("%kAutoRCM mode disabled!%k", 0xFF96FF00, 0xFFCCCCCC);
gfx_printf("\n\nPress any key...\n");
out:
btn_wait();
@@ -284,8 +305,18 @@ void _disable_autorcm() { _toggle_autorcm(false); }
void menu_autorcm()
{
gfx_clear_grey(&gfx_ctxt, 0x1B);
gfx_con_setpos(&gfx_con, 0, 0);
gfx_clear_grey(0x1B);
gfx_con_setpos(0, 0);
if (h_cfg.rcm_patched)
{
gfx_printf("%kThis device is RCM patched and\nAutoRCM function is disabled.\n\n"
"In case %kAutoRCM%k is enabled\nthis will %kBRICK%k your device PERMANENTLY!!%k",
0xFFFFDD00, 0xFFFF0000, 0xFFFFDD00, 0xFFFF0000, 0xFFFFDD00, 0xFFCCCCCC);
btn_wait();
return;
}
// Do a simple check on the main BCT.
sdmmc_storage_t storage;
@@ -304,8 +335,16 @@ void menu_autorcm()
sdmmc_storage_set_mmc_partition(&storage, 1);
sdmmc_storage_read(&storage, 0x200 / NX_EMMC_BLOCKSIZE, 1, tempbuf);
if (tempbuf[0x10] != 0xF7)
disabled = false;
if ((fuse_read_odm(4) & 3) != 3)
{
if (tempbuf[0x10] != 0xF7)
disabled = false;
}
else
{
if (tempbuf[0x10] != 0x37)
disabled = false;
}
free(tempbuf);
sdmmc_storage_end(&storage);
@@ -340,7 +379,7 @@ void menu_autorcm()
memset(&ments[5], 0, sizeof(ment_t));
menu_t menu = {ments, "This corrupts your BOOT0!", 0, 0};
tui_do_menu(&gfx_con, &menu);
tui_do_menu(&menu);
}
int _fix_attributes(char *path, u32 *total, u32 hos_folder, u32 check_first_run)
@@ -407,6 +446,10 @@ int _fix_attributes(char *path, u32 *total, u32 hos_folder, u32 check_first_run)
*total = *total + 1;
f_chmod(path, AM_ARC, AM_ARC);
}
// Update status bar.
tui_sbar(false);
// Enter the directory.
res = _fix_attributes(path, total, hos_folder, 0);
if (res != FR_OK)
@@ -421,8 +464,8 @@ int _fix_attributes(char *path, u32 *total, u32 hos_folder, u32 check_first_run)
void _fix_sd_attr(u32 type)
{
gfx_clear_partial_grey(&gfx_ctxt, 0x1B, 0, 1256);
gfx_con_setpos(&gfx_con, 0, 0);
gfx_clear_partial_grey(0x1B, 0, 1256);
gfx_con_setpos(0, 0);
char path[256];
char label[16];
@@ -443,9 +486,9 @@ void _fix_sd_attr(u32 type)
break;
}
gfx_printf(&gfx_con, "Traversing all %s files!\nThis may take some time...\n\n", label);
gfx_printf("Traversing all %s files!\nThis may take some time...\n\n", label);
_fix_attributes(path, &total, type, type);
gfx_printf(&gfx_con, "%kTotal archive bits cleared: %d!%k\n\nDone! Press any key...", 0xFF96FF00, total, 0xFFCCCCCC);
gfx_printf("%kTotal archive bits cleared: %d!%k\n\nDone! Press any key...", 0xFF96FF00, total, 0xFFCCCCCC);
sd_unmount();
}
btn_wait();
@@ -454,22 +497,10 @@ void _fix_sd_attr(u32 type)
void fix_sd_all_attr() { _fix_sd_attr(0); }
void fix_sd_nin_attr() { _fix_sd_attr(1); }
void fix_battery_desync()
{
gfx_clear_partial_grey(&gfx_ctxt, 0x1B, 0, 1256);
gfx_con_setpos(&gfx_con, 0, 0);
max77620_low_battery_monitor_config();
gfx_puts(&gfx_con, "\nDone!\n");
btn_wait();
}
/* void fix_fuel_gauge_configuration()
{
gfx_clear_partial_grey(&gfx_ctxt, 0x1B, 0, 1256);
gfx_con_setpos(&gfx_con, 0, 0);
gfx_clear_partial_grey(0x1B, 0, 1256);
gfx_con_setpos(0, 0);
int battVoltage, avgCurrent;
@@ -483,23 +514,23 @@ void fix_battery_desync()
EPRINTF("You need to be connected to a wall adapter,\nto apply this fix!");
else
{
gfx_printf(&gfx_con, "%kAre you really sure?\nThis will reset your fuel gauge completely!\n", 0xFFFFDD00);
gfx_printf(&gfx_con, "Additionally this will power off your console.\n%k", 0xFFCCCCCC);
gfx_printf("%kAre you really sure?\nThis will reset your fuel gauge completely!\n", 0xFFFFDD00);
gfx_printf("Additionally this will power off your console.\n%k", 0xFFCCCCCC);
gfx_puts(&gfx_con, "\nPress POWER to Continue.\nPress VOL to go to the menu.\n\n\n");
gfx_puts("\nPress POWER to Continue.\nPress VOL to go to the menu.\n\n\n");
u32 btn = btn_wait();
if (btn & BTN_POWER)
{
max17050_fix_configuration();
msleep(1000);
gfx_con_getpos(&gfx_con, &gfx_con.savedx, &gfx_con.savedy);
gfx_con_getpos(&gfx_con.savedx, &gfx_con.savedy);
u16 value = 0;
gfx_printf(&gfx_con, "%kThe console will power off in 45 seconds.\n%k", 0xFFFFDD00, 0xFFCCCCCC);
gfx_printf("%kThe console will power off in 45 seconds.\n%k", 0xFFFFDD00, 0xFFCCCCCC);
while (value < 46)
{
gfx_con_setpos(&gfx_con, gfx_con.savedx, gfx_con.savedy);
gfx_printf(&gfx_con, "%2ds elapsed", value);
gfx_con_setpos(gfx_con.savedx, gfx_con.savedy);
gfx_printf("%2ds elapsed", value);
msleep(1000);
value++;
}
@@ -521,31 +552,31 @@ void fix_battery_desync()
{
int avgCurrent;
gfx_clear_partial_grey(&gfx_ctxt, 0x1B, 0, 1256);
gfx_con_setpos(&gfx_con, 0, 0);
gfx_clear_partial_grey(0x1B, 0, 1256);
gfx_con_setpos(0, 0);
gfx_printf(&gfx_con, "%k\nThis will wipe your battery stats completely!\n"
gfx_printf("%k\nThis will wipe your battery stats completely!\n"
"%kAnd it may not power on without physically\nremoving and re-inserting the battery.\n%k"
"\nAre you really sure?%k\n", 0xFFFFDD00, 0xFFFF0000, 0xFFFFDD00, 0xFFCCCCCC);
gfx_puts(&gfx_con, "\nPress POWER to Continue.\nPress VOL to go to the menu.\n\n\n");
gfx_puts("\nPress POWER to Continue.\nPress VOL to go to the menu.\n\n\n");
u32 btn = btn_wait();
if (btn & BTN_POWER)
{
gfx_clear_partial_grey(&gfx_ctxt, 0x1B, 0, 1256);
gfx_con_setpos(&gfx_con, 0, 0);
gfx_printf(&gfx_con, "%kKeep the USB cable connected!%k\n\n", 0xFFFFDD00, 0xFFCCCCCC);
gfx_con_getpos(&gfx_con, &gfx_con.savedx, &gfx_con.savedy);
gfx_clear_partial_grey(0x1B, 0, 1256);
gfx_con_setpos(0, 0);
gfx_printf("%kKeep the USB cable connected!%k\n\n", 0xFFFFDD00, 0xFFCCCCCC);
gfx_con_getpos(&gfx_con.savedx, &gfx_con.savedy);
u8 value = 30;
while (value > 0)
{
gfx_con_setpos(&gfx_con, gfx_con.savedx, gfx_con.savedy);
gfx_printf(&gfx_con, "%kWait... (%ds) %k", 0xFF888888, value, 0xFFCCCCCC);
gfx_con_setpos(gfx_con.savedx, gfx_con.savedy);
gfx_printf("%kWait... (%ds) %k", 0xFF888888, value, 0xFFCCCCCC);
msleep(1000);
value--;
}
gfx_con_setpos(&gfx_con, gfx_con.savedx, gfx_con.savedy);
gfx_con_setpos(gfx_con.savedx, gfx_con.savedy);
//Check if still connected.
max17050_get_property(MAX17050_AvgCurrent, &avgCurrent);
@@ -555,7 +586,7 @@ void fix_battery_desync()
{
// Apply fix.
bq24193_fake_battery_removal();
gfx_printf(&gfx_con, "Done! \n"
gfx_printf("Done! \n"
"%k1. Remove the USB cable\n"
"2. Press POWER for 15s.\n"
"3. Reconnect the USB to power-on!%k\n", 0xFFFFDD00, 0xFFCCCCCC);
@@ -571,24 +602,25 @@ void fix_battery_desync()
#include "../soc/fuse.h"
#include "../soc/clock.h"
mtc_config_t mtc_cfg;
void minerva()
{
gfx_clear_partial_grey(&gfx_ctxt, 0x1B, 0, 1256);
gfx_con_setpos(&gfx_con, 0, 0);
gfx_clear_partial_grey(0x1B, 0, 1256);
gfx_con_setpos(0, 0);
u32 curr_ram_idx = 0;
if (!sd_mount())
return;
gfx_printf(&gfx_con, "-- Minerva Training Cell --\n\n");
gfx_printf("-- Minerva Training Cell --\n\n");
// Set table to ram.
mtc_cfg.mtc_table = NULL;
mtc_cfg.sdram_id = (fuse_read_odm(4) >> 3) & 0x1F;
ianos_loader(false, "bootloader/sys/libsys_minerva.bso", DRAM_LIB, (void *)&mtc_cfg);
gfx_printf(&gfx_con, "\nStarting training process..\n\n");
gfx_printf("\nStarting training process..\n\n");
// Get current frequency
for (curr_ram_idx = 0; curr_ram_idx < 10; curr_ram_idx++)
@@ -603,21 +635,21 @@ void minerva()
mtc_cfg.rate_from = mtc_cfg.mtc_table[curr_ram_idx].rate_khz;
mtc_cfg.rate_to = 800000;
mtc_cfg.train_mode = OP_TRAIN_SWITCH;
gfx_printf(&gfx_con, "Training and switching %7d -> %7d\n\n", mtc_cfg.mtc_table[curr_ram_idx].rate_khz, 800000);
gfx_printf("Training and switching %7d -> %7d\n\n", mtc_cfg.mtc_table[curr_ram_idx].rate_khz, 800000);
ianos_loader(false, "bootloader/sys/libsys_minerva.bso", DRAM_LIB, (void *)&mtc_cfg);
// Thefollowing frequency needs periodic training every 100ms.
//msleep(200);
//mtc_cfg.rate_to = 1600000;
//gfx_printf(&gfx_con, "Training and switching %7d -> %7d\n\n", mtc_cfg.current_emc_table->rate_khz, 1600000);
//gfx_printf("Training and switching %7d -> %7d\n\n", mtc_cfg.current_emc_table->rate_khz, 1600000);
//ianos_loader(false, "bootloader/sys/libsys_minerva.bso", DRAM_LIB, (void *)&mtc_cfg);
//mtc_cfg.train_mode = OP_PERIODIC_TRAIN;
sd_unmount();
gfx_printf(&gfx_con, "Finished!");
gfx_printf("Finished!");
btn_wait();
}

View File

@@ -142,7 +142,7 @@ void display_backlight_pwm_init()
{
clock_enable_pwm();
PWM(PWM_CONTROLLER_PWM_CSR) = (1 << 31); // Enable PWM
PWM(PWM_CONTROLLER_PWM_CSR_0) = (1 << 31); // Enable PWM
PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) = (PINMUX_AUX(PINMUX_AUX_LCD_BL_PWM) >> 2) << 2 | 1; // PWM clock source.
gpio_config(GPIO_PORT_V, GPIO_PIN_0, GPIO_MODE_SPIO); // Backlight power mode.
@@ -156,7 +156,7 @@ void display_backlight(bool enable)
void display_backlight_brightness(u32 brightness, u32 step_delay)
{
u32 old_value = (PWM(PWM_CONTROLLER_PWM_CSR) >> 16) & 0xFF;
u32 old_value = (PWM(PWM_CONTROLLER_PWM_CSR_0) >> 16) & 0xFF;
if (brightness == old_value)
return;
@@ -167,7 +167,7 @@ void display_backlight_brightness(u32 brightness, u32 step_delay)
{
for (u32 i = old_value; i < brightness + 1; i++)
{
PWM(PWM_CONTROLLER_PWM_CSR) = (1 << 31) | (i << 16); // Enable PWM
PWM(PWM_CONTROLLER_PWM_CSR_0) = (1 << 31) | (i << 16); // Enable PWM
usleep(step_delay);
}
}
@@ -175,12 +175,12 @@ void display_backlight_brightness(u32 brightness, u32 step_delay)
{
for (u32 i = old_value; i > brightness; i--)
{
PWM(PWM_CONTROLLER_PWM_CSR) = (1 << 31) | (i << 16); // Enable PWM
PWM(PWM_CONTROLLER_PWM_CSR_0) = (1 << 31) | (i << 16); // Enable PWM
usleep(step_delay);
}
}
if (!brightness)
PWM(PWM_CONTROLLER_PWM_CSR) = 0;
PWM(PWM_CONTROLLER_PWM_CSR_0) = 0;
}
void display_end()

View File

@@ -350,9 +350,6 @@
#define MIPI_CAL_MIPI_BIAS_PAD_CFG2 0x60
/*! Display backlight related PWM registers. */
#define PWM_CONTROLLER_PWM_CSR 0x00
void display_init();
void display_backlight_pwm_init();
void display_end();

View File

@@ -1,6 +1,6 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (C) 2018 CTCaer
* Copyright (C) 2018-2019 CTCaer
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@@ -117,73 +117,73 @@ static const u8 _gfx_font[] = {
0x00, 0x00, 0x00, 0x4C, 0x32, 0x00, 0x00, 0x00 // Char 126 (~)
};
void gfx_init_ctxt(gfx_ctxt_t *ctxt, u32 *fb, u32 width, u32 height, u32 stride)
void gfx_init_ctxt(u32 *fb, u32 width, u32 height, u32 stride)
{
ctxt->fb = fb;
ctxt->width = width;
ctxt->height = height;
ctxt->stride = stride;
gfx_ctxt.fb = fb;
gfx_ctxt.width = width;
gfx_ctxt.height = height;
gfx_ctxt.stride = stride;
}
void gfx_clear_grey(gfx_ctxt_t *ctxt, u8 color)
void gfx_clear_grey(u8 color)
{
memset(ctxt->fb, color, 0x3C0000);
memset(gfx_ctxt.fb, color, 0x3C0000);
}
void gfx_clear_color(gfx_ctxt_t *ctxt, u32 color)
void gfx_clear_color(u32 color)
{
for (u32 i = 0; i < ctxt->height * ctxt->stride; i++)
ctxt->fb[i] = color;
for (u32 i = 0; i < gfx_ctxt.height * gfx_ctxt.stride; i++)
gfx_ctxt.fb[i] = color;
}
void gfx_clear_partial_grey(gfx_ctxt_t *ctxt, u8 color, u32 pos_x, u32 height)
void gfx_clear_partial_grey(u8 color, u32 pos_x, u32 height)
{
memset(ctxt->fb + pos_x * ctxt->stride, color, height * 4 * ctxt->stride);
memset(gfx_ctxt.fb + pos_x * gfx_ctxt.stride, color, height * 4 * gfx_ctxt.stride);
}
void gfx_con_init(gfx_con_t *con, gfx_ctxt_t *ctxt)
void gfx_con_init()
{
con->gfx_ctxt = ctxt;
con->fntsz = 16;
con->x = 0;
con->y = 0;
con->savedx = 0;
con->savedy = 0;
con->fgcol = 0xFFCCCCCC;
con->fillbg = 0;
con->bgcol = 0xFF1B1B1B;
con->mute = 0;
gfx_con.gfx_ctxt = &gfx_ctxt;
gfx_con.fntsz = 16;
gfx_con.x = 0;
gfx_con.y = 0;
gfx_con.savedx = 0;
gfx_con.savedy = 0;
gfx_con.fgcol = 0xFFCCCCCC;
gfx_con.fillbg = 1;
gfx_con.bgcol = 0xFF1B1B1B;
gfx_con.mute = 0;
}
void gfx_con_setcol(gfx_con_t *con, u32 fgcol, int fillbg, u32 bgcol)
void gfx_con_setcol(u32 fgcol, int fillbg, u32 bgcol)
{
con->fgcol = fgcol;
con->fillbg = fillbg;
con->bgcol = bgcol;
gfx_con.fgcol = fgcol;
gfx_con.fillbg = fillbg;
gfx_con.bgcol = bgcol;
}
void gfx_con_getpos(gfx_con_t *con, u32 *x, u32 *y)
void gfx_con_getpos(u32 *x, u32 *y)
{
*x = con->x;
*y = con->y;
*x = gfx_con.x;
*y = gfx_con.y;
}
void gfx_con_setpos(gfx_con_t *con, u32 x, u32 y)
void gfx_con_setpos(u32 x, u32 y)
{
con->x = x;
con->y = y;
gfx_con.x = x;
gfx_con.y = y;
}
void gfx_putc(gfx_con_t *con, char c)
void gfx_putc(char c)
{
// Duplicate code for performance reasons.
switch (con->fntsz)
switch (gfx_con.fntsz)
{
case 16:
if (c >= 32 && c <= 126)
{
u8 *cbuf = (u8 *)&_gfx_font[8 * (c - 32)];
u32 *fb = con->gfx_ctxt->fb + con->x + con->y * con->gfx_ctxt->stride;
u32 *fb = gfx_ctxt.fb + gfx_con.x + gfx_con.y * gfx_ctxt.stride;
for (u32 i = 0; i < 16; i+=2)
{
@@ -194,33 +194,33 @@ void gfx_putc(gfx_con_t *con, char c)
{
if (v & 1)
{
*fb = con->fgcol;
*fb = gfx_con.fgcol;
fb++;
*fb = con->fgcol;
*fb = gfx_con.fgcol;
}
else if (con->fillbg)
else if (gfx_con.fillbg)
{
*fb = con->bgcol;
*fb = gfx_con.bgcol;
fb++;
*fb = con->bgcol;
*fb = gfx_con.bgcol;
}
else
fb++;
v >>= 1;
fb++;
}
fb += con->gfx_ctxt->stride - 16;
fb += gfx_ctxt.stride - 16;
v = *cbuf;
}
}
con->x += 16;
gfx_con.x += 16;
}
else if (c == '\n')
{
con->x = 0;
con->y +=16;
if (con->y > con->gfx_ctxt->height - 16)
con->y = 0;
gfx_con.x = 0;
gfx_con.y +=16;
if (gfx_con.y > gfx_ctxt.height - 16)
gfx_con.y = 0;
}
break;
case 8:
@@ -228,45 +228,45 @@ void gfx_putc(gfx_con_t *con, char c)
if (c >= 32 && c <= 126)
{
u8 *cbuf = (u8 *)&_gfx_font[8 * (c - 32)];
u32 *fb = con->gfx_ctxt->fb + con->x + con->y * con->gfx_ctxt->stride;
u32 *fb = gfx_ctxt.fb + gfx_con.x + gfx_con.y * gfx_ctxt.stride;
for (u32 i = 0; i < 8; i++)
{
u8 v = *cbuf++;
for (u32 j = 0; j < 8; j++)
{
if (v & 1)
*fb = con->fgcol;
else if (con->fillbg)
*fb = con->bgcol;
*fb = gfx_con.fgcol;
else if (gfx_con.fillbg)
*fb = gfx_con.bgcol;
v >>= 1;
fb++;
}
fb += con->gfx_ctxt->stride - 8;
fb += gfx_ctxt.stride - 8;
}
con->x += 8;
gfx_con.x += 8;
}
else if (c == '\n')
{
con->x = 0;
con->y += 8;
if (con->y > con->gfx_ctxt->height - 8)
con->y = 0;
gfx_con.x = 0;
gfx_con.y += 8;
if (gfx_con.y > gfx_ctxt.height - 8)
gfx_con.y = 0;
}
break;
}
}
void gfx_puts(gfx_con_t *con, const char *s)
void gfx_puts(const char *s)
{
if (!s || con->mute)
if (!s || gfx_con.mute)
return;
for (; *s; s++)
gfx_putc(con, *s);
gfx_putc(*s);
}
static void _gfx_putn(gfx_con_t *con, u32 v, int base, char fill, int fcnt)
static void _gfx_putn(u32 v, int base, char fill, int fcnt)
{
char buf[65];
static const char digits[] = "0123456789ABCDEFghijklmnopqrstuvwxyz";
@@ -294,28 +294,28 @@ static void _gfx_putn(gfx_con_t *con, u32 v, int base, char fill, int fcnt)
}
}
gfx_puts(con, p);
gfx_puts(p);
}
void gfx_put_small_sep(gfx_con_t *con)
void gfx_put_small_sep()
{
u8 prevFontSize = con->fntsz;
con->fntsz = 8;
gfx_putc(con, '\n');
con->fntsz = prevFontSize;
u8 prevFontSize = gfx_con.fntsz;
gfx_con.fntsz = 8;
gfx_putc('\n');
gfx_con.fntsz = prevFontSize;
}
void gfx_put_big_sep(gfx_con_t *con)
void gfx_put_big_sep()
{
u8 prevFontSize = con->fntsz;
con->fntsz = 16;
gfx_putc(con, '\n');
con->fntsz = prevFontSize;
u8 prevFontSize = gfx_con.fntsz;
gfx_con.fntsz = 16;
gfx_putc('\n');
gfx_con.fntsz = prevFontSize;
}
void gfx_printf(gfx_con_t *con, const char *fmt, ...)
void gfx_printf(const char *fmt, ...)
{
if (con->mute)
if (gfx_con.mute)
return;
va_list ap;
@@ -348,40 +348,40 @@ void gfx_printf(gfx_con_t *con, const char *fmt, ...)
switch(*fmt)
{
case 'c':
gfx_putc(con, va_arg(ap, u32));
gfx_putc(va_arg(ap, u32));
break;
case 's':
gfx_puts(con, va_arg(ap, char *));
gfx_puts(va_arg(ap, char *));
break;
case 'd':
_gfx_putn(con, va_arg(ap, u32), 10, fill, fcnt);
_gfx_putn(va_arg(ap, u32), 10, fill, fcnt);
break;
case 'p':
case 'P':
case 'x':
case 'X':
_gfx_putn(con, va_arg(ap, u32), 16, fill, fcnt);
_gfx_putn(va_arg(ap, u32), 16, fill, fcnt);
break;
case 'k':
con->fgcol = va_arg(ap, u32);
gfx_con.fgcol = va_arg(ap, u32);
break;
case 'K':
con->bgcol = va_arg(ap, u32);
con->fillbg = 1;
gfx_con.bgcol = va_arg(ap, u32);
gfx_con.fillbg = 1;
break;
case '%':
gfx_putc(con, '%');
gfx_putc('%');
break;
case '\0':
goto out;
default:
gfx_putc(con, '%');
gfx_putc(con, *fmt);
gfx_putc('%');
gfx_putc(*fmt);
break;
}
}
else
gfx_putc(con, *fmt);
gfx_putc(*fmt);
fmt++;
}
@@ -389,33 +389,33 @@ void gfx_printf(gfx_con_t *con, const char *fmt, ...)
va_end(ap);
}
void gfx_hexdump(gfx_con_t *con, u32 base, const u8 *buf, u32 len)
void gfx_hexdump(u32 base, const u8 *buf, u32 len)
{
if (con->mute)
if (gfx_con.mute)
return;
u8 prevFontSize = con->fntsz;
con->fntsz = 8;
u8 prevFontSize = gfx_con.fntsz;
gfx_con.fntsz = 8;
for(u32 i = 0; i < len; i++)
{
if(i % 0x10 == 0)
{
if(i != 0)
{
gfx_puts(con, "| ");
gfx_puts("| ");
for(u32 j = 0; j < 0x10; j++)
{
u8 c = buf[i - 0x10 + j];
if(c >= 32 && c <= 126)
gfx_putc(con, c);
gfx_putc(c);
else
gfx_putc(con, '.');
gfx_putc('.');
}
gfx_putc(con, '\n');
gfx_putc('\n');
}
gfx_printf(con, "%08x: ", base + i);
gfx_printf("%08x: ", base + i);
}
gfx_printf(con, "%02x ", buf[i]);
gfx_printf("%02x ", buf[i]);
if (i == len - 1)
{
int ln = len % 0x10 != 0;
@@ -424,22 +424,22 @@ void gfx_hexdump(gfx_con_t *con, u32 base, const u8 *buf, u32 len)
{
k = (len & 0xF) - 1;
for (u32 j = 0; j < 0x10 - k; j++)
gfx_puts(con, " ");
gfx_puts(" ");
}
gfx_puts(con, "| ");
gfx_puts("| ");
for(u32 j = 0; j < (ln ? k : k + 1); j++)
{
u8 c = buf[i - k + j];
if(c >= 32 && c <= 126)
gfx_putc(con, c);
gfx_putc(c);
else
gfx_putc(con, '.');
gfx_putc('.');
}
gfx_putc(con, '\n');
gfx_putc('\n');
}
}
gfx_putc(con, '\n');
con->fntsz = prevFontSize;
gfx_putc('\n');
gfx_con.fntsz = prevFontSize;
}
static int abs(int x)
@@ -449,12 +449,12 @@ static int abs(int x)
return x;
}
void gfx_set_pixel(gfx_ctxt_t *ctxt, u32 x, u32 y, u32 color)
void gfx_set_pixel(u32 x, u32 y, u32 color)
{
ctxt->fb[x + y * ctxt->stride] = color;
gfx_ctxt.fb[x + y * gfx_ctxt.stride] = color;
}
void gfx_line(gfx_ctxt_t *ctxt, int x0, int y0, int x1, int y1, u32 color)
void gfx_line(int x0, int y0, int x1, int y1, u32 color)
{
int dx = abs(x1 - x0), sx = x0 < x1 ? 1 : -1;
int dy = abs(y1 - y0), sy = y0 < y1 ? 1 : -1;
@@ -462,7 +462,7 @@ void gfx_line(gfx_ctxt_t *ctxt, int x0, int y0, int x1, int y1, u32 color)
while (1)
{
gfx_set_pixel(ctxt, x0, y0, color);
gfx_set_pixel(x0, y0, color);
if (x0 == x1 && y0 == y1)
break;
e2 = err;
@@ -479,46 +479,46 @@ void gfx_line(gfx_ctxt_t *ctxt, int x0, int y0, int x1, int y1, u32 color)
}
}
void gfx_set_rect_grey(gfx_ctxt_t *ctxt, const u8 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y)
void gfx_set_rect_grey(const u8 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y)
{
u32 pos = 0;
for (u32 y = pos_y; y < (pos_y + size_y); y++)
{
for (u32 x = pos_x; x < (pos_x + size_x); x++)
{
memset(&ctxt->fb[x + y*ctxt->stride], buf[pos], 4);
memset(&gfx_ctxt.fb[x + y*gfx_ctxt.stride], buf[pos], 4);
pos++;
}
}
}
void gfx_set_rect_rgb(gfx_ctxt_t *ctxt, const u8 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y)
void gfx_set_rect_rgb(const u8 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y)
{
u32 pos = 0;
for (u32 y = pos_y; y < (pos_y + size_y); y++)
{
for (u32 x = pos_x; x < (pos_x + size_x); x++)
{
ctxt->fb[x + y*ctxt->stride] = buf[pos + 2] | (buf[pos + 1] << 8) | (buf[pos] << 16);
gfx_ctxt.fb[x + y * gfx_ctxt.stride] = buf[pos + 2] | (buf[pos + 1] << 8) | (buf[pos] << 16);
pos+=3;
}
}
}
void gfx_set_rect_argb(gfx_ctxt_t *ctxt, const u32 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y)
void gfx_set_rect_argb(const u32 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y)
{
u32 *ptr = (u32 *)buf;
for (u32 y = pos_y; y < (pos_y + size_y); y++)
for (u32 x = pos_x; x < (pos_x + size_x); x++)
ctxt->fb[x + y * ctxt->stride] = *ptr++;
gfx_ctxt.fb[x + y * gfx_ctxt.stride] = *ptr++;
}
void gfx_render_bmp_argb(gfx_ctxt_t *ctxt, const u32 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y)
void gfx_render_bmp_argb(const u32 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y)
{
for (u32 y = pos_y; y < (pos_y + size_y); y++)
{
for (u32 x = pos_x; x < (pos_x + size_x); x++)
ctxt->fb[x + y * ctxt->stride] = buf[(size_y + pos_y - 1 - y ) * size_x + x - pos_x];
gfx_ctxt.fb[x + y * gfx_ctxt.stride] = buf[(size_y + pos_y - 1 - y ) * size_x + x - pos_x];
}
}

View File

@@ -1,6 +1,6 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (C) 2018 CTCaer
* Copyright (C) 2018-2019 CTCaer
* Copyright (C) 2018 M4xw
*
* This program is free software; you can redistribute it and/or modify it
@@ -21,32 +21,32 @@
#include "../../common/common_gfx.h"
#define EPRINTF(text) gfx_printf(&gfx_con, "%k"text"%k\n", 0xFFFF0000, 0xFFCCCCCC)
#define EPRINTFARGS(text, args...) gfx_printf(&gfx_con, "%k"text"%k\n", 0xFFFF0000, args, 0xFFCCCCCC)
#define WPRINTF(text) gfx_printf(&gfx_con, "%k"text"%k\n", 0xFFFFDD00, 0xFFCCCCCC)
#define WPRINTFARGS(text, args...) gfx_printf(&gfx_con, "%k"text"%k\n", 0xFFFFDD00, args, 0xFFCCCCCC)
#define EPRINTF(text) gfx_printf("%k"text"%k\n", 0xFFFF0000, 0xFFCCCCCC)
#define EPRINTFARGS(text, args...) gfx_printf("%k"text"%k\n", 0xFFFF0000, args, 0xFFCCCCCC)
#define WPRINTF(text) gfx_printf("%k"text"%k\n", 0xFFFFDD00, 0xFFCCCCCC)
#define WPRINTFARGS(text, args...) gfx_printf("%k"text"%k\n", 0xFFFFDD00, args, 0xFFCCCCCC)
void gfx_init_ctxt(gfx_ctxt_t *ctxt, u32 *fb, u32 width, u32 height, u32 stride);
void gfx_clear_grey(gfx_ctxt_t *ctxt, u8 color);
void gfx_clear_partial_grey(gfx_ctxt_t *ctxt, u8 color, u32 pos_x, u32 height);
void gfx_clear_color(gfx_ctxt_t *ctxt, u32 color);
void gfx_con_init(gfx_con_t *con, gfx_ctxt_t *ctxt);
void gfx_con_setcol(gfx_con_t *con, u32 fgcol, int fillbg, u32 bgcol);
void gfx_con_getpos(gfx_con_t *con, u32 *x, u32 *y);
void gfx_con_setpos(gfx_con_t *con, u32 x, u32 y);
void gfx_putc(gfx_con_t *con, char c);
void gfx_puts(gfx_con_t *con, const char *s);
void gfx_printf(gfx_con_t *con, const char *fmt, ...);
void gfx_hexdump(gfx_con_t *con, u32 base, const u8 *buf, u32 len);
void gfx_init_ctxt(u32 *fb, u32 width, u32 height, u32 stride);
void gfx_clear_grey(u8 color);
void gfx_clear_partial_grey(u8 color, u32 pos_x, u32 height);
void gfx_clear_color(u32 color);
void gfx_con_init();
void gfx_con_setcol(u32 fgcol, int fillbg, u32 bgcol);
void gfx_con_getpos(u32 *x, u32 *y);
void gfx_con_setpos(u32 x, u32 y);
void gfx_putc(char c);
void gfx_puts(const char *s);
void gfx_printf(const char *fmt, ...);
void gfx_hexdump(u32 base, const u8 *buf, u32 len);
void gfx_set_pixel(gfx_ctxt_t *ctxt, u32 x, u32 y, u32 color);
void gfx_line(gfx_ctxt_t *ctxt, int x0, int y0, int x1, int y1, u32 color);
void gfx_put_small_sep(gfx_con_t *con);
void gfx_put_big_sep(gfx_con_t *con);
void gfx_set_rect_grey(gfx_ctxt_t *ctxt, const u8 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y);
void gfx_set_rect_rgb(gfx_ctxt_t *ctxt, const u8 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y);
void gfx_set_rect_argb(gfx_ctxt_t *ctxt, const u32 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y);
void gfx_render_bmp_argb(gfx_ctxt_t *ctxt, const u32 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y);
void gfx_set_pixel(u32 x, u32 y, u32 color);
void gfx_line(int x0, int y0, int x1, int y1, u32 color);
void gfx_put_small_sep();
void gfx_put_big_sep();
void gfx_set_rect_grey(const u8 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y);
void gfx_set_rect_rgb(const u8 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y);
void gfx_set_rect_argb(const u32 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y);
void gfx_render_bmp_argb(const u32 *buf, u32 size_x, u32 size_y, u32 pos_x, u32 pos_y);
// Global gfx console and context.
gfx_ctxt_t gfx_ctxt;

View File

@@ -32,7 +32,7 @@ extern u8 *Kc_MENU_LOGO;
extern hekate_config h_cfg;
void tui_sbar(gfx_con_t *con, bool force_update)
void tui_sbar(bool force_update)
{
u32 cx, cy;
@@ -41,78 +41,78 @@ void tui_sbar(gfx_con_t *con, bool force_update)
if (timePassed < 5)
return;
u8 prevFontSize = con->fntsz;
con->fntsz = 16;
u8 prevFontSize = gfx_con.fntsz;
gfx_con.fntsz = 16;
h_cfg.sbar_time_keeping = get_tmr_s();
u32 battPercent = 0;
int battVoltCurr = 0;
gfx_con_getpos(con, &cx, &cy);
gfx_con_setpos(con, 0, 1260);
gfx_con_getpos(&cx, &cy);
gfx_con_setpos(0, 1260);
max17050_get_property(MAX17050_RepSOC, (int *)&battPercent);
max17050_get_property(MAX17050_VCELL, &battVoltCurr);
gfx_clear_partial_grey(con->gfx_ctxt, 0x30, 1256, 24);
gfx_printf(con, "%K%k Battery: %d.%d%% (%d mV) - Charge:", 0xFF303030, 0xFF888888,
gfx_clear_partial_grey(0x30, 1256, 24);
gfx_printf("%K%k Battery: %d.%d%% (%d mV) - Charge:", 0xFF303030, 0xFF888888,
(battPercent >> 8) & 0xFF, (battPercent & 0xFF) / 26, battVoltCurr);
max17050_get_property(MAX17050_AvgCurrent, &battVoltCurr);
max17050_get_property(MAX17050_Current, &battVoltCurr);
if (battVoltCurr >= 0)
gfx_printf(con, " %k+%d mA%k%K\n",
gfx_printf(" %k+%d mA%k%K\n",
0xFF008800, battVoltCurr / 1000, 0xFFCCCCCC, 0xFF1B1B1B);
else
gfx_printf(con, " %k-%d mA%k%K\n",
gfx_printf(" %k-%d mA%k%K\n",
0xFF880000, (~battVoltCurr) / 1000, 0xFFCCCCCC, 0xFF1B1B1B);
con->fntsz = prevFontSize;
gfx_con_setpos(con, cx, cy);
gfx_con.fntsz = prevFontSize;
gfx_con_setpos(cx, cy);
}
void tui_pbar(gfx_con_t *con, int x, int y, u32 val, u32 fgcol, u32 bgcol)
void tui_pbar(int x, int y, u32 val, u32 fgcol, u32 bgcol)
{
u32 cx, cy;
if (val > 200)
val = 200;
gfx_con_getpos(con, &cx, &cy);
gfx_con_getpos(&cx, &cy);
gfx_con_setpos(con, x, y);
gfx_con_setpos(x, y);
gfx_printf(con, "%k[%3d%%]%k", fgcol, val, 0xFFCCCCCC);
gfx_printf("%k[%3d%%]%k", fgcol, val, 0xFFCCCCCC);
x += 7 * con->fntsz;
x += 7 * gfx_con.fntsz;
for (int i = 0; i < (con->fntsz >> 3) * 6; i++)
for (int i = 0; i < (gfx_con.fntsz >> 3) * 6; i++)
{
gfx_line(con->gfx_ctxt, x, y + i + 1, x + 3 * val, y + i + 1, fgcol);
gfx_line(con->gfx_ctxt, x + 3 * val, y + i + 1, x + 3 * 100, y + i + 1, bgcol);
gfx_line(x, y + i + 1, x + 3 * val, y + i + 1, fgcol);
gfx_line(x + 3 * val, y + i + 1, x + 3 * 100, y + i + 1, bgcol);
}
gfx_con_setpos(con, cx, cy);
gfx_con_setpos(cx, cy);
// Update status bar.
tui_sbar(con, false);
tui_sbar(false);
}
void *tui_do_menu(gfx_con_t *con, menu_t *menu)
void *tui_do_menu(menu_t *menu)
{
int idx = 0, prev_idx = 0, cnt = 0x7FFFFFFF;
gfx_clear_partial_grey(con->gfx_ctxt, 0x1B, 0, 1256);
tui_sbar(con, true);
gfx_clear_partial_grey(0x1B, 0, 1256);
tui_sbar(true);
#ifdef MENU_LOGO_ENABLE
gfx_set_rect_rgb(con->gfx_ctxt, Kc_MENU_LOGO,
gfx_set_rect_rgb(Kc_MENU_LOGO,
X_MENU_LOGO, Y_MENU_LOGO, X_POS_MENU_LOGO, Y_POS_MENU_LOGO);
#endif //MENU_LOGO_ENABLE
while (true)
{
gfx_con_setcol(con, 0xFFCCCCCC, 1, 0xFF1B1B1B);
gfx_con_setpos(con, menu->x, menu->y);
gfx_printf(con, "[%s]\n\n", menu->caption);
gfx_con_setcol(0xFFCCCCCC, 1, 0xFF1B1B1B);
gfx_con_setpos(menu->x, menu->y);
gfx_printf("[%s]\n\n", menu->caption);
// Skip caption or seperator lines selection.
while (menu->ents[idx].type == MENT_CAPTION ||
@@ -143,30 +143,30 @@ void *tui_do_menu(gfx_con_t *con, menu_t *menu)
for (cnt = 0; menu->ents[cnt].type != MENT_END; cnt++)
{
if (cnt == idx)
gfx_con_setcol(con, 0xFF1B1B1B, 1, 0xFFCCCCCC);
gfx_con_setcol(0xFF1B1B1B, 1, 0xFFCCCCCC);
else
gfx_con_setcol(con, 0xFFCCCCCC, 1, 0xFF1B1B1B);
gfx_con_setcol(0xFFCCCCCC, 1, 0xFF1B1B1B);
if (menu->ents[cnt].type == MENT_CAPTION)
gfx_printf(con, "%k %s", menu->ents[cnt].color, menu->ents[cnt].caption);
gfx_printf("%k %s", menu->ents[cnt].color, menu->ents[cnt].caption);
else if (menu->ents[cnt].type != MENT_CHGLINE)
gfx_printf(con, " %s", menu->ents[cnt].caption);
gfx_printf(" %s", menu->ents[cnt].caption);
if(menu->ents[cnt].type == MENT_MENU)
gfx_printf(con, "%k...", 0xFF0099EE);
gfx_printf(con, " \n");
gfx_printf("%k...", 0xFF0099EE);
gfx_printf(" \n");
}
gfx_con_setcol(con, 0xFFCCCCCC, 1, 0xFF1B1B1B);
gfx_putc(con, '\n');
gfx_con_setcol(0xFFCCCCCC, 1, 0xFF1B1B1B);
gfx_putc('\n');
// Print help and battery status.
gfx_con_setpos(con, 0, 1127);
gfx_con_setpos(0, 1127);
if (h_cfg.errors)
{
gfx_printf(con, "%k Warning: %k", 0xFF800000, 0xFF555555);
gfx_printf("%k Warning: %k", 0xFF800000, 0xFF555555);
if (h_cfg.errors & ERR_LIBSYS_LP0)
gfx_printf(con, "Sleep mode library is missing!\n");
gfx_printf("Sleep mode library is missing!\n");
}
gfx_con_setpos(con, 0, 1191);
gfx_printf(con, "%k VOL: Move up/down\n PWR: Select option%k", 0xFF555555, 0xFFCCCCCC);
gfx_con_setpos(0, 1191);
gfx_printf("%k VOL: Move up/down\n PWR: Select option%k", 0xFF555555, 0xFFCCCCCC);
display_backlight_brightness(h_cfg.backlight, 1000);
@@ -196,7 +196,7 @@ void *tui_do_menu(gfx_con_t *con, menu_t *menu)
ent->handler(ent->data);
break;
case MENT_MENU:
return tui_do_menu(con, ent->menu);
return tui_do_menu(ent->menu);
break;
case MENT_DATA:
return ent->data;
@@ -212,14 +212,14 @@ void *tui_do_menu(gfx_con_t *con, menu_t *menu)
default:
break;
}
con->fntsz = 16;
gfx_clear_partial_grey(con->gfx_ctxt, 0x1B, 0, 1256);
gfx_con.fntsz = 16;
gfx_clear_partial_grey(0x1B, 0, 1256);
#ifdef MENU_LOGO_ENABLE
gfx_set_rect_rgb(con->gfx_ctxt, Kc_MENU_LOGO,
gfx_set_rect_rgb(Kc_MENU_LOGO,
X_MENU_LOGO, Y_MENU_LOGO, X_POS_MENU_LOGO, Y_POS_MENU_LOGO);
#endif //MENU_LOGO_ENABLE
}
tui_sbar(con, false);
tui_sbar(false);
}
return NULL;

View File

@@ -59,8 +59,8 @@ typedef struct _menu_t
#define MDEF_CAPTION(caption, color) { MENT_CAPTION, caption, color }
#define MDEF_CHGLINE() {MENT_CHGLINE}
void tui_sbar(gfx_con_t *con, bool force_update);
void tui_pbar(gfx_con_t *con, int x, int y, u32 val, u32 fgcol, u32 bgcol);
void *tui_do_menu(gfx_con_t *con, menu_t *menu);
void tui_sbar(bool force_update);
void tui_pbar(int x, int y, u32 val, u32 fgcol, u32 bgcol);
void *tui_do_menu(menu_t *menu);
#endif

View File

@@ -60,9 +60,24 @@ typedef struct _fss_content_t
int parse_fss(launch_ctxt_t *ctxt, const char *value)
{
FIL fp;
bool stock = false;
LIST_FOREACH_ENTRY(ini_kv_t, kv, &ctxt->cfg->kvs, link)
{
if (!strcmp("stock", kv->key))
if (kv->val[0] == '1')
stock = true;
}
if (stock && ctxt->pkg1_id->kb <= KB_FIRMWARE_VERSION_620)
return 1;
if (f_open(&fp, value, FA_READ) != FR_OK)
return 0;
ctxt->atmosphere = true;
void *fss = malloc(f_size(&fp));
// Read header.
f_read(&fp, fss, 0x400, NULL);
@@ -72,7 +87,7 @@ int parse_fss(launch_ctxt_t *ctxt, const char *value)
if (fss_meta->magic == FSS0_MAGIC)
{
gfx_printf(&gfx_con, "Found FSS0, Atmosphere %d.%d.%d-%08x\n"
gfx_printf("Found FSS0, Atmosphere %d.%d.%d-%08x\n"
"Max HOS supported: %d.%d.%d\n"
"Unpacking and loading components.. ",
fss_meta->version >> 24, (fss_meta->version >> 16) & 0xFF, (fss_meta->version >> 8) & 0xFF, fss_meta->git_rev,
@@ -89,7 +104,9 @@ int parse_fss(launch_ctxt_t *ctxt, const char *value)
// Load content to launch context.
switch (curr_fss_cnt[i].type)
{
case CNT_TYPE_KIP:;
case CNT_TYPE_KIP:
if (stock)
continue;
merge_kip_t *mkip1 = (merge_kip_t *)malloc(sizeof(merge_kip_t));
mkip1->kip1 = content;
list_append(&ctxt->kip1_list, &mkip1->link);
@@ -114,7 +131,7 @@ int parse_fss(launch_ctxt_t *ctxt, const char *value)
f_read(&fp, content, curr_fss_cnt[i].size, NULL);
}
gfx_printf(&gfx_con, "Done!\n");
gfx_printf("Done!\n");
f_close(&fp);
return 1;

View File

@@ -45,7 +45,7 @@ extern hekate_config h_cfg;
extern void sd_unmount();
//#define DPRINTF(...) gfx_printf(&gfx_con, __VA_ARGS__)
//#define DPRINTF(...) gfx_printf(__VA_ARGS__)
#define DPRINTF(...)
#define PKG2_LOAD_ADDR 0xA9800000
@@ -87,7 +87,7 @@ static const u8 master_keyseed_4xx_5xx_610[0x10] =
{ 0x2D, 0xC1, 0xF4, 0x8D, 0xF3, 0x5B, 0x69, 0x33, 0x42, 0x10, 0xAC, 0x65, 0xDA, 0x90, 0x46, 0x66 };
static const u8 master_keyseed_620[0x10] =
{ 0x37, 0x4B, 0x77, 0x29, 0x59, 0xB4, 0x04, 0x30, 0x81, 0xF6, 0xE5, 0x8C, 0x6D, 0x36, 0x17, 0x9A };
{ 0x37, 0x4B, 0x77, 0x29, 0x59, 0xB4, 0x04, 0x30, 0x81, 0xF6, 0xE5, 0x8C, 0x6D, 0x36, 0x17, 0x9A };
static const u8 console_keyseed_4xx_5xx[0x10] =
{ 0x0C, 0x91, 0x09, 0xDB, 0x93, 0x93, 0x07, 0x81, 0x07, 0x3C, 0xC4, 0x16, 0x22, 0x7C, 0x6C, 0x28 };
@@ -112,17 +112,17 @@ static void _se_lock(bool lock_se)
SB(SB_CSR) = 0x10; // Protected IROM enable.
// This is useful for documenting the bits in the SE config registers, so we can keep it around.
/*gfx_printf(&gfx_con, "SE(SE_SECURITY_0) = %08X\n", SE(SE_SECURITY_0));
gfx_printf(&gfx_con, "SE(0x4) = %08X\n", SE(0x4));
gfx_printf(&gfx_con, "SE(SE_KEY_TABLE_ACCESS_LOCK_OFFSET) = %08X\n", SE(SE_KEY_TABLE_ACCESS_LOCK_OFFSET));
gfx_printf(&gfx_con, "SE(SE_RSA_KEYTABLE_ACCESS_LOCK_OFFSET) = %08X\n", SE(SE_RSA_KEYTABLE_ACCESS_LOCK_OFFSET));
/*gfx_printf("SE(SE_SECURITY_0) = %08X\n", SE(SE_SECURITY_0));
gfx_printf("SE(0x4) = %08X\n", SE(0x4));
gfx_printf("SE(SE_KEY_TABLE_ACCESS_LOCK_OFFSET) = %08X\n", SE(SE_KEY_TABLE_ACCESS_LOCK_OFFSET));
gfx_printf("SE(SE_RSA_KEYTABLE_ACCESS_LOCK_OFFSET) = %08X\n", SE(SE_RSA_KEYTABLE_ACCESS_LOCK_OFFSET));
for(u32 i = 0; i < 16; i++)
gfx_printf(&gfx_con, "%02X ", SE(SE_KEY_TABLE_ACCESS_REG_OFFSET + i * 4) & 0xFF);
gfx_putc(&gfx_con, '\n');
gfx_printf("%02X ", SE(SE_KEY_TABLE_ACCESS_REG_OFFSET + i * 4) & 0xFF);
gfx_putc('\n');
for(u32 i = 0; i < 2; i++)
gfx_printf(&gfx_con, "%02X ", SE(SE_RSA_KEYTABLE_ACCESS_REG_OFFSET + i * 4) & 0xFF);
gfx_putc(&gfx_con, '\n');
gfx_hexdump(&gfx_con, SE_BASE, (void *)SE_BASE, 0x400);*/
gfx_printf("%02X ", SE(SE_RSA_KEYTABLE_ACCESS_REG_OFFSET + i * 4) & 0xFF);
gfx_putc('\n');
gfx_hexdump(SE_BASE, (void *)SE_BASE, 0x400);*/
}
void _pmc_scratch_lock(u32 kb)
@@ -132,7 +132,7 @@ void _pmc_scratch_lock(u32 kb)
case KB_FIRMWARE_VERSION_100_200:
case KB_FIRMWARE_VERSION_300:
case KB_FIRMWARE_VERSION_301:
PMC(APBDEV_PMC_SEC_DISABLE) = 0x7FFFF3;
PMC(APBDEV_PMC_SEC_DISABLE) = 0x7FFFF3;
PMC(APBDEV_PMC_SEC_DISABLE2) = 0xFFFFFFFF;
PMC(APBDEV_PMC_SEC_DISABLE3) = 0xFFAFFFFF;
PMC(APBDEV_PMC_SEC_DISABLE4) = 0xFFFFFFFF;
@@ -308,7 +308,7 @@ static int _read_emmc_pkg1(launch_ctxt_t *ctxt)
EPRINTF("Unknown pkg1 version.");
goto out;
}
gfx_printf(&gfx_con, "Identified pkg1 and Keyblob %d\n\n", ctxt->pkg1_id->kb);
gfx_printf("Identified pkg1 and Keyblob %d\n\n", ctxt->pkg1_id->kb);
// Read the correct keyblob.
ctxt->keyblob = (u8 *)calloc(NX_EMMC_BLOCKSIZE, 1);
@@ -369,6 +369,7 @@ out:;
static void _free_launch_components(launch_ctxt_t *ctxt)
{
ini_free_section(ctxt->cfg);
free(ctxt->keyblob);
free(ctxt->pkg1);
free(ctxt->pkg2);
@@ -388,28 +389,33 @@ int hos_launch(ini_sec_t *cfg)
memset(&tsec_ctxt, 0, sizeof(tsec_ctxt_t));
list_init(&ctxt.kip1_list);
ctxt.cfg = cfg;
if (!gfx_con.mute)
gfx_clear_grey(&gfx_ctxt, 0x1B);
gfx_con_setpos(&gfx_con, 0, 0);
gfx_clear_grey(0x1B);
gfx_con_setpos(0, 0);
// Try to parse config if present.
if (cfg && !parse_boot_config(&ctxt, cfg))
return 0;
gfx_printf(&gfx_con, "Initializing...\n\n");
gfx_printf("Initializing...\n\n");
// Read package1 and the correct keyblob.
if (!_read_emmc_pkg1(&ctxt))
return 0;
// Try to parse config if present.
if (ctxt.cfg && !parse_boot_config(&ctxt))
{
EPRINTF("Wrong ini cfg or missing files!");
return 0;
}
// Check if fuses lower than 4.0.0 and if yes apply NO Gamecard patch.
if (h_cfg.autonogc && !(fuse_read_odm(7) & ~0xF) && ctxt.pkg1_id->kb >= KB_FIRMWARE_VERSION_400)
config_kip1patch(&ctxt, "nogc");
gfx_printf(&gfx_con, "Loaded pkg1 & keyblob\n");
gfx_printf("Loaded pkg1 & keyblob\n");
// Generate keys.
if (!h_cfg.se_keygen_done || ctxt.pkg1_id->kb == KB_FIRMWARE_VERSION_620)
if (!h_cfg.se_keygen_done)
{
tsec_ctxt.fw = (u8 *)ctxt.pkg1 + ctxt.pkg1_id->tsec_off;
tsec_ctxt.pkg1 = ctxt.pkg1;
@@ -418,15 +424,15 @@ int hos_launch(ini_sec_t *cfg)
if (ctxt.pkg1_id->kb >= KB_FIRMWARE_VERSION_700 && !h_cfg.sept_run)
{
gfx_printf(&gfx_con, "Failed to run sept\n");
gfx_printf("Failed to run sept\n");
return 0;
}
if (!keygen(ctxt.keyblob, ctxt.pkg1_id->kb, &tsec_ctxt))
return 0;
DPRINTF("Generated keys\n");
h_cfg.se_keygen_done = 1;
if (ctxt.pkg1_id->kb <= KB_FIRMWARE_VERSION_600)
h_cfg.se_keygen_done = 1;
}
// Decrypt and unpack package1 if we require parts of it.
@@ -438,7 +444,7 @@ int hos_launch(ini_sec_t *cfg)
if (ctxt.pkg1_id->kb <= KB_FIRMWARE_VERSION_620)
{
pkg1_unpack((void *)ctxt.pkg1_id->warmboot_base, (void *)ctxt.pkg1_id->secmon_base, NULL, ctxt.pkg1_id, ctxt.pkg1);
gfx_printf(&gfx_con, "Decrypted & unpacked pkg1\n");
gfx_printf("Decrypted & unpacked pkg1\n");
}
else
{
@@ -459,7 +465,7 @@ int hos_launch(ini_sec_t *cfg)
}
// Else we patch it to allow downgrading.
patch_t *warmboot_patchset = ctxt.pkg1_id->warmboot_patchset;
gfx_printf(&gfx_con, "%kPatching Warmboot%k\n", 0xFFFFBA00, 0xFFCCCCCC);
gfx_printf("%kPatching Warmboot%k\n", 0xFFFFBA00, 0xFFCCCCCC);
for (u32 i = 0; warmboot_patchset[i].off != 0xFFFFFFFF; i++)
*(vu32 *)(ctxt.pkg1_id->warmboot_base + warmboot_patchset[i].off) = warmboot_patchset[i].val;
}
@@ -474,32 +480,32 @@ int hos_launch(ini_sec_t *cfg)
{
// Else we patch it to allow for an unsigned package2 and patched kernel.
patch_t *secmon_patchset = ctxt.pkg1_id->secmon_patchset;
gfx_printf(&gfx_con, "%kPatching Security Monitor%k\n", 0xFFFFBA00, 0xFFCCCCCC);
gfx_printf("%kPatching Security Monitor%k\n", 0xFFFFBA00, 0xFFCCCCCC);
for (u32 i = 0; secmon_patchset[i].off != 0xFFFFFFFF; i++)
*(vu32 *)(ctxt.pkg1_id->secmon_base + secmon_patchset[i].off) = secmon_patchset[i].val;
}
gfx_printf(&gfx_con, "Loaded warmboot and secmon\n");
gfx_printf("Loaded warmboot and secmon\n");
// Read package2.
u8 *bootConfigBuf = _read_emmc_pkg2(&ctxt);
if (!bootConfigBuf)
return 0;
gfx_printf(&gfx_con, "Read pkg2\n");
gfx_printf("Read pkg2\n");
// Decrypt package2 and parse KIP1 blobs in INI1 section.
pkg2_hdr_t *pkg2_hdr = pkg2_decrypt(ctxt.pkg2);
if (!pkg2_hdr)
{
gfx_printf(&gfx_con, "Pkg2 decryption failed!\n");
gfx_printf("Pkg2 decryption failed!\n");
return 0;
}
LIST_INIT(kip1_info);
pkg2_parse_kips(&kip1_info, pkg2_hdr);
pkg2_parse_kips(&kip1_info, pkg2_hdr, &ctxt.new_pkg2);
gfx_printf(&gfx_con, "Parsed ini1\n");
gfx_printf("Parsed ini1\n");
// Use the kernel included in package2 in case we didn't load one already.
if (!ctxt.kernel)
@@ -507,16 +513,23 @@ int hos_launch(ini_sec_t *cfg)
ctxt.kernel = pkg2_hdr->data;
ctxt.kernel_size = pkg2_hdr->sec_size[PKG2_SEC_KERNEL];
if (ctxt.svcperm || ctxt.debugmode || ctxt.atmosphere)
if (!ctxt.stock && (ctxt.svcperm || ctxt.debugmode || ctxt.atmosphere))
{
u32 kernel_crc32 = crc32c(ctxt.kernel, ctxt.kernel_size);
ctxt.pkg2_kernel_id = pkg2_identify(kernel_crc32);
u8 kernel_hash[0x20];
// Hash only Kernel when it embeds INI1.
if (!ctxt.new_pkg2)
se_calc_sha256(kernel_hash, ctxt.kernel, ctxt.kernel_size);
else
se_calc_sha256(kernel_hash, ctxt.kernel + PKG2_NEWKERN_START,
*(u32 *)(ctxt.kernel + PKG2_NEWKERN_INI1_START) - PKG2_NEWKERN_START);
ctxt.pkg2_kernel_id = pkg2_identify(kernel_hash);
// In case a kernel patch option is set; allows to disable SVC verification or/and enable debug mode.
kernel_patch_t *kernel_patchset = ctxt.pkg2_kernel_id->kernel_patchset;
if (kernel_patchset != NULL)
{
gfx_printf(&gfx_con, "%kPatching kernel%k\n", 0xFFFFBA00, 0xFFCCCCCC);
gfx_printf("%kPatching kernel%k\n", 0xFFFFBA00, 0xFFCCCCCC);
u32 *temp;
for (u32 i = 0; kernel_patchset[i].id != 0xFFFFFFFF; i++)
{
@@ -538,7 +551,7 @@ int hos_launch(ini_sec_t *cfg)
}
// Merge extra KIP1s into loaded ones.
gfx_printf(&gfx_con, "%kPatching kips%k\n", 0xFFFFBA00, 0xFFCCCCCC);
gfx_printf("%kPatching kips%k\n", 0xFFFFBA00, 0xFFCCCCCC);
LIST_FOREACH_ENTRY(merge_kip_t, mki, &ctxt.kip1_list, link)
pkg2_merge_kip(&kip1_info, (pkg2_kip1_t *)mki->kip1);
@@ -554,11 +567,11 @@ int hos_launch(ini_sec_t *cfg)
}
// Rebuild and encrypt package2.
pkg2_build_encrypt((void *)PKG2_LOAD_ADDR, ctxt.kernel, ctxt.kernel_size, &kip1_info);
pkg2_build_encrypt((void *)PKG2_LOAD_ADDR, ctxt.kernel, ctxt.kernel_size, &kip1_info, ctxt.new_pkg2);
gfx_printf(&gfx_con, "Rebuilt & loaded pkg2\n");
gfx_printf("Rebuilt & loaded pkg2\n");
gfx_printf(&gfx_con, "\n%kBooting...%k\n", 0xFF96FF00, 0xFFCCCCCC);
gfx_printf("\n%kBooting...%k\n", 0xFF96FF00, 0xFFCCCCCC);
// Clear pkg1/pkg2 keys.
se_aes_key_clear(8);
@@ -610,7 +623,7 @@ int hos_launch(ini_sec_t *cfg)
// Config Exosphère if booting full Atmosphère.
if (ctxt.atmosphere && ctxt.secmon)
config_exosphere(ctxt.pkg1_id->id, ctxt.pkg1_id->kb, (void *)ctxt.pkg1_id->warmboot_base, ctxt.pkg1);
config_exosphere(ctxt.pkg1_id->id, ctxt.pkg1_id->kb, (void *)ctxt.pkg1_id->warmboot_base, ctxt.stock);
// Unmount SD card.
sd_unmount();
@@ -640,7 +653,6 @@ int hos_launch(ini_sec_t *cfg)
secmon_mb->out = 0;
// Free allocated memory.
ini_free_section(cfg);
_free_launch_components(&ctxt);
// Disable display. This must be executed before secmon to provide support for all fw versions.
@@ -652,7 +664,7 @@ int hos_launch(ini_sec_t *cfg)
// Wait for secmon to get ready.
if (smmu_is_used())
smmu_exit();
else
else
cluster_boot_cpu0(ctxt.pkg1_id->secmon_base);
while (!secmon_mb->out)
usleep(1); // This only works when in IRAM or with a trained DRAM.

View File

@@ -51,6 +51,7 @@ typedef struct _launch_ctxt_t
void *pkg2;
u32 pkg2_size;
bool new_pkg2;
void *kernel;
u32 kernel_size;
link_t kip1_list;
@@ -58,7 +59,10 @@ typedef struct _launch_ctxt_t
bool svcperm;
bool debugmode;
bool stock;
bool atmosphere;
ini_sec_t *cfg;
} launch_ctxt_t;
typedef struct _merge_kip_t

View File

@@ -26,48 +26,41 @@
#include "../gfx/gfx.h"
//#define DPRINTF(...) gfx_printf(&gfx_con, __VA_ARGS__)
//#define DPRINTF(...) gfx_printf(__VA_ARGS__)
#define DPRINTF(...)
extern void *sd_file_read(const char *path, u32 *fsize);
static int _config_warmboot(launch_ctxt_t *ctxt, const char *value)
{
FIL fp;
if (f_open(&fp, value, FA_READ) != FR_OK)
ctxt->warmboot = sd_file_read(value, &ctxt->warmboot_size);
if (!ctxt->warmboot)
return 0;
ctxt->warmboot_size = f_size(&fp);
ctxt->warmboot = malloc(ctxt->warmboot_size);
f_read(&fp, ctxt->warmboot, ctxt->warmboot_size, NULL);
f_close(&fp);
return 1;
}
static int _config_secmon(launch_ctxt_t *ctxt, const char *value)
{
FIL fp;
if (f_open(&fp, value, FA_READ) != FR_OK)
ctxt->secmon = sd_file_read(value, &ctxt->secmon_size);
if (!ctxt->secmon)
return 0;
ctxt->secmon_size = f_size(&fp);
ctxt->secmon = malloc(ctxt->secmon_size);
f_read(&fp, ctxt->secmon, ctxt->secmon_size, NULL);
f_close(&fp);
return 1;
}
static int _config_kernel(launch_ctxt_t *ctxt, const char *value)
{
FIL fp;
if (f_open(&fp, value, FA_READ) != FR_OK)
ctxt->kernel = sd_file_read(value, &ctxt->kernel_size);
if (!ctxt->kernel)
return 0;
ctxt->kernel_size = f_size(&fp);
ctxt->kernel = malloc(ctxt->kernel_size);
f_read(&fp, ctxt->kernel, ctxt->kernel_size, NULL);
f_close(&fp);
return 1;
}
static int _config_kip1(launch_ctxt_t *ctxt, const char *value)
{
FIL fp;
u32 size;
if (!memcmp(value + strlen(value) - 1, "*", 1))
{
@@ -90,18 +83,18 @@ static int _config_kip1(launch_ctxt_t *ctxt, const char *value)
break;
memcpy(dir + dirlen, &filelist[i * 256], strlen(&filelist[i * 256]) + 1);
if (f_open(&fp, dir, FA_READ))
merge_kip_t *mkip1 = (merge_kip_t *)malloc(sizeof(merge_kip_t));
mkip1->kip1 = sd_file_read(dir, &size);
if (!mkip1->kip1)
{
free(mkip1);
free(dir);
free(filelist);
return 0;
}
merge_kip_t *mkip1 = (merge_kip_t *)malloc(sizeof(merge_kip_t));
mkip1->kip1 = malloc(f_size(&fp));
f_read(&fp, mkip1->kip1, f_size(&fp), NULL);
DPRINTF("Loaded kip1 from SD (size %08X)\n", f_size(&fp));
f_close(&fp);
DPRINTF("Loaded kip1 from SD (size %08X)\n", size);
list_append(&ctxt->kip1_list, &mkip1->link);
i++;
@@ -113,13 +106,15 @@ static int _config_kip1(launch_ctxt_t *ctxt, const char *value)
}
else
{
if (f_open(&fp, value, FA_READ))
return 0;
merge_kip_t *mkip1 = (merge_kip_t *)malloc(sizeof(merge_kip_t));
mkip1->kip1 = malloc(f_size(&fp));
f_read(&fp, mkip1->kip1, f_size(&fp), NULL);
DPRINTF("Loaded kip1 from SD (size %08X)\n", f_size(&fp));
f_close(&fp);
mkip1->kip1 = sd_file_read(value, &size);
if (!mkip1->kip1)
{
free(mkip1);
return 0;
}
DPRINTF("Loaded kip1 from SD (size %08X)\n", size);
list_append(&ctxt->kip1_list, &mkip1->link);
}
@@ -176,6 +171,16 @@ static int _config_debugmode(launch_ctxt_t *ctxt, const char *value)
return 1;
}
static int _config_stock(launch_ctxt_t *ctxt, const char *value)
{
if (*value == '1')
{
DPRINTF("Disabled all patching\n");
ctxt->stock = true;
}
return 1;
}
static int _config_atmosphere(launch_ctxt_t *ctxt, const char *value)
{
if (*value == '1')
@@ -205,23 +210,26 @@ 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 },
{ NULL, NULL },
};
int parse_boot_config(launch_ctxt_t *ctxt, ini_sec_t *cfg)
int parse_boot_config(launch_ctxt_t *ctxt)
{
LIST_FOREACH_ENTRY(ini_kv_t, kv, &cfg->kvs, link)
LIST_FOREACH_ENTRY(ini_kv_t, kv, &ctxt->cfg->kvs, link)
{
for(u32 i = 0; _config_handlers[i].key; i++)
{
if (!strcmp(_config_handlers[i].key, kv->key))
if (!_config_handlers[i].handler(ctxt, kv->val))
{
EPRINTFARGS("Error while loading %s:\n%s", kv->key, kv->val);
return 0;
}
}
}
return 1;
}

View File

@@ -19,7 +19,7 @@
#include "hos.h"
int parse_boot_config(launch_ctxt_t *ctxt, ini_sec_t *cfg);
int parse_boot_config(launch_ctxt_t *ctxt);
int config_kip1patch(launch_ctxt_t *ctxt, const char *value);
#endif

View File

@@ -143,6 +143,7 @@ static const pkg1_id_t _pkg1_ids[] = {
{ "20181107105733", 6, 0x0E00, 0x6FE0, { 1, 2, 0 }, 0x4002B000, 0x4003D800, false, _secmon_620_patchset, _warmboot_4_patchset }, //6.2.0
{ "20181218175730", 7, 0x0F00, 0x6FE0, { 1, 2, 0 }, 0x40030000, 0x4003E000, false, NULL, _warmboot_4_patchset }, //7.0.0
{ "20190208150037", 7, 0x0F00, 0x6FE0, { 1, 2, 0 }, 0x40030000, 0x4003E000, false, NULL, _warmboot_4_patchset }, //7.0.1
{ "20190314172056", 7, 0x0E00, 0x6FE0, { 1, 2, 0 }, 0x40030000, 0x4003E000, false, NULL, _warmboot_4_patchset }, //8.0.0
{ NULL } //End.
};
@@ -151,7 +152,7 @@ const pkg1_id_t *pkg1_identify(u8 *pkg1)
char build_date[15];
memcpy(build_date, (char *)(pkg1 + 0x10), 14);
build_date[14] = 0;
gfx_printf(&gfx_con, "Found pkg1 ('%s').\n\n", build_date);
gfx_printf("Found pkg1 ('%s').\n\n", build_date);
for (u32 i = 0; _pkg1_ids[i].id; i++)
if (!memcmp(pkg1 + 0x10, _pkg1_ids[i].id, 12))

View File

@@ -27,7 +27,7 @@
#include "../gfx/gfx.h"
/*#include "util.h"
#define DPRINTF(...) gfx_printf(&gfx_con, __VA_ARGS__)
#define DPRINTF(...) gfx_printf(__VA_ARGS__)
#define DEBUG_PRINTING*/
#define DPRINTF(...)
@@ -43,6 +43,7 @@
#define FREE_CODE_OFF_1ST_500 0x5C020
#define FREE_CODE_OFF_1ST_600 0x5EE00
#define FREE_CODE_OFF_1ST_700 0x5FEC0
#define FREE_CODE_OFF_1ST_800 0x607F0
#define ID_SND_OFF_100 0x23CC0
#define ID_SND_OFF_200 0x3F134
@@ -52,6 +53,7 @@
#define ID_SND_OFF_500 0x2AD34
#define ID_SND_OFF_600 0x2BB8C
#define ID_SND_OFF_700 0x2D044
#define ID_SND_OFF_800 0x2F1FC
#define ID_RCV_OFF_100 0x219F0
#define ID_RCV_OFF_200 0x3D1A8
@@ -61,6 +63,7 @@
#define ID_RCV_OFF_500 0x28DAC
#define ID_RCV_OFF_600 0x29B6C
#define ID_RCV_OFF_700 0x2B23C
#define ID_RCV_OFF_800 0x2D424
static u32 PRC_ID_SND_100[] =
{
@@ -98,17 +101,7 @@ static u32 PRC_ID_RCV_300[] =
0xD2FFFFE9, 0x8A09014A, 0xD2FFFFC9, 0xEB09015F, 0x54000040, 0xF9415568, 0xA8C12FEA
};
static u32 PRC_ID_SND_302[] =
{
0xA9BF2FEA, 0x2A1803EB, 0xD37EF56B, 0xF86B6B8B, 0x92FFFFE9, 0x8A090168, 0xD2FFFFE9, 0x8A09016B,
0xD2FFFFC9, 0xEB09017F, 0x54000040, 0xF9415548, 0xA8C12FEA
};
#define FREE_CODE_OFF_2ND_302 (FREE_CODE_OFF_1ST_302 + sizeof(PRC_ID_SND_302) + sizeof(u32))
static u32 PRC_ID_RCV_302[] =
{
0xA9BF2FEA, 0x2A0F03EA, 0xD37EF54A, 0xF9405FEB, 0xF86A696A, 0xF9407BEB, 0x92FFFFE9, 0x8A090148,
0xD2FFFFE9, 0x8A09014A, 0xD2FFFFC9, 0xEB09015F, 0x54000040, 0xF9415568, 0xA8C12FEA
};
#define FREE_CODE_OFF_2ND_302 (FREE_CODE_OFF_1ST_302 + sizeof(PRC_ID_SND_300) + sizeof(u32))
static u32 PRC_ID_SND_400[] =
{
@@ -162,6 +155,8 @@ static u32 PRC_ID_RCV_700[] =
0xD63F0100, 0xA8C127E8, 0xAA0003E8, 0xA8C12FEA, 0xAA0803E0
};
#define FREE_CODE_OFF_2ND_800 (FREE_CODE_OFF_1ST_800 + sizeof(PRC_ID_SND_700) + sizeof(u32))
// Include kernel patches here, so we can utilize pkg1 id
KERNEL_PATCHSET_DEF(_kernel_1_patchset,
{ SVC_VERIFY_DS, 0x3764C, _NOP(), NULL }, // Disable SVC verifications
@@ -210,13 +205,13 @@ KERNEL_PATCHSET_DEF(_kernel_302_patchset,
{ DEBUG_MODE_EN, 0x48414, _MOVZX(8, 1, 0), NULL }, // Enable Debug Patch
// Atmosphère kernel patches.
{ ATM_GEN_PATCH, ID_SND_OFF_302, _B(ID_SND_OFF_302, FREE_CODE_OFF_1ST_302), NULL}, // Send process id branch.
{ ATM_ARR_PATCH, FREE_CODE_OFF_1ST_302, sizeof(PRC_ID_SND_302) >> 2, PRC_ID_SND_302}, // Send process id code.
{ ATM_GEN_PATCH, FREE_CODE_OFF_1ST_302 + sizeof(PRC_ID_SND_302), // Branch back and skip 1 instruction.
_B(FREE_CODE_OFF_1ST_302 + sizeof(PRC_ID_SND_302), ID_SND_OFF_302 + sizeof(u32)), NULL},
{ ATM_ARR_PATCH, FREE_CODE_OFF_1ST_302, sizeof(PRC_ID_SND_300) >> 2, PRC_ID_SND_300}, // Send process id code.
{ ATM_GEN_PATCH, FREE_CODE_OFF_1ST_302 + sizeof(PRC_ID_SND_300), // Branch back and skip 1 instruction.
_B(FREE_CODE_OFF_1ST_302 + sizeof(PRC_ID_SND_300), ID_SND_OFF_302 + sizeof(u32)), NULL},
{ ATM_GEN_PATCH, ID_RCV_OFF_302, _B(ID_RCV_OFF_302, FREE_CODE_OFF_2ND_302), NULL}, // Receive process id branch.
{ ATM_ARR_PATCH, FREE_CODE_OFF_2ND_302, sizeof(PRC_ID_RCV_302) >> 2, PRC_ID_RCV_302}, // Receive process id code.
{ ATM_GEN_PATCH, FREE_CODE_OFF_2ND_302 + sizeof(PRC_ID_RCV_302), // Branch back and skip 1 instruction.
_B(FREE_CODE_OFF_2ND_302 + sizeof(PRC_ID_RCV_302), ID_RCV_OFF_302 + sizeof(u32)), NULL}
{ ATM_ARR_PATCH, FREE_CODE_OFF_2ND_302, sizeof(PRC_ID_RCV_300) >> 2, PRC_ID_RCV_300}, // Receive process id code.
{ ATM_GEN_PATCH, FREE_CODE_OFF_2ND_302 + sizeof(PRC_ID_RCV_300), // Branch back and skip 1 instruction.
_B(FREE_CODE_OFF_2ND_302 + sizeof(PRC_ID_RCV_300), ID_RCV_OFF_302 + sizeof(u32)), NULL}
);
KERNEL_PATCHSET_DEF(_kernel_4_patchset,
@@ -278,17 +273,33 @@ KERNEL_PATCHSET_DEF(_kernel_7_patchset,
_B(FREE_CODE_OFF_2ND_700 + sizeof(PRC_ID_RCV_700), ID_RCV_OFF_700 + sizeof(u32) * 4), NULL}
);
KERNEL_PATCHSET_DEF(_kernel_8_patchset,
{ SVC_GENERIC, 0x3FAD0, _NOP(), NULL }, // Allow same process on svcControlCodeMemory.
{ SVC_VERIFY_DS, 0x4D15C, _NOP(), NULL }, // Disable SVC verifications
{ DEBUG_MODE_EN, 0x5BFAC, _MOVZX(8, 1, 0), NULL }, // Enable Debug Patch
// Atmosphère kernel patches.
{ ATM_GEN_PATCH, ID_SND_OFF_800, _B(ID_SND_OFF_800, FREE_CODE_OFF_1ST_800), NULL}, // Send process id branch.
{ ATM_ARR_PATCH, FREE_CODE_OFF_1ST_800, sizeof(PRC_ID_RCV_700) >> 2, PRC_ID_RCV_700}, // Send process id code.
{ ATM_GEN_PATCH, FREE_CODE_OFF_1ST_800 + sizeof(PRC_ID_RCV_700), // Branch back and skip 4 instructions.
_B(FREE_CODE_OFF_1ST_800 + sizeof(PRC_ID_RCV_700), ID_SND_OFF_800 + sizeof(u32) * 4), NULL},
{ ATM_GEN_PATCH, ID_RCV_OFF_800, _B(ID_RCV_OFF_800, FREE_CODE_OFF_2ND_800), NULL}, // Receive process id branch.
{ ATM_ARR_PATCH, FREE_CODE_OFF_2ND_800, sizeof(PRC_ID_RCV_700) >> 2, PRC_ID_RCV_700}, // Receive process id code.
{ ATM_GEN_PATCH, FREE_CODE_OFF_2ND_800 + sizeof(PRC_ID_RCV_700), // Branch back and skip 4 instructions.
_B(FREE_CODE_OFF_2ND_800 + sizeof(PRC_ID_RCV_700), ID_RCV_OFF_800 + sizeof(u32) * 4), NULL}
);
// Kernel sha256 hashes.
static const pkg2_kernel_id_t _pkg2_kernel_ids[] =
{
{ 0x427f2647, _kernel_1_patchset }, //1.0.0
{ 0xae19cf1b, _kernel_2_patchset }, //2.0.0 - 2.3.0
{ 0x73c9e274, _kernel_3_patchset }, //3.0.0 - 3.0.1
{ 0xe0e8cdc4, _kernel_302_patchset }, //3.0.2
{ 0x485d0157, _kernel_4_patchset }, //4.0.0 - 4.1.0
{ 0xf3c363f2, _kernel_5_patchset }, //5.0.0 - 5.1.0
{ 0x64ce1a44, _kernel_6_patchset }, //6.0.0 - 6.2.0
{ 0x908175e1, _kernel_7_patchset }, //7.0.0
{ 0, 0 } //End.
{ "\xb8\xc5\x0c\x68\x25\xa9\xb9\x5b", _kernel_1_patchset }, //1.0.0
{ "\x64\x0b\x51\xff\x28\x01\xb8\x30", _kernel_2_patchset }, //2.0.0 - 2.3.0
{ "\x50\x84\x23\xac\x6f\xa1\x5d\x3b", _kernel_3_patchset }, //3.0.0 - 3.0.1
{ "\x81\x9d\x08\xbe\xe4\x5e\x1f\xbb", _kernel_302_patchset }, //3.0.2
{ "\xe6\xc0\xb7\xe3\x2f\xf9\x44\x51", _kernel_4_patchset }, //4.0.0 - 4.1.0
{ "\xb2\x38\x61\xa8\xe1\xe2\xe4\xe4", _kernel_5_patchset }, //5.0.0 - 5.1.0
{ "\x85\x97\x40\xf6\xc0\x3e\x3d\x44", _kernel_6_patchset }, //6.0.0 - 6.2.0
{ "\xa2\x5e\x47\x0c\x8e\x6d\x2f\xd7", _kernel_7_patchset }, //7.0.0
{ "\xf1\x5e\xc8\x34\xfd\x68\xf0\xf0", _kernel_8_patchset } //8.0.0. Kernel only.
};
enum kip_offset_section
@@ -539,39 +550,83 @@ static kip1_patchset_t _fs_patches_700_exfat[] =
{ NULL, NULL }
};
static kip1_patch_t _fs_nosigchk_800[] =
{
{ KPS(KIP_TEXT) | 0x7630C, 4, "\x51\x44\x00\x94", "\xE0\x03\x1F\x2A" },
{ KPS(KIP_TEXT) | 0xF49A4, 4, "\xC0\x03\x00\x36", "\x1F\x20\x03\xD5" },
{ 0, 0, NULL, NULL }
};
static kip1_patch_t _fs_nosigchk_800_exfat[] =
{
{ KPS(KIP_TEXT) | 0x818BC, 4, "\x51\x44\x00\x94", "\xE0\x03\x1F\x2A" },
{ KPS(KIP_TEXT) | 0xFFF54, 4, "\xC0\x03\x00\x36", "\x1F\x20\x03\xD5" },
{ 0, 0, NULL, NULL }
};
static kip1_patch_t _fs_nogc_800[] =
{
{ KPS(KIP_TEXT) | 0x136800, 8, "\xF4\x4F\xBE\xA9\xFD\x7B\x01\xA9", "\xE0\x03\x1F\x2A\xC0\x03\x5F\xD6" },
{ KPS(KIP_TEXT) | 0x15EB94, 4, "\x14\x40\x80\x52", "\x14\x80\x80\x52" },
{ 0, 0, NULL, NULL }
};
static kip1_patch_t _fs_nogc_800_exfat[] =
{
{ KPS(KIP_TEXT) | 0x141DB0, 8, "\xF4\x4F\xBE\xA9\xFD\x7B\x01\xA9", "\xE0\x03\x1F\x2A\xC0\x03\x5F\xD6" },
{ KPS(KIP_TEXT) | 0x16A144, 4, "\x14\x40\x80\x52", "\x14\x80\x80\x52" },
{ 0, 0, NULL, NULL }
};
static kip1_patchset_t _fs_patches_800[] =
{
{ "nosigchk", _fs_nosigchk_800 },
{ "nogc", _fs_nogc_800 },
{ NULL, NULL }
};
static kip1_patchset_t _fs_patches_800_exfat[] =
{
{ "nosigchk", _fs_nosigchk_800_exfat },
{ "nogc", _fs_nogc_800_exfat },
{ NULL, NULL }
};
// SHA256 hashes.
static kip1_id_t _kip_ids[] =
{
{ "FS", "\xde\x9f\xdd\xa4\x08\x5d\xd5\xfe\x68\xdc\xb2\x0b\x41\x09\x5b\xb4", _fs_patches_100 }, // FS 1.0.0
{ "FS", "\xfc\x3e\x80\x99\x1d\xca\x17\x96\x4a\x12\x1f\x04\xb6\x1b\x17\x5e", _fs_patches_100 }, // FS 1.0.0 exfat
{ "FS", "\xcd\x7b\xbe\x18\xd6\x13\x0b\x28\xf6\x2f\x19\xfa\x79\x45\x53\x5b", _fs_patches_200 }, // FS 2.0.0
{ "FS", "\xe7\x66\x92\xdf\xaa\x04\x20\xe9\xfd\xd6\x8e\x43\x63\x16\x18\x18", _fs_patches_200 }, // FS 2.0.0 exfat
{ "FS", "\x0d\x70\x05\x62\x7b\x07\x76\x7c\x0b\x96\x3f\x9a\xff\xdd\xe5\x66", _fs_patches_210 }, // FS 2.1.0
{ "FS", "\xdb\xd8\x5f\xca\xcc\x19\x3d\xa8\x30\x51\xc6\x64\xe6\x45\x2d\x32", _fs_patches_210 }, // FS 2.1.0 exfat
{ "FS", "\xa8\x6d\xa5\xe8\x7e\xf1\x09\x7b\x23\xda\xb5\xb4\xdb\xba\xef\xe7", _fs_patches_300 }, // FS 3.0.0
{ "FS", "\x98\x1c\x57\xe7\xf0\x2f\x70\xf7\xbc\xde\x75\x31\x81\xd9\x01\xa6", _fs_patches_300 }, // FS 3.0.0 exfat
{ "FS", "\x57\x39\x7c\x06\x3f\x10\xb6\x31\x3f\x4d\x83\x76\x53\xcc\xc3\x71", _fs_patches_30x }, // FS 3.0.1
{ "FS", "\x07\x30\x99\xd7\xc6\xad\x7d\x89\x83\xbc\x7a\xdd\x93\x2b\xe3\xd1", _fs_patches_30x }, // FS 3.0.1 exfat
{ "FS", "\x06\xe9\x07\x19\x59\x5a\x01\x0c\x62\x46\xff\x70\x94\x6f\x10\xfb", _fs_patches_40x }, // FS 4.0.1
{ "FS", "\x54\x9b\x0f\x8d\x6f\x72\xc4\xe9\xf3\xfd\x1f\x19\xea\xce\x4a\x5a", _fs_patches_40x }, // FS 4.0.1 exfat
{ "FS", "\x80\x96\xaf\x7c\x6a\x35\xaa\x82\x71\xf3\x91\x69\x95\x41\x3b\x0b", _fs_patches_410 }, // FS 4.1.0
{ "FS", "\x02\xd5\xab\xaa\xfd\x20\xc8\xb0\x63\x3a\xa0\xdb\xae\xe0\x37\x7e", _fs_patches_410 }, // FS 4.1.0 exfat
{ "FS", "\xa6\xf2\x7a\xd9\xac\x7c\x73\xad\x41\x9b\x63\xb2\x3e\x78\x5a\x0c", _fs_patches_50x }, // FS 5.0.0
{ "FS", "\xce\x3e\xcb\xa2\xf2\xf0\x62\xf5\x75\xf8\xf3\x60\x84\x2b\x32\xb4", _fs_patches_50x }, // FS 5.0.0 exfat
{ "FS", "\x76\xf8\x74\x02\xc9\x38\x7c\x0f\x0a\x2f\xab\x1b\x45\xce\xbb\x93", _fs_patches_510 }, // FS 5.1.0
{ "FS", "\x10\xb2\xd8\x16\x05\x48\x85\x99\xdf\x22\x42\xcb\x6b\xac\x2d\xf1", _fs_patches_510 }, // FS 5.1.0 exfat
{ "FS", "\x1b\x82\xcb\x22\x18\x67\xcb\x52\xc4\x4a\x86\x9e\xa9\x1a\x1a\xdd", _fs_patches_600 }, // FS 6.0.0-4.0
{ "FS", "\x96\x6a\xdd\x3d\x20\xb6\x27\x13\x2c\x5a\x8d\xa4\x9a\xc9\xd8\xdd", _fs_patches_600_exfat }, // FS 6.0.0-4.0 exfat
{ "FS", "\x3a\x57\x4d\x43\x61\x86\x19\x1d\x17\x88\xeb\x2c\x0f\x07\x6b\x11", _fs_patches_600 }, // FS 6.0.0-5.0
{ "FS", "\x33\x05\x53\xf6\xb5\xfb\x55\xc4\xc2\xd7\xb7\x36\x24\x02\x76\xb3", _fs_patches_600_exfat }, // FS 6.0.0-5.0 exfat
{ "FS", "\x2A\xDB\xE9\x7E\x9B\x5F\x41\x77\x9E\xC9\x5F\xFE\x26\x99\xC9\x33", _fs_patches_700 }, // FS 7.0.0
{ "FS", "\x2C\xCE\x65\x9C\xEC\x53\x6A\x8E\x4D\x91\xF3\xBE\x4B\x74\xBE\xD3", _fs_patches_700_exfat } // FS 7.0.0 exfat
{ "FS", "\xde\x9f\xdd\xa4\x08\x5d\xd5\xfe", _fs_patches_100 }, // FS 1.0.0
{ "FS", "\xfc\x3e\x80\x99\x1d\xca\x17\x96", _fs_patches_100 }, // FS 1.0.0 exfat
{ "FS", "\xcd\x7b\xbe\x18\xd6\x13\x0b\x28", _fs_patches_200 }, // FS 2.0.0
{ "FS", "\xe7\x66\x92\xdf\xaa\x04\x20\xe9", _fs_patches_200 }, // FS 2.0.0 exfat
{ "FS", "\x0d\x70\x05\x62\x7b\x07\x76\x7c", _fs_patches_210 }, // FS 2.1.0
{ "FS", "\xdb\xd8\x5f\xca\xcc\x19\x3d\xa8", _fs_patches_210 }, // FS 2.1.0 exfat
{ "FS", "\xa8\x6d\xa5\xe8\x7e\xf1\x09\x7b", _fs_patches_300 }, // FS 3.0.0
{ "FS", "\x98\x1c\x57\xe7\xf0\x2f\x70\xf7", _fs_patches_300 }, // FS 3.0.0 exfat
{ "FS", "\x57\x39\x7c\x06\x3f\x10\xb6\x31", _fs_patches_30x }, // FS 3.0.1
{ "FS", "\x07\x30\x99\xd7\xc6\xad\x7d\x89", _fs_patches_30x }, // FS 3.0.1 exfat
{ "FS", "\x06\xe9\x07\x19\x59\x5a\x01\x0c", _fs_patches_40x }, // FS 4.0.1
{ "FS", "\x54\x9b\x0f\x8d\x6f\x72\xc4\xe9", _fs_patches_40x }, // FS 4.0.1 exfat
{ "FS", "\x80\x96\xaf\x7c\x6a\x35\xaa\x82", _fs_patches_410 }, // FS 4.1.0
{ "FS", "\x02\xd5\xab\xaa\xfd\x20\xc8\xb0", _fs_patches_410 }, // FS 4.1.0 exfat
{ "FS", "\xa6\xf2\x7a\xd9\xac\x7c\x73\xad", _fs_patches_50x }, // FS 5.0.0
{ "FS", "\xce\x3e\xcb\xa2\xf2\xf0\x62\xf5", _fs_patches_50x }, // FS 5.0.0 exfat
{ "FS", "\x76\xf8\x74\x02\xc9\x38\x7c\x0f", _fs_patches_510 }, // FS 5.1.0
{ "FS", "\x10\xb2\xd8\x16\x05\x48\x85\x99", _fs_patches_510 }, // FS 5.1.0 exfat
{ "FS", "\x1b\x82\xcb\x22\x18\x67\xcb\x52", _fs_patches_600 }, // FS 6.0.0-4.0
{ "FS", "\x96\x6a\xdd\x3d\x20\xb6\x27\x13", _fs_patches_600_exfat }, // FS 6.0.0-4.0 exfat
{ "FS", "\x3a\x57\x4d\x43\x61\x86\x19\x1d", _fs_patches_600 }, // FS 6.0.0-5.0
{ "FS", "\x33\x05\x53\xf6\xb5\xfb\x55\xc4", _fs_patches_600_exfat }, // FS 6.0.0-5.0 exfat
{ "FS", "\x2A\xDB\xE9\x7E\x9B\x5F\x41\x77", _fs_patches_700 }, // FS 7.0.0
{ "FS", "\x2C\xCE\x65\x9C\xEC\x53\x6A\x8E", _fs_patches_700_exfat }, // FS 7.0.0 exfat
{ "FS", "\xB2\xF5\x17\x6B\x35\x48\x36\x4D", _fs_patches_800 }, // FS 8.0.0
{ "FS", "\xDB\xD9\x41\xC0\xC5\x3C\x52\xCC", _fs_patches_800_exfat } // FS 8.0.0 exfat
};
const pkg2_kernel_id_t *pkg2_identify(u32 id)
const pkg2_kernel_id_t *pkg2_identify(u8 *hash)
{
for (u32 i = 0; _pkg2_kernel_ids[i].crc32c_id; i++)
if (id == _pkg2_kernel_ids[i].crc32c_id)
for (u32 i = 0; sizeof(_pkg2_kernel_ids) / sizeof(pkg2_kernel_id_t); i++)
if (!memcmp(hash, _pkg2_kernel_ids[i].hash, sizeof(_pkg2_kernel_ids[0].hash)))
return &_pkg2_kernel_ids[i];
return NULL;
}
@@ -584,9 +639,19 @@ static u32 _pkg2_calc_kip1_size(pkg2_kip1_t *kip1)
return size;
}
void pkg2_parse_kips(link_t *info, pkg2_hdr_t *pkg2)
void pkg2_parse_kips(link_t *info, pkg2_hdr_t *pkg2, bool *new_pkg2)
{
u8 *ptr = pkg2->data + pkg2->sec_size[PKG2_SEC_KERNEL];
u8 *ptr;
// Check for new pkg2 type.
if (!pkg2->sec_size[PKG2_SEC_INI1])
{
u32 kernel_ini1_off = *(u32 *)(pkg2->data + PKG2_NEWKERN_INI1_START);
ptr = pkg2->data + kernel_ini1_off;
*new_pkg2 = true;
}
else
ptr = pkg2->data + pkg2->sec_size[PKG2_SEC_KERNEL];
pkg2_ini1_t *ini1 = (pkg2_ini1_t *)ptr;
ptr += sizeof(pkg2_ini1_t);
@@ -680,10 +745,10 @@ int pkg2_decompress_kip(pkg2_kip1_info_t* ki, u32 sectsToDecomp)
unsigned int compSize = hdr.sections[sectIdx].size_comp;
unsigned int outputSize = hdr.sections[sectIdx].size_decomp;
gfx_printf(&gfx_con, "Decomping %s KIP1 sect %d of size %d...\n", (const char*)hdr.name, sectIdx, compSize);
gfx_printf("Decomping %s KIP1 sect %d of size %d...\n", (const char*)hdr.name, sectIdx, compSize);
if (blz_uncompress_srcdest(srcDataPtr, compSize, dstDataPtr, outputSize) == 0)
{
gfx_printf(&gfx_con, "%kERROR decomping sect %d of %s KIP!%k\n", 0xFFFF0000, sectIdx, (char*)hdr.name, 0xFFCCCCCC);
gfx_printf("%kERROR decomping sect %d of %s KIP!%k\n", 0xFFFF0000, sectIdx, (char*)hdr.name, 0xFFCCCCCC);
free(newKip);
return 1;
@@ -713,7 +778,7 @@ const char* pkg2_patch_kips(link_t *info, char* patchNames)
if (patchNames == NULL || patchNames[0] == 0)
return NULL;
static const u32 MAX_NUM_PATCHES_REQUESTED = sizeof(u32)*8;
static const u32 MAX_NUM_PATCHES_REQUESTED = sizeof(u32) * 8;
char* patches[MAX_NUM_PATCHES_REQUESTED];
u32 numPatches = 1;
@@ -844,7 +909,7 @@ const char* pkg2_patch_kips(link_t *info, char* patchNames)
u32 appliedMask = 1u << currEnabIdx;
if (currPatchset->patches == NULL)
{
gfx_printf(&gfx_con, "Patch '%s' not necessary for %s KIP1\n", currPatchset->name, (const char*)ki->kip1->name);
gfx_printf("Patch '%s' not necessary for %s KIP1\n", currPatchset->name, (const char*)ki->kip1->name);
patchesApplied |= appliedMask;
break;
}
@@ -854,7 +919,7 @@ const char* pkg2_patch_kips(link_t *info, char* patchNames)
{
if (bitsAffected & (1u << currSectIdx))
{
gfx_printf(&gfx_con, "Applying patch '%s' on %s KIP1 sect %d\n", currPatchset->name, (const char*)ki->kip1->name, currSectIdx);
gfx_printf("Applying patch '%s' on %s KIP1 sect %d\n", currPatchset->name, (const char*)ki->kip1->name, currSectIdx);
for (const kip1_patch_t* currPatch=currPatchset->patches;currPatch != NULL && currPatch->length != 0; currPatch++)
{
if (GET_KIP_PATCH_SECTION(currPatch->offset) != currSectIdx)
@@ -863,7 +928,7 @@ const char* pkg2_patch_kips(link_t *info, char* patchNames)
u32 currOffset = GET_KIP_PATCH_OFFSET(currPatch->offset);
if (memcmp(&kipSectData[currOffset], currPatch->srcData, currPatch->length) != 0)
{
gfx_printf(&gfx_con, "%kDATA MISMATCH FOR PATCH AT OFFSET 0x%x!!!%k\n", 0xFFFF0000, currOffset, 0xFFCCCCCC);
gfx_printf("%kDATA MISMATCH FOR PATCH AT OFFSET 0x%x!!!%k\n", 0xFFFF0000, currOffset, 0xFFCCCCCC);
return currPatchset->name; // MUST stop here as kip is likely corrupt.
}
else
@@ -907,7 +972,7 @@ pkg2_hdr_t *pkg2_decrypt(void *data)
// Decrypt header.
se_aes_crypt_ctr(8, hdr, sizeof(pkg2_hdr_t), hdr, sizeof(pkg2_hdr_t), hdr);
//gfx_hexdump(&gfx_con, (u32)hdr, hdr, 0x100);
//gfx_hexdump((u32)hdr, hdr, 0x100);
if (hdr->magic != PKG2_MAGIC)
return NULL;
@@ -919,7 +984,7 @@ DPRINTF("sec %d has size %08X\n", i, hdr->sec_size[i]);
continue;
se_aes_crypt_ctr(8, pdata, hdr->sec_size[i], pdata, hdr->sec_size[i], &hdr->sec_ctr[i * 0x10]);
//gfx_hexdump(&gfx_con, (u32)pdata, pdata, 0x100);
//gfx_hexdump((u32)pdata, pdata, 0x100);
pdata += hdr->sec_size[i];
}
@@ -927,31 +992,8 @@ DPRINTF("sec %d has size %08X\n", i, hdr->sec_size[i]);
return hdr;
}
void pkg2_build_encrypt(void *dst, void *kernel, u32 kernel_size, link_t *kips_info)
static u32 _pkg2_ini1_build(u8 *pdst, pkg2_hdr_t *hdr, link_t *kips_info, bool new_pkg2)
{
u8 *pdst = (u8 *)dst;
// Signature.
memset(pdst, 0, 0x100);
pdst += 0x100;
// Header.
pkg2_hdr_t *hdr = (pkg2_hdr_t *)pdst;
memset(hdr, 0, sizeof(pkg2_hdr_t));
pdst += sizeof(pkg2_hdr_t);
hdr->magic = PKG2_MAGIC;
hdr->base = 0x10000000;
DPRINTF("kernel @ %08X (%08X)\n", (u32)kernel, kernel_size);
// Kernel.
memcpy(pdst, kernel, kernel_size);
hdr->sec_size[PKG2_SEC_KERNEL] = kernel_size;
hdr->sec_off[PKG2_SEC_KERNEL] = 0x10000000;
se_aes_crypt_ctr(8, pdst, kernel_size, pdst, kernel_size, &hdr->sec_ctr[PKG2_SEC_KERNEL * 0x10]);
pdst += kernel_size;
DPRINTF("kernel encrypted\n");
// INI1.
u32 ini1_size = sizeof(pkg2_ini1_t);
pkg2_ini1_t *ini1 = (pkg2_ini1_t *)pdst;
memset(ini1, 0, sizeof(pkg2_ini1_t));
@@ -966,9 +1008,60 @@ DPRINTF("adding kip1 '%s' @ %08X (%08X)\n", ki->kip1->name, (u32)ki->kip1, ki->s
ini1->num_procs++;
}
ini1->size = ini1_size;
hdr->sec_size[PKG2_SEC_INI1] = ini1_size;
hdr->sec_off[PKG2_SEC_INI1] = 0x14080000;
se_aes_crypt_ctr(8, ini1, ini1_size, ini1, ini1_size, &hdr->sec_ctr[PKG2_SEC_INI1 * 0x10]);
if (!new_pkg2)
{
hdr->sec_size[PKG2_SEC_INI1] = ini1_size;
hdr->sec_off[PKG2_SEC_INI1] = 0x14080000;
se_aes_crypt_ctr(8, ini1, ini1_size, ini1, ini1_size, &hdr->sec_ctr[PKG2_SEC_INI1 * 0x10]);
}
else
{
hdr->sec_size[PKG2_SEC_INI1] = 0;
hdr->sec_off[PKG2_SEC_INI1] = 0;
}
return ini1_size;
}
void pkg2_build_encrypt(void *dst, void *kernel, u32 kernel_size, link_t *kips_info, bool new_pkg2)
{
u8 *pdst = (u8 *)dst;
// Signature.
memset(pdst, 0, 0x100);
pdst += 0x100;
// Header.
pkg2_hdr_t *hdr = (pkg2_hdr_t *)pdst;
memset(hdr, 0, sizeof(pkg2_hdr_t));
pdst += sizeof(pkg2_hdr_t);
hdr->magic = PKG2_MAGIC;
if (!new_pkg2)
hdr->base = 0x10000000;
else
hdr->base = 0x60000;
DPRINTF("kernel @ %08X (%08X)\n", (u32)kernel, kernel_size);
// Kernel.
memcpy(pdst, kernel, kernel_size);
if (!new_pkg2)
hdr->sec_off[PKG2_SEC_KERNEL] = 0x10000000;
else
{
// Set new INI1 offset to kernel.
*(u32 *)(pdst + PKG2_NEWKERN_INI1_START) = kernel_size;
kernel_size += _pkg2_ini1_build(pdst + kernel_size, hdr, kips_info, new_pkg2);
hdr->sec_off[PKG2_SEC_KERNEL] = 0x60000;
}
hdr->sec_size[PKG2_SEC_KERNEL] = kernel_size;
se_aes_crypt_ctr(8, pdst, kernel_size, pdst, kernel_size, &hdr->sec_ctr[PKG2_SEC_KERNEL * 0x10]);
pdst += kernel_size;
DPRINTF("kernel encrypted\n");
// INI1.
u32 ini1_size = 0;
if (!new_pkg2)
ini1_size = _pkg2_ini1_build(pdst, hdr, kips_info, new_pkg2);
DPRINTF("INI1 encrypted\n");
//Encrypt header.

View File

@@ -1,6 +1,6 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (C) 2018 CTCaer
* Copyright (C) 2018-2019 CTCaer
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@@ -27,6 +27,9 @@
#define PKG2_SEC_INI1 1
#define INI1_MAGIC 0x31494E49
#define PKG2_NEWKERN_INI1_START 0x168
#define PKG2_NEWKERN_INI1_END 0x170
#define PKG2_NEWKERN_START 0x800
typedef struct _kernel_patch_t
{
@@ -111,7 +114,7 @@ typedef struct _pkg2_kip1_info_t
typedef struct _pkg2_kernel_id_t
{
u32 crc32c_id;
u8 hash[8];
kernel_patch_t *kernel_patchset;
} pkg2_kernel_id_t;
@@ -132,19 +135,19 @@ typedef struct _kip1_patchset_t
typedef struct _kip1_id_t
{
const char* name;
u8 hash[16];
u8 hash[8];
kip1_patchset_t* patchset;
} kip1_id_t;
void pkg2_parse_kips(link_t *info, pkg2_hdr_t *pkg2);
void pkg2_parse_kips(link_t *info, pkg2_hdr_t *pkg2, bool *new_pkg2);
int pkg2_has_kip(link_t *info, u64 tid);
void pkg2_replace_kip(link_t *info, u64 tid, pkg2_kip1_t *kip1);
void pkg2_add_kip(link_t *info, pkg2_kip1_t *kip1);
void pkg2_merge_kip(link_t *info, pkg2_kip1_t *kip1);
const char* pkg2_patch_kips(link_t *info, char* patchNames);
const pkg2_kernel_id_t *pkg2_identify(u32 id);
const pkg2_kernel_id_t *pkg2_identify(u8 *hash);
pkg2_hdr_t *pkg2_decrypt(void *data);
void pkg2_build_encrypt(void *dst, void *kernel, u32 kernel_size, link_t *kips_info);
void pkg2_build_encrypt(void *dst, void *kernel, u32 kernel_size, link_t *kips_info, bool new_pkg2);
#endif

View File

@@ -1,5 +1,6 @@
/*
* Copyright (C) 2018-2019 CTCaer
* Copyright (c) 2018-2019 CTCaer
* Copyright (c) 2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@@ -15,13 +16,22 @@
*/
#include <string.h>
#include <stdlib.h>
#include "hos.h"
#include "../gfx/di.h"
#include "../gfx/gfx.h"
#include "../libs/fatfs/ff.h"
#include "../mem/heap.h"
#include "../soc/fuse.h"
#include "../storage/sdmmc.h"
#include "../utils/btn.h"
#include "../utils/util.h"
#include "../utils/types.h"
extern bool sd_mount();
extern int sd_save_to_file(void *buf, u32 size, const char *filename);
typedef struct _exo_cfg_t
{
vu32 magic;
@@ -36,6 +46,36 @@ typedef struct _atm_meta_t
uint32_t fwno;
} wb_cfg_t;
// Atmosphère reboot-to-fatal-error.
typedef struct _atm_fatal_error_ctx
{
u32 magic;
u32 error_desc;
u64 title_id;
union
{
u64 gprs[32];
struct
{
u64 _gprs[29];
u64 fp;
u64 lr;
u64 sp;
};
};
u64 pc;
u64 padding;
u32 pstate;
u32 afsr0;
u32 afsr1;
u32 esr;
u64 far;
u64 report_identifier; // Normally just system tick.
} atm_fatal_error_ctx;
#define ATM_FATAL_ERR_CTX_ADDR 0x4003E000
#define ATM_FATAL_MAGIC 0x30454641 // AFE0
#define ATM_WB_HEADER_OFF 0x244
#define ATM_WB_MAGIC 0x30544257
@@ -48,7 +88,7 @@ typedef struct _atm_meta_t
#define EXO_FLAG_DBG_PRIV (1 << 1)
#define EXO_FLAG_DBG_USER (1 << 2)
void config_exosphere(const char *id, u32 kb, void *warmboot, void *pkg1)
void config_exosphere(const char *id, u32 kb, void *warmboot, bool stock)
{
u32 exoFwNo = 0;
u32 exoFlags = 0;
@@ -69,14 +109,17 @@ void config_exosphere(const char *id, u32 kb, void *warmboot, void *pkg1)
break;
default:
exoFwNo = kb + 1;
if (!strcmp(id, "20190314172056"))
exoFwNo++; // ATM_TARGET_FW_800.
break;
}
if (kb == KB_FIRMWARE_VERSION_620)
exoFlags |= EXO_FLAG_620_KGN;
// To avoid problems, make private debug mode always on.
exoFlags |= EXO_FLAG_DBG_PRIV;
// To avoid problems, make private debug mode always on if not semi-stock.
if (!stock)
exoFlags |= EXO_FLAG_DBG_PRIV;
// Set mailbox values.
exo_cfg_depr->magic = EXO_MAGIC_VAL;
@@ -115,3 +158,73 @@ void config_exosphere(const char *id, u32 kb, void *warmboot, void *pkg1)
memcpy(warmboot + 0x10, rsa_mod + 0x10, 0x100);
}
}
static const char *get_error_desc(u32 error_desc)
{
switch (error_desc)
{
case 0x100:
return "Instruction Abort";
case 0x101:
return "Data Abort";
case 0x102:
return "PC Misalignment";
case 0x103:
return "SP Misalignment";
case 0x104:
return "Trap";
case 0x106:
return "SError";
case 0x301:
return "Bad SVC";
default:
return "Unknown";
}
}
void secmon_exo_check_panic()
{
volatile atm_fatal_error_ctx *rpt = (atm_fatal_error_ctx *)ATM_FATAL_ERR_CTX_ADDR;
if (rpt->magic != ATM_FATAL_MAGIC)
return;
gfx_clear_grey(0x1B);
gfx_con_setpos(0, 0);
WPRINTF("Panic occurred while running Atmosphere.\n\n");
WPRINTFARGS("Title ID: %08X%08X", (u32)((u64)rpt->title_id >> 32), (u32)rpt->title_id);
WPRINTFARGS("Error Desc: %s (0x%x)\n", get_error_desc(rpt->error_desc), rpt->error_desc);
if (sd_mount())
{
// Save context to the SD card.
char filepath[0x40];
f_mkdir("atmosphere/fatal_errors");
memcpy(filepath, "/atmosphere/fatal_errors/report_", 33);
itoa((u32)((u64)rpt->report_identifier >> 32), filepath + strlen(filepath), 16);
itoa((u32)(rpt->report_identifier), filepath + strlen(filepath), 16);
memcpy(filepath + strlen(filepath), ".bin", 5);
sd_save_to_file((void *)rpt, sizeof(atm_fatal_error_ctx), filepath);
gfx_con.fntsz = 8;
WPRINTFARGS("Report saved to %s\n", filepath);
}
// Change magic to invalid, to prevent double-display of error/bootlooping.
rpt->magic = 0x0;
gfx_con.fntsz = 16;
gfx_printf("\n\nPress POWER to continue.\n");
display_backlight_brightness(100, 1000);
msleep(1000);
u32 btn = btn_wait();
while (!(btn & BTN_POWER))
btn = btn_wait();
display_backlight_brightness(0, 1000);
gfx_con_setpos(0, 0);
}

View File

@@ -19,6 +19,7 @@
#include "../utils/types.h"
void config_exosphere(const char *id, u32 kb, void *warmboot, void *pkg1);
void config_exosphere(const char *id, u32 kb, void *warmboot, bool stock);
void secmon_exo_check_panic();
#endif

View File

@@ -29,7 +29,7 @@
extern heap_t _heap;
extern void *sd_file_read(char *path);
extern void *sd_file_read(const char *path, u32 *fsize);
extern bool sd_mount();
extern void sd_unmount();
@@ -70,19 +70,19 @@ void ianos_print_error(int errorno)
switch (errorno)
{
case 1:
gfx_printf(&gfx_con, "Can't find library!\n");
gfx_printf("Can't find library!\n");
break;
case 2:
gfx_printf(&gfx_con, "Cant init ELF context!\n");
gfx_printf("Cant init ELF context!\n");
break;
case 3:
gfx_printf(&gfx_con, "Cant alloc memory!\n");
gfx_printf("Cant alloc memory!\n");
break;
case 4:
gfx_printf(&gfx_con, "Error loading ELF!\n");
gfx_printf("Error loading ELF!\n");
break;
case 5:
gfx_printf(&gfx_con, "Error relocating ELF!\n");
gfx_printf("Error relocating ELF!\n");
break;
}
}
@@ -101,7 +101,7 @@ int ianos_loader(bool sdmount, char *path, elfType_t type, void *moduleConfig)
}
}
fileBuf = sd_file_read(path);
fileBuf = sd_file_read(path, NULL);
if (sdmount)
sd_unmount();

View File

@@ -27,7 +27,7 @@
#ifdef DEBUG
#include "../../gfx/gfx.h"
#define EL_DEBUG(format, ...) \
gfx_printf(&gfx_con, format __VA_OPT__(, ) __VA_ARGS__)
gfx_printf(format __VA_OPT__(, ) __VA_ARGS__)
#else
#define EL_DEBUG(...) \
do \

View File

@@ -12,9 +12,13 @@
#include "../../storage/sdmmc.h"
#define SDMMC_UPPER_BUFFER 0xB8000000
#define DRAM_START 0x80000000
extern sdmmc_storage_t sd_storage;
/*-----------------------------------------------------------------------*/
/* Get Drive Status */
/*-----------------------------------------------------------------------*/
DSTATUS disk_status (
BYTE pdrv /* Physical drive nmuber to identify the drive */
)
@@ -22,6 +26,9 @@ DSTATUS disk_status (
return 0;
}
/*-----------------------------------------------------------------------*/
/* Inidialize a Drive */
/*-----------------------------------------------------------------------*/
DSTATUS disk_initialize (
BYTE pdrv /* Physical drive nmuber to identify the drive */
)
@@ -29,6 +36,9 @@ DSTATUS disk_initialize (
return 0;
}
/*-----------------------------------------------------------------------*/
/* Read Sector(s) */
/*-----------------------------------------------------------------------*/
DRESULT disk_read (
BYTE pdrv, /* Physical drive nmuber to identify the drive */
BYTE *buff, /* Data buffer to store read data */
@@ -36,9 +46,9 @@ DRESULT disk_read (
UINT count /* Number of sectors to read */
)
{
if ((u32)buff >= 0x90000000)
if ((u32)buff >= DRAM_START)
return sdmmc_storage_read(&sd_storage, sector, count, buff) ? RES_OK : RES_ERROR;
u8 *buf = (u8 *)SDMMC_UPPER_BUFFER; //TODO: define this somewhere.
u8 *buf = (u8 *)SDMMC_UPPER_BUFFER;
if (sdmmc_storage_read(&sd_storage, sector, count, buf))
{
memcpy(buff, buf, 512 * count);
@@ -47,6 +57,9 @@ DRESULT disk_read (
return RES_ERROR;
}
/*-----------------------------------------------------------------------*/
/* Write Sector(s) */
/*-----------------------------------------------------------------------*/
DRESULT disk_write (
BYTE pdrv, /* Physical drive nmuber to identify the drive */
const BYTE *buff, /* Data to be written */
@@ -54,7 +67,7 @@ DRESULT disk_write (
UINT count /* Number of sectors to write */
)
{
if ((u32)buff >= 0x90000000)
if ((u32)buff >= DRAM_START)
return sdmmc_storage_write(&sd_storage, sector, count, (void *)buff) ? RES_OK : RES_ERROR;
u8 *buf = (u8 *)SDMMC_UPPER_BUFFER; //TODO: define this somewhere.
memcpy(buf, buff, 512 * count);
@@ -63,6 +76,9 @@ DRESULT disk_write (
return RES_ERROR;
}
/*-----------------------------------------------------------------------*/
/* Miscellaneous Functions */
/*-----------------------------------------------------------------------*/
DRESULT disk_ioctl (
BYTE pdrv, /* Physical drive nmuber (0..) */
BYTE cmd, /* Control code */

View File

@@ -11,7 +11,6 @@ extern "C" {
#include "../../utils/types.h"
/* Status of Disk Functions */
typedef BYTE DSTATUS;
@@ -46,11 +45,11 @@ DRESULT disk_ioctl (BYTE pdrv, BYTE cmd, void* buff);
/* Command code for disk_ioctrl fucntion */
/* Generic command (Used by FatFs) */
#define CTRL_SYNC 0 /* Complete pending write process (needed at _FS_READONLY == 0) */
#define GET_SECTOR_COUNT 1 /* Get media size (needed at _USE_MKFS == 1) */
#define GET_SECTOR_SIZE 2 /* Get sector size (needed at _MAX_SS != _MIN_SS) */
#define GET_BLOCK_SIZE 3 /* Get erase block size (needed at _USE_MKFS == 1) */
#define CTRL_TRIM 4 /* Inform device that the data on the block of sectors is no longer used (needed at _USE_TRIM == 1) */
#define CTRL_SYNC 0 /* Complete pending write process (needed at FF_FS_READONLY == 0) */
#define GET_SECTOR_COUNT 1 /* Get media size (needed at FF_USE_MKFS == 1) */
#define GET_SECTOR_SIZE 2 /* Get sector size (needed at FF_MAX_SS != FF_MIN_SS) */
#define GET_BLOCK_SIZE 3 /* Get erase block size (needed at FF_USE_MKFS == 1) */
#define CTRL_TRIM 4 /* Inform device that the data on the block of sectors is no longer used (needed at FF_USE_TRIM == 1) */
/* Generic command (Not used by FatFs) */
#define CTRL_POWER 5 /* Get/Set power status */

View File

@@ -1,10 +1,10 @@
/*----------------------------------------------------------------------------/
/ FatFs - Generic FAT Filesystem Module R0.13b /
/ FatFs - Generic FAT Filesystem Module R0.13c (p3) /
/-----------------------------------------------------------------------------/
/
/ Copyright (C) 2018, ChaN, all right reserved.
/ Copyright (c) 2018 naehrwert
/ Copyright (C) 2018 CTCaer
/ Copyright (C) 2018-2019 CTCaer
/
/ FatFs module is an open source software. Redistribution and use of FatFs in
/ source and binary forms, with or without modification, are permitted provided
@@ -25,7 +25,7 @@
#include "diskio.h" /* Declarations of device I/O functions */
#include "../../gfx/gfx.h"
#define EFSPRINTF(text, ...) print_error(); gfx_printf(&gfx_con, "%k"text"%k\n", 0xFFFFFF00, 0xFFFFFFFF);
#define EFSPRINTF(text, ...) print_error(); gfx_printf("%k"text"%k\n", 0xFFFFFF00, 0xFFFFFFFF);
//#define EFSPRINTF(...)
/*--------------------------------------------------------------------------
@@ -34,11 +34,20 @@
---------------------------------------------------------------------------*/
#if FF_DEFINED != 63463 /* Revision ID */
#if FF_DEFINED != 86604 /* Revision ID */
#error Wrong include file (ff.h).
#endif
/* Limits and boundaries */
#define MAX_DIR 0x200000 /* Max size of FAT directory */
#define MAX_DIR_EX 0x10000000 /* Max size of exFAT directory */
#define MAX_FAT12 0xFF5 /* Max FAT12 clusters (differs from specs, but right for real DOS/Windows behavior) */
#define MAX_FAT16 0xFFF5 /* Max FAT16 clusters (differs from specs, but right for real DOS/Windows behavior) */
#define MAX_FAT32 0x0FFFFFF5 /* Max FAT32 clusters (not specified, practical limit) */
#define MAX_EXFAT 0x7FFFFFFD /* Max exFAT clusters (differs from specs, implementation limit) */
/* Character code support macros */
#define IsUpper(c) ((c) >= 'A' && (c) <= 'Z')
#define IsLower(c) ((c) >= 'a' && (c) <= 'z')
@@ -48,18 +57,18 @@
#define IsSurrogateL(c) ((c) >= 0xDC00 && (c) <= 0xDFFF)
/* Additional file attribute bits for internal use */
#define AM_VOL 0x08 /* Volume label */
#define AM_LFN 0x0F /* LFN entry */
#define AM_MASK 0x3F /* Mask of defined bits */
/* Additional file access control and file status flags for internal use */
#define FA_SEEKEND 0x20 /* Seek to end of the file on file open */
#define FA_MODIFIED 0x40 /* File has been modified */
#define FA_DIRTY 0x80 /* FIL.buf[] needs to be written-back */
/* Additional file attribute bits for internal use */
#define AM_VOL 0x08 /* Volume label */
#define AM_LFN 0x0F /* LFN entry */
#define AM_MASK 0x3F /* Mask of defined bits */
/* Name status flags in fn[11] */
#define NSFLAG 11 /* Index of the name status byte */
#define NS_LOSS 0x01 /* Out of 8.3 format */
@@ -72,13 +81,13 @@
#define NS_NONAME 0x80 /* Not followed */
/* Limits and boundaries */
#define MAX_DIR 0x200000 /* Max size of FAT directory */
#define MAX_DIR_EX 0x10000000 /* Max size of exFAT directory */
#define MAX_FAT12 0xFF5 /* Max FAT12 clusters (differs from specs, but right for real DOS/Windows behavior) */
#define MAX_FAT16 0xFFF5 /* Max FAT16 clusters (differs from specs, but right for real DOS/Windows behavior) */
#define MAX_FAT32 0x0FFFFFF5 /* Max FAT32 clusters (not specified, practical limit) */
#define MAX_EXFAT 0x7FFFFFFD /* Max exFAT clusters (differs from specs, implementation limit) */
/* exFAT directory entry types */
#define ET_BITMAP 0x81 /* Allocation bitmap */
#define ET_UPCASE 0x82 /* Up-case table */
#define ET_VLABEL 0x83 /* Volume label */
#define ET_FILEDIR 0x85 /* File and directory */
#define ET_STREAM 0xC0 /* Stream extension */
#define ET_FILENAME 0xC1 /* Name extension */
/* FatFs refers the FAT structure as simple byte array instead of structure member
@@ -526,6 +535,7 @@ static WCHAR LfnBuf[FF_MAX_LFN + 1]; /* LFN working buffer */
#define CODEPAGE CodePage
static WORD CodePage; /* Current code page */
static const BYTE *ExCvt, *DbcTbl; /* Pointer to current SBCS up-case table and DBCS code range table below */
static const BYTE Ct437[] = TBL_CT437;
static const BYTE Ct720[] = TBL_CT720;
static const BYTE Ct737[] = TBL_CT737;
@@ -573,7 +583,7 @@ static const BYTE DbcTbl[] = MKCVTBL(TBL_DC, FF_CODE_PAGE);
void print_error()
{
gfx_printf(&gfx_con, "\n\n\n%k[FatFS] Error: %k", 0xFFFFFF00, 0xFFFFFFFF);
gfx_printf("\n\n\n%k[FatFS] Error: %k", 0xFFFFFF00, 0xFFFFFFFF);
}
@@ -1107,7 +1117,7 @@ static FRESULT sync_fs ( /* Returns FR_OK or FR_DISK_ERR */
if (res == FR_OK) {
if (fs->fs_type == FS_FAT32 && fs->fsi_flag == 1) { /* FAT32: Update FSInfo sector if needed */
/* Create FSInfo structure */
mem_set(fs->win, 0, SS(fs));
mem_set(fs->win, 0, sizeof fs->win);
st_word(fs->win + BS_55AA, 0xAA55);
st_dword(fs->win + FSI_LeadSig, 0x41615252);
st_dword(fs->win + FSI_StrucSig, 0x61417272);
@@ -1307,7 +1317,7 @@ static DWORD find_bitmap ( /* 0:Not found, 2..:Cluster block found, 0xFFFFFFFF:D
if (clst >= fs->n_fatent - 2) clst = 0;
scl = val = clst; ctr = 0;
for (;;) {
if (move_window(fs, fs->database + val / 8 / SS(fs)) != FR_OK) return 0xFFFFFFFF; /* (assuming bitmap is located top of the cluster heap) */
if (move_window(fs, fs->bitbase + val / 8 / SS(fs)) != FR_OK) return 0xFFFFFFFF;
i = val / 8 % SS(fs); bm = 1 << (val % 8);
do {
do {
@@ -1345,9 +1355,9 @@ static FRESULT change_bitmap (
clst -= 2; /* The first bit corresponds to cluster #2 */
sect = fs->database + clst / 8 / SS(fs); /* Sector address (assuming bitmap is located top of the cluster heap) */
i = clst / 8 % SS(fs); /* Byte offset in the sector */
bm = 1 << (clst % 8); /* Bit mask in the byte */
sect = fs->bitbase + clst / 8 / SS(fs); /* Sector address */
i = clst / 8 % SS(fs); /* Byte offset in the sector */
bm = 1 << (clst % 8); /* Bit mask in the byte */
for (;;) {
if (move_window(fs, sect++) != FR_OK) return FR_DISK_ERR;
do {
@@ -1420,7 +1430,7 @@ static FRESULT fill_last_frag (
static FRESULT remove_chain ( /* FR_OK(0):succeeded, !=0:error */
FFOBJID* obj, /* Corresponding object */
DWORD clst, /* Cluster to remove a chain from */
DWORD pclst /* Previous cluster of clst (0:entire chain) */
DWORD pclst /* Previous cluster of clst (0 if entire chain) */
)
{
FRESULT res = FR_OK;
@@ -1658,7 +1668,7 @@ static FRESULT dir_clear ( /* Returns FR_OK or FR_DISK_ERR */
if (sync_window(fs) != FR_OK) return FR_DISK_ERR; /* Flush disk access window */
sect = clst2sect(fs, clst); /* Top of the cluster */
fs->winsect = sect; /* Set window to top of the cluster */
mem_set(fs->win, 0, SS(fs)); /* Clear window buffer */
mem_set(fs->win, 0, sizeof fs->win); /* Clear window buffer */
#if FF_USE_LFN == 3 /* Quick table clear by using multi-secter write */
/* Allocate a temporary buffer */
for (szb = ((DWORD)fs->csize * SS(fs) >= MAX_MALLOC) ? MAX_MALLOC : fs->csize * SS(fs), ibuf = 0; szb > SS(fs) && (ibuf = ff_memalloc(szb)) == 0; szb /= 2) ;
@@ -1888,7 +1898,7 @@ static int cmp_lfn ( /* 1:matched, 0:not matched */
for (wc = 1, s = 0; s < 13; s++) { /* Process all characters in the entry */
uc = ld_word(dir + LfnOfs[s]); /* Pick an LFN character */
if (wc != 0) {
if (i >= FF_MAX_LFN || ff_wtoupper(uc) != ff_wtoupper(lfnbuf[i++])) { /* Compare it */
if (i >= FF_MAX_LFN + 1 || ff_wtoupper(uc) != ff_wtoupper(lfnbuf[i++])) { /* Compare it */
return 0; /* Not matched */
}
wc = uc;
@@ -1924,15 +1934,15 @@ static int pick_lfn ( /* 1:succeeded, 0:buffer overflow or invalid LFN entry */
for (wc = 1, s = 0; s < 13; s++) { /* Process all characters in the entry */
uc = ld_word(dir + LfnOfs[s]); /* Pick an LFN character */
if (wc != 0) {
if (i >= FF_MAX_LFN) return 0; /* Buffer overflow? */
if (i >= FF_MAX_LFN + 1) return 0; /* Buffer overflow? */
lfnbuf[i++] = wc = uc; /* Store it */
} else {
if (uc != 0xFFFF) return 0; /* Check filler */
}
}
if (dir[LDIR_Ord] & LLEF) { /* Put terminator if it is the last LFN part */
if (i >= FF_MAX_LFN) return 0; /* Buffer overflow? */
if (dir[LDIR_Ord] & LLEF && wc != 0) { /* Put terminator if it is the last LFN part and not terminated */
if (i >= FF_MAX_LFN + 1) return 0; /* Buffer overflow? */
lfnbuf[i] = 0;
}
@@ -2168,33 +2178,33 @@ static FRESULT load_xdir ( /* FR_INT_ERR: invalid entry block */
BYTE* dirb = dp->obj.fs->dirbuf; /* Pointer to the on-memory direcotry entry block 85+C0+C1s */
/* Load 85 entry */
/* Load file-directory entry */
res = move_window(dp->obj.fs, dp->sect);
if (res != FR_OK) return res;
if (dp->dir[XDIR_Type] != 0x85) return FR_INT_ERR; /* Invalid order */
if (dp->dir[XDIR_Type] != ET_FILEDIR) return FR_INT_ERR; /* Invalid order */
mem_cpy(dirb + 0 * SZDIRE, dp->dir, SZDIRE);
sz_ent = (dirb[XDIR_NumSec] + 1) * SZDIRE;
if (sz_ent < 3 * SZDIRE || sz_ent > 19 * SZDIRE) return FR_INT_ERR;
/* Load C0 entry */
/* Load stream-extension entry */
res = dir_next(dp, 0);
if (res == FR_NO_FILE) res = FR_INT_ERR; /* It cannot be */
if (res != FR_OK) return res;
res = move_window(dp->obj.fs, dp->sect);
if (res != FR_OK) return res;
if (dp->dir[XDIR_Type] != 0xC0) return FR_INT_ERR; /* Invalid order */
if (dp->dir[XDIR_Type] != ET_STREAM) return FR_INT_ERR; /* Invalid order */
mem_cpy(dirb + 1 * SZDIRE, dp->dir, SZDIRE);
if (MAXDIRB(dirb[XDIR_NumName]) > sz_ent) return FR_INT_ERR;
/* Load C1 entries */
i = 2 * SZDIRE; /* C1 offset to load */
/* Load file-name entries */
i = 2 * SZDIRE; /* Name offset to load */
do {
res = dir_next(dp, 0);
if (res == FR_NO_FILE) res = FR_INT_ERR; /* It cannot be */
if (res != FR_OK) return res;
res = move_window(dp->obj.fs, dp->sect);
if (res != FR_OK) return res;
if (dp->dir[XDIR_Type] != 0xC1) return FR_INT_ERR; /* Invalid order */
if (dp->dir[XDIR_Type] != ET_FILENAME) return FR_INT_ERR; /* Invalid order */
if (i < MAXDIRB(FF_MAX_LFN)) mem_cpy(dirb + i, dp->dir, SZDIRE);
} while ((i += SZDIRE) < sz_ent);
@@ -2299,16 +2309,16 @@ static void create_xdir (
WCHAR wc;
/* Create 85,C0 entry */
/* Create file-directory and stream-extension entry */
mem_set(dirb, 0, 2 * SZDIRE);
dirb[0 * SZDIRE + XDIR_Type] = 0x85; /* 85 entry */
dirb[1 * SZDIRE + XDIR_Type] = 0xC0; /* C0 entry */
dirb[0 * SZDIRE + XDIR_Type] = ET_FILEDIR;
dirb[1 * SZDIRE + XDIR_Type] = ET_STREAM;
/* Create C1 entries */
i = SZDIRE * 2; /* Top of C1 entries */
/* Create file-name entries */
i = SZDIRE * 2; /* Top of file_name entries */
nlen = nc1 = 0; wc = 1;
do {
dirb[i++] = 0xC1; dirb[i++] = 0; /* Entry type C1 */
dirb[i++] = ET_FILENAME; dirb[i++] = 0;
do { /* Fill name field */
if (wc != 0 && (wc = lfn[nlen]) != 0) nlen++; /* Get a character if exist */
st_word(dirb + i, wc); /* Store it */
@@ -2332,8 +2342,8 @@ static void create_xdir (
/* Read an object from the directory */
/*-----------------------------------------------------------------------*/
#define dir_read_file(dp) dir_read(dp, 0)
#define dir_read_label(dp) dir_read(dp, 1)
#define DIR_READ_FILE(dp) dir_read(dp, 0)
#define DIR_READ_LABEL(dp) dir_read(dp, 1)
static FRESULT dir_read (
DIR* dp, /* Pointer to the directory object */
@@ -2342,7 +2352,7 @@ static FRESULT dir_read (
{
FRESULT res = FR_NO_FILE;
FATFS *fs = dp->obj.fs;
BYTE a, c;
BYTE attr, b;
#if FF_USE_LFN
BYTE ord = 0xFF, sum = 0xFF;
#endif
@@ -2350,16 +2360,16 @@ static FRESULT dir_read (
while (dp->sect) {
res = move_window(fs, dp->sect);
if (res != FR_OK) break;
c = dp->dir[DIR_Name]; /* Test for the entry type */
if (c == 0) {
b = dp->dir[DIR_Name]; /* Test for the entry type */
if (b == 0) {
res = FR_NO_FILE; break; /* Reached to end of the directory */
}
#if FF_FS_EXFAT
if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */
if (FF_USE_LABEL && vol) {
if (c == 0x83) break; /* Volume label entry? */
if (b == ET_VLABEL) break; /* Volume label entry? */
} else {
if (c == 0x85) { /* Start of the file entry block? */
if (b == ET_FILEDIR) { /* Start of the file entry block? */
dp->blk_ofs = dp->dptr; /* Get location of the block */
res = load_xdir(dp); /* Load the entry block */
if (res == FR_OK) {
@@ -2371,19 +2381,19 @@ static FRESULT dir_read (
} else
#endif
{ /* On the FAT/FAT32 volume */
dp->obj.attr = a = dp->dir[DIR_Attr] & AM_MASK; /* Get attribute */
dp->obj.attr = attr = dp->dir[DIR_Attr] & AM_MASK; /* Get attribute */
#if FF_USE_LFN /* LFN configuration */
if (c == DDEM || c == '.' || (int)((a & ~AM_ARC) == AM_VOL) != vol) { /* An entry without valid data */
if (b == DDEM || b == '.' || (int)((attr & ~AM_ARC) == AM_VOL) != vol) { /* An entry without valid data */
ord = 0xFF;
} else {
if (a == AM_LFN) { /* An LFN entry is found */
if (c & LLEF) { /* Is it start of an LFN sequence? */
if (attr == AM_LFN) { /* An LFN entry is found */
if (b & LLEF) { /* Is it start of an LFN sequence? */
sum = dp->dir[LDIR_Chksum];
c &= (BYTE)~LLEF; ord = c;
b &= (BYTE)~LLEF; ord = b;
dp->blk_ofs = dp->dptr;
}
/* Check LFN validity and capture it */
ord = (c == ord && sum == dp->dir[LDIR_Chksum] && pick_lfn(fs->lfnbuf, dp->dir)) ? ord - 1 : 0xFF;
ord = (b == ord && sum == dp->dir[LDIR_Chksum] && pick_lfn(fs->lfnbuf, dp->dir)) ? ord - 1 : 0xFF;
} else { /* An SFN entry is found */
if (ord != 0 || sum != sum_sfn(dp->dir)) { /* Is there a valid LFN? */
dp->blk_ofs = 0xFFFFFFFF; /* It has no LFN. */
@@ -2392,7 +2402,7 @@ static FRESULT dir_read (
}
}
#else /* Non LFN configuration */
if (c != DDEM && c != '.' && a != AM_LFN && (int)((a & ~AM_ARC) == AM_VOL) == vol) { /* Is it a valid entry? */
if (b != DDEM && b != '.' && attr != AM_LFN && (int)((attr & ~AM_ARC) == AM_VOL) == vol) { /* Is it a valid entry? */
break;
}
#endif
@@ -2432,7 +2442,7 @@ static FRESULT dir_find ( /* FR_OK(0):succeeded, !=0:error */
UINT di, ni;
WORD hash = xname_sum(fs->lfnbuf); /* Hash value of the name to find */
while ((res = dir_read_file(dp)) == FR_OK) { /* Read an item */
while ((res = DIR_READ_FILE(dp)) == FR_OK) { /* Read an item */
#if FF_MAX_LFN < 255
if (fs->dirbuf[XDIR_NumName] > FF_MAX_LFN) continue; /* Skip comparison if inaccessible object name */
#endif
@@ -2511,17 +2521,17 @@ static FRESULT dir_register ( /* FR_OK:succeeded, FR_DENIED:no free entry or too
#if FF_FS_EXFAT
if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */
nent = (nlen + 14) / 15 + 2; /* Number of entries to allocate (85+C0+C1s) */
res = dir_alloc(dp, nent); /* Allocate entries */
res = dir_alloc(dp, nent); /* Allocate directory entries */
if (res != FR_OK) return res;
dp->blk_ofs = dp->dptr - SZDIRE * (nent - 1); /* Set the allocated entry block offset */
if (dp->obj.stat & 4) { /* Has the directory been stretched? */
if (dp->obj.stat & 4) { /* Has the directory been stretched by new allocation? */
dp->obj.stat &= ~4;
res = fill_first_frag(&dp->obj); /* Fill the first fragment on the FAT if needed */
if (res != FR_OK) return res;
res = fill_last_frag(&dp->obj, dp->clust, 0xFFFFFFFF); /* Fill the last fragment on the FAT if needed */
if (res != FR_OK) return res;
if (dp->obj.sclust != 0) { /* Is it a sub directory? */
if (dp->obj.sclust != 0) { /* Is it a sub-directory? */
DIR dj;
res = load_obj_xdir(&dj, &dp->obj); /* Load the object status */
@@ -2653,6 +2663,7 @@ static void get_fileinfo (
{
UINT si, di;
#if FF_USE_LFN
BYTE lcf;
WCHAR wc, hs;
FATFS *fs = dp->obj.fs;
#else
@@ -2713,9 +2724,10 @@ static void get_fileinfo (
if (di == 0) { /* If LFN and SFN both are invalid, this object is inaccesible */
fno->fname[di++] = '?';
} else {
for (si = di = 0; fno->altname[si]; si++, di++) { /* Copy altname[] to fname[] with case information */
for (si = di = 0, lcf = NS_BODY; fno->altname[si]; si++, di++) { /* Copy altname[] to fname[] with case information */
wc = (WCHAR)fno->altname[si];
if (IsUpper(wc) && (dp->dir[DIR_NTres] & ((si >= 9) ? NS_EXT : NS_BODY))) wc += 0x20;
if (wc == '.') lcf = NS_EXT;
if (IsUpper(wc) && (dp->dir[DIR_NTres] & lcf)) wc += 0x20;
fno->fname[di] = (TCHAR)wc;
}
}
@@ -3272,7 +3284,7 @@ static FRESULT find_volume ( /* FR_OK(0): successful, !=0: an error occurred */
if (SS(fs) > FF_MAX_SS || SS(fs) < FF_MIN_SS || (SS(fs) & (SS(fs) - 1))) return FR_DISK_ERR;
#endif
/* Find an FAT partition on the drive. Supports only generic partitioning rules, FDISK and SFD. */
/* Find an FAT partition on the drive. Supports only generic partitioning rules, FDISK (MBR) and SFD (w/o partition). */
bsect = 0;
fmt = check_fs(fs, bsect); /* Load sector 0 and check if it is an FAT-VBR as SFD */
if (fmt == 2 || (fmt < 2 && LD2PT(vol) != 0)) { /* Not an FAT-VBR or forced partition number */
@@ -3301,13 +3313,12 @@ static FRESULT find_volume ( /* FR_OK(0): successful, !=0: an error occurred */
#if FF_FS_EXFAT
if (fmt == 1) {
QWORD maxlba;
DWORD so, cv, bcl;
for (i = BPB_ZeroedEx; i < BPB_ZeroedEx + 53 && fs->win[i] == 0; i++) ; /* Check zero filler */
if (i < BPB_ZeroedEx + 53)
return FR_NO_FILESYSTEM;
if (i < BPB_ZeroedEx + 53) return FR_NO_FILESYSTEM;
if (ld_word(fs->win + BPB_FSVerEx) != 0x100)
return FR_NO_FILESYSTEM; /* Check exFAT version (must be version 1.0) */
if (ld_word(fs->win + BPB_FSVerEx) != 0x100) return FR_NO_FILESYSTEM; /* Check exFAT version (must be version 1.0) */
if (1 << fs->win[BPB_BytsPerSecEx] != SS(fs)) { /* (BPB_BytsPerSecEx must be equal to the physical sector size) */
EFSPRINTF("EXSPS");
@@ -3315,8 +3326,7 @@ static FRESULT find_volume ( /* FR_OK(0): successful, !=0: an error occurred */
}
maxlba = ld_qword(fs->win + BPB_TotSecEx) + bsect; /* Last LBA + 1 of the volume */
if (maxlba >= 0x100000000)
return FR_NO_FILESYSTEM; /* (It cannot be handled in 32-bit LBA) */
if (maxlba >= 0x100000000) return FR_NO_FILESYSTEM; /* (It cannot be handled in 32-bit LBA) */
fs->fsize = ld_dword(fs->win + BPB_FatSzEx); /* Number of sectors per FAT */
@@ -3327,35 +3337,49 @@ static FRESULT find_volume ( /* FR_OK(0): successful, !=0: an error occurred */
}
fs->csize = 1 << fs->win[BPB_SecPerClusEx]; /* Cluster size */
if (fs->csize == 0) {
return FR_NO_FILESYSTEM; /* (Must be 1..32768) */
}
if (fs->csize == 0) return FR_NO_FILESYSTEM; /* (Must be 1..32768) */
nclst = ld_dword(fs->win + BPB_NumClusEx); /* Number of clusters */
if (nclst > MAX_EXFAT)
return FR_NO_FILESYSTEM; /* (Too many clusters) */
if (nclst > MAX_EXFAT) return FR_NO_FILESYSTEM; /* (Too many clusters) */
fs->n_fatent = nclst + 2;
/* Boundaries and Limits */
fs->volbase = bsect;
fs->database = bsect + ld_dword(fs->win + BPB_DataOfsEx);
fs->fatbase = bsect + ld_dword(fs->win + BPB_FatOfsEx);
if (maxlba < (QWORD)fs->database + nclst * fs->csize)
return FR_NO_FILESYSTEM; /* (Volume size must not be smaller than the size required) */
if (maxlba < (QWORD)fs->database + nclst * fs->csize) return FR_NO_FILESYSTEM; /* (Volume size must not be smaller than the size requiered) */
fs->dirbase = ld_dword(fs->win + BPB_RootClusEx);
/* Check if bitmap location is in assumption (at the first cluster) */
if (move_window(fs, clst2sect(fs, fs->dirbase)) != FR_OK) {
EFSPRINTF("EXBM1C");
return FR_DISK_ERR;
/* Get bitmap location and check if it is contiguous (implementation assumption) */
so = i = 0;
for (;;) { /* Find the bitmap entry in the root directory (in only first cluster) */
if (i == 0) {
if (so >= fs->csize) return FR_NO_FILESYSTEM; /* Not found? */
if (move_window(fs, clst2sect(fs, fs->dirbase) + so) != FR_OK) {
EFSPRINTF("EXBM1C");
return FR_DISK_ERR;
}
so++;
}
if (fs->win[i] == ET_BITMAP) break; /* Is it a bitmap entry? */
i = (i + SZDIRE) % SS(fs); /* Next entry */
}
for (i = 0; i < SS(fs); i += SZDIRE) {
if (fs->win[i] == 0x81 && ld_dword(fs->win + i + 20) == 2) break; /* 81 entry with cluster #2? */
}
if (i == SS(fs)) {
bcl = ld_dword(fs->win + i + 20); /* Bitmap cluster */
if (bcl < 2 || bcl >= fs->n_fatent) {
EFSPRINTF("EXBMM");
return FR_NO_FILESYSTEM;
}
fs->bitbase = fs->database + fs->csize * (bcl - 2); /* Bitmap sector */
for (;;) { /* Check if bitmap is contiguous */
if (move_window(fs, fs->fatbase + bcl / (SS(fs) / 4)) != FR_OK) return FR_DISK_ERR;
cv = ld_dword(fs->win + bcl % (SS(fs) / 4) * 4);
if (cv == 0xFFFFFFFF) break; /* Last link? */
if (cv != ++bcl) {
EFSPRINTF("EXBMM");
return FR_NO_FILESYSTEM; /* Fragmented? */
}
}
#if !FF_FS_READONLY
fs->last_clst = fs->free_clst = 0xFFFFFFFF; /* Initialize cluster allocation information */
#endif
@@ -3373,38 +3397,31 @@ static FRESULT find_volume ( /* FR_OK(0): successful, !=0: an error occurred */
fs->fsize = fasize;
fs->n_fats = fs->win[BPB_NumFATs]; /* Number of FATs */
if (fs->n_fats != 1 && fs->n_fats != 2)
return FR_NO_FILESYSTEM; /* (Must be 1 or 2) */
if (fs->n_fats != 1 && fs->n_fats != 2) return FR_NO_FILESYSTEM; /* (Must be 1 or 2) */
fasize *= fs->n_fats; /* Number of sectors for FAT area */
fs->csize = fs->win[BPB_SecPerClus]; /* Cluster size */
if (fs->csize == 0 || (fs->csize & (fs->csize - 1)))
return FR_NO_FILESYSTEM; /* (Must be power of 2) */
if (fs->csize == 0 || (fs->csize & (fs->csize - 1))) return FR_NO_FILESYSTEM; /* (Must be power of 2) */
fs->n_rootdir = ld_word(fs->win + BPB_RootEntCnt); /* Number of root directory entries */
if (fs->n_rootdir % (SS(fs) / SZDIRE))
return FR_NO_FILESYSTEM; /* (Must be sector aligned) */
if (fs->n_rootdir % (SS(fs) / SZDIRE)) return FR_NO_FILESYSTEM; /* (Must be sector aligned) */
tsect = ld_word(fs->win + BPB_TotSec16); /* Number of sectors on the volume */
if (tsect == 0) tsect = ld_dword(fs->win + BPB_TotSec32);
nrsv = ld_word(fs->win + BPB_RsvdSecCnt); /* Number of reserved sectors */
if (nrsv == 0)
return FR_NO_FILESYSTEM; /* (Must not be 0) */
if (nrsv == 0) return FR_NO_FILESYSTEM; /* (Must not be 0) */
/* Determine the FAT sub type */
sysect = nrsv + fasize + fs->n_rootdir / (SS(fs) / SZDIRE); /* RSV + FAT + DIR */
if (tsect < sysect)
return FR_NO_FILESYSTEM; /* (Invalid volume size) */
if (tsect < sysect) return FR_NO_FILESYSTEM; /* (Invalid volume size) */
nclst = (tsect - sysect) / fs->csize; /* Number of clusters */
if (nclst == 0)
return FR_NO_FILESYSTEM; /* (Invalid volume size) */
if (nclst == 0) return FR_NO_FILESYSTEM; /* (Invalid volume size) */
fmt = 0;
if (nclst <= MAX_FAT32) fmt = FS_FAT32;
if (nclst <= MAX_FAT16) fmt = FS_FAT16;
if (nclst <= MAX_FAT12) fmt = FS_FAT12;
if (fmt == 0)
return FR_NO_FILESYSTEM;
if (fmt == 0) return FR_NO_FILESYSTEM;
/* Boundaries and Limits */
fs->n_fatent = nclst + 2; /* Number of FAT entries */
@@ -3412,21 +3429,17 @@ static FRESULT find_volume ( /* FR_OK(0): successful, !=0: an error occurred */
fs->fatbase = bsect + nrsv; /* FAT start sector */
fs->database = bsect + sysect; /* Data start sector */
if (fmt == FS_FAT32) {
if (ld_word(fs->win + BPB_FSVer32) != 0)
return FR_NO_FILESYSTEM; /* (Must be FAT32 revision 0.0) */
if (fs->n_rootdir != 0)
return FR_NO_FILESYSTEM; /* (BPB_RootEntCnt must be 0) */
if (ld_word(fs->win + BPB_FSVer32) != 0) return FR_NO_FILESYSTEM; /* (Must be FAT32 revision 0.0) */
if (fs->n_rootdir != 0) return FR_NO_FILESYSTEM; /* (BPB_RootEntCnt must be 0) */
fs->dirbase = ld_dword(fs->win + BPB_RootClus32); /* Root directory start cluster */
szbfat = fs->n_fatent * 4; /* (Needed FAT size) */
} else {
if (fs->n_rootdir == 0)
return FR_NO_FILESYSTEM; /* (BPB_RootEntCnt must not be 0) */
if (fs->n_rootdir == 0) return FR_NO_FILESYSTEM; /* (BPB_RootEntCnt must not be 0) */
fs->dirbase = fs->fatbase + fasize; /* Root directory start sector */
szbfat = (fmt == FS_FAT16) ? /* (Needed FAT size) */
fs->n_fatent * 2 : fs->n_fatent * 3 / 2 + (fs->n_fatent & 1);
}
if (fs->fsize < (szbfat + (SS(fs) - 1)) / SS(fs))
return FR_NO_FILESYSTEM; /* (BPB_FATSz must not be less than the size needed) */
if (fs->fsize < (szbfat + (SS(fs) - 1)) / SS(fs)) return FR_NO_FILESYSTEM; /* (BPB_FATSz must not be less than the size needed) */
#if !FF_FS_READONLY
/* Get FSInfo if available */
@@ -3459,7 +3472,7 @@ static FRESULT find_volume ( /* FR_OK(0): successful, !=0: an error occurred */
#if FF_USE_LFN == 1
fs->lfnbuf = LfnBuf; /* Static LFN working buffer */
#if FF_FS_EXFAT
fs->dirbuf = DirBuf; /* Static directory block scratchpad buffer */
fs->dirbuf = DirBuf; /* Static directory block scratchpad buuffer */
#endif
#endif
#if FF_FS_RPATH != 0
@@ -3722,7 +3735,7 @@ FRESULT f_open (
fp->fptr = 0; /* Set file pointer top of the file */
#if !FF_FS_READONLY
#if !FF_FS_TINY
mem_set(fp->buf, 0, FF_MAX_SS); /* Clear sector buffer */
mem_set(fp->buf, 0, sizeof fp->buf); /* Clear sector buffer */
#endif
if ((mode & FA_SEEKEND) && fp->obj.objsize > 0) { /* Seek to end of file if FA_OPEN_APPEND is specified */
fp->fptr = fp->obj.objsize; /* Offset to seek */
@@ -3777,17 +3790,16 @@ FRESULT f_read (
UINT rcnt, cc, csect;
BYTE *rbuff = (BYTE*)buff;
UINT br_tmp;
if (!br)
br = &br_tmp;
*br = 0; /* Clear read byte counter */
res = validate(&fp->obj, &fs); /* Check validity of the file object */
if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) {
EFSPRINTF("FOV");
LEAVE_FF(fs, res); /* Check validity */
}
if (!(fp->flag & FA_READ)) {
EFSPRINTF("NOACCESS");
LEAVE_FF(fs, FR_DENIED); /* Check access mode */
}
if (!(fp->flag & FA_READ)) LEAVE_FF(fs, FR_DENIED); /* Check access mode */
remain = fp->obj.objsize - fp->fptr;
if (btr > remain) btr = (UINT)remain; /* Truncate btr by remaining bytes */
@@ -3819,9 +3831,7 @@ FRESULT f_read (
fp->clust = clst; /* Update current cluster */
}
sect = clst2sect(fs, fp->clust); /* Get current sector */
if (sect == 0) {
ABORT(fs, FR_INT_ERR);
}
if (sect == 0) ABORT(fs, FR_INT_ERR);
sect += csect;
cc = btr / SS(fs); /* When remaining bytes >= sector size, */
if (cc > 0) { /* Read maximum contiguous sectors directly */
@@ -3899,17 +3909,16 @@ FRESULT f_write (
UINT wcnt, cc, csect;
const BYTE *wbuff = (const BYTE*)buff;
UINT bw_tmp;
if (!bw)
bw = &bw_tmp;
*bw = 0; /* Clear write byte counter */
res = validate(&fp->obj, &fs); /* Check validity of the file object */
if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) {
EFSPRINTF("FOV");
LEAVE_FF(fs, res); /* Check validity */
}
if (!(fp->flag & FA_WRITE)) {
EFSPRINTF("NOACCESS");
LEAVE_FF(fs, FR_DENIED); /* Check access mode */
}
if (!(fp->flag & FA_WRITE)) LEAVE_FF(fs, FR_DENIED); /* Check access mode */
/* Check fptr wrap-around (file size cannot reach 4 GiB at FAT volume) */
if ((!FF_FS_EXFAT || fs->fs_type != FS_EXFAT) && (DWORD)(fp->fptr + btw) < (DWORD)fp->fptr) {
@@ -3955,15 +3964,12 @@ FRESULT f_write (
if (fs->winsect == fp->sect && sync_window(fs) != FR_OK) ABORT(fs, FR_DISK_ERR); /* Write-back sector cache */
#else
if (fp->flag & FA_DIRTY) { /* Write-back sector cache */
if (disk_write(fs->pdrv, fp->buf, fp->sect, 1) != RES_OK)
ABORT(fs, FR_DISK_ERR);
if (disk_write(fs->pdrv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR);
fp->flag &= (BYTE)~FA_DIRTY;
}
#endif
sect = clst2sect(fs, fp->clust); /* Get current sector */
if (sect == 0) {
ABORT(fs, FR_INT_ERR);
}
if (sect == 0) ABORT(fs, FR_INT_ERR);
sect += csect;
cc = btw / SS(fs); /* When remaining bytes >= sector size, */
if (cc > 0) { /* Write maximum contiguous sectors directly */
@@ -3998,8 +4004,9 @@ FRESULT f_write (
#else
if (fp->sect != sect && /* Fill sector cache with file data */
fp->fptr < fp->obj.objsize &&
disk_read(fs->pdrv, fp->buf, sect, 1) != RES_OK)
disk_read(fs->pdrv, fp->buf, sect, 1) != RES_OK) {
ABORT(fs, FR_DISK_ERR);
}
#endif
fp->sect = sect;
}
@@ -4245,6 +4252,7 @@ FRESULT f_getcwd (
/* Get logical drive */
buff[0] = 0; /* Set null string to get current volume */
res = find_volume((const TCHAR**)&buff, &fs, 0); /* Get current volume */
if (res == FR_OK) {
dj.obj.fs = fs;
@@ -4263,7 +4271,7 @@ FRESULT f_getcwd (
res = dir_sdi(&dj, 0);
if (res != FR_OK) break;
do { /* Find the entry links to the child directory */
res = dir_read_file(&dj);
res = DIR_READ_FILE(&dj);
if (res != FR_OK) break;
if (ccl == ld_clust(fs, dj.dir)) break; /* Found the entry */
res = dir_next(&dj, 0);
@@ -4595,7 +4603,7 @@ FRESULT f_readdir (
res = dir_sdi(dp, 0); /* Rewind the directory object */
} else {
INIT_NAMBUF(fs);
res = dir_read_file(dp); /* Read an item */
res = DIR_READ_FILE(dp); /* Read an item */
if (res == FR_NO_FILE) res = FR_OK; /* Ignore end of directory */
if (res == FR_OK) { /* A valid entry is found */
get_fileinfo(dp, fno); /* Get the object information */
@@ -4740,7 +4748,7 @@ FRESULT f_getfree (
UINT b;
clst = fs->n_fatent - 2; /* Number of clusters */
sect = fs->database; /* Assuming bitmap starts at cluster 2 */
sect = fs->bitbase; /* Bitmap sector */
i = 0; /* Offset in the sector */
do { /* Counts numbuer of bits with zero in the bitmap */
if (i == 0) {
@@ -4903,7 +4911,7 @@ FRESULT f_unlink (
#endif
res = dir_sdi(&sdj, 0);
if (res == FR_OK) {
res = dir_read_file(&sdj); /* Test if the directory is empty */
res = DIR_READ_FILE(&sdj); /* Test if the directory is empty */
if (res == FR_OK) res = FR_DENIED; /* Not empty? */
if (res == FR_NO_FILE) res = FR_OK; /* Empty? */
}
@@ -4943,47 +4951,43 @@ FRESULT f_mkdir (
DIR dj;
FFOBJID sobj;
FATFS *fs;
BYTE *dir;
DWORD dcl, pcl, tm;
DEF_NAMBUF
/* Get logical drive */
res = find_volume(&path, &fs, FA_WRITE);
res = find_volume(&path, &fs, FA_WRITE); /* Get logical drive */
if (res == FR_OK) {
dj.obj.fs = fs;
INIT_NAMBUF(fs);
res = follow_path(&dj, path); /* Follow the file path */
if (res == FR_OK) res = FR_EXIST; /* Any object with same name is already existing */
if (FF_FS_RPATH && res == FR_NO_FILE && (dj.fn[NSFLAG] & NS_DOT)) {
if (res == FR_OK) res = FR_EXIST; /* Name collision? */
if (FF_FS_RPATH && res == FR_NO_FILE && (dj.fn[NSFLAG] & NS_DOT)) { /* Invalid name? */
res = FR_INVALID_NAME;
}
if (res == FR_NO_FILE) { /* Can create a new directory */
if (res == FR_NO_FILE) { /* It is clear to create a new directory */
sobj.fs = fs; /* New object id to create a new chain */
dcl = create_chain(&sobj, 0); /* Allocate a cluster for the new directory */
res = FR_OK;
if (dcl == 0) res = FR_DENIED; /* No space to allocate a new cluster */
if (dcl == 1) res = FR_INT_ERR;
if (dcl == 0xFFFFFFFF) res = FR_DISK_ERR;
if (res == FR_OK) res = sync_window(fs); /* Flush FAT */
if (dcl == 0) res = FR_DENIED; /* No space to allocate a new cluster? */
if (dcl == 1) res = FR_INT_ERR; /* Any insanity? */
if (dcl == 0xFFFFFFFF) res = FR_DISK_ERR; /* Disk error? */
tm = GET_FATTIME();
if (res == FR_OK) { /* Initialize the new directory table */
res = dir_clear(fs, dcl); /* Clean up the new table */
if (res == FR_OK && (!FF_FS_EXFAT || fs->fs_type != FS_EXFAT)) { /* Create dot entries (FAT only) */
dir = fs->win;
mem_set(dir + DIR_Name, ' ', 11); /* Create "." entry */
dir[DIR_Name] = '.';
dir[DIR_Attr] = AM_DIR;
st_dword(dir + DIR_ModTime, tm);
st_clust(fs, dir, dcl);
mem_cpy(dir + SZDIRE, dir, SZDIRE); /* Create ".." entry */
dir[SZDIRE + 1] = '.'; pcl = dj.obj.sclust;
st_clust(fs, dir + SZDIRE, pcl);
fs->wflag = 1;
}
}
if (res == FR_OK) {
res = dir_register(&dj); /* Register the object to the directoy */
res = dir_clear(fs, dcl); /* Clean up the new table */
if (res == FR_OK) {
if (!FF_FS_EXFAT || fs->fs_type != FS_EXFAT) { /* Create dot entries (FAT only) */
mem_set(fs->win + DIR_Name, ' ', 11); /* Create "." entry */
fs->win[DIR_Name] = '.';
fs->win[DIR_Attr] = AM_DIR;
st_dword(fs->win + DIR_ModTime, tm);
st_clust(fs, fs->win, dcl);
mem_cpy(fs->win + SZDIRE, fs->win, SZDIRE); /* Create ".." entry */
fs->win[SZDIRE + 1] = '.'; pcl = dj.obj.sclust;
st_clust(fs, fs->win + SZDIRE, pcl);
fs->wflag = 1;
}
res = dir_register(&dj); /* Register the object to the parent directoy */
}
}
if (res == FR_OK) {
#if FF_FS_EXFAT
@@ -4998,17 +5002,16 @@ FRESULT f_mkdir (
} else
#endif
{
dir = dj.dir;
st_dword(dir + DIR_ModTime, tm); /* Created time */
st_clust(fs, dir, dcl); /* Table start cluster */
dir[DIR_Attr] = AM_DIR; /* Attribute */
st_dword(dj.dir + DIR_ModTime, tm); /* Created time */
st_clust(fs, dj.dir, dcl); /* Table start cluster */
dj.dir[DIR_Attr] = AM_DIR; /* Attribute */
fs->wflag = 1;
}
if (res == FR_OK) {
res = sync_fs(fs);
}
} else {
remove_chain(&dj.obj, dcl, 0); /* Could not register, remove cluster chain */
remove_chain(&sobj, dcl, 0); /* Could not register, remove the allocated cluster */
}
}
FREE_NAMBUF();
@@ -5248,7 +5251,7 @@ FRESULT f_getlabel (
dj.obj.fs = fs; dj.obj.sclust = 0; /* Open root directory */
res = dir_sdi(&dj, 0);
if (res == FR_OK) {
res = dir_read_label(&dj); /* Find a volume label entry */
res = DIR_READ_LABEL(&dj); /* Find a volume label entry */
if (res == FR_OK) {
#if FF_FS_EXFAT
if (fs->fs_type == FS_EXFAT) {
@@ -5393,7 +5396,7 @@ FRESULT f_setlabel (
dj.obj.fs = fs; dj.obj.sclust = 0; /* Open root directory */
res = dir_sdi(&dj, 0);
if (res == FR_OK) {
res = dir_read_label(&dj); /* Get volume label entry */
res = DIR_READ_LABEL(&dj); /* Get volume label entry */
if (res == FR_OK) {
if (FF_FS_EXFAT && fs->fs_type == FS_EXFAT) {
dj.dir[XDIR_NumLabel] = (BYTE)di; /* Change the volume label */
@@ -5415,7 +5418,7 @@ FRESULT f_setlabel (
if (res == FR_OK) {
mem_set(dj.dir, 0, SZDIRE); /* Clean the entry */
if (FF_FS_EXFAT && fs->fs_type == FS_EXFAT) {
dj.dir[XDIR_Type] = 0x83; /* Create 83 entry */
dj.dir[XDIR_Type] = ET_VLABEL; /* Create volume label entry */
dj.dir[XDIR_NumLabel] = (BYTE)di;
mem_cpy(dj.dir + XDIR_Label, dirvn, 22);
} else {
@@ -5720,7 +5723,7 @@ FRESULT f_mkfs (
b_fat = b_vol + 32; /* FAT start at offset 32 */
sz_fat = ((sz_vol / au + 2) * 4 + ss - 1) / ss; /* Number of FAT sectors */
b_data = (b_fat + sz_fat + sz_blk - 1) & ~(sz_blk - 1); /* Align data area to the erase block boundary */
if (b_data >= sz_vol / 2) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too small volume? */
if (b_data - b_vol >= sz_vol / 2) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too small volume? */
n_clst = (sz_vol - (b_data - b_vol)) / au; /* Number of clusters */
if (n_clst <16) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too few clusters? */
if (n_clst > MAX_EXFAT) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too many clusters? */
@@ -5801,11 +5804,11 @@ FRESULT f_mkfs (
/* Initialize the root directory */
mem_set(buf, 0, szb_buf);
buf[SZDIRE * 0 + 0] = 0x83; /* 83 entry (volume label) */
buf[SZDIRE * 1 + 0] = 0x81; /* 81 entry (allocation bitmap) */
buf[SZDIRE * 0 + 0] = ET_VLABEL; /* Volume label entry */
buf[SZDIRE * 1 + 0] = ET_BITMAP; /* Bitmap entry */
st_dword(buf + SZDIRE * 1 + 20, 2); /* cluster */
st_dword(buf + SZDIRE * 1 + 24, szb_bit); /* size */
buf[SZDIRE * 2 + 0] = 0x82; /* 82 entry (up-case table) */
buf[SZDIRE * 2 + 0] = ET_UPCASE; /* Up-case table entry */
st_dword(buf + SZDIRE * 2 + 4, sum); /* sum */
st_dword(buf + SZDIRE * 2 + 20, 2 + tbl[0]); /* cluster */
st_dword(buf + SZDIRE * 2 + 24, szb_case); /* size */
@@ -6293,8 +6296,7 @@ typedef struct { /* Putchar output buffer and work area */
} putbuff;
static
void putc_bfd ( /* Buffered write with code conversion */
static void putc_bfd ( /* Buffered write with code conversion */
putbuff* pb,
TCHAR c
)
@@ -6405,7 +6407,7 @@ void putc_bfd ( /* Buffered write with code conversion */
#else /* Write it in ANSI/OEM */
if (hs != 0) return;
wc = ff_uni2oem(wc, CODEPAGE); /* UTF-16 ==> ANSI/OEM */
if (wc == 0) return;;
if (wc == 0) return;
if (wc >= 0x100) {
pb->buf[i++] = (BYTE)(wc >> 8); nc++;
}
@@ -6425,8 +6427,7 @@ void putc_bfd ( /* Buffered write with code conversion */
}
static
int putc_flush ( /* Flush left characters in the buffer */
static int putc_flush ( /* Flush left characters in the buffer */
putbuff* pb
)
{
@@ -6439,8 +6440,7 @@ int putc_flush ( /* Flush left characters in the buffer */
}
static
void putc_init ( /* Initialize write buffer */
static void putc_init ( /* Initialize write buffer */
putbuff* pb,
FIL* fp
)

View File

@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------/
/ FatFs - Generic FAT Filesystem module R0.13b /
/ FatFs - Generic FAT Filesystem module R0.13c /
/-----------------------------------------------------------------------------/
/
/ Copyright (C) 2018, ChaN, all right reserved.
@@ -20,7 +20,7 @@
#ifndef FF_DEFINED
#define FF_DEFINED 63463 /* Revision ID */
#define FF_DEFINED 86604 /* Revision ID */
#ifdef __cplusplus
extern "C" {
@@ -95,8 +95,8 @@ typedef DWORD FSIZE_t;
/* Filesystem object structure (FATFS) */
typedef struct {
BYTE fs_type; /* Filesystem type (0:N/A) */
BYTE pdrv; /* Physical drive number */
BYTE fs_type; /* Filesystem type (0:not mounted) */
BYTE pdrv; /* Associated physical drive */
BYTE n_fats; /* Number of FATs (1 or 2) */
BYTE wflag; /* win[] flag (b0:dirty) */
BYTE fsi_flag; /* FSINFO flags (b7:disabled, b0:dirty) */
@@ -133,6 +133,9 @@ typedef struct {
DWORD fatbase; /* FAT base sector */
DWORD dirbase; /* Root directory base sector/cluster */
DWORD database; /* Data base sector */
#if FF_FS_EXFAT
DWORD bitbase; /* Allocation bitmap base sector */
#endif
DWORD winsect; /* Current sector appearing in the win[] */
BYTE win[FF_MAX_SS]; /* Disk access window for Directory, FAT (and file data at tiny cfg) */
} FATFS;
@@ -145,7 +148,7 @@ typedef struct {
FATFS* fs; /* Pointer to the hosting volume of this object */
WORD id; /* Hosting volume mount ID */
BYTE attr; /* Object attribute */
BYTE stat; /* Object chain status (b1-0: =0:not contiguous, =2:contiguous, =3:flagmented in this session, b2:sub-directory stretched) */
BYTE stat; /* Object chain status (b1-0: =0:not contiguous, =2:contiguous, =3:fragmented in this session, b2:sub-directory stretched) */
DWORD sclust; /* Object data start cluster (0:no cluster or root directory) */
FSIZE_t objsize; /* Object size (valid when sclust != 0) */
#if FF_FS_EXFAT
@@ -175,12 +178,12 @@ typedef struct {
DWORD dir_sect; /* Sector number containing the directory entry (not used at exFAT) */
BYTE* dir_ptr; /* Pointer to the directory entry in the win[] (not used at exFAT) */
#endif
#if FF_USE_FASTSEEK
DWORD* cltbl; /* Pointer to the cluster link map table (nulled on open, set by application) */
#endif
#if !FF_FS_TINY
BYTE buf[FF_MAX_SS]; /* File private data read/write window */
#endif
#if FF_USE_FASTSEEK
DWORD* cltbl; /* Pointer to the cluster link map table (nulled on open, set by application) */
#endif
} FIL;

View File

@@ -1,8 +1,8 @@
/*---------------------------------------------------------------------------/
/ FatFs - Configuration file
/ FatFs Functional Configurations
/---------------------------------------------------------------------------*/
#define FFCONF_DEF 63463 /* Revision ID */
#define FFCONF_DEF 86604 /* Revision ID */
/*---------------------------------------------------------------------------/
/ Function Configurations
@@ -232,14 +232,14 @@
#define FF_FS_EXFAT 1
/* This option switches support for exFAT filesystem. (0:Disable or 1:Enable)
/ To enable exFAT, also LFN needs to be enabled.
/ To enable exFAT, also LFN needs to be enabled. (FF_USE_LFN >= 1)
/ Note that enabling exFAT discards ANSI C (C89) compatibility. */
#define FF_FS_NORTC 1
#define FF_NORTC_MON 1
#define FF_NORTC_MDAY 1
#define FF_NORTC_YEAR 2018
#define FF_NORTC_YEAR 2019
/* 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
@@ -262,6 +262,7 @@
/ lock control is independent of re-entrancy. */
/* #include <somertos.h> // O/S definitions */
#define FF_FS_REENTRANT 0
#define FF_FS_TIMEOUT 1000
#define FF_SYNC_t HANDLE
@@ -282,8 +283,6 @@
/ SemaphoreHandle_t and etc. A header file for O/S definitions needs to be
/ included somewhere in the scope of ff.h. */
/* #include <windows.h> // O/S definitions */
/*--- End of configuration options ---*/

View File

@@ -1,6 +1,6 @@
/*------------------------------------------------------------------------*/
/* Sample Code of OS Dependent Functions for FatFs */
/* (C) ChaN, 2017 */
/* (C) ChaN, 2018 */
/* (C) CTCaer, 2018 */
/*------------------------------------------------------------------------*/
@@ -16,7 +16,7 @@
/* Allocate a memory block */
/*------------------------------------------------------------------------*/
void* ff_memalloc ( /* Returns pointer to the allocated memory block (null on not enough core) */
void* ff_memalloc ( /* Returns pointer to the allocated memory block (null if not enough core) */
UINT msize /* Number of bytes to allocate */
)
{
@@ -29,7 +29,7 @@ void* ff_memalloc ( /* Returns pointer to the allocated memory block (null on no
/*------------------------------------------------------------------------*/
void ff_memfree (
void* mblock /* Pointer to the memory block to free (nothing to do for null) */
void* mblock /* Pointer to the memory block to free (nothing to do if null) */
)
{
free(mblock); /* Free the memory block with POSIX API */

View File

@@ -1,5 +1,5 @@
/*------------------------------------------------------------------------*/
/* Unicode handling functions for FatFs R0.13a */
/* Unicode handling functions for FatFs R0.13c */
/*------------------------------------------------------------------------*/
/* This module will occupy a huge memory in the .const section when the /
/ FatFs is configured for LFN with DBCS. If the system has any Unicode /
@@ -7,7 +7,7 @@
/ that function to avoid silly memory consumption. /
/-------------------------------------------------------------------------*/
/*
/ Copyright (C) 2017, ChaN, all right reserved.
/ Copyright (C) 2018, ChaN, all right reserved.
/
/ FatFs module is an open source software. Redistribution and use of FatFs in
/ source and binary forms, with or without modification, are permitted provided
@@ -25,9 +25,9 @@
#include "ff.h"
#if FF_USE_LFN /* This module is blanked when non-LFN configuration */
#if FF_USE_LFN /* This module will be blanked at non-LFN configuration */
#if FF_DEFINED != 63463 /* Revision ID */
#if FF_DEFINED != 86604 /* Revision ID */
#error Wrong include file (ff.h).
#endif

View File

@@ -25,6 +25,7 @@
#include "gfx/logos.h"
#include "gfx/tui.h"
#include "hos/hos.h"
#include "hos/secmon_exo.h"
#include "hos/sept.h"
#include "ianos/ianos.h"
#include "libs/compr/blz.h"
@@ -33,10 +34,12 @@
#include "mem/sdram.h"
#include "power/max77620.h"
#include "rtc/max77620-rtc.h"
#include "soc/fuse.h"
#include "soc/hw_init.h"
#include "soc/i2c.h"
#include "soc/t210.h"
#include "soc/uart.h"
#include "storage/nx_emmc.h"
#include "storage/sdmmc.h"
#include "utils/btn.h"
#include "utils/dirlist.h"
@@ -103,29 +106,24 @@ void sd_unmount()
}
}
void *sd_file_read(char *path)
void *sd_file_read(const char *path, u32 *fsize)
{
FIL fp;
if (f_open(&fp, path, FA_READ) != FR_OK)
return NULL;
u32 size = f_size(&fp);
if (fsize)
*fsize = size;
void *buf = malloc(size);
u8 *ptr = buf;
while (size > 0)
if (f_read(&fp, buf, size, NULL) != FR_OK)
{
u32 rsize = MIN(size, 512 * 8192);
if (f_read(&fp, ptr, rsize, NULL) != FR_OK)
{
free(buf);
f_close(&fp);
free(buf);
f_close(&fp);
return NULL;
}
ptr += rsize;
size -= rsize;
return NULL;
}
f_close(&fp);
@@ -144,7 +142,6 @@ int sd_save_to_file(void *buf, u32 size, const char *filename)
return 1;
}
f_sync(&fp);
f_write(&fp, buf, size, NULL);
f_close(&fp);
@@ -203,10 +200,10 @@ void check_power_off_from_hos()
if (h_cfg.autohosoff == 1)
{
gfx_clear_grey(&gfx_ctxt, 0x1B);
gfx_clear_grey(0x1B);
u8 *BOOTLOGO = (void *)malloc(0x4000);
blz_uncompress_srcdest(BOOTLOGO_BLZ, SZ_BOOTLOGO_BLZ, BOOTLOGO, SZ_BOOTLOGO);
gfx_set_rect_grey(&gfx_ctxt, BOOTLOGO, X_BOOTLOGO, Y_BOOTLOGO, 326, 544);
gfx_set_rect_grey(BOOTLOGO, X_BOOTLOGO, Y_BOOTLOGO, 326, 544);
display_backlight_brightness(10, 5000);
display_backlight_brightness(100, 25000);
@@ -264,8 +261,8 @@ bool is_ipl_updated(void *buf)
int launch_payload(char *path, bool update)
{
if (!update)
gfx_clear_grey(&gfx_ctxt, 0x1B);
gfx_con_setpos(&gfx_con, 0, 0);
gfx_clear_grey(0x1B);
gfx_con_setpos(0, 0);
if (!path)
return 1;
@@ -356,8 +353,8 @@ void launch_tools(u8 type)
ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * (max_entries + 3));
gfx_clear_grey(&gfx_ctxt, 0x1B);
gfx_con_setpos(&gfx_con, 0, 0);
gfx_clear_grey(0x1B);
gfx_con_setpos(0, 0);
if (sd_mount())
{
@@ -399,7 +396,7 @@ void launch_tools(u8 type)
"Choose a file to launch", 0, 0
};
file_sec = (char *)tui_do_menu(&gfx_con, &menu);
file_sec = (char *)tui_do_menu(&menu);
if (!file_sec)
{
@@ -459,8 +456,8 @@ void ini_list_launcher()
ini_sec_t *cfg_sec = NULL;
LIST_INIT(ini_list_sections);
gfx_clear_grey(&gfx_ctxt, 0x1B);
gfx_con_setpos(&gfx_con, 0, 0);
gfx_clear_grey(0x1B);
gfx_con_setpos(0, 0);
if (sd_mount())
{
@@ -495,7 +492,7 @@ void ini_list_launcher()
ments, "Launch ini configurations", 0, 0
};
cfg_tmp = (ini_sec_t *)tui_do_menu(&gfx_con, &menu);
cfg_tmp = (ini_sec_t *)tui_do_menu(&menu);
if (cfg_tmp)
{
@@ -573,8 +570,8 @@ void launch_firmware()
ini_sec_t *cfg_sec = NULL;
LIST_INIT(ini_sections);
gfx_clear_grey(&gfx_ctxt, 0x1B);
gfx_con_setpos(&gfx_con, 0, 0);
gfx_clear_grey(0x1B);
gfx_con_setpos(0, 0);
if (sd_mount())
{
@@ -623,7 +620,7 @@ void launch_firmware()
ments, "Launch configurations", 0, 0
};
cfg_tmp = (ini_sec_t *)tui_do_menu(&gfx_con, &menu);
cfg_tmp = (ini_sec_t *)tui_do_menu(&menu);
if (cfg_tmp)
{
@@ -666,8 +663,8 @@ void launch_firmware()
if (!cfg_sec)
{
gfx_puts(&gfx_con, "\nPress POWER to Continue.\nPress VOL to go to the menu.\n\n");
gfx_printf(&gfx_con, "\nUsing default launch configuration...\n\n\n");
gfx_puts("\nPress POWER to Continue.\nPress VOL to go to the menu.\n\n");
gfx_printf("\nUsing default launch configuration...\n\n\n");
u32 btn = btn_wait();
if (!(btn & BTN_POWER))
@@ -847,10 +844,10 @@ void auto_launch_firmware()
if (!(b_cfg.boot_cfg & BOOT_CFG_FROM_LAUNCH) && h_cfg.bootwait)
{
if (bootlogoCustomEntry) // Check if user set custom logo path at the boot entry.
bitmap = (u8 *)sd_file_read(bootlogoCustomEntry);
bitmap = (u8 *)sd_file_read(bootlogoCustomEntry, NULL);
if (!bitmap) // Custom entry bootlogo not found, trying default custom one.
bitmap = (u8 *)sd_file_read("bootloader/bootlogo.bmp");
bitmap = (u8 *)sd_file_read("bootloader/bootlogo.bmp", NULL);
if (bitmap)
{
@@ -881,7 +878,7 @@ void auto_launch_firmware()
bmpData.pos_y = (1280 - bmpData.size_y) >> 1;
// Get background color from 1st pixel.
if (bmpData.size_x < 720 || bmpData.size_y < 1280)
gfx_clear_color(&gfx_ctxt, *(u32 *)BOOTLOGO);
gfx_clear_color(*(u32 *)BOOTLOGO);
bootlogoFound = true;
}
@@ -893,15 +890,15 @@ void auto_launch_firmware()
// Render boot logo.
if (bootlogoFound)
{
gfx_render_bmp_argb(&gfx_ctxt, (u32 *)BOOTLOGO, bmpData.size_x, bmpData.size_y,
gfx_render_bmp_argb((u32 *)BOOTLOGO, bmpData.size_x, bmpData.size_y,
bmpData.pos_x, bmpData.pos_y);
}
else
{
gfx_clear_grey(&gfx_ctxt, 0x1B);
gfx_clear_grey(0x1B);
BOOTLOGO = (void *)malloc(0x4000);
blz_uncompress_srcdest(BOOTLOGO_BLZ, SZ_BOOTLOGO_BLZ, BOOTLOGO, SZ_BOOTLOGO);
gfx_set_rect_grey(&gfx_ctxt, BOOTLOGO, X_BOOTLOGO, Y_BOOTLOGO, 326, 544);
gfx_set_rect_grey(BOOTLOGO, X_BOOTLOGO, Y_BOOTLOGO, 326, 544);
}
free(BOOTLOGO);
}
@@ -950,6 +947,48 @@ out:
b_cfg.boot_cfg &= ~(BOOT_CFG_AUTOBOOT_EN | BOOT_CFG_FROM_LAUNCH);
}
void patched_rcm_protection()
{
sdmmc_storage_t storage;
sdmmc_t sdmmc;
h_cfg.rcm_patched = fuse_check_patched_rcm();
if (!h_cfg.rcm_patched)
return;
// Check if AutoRCM is enabled and protect from a permanent brick.
if (!sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4))
return;
u8 *tempbuf = (u8 *)malloc(0x200);
sdmmc_storage_set_mmc_partition(&storage, 1);
u8 corr_mod_byte0;
int i, sect = 0;
if ((fuse_read_odm(4) & 3) != 3)
corr_mod_byte0 = 0xF7;
else
corr_mod_byte0 = 0x37;
for (i = 0; i < 4; i++)
{
sect = (0x200 + (0x4000 * i)) / NX_EMMC_BLOCKSIZE;
sdmmc_storage_read(&storage, sect, 1, tempbuf);
// If AutoRCM is enabled, disable it.
if (tempbuf[0x10] != corr_mod_byte0)
{
tempbuf[0x10] = corr_mod_byte0;
sdmmc_storage_write(&storage, sect, 1, tempbuf);
}
}
free(tempbuf);
sdmmc_storage_end(&storage);
}
void about()
{
static const char credits[] =
@@ -993,12 +1032,12 @@ void about()
" (/` ( (` ) ) '-; %k[switchbrew]%k\n"
" ` '-; (-'%k";
gfx_clear_grey(&gfx_ctxt, 0x1B);
gfx_con_setpos(&gfx_con, 0, 0);
gfx_clear_grey(0x1B);
gfx_con_setpos(0, 0);
gfx_printf(&gfx_con, credits, 0xFF00CCFF, 0xFFCCCCCC);
gfx_printf(credits, 0xFF00CCFF, 0xFFCCCCCC);
gfx_con.fntsz = 8;
gfx_printf(&gfx_con, octopus, 0xFF00CCFF, 0xFF00FFCC, 0xFF00CCFF, 0xFFCCCCCC);
gfx_printf(octopus, 0xFF00CCFF, 0xFF00FFCC, 0xFF00CCFF, 0xFFCCCCCC);
btn_wait();
}
@@ -1086,14 +1125,13 @@ ment_t ment_tools[] = {
MDEF_CHGLINE(),
MDEF_CAPTION("-------- Misc --------", 0xFF0AB9E6),
MDEF_HANDLER("Dump package1/2", dump_packages12),
MDEF_HANDLER("Fix battery de-sync", fix_battery_desync),
MDEF_HANDLER("Fix archive bit (except Nintendo)", fix_sd_all_attr),
MDEF_HANDLER("Fix archive bit (Nintendo only)", fix_sd_nin_attr),
//MDEF_HANDLER("Fix fuel gauge configuration", fix_fuel_gauge_configuration),
//MDEF_HANDLER("Reset all battery cfg", reset_pmic_fuel_gauge_charger_config),
//MDEF_HANDLER("Minerva", minerva), // Uncomment for testing Minerva Training Cell
MDEF_CHGLINE(),
MDEF_CAPTION("------ Dangerous -----", 0xFFFF0000),
MDEF_CAPTION("-------- Other -------", 0xFFFFDD00),
MDEF_HANDLER("AutoRCM", menu_autorcm),
MDEF_END()
};
@@ -1119,7 +1157,7 @@ ment_t ment_top[] = {
};
menu_t menu_top = {
ment_top,
"hekate - CTCaer mod v4.9", 0, 0
"hekate - CTCaer mod v4.10.1", 0, 0
};
#define IPL_STACK_TOP 0x90010000
@@ -1154,23 +1192,29 @@ void ipl_main()
display_init();
u32 *fb = display_init_framebuffer();
gfx_init_ctxt(&gfx_ctxt, fb, 720, 1280, 720);
gfx_init_ctxt(fb, 720, 1280, 720);
#ifdef MENU_LOGO_ENABLE
Kc_MENU_LOGO = (u8 *)malloc(ALIGN(SZ_MENU_LOGO, 0x1000));
blz_uncompress_srcdest(Kc_MENU_LOGO_blz, SZ_MENU_LOGO_BLZ, Kc_MENU_LOGO, SZ_MENU_LOGO);
#endif
gfx_con_init(&gfx_con, &gfx_ctxt);
gfx_con_init();
display_backlight_pwm_init();
//display_backlight_brightness(h_cfg.backlight, 1000);
// Check if we had a panic while in CFW.
secmon_exo_check_panic();
// Check if RCM is patched and protect from a possible brick.
patched_rcm_protection();
// Load saved configuration and auto boot if enabled.
auto_launch_firmware();
while (true)
tui_do_menu(&gfx_con, &menu_top);
tui_do_menu(&menu_top);
while (true)
;

View File

@@ -36,7 +36,7 @@ static void _gf256_mul_x(void *block)
u8 *pdata = (u8 *)block;
u32 carry = 0;
for (u32 i = 0xF; i >= 0; i--)
for (int i = 0xF; i >= 0; i--)
{
u8 b = pdata[i];
pdata[i] = (b << 1) | carry;

View File

@@ -188,10 +188,11 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt)
{
smmu_flush_all();
if (k == se[SE_KEYTABLE_DATA0_REG_OFFSET / 4])
continue;
k = se[SE_KEYTABLE_DATA0_REG_OFFSET / 4];
key[kidx++] = k;
if (k != se[SE_KEYTABLE_DATA0_REG_OFFSET / 4])
{
k = se[SE_KEYTABLE_DATA0_REG_OFFSET / 4];
key[kidx++] = k;
}
// Failsafe.
if ((u32)get_tmr_us() - start > 125000)
@@ -215,16 +216,16 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt)
smmu_deinit_for_tsec();
// for (int i = 0; i < kidx; i++)
// gfx_printf(&gfx_con, "key %08X\n", key[i]);
// gfx_printf("key %08X\n", key[i]);
// gfx_printf(&gfx_con, "cpuctl (%08X) mbox (%08X)\n", TSEC(TSEC_CPUCTL), TSEC(TSEC_STATUS));
// gfx_printf("cpuctl (%08X) mbox (%08X)\n", TSEC(TSEC_CPUCTL), TSEC(TSEC_STATUS));
// u32 errst = MC(MC_ERR_STATUS);
// gfx_printf(&gfx_con, " MC %08X %08X %08X\n", MC(MC_INTSTATUS), errst, MC(MC_ERR_ADR));
// gfx_printf(&gfx_con, " type: %02X\n", errst >> 28);
// gfx_printf(&gfx_con, " smmu: %02X\n", (errst >> 25) & 3);
// gfx_printf(&gfx_con, " dir: %s\n", (errst >> 16) & 1 ? "W" : "R");
// gfx_printf(&gfx_con, " cid: %02x\n", errst & 0xFF);
// gfx_printf(" MC %08X %08X %08X\n", MC(MC_INTSTATUS), errst, MC(MC_ERR_ADR));
// gfx_printf(" type: %02X\n", errst >> 28);
// gfx_printf(" smmu: %02X\n", (errst >> 25) & 3);
// gfx_printf(" dir: %s\n", (errst >> 16) & 1 ? "W" : "R");
// gfx_printf(" cid: %02x\n", errst & 0xFF);
}
else
{

View File

@@ -276,12 +276,16 @@ static void _clock_sdmmc_set_reset(u32 id)
{
case SDMMC_1:
CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = L_SET_SDMMC1_RST;
break;
case SDMMC_2:
CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = L_SET_SDMMC2_RST;
break;
case SDMMC_3:
CLOCK(CLK_RST_CONTROLLER_RST_DEV_U_SET) = U_SET_SDMMC3_RST;
break;
case SDMMC_4:
CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = L_SET_SDMMC4_RST;
break;
}
}
@@ -291,12 +295,16 @@ static void _clock_sdmmc_clear_reset(u32 id)
{
case SDMMC_1:
CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_CLR) = L_CLR_SDMMC1_RST;
break;
case SDMMC_2:
CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_CLR) = L_CLR_SDMMC2_RST;
break;
case SDMMC_3:
CLOCK(CLK_RST_CONTROLLER_RST_DEV_U_CLR) = U_CLR_SDMMC3_RST;
break;
case SDMMC_4:
CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_CLR) = L_CLR_SDMMC4_RST;
break;
}
}
@@ -322,12 +330,16 @@ static void _clock_sdmmc_set_enable(u32 id)
{
case SDMMC_1:
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_SET) = L_SET_CLK_ENB_SDMMC1;
break;
case SDMMC_2:
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_SET) = L_SET_CLK_ENB_SDMMC2;
break;
case SDMMC_3:
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_U_SET) = U_SET_CLK_ENB_SDMMC3;
break;
case SDMMC_4:
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_SET) = L_SET_CLK_ENB_SDMMC4;
break;
}
}
@@ -337,21 +349,27 @@ static void _clock_sdmmc_clear_enable(u32 id)
{
case SDMMC_1:
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_CLR) = L_CLR_CLK_ENB_SDMMC1;
break;
case SDMMC_2:
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_CLR) = L_CLR_CLK_ENB_SDMMC2;
break;
case SDMMC_3:
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_U_CLR) = U_CLR_CLK_ENB_SDMMC3;
break;
case SDMMC_4:
CLOCK(CLK_RST_CONTROLLER_CLK_ENB_L_CLR) = L_CLR_CLK_ENB_SDMMC4;
break;
}
}
static u32 _clock_sdmmc_table[8] = { 0 };
#define PLLP_OUT0 0x0
static int _clock_sdmmc_config_clock_source_inner(u32 *pout, u32 id, u32 val)
{
u32 divisor = 0;
u32 source = 0;
u32 source = PLLP_OUT0;
switch (val)
{
@@ -398,16 +416,16 @@ static int _clock_sdmmc_config_clock_source_inner(u32 *pout, u32 id, u32 val)
switch (id)
{
case SDMMC_1:
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC1) = source | divisor;
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC1) = (source << 29) | divisor;
break;
case SDMMC_2:
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC2) = source | divisor;
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC2) = (source << 29) | divisor;
break;
case SDMMC_3:
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC3) = source | divisor;
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC3) = (source << 29) | divisor;
break;
case SDMMC_4:
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC4) = source | divisor;
CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC4) = (source << 29) | divisor;
break;
}
@@ -457,6 +475,7 @@ void clock_sdmmc_get_params(u32 *pout, u16 *pdivisor, u32 type)
case 5:
*pout = 25000;
*pdivisor = 64;
break;
case 6:
case 8:
*pout = 25000;
@@ -465,9 +484,11 @@ void clock_sdmmc_get_params(u32 *pout, u16 *pdivisor, u32 type)
case 7:
*pout = 50000;
*pdivisor = 1;
break;
case 10:
*pout = 100000;
*pdivisor = 1;
break;
case 13:
*pout = 40800;
*pdivisor = 1;

View File

@@ -2,6 +2,7 @@
* Copyright (c) 2018 naehrwert
* Copyright (c) 2018 shuffle2
* Copyright (c) 2018 balika011
* Copyright (c) 2019 CTCaer
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@@ -61,14 +62,28 @@ u32 fuse_read_odm(u32 idx)
void fuse_wait_idle()
{
u32 ctrl;
do
{
ctrl = FUSE(FUSE_CTRL);
} while (((ctrl >> 16) & 0x1f) != 4);
u32 ctrl;
do
{
ctrl = FUSE(FUSE_CTRL);
} while (((ctrl >> 16) & 0x1f) != 4);
}
u32 parity32_even(u32 *words, u32 count)
u32 fuse_read(u32 addr)
{
FUSE(FUSE_ADDR) = addr;
FUSE(FUSE_CTRL) = (FUSE(FUSE_ADDR) & ~FUSE_CMD_MASK) | FUSE_READ;
fuse_wait_idle();
return FUSE(FUSE_RDATA);
}
void fuse_read_array(u32 *words)
{
for (u32 i = 0; i < 192; i++)
words[i] = fuse_read(i);
}
static u32 _parity32_even(u32 *words, u32 count)
{
u32 acc = words[0];
for (u32 i = 1; i < count; i++)
@@ -81,14 +96,14 @@ u32 parity32_even(u32 *words, u32 count)
lo = ((x & 0xf) ^ (x >> 4)) & 3;
hi = ((x & 0xf) ^ (x >> 4)) >> 2;
x = hi ^ lo;
return (x & 1) ^ (x >> 1);
}
int patch_hash_one(u32 *word)
static int _patch_hash_one(u32 *word)
{
u32 bits20_31 = *word & 0xfff00000;
u32 parity_bit = parity32_even(&bits20_31, 1);
u32 parity_bit = _parity32_even(&bits20_31, 1);
u32 hash = 0;
for (u32 i = 0; i < 12; i++)
{
@@ -121,9 +136,9 @@ int patch_hash_one(u32 *word)
return 2;
}
int patch_hash_multi(u32 *words, u32 count)
static int _patch_hash_multi(u32 *words, u32 count)
{
u32 parity_bit = parity32_even(words, count);
u32 parity_bit = _parity32_even(words, count);
u32 bits0_14 = words[0] & 0x7fff;
u32 bit15 = words[0] & 0x8000;
u32 bits16_19 = words[0] & 0xf0000;
@@ -193,7 +208,7 @@ int fuse_read_ipatch(void (*ipatch)(u32 offset, u32 value))
u32 total_read = 0;
word_count = FUSE(FUSE_FIRST_BOOTROM_PATCH_SIZE);
word_count &= 0x7f;
word_count &= 0x7F;
word_addr = 191;
while (word_count)
@@ -205,26 +220,21 @@ int fuse_read_ipatch(void (*ipatch)(u32 offset, u32 value))
}
for (u32 i = 0; i < word_count; i++)
{
FUSE(FUSE_ADDR) = word_addr--;
FUSE(FUSE_CTRL) = (FUSE(FUSE_ADDR) & ~FUSE_CMD_MASK) | FUSE_READ;
fuse_wait_idle();
words[i] = FUSE(FUSE_RDATA);
}
words[i] = fuse_read(word_addr--);
word0 = words[0];
if (patch_hash_multi(words, word_count) >= 2)
if (_patch_hash_multi(words, word_count) >= 2)
{
return 1;
}
u32 ipatch_count = (words[0] >> 16) & 0xf;
u32 ipatch_count = (words[0] >> 16) & 0xF;
if (ipatch_count)
{
for (u32 i = 0; i < ipatch_count; i++)
{
u32 word = words[i + 1];
u32 addr = (word >> 16) * 2;
u32 data = word & 0xffff;
u32 data = word & 0xFFFF;
ipatch(addr, data);
}
@@ -232,7 +242,7 @@ int fuse_read_ipatch(void (*ipatch)(u32 offset, u32 value))
words[0] = word0;
if ((word0 >> 25) == 0)
break;
if (patch_hash_one(&word0) >= 2)
if (_patch_hash_one(&word0) >= 2)
{
return 3;
}
@@ -255,7 +265,7 @@ int fuse_read_evp_thunk(u32 *iram_evp_thunks, u32 *iram_evp_thunks_len)
memset(iram_evp_thunks, 0, *iram_evp_thunks_len);
word_count = FUSE(FUSE_FIRST_BOOTROM_PATCH_SIZE);
word_count &= 0x7f;
word_count &= 0x7F;
word_addr = 191;
while (word_count)
@@ -267,19 +277,14 @@ int fuse_read_evp_thunk(u32 *iram_evp_thunks, u32 *iram_evp_thunks_len)
}
for (u32 i = 0; i < word_count; i++)
{
FUSE(FUSE_ADDR) = word_addr--;
FUSE(FUSE_CTRL) = (FUSE(FUSE_ADDR) & ~FUSE_CMD_MASK) | FUSE_READ;
fuse_wait_idle();
words[i] = FUSE(FUSE_RDATA);
}
words[i] = fuse_read(word_addr--);
word0 = words[0];
if (patch_hash_multi(words, word_count) >= 2)
if (_patch_hash_multi(words, word_count) >= 2)
{
return 1;
}
u32 ipatch_count = (words[0] >> 16) & 0xf;
u32 ipatch_count = (words[0] >> 16) & 0xF;
u32 insn_count = word_count - ipatch_count - 1;
if (insn_count)
{
@@ -303,7 +308,7 @@ int fuse_read_evp_thunk(u32 *iram_evp_thunks, u32 *iram_evp_thunks_len)
words[0] = word0;
if ((word0 >> 25) == 0)
break;
if (patch_hash_one(&word0) >= 2)
if (_patch_hash_one(&word0) >= 2)
{
return 3;
}
@@ -313,13 +318,32 @@ int fuse_read_evp_thunk(u32 *iram_evp_thunks, u32 *iram_evp_thunks_len)
return 0;
}
void read_raw_ipatch_fuses(u32 *words)
bool fuse_check_patched_rcm()
{
for (u32 i = 0; i < 0x100; i++)
// Check if XUSB in use.
if (FUSE(FUSE_RESERVED_SW) & (1<<7))
return true;
// Check if RCM is ipatched.
u32 word_count = FUSE(FUSE_FIRST_BOOTROM_PATCH_SIZE) & 0x7F;
u32 word_addr = 191;
while (word_count)
{
FUSE(FUSE_ADDR) = i;
FUSE(FUSE_CTRL) = (FUSE(FUSE_ADDR) & ~FUSE_CMD_MASK) | FUSE_READ;
fuse_wait_idle();
words[i] = FUSE(FUSE_RDATA);
u32 word0 = fuse_read(word_addr);
u32 ipatch_count = (word0 >> 16) & 0xF;
for (u32 i = 0; i < ipatch_count; i++)
{
u32 word = fuse_read(word_addr - (i + 1));
u32 addr = (word >> 16) * 2;
if (addr == 0x769A)
return true;
}
word_addr -= word_count;
word_count = word0 >> 25;
}
}
return false;
}

View File

@@ -42,6 +42,7 @@
#define FUSE_PRIVATE_KEY1 0x1A8
#define FUSE_PRIVATE_KEY2 0x1AC
#define FUSE_PRIVATE_KEY3 0x1B0
#define FUSE_RESERVED_SW 0x1C0
/*! Fuse commands. */
#define FUSE_READ 0x1
@@ -57,6 +58,7 @@ u32 fuse_read_odm(u32 idx);
void fuse_wait_idle();
int fuse_read_ipatch(void (*ipatch)(u32 offset, u32 value));
int fuse_read_evp_thunk(u32 *iram_evp_thunks, u32 *iram_evp_thunks_len);
void read_raw_ipatch_fuses(u32 *words);
void fuse_read_array(u32 *words);
bool fuse_check_patched_rcm();
#endif

View File

@@ -18,6 +18,14 @@
#include <string.h>
#include "hw_init.h"
#include "clock.h"
#include "fuse.h"
#include "gpio.h"
#include "i2c.h"
#include "pinmux.h"
#include "pmc.h"
#include "t210.h"
#include "uart.h"
#include "../gfx/di.h"
#include "../mem/mc.h"
#include "../mem/sdram.h"
@@ -25,14 +33,6 @@
#include "../power/max7762x.h"
#include "../sec/se.h"
#include "../sec/se_t210.h"
#include "../soc/clock.h"
#include "../soc/fuse.h"
#include "../soc/gpio.h"
#include "../soc/i2c.h"
#include "../soc/pinmux.h"
#include "../soc/pmc.h"
#include "../soc/t210.h"
#include "../soc/uart.h"
#include "../storage/sdmmc.h"
#include "../utils/util.h"
@@ -239,6 +239,9 @@ void config_hw()
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_GPIO5, 2);
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_GPIO6, 2);
// Disable low battery shutdown monitor.
max77620_low_battery_monitor_config();
_config_pmc_scratch(); // Missing from 4.x+
CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) = (CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY) & 0xFFFF8888) | 0x3333;

View File

@@ -179,6 +179,10 @@
#define I2S_CG_SLCG_ENABLE (1 << 0)
#define I2S_CTRL_MASTER_EN (1 << 10)
/*! PWM registers. */
#define PWM_CONTROLLER_PWM_CSR_0 0x00
#define PWM_CONTROLLER_PWM_CSR_1 0x10
/*! Special registers. */
#define EMC_SCRATCH0 0x324
#define EMC_HEKA_UPD (1 << 30)

View File

@@ -59,7 +59,7 @@ typedef struct _emmc_part_t
u32 lba_start;
u32 lba_end;
u64 attrs;
s8 name[37];
char name[37];
link_t link;
} emmc_part_t;

View File

@@ -19,13 +19,16 @@
#include "sdmmc.h"
#include "mmc.h"
#include "sd.h"
#include "../config/config.h"
#include "../gfx/gfx.h"
#include "../mem/heap.h"
#include "../utils/util.h"
//#define DPRINTF(...) gfx_printf(&gfx_con, __VA_ARGS__)
//#define DPRINTF(...) gfx_printf(__VA_ARGS__)
#define DPRINTF(...)
extern hekate_config h_cfg;
static inline u32 unstuff_bits(u32 *resp, u32 start, u32 size)
{
const u32 mask = (size < 32 ? 1 << size : 0) - 1;
@@ -425,7 +428,7 @@ static int _mmc_storage_enable_HS400(sdmmc_storage_t *storage)
static int _mmc_storage_enable_highspeed(sdmmc_storage_t *storage, u32 card_type, u32 type)
{
//TODO: this should be a config item.
//---v
// --v
if (!1 || sdmmc_get_voltage(storage->sdmmc) != SDMMC_POWER_1_8)
goto out;
@@ -519,7 +522,7 @@ int sdmmc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32
free(ext_csd);
DPRINTF("[MMC] got ext_csd\n");
_mmc_storage_parse_cid(storage); //This needs to be after csd and ext_csd
//gfx_hexdump(&gfx_con, 0, ext_csd, 512);
//gfx_hexdump(0, ext_csd, 512);
/* When auto BKOPS is enabled the mmc device should be powered all the time until we disable this and check status.
Disable it for now until BKOPS disable added to power down sequence at sdmmc_storage_end().
@@ -530,7 +533,9 @@ int sdmmc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32
DPRINTF("[MMC] BKOPS enabled\n");
}
else
{
DPRINTF("[MMC] BKOPS disabled\n");
}
if (!_mmc_storage_enable_highspeed(storage, storage->ext_csd.card_type, type))
return 0;
@@ -704,7 +709,7 @@ int _sd_storage_get_scr(sdmmc_storage_t *storage, u8 *buf)
u32 tmp = 0;
sdmmc_get_rsp(storage->sdmmc, &tmp, 4, SDMMC_RSP_TYPE_1);
//Prepare buffer for unstuff_bits
//Prepare buffer for unstuff_bits
for (int i = 0; i < 8; i+=4)
{
storage->raw_scr[i + 3] = buf[i];
@@ -713,7 +718,7 @@ int _sd_storage_get_scr(sdmmc_storage_t *storage, u8 *buf)
storage->raw_scr[i] = buf[i + 3];
}
_sd_storage_parse_scr(storage);
//gfx_hexdump(&gfx_con, 0, storage->raw_scr, 8);
//gfx_hexdump(0, storage->raw_scr, 8);
return _sdmmc_storage_check_result(tmp);
}
@@ -825,12 +830,13 @@ int _sd_storage_enable_highspeed_low_volt(sdmmc_storage_t *storage, u32 type, u8
if (!_sd_storage_switch_get(storage, buf))
return 0;
//gfx_hexdump(&gfx_con, 0, (u8 *)buf, 64);
//gfx_hexdump(0, (u8 *)buf, 64);
u32 hs_type = 0;
switch (type)
{
case 11:
// Fall through if not supported.
if (buf[13] & SD_MODE_UHS_SDR104)
{
type = 11;
@@ -839,7 +845,6 @@ int _sd_storage_enable_highspeed_low_volt(sdmmc_storage_t *storage, u32 type, u8
storage->csd.busspeed = 104;
break;
}
//Fall through.
case 10:
if (buf[13] & SD_MODE_UHS_SDR50)
{
@@ -875,8 +880,8 @@ int _sd_storage_enable_highspeed_high_volt(sdmmc_storage_t *storage, u8 *buf)
{
if (!_sd_storage_switch_get(storage, buf))
return 0;
//gfx_hexdump(&gfx_con, 0, (u8 *)buf, 64);
if (!(buf[13] & 2))
//gfx_hexdump(0, (u8 *)buf, 64);
if (!(buf[13] & SD_MODE_HIGH_SPEED))
return 1;
if (!_sd_storage_enable_highspeed(storage, 1, buf))
@@ -963,7 +968,7 @@ static int _sd_storage_get_ssr(sdmmc_storage_t *storage, u8 *buf)
storage->raw_ssr[i] = buf[i + 3];
}
_sd_storage_parse_ssr(storage);
//gfx_hexdump(&gfx_con, 0, storage->raw_ssr, 64);
//gfx_hexdump(0, storage->raw_ssr, 64);
return _sdmmc_storage_check_result(tmp);
}
@@ -1010,6 +1015,11 @@ static void _sd_storage_parse_csd(sdmmc_storage_t *storage)
int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32 bus_width, u32 type)
{
int is_version_1 = 0;
// Some cards (Sandisk U1), do not like a fast power cycle. Wait min 100ms.
u32 sd_poweroff_time = (u32)get_tmr_ms() - h_cfg.sd_timeoff;
if (id == SDMMC_1 && (sd_poweroff_time < 100))
msleep(100 - sd_poweroff_time);
memset(storage, 0, sizeof(sdmmc_storage_t));
storage->sdmmc = sdmmc;
@@ -1088,7 +1098,7 @@ int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32
return 0;
}
//gfx_hexdump(&gfx_con, 0, storage->raw_scr, 8);
//gfx_hexdump(0, storage->raw_scr, 8);
DPRINTF("[SD] got scr\n");
// Check if card supports a wider bus and if it's not SD Version 1.X
@@ -1103,7 +1113,9 @@ int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32
DPRINTF("[SD] switched to wide bus width\n");
}
else
{
DPRINTF("[SD] SD does not support wide bus width\n");
}
if (storage->is_low_voltage)
{
@@ -1129,7 +1141,9 @@ int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32
// Parse additional card info from sd status.
if (_sd_storage_get_ssr(storage, buf))
{
DPRINTF("[SD] got sd status\n");
}
free(buf);
return 1;

View File

@@ -47,7 +47,7 @@ typedef struct _mmc_csd
u32 read_blkbits;
u32 write_blkbits;
u32 capacity;
u8 write_protect;
u8 write_protect;
u16 busspeed;
} mmc_csd_t;

View File

@@ -19,6 +19,7 @@
#include "mmc.h"
#include "sdmmc.h"
#include "../config/config.h"
#include "../gfx/gfx.h"
#include "../power/max7762x.h"
#include "../soc/clock.h"
@@ -28,9 +29,11 @@
#include "../soc/t210.h"
#include "../utils/util.h"
//#define DPRINTF(...) gfx_printf(&gfx_con, __VA_ARGS__)
//#define DPRINTF(...) gfx_printf(__VA_ARGS__)
#define DPRINTF(...)
extern hekate_config h_cfg;
/*! SCMMC controller base addresses. */
static const u32 _sdmmc_bases[4] = {
0x700B0000,
@@ -116,7 +119,7 @@ static int _sdmmc_config_ven_ceata_clk(sdmmc_t *sdmmc, u32 id)
if (id == 4)
sdmmc->regs->venceatactl = (sdmmc->regs->venceatactl & 0xFFFFC0FF) | 0x2800;
sdmmc->regs->field_1C0 &= 0xFFFDFFFF;
sdmmc->regs->ventunctl0 &= 0xFFFDFFFF;
if (id == 4)
{
if (!sdmmc->venclkctl_set)
@@ -168,11 +171,11 @@ static int _sdmmc_wait_type4(sdmmc_t *sdmmc)
sdmmc->regs->clkcon |= TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE;
}
sdmmc->regs->field_1B0 |= 0x80000000;
sdmmc->regs->vendllcal |= 0x80000000;
_sdmmc_get_clkcon(sdmmc);
u32 timeout = get_tmr_ms() + 5;
while (sdmmc->regs->field_1B0 & 0x80000000)
while (sdmmc->regs->vendllcal & 0x80000000)
{
if (get_tmr_ms() > timeout)
{
@@ -182,7 +185,7 @@ static int _sdmmc_wait_type4(sdmmc_t *sdmmc)
}
timeout = get_tmr_ms() + 10;
while (sdmmc->regs->field_1BC & 0x80000000)
while (sdmmc->regs->dllcfgstatus & 0x80000000)
{
if (get_tmr_ms() > timeout)
{
@@ -561,9 +564,9 @@ int sdmmc_config_tuning(sdmmc_t *sdmmc, u32 type, u32 cmd)
return 0;
}
sdmmc->regs->field_1C0 = (sdmmc->regs->field_1C0 & 0xFFFF1FFF) | flag;
sdmmc->regs->field_1C0 = (sdmmc->regs->field_1C0 & 0xFFFFE03F) | 0x40;
sdmmc->regs->field_1C0 |= 0x20000;
sdmmc->regs->ventunctl0 = (sdmmc->regs->ventunctl0 & 0xFFFF1FFF) | flag;
sdmmc->regs->ventunctl0 = (sdmmc->regs->ventunctl0 & 0xFFFFE03F) | 0x40;
sdmmc->regs->ventunctl0 |= 0x20000;
sdmmc->regs->hostctl2 |= SDHCI_CTRL_EXEC_TUNING;
for (u32 i = 0; i < max; i++)
@@ -1000,8 +1003,8 @@ int sdmmc_init(sdmmc_t *sdmmc, u32 id, u32 power, u32 bus_width, u32 type, int n
sdmmc->clock_stopped = 0;
//TODO: make this skip-able.
sdmmc->regs->field_1F0 |= 0x80000;
sdmmc->regs->field_1AC &= 0xFFFFFFFB;
sdmmc->regs->iospare |= 0x80000;
sdmmc->regs->veniotrimctl &= 0xFFFFFFFB;
static const u32 trim_values[] = { 2, 8, 3, 8 };
sdmmc->regs->venclkctl = (sdmmc->regs->venclkctl & 0xE0FFFFFF) | (trim_values[sdmmc->id] << 24);
sdmmc->regs->sdmemcmppadctl = (sdmmc->regs->sdmemcmppadctl & 0xF) | 7;
@@ -1036,7 +1039,9 @@ void sdmmc_end(sdmmc_t *sdmmc)
if (sdmmc->id == SDMMC_1)
{
gpio_output_enable(GPIO_PORT_E, GPIO_PIN_4, GPIO_OUTPUT_DISABLE);
msleep(1); // To power cycle min 1ms without power is needed.
max77620_regulator_enable(REGULATOR_LDO2, 0);
h_cfg.sd_timeoff = get_tmr_ms(); // Some sandisc U1 cards need 100ms for a power cycle.
msleep(1); // To power cycle, min 1ms without power is needed.
}
_sdmmc_get_clkcon(sdmmc);

View File

@@ -115,18 +115,18 @@ typedef struct _t210_sdmmc_t
vu32 vendebouncecnt;
vu32 venmiscctl;
vu32 res6[34];
vu32 field_1AC;
vu32 field_1B0;
vu32 veniotrimctl;
vu32 vendllcal;
vu8 res7[8];
vu32 field_1BC;
vu32 field_1C0;
vu32 dllcfgstatus;
vu32 ventunctl0;
vu32 field_1C4;
vu8 field_1C8[24];
vu32 sdmemcmppadctl;
vu32 autocalcfg;
vu32 autocalintval;
vu32 autocalsts;
vu32 field_1F0;
vu32 iospare;
} t210_sdmmc_t;
#endif

View File

@@ -74,6 +74,7 @@ char *dirlist(const char *directory, const char *pattern, bool includeHiddenFile
return NULL;
}
// Reorder ini files by ASCII ordering.
for (i = 0; i < k - 1 ; i++)
{
for (j = i + 1; j < k; j++)

View File

@@ -26,7 +26,7 @@
#define OFFSET_OF(t, m) ((u32)&((t *)NULL)->m)
#define CONTAINER_OF(mp, t, mn) ((t *)((u32)mp - OFFSET_OF(t, mn)))
typedef char s8;
typedef signed char s8;
typedef short s16;
typedef short SHORT;
typedef int s32;

View File

@@ -106,17 +106,3 @@ void power_off()
//TODO: we should probably make sure all regulators are powered off properly.
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_ONOFFCNFG1, MAX77620_ONOFFCNFG1_PWR_OFF);
}
#define CRC32C_POLY 0x82F63B78
u32 crc32c(const void *buf, u32 len)
{
const u8 *cbuf = (const u8 *)buf;
u32 crc = 0xFFFFFFFF;
while (len--)
{
crc ^= *cbuf++;
for (int i = 0; i < 8; i++)
crc = crc & 1 ? (crc >> 1) ^ CRC32C_POLY : crc >> 1;
}
return ~crc;
}

View File

@@ -39,6 +39,5 @@ void reboot_normal();
void reboot_rcm();
void power_off();
void exec_cfg(u32 *base, const cfg_op_t *ops, u32 num_ops);
u32 crc32c(const void *buf, u32 len);
#endif

View File

@@ -1,46 +1,59 @@
[config]
autoboot=5
autoboot=4
autoboot_list=0
bootwait=3
customlogo=1
verification=2
verification=1
backlight=100
autohosoff=0
autonogc=1
{-------- Stock -------}
[Stock]
[Stock 6.2.0 and lower]
stock=1
[Stock (SVC perms)]
fullsvcperm=1
debugmode=1
[Stock (Prevent GC access)]
kip1patch=nogc
[Stock (Allow unsigned NCA)]
kip1patch=nosigchk
[Stock All FW]
fss0=atmosphere/fusee-secondary.bin
stock=1
{ }
# Both above disable kernel patching
# Stock All FW, includes exosphere and warmboot, ONLY when >= 7.0.0.
{-- Custom Firmwares --}
[AtmoHB]
kip1=cfw/loader.kip1
kip1=cfw/sm.kip1
[Atmo FSS0 Vanilla]
fss0=atmosphere/fusee-secondary.bin
logopath=cfw/atmo.bmp
[AtmoHB (SVC Perms)]
kip1=cfw/loader.kip1
kip1=cfw/sm.kip1
fullsvcperm=1
[CFW FSS0 extra kips]
fss0=atmosphere/fusee-secondary.bin
kip1=cfw/mods/mods_extra/*
kip1=cfw/mods/mods_extra/single/extra.kip
logopath=cfw/cfw.bmp
# Both options for kip1 can be used. Wildcard and single.
[Atmosphere Full]
secmon=cfw/atmo/exosphere.bin
kip1=cfw/atmo/loader.kip
kip1=cfw/atmo/sm.kip
kip1=cfw/atmo/fs_mitm.kip
logopath=cfw/atmo/atmo.bmp
[Atmo Vanilla]
secmon=cfw/mods/exosphere.bin
warmboot=cfw/mods/lp0fw.bin
kip1=cfw/mods/loader.kip
kip1=cfw/mods/sm.kip
kip1=cfw/mods/pm.kip
kip1=cfw/mods/ams_mitm.kip
logopath=cfw/atmo.bmp
atmosphere=1
# kip1=cfw/atmo/pm.kip
# All kips defined.
[CFW Extra kips]
secmon=cfw/mods/exosphere.bin
warmboot=cfw/mods/lp0fw.bin
kip1=cfw/mods/*
kip1=cfw/mods/extra/extra.kip
logopath=cfw/cfw.bmp
atmosphere=1
# All kips parsed from a directory and extra added.
{ }
{------- Tools -------}
[Clear Error Logs]
kip1=cfw/nx-dreport.kip
[memloader]
payload=bootloader/payloads/memloader.bin
# hekate - CTCaer mod v3.0 .ini template
# hekate - CTCaer mod v4.9.1 .ini template