SlideShare a Scribd company logo
xv6のコンテキストスイッチを読む

              @mfumi2
自己紹介

●
    セキュリティキャンプ2012OS組
最近こんな本が出ました




              はじめてのOSコードリーディング
                         青柳隆宏著




              おすすめ! でも...
UNIX V6 を読む上で大変なところ

●
    PDP11
●
    Cの記法が古い (pre K&R)
●
    アセンブラの記法が特殊
●
    デフォルトが8進数
●
    etc...
xv6とは

●
    MITで開発された教育用OS
    http://pdos.csail.mit.edu/6.828/2012/xv6.html
●
    UNIX V6 を x86 向けに書き直したもの
●
    解説書有り
    http://pdos.csail.mit.edu/6.828/2012/xv6/book-
    rev7.pdf
xv6の特徴

●
    x86
●
    マルチプロセッサ対応
●
    バイナリはELF
●
    スワッピング機能はなし
●
    qemu+gdb で動作可
コンテキストスイッチ

●
    プロセスのコンテキストを切り替える
●
    コンテキスト …
    –   メモリ空間
        → cr3 レジスタを切り替える
    –   スタック
        → %esp を切り替える
    –   各種レジスタ
        → プロセスごとのスタックに退避&スタックから復帰
xv6のコンテキストスイッチ
• switch.S


             void swtch(struct context **old,
                                    struct context *new);




                       • proc.h
xv6のコンテキストスイッチ
    • switch.S
                 void swtch(struct context **old,
                                        struct context *new);
                             メモリ
                     %
                     %
                     %
★
                     %                              %esp
                     %eip(swtchの戻り先)



                                                   new(%edx)
                     %edi
                     %esi
                     %ebx
                     %ebp
                     %eip(swtchの戻り先)
xv6のコンテキストスイッチ
    • switch.S
                 void swtch(struct context **old,
                                        struct context *new);
                             メモリ
                     %edi
                     %esi
                     %ebx                           %esp
★
                     %ebp
                     %eip(swtchの戻り先)



                                                   new(%edx)
                     %edi
                     %esi
                     %ebx
                     %ebp
                     %eip(swtchの戻り先)
xv6のコンテキストスイッチ
    • switch.S
                 void swtch(struct context **old,
                                        struct context *new);
                             メモリ
                     %edi
                     %esi                           %esp
                     %ebx
★
                     %ebp
                     %eip(swtchの戻り先)



                                                   new(%edx)
                     %edi
                     %esi
                     %ebx
                     %ebp
                     %eip(swtchの戻り先)
xv6のコンテキストスイッチ
    • switch.S
                 void swtch(struct context **old,
                                        struct context *new);
                             メモリ
                     %edi                           %esp
                     %esi
                     %ebx
                     %ebp
★                    %eip(swtchの戻り先)



                                                   new(%edx)
                     %edi
                     %esi
                     %ebx
                     %ebp
                     %eip(swtchの戻り先)
xv6のコンテキストスイッチ
    • switch.S
                 void swtch(struct context **old,
                                        struct context *new);
                             メモリ                    %esp
                     %edi
                     %esi
                     %ebx
                     %ebp
                     %eip(swtchの戻り先)
★


                                                   new(%edx)
                     %edi
                     %esi
                     %ebx
                     %ebp
                     %eip(swtchの戻り先)
xv6のコンテキストスイッチ
    • switch.S
                 void swtch(struct context **old,
                                        struct context *new);
                             メモリ                    %esp
                     %edi                           *old(%eax)
                     %esi
                     %ebx
                     %ebp
                     %eip(swtchの戻り先)



★                                                  new(%edx)
                     %edi
                     %esi
                     %ebx
                     %ebp
                     %eip(swtchの戻り先)
xv6のコンテキストスイッチ
    • switch.S
                 void swtch(struct context **old,
                                        struct context *new);
                             メモリ                   *old(%eax)
                      %edi
                      %esi
                      %ebx
                      %ebp
                      %eip(swtchの戻り先)


                                                    %esp
                                                    new(%edx)
