mirror of
https://github.com/AsahiLinux/m1n1
synced 2024-11-21 14:23:01 +00:00
Add support for handling EL3.
A7-A9X has an EL3. Handle it (without SMP support). Signed-off-by: Nick Chan <towinchenmi@gmail.com>
This commit is contained in:
parent
5dfb07f3da
commit
accb393510
7 changed files with 97 additions and 13 deletions
|
@ -1,6 +1,7 @@
|
||||||
ENTRY(_start)
|
ENTRY(_start)
|
||||||
|
|
||||||
_stack_size = 0x20000;
|
_stack_size = 0x20000;
|
||||||
|
_stack_size_el3 = 0x8000;
|
||||||
|
|
||||||
/* We are actually relocatable */
|
/* We are actually relocatable */
|
||||||
. = 0;
|
. = 0;
|
||||||
|
@ -71,6 +72,12 @@ SECTIONS {
|
||||||
*(COMMON)
|
*(COMMON)
|
||||||
_bss_end = .;
|
_bss_end = .;
|
||||||
} : data
|
} : data
|
||||||
|
.stack_el3 : ALIGN(0x4000) {
|
||||||
|
PROVIDE(_stack_top_el3 = .);
|
||||||
|
. += _stack_size_el3 - 8;
|
||||||
|
QUAD(0x5176694b43415453);
|
||||||
|
PROVIDE(_stack_bot_el3 = .);
|
||||||
|
}
|
||||||
.stack : ALIGN(0x4000) {
|
.stack : ALIGN(0x4000) {
|
||||||
PROVIDE(_stack_top = .);
|
PROVIDE(_stack_top = .);
|
||||||
. += _stack_size - 8;
|
. += _stack_size - 8;
|
||||||
|
|
5
m1n1.ld
5
m1n1.ld
|
@ -4,6 +4,7 @@ ENTRY(_start)
|
||||||
_va_base = 0xFFFFFE0007004000;
|
_va_base = 0xFFFFFE0007004000;
|
||||||
|
|
||||||
_stack_size = 0x20000;
|
_stack_size = 0x20000;
|
||||||
|
_stack_size_el3 = 0x8000;
|
||||||
|
|
||||||
_max_payload_size = 64*1024*1024;
|
_max_payload_size = 64*1024*1024;
|
||||||
|
|
||||||
|
@ -176,6 +177,10 @@ SECTIONS {
|
||||||
*(COMMON)
|
*(COMMON)
|
||||||
. = ALIGN(0x4000);
|
. = ALIGN(0x4000);
|
||||||
_bss_end = .;
|
_bss_end = .;
|
||||||
|
PROVIDE(_stack_top_el3 = .);
|
||||||
|
. += _stack_size_el3;
|
||||||
|
PROVIDE(_stack_bot_el3 = .);
|
||||||
|
. = ALIGN(0x4000);
|
||||||
PROVIDE(_stack_top = .);
|
PROVIDE(_stack_top = .);
|
||||||
. += _stack_size;
|
. += _stack_size;
|
||||||
PROVIDE(_stack_bot = .);
|
PROVIDE(_stack_bot = .);
|
||||||
|
|
|
@ -69,7 +69,7 @@ void init_t6021_avalanche(int rev);
|
||||||
void init_t6031_sawtooth(void);
|
void init_t6031_sawtooth(void);
|
||||||
void init_t6031_everest(int rev);
|
void init_t6031_everest(int rev);
|
||||||
|
|
||||||
bool cpufeat_actlr_el2;
|
bool cpufeat_actlr_el2, cpufeat_fast_ipi;
|
||||||
|
|
||||||
const char *init_cpu(void)
|
const char *init_cpu(void)
|
||||||
{
|
{
|
||||||
|
|
|
@ -30,6 +30,8 @@ static char *m_table[0x10] = {
|
||||||
[0x05] = "EL1h", //
|
[0x05] = "EL1h", //
|
||||||
[0x08] = "EL2t", //
|
[0x08] = "EL2t", //
|
||||||
[0x09] = "EL2h", //
|
[0x09] = "EL2h", //
|
||||||
|
[0x0c] = "EL3t", //
|
||||||
|
[0x0d] = "EL3h", //
|
||||||
};
|
};
|
||||||
|
|
||||||
static char *gl_m_table[0x10] = {
|
static char *gl_m_table[0x10] = {
|
||||||
|
@ -114,6 +116,8 @@ static const char *get_exception_level(void)
|
||||||
return "EL1";
|
return "EL1";
|
||||||
else if (lvl == 0x08)
|
else if (lvl == 0x08)
|
||||||
return "EL2";
|
return "EL2";
|
||||||
|
else if (lvl == 0x0c)
|
||||||
|
return "EL3";
|
||||||
}
|
}
|
||||||
|
|
||||||
return "?";
|
return "?";
|
||||||
|
@ -121,7 +125,10 @@ static const char *get_exception_level(void)
|
||||||
|
|
||||||
void exception_initialize(void)
|
void exception_initialize(void)
|
||||||
{
|
{
|
||||||
msr(VBAR_EL1, _vectors_start);
|
if (in_el3())
|
||||||
|
msr(VBAR_EL3, _vectors_start);
|
||||||
|
else
|
||||||
|
msr(VBAR_EL1, _vectors_start);
|
||||||
|
|
||||||
// Clear FIQ sources
|
// Clear FIQ sources
|
||||||
msr(CNTP_CTL_EL0, 7L);
|
msr(CNTP_CTL_EL0, 7L);
|
||||||
|
@ -130,9 +137,12 @@ void exception_initialize(void)
|
||||||
msr(CNTP_CTL_EL02, 7L);
|
msr(CNTP_CTL_EL02, 7L);
|
||||||
msr(CNTV_CTL_EL02, 7L);
|
msr(CNTV_CTL_EL02, 7L);
|
||||||
}
|
}
|
||||||
reg_clr(SYS_IMP_APL_PMCR0, PMCR0_IACT | PMCR0_IMODE_MASK);
|
|
||||||
reg_clr(SYS_IMP_APL_UPMCR0, UPMCR0_IMODE_MASK);
|
if (cpufeat_fast_ipi) {
|
||||||
msr(SYS_IMP_APL_IPI_SR_EL1, IPI_SR_PENDING);
|
reg_clr(SYS_IMP_APL_PMCR0, PMCR0_IACT | PMCR0_IMODE_MASK);
|
||||||
|
reg_clr(SYS_IMP_APL_UPMCR0, UPMCR0_IMODE_MASK);
|
||||||
|
msr(SYS_IMP_APL_IPI_SR_EL1, IPI_SR_PENDING);
|
||||||
|
}
|
||||||
|
|
||||||
if (is_boot_cpu())
|
if (is_boot_cpu())
|
||||||
msr(DAIF, 0 << 6); // Enable SError, IRQ and FIQ
|
msr(DAIF, 0 << 6); // Enable SError, IRQ and FIQ
|
||||||
|
@ -168,8 +178,10 @@ void print_regs(u64 *regs, int el12)
|
||||||
u64 sp = ((u64)(regs)) + 256;
|
u64 sp = ((u64)(regs)) + 256;
|
||||||
|
|
||||||
in_gl = in_gl12();
|
in_gl = in_gl12();
|
||||||
|
bool el3 = in_el3();
|
||||||
|
|
||||||
u64 spsr = in_gl ? mrs(SYS_IMP_APL_SPSR_GL1) : (el12 ? mrs(SPSR_EL12) : mrs(SPSR_EL1));
|
u64 spsr = in_gl ? mrs(SYS_IMP_APL_SPSR_GL1)
|
||||||
|
: (el12 ? mrs(SPSR_EL12) : (el3 ? mrs(SPSR_EL3) : mrs(SPSR_EL1)));
|
||||||
|
|
||||||
printf("Exception taken from %s\n", get_exception_source(spsr));
|
printf("Exception taken from %s\n", get_exception_source(spsr));
|
||||||
printf("Running in %s\n", get_exception_level());
|
printf("Running in %s\n", get_exception_level());
|
||||||
|
@ -184,9 +196,12 @@ void print_regs(u64 *regs, int el12)
|
||||||
printf("x24-x27: %016lx %016lx %016lx %016lx\n", regs[24], regs[25], regs[26], regs[27]);
|
printf("x24-x27: %016lx %016lx %016lx %016lx\n", regs[24], regs[25], regs[26], regs[27]);
|
||||||
printf("x28-x30: %016lx %016lx %016lx\n", regs[28], regs[29], regs[30]);
|
printf("x28-x30: %016lx %016lx %016lx\n", regs[28], regs[29], regs[30]);
|
||||||
|
|
||||||
u64 elr = in_gl ? mrs(SYS_IMP_APL_ELR_GL1) : (el12 ? mrs(ELR_EL12) : mrs(ELR_EL1));
|
u64 elr = in_gl ? mrs(SYS_IMP_APL_ELR_GL1)
|
||||||
u64 esr = in_gl ? mrs(SYS_IMP_APL_ESR_GL1) : (el12 ? mrs(ESR_EL12) : mrs(ESR_EL1));
|
: (el12 ? mrs(ELR_EL12) : (el3 ? mrs(ELR_EL3) : mrs(ELR_EL1)));
|
||||||
u64 far = in_gl ? mrs(SYS_IMP_APL_FAR_GL1) : (el12 ? mrs(FAR_EL12) : mrs(FAR_EL1));
|
u64 esr = in_gl ? mrs(SYS_IMP_APL_ESR_GL1)
|
||||||
|
: (el12 ? mrs(ESR_EL12) : (el3 ? mrs(ESR_EL3) : mrs(ESR_EL1)));
|
||||||
|
u64 far = in_gl ? mrs(SYS_IMP_APL_FAR_GL1)
|
||||||
|
: (el12 ? mrs(FAR_EL12) : (el3 ? mrs(FAR_EL3) : mrs(FAR_EL1)));
|
||||||
|
|
||||||
printf("PC: 0x%lx (rel: 0x%lx)\n", elr, elr - (u64)_base);
|
printf("PC: 0x%lx (rel: 0x%lx)\n", elr, elr - (u64)_base);
|
||||||
printf("SP: 0x%lx\n", sp);
|
printf("SP: 0x%lx\n", sp);
|
||||||
|
@ -221,10 +236,11 @@ void exc_sync(u64 *regs)
|
||||||
u32 insn;
|
u32 insn;
|
||||||
int el12 = 0;
|
int el12 = 0;
|
||||||
bool in_gl = in_gl12();
|
bool in_gl = in_gl12();
|
||||||
|
bool el3 = in_el3();
|
||||||
|
|
||||||
u64 spsr = in_gl ? mrs(SYS_IMP_APL_SPSR_GL1) : mrs(SPSR_EL1);
|
u64 spsr = in_gl ? mrs(SYS_IMP_APL_SPSR_GL1) : (el3 ? mrs(SPSR_EL3) : mrs(SPSR_EL1));
|
||||||
u64 esr = in_gl ? mrs(SYS_IMP_APL_ESR_GL1) : mrs(ESR_EL1);
|
u64 esr = in_gl ? mrs(SYS_IMP_APL_ESR_GL1) : (el3 ? mrs(ESR_EL3) : mrs(ESR_EL1));
|
||||||
u64 elr = in_gl ? mrs(SYS_IMP_APL_ELR_GL1) : mrs(ELR_EL1);
|
u64 elr = in_gl ? mrs(SYS_IMP_APL_ELR_GL1) : (el3 ? mrs(ELR_EL3) : mrs(ELR_EL1));
|
||||||
|
|
||||||
if ((spsr & 0xf) == 0 && ((esr >> 26) & 0x3f) == 0x3c) {
|
if ((spsr & 0xf) == 0 && ((esr >> 26) & 0x3f) == 0x3c) {
|
||||||
// On clean EL0 return, let the normal exception return
|
// On clean EL0 return, let the normal exception return
|
||||||
|
@ -256,6 +272,14 @@ void exc_sync(u64 *regs)
|
||||||
printf("Unknown HVC: 0x%x\n", imm);
|
printf("Unknown HVC: 0x%x\n", imm);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
} else if (in_el3() && ((esr >> 26) & 0x3f) == 0x17) {
|
||||||
|
// Monitor call
|
||||||
|
u32 imm = mrs(ESR_EL3) & 0xffff;
|
||||||
|
switch (imm) {
|
||||||
|
default:
|
||||||
|
printf("Unknown SMC: 0x%x\n", imm);
|
||||||
|
break;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!(exc_guard & GUARD_SILENT))
|
if (!(exc_guard & GUARD_SILENT))
|
||||||
printf("Exception: SYNC\n");
|
printf("Exception: SYNC\n");
|
||||||
|
@ -297,6 +321,8 @@ void exc_sync(u64 *regs)
|
||||||
printf("Recovering from exception (ELR=0x%lx)\n", elr);
|
printf("Recovering from exception (ELR=0x%lx)\n", elr);
|
||||||
if (in_gl)
|
if (in_gl)
|
||||||
msr(SYS_IMP_APL_ELR_GL1, elr);
|
msr(SYS_IMP_APL_ELR_GL1, elr);
|
||||||
|
if (el3)
|
||||||
|
msr(ELR_EL3, elr);
|
||||||
else
|
else
|
||||||
msr(ELR_EL1, elr);
|
msr(ELR_EL1, elr);
|
||||||
|
|
||||||
|
|
32
src/start.S
32
src/start.S
|
@ -96,11 +96,27 @@ _start:
|
||||||
mov w0, '\n'
|
mov w0, '\n'
|
||||||
bl debug_putc
|
bl debug_putc
|
||||||
|
|
||||||
|
mrs x8, CurrentEL
|
||||||
|
cmp x8, #0xc
|
||||||
|
beq start_el3
|
||||||
|
|
||||||
mov x0, x19
|
mov x0, x19
|
||||||
mov x1, x20
|
mov x1, x20
|
||||||
bl _start_c
|
bl _start_c
|
||||||
b .
|
b .
|
||||||
|
|
||||||
|
.globl exception_initialize
|
||||||
|
start_el3:
|
||||||
|
bl exception_initialize
|
||||||
|
adrp x8, _stack_bot_el3
|
||||||
|
mov sp, x8
|
||||||
|
mov x0, x19
|
||||||
|
mov x1, x20
|
||||||
|
msr tpidr_el3, xzr
|
||||||
|
adrp x6, _stack_bot
|
||||||
|
adr x7, _start_c
|
||||||
|
b el3_eret_to_el1
|
||||||
|
|
||||||
.globl exc_unk
|
.globl exc_unk
|
||||||
.type exc_unk, @function
|
.type exc_unk, @function
|
||||||
exc_unk:
|
exc_unk:
|
||||||
|
@ -148,6 +164,22 @@ cpu_reset:
|
||||||
bl _cpu_reset_c
|
bl _cpu_reset_c
|
||||||
b .
|
b .
|
||||||
|
|
||||||
|
el3_eret_to_el1:
|
||||||
|
adr x8, _vectors_start
|
||||||
|
msr sctlr_el1, xzr
|
||||||
|
|
||||||
|
mrs x8, scr_el3
|
||||||
|
orr x8, x8, #(1<<10) // EL1 execution state is AArch64
|
||||||
|
orr x8, x8, #(1<<0) // EL1 is non-secure
|
||||||
|
msr scr_el3, x8
|
||||||
|
msr elr_el3, x7 // Set EL1 entry point
|
||||||
|
mov x8, #0x5 // EL1h
|
||||||
|
msr spsr_el3, x8
|
||||||
|
|
||||||
|
msr sp_el1, x6 // Set EL1 stack pointer
|
||||||
|
|
||||||
|
eret
|
||||||
|
|
||||||
.globl debug_putc
|
.globl debug_putc
|
||||||
.type debug_putc, @function
|
.type debug_putc, @function
|
||||||
debug_putc:
|
debug_putc:
|
||||||
|
|
|
@ -115,9 +115,13 @@ void _cpu_reset_c(void *stack)
|
||||||
printf(" MPIDR: 0x%lx\n", mrs(MPIDR_EL1));
|
printf(" MPIDR: 0x%lx\n", mrs(MPIDR_EL1));
|
||||||
const char *type = init_cpu();
|
const char *type = init_cpu();
|
||||||
printf(" CPU: %s\n", type);
|
printf(" CPU: %s\n", type);
|
||||||
|
printf(" Running in EL%lu\n\n", mrs(CurrentEL) >> 2);
|
||||||
|
|
||||||
exception_initialize();
|
exception_initialize();
|
||||||
|
|
||||||
|
if (in_el3())
|
||||||
|
return;
|
||||||
|
|
||||||
if (!is_boot_cpu())
|
if (!is_boot_cpu())
|
||||||
smp_secondary_entry();
|
smp_secondary_entry();
|
||||||
else
|
else
|
||||||
|
|
12
src/utils.h
12
src/utils.h
|
@ -342,6 +342,16 @@ static inline int in_el2(void)
|
||||||
return (mrs(CurrentEL) >> 2) == 2;
|
return (mrs(CurrentEL) >> 2) == 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline int in_el3(void)
|
||||||
|
{
|
||||||
|
return (mrs(CurrentEL) >> 2) == 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int has_el3(void)
|
||||||
|
{
|
||||||
|
return !!(mrs(ID_AA64PFR0_EL1) & 0xf000);
|
||||||
|
}
|
||||||
|
|
||||||
extern int boot_cpu_idx;
|
extern int boot_cpu_idx;
|
||||||
extern u64 boot_cpu_mpidr;
|
extern u64 boot_cpu_mpidr;
|
||||||
static inline int is_boot_cpu(void)
|
static inline int is_boot_cpu(void)
|
||||||
|
@ -438,7 +448,7 @@ struct vector_args {
|
||||||
|
|
||||||
extern u32 board_id, chip_id;
|
extern u32 board_id, chip_id;
|
||||||
extern bool is_mac;
|
extern bool is_mac;
|
||||||
extern bool cpufeat_actlr_el2;
|
extern bool cpufeat_actlr_el2, cpufeat_fast_ipi;
|
||||||
|
|
||||||
extern struct vector_args next_stage;
|
extern struct vector_args next_stage;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue