enter_supervisor_mode

 

 

204     void enter_supervisor_mode(void (*fn)(uintptr_t), uintptr_t arg0, uintptr_t arg1)
205   {
206         uintptr_t mstatus = read_csr(mstatus);
207      mstatus = INSERT_FIELD(mstatus, MSTATUS_MPP, PRV_S);
208      mstatus = INSERT_FIELD(mstatus, MSTATUS_MPIE, 0);
209         write_csr(mstatus, mstatus);
210      write_csr(mscratch, MACHINE_STACK_TOP() - MENTRY_FRAME_SIZE);
211        #ifndef __riscv_flen
212      uintptr_t *p_fcsr = MACHINE_STACK_TOP() - MENTRY_FRAME_SIZE; // the x0's save slot
213      *p_fcsr = 0;
214       #endif
215      write_csr(mepc, fn);
216
217         register uintptr_t a0 asm ("a0") = arg0;
218         register uintptr_t a1 asm ("a1") = arg1;
219       asm volatile ("mret" : : "r" (a0), "r" (a1));
220      __builtin_unreachable();
221     }

The relevant bits of the code disassembled:

80004300 <enter_supervisor_mode>:

void enter_supervisor_mode(void (*fn)(uintptr_t), uintptr_t arg0, uintptr_t arg1)
{
...
 write_csr(mepc, fn);
800043a4:    fdc42783              lw    a5,-36(s0)
800043a8:    34179073              csrw    mepc,a5

 register uintptr_t a0 asm ("a0") = arg0;
800043ac:    fd842503              lw    a0,-40(s0)
 register uintptr_t a1 asm ("a1") = arg1;
800043b0:    fd442583              lw    a1,-44(s0)
 asm volatile ("mret" : : "r" (a0), "r" (a1));
800043b4:    30200073              mret

800043b8 <enter_machine_mode>:
 __builtin_unreachable();
}

 

 

在enter_supervisor_mode函数中,将 mstatus的MPP域设置为1,表示中断发生之前的模式是Supervisor,将mstatus的MPIE域设置为0,表示中段发生前MIE的值为0。随即将机器模式的内核栈顶写入mscratch寄存器中,设置mepc为rest_of_boot_loader的地址,并将kernel_stack_top与0作为参数存入a0和a1。

​最后,执行mret指令,该指令执行时,程序从机器模式的异常返回,将程序计数器pc设置为mepc,即rest_of_boot_loader的地址;将特权级设置为mstatus寄存器的MPP域,即方才所设置的代表Supervisor的1,MPP设置为0;将mstatus寄存器的MIE域设置为MPIE,即方才所设置的表示中断关闭的0,MPIE设置为1。

​于是,当mret指令执行完毕.

This means that by setting up the MSTATUS_MPP, MSTATUS_MPIE fields

For comparison, the enter_machine_mode counterpart is simpler as the bootloader code is already running in the machine mode:

  uintptr_t mstatus = read_csr(mstatus);
  mstatus = INSERT_FIELD(mstatus, MSTATUS_MPIE, 0);
  write_csr(mstatus, mstatus);
  write_csr(mscratch, MACHINE_STACK_TOP() - MENTRY_FRAME_SIZE);

  /* Jump to the payload's entry point */
  fn(arg0, arg1);

  __builtin_unreachable();
}

 

上一篇:linux系统进行supervisor安装使用


下一篇:supervisor管理服务器的进程——守护进程