From 4c4a6511f3c0cd9bdef44244813ac191c084484c Mon Sep 17 00:00:00 2001 From: "Such Meme, Many Skill" Date: Thu, 23 Apr 2020 13:54:48 +0200 Subject: [PATCH] Merge hekate changes https://github.com/shchmue/Lockpick_RCM/commit/25ff127404b12bdffb5588d426bb4f538db77fbe --- source/config/config.c | 104 ++++++++++-------------------------- source/config/config.h | 8 +-- source/config/ini.c | 19 ++++--- source/hos/pkg2.c | 35 ++++++++++-- source/hos/pkg2.h | 6 +-- source/main.c | 15 ++++-- source/mem/heap.c | 46 ++++++++++------ source/mem/heap.h | 1 + source/mem/minerva.c | 5 +- source/mem/sdram.c | 3 +- source/power/max17050.h | 9 +++- source/power/max7762x.c | 5 +- source/power/max7762x.h | 4 +- source/rtc/max77620-rtc.c | 94 +++++++++++++++++++++++++++++++- source/rtc/max77620-rtc.h | 2 + source/soc/hw_init.c | 31 +++++++---- source/soc/i2c.c | 8 ++- source/soc/i2c.h | 2 + source/storage/nx_emmc.c | 2 +- source/utils/aarch64_util.h | 12 +++-- source/utils/list.h | 6 ++- source/utils/util.h | 11 +++- 22 files changed, 273 insertions(+), 155 deletions(-) diff --git a/source/config/config.c b/source/config/config.c index 38e5bcf..23b516f 100644 --- a/source/config/config.c +++ b/source/config/config.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018-2019 CTCaer + * Copyright (c) 2018-2020 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -37,12 +37,12 @@ void set_default_configuration() h_cfg.autoboot = 0; h_cfg.autoboot_list = 0; h_cfg.bootwait = 3; - h_cfg.verification = 1; h_cfg.se_keygen_done = 0; h_cfg.sbar_time_keeping = 0; h_cfg.backlight = 100; h_cfg.autohosoff = 0; h_cfg.autonogc = 1; + h_cfg.updater2p = 0; h_cfg.brand = NULL; h_cfg.tagline = NULL; h_cfg.errors = 0; @@ -50,7 +50,7 @@ void set_default_configuration() h_cfg.rcm_patched = true; h_cfg.emummc_force_disable = false; - sd_power_cycle_time_start = 0xFFFFFFF; + sd_power_cycle_time_start = 0; } int create_config_entry() @@ -96,9 +96,6 @@ int create_config_entry() f_puts("\nbootwait=", &fp); itoa(h_cfg.bootwait, lbuf, 10); f_puts(lbuf, &fp); - f_puts("\nverification=", &fp); - itoa(h_cfg.verification, lbuf, 10); - f_puts(lbuf, &fp); f_puts("\nbacklight=", &fp); itoa(h_cfg.backlight, lbuf, 10); f_puts(lbuf, &fp); @@ -108,6 +105,9 @@ int create_config_entry() f_puts("\nautonogc=", &fp); itoa(h_cfg.autonogc, lbuf, 10); f_puts(lbuf, &fp); + f_puts("\nupdater2p=", &fp); + itoa(h_cfg.updater2p, lbuf, 10); + f_puts(lbuf, &fp); if (h_cfg.brand) { f_puts("\nbrand=", &fp); @@ -281,10 +281,11 @@ void config_autoboot() LIST_INIT(ini_sections); u8 max_entries = 30; + u32 boot_text_size = 512; ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * (max_entries + 5)); u32 *boot_values = (u32 *)malloc(sizeof(u32) * max_entries); - char *boot_text = (char *)malloc(512 * max_entries); + char *boot_text = (char *)malloc(boot_text_size * max_entries); for (u32 j = 0; j < max_entries; j++) boot_values[j] = j; @@ -330,12 +331,12 @@ void config_autoboot() else { if (h_cfg.autoboot != (i - 4) || h_cfg.autoboot_list) - boot_text[(i - 4) * 512] = ' '; + boot_text[(i - 4) * boot_text_size] = ' '; else - boot_text[(i - 4) * 512] = '*'; - strcpy(boot_text + (i - 4) * 512 + 1, ini_sec->name); - ments[i].caption = &boot_text[(i - 4) * 512]; + boot_text[(i - 4) * boot_text_size] = '*'; + strcpy(boot_text + (i - 4) * boot_text_size + 1, ini_sec->name); + ments[i].caption = &boot_text[(i - 4) * boot_text_size]; } ments[i].type = ini_sec->type; ments[i].data = &boot_values[i - 4]; @@ -391,10 +392,11 @@ void config_bootdelay() gfx_con_setpos(0, 0); u32 delay_entries = 6; + u32 delay_text_size = 32; ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * (delay_entries + 3)); u32 *delay_values = (u32 *)malloc(sizeof(u32) * delay_entries); - char *delay_text = (char *)malloc(32 * delay_entries); + char *delay_text = (char *)malloc(delay_text_size * delay_entries); for (u32 j = 0; j < delay_entries; j++) delay_values[j] = j; @@ -415,14 +417,14 @@ void config_bootdelay() for (i = 1; i < delay_entries; i++) { if (h_cfg.bootwait != i) - delay_text[i * 32] = ' '; + delay_text[i * delay_text_size] = ' '; else - delay_text[i * 32] = '*'; - delay_text[i * 32 + 1] = i + '0'; - strcpy(delay_text + i * 32 + 2, " seconds"); + delay_text[i * delay_text_size] = '*'; + delay_text[i * delay_text_size + 1] = i + '0'; + strcpy(delay_text + i * delay_text_size + 2, " seconds"); ments[i + 2].type = MENT_DATA; - ments[i + 2].caption = delay_text + i * 32; + ments[i + 2].caption = delay_text + (i * delay_text_size); ments[i + 2].data = &delay_values[i]; } @@ -445,69 +447,17 @@ void config_bootdelay() btn_wait(); } -void config_verification() -{ - 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); - char *vr_text = (char *)malloc(64 * 3); - - for (u32 j = 0; j < 3; j++) - { - vr_values[j] = j; - ments[j + 2].type = MENT_DATA; - ments[j + 2].data = &vr_values[j]; - } - - ments[0].type = MENT_BACK; - ments[0].caption = "Back"; - - ments[1].type = MENT_CHGLINE; - - strcpy(vr_text, " Disable (Fastest - Unsafe)"); - strcpy(vr_text + 64, " Sparse (Fast - Safe)"); - strcpy(vr_text + 128, " Full (Slow - Safe)"); - - for (u32 i = 0; i < 3; i++) - { - if (h_cfg.verification != i) - vr_text[64 * i] = ' '; - else - vr_text[64 * i] = '*'; - ments[2 + i].caption = vr_text + (i * 64); - } - - memset(&ments[5], 0, sizeof(ment_t)); - menu_t menu = {ments, "Backup & Restore verification", 0, 0}; - - u32 *temp_verification = (u32 *)tui_do_menu(&menu); - if (temp_verification != NULL) - { - h_cfg.verification = *(u32 *)temp_verification; - _save_config(); - } - - free(ments); - free(vr_values); - free(vr_text); - - if (temp_verification == NULL) - return; - btn_wait(); -} - void config_backlight() { gfx_clear_grey(0x1B); gfx_con_setpos(0, 0); + u32 bri_text_size = 8; u32 bri_entries = 11; ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * (bri_entries + 3)); u32 *bri_values = (u32 *)malloc(sizeof(u32) * bri_entries); - char *bri_text = (char *)malloc(8 * bri_entries); + char *bri_text = (char *)malloc(bri_text_size * bri_entries); for (u32 j = 1; j < bri_entries; j++) bri_values[j] = j * 10; @@ -521,20 +471,20 @@ void config_backlight() for (i = 1; i < bri_entries; i++) { if ((h_cfg.backlight / 20) != i) - bri_text[i * 32] = ' '; + bri_text[i * bri_text_size] = ' '; else - bri_text[i * 32] = '*'; + bri_text[i * bri_text_size] = '*'; if (i < 10) { - bri_text[i * 32 + 1] = i + '0'; - strcpy(bri_text + i * 32 + 2, "0%"); + bri_text[i * bri_text_size + 1] = i + '0'; + strcpy(bri_text + i * bri_text_size + 2, "0%"); } else - strcpy(bri_text + i * 32 + 1, "100%"); + strcpy(bri_text + i * bri_text_size + 1, "100%"); ments[i + 1].type = MENT_DATA; - ments[i + 1].caption = bri_text + i * 32; + ments[i + 1].caption = bri_text + (i * bri_text_size); ments[i + 1].data = &bri_values[i]; } diff --git a/source/config/config.h b/source/config/config.h index 8cd34e1..0410a7e 100644 --- a/source/config/config.h +++ b/source/config/config.h @@ -25,10 +25,10 @@ typedef struct _hekate_config u32 autoboot; u32 autoboot_list; u32 bootwait; - u32 verification; u32 backlight; u32 autohosoff; u32 autonogc; + u32 updater2p; char *brand; char *tagline; // Global temporary config. @@ -40,16 +40,10 @@ typedef struct _hekate_config u32 errors; } hekate_config; -typedef enum -{ - ERR_LIBSYS_LP0 = (1 << 0), -} hsysmodule_t; - void set_default_configuration(); int create_config_entry(); void config_autoboot(); void config_bootdelay(); -void config_verification(); void config_backlight(); void config_auto_hos_poweroff(); void config_nogc(); diff --git a/source/config/ini.c b/source/config/ini.c index e807aec..85a19b1 100644 --- a/source/config/ini.c +++ b/source/config/ini.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2018 naehrwert - * Copyright (c) 2018-2019 CTCaer + * Copyright (c) 2018-2020 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, @@ -44,7 +44,8 @@ static char *_strdup(char *str) u32 _find_section_name(char *lbuf, u32 lblen, char schar) { u32 i; - for (i = 0; i < lblen && lbuf[i] != schar && lbuf[i] != '\n' && lbuf[i] != '\r'; i++) + // Depends on 'FF_USE_STRFUNC 2' that removes \r. + for (i = 0; i < lblen && lbuf[i] != schar && lbuf[i] != '\n'; i++) ; lbuf[i] = 0; @@ -123,8 +124,8 @@ int ini_parse(link_t *dst, char *ini_path, bool is_dir) f_gets(lbuf, 512, &fp); lblen = strlen(lbuf); - // Remove trailing newline. - if (lbuf[lblen - 1] == '\n' || lbuf[lblen - 1] == '\r') + // Remove trailing newline. Depends on 'FF_USE_STRFUNC 2' that removes \r. + if (lblen && lbuf[lblen - 1] == '\n') lbuf[lblen - 1] = 0; if (lblen > 2 && lbuf[0] == '[') // Create new section. @@ -134,24 +135,22 @@ int ini_parse(link_t *dst, char *ini_path, bool is_dir) csec = _ini_create_section(dst, csec, &lbuf[1], INI_CHOICE); list_init(&csec->kvs); } - else if (lblen > 2 && lbuf[0] == '{') //Create new caption. + else if (lblen > 1 && lbuf[0] == '{') // Create new caption. Support empty caption '{}'. { _find_section_name(lbuf, lblen, '}'); csec = _ini_create_section(dst, csec, &lbuf[1], INI_CAPTION); csec->color = 0xFF0AB9E6; } - else if (lblen > 2 && lbuf[0] == '#') //Create empty lines and comments. + else if (lblen > 2 && lbuf[0] == '#') // Create comment. { - _find_section_name(lbuf, lblen, '\0'); - csec = _ini_create_section(dst, csec, &lbuf[1], INI_COMMENT); } - else if (lblen < 2) + else if (lblen < 2) // Create empty line. { csec = _ini_create_section(dst, csec, NULL, INI_NEWLINE); } - else if (csec && csec->type == INI_CHOICE) //Extract key/value. + else if (csec && csec->type == INI_CHOICE) // Extract key/value. { u32 i = _find_section_name(lbuf, lblen, '='); diff --git a/source/hos/pkg2.c b/source/hos/pkg2.c index e745cbc..bc77d1e 100644 --- a/source/hos/pkg2.c +++ b/source/hos/pkg2.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2018 naehrwert - * Copyright (c) 2018-2019 CTCaer + * Copyright (c) 2018-2020 CTCaer * Copyright (c) 2018 Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it @@ -41,14 +41,34 @@ static u32 _pkg2_calc_kip1_size(pkg2_kip1_t *kip1) void pkg2_get_newkern_info(u8 *kern_data) { - u32 info_op = *(u32 *)(kern_data + PKG2_NEWKERN_GET_INI1); - pkg2_newkern_ini1_val = ((info_op & 0xFFFF) >> 3) + PKG2_NEWKERN_GET_INI1; // Parse ADR and PC. + u32 pkg2_newkern_ini1_off = 0; + pkg2_newkern_ini1_start = 0; + + // Find static OP offset that is close to INI1 offset. + u32 counter_ops = 0x100; + while (counter_ops) + { + if (*(u32 *)(kern_data + 0x100 - counter_ops) == PKG2_NEWKERN_GET_INI1_HEURISTIC) + { + pkg2_newkern_ini1_off = 0x100 - counter_ops + 12; // OP found. Add 12 for the INI1 offset. + break; + } + + counter_ops -= 4; + } + + // Offset not found? + if (!counter_ops) + return; + + u32 info_op = *(u32 *)(kern_data + pkg2_newkern_ini1_off); + pkg2_newkern_ini1_val = ((info_op & 0xFFFF) >> 3) + pkg2_newkern_ini1_off; // Parse ADR and PC. pkg2_newkern_ini1_start = *(u32 *)(kern_data + pkg2_newkern_ini1_val); pkg2_newkern_ini1_end = *(u32 *)(kern_data + pkg2_newkern_ini1_val + 0x8); -} + } -void pkg2_parse_kips(link_t *info, pkg2_hdr_t *pkg2, bool *new_pkg2) +bool pkg2_parse_kips(link_t *info, pkg2_hdr_t *pkg2, bool *new_pkg2) { u8 *ptr; // Check for new pkg2 type. @@ -56,6 +76,9 @@ void pkg2_parse_kips(link_t *info, pkg2_hdr_t *pkg2, bool *new_pkg2) { pkg2_get_newkern_info(pkg2->data); + if (!pkg2_newkern_ini1_start) + return false; + ptr = pkg2->data + pkg2_newkern_ini1_start; *new_pkg2 = true; } @@ -75,6 +98,8 @@ void pkg2_parse_kips(link_t *info, pkg2_hdr_t *pkg2, bool *new_pkg2) ptr += ki->size; DPRINTF(" kip1 %d:%s @ %08X (%08X)\n", i, kip1->name, (u32)kip1, ki->size); } + + return true; } int pkg2_decompress_kip(pkg2_kip1_info_t* ki, u32 sectsToDecomp) diff --git a/source/hos/pkg2.h b/source/hos/pkg2.h index 0cb9962..ba6a8a0 100644 --- a/source/hos/pkg2.h +++ b/source/hos/pkg2.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2018 naehrwert - * Copyright (C) 2018-2019 CTCaer + * Copyright (C) 2018-2020 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, @@ -26,7 +26,7 @@ #define PKG2_SEC_KERNEL 0 #define PKG2_SEC_INI1 1 -#define PKG2_NEWKERN_GET_INI1 0x44 +#define PKG2_NEWKERN_GET_INI1_HEURISTIC 0xD2800015 // Offset of OP + 12 is the INI1 offset. u32 pkg2_newkern_ini1_val; u32 pkg2_newkern_ini1_start; @@ -87,7 +87,7 @@ typedef struct _pkg2_kip1_info_t link_t link; } pkg2_kip1_info_t; -void pkg2_parse_kips(link_t *info, pkg2_hdr_t *pkg2, bool *new_pkg2); +bool pkg2_parse_kips(link_t *info, pkg2_hdr_t *pkg2, bool *new_pkg2); int pkg2_decompress_kip(pkg2_kip1_info_t* ki, u32 sectsToDecomp); pkg2_hdr_t *pkg2_decrypt(void *data); diff --git a/source/main.c b/source/main.c index 63d4cd3..e3c98b7 100644 --- a/source/main.c +++ b/source/main.c @@ -137,11 +137,13 @@ int sd_save_to_file(void *buf, u32 size, const char *filename) #define PATCHED_RELOC_SZ 0x94 #define PATCHED_RELOC_STACK 0x40007000 #define PATCHED_RELOC_ENTRY 0x40010000 -#define EXT_PAYLOAD_ADDR 0xC03C0000 +#define EXT_PAYLOAD_ADDR 0xC0000000 #define RCM_PAYLOAD_ADDR (EXT_PAYLOAD_ADDR + ALIGN(PATCHED_RELOC_SZ, 0x10)) -#define COREBOOT_ADDR (0xD0000000 - 0x100000) +#define COREBOOT_END_ADDR 0xD0000000 #define CBFS_DRAM_EN_ADDR 0x4003e000 -#define CBFS_DRAM_MAGIC 0x4452414D // "DRAM" +#define CBFS_DRAM_MAGIC 0x4452414D // "DRAM" + +static void *coreboot_addr; void reloc_patcher(u32 payload_dst, u32 payload_src, u32 payload_size) { @@ -156,7 +158,7 @@ void reloc_patcher(u32 payload_dst, u32 payload_src, u32 payload_size) if (payload_size == 0x7000) { - memcpy((u8 *)(payload_src + ALIGN(PATCHED_RELOC_SZ, 0x10)), (u8 *)COREBOOT_ADDR, 0x7000); //Bootblock + memcpy((u8 *)(payload_src + ALIGN(PATCHED_RELOC_SZ, 0x10)), coreboot_addr, 0x7000); //Bootblock *(vu32 *)CBFS_DRAM_EN_ADDR = CBFS_DRAM_MAGIC; } } @@ -186,7 +188,10 @@ int launch_payload(char *path) if (size < 0x30000) buf = (void *)RCM_PAYLOAD_ADDR; else - buf = (void *)COREBOOT_ADDR; + { + coreboot_addr = (void *)(COREBOOT_END_ADDR - size); + buf = coreboot_addr; + } if (f_read(&fp, buf, size, NULL)) { diff --git a/source/mem/heap.c b/source/mem/heap.c index 1e3493a..4ed7230 100644 --- a/source/mem/heap.c +++ b/source/mem/heap.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2018 naehrwert + * Copyright (c) 2018-2020 CTCaer * Copyright (c) 2018 M4xw * * This program is free software; you can redistribute it and/or modify it @@ -29,7 +30,7 @@ static void _heap_create(heap_t *heap, u32 start) // Node info is before node address. static u32 _heap_alloc(heap_t *heap, u32 size) { - hnode_t *node, *new; + hnode_t *node, *new_node; // Align to cache line size. size = ALIGN(size, sizeof(hnode_t)); @@ -49,22 +50,29 @@ static u32 _heap_alloc(heap_t *heap, u32 size) node = heap->first; while (true) { + // Check if there's available unused node. if (!node->used && (size <= node->size)) { + // Size and offset of the new unused node. u32 new_size = node->size - size; - new = (hnode_t *)((u32)node + sizeof(hnode_t) + size); + new_node = (hnode_t *)((u32)node + sizeof(hnode_t) + size); - // If there's aligned leftover space, create a new node. + // If there's aligned unused space from the old node, + // create a new one and set the leftover size. if (new_size >= (sizeof(hnode_t) << 2)) { - new->size = new_size - sizeof(hnode_t); - new->used = 0; - new->next = node->next; - new->next->prev = new; - new->prev = node; - node->next = new; + new_node->size = new_size - sizeof(hnode_t); + new_node->used = 0; + new_node->next = node->next; + + // Check that we are not on first node. + if (new_node->next) + new_node->next->prev = new_node; + + new_node->prev = node; + node->next = new_node; } - else + else // Unused node size is just enough. size += new_size; node->size = size; @@ -72,20 +80,23 @@ static u32 _heap_alloc(heap_t *heap, u32 size) return (u32)node + sizeof(hnode_t); } + + // No unused node found, try the next one. if (node->next) node = node->next; else break; } - new = (hnode_t *)((u32)node + sizeof(hnode_t) + node->size); - new->used = 1; - new->size = size; - new->prev = node; - new->next = NULL; - node->next = new; + // No unused node found, create a new one. + new_node = (hnode_t *)((u32)node + sizeof(hnode_t) + node->size); + new_node->used = 1; + new_node->size = size; + new_node->prev = node; + new_node->next = NULL; + node->next = new_node; - return (u32)new + sizeof(hnode_t); + return (u32)new_node + sizeof(hnode_t); } static void _heap_free(heap_t *heap, u32 addr) @@ -101,6 +112,7 @@ static void _heap_free(heap_t *heap, u32 addr) { node->prev->size += node->size + sizeof(hnode_t); node->prev->next = node->next; + if (node->next) node->next->prev = node->prev; } diff --git a/source/mem/heap.h b/source/mem/heap.h index 4ec3fb0..e029597 100644 --- a/source/mem/heap.h +++ b/source/mem/heap.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2018 naehrwert + * Copyright (c) 2018-2020 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, diff --git a/source/mem/minerva.c b/source/mem/minerva.c index d2c966e..84efee0 100644 --- a/source/mem/minerva.c +++ b/source/mem/minerva.c @@ -34,18 +34,21 @@ u32 minerva_init() minerva_cfg = NULL; mtc_config_t *mtc_cfg = (mtc_config_t *)&nyx_str->mtc_cfg; + memset(mtc_cfg, 0, sizeof(mtc_config_t)); // Set table to nyx storage. mtc_cfg->mtc_table = (emc_table_t *)&nyx_str->mtc_table; mtc_cfg->sdram_id = (fuse_read_odm(4) >> 3) & 0x1F; mtc_cfg->init_done = MTC_NEW_MAGIC; // Initialize mtc table. - + u32 ep_addr = ianos_loader(false, "bootloader/sys/libsys_minerva.bso", DRAM_LIB, (void *)mtc_cfg); // Ensure that Minerva is new. if (mtc_cfg->init_done == MTC_INIT_MAGIC) minerva_cfg = (void *)ep_addr; + else + mtc_cfg->init_done = 0; if (!minerva_cfg) return 1; diff --git a/source/mem/sdram.c b/source/mem/sdram.c index a9a26d3..3bc283d 100644 --- a/source/mem/sdram.c +++ b/source/mem/sdram.c @@ -1,7 +1,7 @@ /* * Copyright (c) 2018 naehrwert * Copyright (c) 2018 balika011 - * Copyright (c) 2019 CTCaer + * Copyright (c) 2019-2020 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, @@ -696,7 +696,6 @@ sdram_params_t *sdram_get_params_patched() void sdram_init() { - //TODO: sdram_id should be in [0,4]. const sdram_params_t *params = (const sdram_params_t *)sdram_get_params(); // Set DRAM voltage. diff --git a/source/power/max17050.h b/source/power/max17050.h index e4c8acf..30a7ca0 100644 --- a/source/power/max17050.h +++ b/source/power/max17050.h @@ -4,7 +4,7 @@ * * Copyright (c) 2011 Samsung Electronics * MyungJoo Ham - * Copyright (c) 2018 CTCaer + * Copyright (c) 2018-2020 CTCaer * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -96,14 +96,17 @@ enum MAX17050_reg { MAX17050_K_empty0 = 0x3B, MAX17050_TaskPeriod = 0x3C, MAX17050_FSTAT = 0x3D, - + MAX17050_TIMER = 0x3E, MAX17050_SHDNTIMER = 0x3F, + MAX17050_QRTbl30 = 0x42, + MAX17050_dQacc = 0x45, MAX17050_dPacc = 0x46, MAX17050_VFSOC0 = 0x48, + Max17050_QH0 = 0x4C, MAX17050_QH = 0x4D, MAX17050_QL = 0x4E, @@ -111,6 +114,8 @@ enum MAX17050_reg { MAX17050_MaxVolt = 0x51, // Custom ID. Not to be sent to i2c. MAX17050_VFSOC0Enable = 0x60, + MAX17050_MODELEnable1 = 0x62, + MAX17050_MODELEnable2 = 0x63, MAX17050_MODELChrTbl = 0x80, diff --git a/source/power/max7762x.c b/source/power/max7762x.c index 0e7a6b5..ce07cbe 100644 --- a/source/power/max7762x.c +++ b/source/power/max7762x.c @@ -137,6 +137,7 @@ int max77620_regulator_enable(u32 id, int enable) return 1; } +// LDO only. int max77620_regulator_set_volt_and_flags(u32 id, u32 mv, u8 flags) { if (id > REGULATOR_MAX) @@ -168,9 +169,9 @@ void max77620_config_default() _max77620_try_set_reg(MAX77620_REG_SD_CFG2, 4); } -void max77620_low_battery_monitor_config() +void max77620_low_battery_monitor_config(bool enable) { _max77620_try_set_reg(MAX77620_REG_CNFGGLBL1, - MAX77620_CNFGGLBL1_LBDAC_EN | MAX77620_CNFGGLBL1_MPPLD | + MAX77620_CNFGGLBL1_LBDAC_EN | (enable ? MAX77620_CNFGGLBL1_MPPLD : 0) | MAX77620_CNFGGLBL1_LBHYST_200 | MAX77620_CNFGGLBL1_LBDAC_2800); } diff --git a/source/power/max7762x.h b/source/power/max7762x.h index 3a0afe3..8a11a9f 100644 --- a/source/power/max7762x.h +++ b/source/power/max7762x.h @@ -33,7 +33,7 @@ * ldo2 | SDMMC1 | 50000 | 800000 | 1800000 | 3300000 | * ldo3 | GC ASIC | 50000 | 800000 | 3100000 | 3100000 | 3.1V (pcv) * ldo4 | RTC | 12500 | 800000 | 850000 | 850000 | -* ldo5 | GC ASIC | 50000 | 800000 | 1800000 | 1800000 | 1.8V (pcv) +* ldo5 | GC Card | 50000 | 800000 | 1800000 | 1800000 | 1.8V (pcv) * ldo6 | Touch, ALS | 50000 | 800000 | 2900000 | 2900000 | 2.9V * ldo7 | XUSB | 50000 | 800000 | 1050000 | 1050000 | * ldo8 | XUSB, DC | 50000 | 800000 | 1050000 | 1050000 | @@ -113,6 +113,6 @@ int max77620_regulator_set_voltage(u32 id, u32 mv); int max77620_regulator_enable(u32 id, int enable); int max77620_regulator_set_volt_and_flags(u32 id, u32 mv, u8 flags); void max77620_config_default(); -void max77620_low_battery_monitor_config(); +void max77620_low_battery_monitor_config(bool enable); #endif diff --git a/source/rtc/max77620-rtc.c b/source/rtc/max77620-rtc.c index e214363..d2a780a 100644 --- a/source/rtc/max77620-rtc.c +++ b/source/rtc/max77620-rtc.c @@ -1,7 +1,8 @@ /* * PMIC Real Time Clock driver for Nintendo Switch's MAX77620-RTC * - * Copyright (c) 2018 CTCaer + * Copyright (c) 2018-2019 CTCaer + * Copyright (c) 2019-2020 shchmue * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -75,3 +76,94 @@ void max77620_rtc_stop_alarm() // Update RTC clock from RTC regs. i2c_send_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_UPDATE0_REG, MAX77620_RTC_WRITE_UPDATE); } + +void max77620_rtc_epoch_to_date(u32 epoch, rtc_time_t *time) +{ + u32 tmp, edays, year, month, day; + + // Set time. + time->sec = epoch % 60; + epoch /= 60; + time->min = epoch % 60; + epoch /= 60; + time->hour = epoch % 24; + epoch /= 24; + + // Calculate base date values. + tmp = (u32)(((u64)4 * epoch + 102032) / 146097 + 15); + tmp = (u32)((u64)epoch + 2442113 + tmp - (tmp >> 2)); + + year = (20 * tmp - 2442) / 7305; + edays = tmp - 365 * year - (year >> 2); + month = edays * 1000 / 30601; + day = edays - month * 30 - month * 601 / 1000; + + // Month/Year offset. + if(month < 14) + { + year -= 4716; + month--; + } + else + { + year -= 4715; + month -= 13; + } + + // Set date. + time->year = year; + time->month = month; + time->day = day; + + // Set weekday. + time->weekday = 0; //! TODO. +} + +u32 max77620_rtc_date_to_epoch(const rtc_time_t *time, bool hos_encoding) +{ + u32 year, month, epoch; + + //Year + year = time->year; + //Month of year + month = time->month; + + if (!hos_encoding) + { + // Month/Year offset. + if(month < 3) + { + month += 12; + year--; + } + } + else + { + year -= 2000; + month++; + + // Month/Year offset. + if(month < 3) + { + month += 9; + year--; + } + else + month -= 3; + } + + epoch = (365 * year) + (year >> 2) - (year / 100) + (year / 400); // Years to days. + + if (!hos_encoding) + { + epoch += (30 * month) + (3 * (month + 1) / 5) + time->day; // Months to days. + epoch -= 719561; // Epoch time is 1/1/1970. + } + else + epoch += (30 * month) + ((3 * month + 2) / 5) + 59 + time->day; // Months to days. + + epoch *= 86400; // Days to seconds. + epoch += (3600 * time->hour) + (60 * time->min) + time->sec; // Add hours, minutes and seconds. + + return epoch; +} diff --git a/source/rtc/max77620-rtc.h b/source/rtc/max77620-rtc.h index 981ccfe..99199d2 100644 --- a/source/rtc/max77620-rtc.h +++ b/source/rtc/max77620-rtc.h @@ -71,5 +71,7 @@ typedef struct _rtc_time_t { void max77620_rtc_get_time(rtc_time_t *time); void max77620_rtc_stop_alarm(); +void max77620_rtc_epoch_to_date(u32 epoch, rtc_time_t *time); +u32 max77620_rtc_date_to_epoch(const rtc_time_t *time, bool hos_encoding); #endif /* _MFD_MAX77620_RTC_H_ */ diff --git a/source/soc/hw_init.c b/source/soc/hw_init.c index 9f0e900..a7703a2 100644 --- a/source/soc/hw_init.c +++ b/source/soc/hw_init.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2018 naehrwert - * Copyright (c) 2018-2019 CTCaer + * Copyright (c) 2018-2020 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -39,6 +39,7 @@ extern sdmmc_t sd_sdmmc; extern boot_cfg_t b_cfg; +extern volatile nyx_storage_t *nyx_str; /* * CLK_OSC - 38.4 MHz crystal. @@ -78,8 +79,8 @@ void _config_gpios() PINMUX_AUX(PINMUX_AUX_UART3_TX) = 0; // Set Joy-Con IsAttached direction. - PINMUX_AUX(PINMUX_AUX_GPIO_PE6) = PINMUX_INPUT_ENABLE; - PINMUX_AUX(PINMUX_AUX_GPIO_PH6) = PINMUX_INPUT_ENABLE; + PINMUX_AUX(PINMUX_AUX_GPIO_PE6) = PINMUX_INPUT_ENABLE | PINMUX_TRISTATE; + PINMUX_AUX(PINMUX_AUX_GPIO_PH6) = PINMUX_INPUT_ENABLE | PINMUX_TRISTATE; // Set pin mode for Joy-Con IsAttached and UARTB/C TX pins. #if !defined (DEBUG_UART_PORT) || DEBUG_UART_PORT != UART_B @@ -109,7 +110,7 @@ void _config_gpios() gpio_output_enable(GPIO_PORT_X, GPIO_PIN_7, GPIO_OUTPUT_DISABLE); // Configure HOME as inputs. - // PINMUX_AUX(PINMUX_AUX_BUTTON_HOME) = PINMUX_PULL_UP | PINMUX_INPUT_ENABLE; + // PINMUX_AUX(PINMUX_AUX_BUTTON_HOME) = PINMUX_INPUT_ENABLE | PINMUX_TRISTATE; // gpio_config(GPIO_PORT_Y, GPIO_PIN_1, GPIO_MODE_GPIO); } @@ -160,7 +161,7 @@ void _mbist_workaround() // Enable specific clocks and disable all others. CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_H) = 0xC0; // Enable clock PMC, FUSE. CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_L) = 0x80000130; // Enable clock RTC, TMR, GPIO, BPMP_CACHE. - //CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_L) = 0x80400130; // Keep USB data ON. + //CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_L) = 0x80400130; // Keep USBD ON. CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_U) = 0x1F00200; // Enable clock CSITE, IRAMA, IRAMB, IRAMC, IRAMD, BPMP_CACHE_RAM. CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_V) = 0x80400808; // Enable clock MSELECT, APB2APE, SPDIF_DOUBLER, SE. CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_W) = 0x402000FC; // Enable clock PCIERX0, PCIERX1, PCIERX2, PCIERX3, PCIERX4, PCIERX5, ENTROPY, MC1. @@ -184,6 +185,9 @@ void _mbist_workaround() void _config_se_brom() { + // Enable fuse clock. + clock_enable_fuse(true); + // Skip SBK/SSK if sept was run. if (!(b_cfg.boot_cfg & BOOT_CFG_SEPT_RUN)) { @@ -217,10 +221,19 @@ void _config_se_brom() void _config_regulators() { + // Disable low battery shutdown monitor. + max77620_low_battery_monitor_config(false); + + // Disable SDMMC1 IO power. + gpio_output_enable(GPIO_PORT_E, GPIO_PIN_4, GPIO_OUTPUT_DISABLE); + max77620_regulator_enable(REGULATOR_LDO2, 0); + sd_power_cycle_time_start = get_tmr_ms(); + i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_CNFGBBC, MAX77620_CNFGBBC_RESISTOR_1K); i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_ONOFFCNFG1, (1 << 6) | (3 << MAX77620_ONOFFCNFG1_MRT_SHIFT)); // PWR delay for forced shutdown off. + // Configure all Flexible Power Sequencers. i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_CFG0, (7 << MAX77620_FPS_TIME_PERIOD_SHIFT)); i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_CFG1, @@ -236,10 +249,10 @@ void _config_regulators() i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_FPS_GPIO3, (4 << MAX77620_FPS_TIME_PERIOD_SHIFT) | (2 << MAX77620_FPS_PD_PERIOD_SHIFT)); // 3.x+ - // Set vdd_core voltage to 1.125V + // Set vdd_core voltage to 1.125V. max77620_regulator_set_voltage(REGULATOR_SD0, 1125000); - // Fix CPU/GPU after a Linux warmboot. + // Fix CPU/GPU after a L4T warmboot. i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_GPIO5, 2); i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_GPIO6, 2); @@ -256,9 +269,6 @@ void _config_regulators() i2c_send_byte(I2C_5, MAX77621_GPU_I2C_ADDR, MAX77621_CONTROL2_REG, MAX77621_T_JUNCTION_120 | MAX77621_FT_ENABLE | MAX77621_CKKADV_TRIP_75mV_PER_US_HIST_DIS | MAX77621_CKKADV_TRIP_150mV_PER_US | MAX77621_INDUCTOR_NOMINAL); - - // Enable low battery shutdown monitor for < 2800mV. - max77620_low_battery_monitor_config(); } void config_hw() @@ -312,6 +322,7 @@ void reconfig_hw_workaround(bool extra_reconfig, u32 magic) bpmp_mmu_disable(); bpmp_clk_rate_set(BPMP_CLK_NORMAL); minerva_change_freq(FREQ_204); + nyx_str->mtc_cfg.init_done = 0; // Re-enable clocks to Audio Processing Engine as a workaround to hanging. CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_V) |= (1 << 10); // Enable AHUB clock. diff --git a/source/soc/i2c.c b/source/soc/i2c.c index d06d64a..94239b5 100644 --- a/source/soc/i2c.c +++ b/source/soc/i2c.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2018 naehrwert + * Copyright (c) 2018-2020 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -19,7 +20,7 @@ #include "i2c.h" #include "../utils/util.h" -static u32 i2c_addrs[] = { +static const u32 i2c_addrs[] = { 0x7000C000, 0x7000C400, 0x7000C500, 0x7000C700, 0x7000D000, 0x7000D100 }; @@ -121,6 +122,11 @@ int i2c_send_buf_small(u32 idx, u32 x, u32 y, u8 *buf, u32 size) return _i2c_send_pkt(idx, x, tmp, size + 1); } +int i2c_recv_buf(u8 *buf, u32 size, u32 idx, u32 x) +{ + return _i2c_recv_pkt(idx, buf, size, x); +} + int i2c_recv_buf_small(u8 *buf, u32 size, u32 idx, u32 x, u32 y) { int res = _i2c_send_pkt(idx, x, (u8 *)&y, 1); diff --git a/source/soc/i2c.h b/source/soc/i2c.h index e2b2af5..4f04bac 100644 --- a/source/soc/i2c.h +++ b/source/soc/i2c.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2018 naehrwert + * Copyright (c) 2020 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -39,6 +40,7 @@ void i2c_init(u32 idx); int i2c_send_buf_small(u32 idx, u32 x, u32 y, u8 *buf, u32 size); +int i2c_recv_buf(u8 *buf, u32 size, u32 idx, u32 x); int i2c_recv_buf_small(u8 *buf, u32 size, u32 idx, u32 x, u32 y); int i2c_send_byte(u32 idx, u32 x, u32 y, u8 b); u8 i2c_recv_byte(u32 idx, u32 x, u32 y); diff --git a/source/storage/nx_emmc.c b/source/storage/nx_emmc.c index 6df300c..10977b1 100644 --- a/source/storage/nx_emmc.c +++ b/source/storage/nx_emmc.c @@ -31,7 +31,7 @@ void nx_emmc_gpt_parse(link_t *gpt, sdmmc_storage_t *storage) for (u32 i = 0; i < hdr->num_part_ents; i++) { gpt_entry_t *ent = (gpt_entry_t *)(buf + (hdr->part_ent_lba - 1) * NX_EMMC_BLOCKSIZE + i * sizeof(gpt_entry_t)); - emmc_part_t *part = (emmc_part_t *)malloc(sizeof(emmc_part_t)); + emmc_part_t *part = (emmc_part_t *)calloc(sizeof(emmc_part_t), 1); part->lba_start = ent->lba_start; part->lba_end = ent->lba_end; part->attrs = ent->attrs; diff --git a/source/utils/aarch64_util.h b/source/utils/aarch64_util.h index 3fa0188..a5002c0 100644 --- a/source/utils/aarch64_util.h +++ b/source/utils/aarch64_util.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2018 naehrwert + * 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, @@ -25,11 +26,12 @@ #define _PAGEOFF(x) ((x) & 0xFFFFF000) -#define _ADRP(r, o) 0x90000000 | ((((o) >> 12) & 0x3) << 29) | ((((o) >> 12) & 0x1FFFFC) << 3) | ((r) & 0x1F) -#define _BL(a, o) 0x94000000 | ((((o) - (a)) >> 2) & 0x3FFFFFF) -#define _B(a, o) 0x14000000 | ((((o) - (a)) >> 2) & 0x3FFFFFF) -#define _MOVKX(r, i, s) 0xF2800000 | (((s) & 0x30) << 17) | (((i) & 0xFFFF) << 5) | ((r) & 0x1F) -#define _MOVZX(r, i, s) 0xD2800000 | (((s) & 0x30) << 17) | (((i) & 0xFFFF) << 5) | ((r) & 0x1F) +#define _ADRP(r, o) (0x90000000 | ((((o) >> 12) & 0x3) << 29) | ((((o) >> 12) & 0x1FFFFC) << 3) | ((r) & 0x1F)) +#define _BL(a, o) (0x94000000 | ((((o) - (a)) >> 2) & 0x3FFFFFF)) +#define _B(a, o) (0x14000000 | ((((o) - (a)) >> 2) & 0x3FFFFFF)) +#define _MOVKX(r, i, s) (0xF2800000 | (((s) & 0x30) << 17) | (((i) & 0xFFFF) << 5) | ((r) & 0x1F)) +#define _MOVZX(r, i, s) (0xD2800000 | (((s) & 0x30) << 17) | (((i) & 0xFFFF) << 5) | ((r) & 0x1F)) +#define _MOVZW(r, i, s) (0x52800000 | (((s) & 0x30) << 17) | (((i) & 0xFFFF) << 5) | ((r) & 0x1F)) #define _NOP() 0xD503201F #endif diff --git a/source/utils/list.h b/source/utils/list.h index 7d43e36..80e4498 100644 --- a/source/utils/list.h +++ b/source/utils/list.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2018 naehrwert + * Copyright (c) 2020 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, @@ -33,9 +34,10 @@ #define LIST_FOREACH_SAFE(iter, list) \ for(link_t *iter = (list)->next, *safe = iter->next; iter != (list); iter = safe, safe = iter->next) -/*! Iterate over all list members. */ +/*! Iterate over all list members and make sure that the list has at least one entry. */ #define LIST_FOREACH_ENTRY(etype, iter, list, mn) \ - for(etype *iter = CONTAINER_OF((list)->next, etype, mn); &iter->mn != (list); iter = CONTAINER_OF(iter->mn.next, etype, mn)) + if ((list)->next != (list)) \ + for(etype *iter = CONTAINER_OF((list)->next, etype, mn); &iter->mn != (list); iter = CONTAINER_OF(iter->mn.next, etype, mn)) typedef struct _link_t { diff --git a/source/utils/util.h b/source/utils/util.h index 55f5f18..9ee1a74 100644 --- a/source/utils/util.h +++ b/source/utils/util.h @@ -33,15 +33,22 @@ typedef struct _cfg_op_t u32 val; } cfg_op_t; +typedef struct _nyx_info_t +{ + u32 rsvd; + u32 errors; +} nyx_info_t; + typedef struct _nyx_storage_t { u32 version; u32 cfg; u8 irama[0x8000]; u8 hekate[0x30000]; - u8 rsvd[0x800000]; + u8 rsvd[0x800000 - sizeof(nyx_info_t)]; + nyx_info_t info; mtc_config_t mtc_cfg; - emc_table_t mtc_table; + emc_table_t mtc_table[10]; } nyx_storage_t; u32 get_tmr_us();