mirror of
https://github.com/cccriscv/mini-riscv-os.git
synced 2025-11-16 04:24:33 +00:00
@@ -3,11 +3,19 @@
|
||||
## Build & Run
|
||||
|
||||
```sh
|
||||
user@DESKTOP-96FRN6B MINGW64 /d/ccc109/sp/11-os/mini-riscv-os/04-TimerInterrupt (master)
|
||||
$ make clean
|
||||
rm -f *.elf
|
||||
|
||||
user@DESKTOP-96FRN6B MINGW64 /d/ccc109/sp/11-os/mini-riscv-os/04-TimerInterrupt (master)
|
||||
$ make
|
||||
riscv64-unknown-elf-gcc -nostdlib -fno-builtin -mcmodel=medany -march=rv32ima -mabi=ilp32 -T os.ld -o os.elf start.s sys.s lib.c timer.c os.c
|
||||
riscv64-unknown-elf-gcc -nostdlib -fno-builtin -mcmodel=medany -march=rv32ima
|
||||
-mabi=ilp32 -T os.ld -o os.elf start.s sys.s lib.c timer.c os.c
|
||||
|
||||
user@DESKTOP-96FRN6B MINGW64 /d/ccc109/sp/11-os/mini-riscv-os/04-TimerInterrupt (master)
|
||||
$ make qemu
|
||||
Press Ctrl-A and then X to exit QEMU
|
||||
qemu-system-riscv32 -nographic -smp 4 -machine virt -bios none -kernel os.elf
|
||||
qemu-system-riscv32 -nographic -smp 4 -machine virt -bios none -kernel os.elf
|
||||
OS start
|
||||
timer_handler: 1
|
||||
timer_handler: 2
|
||||
|
||||
@@ -4,7 +4,8 @@ int os_main(void)
|
||||
{
|
||||
lib_puts("OS start\n");
|
||||
timer_init(); // start timer interrupt ...
|
||||
while (1) {} // os : do nothing, just loop!
|
||||
|
||||
while (1) {} // stop here !
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,8 @@
|
||||
#include "lib.h"
|
||||
#include "timer.h"
|
||||
|
||||
extern void os_loop(void);
|
||||
extern void user_init();
|
||||
extern void os_kernel();
|
||||
extern int os_main(void);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,15 +1,163 @@
|
||||
# This Code derived from xv6-riscv (64bit)
|
||||
# -- https://github.com/mit-pdos/xv6-riscv/blob/riscv/kernel/swtch.S
|
||||
|
||||
# ============ MACRO ==================
|
||||
.macro ctx_save base
|
||||
sw ra, 0(\base)
|
||||
sw sp, 4(\base)
|
||||
sw s0, 8(\base)
|
||||
sw s1, 12(\base)
|
||||
sw s2, 16(\base)
|
||||
sw s3, 20(\base)
|
||||
sw s4, 24(\base)
|
||||
sw s5, 28(\base)
|
||||
sw s6, 32(\base)
|
||||
sw s7, 36(\base)
|
||||
sw s8, 40(\base)
|
||||
sw s9, 44(\base)
|
||||
sw s10, 48(\base)
|
||||
sw s11, 52(\base)
|
||||
.endm
|
||||
|
||||
.macro ctx_load base
|
||||
lw ra, 0(\base)
|
||||
lw sp, 4(\base)
|
||||
lw s0, 8(\base)
|
||||
lw s1, 12(\base)
|
||||
lw s2, 16(\base)
|
||||
lw s3, 20(\base)
|
||||
lw s4, 24(\base)
|
||||
lw s5, 28(\base)
|
||||
lw s6, 32(\base)
|
||||
lw s7, 36(\base)
|
||||
lw s8, 40(\base)
|
||||
lw s9, 44(\base)
|
||||
lw s10, 48(\base)
|
||||
lw s11, 52(\base)
|
||||
.endm
|
||||
|
||||
.macro reg_save base
|
||||
# save the registers.
|
||||
sw ra, 0(\base)
|
||||
sw sp, 4(\base)
|
||||
sw gp, 8(\base)
|
||||
sw tp, 12(\base)
|
||||
sw t0, 16(\base)
|
||||
sw t1, 20(\base)
|
||||
sw t2, 24(\base)
|
||||
sw s0, 28(\base)
|
||||
sw s1, 32(\base)
|
||||
sw a0, 36(\base)
|
||||
sw a1, 40(\base)
|
||||
sw a2, 44(\base)
|
||||
sw a3, 48(\base)
|
||||
sw a4, 52(\base)
|
||||
sw a5, 56(\base)
|
||||
sw a6, 60(\base)
|
||||
sw a7, 64(\base)
|
||||
sw s2, 68(\base)
|
||||
sw s3, 72(\base)
|
||||
sw s4, 76(\base)
|
||||
sw s5, 80(\base)
|
||||
sw s6, 84(\base)
|
||||
sw s7, 88(\base)
|
||||
sw s8, 92(\base)
|
||||
sw s9, 96(\base)
|
||||
sw s10, 100(\base)
|
||||
sw s11, 104(\base)
|
||||
sw t3, 108(\base)
|
||||
sw t4, 112(\base)
|
||||
sw t5, 116(\base)
|
||||
sw t6, 120(\base)
|
||||
.endm
|
||||
|
||||
.macro reg_load base
|
||||
# restore registers.
|
||||
lw ra, 0(\base)
|
||||
lw sp, 4(\base)
|
||||
lw gp, 8(\base)
|
||||
# not this, in case we moved CPUs: lw tp, 12(\base)
|
||||
lw t0, 16(\base)
|
||||
lw t1, 20(\base)
|
||||
lw t2, 24(\base)
|
||||
lw s0, 28(\base)
|
||||
lw s1, 32(\base)
|
||||
lw a0, 36(\base)
|
||||
lw a1, 40(\base)
|
||||
lw a2, 44(\base)
|
||||
lw a3, 48(\base)
|
||||
lw a4, 52(\base)
|
||||
lw a5, 56(\base)
|
||||
lw a6, 60(\base)
|
||||
lw a7, 64(\base)
|
||||
lw s2, 68(\base)
|
||||
lw s3, 72(\base)
|
||||
lw s4, 76(\base)
|
||||
lw s5, 80(\base)
|
||||
lw s6, 84(\base)
|
||||
lw s7, 88(\base)
|
||||
lw s8, 92(\base)
|
||||
lw s9, 96(\base)
|
||||
lw s10, 100(\base)
|
||||
lw s11, 104(\base)
|
||||
lw t3, 108(\base)
|
||||
lw t4, 112(\base)
|
||||
lw t5, 116(\base)
|
||||
lw t6, 120(\base)
|
||||
.endm
|
||||
# ============ Macro END ==================
|
||||
|
||||
# Context switch
|
||||
#
|
||||
# void sys_switch(struct context *old, struct context *new);
|
||||
#
|
||||
# Save current registers in old. Load from new.
|
||||
|
||||
.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
|
||||
.align 4
|
||||
sys_kernel:
|
||||
addi sp, sp, -128 # alloc stack space
|
||||
reg_save sp # save all registers
|
||||
call timer_handler # call timer.c:timer_handler
|
||||
reg_load sp # restore all registers
|
||||
addi sp, sp, 128 # restore stack pointer
|
||||
jr a7 # jump to a7=mepc , return to timer break point
|
||||
|
||||
.globl sys_timer
|
||||
.align 4
|
||||
sys_timer:
|
||||
# call the C timer_handler(reg_t epc, reg_t cause)
|
||||
csrr a0, mepc
|
||||
csrr a1, mcause
|
||||
call timer_handler
|
||||
# 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.
|
||||
|
||||
# timer_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)
|
||||
|
||||
mret # back to interrupt location (pc=mepc)
|
||||
# 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
|
||||
csrw mepc, a1 # mret : will jump to sys_kernel
|
||||
|
||||
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)
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
#include "timer.h"
|
||||
|
||||
#define interval 10000000 // cycles; about 1 second in qemu.
|
||||
extern void os_kernel();
|
||||
|
||||
// a scratch area per CPU for machine-mode timer interrupts.
|
||||
reg_t timer_scratch[NCPU][5];
|
||||
|
||||
void timer_init()
|
||||
{
|
||||
@@ -8,8 +11,18 @@ void timer_init()
|
||||
int id = r_mhartid();
|
||||
|
||||
// ask the CLINT for a timer interrupt.
|
||||
int interval = 10000000; // cycles; about 1 second in qemu.
|
||||
*(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.
|
||||
// scratch[3] : address of CLINT MTIMECMP register.
|
||||
// scratch[4] : desired interval (in cycles) between timer interrupts.
|
||||
reg_t *scratch = &timer_scratch[id][0];
|
||||
scratch[3] = CLINT_MTIMECMP(id);
|
||||
scratch[4] = interval;
|
||||
w_mscratch((reg_t)scratch);
|
||||
|
||||
// set the machine-mode trap handler.
|
||||
w_mtvec((reg_t)sys_timer);
|
||||
|
||||
@@ -22,15 +35,7 @@ void timer_init()
|
||||
|
||||
static int timer_count = 0;
|
||||
|
||||
reg_t timer_handler(reg_t epc, reg_t cause)
|
||||
{
|
||||
reg_t return_pc = epc;
|
||||
// disable machine-mode timer interrupts.
|
||||
w_mie(~((~r_mie()) | (1 << 7)));
|
||||
void timer_handler() {
|
||||
lib_printf("timer_handler: %d\n", ++timer_count);
|
||||
int id = r_mhartid();
|
||||
*(reg_t *)CLINT_MTIMECMP(id) = *(reg_t *)CLINT_MTIME + interval;
|
||||
// enable machine-mode timer interrupts.
|
||||
w_mie(r_mie() | MIE_MTIE);
|
||||
return return_pc;
|
||||
// os_kernel();
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
#include "sys.h"
|
||||
#include "lib.h"
|
||||
|
||||
extern reg_t timer_handler(reg_t epc, reg_t cause);
|
||||
extern void timer_handler();
|
||||
extern void timer_init();
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user