QEMU裸机开发之S模式软中断
S模式下的软中断我们借助m模式下的定时器中断进行触发,在m模式下设置sip中的soft位域就可以触发S模式下的软中断,如下所示。
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; }
当m模式中断处理结束时就会立马进入s模式中断处理,在s模式的软中断处理中通过将sip中的soft位域置0来清除s模式软中断状态,如下所示。
void supervisor_trap(void) { unsigned long tval = stval_get(); unsigned long sepc = sepc_get(); unsigned long cause = scause_get(); int is_int = (cause & (1l << 63l)) ? 1 : 0; int scode = cause & 0xff; if (scode >= 16) { printf("%s : %s.\r\n", is_int ? "Interrupt" : "Exception", "Unknown code"); return; } if (is_int) { printf("Interrupt : %s.\r\n", interrupt_cause[scode]); switch (scode) { case S_SOFT_INT: // acknowledge the software interrupt by clearing // the SSIP bit in sip. sip_set(sip_get() & (~SIP_SSIP)); break; case S_TIMER_INT: break; } } else { printf("Exception : %s.\r\n", exception_cause[scode]); switch (scode) { case ILLEGAL_INSTRUCTION: printf("tval = %p\r\n", tval); printf("sepc = %p\r\n", sepc); break; } sepc_set(sepc + 4); } return; }
在“start”中设置定时器以让定时器产生可以产生中断,如下所示。
void start(void) { printf("%s %d.\r\n", __func__, __LINE__); machine_trap_init(); //msoftint_make(); timer_set(timer_get() + TIMER_CLK_RATE); machine_switchto_supervisor(); }
注意本章节只是为了说明S模式软中断是如何使用的而采用了一种简单方便的测试方法,在实际的软件中,需要借助OpenSBI来进行核间中断设置和处理。
在命令行执行“make qemu”,可以看到先打印m模式下定时器中断信息,然后再打印s模式下的软中断信息,如下所示。
gewenbin@gewenbin-virtual-machine:~/Desktop/qemu_test/lesson9$ make qemu riscv64-unknown-elf-gcc -c -o entry.o entry.S riscv64-unknown-elf-gcc -Wall -Werror -O -fno-omit-frame-pointer -ggdb -mcmodel=medany -ffreestanding -fno-common -nostdlib -mno-relax -I. -fno-stack-protector -fno-pie -no-pie -c -o start.o start.c riscv64-unknown-elf-gcc -Wall -Werror -O -fno-omit-frame-pointer -ggdb -mcmodel=medany -ffreestanding -fno-common -nostdlib -mno-relax -I. -fno-stack-protector -fno-pie -no-pie -c -o uart.o uart.c riscv64-unknown-elf-gcc -Wall -Werror -O -fno-omit-frame-pointer -ggdb -mcmodel=medany -ffreestanding -fno-common -nostdlib -mno-relax -I. -fno-stack-protector -fno-pie -no-pie -c -o trap.o trap.c riscv64-unknown-elf-gcc -Wall -Werror -O -fno-omit-frame-pointer -ggdb -mcmodel=medany -ffreestanding -fno-common -nostdlib -mno-relax -I. -fno-stack-protector -fno-pie -no-pie -c -o clint.o clint.c riscv64-unknown-elf-ld -z max-page-size=4096 -T kernel.ld -o kernelimage entry.o start.o uart.o trap.o clint.o riscv64-unknown-elf-objdump -S kernelimage > kernel.asm riscv64-unknown-elf-objdump -t kernelimage | sed '1,/SYMBOL TABLE/d; s/ .* / /; /^$/d' > kernel.sym qemu-system-riscv64 -machine virt -bios none -kernel kernelimage -m 128M -smp 1 -nographic start 76. main 44. Interrupt : Machine timer interrupt. Interrupt : Supervisor software interrupt. Interrupt : Machine timer interrupt. Interrupt : Supervisor software interrupt. Interrupt : Machine timer interrupt. Interrupt : Supervisor software interrupt.
工程源码:链接:https://pan.baidu.com/s/1TnTYr7mywdKj5bxpdmWnyA,提取码:q772,见lesson9。
评论