279 lines
5.7 KiB
C
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);
|
|
}
|