Showing posts with label Magenta. Show all posts
Showing posts with label Magenta. Show all posts

Sunday, June 25, 2017

Magenta RISC-V booting

Below is an output of Magenta RISC-V port riscv-magenta

[1266874889.709] 00000.00000> Available physical memory: 2032dMB
[1266874889.709] 00000.00000> 
welcome to lk/MP

[1266874889.709] 00000.00000> INIT: cpu 0, calling hook 0xffffffff8006e2d4 (global_prng_seed) at level 0x30000, flags 0x1
[1266874889.709] 00000.00000> WARNING: System has insufficient randomness.  It is completely unsafe to use this system for any cryptographic applications.
[1266874889.709] 00000.00000> INIT: cpu 0, calling hook 0xffffffff800386b0 (elf_build_id) at level 0x3fffe, flags 0x1
[1266874889.709] 00000.00000> INIT: cpu 0, calling hook 0xffffffff800385f0 (version) at level 0x3ffff, flags 0x1
[1266874889.709] 00000.00000> version:
[1266874889.709] 00000.00000>  arch:     RISCV
[1266874889.709] 00000.00000>  platform: RISCV_RV64
[1266874889.709] 00000.00000>  target:   QEMU_RISCV_RV64
[1266874889.709] 00000.00000>  project:  MAGENTA_QEMU_RISCV_RV64
[1266874889.709] 00000.00000>  buildid:  GIT_0FBB50D3A8FC1D242E1D7A2921674579C9192D66_DIRTY_LOCAL
[1266874889.709] 00000.00000>  ELF build ID: be2909891fc4cce74084f5fa3f14d6e98903d3bb
[1266874889.709] 00000.00000> INIT: cpu 0, calling hook 0xffffffff80042f0c (vm_preheap) at level 0x3ffff, flags 0x1
[1266874889.709] 00000.00000> initializing heap
[1266874889.709] 00000.00000> INIT: cpu 0, calling hook 0xffffffff8004305c (vm) at level 0x50000, flags 0x1
[1266874889.709] 00000.00000> VM: reserving kernel region [ffffffff80000000, ffffffff800f7000) flags 0x28 name 'kernel_code'
[1266874889.709] 00000.00000> VM: reserving kernel region [ffffffff800f7000, ffffffff80139000) flags 0x8 name 'kernel_rodata'
[1266874889.709] 00000.00000> VM: reserving kernel region [ffffffff80139000, ffffffff8013c000) flags 0x18 name 'kernel_data'
[1266874889.709] 00000.00000> VM: reserving kernel region [ffffffff8013c000, ffffffff80166000) flags 0x18 name 'kernel_bss'
[1266874889.709] 00000.00000> VM: reserving kernel region [ffffffff8016a000, ffffffff8114b000) flags 0x18 name 'kernel_bootalloc'
[1266874889.709] 00000.00000> INIT: cpu 0, calling hook 0xffffffff8000197c (timer) at level 0x50003, flags 0x1
[00003.966] 00000.00000> initializing mp
[00003.966] 00000.00000> initializing threads
[00003.967] 00000.00000> initializing timers
[00003.967] 00000.00000> INIT: cpu 0, calling hook 0xffffffff800132d4 (debuglog) at level 0x6ffff, flags 0x1
[00003.970] 00000.00000> INIT: cpu 0, calling hook 0xffffffff8006e448 (global_prng_thread_safe) at level 0x6ffff, flags 0x1
[00003.971] 00000.00000> creating bootstrap completion thread
[00004.057] 00000.00000> top of bootstrap2()
[00004.058] 00000.00000> INIT: cpu 0, calling hook 0xffffffff80070c9c (dpc) at level 0x70000, flags 0x1
[00004.064] 00000.00000> INIT: cpu 0, calling hook 0xffffffff8009158c (magenta) at level 0x70000, flags 0x1
[00004.078] 00000.00000> initializing platform
[00004.078] 00000.00000> initializing target
[00004.078] 00000.00000> calling apps_init()
[00004.078] 00000.00000> INIT: cpu 0, calling hook 0xffffffff80014464 (ktrace) at level 0xaffff, flags 0x1
[00005.091] 00000.00000> ktrace: buffer at 0xffffffc000e01000 (33554432 bytes)
[00005.094] 00000.00000> INIT: cpu 0, calling hook 0xffffffff800384bc (userboot) at level 0xaffff, flags 0x1
[00005.161] 00000.00000> userboot: userboot rodata       0 @ [0x292f043000,0x292f045000)
[00005.163] 00000.00000> userboot: userboot code    0x2000 @ [0x292f045000,0x292f05a000)
[00005.165] 00000.00000> userboot: vdso/full rodata       0 @ [0x292f05a000,0x292f05f000)
[00005.167] 00000.00000> userboot: vdso/full code    0x5000 @ [0x292f05f000,0x292f061000)
[00005.193] 00000.00000> userboot: entry point             @ 0x292f046da0
[00005.293] 00000.00000> starting app shell
] [00005.296] 00000.00000> entering main console loop

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.