★                     %edi
                      %esi
                      %ebx
                      %ebp
                      %eip(swtchの戻り先)
xv6のコンテキストスイッチ
    • switch.S
                 void swtch(struct context **old,
                                        struct context *new);
                             メモリ                   *old(%eax)
                     %edi
                     %esi
                     %ebx
                     %ebp
                     %eip(swtchの戻り先)



                                                   new(%edx)
                     %edi                          %esp
                     %esi
                     %ebx
★                    %ebp
                     %eip(swtchの戻り先)
xv6のコンテキストスイッチ
    • switch.S
                 void swtch(struct context **old,
                                        struct context *new);
                             メモリ                   *old(%eax)
                     %edi
                     %esi
                     %ebx
                     %ebp
                     %eip(swtchの戻り先)



                                                   new(%edx)
                     %edi
                     %esi                           %esp
                     %ebx
                     %ebp
★                    %eip(swtchの戻り先)
xv6のコンテキストスイッチ
    • switch.S
                 void swtch(struct context **old,
                                        struct context *new);
                             メモリ                   *old(%eax)
                     %edi
                     %esi
                     %ebx
                     %ebp
                     %eip(swtchの戻り先)



                                                   new(%edx)
                     %edi
                     %esi
                     %ebx                           %esp
                     %ebp
                     %eip(swtchの戻り先)
★
xv6のコンテキストスイッチ
    • switch.S
                 void swtch(struct context **old,
                                        struct context *new);
                             メモリ                   *old(%eax)
                     %edi
                     %esi
                     %ebx
                     %ebp
                     %eip(swtchの戻り先)



                                                   new(%edx)
                     %edi
                     %esi
                     %ebx
                     %ebp                           %esp
                     %eip(swtchの戻り先)
★
xv6のコンテキストスイッチの流れ


ユーザプロセス1                                ユーザプロセス2

    タイマ割り込み                                 iret
                
割り込みハンドラ             スケジューラ             割り込みハンドラ
           swtch()            swtch()
(1) 割り込みの発生

●
    xv6では100msごとにタイマ割り込みが発生
●
    割り込みが発生すると
    –   特権レベルが3から0に移行
    –   スタックがカーネルスタックに切り替わる
        (TSSからカーネル用%espと%ssを読み込む)
    –   スタックに%ss, %esp, %eflags, %cs, %eip を積む
        (現在実行していたプロセスの状態を積む)
    –   対応する割り込みハンドラに移行
(1) 割り込みの発生

    xv6では
●
    vectors.S (vectors.plから生成される) 内に定義してあ
    る vector$i() ($iは割り込み番号) が呼び出される
    (割り込みハンドラの設定は trap.c の tvinit(), idtinit(), いずれも main.c
    のmain()から呼ばれる )
●
    vector$i から trapasm.S の alltraps() に飛ぶ
(2) 割り込みハンドラの処理
●
    trapasm.S alltraps




                         ・自動に退避されないレジスタを退避
                         ・カーネル用セグメントの設定
                         ・最終的に trap.c の trap()を呼ぶ
(2) 割り込みハンドラの処理

●
     trap.c の trap() でそれぞれの処理に応じた割り込み処
     理をおこなう
     (割り込みハンドラごとに処理をおこなっていない)
●
     タイマ割り込みの場合 CPU 時間切れなら proc.c の yield()を呼ぶ
●
     yield()からさらに proc.cの shced()が呼ばれる




    タイマ割り込み → vectors.S#vector$i() → trapasm.S#alltraps()
    → trap.c#trap() → proc.c#yield() → proc.c#shced()
(2) 割り込みハンドラの処理
●
    proc.c の sched()
    スケジューラプロセスにコンテキストスイッチする


                   ・proc‥現在のプロセスの情報をも
                   つ構造体
                   ・cpu‥各CPUが持つCPUの情報を
                   もつ構造体
                   それぞれproc.h で定義




                             コンテキストの切り替え
                   •swtch()からの戻り先 (cpu->scheduler.eip)
                    は proc.c の scheduler()
