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
asm volatile ("csrw mtvec, %[reg]" : : [reg] "r" (riscv_mtrap));did you forget to put the equal sign to r, so it looks likeasm volatile ("csrw mtvec, %[reg]" : : [reg] "=r" (riscv_mtrap));asm volatile ("j riscv_data1");whereriscv_data1is defined in.datasection as a.longwith0xdeadc0debefore thewfiinstruction 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.