2

Hello I am writing a small kernel to better understand RISC-V. Until now I managed to use the UART and setup a simple memory manager. To be able to parse user input I setup an interrupt handler and set its address to MTVEC. Then I enabled interrupt in MSTATUS and MIE. After that I setup MTIMECMP through mmio register and loop forever with WFI (RISC-V wait for interrupt instruction). I noticed then that MIP contained 0x8 as expected (which means machine mode timer interrupt pending). The only problem my code did not jump to MTVEC. What did I wrong? Best regards, Serge Teodori

source:

void mtrap(){
    uint8_t txt[0x100];
    struct uart_t uart = { .reg = (uint32_t*) 0x10013000 };

    stringFormat(txt, 0x100, "machine trap\r\n");
    uart_write(&uart, txt, 0x100);
}

void main(){
    uint8_t txt[0x100];
    uint64_t mvendorid, marchid, mimpid, mhartid, mstatus, misa, mtvec, mie, mip, mcause;
    struct clint_t clint = { .addr = 0x2000000 };
    struct plic_t plic = { .reg = (uint32_t*) 0x0c000000 };
    struct uart_t uart = { .reg = (uint32_t*) 0x10013000 };

    asm volatile ("csrr %[reg], mvendorid" : [reg] "=r" (mvendorid));
    asm volatile ("csrr %[reg], marchid" : [reg] "=r" (marchid));
    asm volatile ("csrr %[reg], mimpid" : [reg] "=r" (mimpid));
    asm volatile ("csrr %[reg], mhartid" : [reg] "=r" (mhartid));
    asm volatile ("csrr %[reg], misa" : [reg] "=r" (misa));

    // block all harts except hart 0
    if(mhartid)
        for(;;){ asm volatile ("wfi"); }

    mm_init(0x84000000, 0x1bffe000); // addr: 2GB + 64MB & size: 512MB - 64MB - 8KB
    uart_init(&uart);

    stringFormat(txt, 0x100, "mvendorid=%x, marchid=%x, mimpid=%x, mhartid=%x, misa=%x\r\n", mvendorid, marchid, mimpid, mhartid, misa);
    uart_write(&uart, txt, 0x100);

    // check if pending interrupt
    asm volatile ("csrr %[reg], mie" : [reg] "=r" (mie));
    asm volatile ("csrr %[reg], mip" : [reg] "=r" (mip));
    asm volatile ("csrr %[reg], mstatus" : [reg] "=r" (mstatus));
    asm volatile ("csrr %[reg], mcause" : [reg] "=r" (mcause));
    stringFormat(txt, 0x100, "mie=%x, mip=%x, mstatus=%x, mcause=%x\r\n", mie, mip, mstatus, mcause);
    uart_write(&uart, txt, 0x100);

    // set interrupt function or vector
    asm volatile ("csrw mtvec, %[reg]" : : [reg] "r" (riscv_mtrap));
    asm volatile ("csrr %[reg], mtvec" : [reg] "=r" (mtvec));
    stringFormat(txt, 0x100, "mtvec=%x\r\n", mtvec);
    uart_write(&uart, txt, 0x100);

    // enable machine mode interrupts
    asm volatile ("csrs mstatus, 0x8");

    // enable interrupts
    asm volatile ("csrs mie, 0x8");

    // check if pending interrupt
    asm volatile ("csrr %[reg], mie" : [reg] "=r" (mie));
    asm volatile ("csrr %[reg], mip" : [reg] "=r" (mip));
    asm volatile ("csrr %[reg], mstatus" : [reg] "=r" (mstatus));
    asm volatile ("csrr %[reg], mcause" : [reg] "=r" (mcause));
    stringFormat(txt, 0x100, "mie=%x, mip=%x, mstatus=%x, mcause=%x\r\n", mie, mip, mstatus, mcause);
    uart_write(&uart, txt, 0x100);

    // enable timer and wait for x cycles
    clint_set_hart_timer(&clint, mhartid, 10);
    for(mip = 0; mip < 0x100; mip++){}

    // check if pending interrupt
    asm volatile ("csrr %[reg], mie" : [reg] "=r" (mie));
    asm volatile ("csrr %[reg], mip" : [reg] "=r" (mip));
    asm volatile ("csrr %[reg], mstatus" : [reg] "=r" (mstatus));
    asm volatile ("csrr %[reg], mcause" : [reg] "=r" (mcause));
    stringFormat(txt, 0x100, "mie=%x, mip=%x, mstatus=%x, mcause=%x\r\n", mie, mip, mstatus, mcause);
    uart_write(&uart, txt, 0x100);

    for(;;){ asm volatile ("wfi"); }
}

asm:

    .align 4
    .globl riscv_mtrap
    .type riscv_mtrap, @function
riscv_mtrap:
    j mtrap
    mret

output:

mvendorid=0, marchid=0, mimpid=0, mhartid=0, misa=800000000014112d
mie=0, mip=0, mstatus=0, mcause=0
mtvec=80000010
mie=8, mip=0, mstatus=8, mcause=0
mie=8, mip=80, mstatus=8, mcause=0
5
  • can you provide some assembly code to understand why ? Commented Sep 10, 2019 at 20:04
  • Yes I'll post it tomorrow. Is the way I do it right or did I missed something? Commented Sep 10, 2019 at 21:08
  • asm volatile ("csrw mtvec, %[reg]" : : [reg] "r" (riscv_mtrap)); did you forget to put the equal sign to r, so it looks like asm volatile ("csrw mtvec, %[reg]" : : [reg] "=r" (riscv_mtrap)); Commented Sep 11, 2019 at 7:17
  • That means, write the address of the interrupt service routine, from a register to CSR MTVEC. "r" means read from and "=r" means write to, so no error there. Commented Sep 11, 2019 at 7:38
  • When I add asm volatile ("j riscv_data1"); where riscv_data1 is defined in .data section as a .long with 0xdeadc0de before the wfi instruction at the end, the processor trigger the trap... So invalid or misaligned instructions trigger the interrupt handler. Perhaps there is no interval timer running... Hm have to check qemu's doc. Commented Sep 11, 2019 at 16:00

1 Answer 1

2

Found the error. asm volatile ("csrs mie, 0x8"); enables software interrupts. I had to asm volatile ("csrw mie, 0x80");, and now it works.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.