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
3k
6
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
xv6 initプロセス ことはじめ
教育用OS「xv6」のソースコードから、initプロセスの生成と実行を見る。
Toasa
February 08, 2020
Other Decks in Programming
See All in Programming
Vue × Nuxt × Oxc どこまで使える?実運用の現在地
andpad
0
360
Vite+ Unified Toolchain for the Web
naokihaba
0
660
どこまでゆるくて許されるのか
tk3fftk
0
340
AI時代の仕事技芸論〜ソフトウェア開発で「遊ぶように働く」職人的熟達のすすめ(スクフェス仙台 2026バージョン)
kuranuki
0
350
例外の正しい扱い方 そのエラー try-catchして大丈夫?
jinwatanabe
0
340
AIキャラアプリkaiwaの低遅延音声通話基盤をどう作ったか - AWS Gravitonで支える低遅延・低コストAI Agent基盤
mogamit
0
160
act1-costs.pdf
sumedhbala
0
170
壊れたパーサから始める関数型設計と構成的なパーサ #fp_matsuri
raiga0310
2
160
技術記事、 専門家としてのプログラマ、 言語化
mizchi
14
7.3k
【SRE NEXT 2026 Lunch Session】一人目専任SREの立ち上げを加速する ― AIと進めたオンボーディングで2分を0.04秒にした話
pkshadeck
PRO
0
350
IBM Bobを活用したレガシーアプリの最新化
oniak3ibm
PRO
1
240
Agentic UI
manfredsteyer
PRO
0
220
Featured
See All Featured
Chrome DevTools: State of the Union 2024 - Debugging React & Beyond
addyosmani
10
1.2k
Joys of Absence: A Defence of Solitary Play
codingconduct
1
410
Exploring the Power of Turbo Streams & Action Cable | RailsConf2023
kevinliebholz
37
6.5k
Thoughts on Productivity
jonyablonski
76
5.2k
CoffeeScript is Beautiful & I Never Want to Write Plain JavaScript Again
sstephenson
162
16k
JavaScript: Past, Present, and Future - NDC Porto 2020
reverentgeek
52
6k
WENDY [Excerpt]
tessaabrams
11
38k
Speed Design
sergeychernyshev
33
1.9k
How to audit for AI Accessibility on your Front & Back End
davetheseo
0
460
Groundhog Day: Seeking Process in Gaming for Health
codingconduct
0
240
Evolution of real-time – Irina Nazarova, EuRuKo, 2024
irinanazarova
9
1.4k
The Limits of Empathy - UXLibs8
cassininazir
1
390
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