---
# System prepended metadata

title: 'xv6 Kernel-3: Startup + Organization'

---

# xv6 Kernel-3: Startup + Organization
### xv6 開機的三大步驟
1. `entry.S`: set up stack
1. `start.c`: machine mode
1. `main.c`: supervisor mode

* modes of xv6
1. machine mode: 極少的 kernel 會使用 machine mode
1. supervisor mode: 多數 kernel 都是使用這個 mode
1. user mode: user program 使用的 mode

### `entry.S` 的解析
```asm=
        # qemu -kernel loads the kernel at 0x80000000
        # and causes each hart (i.e. CPU) to jump there.
        # kernel.ld causes the following code to
        # be placed at 0x80000000.
.section .text
.global _entry
_entry:
        # set up a stack for C.
        # stack0 is declared in start.c,
        # with a 4096-byte stack per CPU.
        # sp = stack0 + (hartid * 4096)
        la sp, stack0
        li a0, 1024*4
        csrr a1, mhartid
        addi a1, a1, 1
        mul a0, a0, a1
        add sp, sp, a0
        # jump to start() in start.c
        call start
spin:
        j spin
```
* [csr](https://ithelp.ithome.com.tw/articles/10289643)

### `main.c` 的解析
```clike=
#include "types.h"
#include "param.h"
#include "memlayout.h"
#include "riscv.h"
#include "defs.h"

volatile static int started = 0;

// start() jumps here in supervisor mode on all CPUs.
void
main()
{
  if(cpuid() == 0){
    consoleinit();
    printfinit();
    printf("\n");
    printf("xv6 kernel is booting\n");
    printf("\n");
    kinit();         // physical page allocator
    kvminit();       // create kernel page table
    kvminithart();   // turn on paging
    procinit();      // process table
    trapinit();      // trap vectors
    trapinithart();  // install kernel trap vector
    plicinit();      // set up interrupt controller
    plicinithart();  // ask PLIC for device interrupts
    binit();         // buffer cache
    iinit();         // inode table
    fileinit();      // file table
    virtio_disk_init(); // emulated hard disk
    userinit();      // first user process
    __sync_synchronize();
    started = 1;
  } else {
    while(started == 0)
      ;
    __sync_synchronize();
    printf("hart %d starting\n", cpuid());
    kvminithart();    // turn on paging
    trapinithart();   // install kernel trap vector
    plicinithart();   // ask PLIC for device interrupts
  }

  scheduler();        
}
```
當 xv6 開機時，只有其中一個 CPU 在做初始化了動作，其他的 CPU 就要等到這個 CPU 把事情做完之後，才會開始做各自的事情。

* 在 `main()` 的最後，會執行 `scheduler()` (可能跟 yunikoen 的 scheduler 的角色有點像)
### `kernel/proc.c: scheduler()`
* 這是在 `main()` 最後一行執行的 function
```clike=
void
scheduler(void)
{
  struct proc *p;
  struct cpu *c = mycpu();
  
  c->proc = 0;
  for(;;){
    // Avoid deadlock by ensuring that devices can interrupt.
    intr_on();

    for(p = proc; p < &proc[NPROC]; p++) {
      acquire(&p->lock);
      if(p->state == RUNNABLE) {
        // Switch to chosen process.  It is the process's job
        // to release its lock and then reacquire it
        // before jumping back to us.
        p->state = RUNNING;
        c->proc = p;
        swtch(&c->context, &p->context);

        // Process is done running for now.
        // It should have changed its p->state before coming back.
        c->proc = 0;
      }
      release(&p->lock);
    }
  }
}
```
* `scheduler()` 是只有一個 thread 在執行嗎？

### 註記
* `__sync_syncronize()` 的作用：
    * 必須要先前的程式都執行完了，才可以往下執行
* `kernel/param.h` 裏面有紀錄了一些參數

## 參考資料
* [xv6 Kernel-3: Startup + Organization](https://www.youtube.com/watch?v=6hhJ6JN95As&list=PLbtzT1TYeoMhTPzyTZboW_j7TPAnjv9XB&index=4)