// lib/sbi/sbi_hart.c | |
// sbi_hart_switch_mode(hartid, scratch->next_arg1, scratch->next_addr, scratch->next_mode, false); | |
void __attribute__((noreturn)) | |
sbi_hart_switch_mode(unsigned long arg0, unsigned long arg1, | |
unsigned long next_addr, unsigned long next_mode, | |
bool next_virt) | |
{ | |
unsigned long val; | |
switch (next_mode) { // scratch->next_mode | |
case PRV_M: | |
break; | |
case PRV_S: // here! | |
if (!misa_extension('S')) | |
sbi_hart_hang(); | |
break; | |
case PRV_U: | |
if (!misa_extension('U')) | |
sbi_hart_hang(); | |
break; | |
default: | |
sbi_hart_hang(); | |
} | |
val = csr_read(CSR_MSTATUS); | |
val = INSERT_FIELD(val, MSTATUS_MPP, next_mode); | |
val = INSERT_FIELD(val, MSTATUS_MPIE, 0); | |
csr_write(CSR_MSTATUS, val); | |
csr_write(CSR_MEPC, next_addr); | |
if (next_mode == PRV_S) { // here! | |
csr_write(CSR_STVEC, next_addr); | |
csr_write(CSR_SSCRATCH, 0); | |
csr_write(CSR_SIE, 0); | |
csr_write(CSR_SATP, 0); | |
} else if (next_mode == PRV_U) { | |
csr_write(CSR_UTVEC, next_addr); | |
csr_write(CSR_USCRATCH, 0); | |
csr_write(CSR_UIE, 0); | |
} | |
register unsigned long a0 asm("a0") = arg0; | |
register unsigned long a1 asm("a1") = arg1; | |
__asm__ __volatile__("mret" : : "r"(a0), "r"(a1)); | |
__builtin_unreachable(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment