mirror of
https://github.com/CTCaer/hekate.git
synced 2024-11-26 19:52:11 +00:00
bdk: fuse: add ipatch support for T210B01
This commit is contained in:
parent
331f1926d1
commit
e9587a325c
2 changed files with 69 additions and 36 deletions
100
bdk/soc/fuse.c
100
bdk/soc/fuse.c
|
@ -2,7 +2,7 @@
|
||||||
* Copyright (c) 2018 naehrwert
|
* Copyright (c) 2018 naehrwert
|
||||||
* Copyright (c) 2018 shuffle2
|
* Copyright (c) 2018 shuffle2
|
||||||
* Copyright (c) 2018 balika011
|
* 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
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
* under the terms and conditions of the GNU General Public License,
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
@ -19,6 +19,7 @@
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <mem/heap.h>
|
||||||
#include <sec/se.h>
|
#include <sec/se.h>
|
||||||
#include <sec/se_t210.h>
|
#include <sec/se_t210.h>
|
||||||
#include <soc/fuse.h>
|
#include <soc/fuse.h>
|
||||||
|
@ -42,12 +43,19 @@ static const u32 evp_thunk_template[] = {
|
||||||
0xe3822001, // ORR R2, R2, #1
|
0xe3822001, // ORR R2, R2, #1
|
||||||
0xe8bd0003, // LDMFD SP!, {R0,R1}
|
0xe8bd0003, // LDMFD SP!, {R0,R1}
|
||||||
0xe12fff12, // BX R2
|
0xe12fff12, // BX R2
|
||||||
|
// idx: 15:
|
||||||
0x001007b0, // off_1007EC DCD evp_thunk_template
|
0x001007b0, // off_1007EC DCD evp_thunk_template
|
||||||
0x001007f8, // off_1007F0 DCD thunk_end
|
0x001007f8, // off_1007F0 DCD thunk_end
|
||||||
0x40004c30, // off_1007F4 DCD iram_evp_thunks
|
0x40004c30, // off_1007F4 DCD iram_evp_thunks
|
||||||
// thunk_end is here
|
// 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
|
// treated as 12bit values
|
||||||
static const u32 hash_vals[] = {1, 2, 4, 8, 0, 3, 5, 6, 7, 9, 10, 11};
|
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)
|
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++)
|
for (u32 i = 0; i < array_size; i++)
|
||||||
words[i] = fuse_read(i);
|
words[i] = fuse_read(i);
|
||||||
|
@ -180,9 +189,8 @@ static u32 _parity32_even(u32 *words, u32 count)
|
||||||
{
|
{
|
||||||
u32 acc = words[0];
|
u32 acc = words[0];
|
||||||
for (u32 i = 1; i < count; i++)
|
for (u32 i = 1; i < count; i++)
|
||||||
{
|
|
||||||
acc ^= words[i];
|
acc ^= words[i];
|
||||||
}
|
|
||||||
u32 lo = ((acc & 0xffff) ^ (acc >> 16)) & 0xff;
|
u32 lo = ((acc & 0xffff) ^ (acc >> 16)) & 0xff;
|
||||||
u32 hi = ((acc & 0xffff) ^ (acc >> 16)) >> 8;
|
u32 hi = ((acc & 0xffff) ^ (acc >> 16)) >> 8;
|
||||||
u32 x = hi ^ lo;
|
u32 x = hi ^ lo;
|
||||||
|
@ -198,26 +206,26 @@ static int _patch_hash_one(u32 *word)
|
||||||
u32 bits20_31 = *word & 0xfff00000;
|
u32 bits20_31 = *word & 0xfff00000;
|
||||||
u32 parity_bit = _parity32_even(&bits20_31, 1);
|
u32 parity_bit = _parity32_even(&bits20_31, 1);
|
||||||
u32 hash = 0;
|
u32 hash = 0;
|
||||||
|
|
||||||
for (u32 i = 0; i < 12; i++)
|
for (u32 i = 0; i < 12; i++)
|
||||||
{
|
{
|
||||||
if (*word & (1 << (20 + i)))
|
if (*word & (1 << (20 + i)))
|
||||||
{
|
|
||||||
hash ^= hash_vals[i];
|
hash ^= hash_vals[i];
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hash == 0)
|
if (hash == 0)
|
||||||
{
|
{
|
||||||
if (parity_bit == 0)
|
if (parity_bit == 0)
|
||||||
{
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
*word ^= 1 << 24;
|
*word ^= 1 << 24;
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parity_bit == 0)
|
if (parity_bit == 0)
|
||||||
{
|
|
||||||
return 3;
|
return 3;
|
||||||
}
|
|
||||||
for (u32 i = 0; i < ARRAY_SIZE(hash_vals); i++)
|
for (u32 i = 0; i < ARRAY_SIZE(hash_vals); i++)
|
||||||
{
|
{
|
||||||
if (hash_vals[i] == hash)
|
if (hash_vals[i] == hash)
|
||||||
|
@ -226,6 +234,7 @@ static int _patch_hash_one(u32 *word)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -246,9 +255,7 @@ static int _patch_hash_multi(u32 *words, u32 count)
|
||||||
for (u32 bitpos = 0; bitpos < 32; bitpos++)
|
for (u32 bitpos = 0; bitpos < 32; bitpos++)
|
||||||
{
|
{
|
||||||
if ((w >> bitpos) & 1)
|
if ((w >> bitpos) & 1)
|
||||||
{
|
|
||||||
hash ^= 0x4000 + i * 32 + bitpos;
|
hash ^= 0x4000 + i * 32 + bitpos;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -260,16 +267,14 @@ static int _patch_hash_multi(u32 *words, u32 count)
|
||||||
if (hash == 0)
|
if (hash == 0)
|
||||||
{
|
{
|
||||||
if (parity_bit == 0)
|
if (parity_bit == 0)
|
||||||
{
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
words[0] ^= 0x8000;
|
words[0] ^= 0x8000;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
if (parity_bit == 0)
|
if (parity_bit == 0)
|
||||||
{
|
|
||||||
return 3;
|
return 3;
|
||||||
}
|
|
||||||
u32 bitcount = hash - 0x4000;
|
u32 bitcount = hash - 0x4000;
|
||||||
if (bitcount < 16 || bitcount >= count * 32)
|
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++)
|
for (u32 bitpos = 0; bitpos < 15; bitpos++)
|
||||||
{
|
{
|
||||||
if ((hash >> bitpos) & 1)
|
if ((hash >> bitpos) & 1)
|
||||||
{
|
|
||||||
num_set++;
|
num_set++;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (num_set != 1)
|
if (num_set != 1)
|
||||||
{
|
|
||||||
return 2;
|
return 2;
|
||||||
}
|
|
||||||
words[0] ^= hash;
|
words[0] ^= hash;
|
||||||
return 1;
|
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 = FUSE(FUSE_FIRST_BOOTROM_PATCH_SIZE);
|
||||||
word_count &= 0x7F;
|
word_count &= 0x7F;
|
||||||
word_addr = 191;
|
word_addr = FUSE_ARRAY_WORDS_NUM - 1;
|
||||||
|
|
||||||
while (word_count)
|
while (word_count)
|
||||||
{
|
{
|
||||||
total_read += word_count;
|
total_read += word_count;
|
||||||
if (total_read >= ARRAY_SIZE(words))
|
if (total_read >= ARRAY_SIZE(words))
|
||||||
{
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
|
|
||||||
for (u32 i = 0; i < word_count; i++)
|
for (u32 i = 0; i < word_count; i++)
|
||||||
|
{
|
||||||
words[i] = fuse_read(word_addr--);
|
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];
|
word0 = words[0];
|
||||||
if (_patch_hash_multi(words, word_count) >= 2)
|
if (_patch_hash_multi(words, word_count) >= 2)
|
||||||
{
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
|
||||||
u32 ipatch_count = (words[0] >> 16) & 0xF;
|
u32 ipatch_count = (words[0] >> 16) & 0xF;
|
||||||
if (ipatch_count)
|
if (ipatch_count)
|
||||||
{
|
{
|
||||||
|
@ -332,13 +340,14 @@ int fuse_read_ipatch(void (*ipatch)(u32 offset, u32 value))
|
||||||
ipatch(addr, data);
|
ipatch(addr, data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
words[0] = word0;
|
words[0] = word0;
|
||||||
if ((word0 >> 25) == 0)
|
if ((word0 >> 25) == 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (_patch_hash_one(&word0) >= 2)
|
if (_patch_hash_one(&word0) >= 2)
|
||||||
{
|
|
||||||
return 3;
|
return 3;
|
||||||
}
|
|
||||||
word_count = word0 >> 25;
|
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;
|
u32 total_read = 0;
|
||||||
int evp_thunk_written = 0;
|
int evp_thunk_written = 0;
|
||||||
void *evp_thunk_dst_addr = 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);
|
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 = FUSE(FUSE_FIRST_BOOTROM_PATCH_SIZE);
|
||||||
word_count &= 0x7F;
|
word_count &= 0x7F;
|
||||||
word_addr = 191;
|
word_addr = FUSE_ARRAY_WORDS_NUM - 1;
|
||||||
|
|
||||||
while (word_count)
|
while (word_count)
|
||||||
{
|
{
|
||||||
total_read += word_count;
|
total_read += word_count;
|
||||||
if (total_read >= ARRAY_SIZE(words))
|
if (total_read >= ARRAY_SIZE(words))
|
||||||
{
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
|
|
||||||
for (u32 i = 0; i < word_count; i++)
|
for (u32 i = 0; i < word_count; i++)
|
||||||
|
{
|
||||||
words[i] = fuse_read(word_addr--);
|
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];
|
word0 = words[0];
|
||||||
if (_patch_hash_multi(words, word_count) >= 2)
|
if (_patch_hash_multi(words, word_count) >= 2)
|
||||||
{
|
{
|
||||||
|
free(evp_thunk_tmp);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 ipatch_count = (words[0] >> 16) & 0xF;
|
u32 ipatch_count = (words[0] >> 16) & 0xF;
|
||||||
u32 insn_count = word_count - ipatch_count - 1;
|
u32 insn_count = word_count - ipatch_count - 1;
|
||||||
if (insn_count)
|
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;
|
evp_thunk_dst_addr = (void *)iram_evp_thunks;
|
||||||
|
|
||||||
memcpy(evp_thunk_dst_addr, (void *)evp_thunk_template, evp_thunk_template_len);
|
memcpy(evp_thunk_dst_addr, (void *)evp_thunk_tmp, sizeof(evp_thunk_template));
|
||||||
evp_thunk_dst_addr += evp_thunk_template_len;
|
evp_thunk_dst_addr += sizeof(evp_thunk_template);
|
||||||
evp_thunk_written = 1;
|
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);
|
//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;
|
evp_thunk_dst_addr += thunk_patch_len;
|
||||||
*iram_evp_thunks_len += thunk_patch_len;
|
*iram_evp_thunks_len += thunk_patch_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
words[0] = word0;
|
words[0] = word0;
|
||||||
if ((word0 >> 25) == 0)
|
if ((word0 >> 25) == 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (_patch_hash_one(&word0) >= 2)
|
if (_patch_hash_one(&word0) >= 2)
|
||||||
{
|
{
|
||||||
|
free(evp_thunk_tmp);
|
||||||
return 3;
|
return 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
word_count = word0 >> 25;
|
word_count = word0 >> 25;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
free(evp_thunk_tmp);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -419,7 +449,7 @@ bool fuse_check_patched_rcm()
|
||||||
|
|
||||||
// Check if RCM is ipatched.
|
// Check if RCM is ipatched.
|
||||||
u32 word_count = FUSE(FUSE_FIRST_BOOTROM_PATCH_SIZE) & 0x7F;
|
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)
|
while (word_count)
|
||||||
{
|
{
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
* Copyright (c) 2018 naehrwert
|
* Copyright (c) 2018 naehrwert
|
||||||
* Copyright (c) 2018 shuffle2
|
* Copyright (c) 2018 shuffle2
|
||||||
* Copyright (c) 2018 balika011
|
* 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
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
* under the terms and conditions of the GNU General Public License,
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
@ -82,6 +82,9 @@
|
||||||
/*! Fuse cache registers. */
|
/*! Fuse cache registers. */
|
||||||
#define FUSE_RESERVED_ODMX(x) (0x1C8 + 4 * (x))
|
#define FUSE_RESERVED_ODMX(x) (0x1C8 + 4 * (x))
|
||||||
|
|
||||||
|
#define FUSE_ARRAY_WORDS_NUM 192
|
||||||
|
#define FUSE_ARRAY_WORDS_NUM_T210B01 256
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
FUSE_NX_HW_TYPE_ICOSA,
|
FUSE_NX_HW_TYPE_ICOSA,
|
||||||
|
|
Loading…
Reference in a new issue