(3) スケジューラの処理   proc.c
                scheduler()




                   次に実行するプロセス
                   を探す(ラウンドロビン)




                  メモリ空間の切り替え
                  選択したプロセスにswtch()
★                  sched()のswtch()から
                   の戻り先
                   メモリ空間をカーネル用
                   に切り替え
(3) スケジューラの処理

●
    何故sched()のswtch()からscheduler()に戻るのか?
    → ブートローダから呼ばれることになる main.c の
    main()でinitプロセス(proc[0])を起動後shceduler()を呼
    ぶため
(4) 割り込みハンドラの処理(後半)
    ●
        proc.c の sched()
        scheduler() から swtch() によって選択されたプロセスの再開




★
                                   ここから処理が再開
(4) 割り込みハンドラの処理(後半)

●
    最終的にalltrap() まで return し,そこで iret して割り込み終了
●
    iret でスタックからプロセスの状態を復帰させる.このとき特権レ
    ベルも3に戻る
    スタックが切り替わっているので別のプロセス状態に戻る

    trapasm.S
                                    メモリ
                               %eip
                               %cs
                               %eflags
                               %esp
                               %ss
xv6のコンテキストスイッチの流れ(再掲)


ユーザプロセス1                                ユーザプロセス2

    タイマ割り込み                                 iret
                
割り込みハンドラ             スケジューラ             割り込みハンドラ
           swtch()            swtch()
まとめ

●
    PDP11がいやな人はxv6読んでみたらどうでしょうか
●
    いろいろと改造のしどころ有り

More Related Content

PDF
x86とコンテキストスイッチ
PDF
EthernetやCPUなどの話
PPTX
PDF
C++でCプリプロセッサを作ったり速くしたりしたお話
PDF
eBPFは何が嬉しいのか
PDF
イマドキC++erのモテカワリソース管理術
PDF
ダブル配列の豆知識
PDF
CRC-32
x86とコンテキストスイッチ
EthernetやCPUなどの話
C++でCプリプロセッサを作ったり速くしたりしたお話
eBPFは何が嬉しいのか
イマドキC++erのモテカワリソース管理術
ダブル配列の豆知識
CRC-32

What's hot (20)

PDF
高速な倍精度指数関数expの実装
PDF
C++ マルチスレッドプログラミング
PDF
C++でできる!OS自作入門
PPTX
C#とILとネイティブと
PDF
SSE4.2の文字列処理命令の紹介
PDF
Deflate
PDF
条件分岐とcmovとmaxps
PDF
Intro to SVE 富岳のA64FXを触ってみた
PDF
ゲーム開発者のための C++11/C++14
PDF
LLVM最適化のこつ
PDF
様々な全域木問題
PPTX
PostgreSQLクエリ実行の基礎知識 ~Explainを読み解こう~
PDF
カスタムメモリマネージャと高速なメモリアロケータについて
PDF
ARM CPUにおけるSIMDを用いた高速計算入門
PDF
Union find(素集合データ構造)
PDF
Dockerfile を書くためのベストプラクティス解説編
PDF
Web エンジニアが postgre sql を選ぶ 3 つの理由
PDF
Xbyakの紹介とその周辺
PDF
プログラムを高速化する話
PDF
コンテナの作り方「Dockerは裏方で何をしているのか?」
高速な倍精度指数関数expの実装
C++ マルチスレッドプログラミング
C++でできる!OS自作入門
C#とILとネイティブと
SSE4.2の文字列処理命令の紹介
Deflate
条件分岐とcmovとmaxps
Intro to SVE 富岳のA64FXを触ってみた
ゲーム開発者のための C++11/C++14
LLVM最適化のこつ
様々な全域木問題
PostgreSQLクエリ実行の基礎知識 ~Explainを読み解こう~
カスタムメモリマネージャと高速なメモリアロケータについて
ARM CPUにおけるSIMDを用いた高速計算入門
Union find(素集合データ構造)
Dockerfile を書くためのベストプラクティス解説編
Web エンジニアが postgre sql を選ぶ 3 つの理由
Xbyakの紹介とその周辺
プログラムを高速化する話
コンテナの作り方「Dockerは裏方で何をしているのか?」
Ad

