riscv 開發之S模式ecall調用


我們知道有些寄存器只能在m模式下設置和訪問,如果s模式想要使用某個功能,只能先回到m模式然后再進行相應的設置。OpenSBI定義了s模式和m模式之間功能調用的接口,s模式通過執行“ecall”指令回到m模式使用相關功能,在本章節和下一章節我們將通過類似的方式來學習s模式下如何使用ecall和m模式下如何處理來自s模式的ecall異常。

首先我們將ecall指令封裝成宏來使用,如下所示。

#ifndef _ASM_RISCV_ECALL_H
#define _ASM_RISCV_ECALL_H
#define RISCV_ECALL(which, arg0, arg1, arg2) ({            \
    register unsigned long a0 asm ("a0") = (unsigned long)(arg0);   \
    register unsigned long a1 asm ("a1") = (unsigned long)(arg1);   \
    register unsigned long a2 asm ("a2") = (unsigned long)(arg2);   \
    register unsigned long a7 asm ("a7") = (unsigned long)(which);  \
    asm volatile ("ecall"                   \
              : "+r" (a0)               \
              : "r" (a1), "r" (a2), "r" (a7)        \
              : "memory");              \
    a0;                         \
})
#define RISCV_ECALL_0(which) RISCV_ECALL(which, 0, 0, 0)
#endif

這個宏的封裝方式也是參考了Linux下的“sbi.h”,which表示調用號,按照OpenSBI的規范,調用號是存放在a7寄存器中,其他的參數從a0寄存器開始存放。當然在測試中我們不會去檢測a7寄存器的,在實際的OpenSBI代碼中,會通過a7寄存器判斷是何種ecall調用然后進行不同的處理。在“main”中調用ecall宏發起一個ecall調用,如下所示。

static void main(void)
{
    printf("%s %d.\r\n", __func__, __LINE__);
    supervisor_trap_init();
    RISCV_ECALL_0(0);
    while(1);
}

在m模式的異常處理中,我們先對s模式的ecall異常不做任何處理,如下所示。

static char *interrupt_cause[] = {
    "Reserved",
    "Supervisor software interrupt",
    "Reserved",
    "Machine software interrupt",
    "Reserved",
    "Supervisor timer interrupt",
    "Reserved",
    "Machine timer interrupt",
    "Reserved",
    "Supervisor external interrupt",
    "Reserved",
    "Machine external interrupt",
    "Reserved",
    "Reserved",
    "Reserved",
    "Reserved"
};

static char *exception_cause[] = {
    "Instruction address misaligned",
    "Instruction access fault",
    "Illegal instruction",
    "Breakpoint",
    "Load address misaligned",
    "Load access fault",
    "Store/AMO address misaligned",
    "Store/AMO access fault",
    "Environment call from U-mode",
    "Environment call from S-mode",
    "Reserved",
    "Environment call from M-mode",
    "Instruction page fault",
    "Load page fault",
    "Reserved",
    "Store/AMO page fault"
};

 

 

 

 

void machine_trap(void)
{ 
    unsigned long cause = mcause_get();
    unsigned long mepc  = mepc_get();
    unsigned long tval  = mtval_get();
    int is_int = (cause & (1l << 63l)) ? 1 : 0;
    int mcode = cause & 0xff;
    if (mcode >= 16) {
        printf("%s : %s.\r\n", is_int ? "Interrupt" : "Exception", "Unknown code");
        return;
    }
    if (is_int) {
        printf("Interrupt : %s.\r\n", interrupt_cause[mcode]); 
        switch (mcode) {
        case M_SOFT_INT:
            msoftint_clear();
            break;
        case M_TIMER_INT:
            timer_set(timer_get() + TIMER_CLK_RATE);
            // raise a supervisor software interrupt.
            //sip_set(SIP_SSIP);
            break;
        }
    } else {
        printf("Exception : %s.\r\n", exception_cause[mcode]); 
        switch (mcode) {
        case ILLEGAL_INSTRUCTION:
            printf("tval = %p\r\n", tval);
            printf("mepc = %p\r\n", mepc);
            break;
        case ECALL_FROM_SMODE:
            break;
        }
        mepc_set(mepc + 4);
    }
    return;
}

 

 

 

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM