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
Sponsored
·
Your Podcast. Everywhere. Effortlessly.
Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
→
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
DynamoDBには集計系のクエリがないけどなんとかしたい
musan
1
130
The Arts and Crafts of Work in the AI Era — Toward Mastery in Software Development
kuranuki
1
750
AIで効率化できた業務・日常
ochtum
0
120
並列実装の現場、2ヶ月間実務でAIを使い倒したAIもPCも私も限界が近い
ming_ayami
0
120
Contextとはなにか
chiroruxx
1
290
Webフレームワークの ベンチマークについて
yusukebe
0
160
Semantic Version 単位で戦略を柔軟に変えて、パッケージアップデートを自動化する
daitasu
0
220
Signal Forms: Details & Live Coding @enterJS 2026 in Mannheim
manfredsteyer
PRO
0
100
不変条件と整合性境界—ビジネスが決める設計判断と実現パターン / Invariants and Consistency Boundaries
nrslib
13
3.6k
Spec Driven Development | AI Summit Lisbon
danielsogl
PRO
0
180
IBM Bobを活用したレガシーアプリの最新化
oniak3ibm
PRO
1
190
Signal Forms: Beyond the Basics @ngBaguette 2026 in Paris
manfredsteyer
PRO
0
240
Featured
See All Featured
Why Your Marketing Sucks and What You Can Do About It - Sophie Logan
marketingsoph
0
170
Test your architecture with Archunit
thirion
1
2.3k
Faster Mobile Websites
deanohume
310
31k
Building a Modern Day E-commerce SEO Strategy
aleyda
45
9.1k
How to build an LLM SEO readiness audit: a practical framework
nmsamuel
1
770
The Curse of the Amulet
leimatthew05
1
13k
The Limits of Empathy - UXLibs8
cassininazir
1
350
Navigating Team Friction
lara
192
16k
Optimising Largest Contentful Paint
csswizardry
37
3.7k
Building a A Zero-Code AI SEO Workflow
portentint
PRO
0
570
16th Malabo Montpellier Forum Presentation
akademiya2063
PRO
0
140
Practical Tips for Bootstrapping Information Extraction Pipelines
honnibal
25
2k
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