Monday, June 19, 2017

RISC-V Magenta context switch


The code related to RISC-V Magenta context switching can be found in exception.S  and switch_to.h files.
A thread for a CPU is switched by a call to
static inline void riscv_switch_to(struct riscv_thread_state * prev,
                                   struct riscv_thread_state * next)
{
    __switch_to_aux(prev, next);
    __switch_to(prev, next);
    assert(get_current());
}
The registers are saved and restored from the riscv_thread_state structure.
/*
 * Integer register context switch
 * The callee-saved registers must be saved and restored.
 * 
 *   a0: previous task_struct (must be preserved across the switch)
 *   a1: next task_struct
 */
.section .text
FUNCTION(__switch_to)
    /*
    * $a0 == &prev->arch.stat
    * $a1 == &next->arch.stat
    */
    /* Save context into prev->arch.state */
    REG_S ra,  THREAD_RA(a0)
    REG_S sp,  THREAD_SP(a0)
    REG_S s0,  THREAD_S0(a0)
    REG_S s1,  THREAD_S1(a0)
    REG_S s2,  THREAD_S2(a0)
    REG_S s3,  THREAD_S3(a0)
    REG_S s4,  THREAD_S4(a0)
    REG_S s5,  THREAD_S5(a0)
    REG_S s6,  THREAD_S6(a0)
    REG_S s7,  THREAD_S7(a0)
    REG_S s8,  THREAD_S8(a0)
    REG_S s9,  THREAD_S9(a0)
    REG_S s10, THREAD_S10(a0)
    REG_S s11, THREAD_S11(a0)
    /* Restore context from next->arch.state */
    REG_L ra,  THREAD_RA(a1)
    REG_L sp,  THREAD_SP(a1)
    REG_L s0,  THREAD_S0(a1)
    REG_L s1,  THREAD_S1(a1)
    REG_L s2,  THREAD_S2(a1)
    REG_L s3,  THREAD_S3(a1)
    REG_L s4,  THREAD_S4(a1)
    REG_L s5,  THREAD_S5(a1)
    REG_L s6,  THREAD_S6(a1)
    REG_L s7,  THREAD_S7(a1)
    REG_L s8,  THREAD_S8(a1)
    REG_L s9,  THREAD_S9(a1)
    REG_L s10, THREAD_S10(a1)
    REG_L s11, THREAD_S11(a1)
    REG_L tp,  THREAD_TI(a1) /* Next thread_info pointer */
    /*return to $ra, the new $sp has been set*/
    ret
END(__switch_to)
The new thread $ra points to the next instruction after a call to __switch_to inside riscv_switch_to
(gdb) p/x newthread->arch.state
$137 = {ra = 0xffffffff80002f3c, sp = 0xffffffff8114cc80, s = {0xffffffff8114ccb0, 0xffffffff800031c4, 0x1, 0xffffffff800347f8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, fstate = {f = {
      0x0 <repeats 32 times>}, fcsr = 0x0}, ti = 0xffffffff8114ae80}
The ret instruction at the end of __switch_to resumes a thread at this address.
The scheduled out thread state has $ra pointing to same address.
(gdb) p/x oldthread->arch.state
$138 = {ra = 0xffffffff8000b3f8, sp = 0xffffffc002e04000, s = {0x0 <repeats 12 times>}, fstate = {f = {0x0 <repeats 32 times>}, fcsr = 0x0}, ti = 0xffffffff8116a9d8}
The riscv_switch_to disassembled listing is
(gdb) disassem 0xffffffff80002f3c
Dump of assembler code for function riscv_switch_to:
   0xffffffff80002f04 <+0>: addi sp,sp,-48
   0xffffffff80002f08 <+4>: sd ra,40(sp)
   0xffffffff80002f0c <+8>: sd s0,32(sp)
   0xffffffff80002f10 <+12>: sd s1,24(sp)
   0xffffffff80002f14 <+16>: addi s0,sp,48
   0xffffffff80002f18 <+20>: mv s1,ra
   0xffffffff80002f1c <+24>: sd a0,-40(s0)
   0xffffffff80002f20 <+28>: sd a1,-48(s0)
   0xffffffff80002f24 <+32>: ld a1,-48(s0)
   0xffffffff80002f28 <+36>: ld a0,-40(s0)
   0xffffffff80002f2c <+40>: jal ra,0xffffffff80002ee0 <__switch_to_aux>
   0xffffffff80002f30 <+44>: ld a1,-48(s0)
   0xffffffff80002f34 <+48>: ld a0,-40(s0)
   0xffffffff80002f38 <+52>: jal ra,0xffffffff800003a8 <__switch_to>
   0xffffffff80002f3c <+56>: jal ra,0xffffffff80002e70 <get_current>
   0xffffffff80002f40 <+60>: mv a5,a0
   0xffffffff80002f44 <+64>: seqz a5,a5
   0xffffffff80002f48 <+68>: andi a5,a5,255
   0xffffffff80002f4c <+72>: beqz a5,0xffffffff80002f78 <riscv_switch_to+116>
   0xffffffff80002f50 <+76>: mv a0,s1
   0xffffffff80002f54 <+80>: mv a1,s0
   0xffffffff80002f58 <+84>: lui a5,0x800f2
   0xffffffff80002f5c <+88>: addi a5,a5,1880 # 0xffffffff800f2758
   0xffffffff80002f60 <+92>: li a4,34
   0xffffffff80002f64 <+96>: lui a3,0x800f2
   0xffffffff80002f68 <+100>: addi a3,a3,1896 # 0xffffffff800f2768
   0xffffffff80002f6c <+104>: lui a2,0x800f2
   0xffffffff80002f70 <+108>: addi a2,a2,1840 # 0xffffffff800f2730
   0xffffffff80002f74 <+112>: jal ra,0xffffffff8006b9f0 <_panic>
   0xffffffff80002f78 <+116>: nop
   0xffffffff80002f7c <+120>: ld ra,40(sp)
   0xffffffff80002f80 <+124>: ld s0,32(sp)
   0xffffffff80002f84 <+128>: ld s1,24(sp)
   0xffffffff80002f88 <+132>: addi sp,sp,48
   0xffffffff80002f8c <+136>: ret
As you can see 0xffffffff80002f3c is an address of a call to get_current which is a parameter to the assert check after a call to __switch_to.

No comments:

Post a Comment