kernel-brax3-ubuntu-touch/drivers/misc/mediatek/mkp/ksym.c
erascape f319b992b1 kernel-5.15: Initial import brax3 UT kernel
* halium configs enabled

Signed-off-by: erascape <erascape@proton.me>
2025-09-23 15:17:10 +00:00

279 lines
5.7 KiB
C

// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2021 MediaTek Inc.
*/
#include "ksym.h"
DEBUG_SET_LEVEL(DEBUG_LEVEL_ERR);
static unsigned long *mkp_ka;
static int *mkp_ko;
static unsigned long *mkp_krb;
static unsigned int *mkp_kns;
static u8 *mkp_kn;
static unsigned int *mkp_km;
static u8 *mkp_ktt;
static u16 *mkp_kti;
void __init *mkp_abt_addr(void *ssa)
{
void *pos;
u8 abt[SM_SIZE];
int i;
unsigned long s_left;
for (i = 0; i < SM_SIZE; i++) {
if (i & 0x1)
abt[i] = 0;
else
abt[i] = 0x61 + i / 2;
}
if ((unsigned long)ssa >= KV + S_MAX) {
MKP_ERR("out of range: 0xlx\n", (unsigned long)ssa);
return NULL;
}
pos = ssa;
s_left = KV + S_MAX - (unsigned long)ssa;
while ((u64)pos < (u64)(KV + S_MAX)) {
pos = memchr(pos, 'a', s_left);
if (!pos) {
MKP_ERR("fail at: 0x%lx @ 0x%lx\n", (unsigned long)ssa, s_left);
return NULL;
}
if (!memcmp(pos, (const void *)abt, sizeof(abt)))
return pos;
pos = (char *)pos + 1;
s_left = KV + S_MAX - (unsigned long)pos;
}
MKP_ERR("fail at end: 0x%lx @ 0x%lx\n", (unsigned long)ssa, s_left);
return NULL;
}
unsigned long __init *mkp_krb_addr(void)
{
void *abt_addr = (void *)KV;
void *ssa = (void *)KV;
unsigned long *pos;
while ((u64)ssa < KV + S_MAX) {
abt_addr = mkp_abt_addr(ssa);
if (!abt_addr) {
MKP_ERR("krb not found: 0x%lx\n", (unsigned long)ssa);
return NULL;
}
abt_addr = (void *)round_up((unsigned long)abt_addr, 8);
for (pos = (unsigned long *)abt_addr;
(u64)pos > (u64)ssa ; pos--) {
/*
* When kallsyms_relative_base scan at _stext, we
* need to break. Because we already hit the start
* of kernel image.
*/
if ((u64)pos == (u64)KV)
break;
/*
* kallsyms_relative_base store the _text value.
* _text is equal to kimage_vaddr. If we find the
* value, this position is krb addr.
*/
if (*pos == kimage_vaddr)
return pos;
}
ssa = abt_addr + 1;
}
MKP_ERR("krb not found: 0x%lx\n", (unsigned long)ssa);
return NULL;
}
unsigned int __init *mkp_km_addr(void)
{
const u8 *name = mkp_kn;
unsigned int loop = *mkp_kns;
while (loop--)
name = name + (*name) + 1;
return (unsigned int *)round_up((unsigned long)name, 8);
}
u16 __init *mkp_kti_addr(void)
{
const u8 *pch = mkp_ktt;
int loop = TT_SIZE;
while (loop--) {
for (; *pch; pch++)
;
pch++;
}
return (u16 *)round_up((unsigned long)pch, 8);
}
int __init mkp_ka_init(void)
{
unsigned int kns;
mkp_krb = mkp_krb_addr();
if (!mkp_krb)
return -EINVAL;
mkp_kns = (unsigned int *)(mkp_krb + 1);
mkp_kn = (u8 *)(mkp_krb + 2);
kns = *mkp_kns;
mkp_ko = (int *)(mkp_krb - (round_up(kns, 2) / 2));
mkp_km = mkp_km_addr();
mkp_ktt = (u8 *)round_up((unsigned long)(mkp_km +
(round_up(kns, 256) / 256)), 8);
mkp_kti = mkp_kti_addr();
return 0;
}
unsigned int __init mkp_checking_names(unsigned int off,
char *namebuf, size_t buflen)
{
int len, skipped_first = 0;
const u8 *tptr, *data;
data = mkp_kn + off;
len = *data;
data++;
off += len + 1;
while (len) {
tptr = mkp_ktt + *(mkp_kti + *data);
data++;
len--;
while (*tptr) {
if (skipped_first) {
if (buflen <= 1)
goto tail;
*namebuf = *tptr;
namebuf++;
buflen--;
} else
skipped_first = 1;
tptr++;
}
}
tail:
if (buflen)
*namebuf = '\0';
return off;
}
unsigned long __init mkp_idx2addr(int idx)
{
if (!IS_ENABLED(CONFIG_KALLSYMS_BASE_RELATIVE))
return *(mkp_ka + idx);
if (!IS_ENABLED(CONFIG_KALLSYMS_ABSOLUTE_PERCPU))
return *mkp_krb + (u32)(*(mkp_ko + idx));
if (*(mkp_ko + idx) >= 0)
return *(mkp_ko + idx);
return *mkp_krb - 1 - *(mkp_ko + idx);
}
unsigned long __init mkp_addr_find(const char *name)
{
char strbuf[NAME_LEN];
unsigned long i;
unsigned int off;
for (i = 0, off = 0; i < *mkp_kns; i++) {
off = mkp_checking_names(off, strbuf, ARRAY_SIZE(strbuf));
if (strcmp(strbuf, name) == 0)
return mkp_idx2addr(i);
}
return 0;
}
static void __init mkp_addr_find_krn_info(unsigned long *stext,
unsigned long *etext, unsigned long *init_begin)
{
char strbuf[NAME_LEN];
unsigned long i, j;
unsigned int off;
char name[3][NAME_LEN] = {"_stext", "_etext", "__init_begin"};
for (i = 0, j = 0, off = 0; (i < *mkp_kns) && (j < 3); i++) {
off = mkp_checking_names(off, strbuf, ARRAY_SIZE(strbuf));
if (strcmp(strbuf, name[j]) == 0) {
if (j == 0)
*stext = mkp_idx2addr(i);
else if (j == 1)
*etext = mkp_idx2addr(i);
else if (j == 2)
*init_begin = mkp_idx2addr(i);
j++;
}
}
}
void __init mkp_get_krn_info(void **p_stext, void **p_etext,
void **p__init_begin)
{
unsigned long stext, etext, init_begin;
mkp_addr_find_krn_info(&stext, &etext, &init_begin);
*p_stext = (void *)stext;
*p_etext = (void *)etext;
*p__init_begin = (void *)init_begin;
MKP_DEBUG("_stext: %p, _etext: %p\n", *p_stext, *p_etext);
MKP_DEBUG(" __init_begin: %p\n", *p__init_begin);
}
void __init mkp_get_krn_code(void **p_stext, void **p_etext)
{
if (*p_stext && *p_etext)
return;
*p_stext = (void *)(mkp_addr_find("_stext"));
*p_etext = (void *)(mkp_addr_find("_etext"));
if (!(*p_etext)) {
MKP_ERR("%s: _stext not found\n", __func__);
return;
}
if (!(*p_etext)) {
MKP_ERR("%s: _etext not found\n", __func__);
return;
}
MKP_DEBUG("_stext: %p, _etext: %p\n", *p_stext, *p_etext);
}
void __init mkp_get_krn_rodata(void **p_etext, void **p__init_begin)
{
if (*p_etext && *p__init_begin)
return;
*p_etext = (void *)(mkp_addr_find("_etext"));
*p__init_begin = (void *)(mkp_addr_find("__init_begin"));
if (!(*p_etext)) {
MKP_ERR("%s: _etext not found\n", __func__);
return;
}
if (!(*p__init_begin)) {
MKP_ERR("%s: __init_begin not found\n", __func__);
return;
}
MKP_DEBUG("_etext: %p, __init_begin: %p\n", *p_etext, *p__init_begin);
}