x86_64での自作OS - サイボウズ・ラボユース 成果発表会

x86_64での自作OS - サイボウズ・ラボユース 成果発表会

E7f042ba574c7cfe39e8ca27d32d32de?s=128

Totsugekitai

March 30, 2020
Tweet

Transcript

  1. x86_64での自作OS サイボウズ・ラボユース 成果発表会 広瀬 智之 2020.3.30

  2. 自己紹介 • 名前:広瀬智之 • 所属:筑波大学情報科学類 2 年 • サイボウズ・ラボユース 第

    9 期 • セキュリティキャンプ 2019 全国大会 OS 開発ゼミ修了 • 今年度は自作 OS をしていました 1
  3. このテーマを選んだ理由 • 学部 1 年の春休みに「30 日ででき る! OS 自作入門」を読み、自作 OS

    に興味を持った • 素晴らしい本であるが、今の PC で は動作させづらい • 32bit only • セグメンテーションを用いたメモ リ管理 • フロッピーディスクの使用 Figure 1: OS 自作入門 -> 今の PC でも動かせる自作 OS をやろう! 2
  4. minOS(私の自作 OS)の概観 • CPU は 64bit モードを前提に作成 • UEFI 対応

    • スレッド機能を実装し並行処理を実現 • ページングでメモリを初期化 • 割り込みを用いたシリアル通信 • AHCI(SATA コントローラ)のドライバを実装 • SATA 接続されたストレージへの(原始的な)読み書き ができます 以下のリポジトリで公開しています https://github.com/Totsugekitai/minOSv2 3
  5. minOS(私の自作 OS)の概観 • CPU は 64bit モードを前提に作成 • UEFI 対応

    • スレッド機能を実装し並行処理を実現 • ページングでメモリを初期化 • 割り込みを用いたシリアル通信 • AHCI(SATA コントローラ)のドライバを実装 • SATA 接続されたストレージへの(原始的な)読み書き ができます 以下のリポジトリで公開しています https://github.com/Totsugekitai/minOSv2 4
  6. スレッドとは • 実行中のプログラム単位 = プログラムコード + 状態 • スレッドの状態を構成するもの =

    レジスタの値 • スレッドの切り替え -> 今のスレッドのレジスタ値をストア -> 次のスレッドのレジスタ値をロード -> 次のスレッドのコードにジャンプ • レジスタ値のストア先 = 各スレッドのスタック 5
  7. スレッドを定義 1 struct thread { 2 uint64_t *stack; // ス

    タ ッ ク の 底 の ア ド レ ス 3 uint64_t *rsp; // ス タ ッ ク ポ イ ン タ の 値 4 struct thread_func func; // 実 行 す る 関 数 の 情 報 5 enum thread_state state; // 状 態 6 int index; // 何 番 目 の ス レ ッ ド な の か 7 }; 8 9 struct thread *threads[THREAD_NUM]; // ス レ ッ ド 一 覧 6
  8. スレッドの切り替え 1 void thread_scheduler(void) 2 { 3 // update cindex

    4 int oindex = cindex; 5 int i = 1; 6 while (cindex == oindex) { 7 if (threads[(cindex + i) % THREAD_NUM]->state == RUNNABLE) { 8 cindex = (cindex + i) % THREAD_NUM; 9 } 10 i++; 11 } 12 13 switch_context(&threads[oindex]->rsp, threads[cindex]->rsp); 14 } 7
  9. スレッドの切り替え switch_context のアセンブラ 1 switch_context: 2 push rbp 3 push

    r15 4 push r14 5 push r13 6 push r12 7 push r11 8 push r10 9 push r9 10 push r8 11 push rdi 12 push rsi 13 push rdx 14 push rcx 15 push rbx 16 push rax 17 mov [rdi],rsp 18 mov rsp,rsi 19 pop rax 20 pop rbx 21 pop rcx 22 pop rdx 23 pop rsi 24 pop rdi 25 pop r8 26 pop r9 27 pop r10 28 pop r11 29 pop r12 30 pop r13 31 pop r14 32 pop r15 33 pop rbp 34 ret 8
  10. スレッドの切り替え タイマハンドラで呼び出す 1 __attribute__((interrupt)) 2 void timer_handler(struct intr_frame *frame) 3

    { 4 tick++; 5 io_out8(PIC0_OCW2, PIC_EOI); 6 io_out8(PIC1_OCW2, PIC_EOI); 7 8 if (tick > previous_interrupt + timer_period) { 9 previous_interrupt = tick; 10 thread_scheduler(); 11 } 12 } 9
  11. 実装で苦労した部分 • 最初は ret を iret にしていた • スケジューラはタイマ割り込み中に呼び出し ->

    iret のほうが行儀良さそう? • iret はスタックの調整が大変で、いくら調整し直して もずれが発生していた • ret を代わりに使うようにしたら 30 分で動いた Simple is the best! 10
  12. まとめ • x86_64 アーキテクチャで自作 OS をした • スレッドを実装し並行処理ができるようになった • 他にも以下のような機能を実装した

    • 割り込みを用いたシリアル通信 • ページングを用いたメモリ初期化 • AHCI のドライバを実装してストレージの読み書き • これからしたいこと • ファイルシステムの実装 • ドキュメントを充実させる 11