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.9k
xv6 initプロセス ことはじめ
教育用OS「xv6」のソースコードから、initプロセスの生成と実行を見る。
Toasa
February 08, 2020
Tweet
Share
Other Decks in Programming
See All in Programming
AI駆動開発の本音 〜Claude Code並列開発で見えたエンジニアの新しい役割〜
hisuzuya
4
490
AHC061解説
shun_pi
0
340
AIプロダクト時代のQAエンジニアに求められること
imtnd
2
740
メタプログラミングで実現する「コードを仕様にする」仕組み/nikkei-tech-talk43
nikkei_engineer_recruiting
0
160
Geminiの機能を調べ尽くしてみた
naruyoshimi
0
200
Claude Codeセッション現状確認 2026福岡 / fukuoka-aicoding-00-beacon
monochromegane
4
400
エージェント開発初心者の僕がエージェントを作った話と今後やりたいこと
thasu0123
0
230
The Past, Present, and Future of Enterprise Java
ivargrimstad
0
410
20260228_JAWS_Beginner_Kansai
takuyay0ne
5
460
AI時代でも変わらない技術コミュニティの力~10年続く“ゆるい”つながりが生み出す価値
n_takehata
2
660
Go1.26 go fixをプロダクトに適用して困ったこと
kurakura0916
0
330
クライアントワークでSREをするということ。あるいは事業会社におけるSREと同じこと・違うこと
nnaka2992
1
310
Featured
See All Featured
16th Malabo Montpellier Forum Presentation
akademiya2063
PRO
0
64
Automating Front-end Workflow
addyosmani
1370
200k
AI Search: Implications for SEO and How to Move Forward - #ShenzhenSEOConference
aleyda
1
1.1k
Writing Fast Ruby
sferik
630
63k
Building a A Zero-Code AI SEO Workflow
portentint
PRO
0
370
How to optimise 3,500 product descriptions for ecommerce in one day using ChatGPT
katarinadahlin
PRO
1
3.5k
Have SEOs Ruined the Internet? - User Awareness of SEO in 2025
akashhashmi
0
280
How Software Deployment tools have changed in the past 20 years
geshan
0
32k
The #1 spot is gone: here's how to win anyway
tamaranovitovic
2
980
SEO in 2025: How to Prepare for the Future of Search
ipullrank
3
3.4k
Easily Structure & Communicate Ideas using Wireframe
afnizarnur
194
17k
Music & Morning Musume
bryan
47
7.1k
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