WEB+DB PRESS plusシリーズ[作って学ぶ]OSのしくみⅠ
──メモリ管理、マルチタスク、ハードウェア制御

[表紙][作って学ぶ]OSのしくみⅠ ──メモリ管理、マルチタスク、ハードウェア制御

紙版発売
電子版発売

A5判/552ページ

定価3,520円(本体3,200円+税10%)

ISBN 978-4-297-14859-1

電子版

→学校・法人一括購入ご検討の皆様へ

書籍の概要

この本の概要

Webサイトの閲覧をはじめとして,コンピューターはさまざまな場面でみなさんの日常と密接にかかわっています。しかし,その裏側で起きていることを理解するのは,現代の複雑なコンピューターシステムの上では困難です。そこで本書では,シンプルなOSをRustを用いて実装し,普段は見えないOSの役割とその動作を理解していきます。Ⅰ巻ではメモリ管理,マルクタスク,ハードウェア制御に関する部分を実装し,Ⅱ巻ではユーザーインタフェース,アプリケーション実行,インターネットへの接続に関する部分を実装します。既刊の『[作って学ぶ]ブラウザのしくみ』で実装するブラウザは,本書で実装するOS上で動作することを想定しています。ですので,本書と『[作って学ぶ]ブラウザのしくみ』で,OSの動作と,そのOS上でブラウザなどのアプリがどのように動作しているのかとを理解できます。

本書のサンプル

本書の一部ページを,PDFで確認することができます。

本書の紙面イメージは次のとおりです。画像をクリックすることで拡大して確認することができます。

サンプル画像1

サンプル画像2

サンプル画像3

サンプル画像4

サンプル画像5

目次

  • はじめに
  • 本書の読み方
    • サンプルコードのダウンロード
    • 想定読者
    • 本書の構成
    • 関連書籍について
    • 開発環境のセットアップ
    • 本書のコードの読み方
    • 参照している仕様書の表記方法
  • 目次

第1章:OSとは──コンピューターの裏側を支えるソフトウェアを知る

OSとは何か

  • 日常にあるOSの例
  • OSとコンピューターの関係
    • コンピューターの基本的なしくみ
    • アプリケーション──人々がコンピューターを使う理由
    • OS──ハードウェアとアプリケーションの狭間で

本書で実装するOSの全体像

  • ベアメタルプログラミング
  • 資源(メモリとCPU)の管理
  • ハードウェアの制御
  • 本書のゴールと関連書籍の紹介

本題に入る前に

第2章:ベアメタルプログラミングをしてみる──OSのない世界でプログラムを動かすための準備

コンピューターの構成要素

  • メモリ
  • CPU
  • 入出力

すべてはバイナリ

  • すべてのデータは2進法で表現できる
    • 数値をバイナリで表現する
    • 16進法は便利
    • ひとくちサイズのバイナリ,byte
    • 文字列のバイナリ表現
  • 画像のバイナリ表現
  • プログラムもバイナリ
  • コンパイラ──ソースコードを翻訳してバイナリを作るプログラム

UEFIアプリケーションを作ってみる

  • 開発環境の構築
  • Hello, worldを書いてみる
  • Rustツールチェインのバージョンを固定する
  • アプリケーションとOSの違い
  • UEFI──OSよりも前に起動する,OSを起動するためのプログラム
    • [column]色々なファームウェア──Legacy BIOSとUEFI BIOS
  • ターゲット──どの実行環境向けにバイナリを生成するのかコンパイラに伝える
  • QEMUを利用してUEFIアプリケーションを実行する

UEFIからの脱却

  • "Hello, world"はどこへ行く?
  • no_stdで生きていく──coreクレートと歩むベアメタル生活
    • [column]普段は当たり前だと思っているが実はOSが提供しているもの
  • フレームバッファに何か描く

Rustの便利機能を活用する

  • ビルドや実行を簡単にする
  • cargo clippyとHLT命令──CPUを無駄に回さないようにする
  • cargo fmt──コードをきれいに整形する

もっと色々なものを描く

  • 四角形を描く
  • 線分を描く
  • 画面に文字を表示する
  • 文字の列,文字列を表示する

writeln!()マクロを使ってみる

  • メモリマップを表示する
  • 図形描画のコードを整理する
  • UEFIのない世界へ行く──ExitBootServices

第3章:メモリ管理を実装しよう──限りある資源を効率良く使えるようにする

OSとメモリの関係

  • メモリとは何か
  • メモリ管理とは何か

実装前の準備

  • ソースコードの整理──ファイルを分割する
  • cargo testが通らない理由
  • カスタムテストフレームワークを有効にする

バイト単位のアロケータを実装する

  • アライメントはなぜ必要か
    • メモリの速度とバス幅
    • キャッシュ──よく使うものは近くに置こう
    • アライメントが合っていないと回路がつらい
  • 簡単なメモリアロケータの実装

OSのテストをRustで書く

  • シリアルポート出力の実装
    • [column]CONVENTIONAL_MEMORY以外の領域の正体
  • デバッグを便利にする関数たちを実装する