Monday, June 12, 2017

RISC-V Magenta. The init process.

The init process address space initialisation.
#2  0xffffffff80004690 in arch_mmu_init_aspace (aspace=0xffffffff81168310, base=16777216, size=274861125632, flags=0) at kernel/arch/riscv/mmu.cpp:73
#3  0xffffffff8004bb64 in VmAspace::Init (this=0xffffffff811681c0) at kernel/kernel/vm/vm_aspace.cpp:142
#4  0xffffffff8004bdb0 in VmAspace::Create (flags=0, name=0x0) at kernel/kernel/vm/vm_aspace.cpp:180
#5  0xffffffff8008f7e0 in ProcessDispatcher::Initialize (this=0xffffffff81167eb0) at kernel/lib/magenta/process_dispatcher.cpp:147
#6  0xffffffff8008ef30 in ProcessDispatcher::Create (job=..., name=..., flags=0, dispatcher=0xffffffff81146e48, rights=0xffffffff81146e3c, root_vmar_disp=0xffffffff81146e40, 
    root_vmar_rights=0xffffffff81146e38) at kernel/lib/magenta/process_dispatcher.cpp:73
#7  0xffffffff80032b84 in attempt_userboot () at kernel/lib/userboot/userboot.cpp:283
#8  0xffffffff800330ec in userboot_init (level=720895) at kernel/lib/userboot/userboot.cpp:357
#9  0xffffffff80005da8 in lk_init_level (required_flag=LK_INIT_FLAG_PRIMARY_CPU, start_level=655360, stop_level=720895) at kernel/top/init.c:86
#10 0xffffffff80005e4c in lk_primary_cpu_init_level (start_level=655360, stop_level=720895) at kernel/include/lk/init.h:51
#11 0xffffffff800060fc in bootstrap2 (arg=0x0) at kernel/top/main.c:136
#12 0xffffffff8000a78c in initial_thread_func () at kernel/kernel/thread.c:84
#13 0xffffffff8000a74c in init_thread_struct (t=0xffffffff81144be0, name=0x0) at kernel/kernel/thread.c:72

Friday, May 19, 2017

Magenta RISC-V is running in kernel mode with threads.

Great news!

Magenta RISC-V port ( riscv-magenta ) reached a milestone. The kernel is running and switching between kernel threads.

Tuesday, May 16, 2017

RISC-V Magenta kernel manual stack unwinding

A manual stack unwinding when handle_exception sets a call frame
(gdb) bt
#0  0xffffffff8002e0c4 in _panic (caller=0xffffffff80002554 <do_trap_insn_misaligned+52>, frame=0xffffffff80040de8 <init_thread_union+7656>, fmt=0xffffffff800343c8 "%s unimplemented\n")
    at kernel/lib/debug/debug.c:32
#1  0xffffffff80002490 in do_trap_error (regs=0xffffffff80040e08 <init_thread_union+7688>, signo=7, code=1, addr=18446744071562076884, str=0xffffffff80034420 "Oops - instruction address misaligned")
    at kernel/arch/riscv/traps.c:52
#2  0xffffffff80002554 in do_trap_insn_misaligned (regs=0xffffffff80040e08 <init_thread_union+7688>) at kernel/arch/riscv/traps.c:67
#3  0xffffffff8000027c in handle_exception () at kernel/arch/riscv/rv64/exception.S:221
Backtrace stopped: frame did not save the PC
A frame stack has the following layout
struct frame{
    coid* caller_s0; // $s0
    void* caller_pc; // $ra
}
the current frame pointer is saved in the s0 register.
(gdb) p/x $s0
$1 = 0xffffffff80040d88
(gdb) x/2xg 0xffffffff80040d88-16
0xffffffff80040d78 <init_thread_union+7544>: 0xffffffff80040de8 0xffffffff80002490
(gdb) x/2xg 0xffffffff80040de8-16
0xffffffff80040dd8 <init_thread_union+7640>: 0xffffffff80040e08 0xffffffff80002554
(gdb) x/2xg 0xffffffff80040e08-16
0xffffffff80040df8 <init_thread_union+7672>: 0xffffffff80040f30 0xffffffff8000027c
(gdb) x/2xg 0xffffffff80040f30-16
0xffffffff80040f20 <init_thread_union+7968>: 0xffffffff80040f70 0xffffffff800022d4
(gdb) x/2xg 0xffffffff80040f70-16
0xffffffff80040f60 <init_thread_union+8032>: 0xffffffff80040fb0 0xffffffff80008f20
(gdb) x/2xg 0xffffffff80040fb0-16
0xffffffff80040fa0 <init_thread_union+8096>: 0xffffffff80040fe0 0xffffffff80008ff8
(gdb) x/5i 0xffffffff8000027c
   0xffffffff8000027c <handle_exception+352>: ld s1,256(sp)
   0xffffffff80000280 <handle_exception+356>: csrci sstatus,2
   0xffffffff80000284 <handle_exception+360>: andi s1,s1,256
   0xffffffff80000288 <handle_exception+364>: bnez s1,0xffffffff80000294 <handle_exception+376>
   0xffffffff8000028c <handle_exception+368>: addi s1,sp,280
