diff --git a/bdk/soc/fuse.c b/bdk/soc/fuse.c index 63037e9..da9063f 100644 --- a/bdk/soc/fuse.c +++ b/bdk/soc/fuse.c @@ -2,7 +2,7 @@ * Copyright (c) 2018 naehrwert * Copyright (c) 2018 shuffle2 * Copyright (c) 2018 balika011 - * Copyright (c) 2019-2021 CTCaer + * Copyright (c) 2019-2022 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -19,6 +19,7 @@ #include +#include #include #include #include @@ -42,12 +43,19 @@ static const u32 evp_thunk_template[] = { 0xe3822001, // ORR R2, R2, #1 0xe8bd0003, // LDMFD SP!, {R0,R1} 0xe12fff12, // BX R2 + // idx: 15: 0x001007b0, // off_1007EC DCD evp_thunk_template 0x001007f8, // off_1007F0 DCD thunk_end 0x40004c30, // off_1007F4 DCD iram_evp_thunks // thunk_end is here }; -static const u32 evp_thunk_template_len = sizeof(evp_thunk_template); + +static const u32 evp_thunk_func_offsets_t210b01[] = { + 0x0010022c, // off_100268 DCD evp_thunk_template + 0x00100174, // off_10026C DCD thunk_end + 0x40004164, // off_100270 DCD iram_evp_thunks + // thunk_end is here +}; // treated as 12bit values static const u32 hash_vals[] = {1, 2, 4, 8, 0, 3, 5, 6, 7, 9, 10, 11}; @@ -170,7 +178,8 @@ u32 fuse_read(u32 addr) void fuse_read_array(u32 *words) { - u32 array_size = (hw_get_chip_id() == GP_HIDREV_MAJOR_T210B01) ? 256 : 192; + u32 array_size = (hw_get_chip_id() == GP_HIDREV_MAJOR_T210B01) ? + FUSE_ARRAY_WORDS_NUM_T210B01 : FUSE_ARRAY_WORDS_NUM; for (u32 i = 0; i < array_size; i++) words[i] = fuse_read(i); @@ -180,9 +189,8 @@ static u32 _parity32_even(u32 *words, u32 count) { u32 acc = words[0]; for (u32 i = 1; i < count; i++) - { acc ^= words[i]; - } + u32 lo = ((acc & 0xffff) ^ (acc >> 16)) & 0xff; u32 hi = ((acc & 0xffff) ^ (acc >> 16)) >> 8; u32 x = hi ^ lo; @@ -198,26 +206,26 @@ static int _patch_hash_one(u32 *word) u32 bits20_31 = *word & 0xfff00000; u32 parity_bit = _parity32_even(&bits20_31, 1); u32 hash = 0; + for (u32 i = 0; i < 12; i++) { if (*word & (1 << (20 + i))) - { hash ^= hash_vals[i]; - } } + if (hash == 0) { if (parity_bit == 0) - { return 0; - } + *word ^= 1 << 24; + return 1; } + if (parity_bit == 0) - { return 3; - } + for (u32 i = 0; i < ARRAY_SIZE(hash_vals); i++) { if (hash_vals[i] == hash) @@ -226,6 +234,7 @@ static int _patch_hash_one(u32 *word) return 1; } } + return 2; } @@ -246,9 +255,7 @@ static int _patch_hash_multi(u32 *words, u32 count) for (u32 bitpos = 0; bitpos < 32; bitpos++) { if ((w >> bitpos) & 1) - { hash ^= 0x4000 + i * 32 + bitpos; - } } } } @@ -260,16 +267,14 @@ static int _patch_hash_multi(u32 *words, u32 count) if (hash == 0) { if (parity_bit == 0) - { return 0; - } + words[0] ^= 0x8000; return 1; } if (parity_bit == 0) - { return 3; - } + u32 bitcount = hash - 0x4000; if (bitcount < 16 || bitcount >= count * 32) { @@ -277,14 +282,11 @@ static int _patch_hash_multi(u32 *words, u32 count) for (u32 bitpos = 0; bitpos < 15; bitpos++) { if ((hash >> bitpos) & 1) - { num_set++; - } } if (num_set != 1) - { return 2; - } + words[0] ^= hash; return 1; } @@ -302,24 +304,30 @@ int fuse_read_ipatch(void (*ipatch)(u32 offset, u32 value)) word_count = FUSE(FUSE_FIRST_BOOTROM_PATCH_SIZE); word_count &= 0x7F; - word_addr = 191; + word_addr = FUSE_ARRAY_WORDS_NUM - 1; while (word_count) { total_read += word_count; if (total_read >= ARRAY_SIZE(words)) - { break; - } for (u32 i = 0; i < word_count; i++) + { words[i] = fuse_read(word_addr--); + // Parse extra T210B01 fuses when the difference is reached. + if (hw_get_chip_id() == GP_HIDREV_MAJOR_T210B01 && + word_addr == ((FUSE_ARRAY_WORDS_NUM - 1) - + (FUSE_ARRAY_WORDS_NUM_T210B01 - FUSE_ARRAY_WORDS_NUM) / sizeof(u32))) + { + word_addr = FUSE_ARRAY_WORDS_NUM_T210B01 - 1; + } + } word0 = words[0]; if (_patch_hash_multi(words, word_count) >= 2) - { return 1; - } + u32 ipatch_count = (words[0] >> 16) & 0xF; if (ipatch_count) { @@ -332,13 +340,14 @@ int fuse_read_ipatch(void (*ipatch)(u32 offset, u32 value)) ipatch(addr, data); } } + words[0] = word0; if ((word0 >> 25) == 0) break; + if (_patch_hash_one(&word0) >= 2) - { return 3; - } + word_count = word0 >> 25; } @@ -354,29 +363,44 @@ int fuse_read_evp_thunk(u32 *iram_evp_thunks, u32 *iram_evp_thunks_len) u32 total_read = 0; int evp_thunk_written = 0; void *evp_thunk_dst_addr = 0; + bool t210b01 = hw_get_chip_id() == GP_HIDREV_MAJOR_T210B01; + u32 *evp_thunk_tmp = (u32 *)malloc(sizeof(evp_thunk_template)); + memcpy(evp_thunk_tmp, evp_thunk_template, sizeof(evp_thunk_template)); memset(iram_evp_thunks, 0, *iram_evp_thunks_len); + if (t210b01) + memcpy(&evp_thunk_tmp[15], evp_thunk_func_offsets_t210b01, sizeof(evp_thunk_func_offsets_t210b01)); + word_count = FUSE(FUSE_FIRST_BOOTROM_PATCH_SIZE); word_count &= 0x7F; - word_addr = 191; + word_addr = FUSE_ARRAY_WORDS_NUM - 1; while (word_count) { total_read += word_count; if (total_read >= ARRAY_SIZE(words)) - { break; - } for (u32 i = 0; i < word_count; i++) + { words[i] = fuse_read(word_addr--); + // Parse extra T210B01 fuses when the difference is reached. + if (hw_get_chip_id() == GP_HIDREV_MAJOR_T210B01 && + word_addr == ((FUSE_ARRAY_WORDS_NUM - 1) - + (FUSE_ARRAY_WORDS_NUM_T210B01 - FUSE_ARRAY_WORDS_NUM) / sizeof(u32))) + { + word_addr = FUSE_ARRAY_WORDS_NUM_T210B01 - 1; + } + } word0 = words[0]; if (_patch_hash_multi(words, word_count) >= 2) { + free(evp_thunk_tmp); return 1; } + u32 ipatch_count = (words[0] >> 16) & 0xF; u32 insn_count = word_count - ipatch_count - 1; if (insn_count) @@ -385,10 +409,10 @@ int fuse_read_evp_thunk(u32 *iram_evp_thunks, u32 *iram_evp_thunks_len) { evp_thunk_dst_addr = (void *)iram_evp_thunks; - memcpy(evp_thunk_dst_addr, (void *)evp_thunk_template, evp_thunk_template_len); - evp_thunk_dst_addr += evp_thunk_template_len; + memcpy(evp_thunk_dst_addr, (void *)evp_thunk_tmp, sizeof(evp_thunk_template)); + evp_thunk_dst_addr += sizeof(evp_thunk_template); evp_thunk_written = 1; - *iram_evp_thunks_len = evp_thunk_template_len; + *iram_evp_thunks_len = sizeof(evp_thunk_template); //write32(TEGRA_EXCEPTION_VECTORS_BASE + 0x208, iram_evp_thunks); } @@ -398,16 +422,22 @@ int fuse_read_evp_thunk(u32 *iram_evp_thunks, u32 *iram_evp_thunks_len) evp_thunk_dst_addr += thunk_patch_len; *iram_evp_thunks_len += thunk_patch_len; } + words[0] = word0; if ((word0 >> 25) == 0) break; + if (_patch_hash_one(&word0) >= 2) { + free(evp_thunk_tmp); return 3; } + word_count = word0 >> 25; } + free(evp_thunk_tmp); + return 0; } @@ -419,7 +449,7 @@ bool fuse_check_patched_rcm() // Check if RCM is ipatched. u32 word_count = FUSE(FUSE_FIRST_BOOTROM_PATCH_SIZE) & 0x7F; - u32 word_addr = 191; + u32 word_addr = FUSE_ARRAY_WORDS_NUM - 1; while (word_count) { diff --git a/bdk/soc/fuse.h b/bdk/soc/fuse.h index a9154bb..f032326 100644 --- a/bdk/soc/fuse.h +++ b/bdk/soc/fuse.h @@ -2,7 +2,7 @@ * Copyright (c) 2018 naehrwert * Copyright (c) 2018 shuffle2 * Copyright (c) 2018 balika011 - * Copyright (c) 2019-2021 CTCaer + * Copyright (c) 2019-2022 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -82,6 +82,9 @@ /*! Fuse cache registers. */ #define FUSE_RESERVED_ODMX(x) (0x1C8 + 4 * (x)) +#define FUSE_ARRAY_WORDS_NUM 192 +#define FUSE_ARRAY_WORDS_NUM_T210B01 256 + enum { FUSE_NX_HW_TYPE_ICOSA,