Viewers also liked (20)

PDF
あなたの知らないネットワークプログラミングの世界
PPTX
An other world awaits you
PDF
Kernel vm study_2_xv6_scheduler_part1_revised
PDF
πολλαπλασιασμοι ενοτητα 11
PDF
とある帽子の大蛇料理Ⅱ
PPTX
Bish Bash Bosh & Co
PDF
100Gbpsソフトウェアルータの実現可能性に関する論文
PDF
User-space Network Processing
PDF
デバドラを書いてみよう!
PDF
I/O仮想化最前線〜ネットワークI/Oを中心に〜
PDF
Disruptive IP Networking with Intel DPDK on Linux
PDF
クラウド環境におけるキャッシュメモリQoS制御の評価
PDF
DPDKを拡張してみた話し
PDF
Async deepdive before de:code
PDF
continuatioN Linking
PDF
これからの「async/await」の話をしよう
PDF
async/awaitダークサイド is 何
PDF
Xeon dとlagopusと、pktgen dpdk
PDF
Dpdk環境の話
PDF
async/await不要論
あなたの知らないネットワークプログラミングの世界
An other world awaits you
Kernel vm study_2_xv6_scheduler_part1_revised
πολλαπλασιασμοι ενοτητα 11
とある帽子の大蛇料理Ⅱ
Bish Bash Bosh & Co
100Gbpsソフトウェアルータの実現可能性に関する論文
User-space Network Processing
デバドラを書いてみよう!
I/O仮想化最前線〜ネットワークI/Oを中心に〜
Disruptive IP Networking with Intel DPDK on Linux
クラウド環境におけるキャッシュメモリQoS制御の評価
DPDKを拡張してみた話し
Async deepdive before de:code
continuatioN Linking
これからの「async/await」の話をしよう
async/awaitダークサイド is 何
Xeon dとlagopusと、pktgen dpdk
Dpdk環境の話
async/await不要論
Ad

Similar to xv6のコンテキストスイッチを読む (10)

PDF
PFI Seminar 2010/02/18
PDF
PDF
d-kami x86-1
PDF
2011.09.18 v7から始めるunix まとめ
PDF
初めてのCPUを作ってみた
PDF
mbedではじめる組み込みHaskellプログラミング
PPTX
もしも… Javaでヘテロジニアスコアが使えたら…
PDF
V6 unix in okinawa
PDF
Tora pointer3
PDF
llvm入門
PFI Seminar 2010/02/18
d-kami x86-1
2011.09.18 v7から始めるunix まとめ
初めてのCPUを作ってみた
mbedではじめる組み込みHaskellプログラミング
もしも… Javaでヘテロジニアスコアが使えたら…
V6 unix in okinawa
Tora pointer3
llvm入門

More from mfumi (12)

PDF
MMDs 12.3 SVM
PDF
MMDs10.6-7
PDF
IA16 2
PDF
IA16
PDF
IA14
PDF
木を綺麗に描画するアルゴリズム
PDF
MMDs Chapter 9
PDF
グラフを奇麗に描画するアルゴリズム
PDF
Algorithms Introduction 9章
PDF
MMDs 6.3-6.5
PDF
MMDs Chapter 5.1 PageRank
PDF
ファイルの隠し方
MMDs 12.3 SVM
MMDs10.6-7
IA16 2
IA16
IA14
木を綺麗に描画するアルゴリズム
MMDs Chapter 9
グラフを奇麗に描画するアルゴリズム
Algorithms Introduction 9章
MMDs 6.3-6.5
MMDs Chapter 5.1 PageRank
ファイルの隠し方

