mirror of
https://github.com/cccriscv/mini-riscv-os.git
synced 2025-11-16 12:34:33 +00:00
Modify the interrupt vector
This commit is contained in:
@@ -1,6 +1,16 @@
|
||||
CC = riscv64-unknown-elf-gcc
|
||||
CFLAGS = -nostdlib -fno-builtin -mcmodel=medany -march=rv32ima -mabi=ilp32
|
||||
|
||||
OBJ = \
|
||||
start.s \
|
||||
sys.s \
|
||||
lib.c \
|
||||
timer.c \
|
||||
task.c \
|
||||
os.c \
|
||||
user.c \
|
||||
trap.c
|
||||
|
||||
QEMU = qemu-system-riscv32
|
||||
QFLAGS = -nographic -smp 4 -machine virt -bios none
|
||||
|
||||
@@ -8,7 +18,7 @@ OBJDUMP = riscv64-unknown-elf-objdump
|
||||
|
||||
all: os.elf
|
||||
|
||||
os.elf: start.s sys.s lib.c timer.c task.c os.c user.c
|
||||
os.elf: $(OBJ)
|
||||
$(CC) $(CFLAGS) -T os.ld -o os.elf $^
|
||||
|
||||
qemu: $(TARGET)
|
||||
|
||||
@@ -1,12 +1,17 @@
|
||||
#include "os.h"
|
||||
|
||||
void os_kernel() {
|
||||
extern void trap_init(void);
|
||||
|
||||
void os_kernel()
|
||||
{
|
||||
task_os();
|
||||
}
|
||||
|
||||
void os_start() {
|
||||
void os_start()
|
||||
{
|
||||
lib_puts("OS start\n");
|
||||
user_init();
|
||||
trap_init();
|
||||
timer_init(); // start timer interrupt ...
|
||||
}
|
||||
|
||||
@@ -15,7 +20,8 @@ int os_main(void)
|
||||
os_start();
|
||||
|
||||
int current_task = 0;
|
||||
while (1) {
|
||||
while (1)
|
||||
{
|
||||
lib_puts("OS: Activate next task\n");
|
||||
task_go(current_task);
|
||||
lib_puts("OS: Back to OS\n");
|
||||
@@ -24,4 +30,3 @@ int os_main(void)
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -116,48 +116,34 @@
|
||||
.globl sys_switch
|
||||
.align 4
|
||||
sys_switch:
|
||||
|
||||
ctx_save a0 # a0 => struct context *old
|
||||
ctx_load a1 # a1 => struct context *new
|
||||
ret # pc=ra; swtch to new task (new->ra)
|
||||
|
||||
.globl sys_kernel
|
||||
|
||||
.globl trap_vector
|
||||
# the trap vector base address must always be aligned on a 4-byte boundary
|
||||
.align 4
|
||||
sys_kernel:
|
||||
addi sp, sp, -128 # alloc stack space
|
||||
reg_save sp # save all registers
|
||||
call timer_handler # call timer_handler in timer.c
|
||||
reg_load sp # restore all registers
|
||||
addi sp, sp, 128 # restore stack pointer
|
||||
jr a7 # jump to a7=mepc , return to timer break point
|
||||
trap_vector:
|
||||
# save context(registers).
|
||||
csrrw t6, mscratch, t6 # swap t6 and mscratch
|
||||
reg_save t6
|
||||
csrw mscratch, t6
|
||||
# call the C trap handler in trap.c
|
||||
csrr a0, mepc
|
||||
csrr a1, mcause
|
||||
call trap_handler
|
||||
|
||||
.globl sys_timer
|
||||
.align 4
|
||||
sys_timer:
|
||||
# timer_init() has set up the memory that mscratch points to:
|
||||
# scratch[0,4,8] : register save area.
|
||||
# scratch[12] : address of CLINT's MTIMECMP register.
|
||||
# scratch[16] : desired interval between interrupts.
|
||||
# trap_handler will return the return address via a0.
|
||||
csrw mepc, a0
|
||||
|
||||
csrrw a0, mscratch, a0 # exchange(mscratch,a0)
|
||||
sw a1, 0(a0)
|
||||
sw a2, 4(a0)
|
||||
sw a3, 8(a0)
|
||||
# restore context(registers).
|
||||
csrr t6, mscratch
|
||||
reg_load t6
|
||||
|
||||
# schedule the next timer interrupt
|
||||
# by adding interval to mtimecmp.
|
||||
lw a1, 12(a0) # CLINT_MTIMECMP(hart)
|
||||
lw a2, 16(a0) # interval
|
||||
lw a3, 0(a1) # a3 = CLINT_MTIMECMP(hart)
|
||||
add a3, a3, a2 # a3 += interval
|
||||
sw a3, 0(a1) # CLINT_MTIMECMP(hart) = a3
|
||||
|
||||
csrr a7, mepc # a7 = mepc, for sys_kernel jump back to interrupted point
|
||||
la a1, sys_kernel # mepc = sys_kernel
|
||||
la a1, os_kernel # mepc = sys_kernel
|
||||
csrw mepc, a1 # mret : will jump to sys_kernel
|
||||
# return to whatever we were doing before trap.
|
||||
mret
|
||||
|
||||
lw a3, 8(a0)
|
||||
lw a2, 4(a0)
|
||||
lw a1, 0(a0)
|
||||
csrrw a0, mscratch, a0 # exchange(mscratch,a0)
|
||||
|
||||
mret # jump to mepc (=sys_kernel)
|
||||
|
||||
@@ -5,6 +5,8 @@ extern void os_kernel();
|
||||
// a scratch area per CPU for machine-mode timer interrupts.
|
||||
reg_t timer_scratch[NCPU][5];
|
||||
|
||||
#define interval 20000000 // cycles; about 2 second in qemu.
|
||||
|
||||
void timer_init()
|
||||
{
|
||||
// each CPU has a separate source of timer interrupts.
|
||||
@@ -12,8 +14,8 @@ void timer_init()
|
||||
|
||||
// ask the CLINT for a timer interrupt.
|
||||
// int interval = 1000000; // cycles; about 1/10th second in qemu.
|
||||
int interval = 20000000; // cycles; about 2 second in qemu.
|
||||
*(reg_t*)CLINT_MTIMECMP(id) = *(reg_t*)CLINT_MTIME + interval;
|
||||
|
||||
*(reg_t *)CLINT_MTIMECMP(id) = *(reg_t *)CLINT_MTIME + interval;
|
||||
|
||||
// prepare information in scratch[] for timervec.
|
||||
// scratch[0..2] : space for timervec to save registers.
|
||||
@@ -24,19 +26,15 @@ void timer_init()
|
||||
scratch[4] = interval;
|
||||
w_mscratch((reg_t)scratch);
|
||||
|
||||
// set the machine-mode trap handler.
|
||||
w_mtvec((reg_t)sys_timer);
|
||||
|
||||
// enable machine-mode interrupts.
|
||||
w_mstatus(r_mstatus() | MSTATUS_MIE);
|
||||
|
||||
// enable machine-mode timer interrupts.
|
||||
w_mie(r_mie() | MIE_MTIE);
|
||||
}
|
||||
|
||||
static int timer_count = 0;
|
||||
|
||||
void timer_handler() {
|
||||
void timer_handler()
|
||||
{
|
||||
lib_printf("timer_handler: %d\n", ++timer_count);
|
||||
os_kernel();
|
||||
int id = r_mhartid();
|
||||
*(reg_t *)CLINT_MTIMECMP(id) = *(reg_t *)CLINT_MTIME + interval;
|
||||
}
|
||||
|
||||
48
05-Preemptive/trap.c
Normal file
48
05-Preemptive/trap.c
Normal file
@@ -0,0 +1,48 @@
|
||||
#include "os.h"
|
||||
extern void trap_vector();
|
||||
|
||||
void trap_init()
|
||||
{
|
||||
// set the machine-mode trap handler.
|
||||
w_mtvec((reg_t)trap_vector);
|
||||
|
||||
// enable machine-mode interrupts.
|
||||
w_mstatus(r_mstatus() | MSTATUS_MIE);
|
||||
}
|
||||
|
||||
reg_t trap_handler(reg_t epc, reg_t cause)
|
||||
{
|
||||
reg_t return_pc = epc;
|
||||
reg_t cause_code = cause & 0xfff;
|
||||
|
||||
if (cause & 0x80000000)
|
||||
{
|
||||
/* Asynchronous trap - interrupt */
|
||||
switch (cause_code)
|
||||
{
|
||||
case 3:
|
||||
lib_puts("software interruption!\n");
|
||||
break;
|
||||
case 7:
|
||||
lib_puts("timer interruption!\n");
|
||||
timer_handler();
|
||||
break;
|
||||
case 11:
|
||||
lib_puts("external interruption!\n");
|
||||
break;
|
||||
default:
|
||||
lib_puts("unknown async exception!\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Synchronous trap - exception */
|
||||
lib_puts("Sync exceptions!\n");
|
||||
while (1)
|
||||
{
|
||||
/* code */
|
||||
}
|
||||
}
|
||||
return return_pc;
|
||||
}
|
||||
Reference in New Issue
Block a user