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
AI駆動開発ライフサイクル(AI-DLC)のホワイトペーパーを解説
swxhariu5
0
1.1k
Register is more than clipboard
satorunooshie
1
480
The Missing Link in Angular's Signal Story: Resource API and httpResource
manfredsteyer
PRO
0
130
知られているようで知られていない JavaScriptの仕様 4選
syumai
0
610
Rails Girls Sapporo 2ndの裏側―準備の日々から見えた、私が得たもの / SAPPORO ENGINEER BASE #11
lemonade_37
2
180
OSS開発者の憂鬱
yusukebe
12
4.4k
Amazon Bedrock Knowledge Bases Hands-on
konny0311
0
150
Agentに至る道 〜なぜLLMは自動でコードを書けるようになったのか〜
mackee
5
1.7k
2026年向け会社紹介資料
misu
0
240
GraalVM Native Image トラブルシューティング機能の最新状況(2025年版)
ntt_dsol_java
0
150
Honoを技術選定したAI要件定義プラットフォームAcsimでの意思決定
codenote
0
250
『実践MLOps』から学ぶ DevOps for ML
nsakki55
2
430
Featured
See All Featured
A better future with KSS
kneath
239
18k
JavaScript: Past, Present, and Future - NDC Porto 2020
reverentgeek
52
5.7k
What’s in a name? Adding method to the madness
productmarketing
PRO
24
3.8k
The Hidden Cost of Media on the Web [PixelPalooza 2025]
tammyeverts
1
30
Raft: Consensus for Rubyists
vanstee
140
7.2k
Understanding Cognitive Biases in Performance Measurement
bluesmoon
31
2.7k
Into the Great Unknown - MozCon
thekraken
40
2.2k
RailsConf 2023
tenderlove
30
1.3k
Agile that works and the tools we love
rasmusluckow
331
21k
The MySQL Ecosystem @ GitHub 2015
samlambert
251
13k
We Have a Design System, Now What?
morganepeng
54
7.9k
Performance Is Good for Brains [We Love Speed 2024]
tammyeverts
12
1.3k
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