xv6のコンテキストスイッチを読む

  • 2. 自己紹介 ● セキュリティキャンプ2012OS組
  • 3. 最近こんな本が出ました はじめてのOSコードリーディング 青柳隆宏著 おすすめ! でも...
  • 4. UNIX V6 を読む上で大変なところ ● PDP11 ● Cの記法が古い (pre K&R) ● アセンブラの記法が特殊 ● デフォルトが8進数 ● etc...
  • 5. xv6とは ● MITで開発された教育用OS http://pdos.csail.mit.edu/6.828/2012/xv6.html ● UNIX V6 を x86 向けに書き直したもの ● 解説書有り http://pdos.csail.mit.edu/6.828/2012/xv6/book- rev7.pdf
  • 6. xv6の特徴 ● x86 ● マルチプロセッサ対応 ● バイナリはELF ● スワッピング機能はなし ● qemu+gdb で動作可
  • 7. コンテキストスイッチ ● プロセスのコンテキストを切り替える ● コンテキスト … – メモリ空間 → cr3 レジスタを切り替える – スタック → %esp を切り替える – 各種レジスタ → プロセスごとのスタックに退避&スタックから復帰
  • 8. xv6のコンテキストスイッチ • switch.S void swtch(struct context **old, struct context *new); • proc.h
  • 9. xv6のコンテキストスイッチ • switch.S void swtch(struct context **old, struct context *new); メモリ % % % ★ % %esp %eip(swtchの戻り先) new(%edx) %edi %esi %ebx %ebp %eip(swtchの戻り先)
  • 10. xv6のコンテキストスイッチ • switch.S void swtch(struct context **old, struct context *new); メモリ %edi %esi %ebx %esp ★ %ebp %eip(swtchの戻り先) new(%edx) %edi %esi %ebx %ebp %eip(swtchの戻り先)
  • 11. xv6のコンテキストスイッチ • switch.S void swtch(struct context **old, struct context *new); メモリ %edi %esi %esp %ebx ★ %ebp %eip(swtchの戻り先) new(%edx) %edi %esi %ebx %ebp %eip(swtchの戻り先)
  • 12. xv6のコンテキストスイッチ • switch.S void swtch(struct context **old, struct context *new); メモリ %edi %esp %esi %ebx %ebp ★ %eip(swtchの戻り先) new(%edx) %edi %esi %ebx %ebp %eip(swtchの戻り先)
  • 13. xv6のコンテキストスイッチ • switch.S void swtch(struct context **old, struct context *new); メモリ %esp %edi %esi %ebx %ebp %eip(swtchの戻り先) ★ new(%edx) %edi %esi %ebx %ebp %eip(swtchの戻り先)
  • 14. xv6のコンテキストスイッチ • switch.S void swtch(struct context **old, struct context *new); メモリ %esp %edi *old(%eax) %esi %ebx %ebp %eip(swtchの戻り先) ★ new(%edx) %edi %esi %ebx %ebp %eip(swtchの戻り先)
  • 15. xv6のコンテキストスイッチ • switch.S void swtch(struct context **old, struct context *new); メモリ *old(%eax) %edi %esi %ebx %ebp %eip(swtchの戻り先) %esp new(%edx) ★ %edi %esi %ebx %ebp %eip(swtchの戻り先)
  • 16. xv6のコンテキストスイッチ • switch.S void swtch(struct context **old, struct context *new); メモリ *old(%eax) %edi %esi %ebx %ebp %eip(swtchの戻り先) new(%edx) %edi %esp %esi %ebx ★ %ebp %eip(swtchの戻り先)
  • 17. xv6のコンテキストスイッチ • switch.S void swtch(struct context **old, struct context *new); メモリ *old(%eax) %edi %esi %ebx %ebp %eip(swtchの戻り先) new(%edx) %edi %esi %esp %ebx %ebp ★ %eip(swtchの戻り先)
  • 18. xv6のコンテキストスイッチ • switch.S void swtch(struct context **old, struct context *new); メモリ *old(%eax) %edi %esi %ebx %ebp %eip(swtchの戻り先) new(%edx) %edi %esi %ebx %esp %ebp %eip(swtchの戻り先) ★
  • 19. xv6のコンテキストスイッチ • switch.S void swtch(struct context **old, struct context *new); メモリ *old(%eax) %edi %esi %ebx %ebp %eip(swtchの戻り先) new(%edx) %edi %esi %ebx %ebp %esp %eip(swtchの戻り先) ★
  • 20. xv6のコンテキストスイッチの流れ ユーザプロセス1 ユーザプロセス2 タイマ割り込み iret   割り込みハンドラ スケジューラ 割り込みハンドラ swtch() swtch()
  • 21. (1) 割り込みの発生 ● xv6では100msごとにタイマ割り込みが発生 ● 割り込みが発生すると – 特権レベルが3から0に移行 – スタックがカーネルスタックに切り替わる (TSSからカーネル用%espと%ssを読み込む) – スタックに%ss, %esp, %eflags, %cs, %eip を積む (現在実行していたプロセスの状態を積む) – 対応する割り込みハンドラに移行
  • 22. (1) 割り込みの発生 xv6では ● vectors.S (vectors.plから生成される) 内に定義してあ る vector$i() ($iは割り込み番号) が呼び出される (割り込みハンドラの設定は trap.c の tvinit(), idtinit(), いずれも main.c のmain()から呼ばれる ) ● vector$i から trapasm.S の alltraps() に飛ぶ
  • 23. (2) 割り込みハンドラの処理 ● trapasm.S alltraps ・自動に退避されないレジスタを退避 ・カーネル用セグメントの設定 ・最終的に trap.c の trap()を呼ぶ
  • 24. (2) 割り込みハンドラの処理 ● trap.c の trap() でそれぞれの処理に応じた割り込み処 理をおこなう (割り込みハンドラごとに処理をおこなっていない) ● タイマ割り込みの場合 CPU 時間切れなら proc.c の yield()を呼ぶ ● yield()からさらに proc.cの shced()が呼ばれる タイマ割り込み → vectors.S#vector$i() → trapasm.S#alltraps() → trap.c#trap() → proc.c#yield() → proc.c#shced()
  • 25. (2) 割り込みハンドラの処理 ● proc.c の sched() スケジューラプロセスにコンテキストスイッチする ・proc‥現在のプロセスの情報をも つ構造体 ・cpu‥各CPUが持つCPUの情報を もつ構造体 それぞれproc.h で定義 コンテキストの切り替え •swtch()からの戻り先 (cpu->scheduler.eip) は proc.c の scheduler()
  • 26. (3) スケジューラの処理 proc.c scheduler() 次に実行するプロセス を探す(ラウンドロビン) メモリ空間の切り替え 選択したプロセスにswtch() ★ sched()のswtch()から の戻り先 メモリ空間をカーネル用 に切り替え
  • 27. (3) スケジューラの処理 ● 何故sched()のswtch()からscheduler()に戻るのか? → ブートローダから呼ばれることになる main.c の main()でinitプロセス(proc[0])を起動後shceduler()を呼 ぶため
  • 28. (4) 割り込みハンドラの処理(後半) ● proc.c の sched() scheduler() から swtch() によって選択されたプロセスの再開 ★ ここから処理が再開
  • 29. (4) 割り込みハンドラの処理(後半) ● 最終的にalltrap() まで return し,そこで iret して割り込み終了 ● iret でスタックからプロセスの状態を復帰させる.このとき特権レ ベルも3に戻る スタックが切り替わっているので別のプロセス状態に戻る trapasm.S メモリ %eip %cs %eflags %esp %ss
  • 30. xv6のコンテキストスイッチの流れ(再掲) ユーザプロセス1 ユーザプロセス2 タイマ割り込み iret   割り込みハンドラ スケジューラ 割り込みハンドラ swtch() swtch()
  • 31. まとめ ● PDP11がいやな人はxv6読んでみたらどうでしょうか ● いろいろと改造のしどころ有り