ページング──より高度なメモリ管理を行う

  • ページングとは
  • x86_64におけるページング
  • 現在のページテーブルを表示してみる
  • 動作確認のために割り込み処理・例外処理を実装する
    • GDT──コンピューター黎明期,8086時代の遺物
    • TSS──割り込み時のスタック切り替えを制御する
  • コードセグメントとデータセグメントの設定
  • 割り込み関連の初期化
  • ブレークポイント例外のあとに実行を継続する
  • ページテーブルを作って設定する
  • ページングの動作確認をする
  • Pinの落とし穴

第4章:マルチタスクを実装しよう──1つのCPUで複数の作業を並行して行う方法について知る

マルチタスクとは何か

  • マルチタスクの例
    • [column]並行と並列の違い
  • 簡単にマルチタスクもどきを実装してみる

Rustのasync/awaitで協調的マルチタスクをする

  • aync/awaitを使えるようにする
    • Future trait
    • WakerとRawWaker
    • block_onの実装
    • Executor
    • ほかのタスクに処理を譲る(yieldする)
  • 時間経過を計る
    • タイマー──時間を計るデバイス
    • ACPIからHPETの場所を教えてもらう
    • HPETを初期化する
    • static mutを使ってHPETを共有する
  • スレッド間で安全にデータを共有する
    • データ競合とは
    • Rustにおける参照のルール
    • Mutex──実行時にメモリ競合を回避するしくみ
    • Mutexを使ってHPETのインスタンスをOS全体で共有する
  • タスクの実行を一定時間止めるFutureを作る
  • 協調的マルチタスクの問題点
  • (発展)非協調的マルチタスク

ソースコードの整理

  • HPETの初期化処理をリファクタリングする
  • メモリアロケータの初期化を関数に切り出す
  • ページング関連のコードを整理する
  • 画面描画周りの初期化を別の関数に切り出す
  • VramTextWriterをBitmapTextWriterに一般化する
  • print系マクロの出力をQEMUの画面上にも表示する

第5章:ハードウェアを制御する(1)──デバイスを動かす方法を知る

OSとハードウェアの関係

  • Port Mapped I/OとMemory Mapped I/O
  • Port Mapped I/Oの例──シリアル入力を実装する

PCIとは

  • PCIの概要
  • Bus,Device,Function
  • ベンダー ID,デバイスID

PCIデバイスの一覧を取得する

  • PCI Configuration空間
  • ECAM──Enhanced Configuration Access Method
  • PCIデバイスの一覧を表示するコードを実装する

USBコントローラ(xHCI)のドライバを実装する

  • USBとは
  • xHCIとは
  • xHCの検出
  • ちょっと脱線──諸々の改良
  • 起動時のページテーブル初期化の高速化
  • Memory mapped I/OでxHCとやりとりをする
  • xHCのレジスタ
  • xHCの初期化
    • xHCをリセットする
    • Scratchpad Bufferを確保して設定する
    • DCBAAを確保して設定する
    • Primary Event Ringを用意する
    • Command Ringを用意する
    • xHCをスタートする
  • IoBox──CPUのキャッシュとMemory-mapped I/Oの関係
  • USBデバイス接続時の処理を実装する
    • イベントのポーリングをする
    • USBデバイスの検出
    • デバイスの検出とポートの初期化
    • Device Slotの有効化
    • USBポートの初期化処理を整理する
    • Address Deviceコマンド──USBデバイスにアドレスを割り当てる

第6章:ハードウェアを制御する(2)──USBデバイスを使えるようにする

USBデバイスの情報を取得する

    • [column]FromトレイトとIntoトレイト
  • Device Descriptorの取得
  • デバイスクラス
  • USBにおけるConfig,Interface,Endpointの関係
  • Config Descriptorとその仲間たちを取得する

USBキーボードを使えるようにする

  • USBキーボードの基本
    • [column]Nキーロールオーバー
  • キーの押下状態から変化したキーを特定する
  • なぜHashSetではなくBTreeSetを使うのか
  • キーコードから文字への変換
    • [column]キーボードレイアウトの闇──打ちたい記号が入力できない!

USBマウス……もといタブレット入力を使えるようにする

  • HIDレポートディスクリプタを解析する
  • USBタブレットの状態変化を表示する
  • ビットを切り出す関数を実装する
  • マウスボタンの状態を解釈する
  • ポインタ位置の情報を取り出して表示する

Appendix:実ハードウェアでの起動を試す

  • USBメモリをFATファイルシステムでフォーマットする
  • WasabiOSをUSBメモリに書き込む
  • USBメモリからの起動
  • 実機で試すときの注意点
  • おわりに
  • 参照している仕様書の一覧
  • 索引
  • 著者プロフィール

著者プロフィール

hikalium

小学生のころから自作OSの楽しさに目覚め,以後エミュレーターやCPU,コンパイラなどの自作にも手をのばす。2017年よりIPA主催のセキュリティ・キャンプ全国大会にて講師を担当。現在はGoogleでソフトウェアエンジニアとしてChrome OSの開発に従事している。

X@hikalium