ハイパーバイザを自作して仮想化技術やセキュリティについて学ぶゼミ 応募課題

はじめに

問題は4つあります。回答する際は以下のことに気をつけてください。

生成系AIの使用について

生成系AIの使用は許可します。ただし使用した際はそのことを明記してください。

生成系AIには、単純に文章を生成するものと生成する際に使用した文章の出典を付記するものがあります。 適宜、出典を確認しその情報の真偽を確認してください。

低レイヤの情報は、残念ながらあまり文章化されておらず情報源が乏しいもの、誤った知識で書かれたもの、別の環境の情報で役に立たないものなどが多く存在します。 このため生成系AIの出力する情報については必ずしも正確とは言えません。また一般的には正解だったとしても対象とした条件下では動作しない場合があります。

また、各種生成系AIにおいても学習セットや手法によっては真逆の回答が得られる場合があります。複数の生成系AIを比較するのも手でしょう。

例として、「i386のCPUを搭載したVirtualBoxでIntel 64用OSは動作しますか?」と入力した際の、GPT-3.5とGPT-4の結果を示します。

GPT-3.5

はい、i386のCPUを搭載したVirtualBox上でIntel 64用のオペレーティングシステムは動作します。 VirtualBoxは、ホストマシンのアーキテクチャとは異なるアーキテクチャの仮想マシンを実行することができます。 i386のCPUを搭載したVirtualBox上で64ビットのオペレーティングシステムを実行する場合、仮想マシンの設定でIntel 64(AMD64)を有効にする必要があります。 ただし、仮想マシンのパフォーマンスは、ホストマシンの性能に依存するため、注意が必要です。

GPT-4

「i386」のCPUを搭載したVirtualBoxで「Intel 64」用のOSを動作させることは基本的に不可能です。 なぜなら、i386は32ビットアーキテクチャを示し、Intel 64は64ビットアーキテクチャを示すためです。 64ビットOSは、64ビットアーキテクチャ上でしか動作しないため、32ビットアーキテクチャの上では動作しません。

ただし、一部の64ビットOSには32ビットモードがあり、その場合は動作する可能性もありますが、性能面で大幅な制限があることを理解しておいてください。 また、すべての64ビットOSが32ビットモードをサポートしているわけではありません。

以上の情報は2021年9月までのもので、それ以降の情報については保証できません。 もし最新の情報が必要なら、公式のVirtualBoxのウェブサイトや関連のフォーラムをご覧になることをお勧めします。具体的なOSや設定についてもっと詳しく知りたい場合は、お知らせください。

生成系AIの出力した情報を元に自分で検討・検証し、その結果を踏まえてさらなる調査や実験を行うことを期待します。

問題.1

本ゼミで取り組んでみたいことを、講義概要を読んだ上で回答してください。 あなたの知識や経験、及びそれらから得た学びなどを記述すると良いでしょう。 もしこの分野について初心者であるという場合は、なぜあなたがハイパーバイザに興味を持ったかを記述してください。

また、取り組む上で必要となる知識やそれを得るための手法、前提となるコンピュータの機能などを調査し記述してください。

問題.2

ハイパーバイザによる仮想化とエミュレータによるエミュレーションの違いについて述べてください。 ポイントとして以下の点を調べて挙げてください。

問題.3

Booting AArch64 Linux を読んでAArch64用のLinuxをブートする際にブートローダがすべきことを述べてください。

またハイパーバイザで必要となるブートローダの処理について、特にメモリ配置に注意して、以下のC言語のテンプレートを元に記述してください。

実装条件は以下のとおりです。

この問題では、仕様を自分なりに調べて理解しコード設計に落とし込めるかどうかを見ています。 指定したドキュメントには今回の処理に必要ない規定や説明があります。この中から必要な情報を探し出してコードに書き出してください。

すべての処理を完璧に記載する必要はありません。システムプログラムを書く際は、まず最低限動くようにする事を目標にすることが多いです。 このため、実装の優先度を把握し、必要な部分を実装するテクニックが必要です。 「本来はこのような処理が必要だが、今回はこうなっているであろうと仮定して記述した」というのがあればそれがわかるようにコメントで記載してください。

まずは、メモリに正しく"Image"と"DTB"が正しく配置され、entry_pointに適切にジャンプできることを目指してください。 その上で、追加の"Initramfs"のロードと、そのアドレスの通知、周辺デバイスの初期化などをわかる範囲で記述してください。

わからない部分があった場合は、その事を明記して自分の思う実装を記述してください。 間違った処理となっていても減点はしません。その処理がどのくらいの優先度で必要かを把握できていれば加点します。

何をしたら良いか分からない方へのヒント

この問題はLinuxという「ソフトウェア」を如何にメモリ上にロードして実行開始場所を特定するかが理解できるかを見ています。

