risc-v Lookup

CSRs 参考riscv-privileged-20211203.pdf sstatus SPP: 在进入S mode之前hart处于什么mode。 用户态trap进入S mode,SPP被设置为0,其他情况为1。 如果SPP为0,执行SRET后,返回U mode。如果SPP为1,执行SRET后,返回S mode。随后SPP置0。 SIE: 1开启/0关闭 S mode的所有中断 in S mode。 在U mode时,SIE被忽略,S mode 的中断都是打开的。 SPIE: 当trap进入S mode,SIE会置0禁止S mode所有中断,SIE的旧值会保存到SPIE中。 执行SRET后,SIE被设置为SPIE中之前保存的旧值,SPIE置1。 stvec Supervisor Trap Vector Base Address Register, 保存S mode异常/中断的跳转地址。 MODE为0,直接跳转到BASE;MODE为1,跳转到BASE + cause * 4。 在linux entry.S中的做法为直接设置stvec为handle_exception地址,地址的后两位肯定是4bytes对齐的,所以为00。跳转到handle_exception后,分开处理中断、系统调用、异常。根据异常cause再跳转到不同的异常处理函数。 SIP SIE Supervisor Interrupt pending/enable Registers SIP中断挂起(待处理的中断)和SIE中断使能。每一位代表的中断与scause中的为每个中断分配的异常码一致。 当sstatus.SIE=1, SIP[x]=1, SIE[x]=1,表示系统能够处理某个中断。 SIP中有的位是只读的,不能通过直接写0来清除: SEIP is read-only in sip, and is set and cleared by the execution environment, typically through a platform-specific interrupt controller....

2023-05-26 · 1 min

uCore_Chapter3 多道程序与分时多任务

分时多任务系统与抢占式调度 RISC-V架构中断 以内核所在的 S 特权级为例,中断屏蔽相应的 CSR 有 sstatus 和 sie 。sstatus 的 sie 为 S 特权级的中断使能,能够同时控制三种中断,如果将其清零则会将它们全部屏蔽。即使 sstatus.sie 置 1 ,还要看 sie 这个 CSR,它的三个字段 ssie/stie/seie 分别控制 S 特权级的软件中断、时钟中断和外部中断的中断使能。 当 Trap 发生时,sstatus.sie 会被保存在 sstatus.spie 字段中,同时 sstatus.sie 置零,这也就在 Trap 处理的过程中屏蔽了所有 S 特权级的中断; 当 Trap 处理完毕 sret 的时候, sstatus.sie 会恢复到 sstatus.spie 内的值。 也就是说,如果不去手动设置 sstatus CSR ,在只考虑 S 特权级中断的情况下,是不会出现 嵌套中断 (Nested Interrupt) 的。 嵌套中断可以分为两部分:在处理一个中断的过程中又被同特权级/高特权级中断所打断。默认情况下硬件会避免前一部分,也可以通过手动设置来允许前一部分的存在;而从上面介绍的规则可以知道,后一部分则是无论如何设置都不可避免的。 时钟中断与计时器 计数器保存在一个 64 位的 CSR mtime 另外一个 64 位的 CSR mtimecmp 的作用是:一旦计数器 mtime 的值超过了 mtimecmp,就会触发一次时钟中断。这使得我们可以方便的通过设置 mtimecmp 的值来决定下一次时钟中断何时触发。...

2023-05-17 · 2 min

uCore_Chapter1 应用程序与基本执行环境

Notes make build # 仅编译 make run # 编译+运行qemu make run LOG=trace # 其他选项可以看Makefile make clean # rm build/ make debug # 编译+运行gdb调试 每次在make run之前,尽量先执行make clean以删除缓存,特别是在切换ch分支之后。 退出 qemu 的方法 如果是正常推出,uCore 会自动关闭 qemu,但如果 os 跑飞了,我们不能通过 Ctrl + C 来推出。此时可以先按下 Ctrl+A ,再按下 X 来退出 Qemu。 ch1 流程 // entry.S _entry la sp, boot_stack_top //设置堆栈 call main // main.c clean_bss(); printf("hello wrold!\n"); consputc(); console_putchar(int c); sbi_call(SBI_CONSOLE_PUTCHAR, c, 0, 0); 怎么用gdb调试?`file kernel`然后? Makefile流程分析 根据make run 打印的信息:...

2023-04-25 · 1 min

uCore_Chapter2 批处理系统

make -C user clean # 在os目录,相当于cd user;make clean;cd .. make clean # 或者在user目录 git checkout ch2 make user BASE=1 CHAPTER=2 make run make test BASE=1 # make test 会完成 make user 和 make run 两个步骤(自动设置 CHAPTER) 流程 main(); printf("hello wrold!\n"); trap_init(); // 设置中断/异常处理地址 w_stvec((uint64)uservec & ~0x3); //把uservec地址传入,uservec在trampoline.S中定义 asm volatile("csrw stvec, %0" : : "r"(x)); // 设置stvec CSR loader_init(); run_next_app(); load_app(); usertrapret(trapframe, (uint64)boot_stack_top); w_sepc(trapframe->epc); r_sstatus(); w_sstatus(); userret(); sret // 返回到sepc中的值,0x80400000第一个app 应用程序系统调用ecall进入内核异常处理过程 // 进入应用程序 exit(MAGIC); syscall(SYS_exit, code); __syscall1(n, long(1234)); __asm_syscall("r"(a7), "0"(a0)); ecall //通过ecall 进入uservec uservec usertrap(); // ld t0, 16(a0) jr t0 r_scause(); csrr %0, scause // 应用层调用了ecall指令,所以scause自动被设置为8 syscall(); //在uservec中应用层传入eid到寄存器a7,这里读a7来判断是什么system call id = trapframe->a7; usertrapret(); // 这里回到第九行一样,循环,执行第二个应用程序 分析下uservec,注意:这里只是把stvec设置为uservec地址,并不会执行uservec下的代码,要等U mode的中断/异常到来时才会从uservec开始执行。...

2023-04-25 · 1 min