(gdb) x/5i 0xffffffff800022d4
   0xffffffff800022d4 <arch_thread_construct_first+36>: sw a5,0(a4)
   0xffffffff800022d8 <arch_thread_construct_first+40>: jal ra,0xffffffff800021e4 <current_thread_info>
   0xffffffff800022dc <arch_thread_construct_first+44>: sd a0,-40(s0)
   0xffffffff800022e0 <arch_thread_construct_first+48>: ld a5,-40(s0)
   0xffffffff800022e4 <arch_thread_construct_first+52>: ld a4,-56(s0)
(gdb) x/5i 0xffffffff80008f20
   0xffffffff80008f20 <thread_construct_first+188>: addi a5,s0,-48
   0xffffffff80008f24 <thread_construct_first+192>: li a2,0
   0xffffffff80008f28 <thread_construct_first+196>: mv a1,a5
   0xffffffff80008f2c <thread_construct_first+200>: lui a5,0x80045
   0xffffffff80008f30 <thread_construct_first+204>: addi a0,a5,-1232
(gdb) x/5i 0xffffffff80008ff8
   0xffffffff80008ff8 <thread_init_early+112>: jal ra,0xffffffff80007678 <sched_init_early>
   0xffffffff80008ffc <thread_init_early+116>: nop
   0xffffffff80009000 <thread_init_early+120>: ld ra,40(sp)
   0xffffffff80009004 <thread_init_early+124>: ld s0,32(sp)
   0xffffffff80009008 <thread_init_early+128>: ld s1,24(sp)
GDB can not unwind after handle_exception as it is unable to verify that the handle_exception frame is valid, the handle_exception function has been written on assembler with a prolog that restores sp from a scratch register instead of a frame initalization. I added a frame pointer saving for handle_exception after the stack pointer restoration ( https://github.com/slavaim/riscv-magenta/blob/riscv/kernel/arch/riscv/rv64/exception.S ).
    /*a call frame to facilitate with debugging*/
    .macro SET_GDB_FRAME
    addi    sp, sp, -2*SZREG /* allocate the frame */
    REG_S   s0, 0(sp)        /* get the frame pointer at the exception moment */
    csrr    s0, sepc         /* get the exception PC */
    REG_S   s0, SZREG(sp)    /* set the exception PC as $ra for the frame */
    addi    s0, sp, 2*SZREG  /* set s0 to the current frame pointer */
    .endm

    .macro DEL_GDB_FRAME
    REG_L   s0, 0(sp)        /* restore the caller frame pointer */
    addi    sp, sp, 2*SZREG  /* restore the stack pointer */
    .endm
From the frame before the exception handler we see that the arch_thread_construct_first raised the exception. We need to examine this function prologue to get the offset to the bootom of the stack from the frame address.
(gdb) x/10i arch_thread_construct_first
   0xffffffff800022b0 <arch_thread_construct_first>: addi sp,sp,-64
   0xffffffff800022b4 <arch_thread_construct_first+4>: sd ra,56(sp)
   0xffffffff800022b8 <arch_thread_construct_first+8>: sd s0,48(sp)
   0xffffffff800022bc <arch_thread_construct_first+12>: sd s1,40(sp)
   0xffffffff800022c0 <arch_thread_construct_first+16>: addi s0,sp,64
   0xffffffff800022c4 <arch_thread_construct_first+20>: mv s1,ra
   0xffffffff800022c8 <arch_thread_construct_first+24>: sd a0,-56(s0)
   0xffffffff800022cc <arch_thread_construct_first+28>: li a4,0
   0xffffffff800022d0 <arch_thread_construct_first+32>: li a5,1
=> 0xffffffff800022d4 <arch_thread_construct_first+36>: sw a5,0(a4)
Now the $pc, $sp and $s0 (a frame pointer ) registers can be set to unwind the stack before handle_exception was called by a CPU. 64 bytes was subtracted from the s0 register value to get the sp register value according to the function prologue displayed above.
(gdb) set $pc=0xffffffff800022d4
(gdb) set $sp=0xffffffff80040f70-64
(gdb) set $s0=0xffffffff80040f70
(gdb) bt
#0  0xffffffff800022d4 in arch_thread_construct_first (t=0xffffffff800426d8 <idle_threads>) at kernel/arch/riscv/thread.c:34
#1  0xffffffff80008f20 in thread_construct_first (t=0xffffffff800426d8 <idle_threads>, name=0xffffffff80035368 "bootstrap") at kernel/kernel/thread.c:1016
#2  0xffffffff80008ff8 in thread_init_early () at kernel/kernel/thread.c:1037
#3  0xffffffff80003ec4 in lk_main () at kernel/top/main.c:53
#4  0xffffffff8000146c in _riscv_start () at kernel/arch/riscv/rv64/start.S:42
Backtrace stopped: frame did not save the PC