先抛出来一个问题,为什么不直接使用 mscratch ?
直接使用 mscratch 作为基地址是不合适的,因为 mscratch 是一个CSR寄存器,而 reg_save 和 reg_restore 宏需要一个通用寄存器作为基地址。此外,mscratch 不能用于加载和存储指令的基地址,因为这些指令只接受通用寄存器作为基地址。

内核启动

#include "os.h"
//外部文件定义的函数
extern void uart_init(void);
extern void page_init(void);
extern void sched_init(void);
extern void schedule(void);

void start_kernel(void)
{
    uart_init();
    uart_puts("Hello, RVOS!\n");
    page_init(); //内存初始化 
    sched_init(); //多任务切换的初始化
    schedule();//触发多任务切换
    uart_puts("Would not go here!\n");
    while (1) {}; // stop here!
}

切换的核心逻辑

static void w_mscratch(reg_t x) {
  asm volatile("csrw mscratch, %0" : : "r"(x));
}

void user_task0(void);
void sched_init() {
  w_mscratch(0);
  // ctx_task没有切换之前这里只是一段内存空间
  // sp 是内存模拟,这代区域代表,栈空间,给了一个新的地址, 这个很重要, 灵魂
  // ra 也是内存模拟。这会还都是内存空间,没啥实际意义,需要触发才有意义
  // sp 是ra 这个任务用到的栈空间

  ctx_task.sp = (reg_t)&task_stack[STACK_SIZE];
  ctx_task.ra = (reg_t)user_task0;
}

void schedule() {
  struct context *next = &ctx_task;
  //切换给当前线程的一个任务,这里出发一个函数调用
  //a0=next
  switch_to(next);
  //退出之后, 有xxx输出,正常应该是走不到
}

// 下面是任务的模拟, 没啥好说的

void task_delay(volatile int count) {
  count *= 50000;
  while (count--)
    ;
}

void user_task0(void) {
  uart_puts("Task 0: Created!\n");
  while (1) {
    uart_puts("Task 0: Running...\n");
    task_delay(1000);
  }
}

接下来分析一个switch_to 函数

.text
.globl switch_to
.balign 4
switch_to:
    # 从总的执行过程来看: 
    # 函数第一次被调用的时候,mscratch=0,执行到label=1地方,建议先看label=1 之后的代码
    # 函数第二次调用的时候,mscratch=a0=要执行任务的地址, 不等于0,执行到 reg_save t6, 把自己保存起来
    # mscratch 相当于一个任务的指针,为啥没有直接用它呢? 而是用一个t6? 
    # 原因是-->
    csrrw    t6, mscratch, t6    
    beqz    t6, 1f                                      
    reg_save t6        

    mv    t5, t6        
    csrr    t6, mscratch        
    STORE    t6, 30*SIZE_REG(t5)
1:
    csrw    mscratch, a0 #此时,a0是next指针
    mv    t6, a0 
    #相当于一个环境的初始化, 触发之前的准备,把内存模拟的sp,ra 等真正的加载到寄存器中
    reg_restore t6 
    #伪指令  相当于 jalr x0, ra, 0。 
    #开始触发,跳转到ra的地址处执行,ra 存储的是任务的地址。sp存储的是任务的栈
    #ret  执行的是ra , 不是return 关键字
    #这个函数严格来说,只是一个切换任务的函数
    ret 

.end

putao
8 声望1 粉丝

推动世界向前发展,改善民生。