ソフトウェアは通常メモリにロードされ、CPUのインストラクションポインタをロードしたソフトウェアのエントリポイントに設定することで実行されます。 これは、OSであるLinuxでも変わりません。

仮想マシンでゲストOSを起動する際はデバイスの設定などが必要ですが、今回は難しいことを抜きにしてソフトウェアを読み込む作業に集中してください。

指定したドキュメントには、"must be placed"というワードが複数出てきます。"placed"はすなわちメモリに配置される、ロードされるという意味です。 各プログラムやファイルを読み込む際には読み込む場所(アドレス)に制約があります。一番良く出てくるのがアライメントです。 アライメントについて知らない場合はまずこれについて調べて記述してみてください。その後アドレスの計算を行ってみてください。

今回メモリはmemで確保してあります。仮想マシンで使用するメモリの0番地がmemの指す先だと考えると仮想マシン上でのx番地はmem + xということになります。

これらを元にプログラムを書くと、実は数回、fread(mem + offset, 1, read_size, fp) を実行し読み込んだ値をif文で少し検証し、値を取り出してlaunch_vmに渡すだけで最低限の実装は完了します。 書いた後に、「こんな少ない行数でいいんだろうか...」と不安になるくらいかもしれません。 しかし実際のところ、これにデバイスの設定などを追加するだけでLinuxは動作してしまいます。 実装が出来たら、どうしてそのような実装にしたかをドキュメントを元に記述してみてください。

ここまで出来て余裕があったら、ドキュメントに書いてあるデバイスの設定などにトライしてみてください。 おすすめは、"initramfs"のロードです。これは単純にfreadするだけでは不十分です。 何が必要かを考え、適宜関数宣言を追加してください。

テンプレート

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>

#define MEM_SIZE (512 * 1024 * 1024)
#define MEM_ALIGN 1 /* 調整してください */

/*
 処理内容: VMを指定された条件で実行を開始します。
 引数:
 - mem_start: 仮想環境と共有するメモリ領域の開始アドレス
 - mem_size: 仮想環境と共有するメモリのサイズ
   - 仮想環境は mem_start ~ (mem_start + mem_size)
 の間のメモリにアクセス可能です。
 - entry_point: 仮想環境で実行を始めるアドレス
 - x0: 実行を開始する際のx0 registerの値
 - x1: 実行を開始する際のx1 registerの値
 - x2: 実行を開始する際のx2 registerの値
 - x3: 実行を開始する際のx3 registerの値

 結果:
 成功した場合は、VMに制御が移り、この関数は戻ってきません。失敗した場合はエラーコードが返却されます。
 */
int launch_vm(uintptr_t mem_start, size_t mem_size, uintptr_t entry_point,
              uint64_t x0, uint64_t x1, uint64_t x2, uint64_t x3);

/*
 main関数内では表現できない処理がある場合は、上の"launch_vm"のように処理内容と引数、結果を明記して関数宣言の形で記載してください。
 */

int main(void) {
  void *mem =
      aligned_alloc(MEM_ALIGN, MEM_SIZE); /* VMに割り当てるメモリです */
  FILE *image = fopen("./Image", "rb"); /* Linux Kernel Image */
  FILE *initrd =
      fopen("./initramfs", "rb"); /* Initramfs 使用しなくても構いません */
  FILE *dtb = fopen("./dtb", "rb"); /* The device tree blob (dtb) */
  int err = 0;

  /* ここから処理を記述してください */

  err = launch_vm(mem_start /*変更してください*/, mem_size /*変更してください*/,
                  entry_point /*変更してください*/, x0 /*変更してください*/,
                  x1 /*変更してください*/, x2 /*変更してください*/,
                  x3 /*変更してください*/);
  return err;
}

問題.4

これまでにあなたが行ってきたプログラミングに関することについて記述してください。 自作ハイパーバイザや、自作OS、その他システムプログラミング、それ以外のプログラミングについても可能な限り記述してください。 リポジトリへのリンクや、活動記録サイトへのリンク、プログラミングでのこだわりなども歓迎します。 また、この応募課題を解くにあたって、苦労した点や分からなかった点があれば記載してください。

アンケート(任意)

選考を通過し、本ゼミに参加できるようになった場合に、どのくらい事前学習に時間が割けるかと自身の知識や環境について差し支えない範囲で教えてください。 この項目は選考には影響しません。選考が完了し事前学習に向けて資料や環境作成を行う際に、どのような事を重視すべきかやスケジュールを決定する際に参考とします。 基本的にはLinux環境(VM含む)でRustを使用しようと思いますが、「どうしてもLinux環境が用意できない」「Rustは何度も挫折しており到底理解が出来ない」などあれば記載してください。