Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
xv6 initプロセス ことはじめ
Search
Toasa
February 08, 2020
Programming
6
2.8k
xv6 initプロセス ことはじめ
教育用OS「xv6」のソースコードから、initプロセスの生成と実行を見る。
Toasa
February 08, 2020
Tweet
Share
Other Decks in Programming
See All in Programming
Playwrightはどのようにクロスブラウザをサポートしているのか
yotahada3
7
2.3k
開発者への寄付をアプリ内課金として実装する時の気の使いどころ
ski
0
350
止められない医療アプリ、そっと Swift 6 へ
medley
1
120
タスクの特性や不確実性に応じた最適な作業スタイルの選択(ペアプロ・モブプロ・ソロプロ)と実践 / Optimal Work Style Selection: Pair, Mob, or Solo Programming.
honyanya
3
140
iOS 17で追加されたSubscriptionStoreView を利用して5分でサブスク実装チャレンジ
natmark
0
620
私達はmodernize packageに夢を見るか feat. go/analysis, go/ast / Go Conference 2025
kaorumuta
2
500
私はどうやって技術力を上げたのか
yusukebe
43
17k
uniqueパッケージの内部実装を支えるweak pointerの話
magavel
0
920
Your Perfect Project Setup for Angular @BASTA! 2025 in Mainz
manfredsteyer
PRO
0
130
ポスターセッション: 「まっすぐ行って、右!」って言ってラズパイカーを動かしたい 〜生成AI × Raspberry Pi Pico × Gradioの試作メモ〜
komofr
0
980
Catch Up: Go Style Guide Update
andpad
0
180
dynamic!
moro
9
6.7k
Featured
See All Featured
JavaScript: Past, Present, and Future - NDC Porto 2020
reverentgeek
52
5.6k
GraphQLとの向き合い方2022年版
quramy
49
14k
A Modern Web Designer's Workflow
chriscoyier
697
190k
StorybookのUI Testing Handbookを読んだ
zakiyama
31
6.2k
Six Lessons from altMBA
skipperchong
28
4k
Fight the Zombie Pattern Library - RWD Summit 2016
marcelosomers
234
17k
Designing for humans not robots
tammielis
254
25k
Understanding Cognitive Biases in Performance Measurement
bluesmoon
29
2.6k
Building Flexible Design Systems
yeseniaperezcruz
329
39k
How STYLIGHT went responsive
nonsquared
100
5.8k
Optimizing for Happiness
mojombo
379
70k
Build your cross-platform service in a week with App Engine
jlugia
232
18k
Transcript
xv6 initプロセス ことはじめ toasa
自己紹介 - 仕事:zen言語でアプリケーションを書いている - 趣味:低レイヤのことなど
OSの勉強中...
「あるプロセスには親プロセスが存在する」 → その親にも親が存在する → その親も . . . ではすべての祖となるようなプロセスはあるの? → init プロセス
init プロセスとは? - UNIX系での呼び名 - PIDは1 - あらゆるプロセスの祖 → なんだか、かっこいいな
手軽なOSで initプロセスを 見てみよう
xv6
xv6とは? - 教育用OS - Unix v6インスパイア - ANSI Cで書かれた -
x86上で動く - https://github.com/mit-pdos/xv6-public
何故xv6? • 学習用途 ◦ ANSI Cで書かれている ◦ 総行数約8500行(.c or .S)
▪ ヘッダファイル含めても1万行いかない ◦ 教科書がある https://pdos.csail.mit.edu/6.828/2018/xv6/book-rev11.pdf
どれくらい わかりやすいの? → catコマンドを見てみよう
catコマンド void cat(int fd) { int n; while((n = read(fd,
buf, sizeof(buf))) > 0) { if (write(1, buf, n) != n) { printf(1, "cat: write error\n"); exit(); } } if(n < 0){ printf(1, "cat: read error\n"); exit(); } }
では、本題
xv6の initプロセス (の生成と実行) を見ていこう
注意 • マルチプロセッサの話題は話(し | せ)ません • ブートローダー → カーネル → init プロセス
注意 • マルチプロセッサの話題は話(し | せ)ません • ブートローダー → カーネル → init プロセス カーネルの起動&設定は完了済とする
注意 • マルチプロセッサの話題は話(し | せ)ません • ブートローダー → カーネル → init プロセス • 図は上が
high アドレス カーネルの起動&設定は完了済とする
xv6の プロセス
proc構造体(一部) struct proc { pde_t* pgdir; char *kstack; enum procstate
state; int pid; struct proc *parent; struct trapframe *tf; struct context *context; };
proc構造体 struct proc { pde_t* pgdir; char *kstack; enum procstate
state; int pid; struct proc *parent; struct trapframe *tf; struct context *context; }; context tf parent pid state kstack pgdir high
あらすじ • init プロセスを生成 • プロセステーブルに登録 • スケジューラに選ばれる • コンテキストスイッチ
• init 実行
main int main(void) { ... userinit(); mpmain(); }
userinit(概要) • initプロセスを生成する ◦ allocproc() • initのカーネル空間のpagingを設定する ◦ setupkvm() •
initのプログラムをメモリに展開する ◦ inituvm()
userinit(概要) • initプロセスを生成する ◦ allocproc() • initのカーネル空間のpagingを設定する ◦ setupkvm() •
initのプログラムをメモリに展開する ◦ inituvm()
userinit() void userinit(void) { struct proc *p; p = allocproc();
if((p->pgdir = setupkvm()) == 0) panic("userinit: out of memory?"); inituvm(p->pgdir, _binary_initcode_start, _binary_initcode_size); ..... }
allocproc()に 入る前に...
proc.cのグローバル変数 struct { ... struct proc proc[64]; } ptable; int
nextpid = 1;
プロセステーブル struct { ... struct proc proc[64]; } ptable; int
nextpid = 1; proc[0] proc[1] proc[2] proc[63]
allocprocでやること • UNUSEDなプロセスをテーブルから探す • そのプロセスの設定 ◦ pid, state, trapframe, etc…
• 設定したプロセスを返す
allocproc static struct proc* allocproc(void) { struct proc *p; for
(p = ptable.proc; p < &ptable.proc[NPROC]; p++) if(p->state == UNUSED) goto found; return 0; found: ... }
allocproc(つづき) static struct proc* allocproc(void) { ... found: p->state =
EMBRYO; p->pid = nextpid++; p->kstack = kalloc(); ... }
context tf parent pid = 1 state = EMBRYO kstack
pgdir 4096B (= 1page) kernel stack
allocproc(つづき) static struct proc* allocproc(void) { sp = p->kstack +
KSTACKSIZE; // Leave room for trap frame. sp -= sizeof *p->tf; p->tf = (struct trapframe*)sp; kernel stack p->kstack sp
sp allocproc(つづき) static struct proc* allocproc(void) { sp = p->kstack
+ KSTACKSIZE; // Leave room for trap frame. sp -= sizeof *p->tf; p->tf = (struct trapframe*)sp; trap frame p->kstack
sp trapframe分のメモリ確保 static struct proc* allocproc(void) { sp = p->kstack
+ KSTACKSIZE; // Leave room for trap frame. sp -= sizeof *p->tf; p->tf = (struct trapframe*)sp; trap frame p->kstack
allocproc(つづき) static struct proc* allocproc(void) { ... sp -= 4;
*(uint*)sp = (uint)trapret; sp -= sizeof *p->context; p->context = (struct context*)sp; sp trap frame p->kstack trapret
context分のメモリ確保 static struct proc* allocproc(void) { ... sp -= 4;
*(uint*)sp = (uint)trapret; sp -= sizeof *p->context; p->context = (struct context*)sp; return p; } kernel stack trap frame trapret context sp
context分のメモリ確保 static struct proc* allocproc(void) { ... sp -= 4;
*(uint*)sp = (uint)trapret; sp -= sizeof *p->context; p->context = (struct context*)sp; return p; } kernel stack trap frame trapret context sp
allocproc脱出時 context tf parent pid = 1 state = EMBRYO
kstack pgdir p->kstack kernel stack trap frame trapret context
ふたたび userinit() void userinit(void) { struct proc *p; p =
allocproc(); if((p->pgdir = setupkvm()) == 0) panic("userinit: out of memory?"); inituvm(p->pgdir, _binary_initcode_start, _binary_initcode_size); ..... }
inituvm void userinit(void) { struct proc *p; p = allocproc();
if((p->pgdir = setupkvm()) == 0) panic("userinit: out of memory?"); inituvm(p->pgdir, _binary_initcode_start, _binary_initcode_size); ..... }
initプログラムメモリ確保 4096B initcode 0
trapframeの設定 void userinit(void) { ... p->tf->esp = PGSIZE; p->tf->eip =
0; p->state = RUNNABLE; }
trapframeの設定 kernel stack trap frame trapret context 4096B initcode 0
trapframeの設定 kernel stack trapret context 4096B initcode 0 esp eip
trapframe
userinitの最後 void userinit(void) { ... p->state = RUNNABLE; }
下準備完了 kernel stack trapret context 4096B initcode 0 esp eip
context tf parent pid = 1 state = RUNNABLE kstack pgdir init
scheduler
scheduler proc[0] proc[1] proc[2] proc[63] RUNNABLEな プロセス発見! → そのプロセスへ コンテキストスイッチ
scheduler void scheduler(void) { for(;;) { ... for (p =
ptable.proc; p < &ptable.proc[NPROC]; p++) { if (p->state != RUNNABLE) continue; ... } } }
scheduler void scheduler(void) { for(;;) { ... switchuvm(p); p->state =
RUNNING; swtch(&(c->scheduler), p->context); switchkvm(); ... } } }
scheduler void scheduler(void) { for(;;) { ... switchuvm(p); p->state =
RUNNING; swtch(&(c->scheduler), p->context); switchkvm(); ... } } }
scheduler void scheduler(void) { for(;;) { ... switchuvm(p); p->state =
RUNNING; swtch(&(c->scheduler), p->context); switchkvm(); ... } } }
schedulerのカーネルスタック swtch(&(c->scheduler), p->context); p ->context &(c->scheduler) swtch()の戻り先 呼び出し直後
schedulerのカーネルスタック swtch(..., ...); p ->context &(c->scheduler) swtch()の戻り先 呼び出し直後 esp->
swtch.S movl 4(%esp), %eax movl 8(%esp), %edx pushl %ebp pushl
%ebx pushl %esi pushl %edi ... p ->context &(c->scheduler) swtch()の戻り先 edx = esp-> eax =
swtch.S movl 4(%esp), %eax movl 8(%esp), %edx pushl %ebp pushl
%ebx pushl %esi pushl %edi ... p ->context &(c->scheduler) swtch()の戻り先 ebp ebx edi esi edx = esp-> eax = schedulerの context
swtch.S ... movl %esp, (%eax) movl %edx, %esp popl %edi
popl %esi popl %ebx popl %ebp ret p ->context &(c->scheduler) swtch()の戻り先 ebp ebx edi esi edx = esp-> eax = 古いコンテキストを 保存
swtch.S ... movl %esp, (%eax) movl %edx, %esp popl %edi
popl %esi popl %ebx popl %ebp ret p ->context &(c->scheduler) swtch()の戻り先 ebp ebx edi esi edx = esp-> eax = 新しいコンテキストへ スイッチ
initプロセス kernel stack trapret eip 4096B initcode 0 esp eip
esp-> context ebp ebx esi edi
swtch.Sのつづき kernel stack trapret eip 4096B initcode 0 esp eip
esp-> ebp ebx esi edi ... popl %edi popl %esi popl %ebx popl %ebp ret
swtch.Sのつづき kernel stack trapret eip 4096B initcode 0 esp eip
esp-> ebp ebx esi edi ... popl %edi popl %esi popl %ebx popl %ebp ret
swtch.Sのつづき kernel stack trapret eip 4096B initcode 0 esp eip
esp-> ebp ebx esi edi trapframe を拡大
trapret 4096B initcode 0 trapret: popal popl %gs popl %fs
popl %es popl %ds addl $0x8, %esp iret trape frame edi eax esp-> gs ds trapno err eip esp
trapret 4096B initcode 0 trapret: popal popl %gs popl %fs
popl %es popl %ds addl $0x8, %esp iret trape frame edi eax esp-> gs ds trapno err eip esp
trapret 4096B initcode 0 trapret: popal popl %gs popl %fs
popl %es popl %ds addl $0x8, %esp iret trape frame edi eax esp-> gs ds trapno err eip esp
trapret 4096B initcode 0 trapret: popal popl %gs popl %fs
popl %es popl %ds addl $0x8, %esp iret trape frame edi eax esp-> gs ds trapno err eip esp
4096B initcode 0 trape frame edi eax esp-> gs ds
trapno err eip esp eip->
その後
init プロセスは fork() を実行。 その子プロセスは shell を起動。
おしまい
参考文献 • xv6 ◦ https://github.com/mit-pdos/xv6-public • book-rev11.pdf ◦ https://pdos.csail.mit.edu/6.828/2018/xv6/book-rev11.pdf •
xv6実装の詳解(マルチタスク処理 switching編) ◦ https://qiita.com/knknkn1162/items/0bc9afc3ae304590e16c