# 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)