マイクロカーネルとL4について (Yabaitech.tokyo, Writing a (micro)kernel in Rust in 12 days より)

怒田さん*1のこの記事、「CとRustで一から作るマイクロカーネルOS」のおかげで、マイクロカーネルとRustが今ホットです。そこで、技術書典6, 7に出展したYabaitech.tokyoにて連載している、"Writing a (micro)kernel in Rust in 12 days"から、マイクロカーネルとL4についての話を書いた"1日目"の記事の一部冒頭を、いい機会なので再編集してご紹介します。「マイクロカーネルってタネンバウム教授とリーナスの論争のあれだよね?」とか、「L4ってなに?」って方に読んでいただいて、L4ファミリーとマイクロカーネルについて簡単にご紹介できればなと思います。

ちなみに抜粋元の上述の記事は、僕が怒田さんと同じようにRustでマイクロカーネルを書いてみよう、という趣旨の企画です。なので、Yabaitech.tokyoの方もよろしくお願いします!ただし、肝心の連載/実装の方は大して進んでいないので、僕のマイクロカーネル実装が気になったとしても、もう少し首を長くしてお待ちください。Yabaitech.tokyo自体には、粘菌を育てる話、Automata Inference, 新矛盾主義紹介などなど個性的な記事が多いので、ぜひぜひよろしくお願いします。*2

 

 


マイクロカーネルとL4

What is Microkernel?

 早速だが、 マイクロカーネルとは何だろう?ひと段落で言えばだいたい次のようにな
る。

マイクロカーネル(英 : microkernel)とはオペレーティングシステムの設計思想、及びそのような OS のカーネル部の名称である。
OS が担う各種機能のうち、必要最小限のみをカーネル空間に残し、残りをユーザーレベルに移すことで全体の設計が簡素化でき、結果的にカスタマイズ性が向上し、性能も向上できるという OS の設計手法のことである。
カーネル本体が小規模な機能に限定されるので「マイクロカーネル」と呼ばれるが、必ずしも小さな OS を構成するとは限らない。

 以上、Wikipedia 日本語版 からの引用だ。ちなみに、マイクロカーネルの対義語にあたる、普通のカーネルの呼び名はモノリシックカーネルという。Linuxカーネルはこのモノリシックカーネルの典型的な例だ。主なメリットはそのカスタマイズ性の高さと信頼性、堅牢性*3といったところなんだけれど、これだけじゃ何が何だかという感じだろうし、重要な特徴をかいつまんで説明していこう。

 極小性

 まず、重要なことは、さっきの引用にもあるように、カーネルには必要最小限の機能のみがあるということだ。 カーネル空間では、CPU の特権命令を発行する必要があるような、本当にプリミティブな機能だけが動く。そして、それ以上の機能は、ユーザー空間で動くプロセスが、そのプリミティブな機能をシステムコールとして使いながら実現していく。これらのユーザー空間のプロセスはマイクロカーネルの世界では、「サーバー」と呼ばれる。サーバーは一つであるとは限らず、複数のサーバーがIPCを通じて連携して動作するのがむしろ普通だ。

L4 カーネルを例にとれば、カーネル空間で動く機能はおおまかに次の 5 つだけとなる。

  1. スレッドプリミティブ
  2. スケジューリング
  3. メモリ空間の制御
  4. IPC
  5. 割り込み制御

 もしかしたら、一見カーネル空間が担う機能としては普通のリストに見えるかもしれな
い。だから、普通の LinuxmacOSカーネル空間には存在しているけれど、このリストでは実は欠けているものをいくつか挙げてみよう。

まず、真っ先に気づきやすいのはデバイスドライバがリストにないことだ。マイクロカーネルアーキテクチャでは、デバイスドライバはユーザー空間で実現される。User space I/Oにあたるものがマイクロカーネルからデバイスドライバに提供され、デバイスドライバはユーザー空間にいながら特定のメモリ空間や IO ポートをたたくことでデバイス管理を実現する。これにより、マイクロカーネルではデバイスドライバがクラッシュしたとして、ほかのユーザー空間プロセスに影響を与えることはないわけだ。ファイルシステムデバイスドライバと似たような方法でユーザー空間に移されている。

欠けているものその 2 として挙げたいのは、プロセス管理機構。一見すると、あれ、そ
れは (1) で実現されているんじゃ?と思うかもね。でも実はそういうわけじゃない。L4 でいうスレッドとは、レジスタの値とメモリ空間の組を保存したもの、くらいの意味合いしかない。これもそれだけ聞くと普通そんなものなんじゃ?と思ってしまうだろうから、モノリシックカーネルではプロセス管理のためにもっとどんな機能があるか思い出そう。

分かりやすいのはプロセスの起動だろう。execve システムコールは、POSIX OS でプロセスを起動するためのシステムコールだとざっくり言ってしまってもいいと思うが、*4 このシステムコールの第一引数は起動したい実行ファイルのパスだ。 例えば macOS では、 ここに Mach-O フォーマットのファイルへのパスが渡される。 すると、 カーネルは、 あたらしいスレッドプリミティブを作成し、MachOフォーマットをファイルからパースして、しかも用意したスレッドプリミティブのメモリ空間にそれを展開してくれるわけだ。

f:id:nullpo_head:20191215171249p:plain

モノリシックカーネルにおけるexecve

一方、L4 のシステムコールではそこまでやってくれない。そもそもファイルシステムカーネルにないし、ファイルシステムを用意してあげたとして、Mach-O をパースするのはユーザー空間の役割だ。L4 のカーネルがやってくれるのは、単に空のメモリ空間と空のレジスタを持ったスケジュール可能なスレッドプリミティブを作ることだけ。それ以外のすべてはユーザー空間に実装されたサーバーの役割だ。 例えばプロセスが開いているファイルハンドルの管理、プロセスの実行ユーザーや実行グループの管理といった機能もすべて同様に L4 カーネルには欠けている。L4 のスレッドプリミティブを呼ぶだけでは、 普段私たちが親しんでいるプロセスらしいことは何も実現できないってわけだ。

このように色々な機能がユーザー空間のサーバーの役割とされて、カーネルは最小の機
能だけを実現することになっているのが、「マイクロカーネル」と呼ばれる理由だろう。これにより、カーネルのサイズはとても小さいものになる。それに、それぞれのサーバーはメモリ空間が分離されているから、一つ一つがクラッシュしても、その影響を最小限に抑えることができ、堅牢性も向上する。

OS パーソナリティ

じゃあ、 そんな最小限なカーネルを使ってしまったら、 いったいどうやって全体とし
Linux みたいなオペレーティングシステムを実現するのだろう!一言でいえば、 そう
いうマイクロカーネルに足りない部分を全部やるサーバーを一つ作る、 というのが答え
になる。

L4カーネル自体よりも、普通のOSに必要なもろもろの機能を実現するこのサーバーこそ、ユーザーからすればむしろ"OS"と呼びたくなる部分だろう。そしてこのサーバー(群)は、"OS パーソナリティ"と呼ばれることがある。

OS パーソナリティサーバーが、ファイルシステムサーバーやデバイスドライバサーバーを IPC を通して制御し、 POSIX の fork や read, write のような、ユーザーアプリケーションから見えるシステムコールを実装する。そういったサーバー群が協調して、全体として一つのオペレーティングシステムを実現する、 というのがマイクロカーネルベースのオペレーティングシステムの一つの形だ。仮にLinuxの機能を実現したOSパーソナリティがあったとすると、ユーザーアプリケーションがexecveを呼びたければ、L4カーネルシステムコールをたたくのではなく、このOSパーソナリティに対して、IPCを通じてexecveを要求することになる。

 

f:id:nullpo_head:20191215182915p:plain

マイクロカーネルOSにおけるexecveの一例



マイクロカーネルの面白いところは、このパーソナリティサーバーを取り換えることで
同じマイクロカーネルでも違うオペレーティングシステムを実現できることだ。L4 の上で Linux パーソナリティを走らせれば、Linux のアプリケーションが動くし、(仮にあるとすればだが)macOS パーソナリティを走らせれば macOS のアプリケーションが動く。 おまけにパーソナリティはユーザー空間のサーバーだから、同時にいくつも並行して走らせることができる。*5マイクロカーネルとパーソナリティの試みは、面白い具体例が色々ある。Fiasco.OC L4 カーネル上で Linux が動く L4 Linux。 これは今も開発が活発に続いている。 何しろ Fiasco.OC は商用 L4 マイクロカーネルだ。 過去の例でいえば、Minixが L4Ka 上で動く Minix/L4Mach カーネル上で Linux が動く MkLinux、 それに同じく Mach 上で動く OS である GNU Hurd. 他にも色々あるから、探してみるのもいいんじゃないだろうか。このようなOS全体の機能のカスタマイズ性の高さも、マイクロカーネルのメリットの一つだ。

そして、この面白い特徴から、一度あるマイクロカーネルの互換カーネルを作ってしまえば、その上でそのマイクロカーネル用の OS パーソナリティやサーバー群が動くことになる!これが Introduction で説明した自作カーネルを既存のマイクロカーネルの仕様に準拠させるモチベーションの一つだ。*6

L4 Microkernel

L4 family tree

さて、これでマイクロカーネルの一般的な概念の紹介はおしまいだ。まぁ大事なのは、 マイクロカーネルは小さな機能だけで構成されていること。 それに、 通常のオペレーティングシステムとしての機能は、マイクロカーネルの上で動く OS パーソナリティで実現されることだ。 この節からは、L4 マイクロカーネルについての話を始めよう。

L4 は、先ほど説明したマイクロカーネルアーキテクチャに基づくマイクロカーネル
一つだ。L4 と呼ばれるマイクロカーネル実装は複数あるから、きちんと呼ぶなら「L4 マイクロカーネルファミリー」になる。このファミリーというのは、だいたい「Windowsファミリー」と同じくらいの感覚だ。Windows には 95 系と NT 系があるわけだけど、どちらも Windows カーネルと呼ばれるし、それぞれでもバージョン毎にだいぶ違いがある。つまり、 ファミリーとは一つの実装を指しているわけではなく、 共通の系譜を継いだお仲間たちだというわけだね。

そして、L4 マイクロカーネルファミリーの系譜のおおよその起源は、Jochen Liedtke 先生による 1993 年の、ずばり「L4」だ。*7*8 L4 を起源とする L4 ファミリーの系譜の図を Wikipedia から上に引用した。論文"From L3 to seL4 - What Have We Learnt in 20 Years of L4 Microkernels?"*9は、L4 の重要な概念がよくまとまっているうえに、この系譜図上の L4 から seL4 にいたるまでに L4 ファミリーが解決してきた問題や、設計の変遷をまとめたとても良い読み物だ。L4 についてより詳しい資料を読みたくなったら初めにこれを参照してほしい。

他の L4 の重要な情報源といえばずばり公式サイトである http://l4hq.org *10だ。各種 L4 のドキュメントや仕様がまとめられているので、こちらも初めに参照してほしい。

マイクロカーネルとパフォーマンス - L4 の革命

L4 の開発がはじめられたモチベーションは、マイクロカーネルが抱えていた大きな問
題の解決にあった。その問題とは、パフォーマンスの悪さだ。マイクロカーネルは、そ
の設計上 IPC がボトルネックになりやすいということがよく議論にあがる。マイクロカーネルでは、システムコールがサーバー間の複数の IPC で実装され、そして IPC はコンテキストスイッチを伴う。 一方、 モノリシックカーネルシステムコールは通常 1 回のコンテキストスイッチで済むから、比較するとマイクロカーネルではシステムコールのコストが割高になってしまう。

L4 は、Liedtke がこの問題を緩和するために開発した、画期的なマイクロカーネルだっ
た。先ほど名前だけ少し出た、Machというマイクロカーネルでは、IPC のコストが顕著だった。*11この Mach は L4 の文脈では、「第 1 世代マイクロカーネル」として言及される。もちろん、L4 が第 2 世代だという流れでだけど。

Liedtke は、L4 で極小性をキーコンセプトとしてマイクロカーネルをデザインしなおした。IPC の機構は Mach に比べて極端に単純になり、メッセージサイズも小さくなり CPU のキャッシュになるべくすべてのメッセージが載るように設計した。スケジューリングなども単純化され、さらにはカーネルすべてをアセンブリで書いてしまうというものすごい執念でありうる極小のマイクロカーネルを完成させた。結果はどうなったと思う?なんと IPC は Mach に比べて 20 倍も高速化したのだ! *12ちなみに、 のちに L4 カーネルは C や C++ で書き直されたが、 パフォーマンスは悪化しなかったので安心してほしい。さらに後続の研究では、Linux パーソナリティが L4 上で実装され、 本物の Linux カーネルに比べても数パーセントのオーバーヘッドしか発生しないことが示された。*13もっとも、この実装では、LinuxパーソナリティにFSもデバイスドライバも組み込まれていることで、IPCのコストが抑えられていることには注意してほしい。*14

なにはともあれ、こうして L4 により、マイクロカーネルは実用的なオーバーヘッドで実現できるということが示されたのだ。

マイクロカーネルの逆襲

L4 の登場以降、マイクロカーネルは様々な方向に発展している。MINIX のタネンバウ
ム教授が 2016 年に"Lessons learned from 30 years of Minix"で述べているように、L4 ベースのマイクロカーネルはほとんどあらゆる iPhone のセキュリティチップで動いているし、QNX は色々な組み込み機器で実用化されている。 こいういう機器では、 少々の性能のオーバーヘッドよりも信頼性が重要だからだ。*15 そのタネンバウム先生の MINIX 自身も、実は世界中の Intel x86 CPU で動いていたという事実が最近判明した。*16

マイクロカーネルの発展は実用化方面だけではない。一番クールなプロダクトはやはり
seL4 だろう。*17 seL4 は、マイクロカーネルのコードサイズが小さいことを利用して、その正当性を Isabelle で証明したおそらく世界で唯一のカーネルだ。メモリ安全性といった一般的な性質や、ポートベースのポリシーシステムが決して違反されないことなどを数学的に証明している。*18

しかも seL4 はその仕様設計自体もかなりシンプルで良い感じだ。実際、今回実装する仕様の対象として seL4 はかなり有力な候補だった。しかし、仕様の大きさの問題でこの記事では seL4 を選ばなかった。 また、seL4 の仕様とそれ以前の L4ファミリーの共通点はほとんどないことも注意事項かもしれない。思想上の家族、といったところなのかもね。*19

普段 x86 Linux の世界でだけ生きていると、1992 年、つまり L4 発表の前年のリーナスとタネンバウム先生の論争からマイクロカーネルの時は止まっているかのように思えてしまうものだ。しかし、 マイクロカーネルのパフォーマンスは、モノリシックカーネルに比べれば見劣りこそするかもしれないが、L4 以降大幅に改善した。実用化という面では、QNX, MINIX, L4 の数を足してみれば、もしかすると実は Linux よりも多くの数のマイクロカーネルが世界では動いている可能性すらある。証明済みカーネルというユニークな成果も、マイクロカーネルでなければ不可能だったものだ。あまり大きくは知られていないけれど、マイクロカーネルの世界はどんどん発展していて、いつの間にか逆襲を果たしていたというわけかもしれない。

 

 

(おまけ) 自作OSとマイクロカーネルの相性、またL4 X.2. Standardについて


抜粋元のYabaitech.tokyoの記事は、マイクロカーネルの解説本ではなくて、Rustでマイクロカーネルを作ろうという記事でした。自作OSにはマイクロカーネルはピッタリなのでは?という話と、L4には「規格」があって開発しやすいという話を引用して終わりにします。


 

Rust 言語は、2019 年の今最も注目されているプログラミング言語の一つで、 低レイヤーの分野においては、特にモダンな言語機能を一通りそろっていることによる快適性と、所有権という新しい概念による GC に頼らないメモリ安全性から注目されている。(C 言語でのメモリ関連のデバッグの苦労を思い出せ!) コミュニティ全体で、システムレイヤ ―での応用を考慮しながら開発が進められているのも魅力的なポイントだ。だから、2019 年にカーネルを書く際に Rust でやってみようと思うのは全く奇妙なことではないだろう。*20一方カーネルは、 知っての通り、オペレーティングシステムの中核コンポーネントだ。CPU のもっとも権限の高い空間で動作し、コンピュータのすべてを管理しなければならない。それを 0 から自分で書くというのはとても面白い体験だと思う。プログラマーの「3 大作ってみたいもの」によくあがる、コンパイラ・ CPU・オペレーティングシステムのまさに 3 つ目にもあたることだし。*21 そして今回書くカーネルはただのカーネルではなくマイクロカーネルだ。

今回マイクロカーネルを選んだ大きな理由は二つある。一つは、マイクロカーネルはサイズがとても小さいということ。実用レベルの OS である Redox でも、マイクロカーネル部分のコードは 1 万行未満だ。Linux カーネルのような巨大なモノリシックカーネルを自作してみようというのは途方もない話だが、マイクロカーネルならば短い期間でゼロからでも完成させることができるはずだ。実は去年ついに大学院を卒業して会社員になってしまい、無事に自由時間が今までの 7 分の 2 に減ってしまった。だから短い期間で完成させたいというのは結構切実な願いで、そのために作るカーネルとしてマイクロカーネルを選んだのは自然なことだったわけだ。

そして、もう一つの理由は、L4 マイクロカーネルファミリーという有名なマイクロカーネルの仕様が存在すること。実装するべき完成図がはっきりしているから学びながら開発していくのに都合がいいし、しかも無事仕様をみたせたときには自作したカーネルのうえで、既存のユーザーランドアプリケーションが動作することになる。OS を自作するとき、こんなに嬉しいことはないだろう!小さな労力でこれを達成したら、あとはサーバーなどの自分のユーザーランドをインクリメンタルに開発してゆくことも可能だ。L4 マイクロカーネルは実世界で使われた実績もあってまだ活発に開発・研究がされている。そして今回扱う L4 X.2 Standard のいいところは、何と言ったってシステムコールが 12 個しかないことだ。そう聞いたらなおさら短期間で作れそうな気がしてこないだろうか?仕様があるってことに加えて、 しかもその仕様が小さいわけだ。 色々と説明したけれど、 つまりはマイクロカーネルは自作をするにはピッタリだってこと!

L4 X.2 Standard

さて、 前の節の話でなんとなく分かるように、L4 と一言で言ってみてもまぁ色々な実
装があるわけだ。 じゃあ今回何を作ろうかと考えて決めた結論は、 系譜図のど真ん中あたりに陣取っている Pistachio だ。 Pistachio を選んだ理由は、一言でいって、短期間で自作するのにぴったりだから、だ。系譜図で紹介したように、L4 にはたくさん実装があるのだけれど、そのうちいくつかの実装は、「L4 マイクロカーネルの標準仕様」 に準拠して実装されている。マイクロカーネルの仕様、といわれてもピンとこないかもしれないが、 要は POSIX と似たようなもので、 カーネルが実装しているシステムコール、 そのシステムコールの呼び出し ABI などが定義されている。 割り込みが起きたときにどのようなプロトコルで処理が走るべきか、なんかも定義されているのは少しカーネルらしいところかもしれない。そして、Pistachio は、きちんと定義された最後の仕様といっていい、L4 X.2 Standard というものに準拠している実装なのだ。

L4 X.2 Standard はシステムコールが 12 個しかないというとても小さい仕様になっていて、準拠したマイクロカーネルを実装しやすい。ちなみにこの記事*22が 12 日でカーネルを作る、と言い張っているのはこのAPI が 12 個しかない、 ということを根拠にしている。 X.2 以降のおおよそ似たような L4 ファミリーといえば OKL4 と Fiasco.OC になるのだが、これらはどちらも実用的なマイクロカーネルとなっていて、アカデミアの世界で完結している X.2 に比べ実装されている API がとても多く、互換カーネルを作るのが困難だ。それにそもそもこれらのカーネルは、 もはやきちんと定義された仕様が存在しない。 一方 seL4 は、 実用性も兼ねているにもかかわらずきちんと定義された仕様が存在するのだが、 やはり X.2 に比べるとだいぶ大きな仕様になってしまっている。そんなわけで、最後の実質的な更新は 2010 年頃と少し古いけれど、互換カーネルを自作するのにピッタリの対象としては、X.2、それにPistachio が選ばれたというわけ。

さて、L4 の X.2 Standard について簡単にだけ触れておこう。 そもそも L4 の仕様とい
うときは、だいたい API と ABI の仕様を決めていると思ってくれていい。L4 X.2 では 12個のシステムコール (API) と、それらを呼び出す際の ABI が決められている。そのシステムコールとは、次のものだ。

  1. KERNELINTERFACE
  2. EXCHANGEREGISTERS
  3. THREADCONTROL
  4. SYSTEMCLOCK
  5. THREADSWITCH
  6. SCHEDULE
  7. IPC
  8. LIPC
  9. UNMAP
  10. SPACECONTROL
  11. PROCESSORCONTROL
  12. MEMORYCONTROL

冗談抜きでこれで全部だ。 実にシンプルで小さい仕様だ。ファイルフォーマットが ELF であること、みたいな仕様の範疇を越えることもあるから完全に互換ではないが、 気を付ければ同じユーザーアプリケーションを動かすことは実現できる。 それぞれのシステムコールが何をするものなのかはおおよそ名前から推測できると思う。 これらの詳しい仕様の資料は、http://www.l4ka.org/l4ka/l4-x2-r7.pdf から入手できる。この12個のシステムコールさえ実装すれば、自作のマイクロカーネルも、おおよそ Pistachio と互換のものになるだろう。そしてそうすれば、Pistachio用に書いたユーザーランドが、自作カーネルで動くことになる。そしてそれが、今回のモチベーションだ。*23

*1:ちなみになんですが、怒田さん2016年度の未踏同期の方です。

*2:Boothでこの記事のフル版も含め過去の3冊が買えますよ。

*3:Wikipediaが性能とまとめたもの

*4:おっと、顔をしかめないでほしい。 fork や exec の話は今は本質じゃないから先に進もう。

*5:まるでハイパーバイザみたいな話だが、実際マイクロカーネルは現代の仮想化機構と共通点が多い。

*6:Yabaitech.tokyo本誌ではこの章の前にIntroductionがあります。

*7:Jochen Liedtke. Improving IPC by kernel design. 14th ACM Symposium on OperatingSystem Principles, pages 175–188, 1993.

*8:L3 という L4 の前身のカーネルもある。そして正確にはそちらが起源なのだが、説明を簡単にするため L4 から始めたい。

*9:Kevin Elphinstone and Gernot Heiser. From L3 to seL4 What Have We Learnt in 20 Years of L4 Microkernels?. SOSP’13, pages 0–0, 1993

*10:2019/12/15日現在、どうやらサイトが落ちているようでうす。ひとまずGoogleのキャッシュなどからご覧ください。

*11:MachMinix と並んでもっとも著名なマイクロカーネルの一つだろう。現在の macOS の XNUカーネルの源流でもある。

*12:Wikipediaを参照

*13:前出、"From L3 to seL4 What Have We Learnt in 20 Years of L4 Microkernels?"より

*14:あまり典型的なマイクロカーネルOSの設計ではない。

*15:Tanenbaum Andrew S. Lessons Learned from 30 Years of MINIX. Commun. ACM, 59, pages 70–78, 2016.

*16:NETWORK WORLD. What is MINIX? The most popular OS in the world, thanks to Intel. https://www.networkworld.com/article/3236064/minix-the-mostpopular-os-in-the-world-thanks-to-intel.html, 2017

*17:Data61/CSIRO. The seL4 Microkernel. https://sel4.systems/, 2016.

*18:Data61/CSIRO. The Proof. http://sel4.systems/Info/FAQ/proof.pml, 2016.

*19:seL4のライセンスはGPL v2なのですが、ユーザーランドのネットワークドライバやファイルシステムBSDライセンスなのもポイントとsuzaki先生からコメントをいただきました. https://twitter.com/KuniSuzaki/status/1206186021257302017

*20:怒田さんは、カーネル部分を5回くらい書き直した結果、RustよりもCの方がマイクロカーネルには向いていそうだ、と結論付けています。とても興味深い結果ですね。僕の方もやってみて、Rustでマイクロカーネルを書いた感想がいつか書けたらいいなぁと思っています。

*21:ほんとか?

*22:引用元の元の記事

*23:実際は現存してきちんと動くPistachio用のユーザーランドはほぼ皆無なのですが、Pistachioの資産を用いてテストがしやすいという意味ではやはりアリでしょう。

Linuxカーネルを新しいCPUに移植する

この記事はLinuxアドベントカレンダー2015 21日目に大遅刻した記事です。ごめんなさい

皆さん、ご家庭に「作ってみたはいいけれど、動くOSがなくて困ってる!」っていうCPUはありませんか?もしそんなCPUがあればLinuxを移植してみてはどうでしょう??
この記事ではLinuxを新しいCPUへ移植する話をします。

前書き

なぜLinuxを新CPUに移植する話をしているかというと、学科の同期数名で、FPGAで作ったCPUにLinuxを移植するということを5月ごろから細々と進めているからです。(もっとも院試やら卒論やらで本格的に作業できるのは実際には来年の2月以降です。。)これは以前自作CPUにxv6を移植したやつの第2段階ですね。

まだ新CPUのもろもろが出来上がっていませんので、現在は本番の移植のための勉強としてx86アーキテクチャのミニマムな再実装をやっているところです。本記事は今までの知見をもとに書かれています。まだ移植を完成させたわけではないので、記述に不完全/誤ったところがあるはずです。見つけた場合はご指摘くださいませ。

移植関連資料

さて、Linuxを新CPUに移植するのは簡単なタスクではありません。やることはそれなりにありますしLinuxカーネルの理解ももちろん必要です。そして何よりまとまった資料が少ないことが問題になりました。以下に参考になりそうな資料をいくつか挙げておきます。

Embedded Linux Conferenceでの発表資料です。移植の全体的な流れが俯瞰できると思います。

K1というプロセッサーにLinuxを移植した際の話が載っています。実際に移植する際の具体的な雰囲気が感じ取れます。

Linuxカーネルを移植するための正しい方法」についてのLWNの記事なんですが、要約すると「x86からコピペすんなカス」という記事です。詳しい移植の流れなどについては特に触れられていませんが、今では不可欠な存在になったasm-genericが紹介されています。

で、僕らが作業を始めた頃はこれくらいしか資料がなく大変だなーと思っていたのですが、実は最近次の記事がLWNに上がったようです。

移植にあたって書かなければいけないことが、簡単にではありますが、網羅的にまとまっています。これからLinuxを移植しようと思ったらまず第一に参照すべき資料になると思います。*1

Linuxカーネルそのものの情報については、定番ですが

詳解 Linuxカーネル 第3版

詳解 Linuxカーネル 第3版

が参考になると思います。

ただ、ご存じの通り詳解Linuxカーネルは扱うカーネルのバージョンがだいぶ古く、現在の状況と食い違うことがしばしばあります。最近は0xAXさんによる Linux Inside - GitBook が、最新の4.x系列のカーネルに沿った解説をしていてかなり参考になります。現在進行形で内容がどんどん充実してきているのでぜひブクマしておきましょう。

ツールチェインの移植 - clangも使えるけど・・・

Linuxを移植するにはLinuxコンパイルできるコンパイラアセンブラ、リンカが必要になります。なので先にこれを移植しなければなりません。

まず絶対にGNU binutilsは必要です。asやldですね。Linuxをビルドしたいなら他の選択肢はないはずです。次にコンパイラですが、移植するのはgccとclangどちらでも一応大丈夫です。「あれ、Linuxってclangでビルドできたっけ?」となると思うんですが、実はアーキテクチャ非依存部はclangでもビルド可能になっています。x86のビルドが現時点ではこけてしまうので実感がないと思うのですが、後々紹介するスタブアーキテクチャはclangでもばっちりビルドできます。clangでのLinuxのビルドの状況は別記事にでもまとめたいですね。

ただ現状ではclangのビルドは不安定です。3.6系でtypeof演算子のバグを踏んでカーネルのビルドが落ちていたなどclang側でも時々問題が発生しますし、カーネル側もarch/x86を見ればわかる通りclang未対応の機能を気兼ねなくぶち込んできます。お互いにお互いをあまり慮っていないように見えるので、clangを選ぶ際はそこらへんを考慮した方がいいでしょうね。Linuxをclangでビルドできることが当たり前になる時代はそう遠くないと体感的には感じているんですが・・・。

gccbinutilsの移植に関しては今回はこれ以上触れません。 詳しくは、Open Computer Design Projectの 新アーキテクチャに GCC を移植 [Open Design Computer Project] がとても参考になると思います。

archディレクトリ

ここからが本題になりますね。Linuxカーネルアーキテクチャ依存部を書く話です。

まずLinuxソースコードの構成をざっと俯瞰すると、だいたい以下のような感じになっています。

├ Documentation/     
├ arch/     
├ block/    
├ certs/    
├ crypto/   
├ drivers/  
├ firmware/     
├ fs/   
├ include/  
├ init/     
├ ipc/  
├ kernel/   
├ lib/  
├ mm/   
├ net/  
├ samples/  
├ scripts/  
├ security/     
├ sound/    
├ tools/    
└ usr/virt/  

kernelにはカーネルのコアになる機能、fsにはファイルシステム、mmにはメモリ管理周りといった風に、目的に応じてソースコードが分類されて詰められています。ドライバーなどは別にすれば、移植に当たって触らなければいけないのは、上から2番目のarchディレクトリだけです。この中にさらにアーキテクチャごとにディレクトリが作られ、例えばx86やらmipsやらopenriscやらといったものがこの中にすでに並んでいます。ここに新しいディレクトリを作り、アーキテクチャ依存部として必要なソースコードを追加していくのが具体的なLinuxの移植作業になります。

例えばnew_cpuというアーキテクチャを追加したければ、arch/new_cpuなるディレクトリを作ればいいことになります。加えてちょこちょことMakefileなどを追加すれば、

make ARCH="new_cpu"

とかするとカーネルがnew_cpuディレクトリを認識してくれてビルドを始めることができます。便利ですね。
といっても何も書いていない空ディレクトリではもちろん普通にビルドに失敗します。移植の第一歩はひとまずビルドができるように、各種ファイルやスタブ実装のコードを用意することになります。

ビルドシステムの理解

arch/new_cpu以下に必要なのはソースコードだけではありません。arch依存のMakefileも必要ですし、menuconfig用のconfigなどなども必要になります。ここらへんを何の頼りもなしに用意するのは不可能ですから、ほかのアーキテクチャを参考にしてarch/new_cpu以下に何を配置すべきなのか参考にしましょう。ただしこのとき、間違ってもx86などの奇天烈なアーキテクチャを参考にしてはいけません。おすすめなのは先ほど上げた資料中でも紹介されていたscoreというアーキテクチャで、とてもファイル数が少なく全体を読み通すことができます。僕らのx86再実装もscoreを参考にしつつ進めています。

scoreを参考にしてarch/score以下にどのようなファイルがあるか見てみましょう。

 ├ boot/  
 │    vmlinuxの作成に必要なMakefileなど  
 ├ configs/  
 │    アーキテクチャのデフォルトのmenuconfigなど  
 ├ include/    
 │    ├ asm  
 │    │   アーキテクチャ依存ヘッダファイル
 │    └ uapi  
 │         そのうち、ユーザー空間にエクスポートされるもの  
 ├ kernel/  
 │   ├ *.c      
 │   │   アーキテクチャ依存の関数などを記述します  
 │   └ vmlinux.ld.S  
 │        カーネルのリンカスクリプトを記述します  
 ├ lib/  
 │    文字列関数やビット演算など補助ライブラリ  
 └ mm/  
       アーキテクチャ依存関数のうち、メモリ管理周り  

x86などの巨大なアーキテクチャでない限り、だいたいこれと同じ構成になります。例えばopenriscなんかは全く同じディレクトリ構成です。(もっともscoreがopenriscを参考にしたのかもしれませんが。)
scoreの具体的なソースコードは、Linux/arch/score/ - Linux Cross Reference - Free Electronsなどでご覧ください。kernelやmmを覗くと、移植に必要なファイル数は思ったよりも少ないかも?って感想を抱くかもしれません。

ご覧の通り、ビルドのために各種Makefileやconfigファイルが必要です。先ほど書いた通り、各アーキテクチャの実装も参考にするのでが、大本の参考資料としてkernel.orgのDocumentationにあるKbuildのマニュアルは必読です。これらはおそらくオンラインで手に入るLinuxMakefileやconfigの最も詳細な解説になります。arch開発者向けの資料も用意されています。

リンカスクリプトであるvmlinux.ld.Sも書く必要があります。リンカスクリプトは資料がほとんどないため書くのに苦労すると思います。基本的にはGNU ldのあまりまとまりのよろしくないマニュアルを読んで理解するしかありません。VMAとLMAがきちんと設定できているか気を付けながら書きましょう。具体的なカーネルリンカスクリプトの例の一部がinclude/asm-generic/vmlinux.lds.hの冒頭のコメントにあって参考になります。また、後に紹介する僕らのアーキテクチャstub nullpo-head/Linux-Architecture-Stub · GitHub がこれをもとに完全なvmlinux.ld.Sを書いていますので参考になるかと思います。

スタブを作る

ビルドシステムに必要なファイルを準備できたら、次はリンクを成功させるためにスタブコードを用意しなければなりません。

一番最初に紹介した資料Porting Linuxのように、基本的には「他のアーキテクチャをコピペしてはいけない」です。ので、Makefileやvmlinux.ld.Sだけ他のアーキテクチャを参考に書き、ひとまずビルドが走るようになったらエラーメッセージを頼りにスタブを増やしていく・・・というのが理想の流れとされているようです。Porting Linux to a new processor architecture, part 1: The basics [LWN.net]でも、エラーメッセージを頼りに何の関数が必要か推測すると書いてあります。これは、すでにあるアーキテクチャをコピーすると不要なものまで実装してしまいやすいからだとThe right way...では説明されています。

とはいえこの作業は大変ですし、最低限のスタブはわりとHW非依存になるはずなのに各自で書くことに若干不毛さも感じてしまいます。これを解消するためにThe right way...では、「ブートまでできるexampleアーキテクチャを用意してそこからブランチできるようにするぜ!」と宣言していて実装も進んでいたそうなんですが、コメント欄いわく「gitインフラ移行のゴタゴタで消えちゃったわ」だそうです。合掌。

さて、前言をひっくり返すようですが、僕らはx86最小実装ではあえてscoreのコピーから始め、最低限の定義以外をガリガリ削ってスタブを作ることにしました。繰り返すように、既存のアーキテクチャをコピーして始めることのデメリットはとにもかくにも無駄な機能もよく分からないままコピーしてしまうことです。しかし、scoreはとても小さい実装なのですべての行に目を通すことができ、なおかつPorting Linuxで紹介されているようにとてもきれいで読みやすいです。なのでx86やarmなどの巨大なアーキテクチャと違い、目を通さないまま丸々コピペする心配があまりありません。この方法で始めると最初からビルドが通るので、作業中に誤りを埋め込んでもすぐに発見できてとても楽になりました。

先ほどのブートまでできるexampleアークテクチャには及びませんが、x86再実装とは別にscoreをもとにしたstubアーキテクチャ

github.com

にて作成中です。もし新しく移植を始める際にはお役に立つかもしれません。まだまだscore依存のコードが(特にヘッダファイルに)残っていますが、x86再実装の進行とともに洗練させていくつもりです。

make ARCH=stubs tinyconfig
make ARCH=stubs -j4

にてビルド可能です。出来上がるELFはx86用になっています。

ところでツールチェインの節で紹介したようにこれはclangでもビルド可能です。その場合、

make ARCH=stubs CC="clang -no-integrated-as"

となります。-no-integrated-asって何やねんというとclangの統合インラインアセンブリによる最適化を無効にするオプションです。clangのバグと機能不足によるもので、現時点ではこれを付けるのがLinuxビルドのデファクトになっています。

中身を書く

スタブができたら後はひたすら中身を実際に実装していく作業になります。スタブを理解してほかのアーキテクチャを流し読みしていると、だいたいやるべきことが分かってきます。流れとしてはだいたい以下のようになります。

  1. head.Sにブートシークエンスを書いてstart_kernelまで走らせる

  2. メモリ初期化や割り込み初期化など初期化処理を書いてstart_kernelを完遂させる

  3. 割り込みハンドラやswitch_toなど、カーネルの動作に必要なarch依存部を書いてinitを起動させる

なお、これらはkernel/*.cだけを埋めていけばいいというわけではなく、動作に必要なヘッダファイルも並行して埋めていくことになります。例えばメモリのレイアウトに関する定数など。またLinuxはヘッダファイルにも.cファイル並みに関数の実装を書くので、それも書いていく必要があります。書かなければいけない主要な関数などは、

Porting Linux to a new processor architecture, part 2: The early code [LWN.net]

にまとまっているので雰囲気を知りたい方はぜひ参考にしてください。

x86再実装においては、僕らはまだまだ2の途中の段階です。1のブートシークエンスはmulti boot headerを書いてgrubqemuにハードウェアの初期化を任せ簡潔に済ませました。

実際にコードを書いていく作業は当たり前なんですが大変です。数としては書くべき.cは意外と多くないのですが、カーネルの理解が必要とされるので、カーネルの勉強を並行しての作業だとあまり速くは書けません。また、include/以下の.hの方は多いと100個ほど書かなければならないそうです。もっとも現在はasm-genericをincludeするだけで大半のものが済ませてしまいます。感謝感謝。

自分もまだまだ作業中なので、この部分に関して簡潔にまとめることは残念ながらまだまだできません。実際に作業をしての雑感としては、コードを書いている時間よりもカーネルのコアのコードや資料を読んでいる時間の方が何十倍もあるね!という感じです。(カーネルnewbieなので当然ですね。)新年ではカーネルの移植を完了しての雑感を書きたいところです。

まとめ

Linuxを新しいCPUへ移植する作業は、ツールチェインを移植したのち、archディレクトリ以下をほかのアーキテクチャを参考にしつつ実装していく作業でした。最近はPorting Linux to a new processor architecture, part 1: The basics [LWN.net]などのいい感じの資料も出てきて作業がしやすくなっています。カーネルの勉強にももしかしたらちょうどいいかもしれません[要出典]

Linuxを移植したいけど余った新しいCPUがない?そんな場合は学科の後輩たちが書いている CPU実験 Advent Calendar 2015 - Adventar にいい感じのCPUの作り方の記事があるかもしれませんし、ないかもしれません。(雑な宣伝)

ところで文中何度も出てきたx86のミニマムな再実装ですが、レポジトリこちらになります。ただし本格的な作業がまだなので、今はどなたかの参考になる段階にはないと思います。。後々の成長を見守ってくださいませ。

それでは皆様、メリークリスマス! & よいお年を!

*1:移植が終わったらこういう資料を作ろうと思っていた僕たちからすると少し複雑

ビルドしたLinuxカーネルをブートできる最低限の環境を用意する(with Busybox & qemu)

最近Linuxカーネル周りを触り始めています。Linuxカーネル周りを触り始めたといってもそもそもLinux歴が浅く、menuconfigを本格的にいじりながらビルドするのは今回が初めてだったりしてブートするだけでも大変でした。そこらへんをまとめます。

カスタムビルドしたLinuxカーネルをブートできる環境を簡単に用意する

今更何だという感じですが、Linuxとは正確にはカーネルの部分だけのことを指していて、ユーザーランドを含みません。巷でよく言われるアレですね。(もしあなたが十分に信心深いなら、Linuxシステム全体をLIGNUXと呼んでもよいです。)
なのでkernel.orgから引っ張ってきたカーネルソースをビルドしても、すぐには起動して試すことができません。ubuntuなどのディストリのカーネルを入れ替える形でブートさせてもいいのですが、 カーネルソース自体をいじっていてテストをしたいときなど、あまりデカいディストリを振り回したくない状況もあるでしょう。本記事ではBusyBoxで簡単なユーザーランドを作ってqemu上でカーネルをブートし、カーネルの動作を確認できるように基本的なコマンドを使える環境を構築する方法を紹介します。

注意

この記事は、特にARMをターゲットとしていないことと一般的なカーネルビルドの方法もまとめて書いてあることを除いては Busybox for ARM on QEMU | Freedom Embedded に書いてあること以上のことは何も書いていません。BusyBoxを用いてファイルシステムを構築する方法を手早く知りたければこちらを参照することをオススメします。

カーネルをビルドする

まず一般的なカーネルのビルド方法をメモ書きしておきます。

とにもかくにもカーネルのソースが必要です。kernel.orgからほしいバージョンのソースを入手しましょう。適当にアーカイブを展開し、展開したディレクトリに移動すれば

$ make menuconfig

を叩くことによってカーネルの各種オプションを設定できます。なおこの記事ではinitramfsを使ってブートするので、General Optionsの中のinitramfsをサポートするオプションは無効化しないでください。
ちなみにこれは、GUIバージョンもあり、

$ make xconfig

および

$ make gconfig

を使うことができます。それぞれKDEGNOMEを使うGUIです。
また、色々いじった設定を元に戻したければ、

$ make defconfig

すればオーケーです。

次にやることは本番のビルドです。

$ make -j4

とすればオーケー。普通ですね。もちろん-j4の部分のスレッド数は適宜あなたのコア数などに合わせて置き換えてください。だいたい10分くらいビルドに時間がかかるように思います。

さて、ubuntuなどのディストリのカーネルを入れ替える場合は普通この後make installとかするわけですが、今回はこのカスタムカーネルをとりあえずブートしてテストしたいだけなのでやりません。ユーザーランドをBusyBoxで作っていきます。

BusyBoxでユーザーランドを作る

次にBusyBoxを使ってinitramfsを作っていきます。なお、今回qemu上で動かすLinuxは、RAMのみのディスクなし、ユーザーランドもBusyBoxのコマンド群のみという構成になります。またアーキテクチャは、特に指定していない場合ホストのマシンと一致されます。

カーネルの時と同じく、まずBusyBoxのソースを用意しましょう。適当に展開した後は、そのディレクトリにて

$ make menuconfig

を叩くと、BusyBoxの設定のコンフィグ画面が表示されるので、ライブラリを静的にリンクするようにしてください。
その後、

$ make install

を実行してください。make installではありますが、ホスト上のマシンに何かがインストールされるわけではなく、単に_installというディレクトリができるだけです。sudoはつけないようにしましょう。
次に、起動後ルートファイルシステムとなることになるファイルを作ります。

$ cd _install
$ find . | cpio -o --format=newc > ../rootfs.img

もし容量を小さくしたい場合は、さらに先ほどの参考サイトに従って圧縮をかけてもいいです。

qemuカーネルをブートする

qemuは-kernelというオプションがあり、カーネルのelfバイナリを読んで直接メモリ上に配置してくれます。これによって特にブートローダを用意せずともカーネルをブートすることができます。さらにinitrdオプションを使って先ほど作ったrootfs.imgを渡します。
以下のコマンド

$ qemu-system-x86_64 -kernel bzImage -initrd rootfs.img -append "root=/dev/ram rdinit=/bin/sh"

を走らせることで、BusyBoxによるシェルが起動します。あとは普通にlsやらcatやらが使用できると思います。お疲れ様でした。

オプション:/procや/sysを機能させる

参考サイトにもあるフォローアップをこの記事でも書いておきます。
上までの手順では、/procや/sysが必要になる機能、たとえばpsコマンドが動きません。なのでこれらを機能させたければきちんとマウントする必要があります。

# mkdir /proc
# mount -t proc none /proc
# mkdir /sys
# mount -t sysfs none /sys
# mdev -s

これらを毎回行いたければ、proc, sysディレクトリおよびetc/init.d/rcSスクリプトをrootfs.imgの中に追加し、qemuのappendに書くブートパラメータのrdinitを/bin/shではなく/sbin/initに変更しましょう。
rcSの内容はだいたい以下のようになります。

#!/bin/sh
mount -t proc none /proc
mount -t sysfs none /sys
/sbin/mdev -s

ざーっと要点だけ書いてしまっていますので、詳しくは元ネタのBusybox for ARM on QEMU | Freedom Embeddedの方を参照してください。

CPU実験で自作CPUにUNIXライクOS (xv6) を移植した話

今年のCPU実験では、有志からなる我らがX班が、おそらくCPU実験史上初である自作CPUへのOS (xv6) 移植に成功しました。コア係とコンパイラ係の面々がそれぞれまとめ記事を書いていたので、OS係から見たOS移植のまとめも書こうかなと思います。こんなことしてましたってことが伝わればいいなと思います。

この記事を読む後輩やらなんやらがいたら、ぜひ僕らがやったようなことはさっさとクリアしちゃって、さらにさらに面白いことをする踏み台にしていってほしいですね。

どなたが読んでもある程度概要が伝わるよう、まずCPU実験とは何かということをさらっと書いた後、実際にxv6を移植するにあたってやったことをまとめたいと思います。

CPU実験とは

CPU実験は僕の学科(理学部情報科学科)で3年冬に行われる、半年間にわたる学科名物演習です。

最初の週で4~5人程度の班に分けられた後、それぞれの班でオリジナルのCPUアーキテクチャを考案しそれをFPGA上に実装、加えてそのCPU用のocamlサブセットコンパイラを作り、作ったCPU上で課題のレイトレプログラムを走らせる、というものです。当然この命令セットが動く仮想マシンなんてものはこの世に存在しないので、自分たちの手でシミュレータを作る必要があります。またコンパイラの下で動くアセンブラも必要ですし、課題のプログラムがレイトレなのでCPUにはFPUも載せる必要があります。まぁこれがなかなか大変な演習で、過去には失踪者が出た例もあるとかないとか・・・。

ちなみにこのCPU、VHDLというハードウェア記述言語で作らされるのですが、大学でVHDLの書き方を習ったことは1ミリもありません。心温まるお話ですね。*1

自分たちで作ったCPUでOSを動かそう

さて、CPU実験の概要はそんな感じです。お気づきの方もいるかと思いますが、上の説明にはOSの話なんて全く出てきません。ちょっと説明を加えます。

実験の流れとして、ふつうはまずどんなに遅くてもいいから課題のプログラムが確実に動くCPUを一つ完成させます。これはよく1stアーキテクチャとか呼ばれます。で、実際に動くCPUを一つ作りさえすれば単位が確定するので、早めに完成した班はあとは割と自由な時間となるのです。ここから高速化を目指すのが正統派の班の行動なんですが、中にはゲームを作ったりスピーカーで音楽を奏で始めたりとお遊びに力を入れる班もでてきます。僕がコア係として所属していた6班は余興大好きの方の班で、CPU実験開始当初からOSを動かそうという話になっていました。この話に他班も興味を示した結果、晴れて8人くらいからなる合同班、X班が結成され、「自分たちのCPUでOSを動かすぞー!」という運びになったわけです。

xv6

移植するOSは、MITが教育用に作成した、Unix v6インスパイアなシンプルなOSであるxv6にしました。xv6はUnix v6と違ってANSI Cで書かれていて、x86上で動作します。教育用なだけあって、ユーザーランド周りやプロセス周りが少し貧弱ですが、シンプルかつUnixライクなOSとして割と十分な機能を持っています。詳しい情報はwikipedia公式サイトででも。

大変!

xv6移植する移植すると言っても、なんでもかんでもゼロから作ろうってわけですからソフトウェア側だけでも障害がいくつもあります。

  1. コンパイラどうすんねん
    CPU実験では普通mlコンパイラを作ります。当然Cなんてコンパイルできません。

  2. リンカも割とリッチなやつが必要っぽい
    xv6ではリンカスクリプトを活用してバイナリファイルをくっつけたりディスクイメージをくっつけたりします。CPU実験で作ったツールチェインにはリンカなんて高級なものはなく、だいたいアセンブラ複数ファイルをぶん投げたら一つのバイナリを吐くような作りになってしまっています。

  3. デバッグ用のシミュレーターどうすんねん
    CPU実験で作ったシミュレータはありますが、1命令1命令ずつ実行するシンプルなもので、割り込みとかありませんし仮想アドレス変換なんかもありません。

  4. というかそもそもCPUの機能には何がいるねん
    リングプロテクション?仮想アドレス?割り込み?そもそも何がいるのか不明瞭です。ここが決まらないと2のシミュレータも作れません。

  5. ハードウェア資源は足りるの?
    僕らのFPGA基盤に乗っているもので使えるメモリはだいたい4MBのSRAMだけ*2だし、通信手段はシリアルポートだけ*3です。SDカードやIDEディスクをくっつけてる余裕はなさそう。

  6. xv6、x86にべったり依存して書かれすぎ
    ブートの最初の方で4MBページ拡張使うわ、char 1byte, int 4byteであることを前提にハードコーディングするわ、スタックいじくりまくったトランポリンするわで移植性皆無です。まあxv6という名前がx86Unix "v6"から来てそうだし仕方ない。

まあこんな感じで不安点はいくらでもあったんですがX班OS移植プロジェクトは12月くらいにスタートしました。

ここからはだいたい時系列順でやったことを書いていこうかと思うのですが、かなり長いので先に動いてるOSの話を読みたい!みたいな方は3月の話以降を。

11月終わり~12月初頭

まず1個目の「コンパイラどうすんねん」が解決します。なんと「C89コンパイラフルスクラッチ」です。正直これでいくと思ってませんでした。インド人もびっくり。最初はid:wasabizgccllvmでもやるかーって話してた記憶があるんですが、うどんくん(id:kw_udon)が突然「Cコンパイラ書いてきた」と言って簡単なパーサとエミッタを積んだコンパイラを持ってきました。楽しそうだったので最速完動した3班由来のメンバーであるwasabizと@b-inaryが加わって、この3人がコンパイラ係としてフルスクラッチコンパイラを書き始めます。これが後のuccとなります。ucc開発についてはうどんくんの下の記事が詳しいです。

kw-udon.hatenablog.com

5個目の「ハードウェア資源は足りるの?」も解決します。このころはまだOSが決まっていなかったのですが、xv6が標準でシリアルで外部と通信し、しかもメモリは1MBも食わない、memfsも簡単に使えるのでディスクもいらないなどなど、我らがFPGA基盤にぴったりだということが判明し、xv6で行くことになります。コードがコンパクトなのもとてもgood。

12月中旬

OS係が動き始めます。また、12月8日に僕が作ったCPU実験本筋のCPUとシミュレーションのレイトレ結果の数ビットのdiffがようやくなくなり、6班(僕らの班)が完動します。原因は、ISE(VHDLから回路を合成してくれるすごいやつだよ)が吐くFPUの回路の挙動が、実際に書いたVHDLの挙動と食い違っていたせいでした。すごいやつって書いたけどあいつ絶対許さない。VHDL文のwhile文は合成できても使っちゃダメですよ絶対。班公式の仕事としての完動は3番目だったように思います。

ここらで6班メンバーがX班のOS係やらMMU係やらになります。OS係のメンバーが最終的なものと同じ、僕(@nullpo_head)、warelle@mhの3人に固まります。

12月終わり~1月中旬

4個目の大変ポイント、「というかそもそもCPUの機能には何がいるねん」が解決し始めます。

OS班のメンバーが固まったので、週1で輪読でxv6のソースコードリーディングを始めます。xv6にはMIT謹製の教科書があるんですが、結局これはあんまり読みませんでした。今からxv6を読みたいという人、OSの基礎的な概念を理解しているなら特に読む必要はなさそうです。このころ同時に僕はxv6をMIPSに移植し始めました。MIPS移植がなさそうだったので(ARMはある)。一週間くらいでスケジューラが動き始めるくらいまで移植が完了します。(外部周辺機器の割り込み周りの制御とユーザープログラムの起動はまだうまくいかない)ここで書き換えのためにMIPSについて、xv6の動作を理解するためにx86についてそれぞれ調べまくったので、割り込み周りの概念とMMUの概念を理解します。CPUに必要なものが見えてきます。

自作アーキテクチャシミュレータ上のxv6でも、色々コメントアウトして頑張った結果、ブートシークェンスの最初の文字

xv6...
cpu0: starting...

が表示されます。つまり、このころにはもうuccがxv6の大部分をコンパイルできるほど成長しています。uccすごい。

ここで大学のテストが挟まって、2月くらいまで一旦作業が鈍化します。

2月

テストが終わりました。OS係に本腰が入ります。全体のタスクがだいたい把握できたので4週間ほどでOS移植が完了する線表を引きました。

1日にはMIPS移植もPICあたりの初期化が完成し(マジ大変だった)、割り込みハンドラのひとまずの書き換えも完了してユーザープログラムが起動する直前まで移植されます。ここでの経験を基に自作CPUの割り込みの仕様と仮想アドレス変換の仕様を決めました。「というかそもそもCPUの機能には何がいるねん」が解決します。xv6は割り込みと仮想アドレス変換さえあれば動く!!周辺機器はタイマーとシリアルしかないので大がかりな割り込みコントローラはいらないし、デマンドページングがないのでリングプロテクションもいりません! なお、仮想アドレス変換はx86のページング部分と同じ方式にしました。一見CPUの実装が大変になるように見えますが、速さを犠牲にしてTLBが毎回ミスするような挙動にすれば実装が簡単なのではという話になっていました。(まあ最終的には優秀なコアができあがったので、TLBにあたるものもきちんと乗りました。) ちなみにOS移植が本格的に動き始めたので、MIPS移植は以降手がつけられなくなります。残念。

あとは怒涛の進捗が始まるので週区切りで記します。。。。

1週目

コメントアウトだらけのなんちゃってブートシークエンスではなく、mhにより初期化処理がきちんと移植され始めます。warelleがx86アセンブリを自作アーキテクチャのものに書き換えます。僕は、策定した仕様を基にCPU実験用のシンプルなシミュレータに割り込みシミュレーション機能をつけ、仮想アドレス変換の対応も完全にしました。シミュレータにOSを動かすのに十分な機能が付きます。またMakefileを自作アーキテクチャ用のものに書き換えました。全体として色々と開発の下地が整っていきました。

2週目

僕は大変ポイントその2、「リンカも割とリッチなやつが必要っぽい」に対応します。アセンブラ作者のb-inary先生に.setディレクティブの追加と、ファイルのアセンブル時の先頭アドレスを変更できる機能の追加をお願いします。xv6では主にカーネルの終端アドレスであるend, バイナリイメージであるfs.imgとinitcodeの先頭アドレスやサイズを得るためにldのbinary blobsを使うのですが、追加してもらった.setディレクティブさえあれば、
1. まずend, _binary_initcode_startなどには0xdeadbeefなどの適当なダミー値を.setで与えてアセンブル、ひとまずカーネルのサイズを得る
2. そのカーネルのサイズからそれぞれのシンボルの値を計算、.setディレクティブで無理やり追加
3. 計算しなおしたその値でもう一度アセンブル
4. できあがったカーネルにfs.imgやinitcodeをcatでくっつける
5. こうしてできあがったカーネルのヘッダを再計算してごにょごにょ書き換え、完成
という手順で同等のことを達成、原始的なリンカっぽいことができるようになります。ステキ。rubyスクリプトMakefileでこれらをやってやります。 先頭アドレスの変更は、もちろんカーネルのbaseアドレスやユーザープログラムのベースアドレスをそれぞれ0x80000000や0x0に返るためのものです。
warelleは割り込み周りを書き換えます。割り込み周りは理解が難しい、流れを把握するのが難しい、デバッグが難しいで難しい揃いです。僕がMIPSを移植したときにはgdbという神器があるのでまだ楽でしたが、独自シミュレータにはデバッグ機能など皆無だったのでデバッグがかなり難しかったのではないかと思います。(このときだったかどうかちょっと記憶が怪しいのですが)デバッグのしづらさに耐えかねたのかwarelleはシミュレータにディスアセンブラデバッグダンプ機能を付けてきました。これを皮切りにシミュレータのデバッグ機能はOSチームによりどんどん高機能化され、最終的には下図みたいな感じに成長します。

f:id:nullpo_head:20150324100129p:plain

このころmhはファイルシステム担当として、ファイルシステム周りを教科書を読みつつ理解していました。

3週目~

山あり谷ありで書き換えが進んだxv6、なんだかんだ言って動きません。特にuccの、charもintもともに32bitであるという仕様が響きました。実はCの仕様ではsizeof(char) <= sizeof(int)なことしか要求されてないので、これは仕様的には合法ですし僕らのアーキテクチャ上では実際問題ありませんでした。しかしxv6はx86を前提として書かれているので、sizeof(int) == 4なことを前提にポインタの値に定数をガンガン加算したりしてくるので、色々と不整合が起きてしまいます。これが生むバグが分かりづらい上に量も多かったので、結局uccの方にcharを8bitにしてくれるようお願いすることになります。このchar 32bit問題をuccチームに任せた後は、僕は最初のentry段階のページ初期化を書いたり割り込み周りがきちんと動くよう修正トライ&エラーを繰り返したりしました。要は大変ポイントその6、「xv6、x86にべったり依存して書かれすぎ」を地道につぶす作業です。

27,28日

slackを見返すとやたらこの日に進捗が生まれてます。多分悔いを残して2/29日に突入しないためだと思います。ucc班が爆速でchar 8bit対応を終わらせてくれた後なんやかんやで頑張り、ついに、初めてのユーザープログラムinitが起動します。そしてそのあと怒涛の進捗をだし、ついにシェルまで起動します。その後、MIPS移植ではたどり着かなったユーザープロセス周りの移植をどんどん進めました。
再現しづらいバグやら割り込み仕様の不備やらが発覚、潰しは発生、潰しは発生しますが、なんやかんやでなんとか乗り越えます。なんやかんやはなんやかんやです。

3月

1日、そしてxv6の移植が完了します。シミュレータ上でxv6が動きました・・・!

f:id:nullpo_head:20150324091208p:plain

線表上では3/4が完成目標だったので、結構余裕ができました。ちなみに最終発表の日数は3/17です。

余興かくあるべし

ここからはもともとお遊びだったOS移植のお遊びがさらに加速します。

まずmhの手によって4時間くらいでミニcursesが作られ、シミュレータ上でslが走ります。(遊びとなると進捗ってめっちゃ速くでるんだなあ・・・)

f:id:nullpo_head:20150324091346p:plain

warelleはなんだかマインスイーパーがしたくなりました。

f:id:nullpo_head:20150324091509p:plain

また、ここらへんで僕の趣味でディレクトリ構造をきれいにして、ヘッダファイル類をモダンなunixの構造っぽく変更、またuccチーム 謹製のlibcを移植しました。たとえば今まで

#include "types.h"
#include "stat.h"
#include "user.h"

char buf[512];

void
cat(int fd)
{
  int n;

  while((n = read(fd, buf, sizeof(buf))) > 0)
    write(1, buf, n);
  if(n < 0){
    printf(1, "cat: read error\n");
    exit();
  }
}

みたいな感じで独自仕様感がたっぷりだったcatは、

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

char buf[512];

void
cat(int fd)
{
  int n;

  while((n = read(fd, buf, sizeof(buf))) > 0)
  write(1, buf, n);
  if(n < 0){
    printf("cat: read error\n");
    exit(1);
  }
}

こうなりました。しかもwasabizの手によりX班コアGAIAも完成*4、シミュレータよりはるかに速く動くので遊びやすいし開発しやすい。満を持して、今回屈指の完成度を誇る2048が作られます。

f:id:nullpo_head:20150324091905p:plain

この2048、本当に完成度が高く、コア係のwasabizは実機上でずっとこの2048で遊んでました。
ちなみに2048では非ラインバッファリングな入力が使われていますが、xv6にはもともとこの機能はなく、read, writeに加えてioctlをdevswのアクションとして追加し、ICANONやechoを制御するtermios関連の機能を新たに追加しました。なのでこんなに完成度の高い2048が遊べるxv6はGAIA上のものだけです。
(なお、V6インスパイアなxv6としてはgtty, sttyシステムコールを追加するほうがそれっぽいとは思うんですが、xv6にはttyの概念がないのでこれを追加するのは変だなと思ったのと、ioctlがUnix V7からの登場と意外と古株だったのでioctlを採用しました)

さて、少しかっこいいお遊びとして、xv6-gaiaには小さなアセンブリが載っています。うどんくん製です。また、warelleがまさかの1日で作ってきたミニviも載っています。この二つを使うとできることが、

f:id:nullpo_head:20150324092118p:plain f:id:nullpo_head:20150324092125p:plain

こんな感じのFPGA上での動的なプログラミングです。CPU実験としてはかなりレベルが高い余興なんじゃないでしょうか。

最後の余興

CPU実験のもともとのお題は、「自作CPU上でレイトレを動かせ」でした。せっかくOSが動いたんですから、やることは決まっています。「自作CPU上"のOS上"でレイトレ」です。うどんくんとb-inaryさんが課題のmlプログラム、min-rtをCに移植してくれました。完成したのは最終発表当日ギリギリです。
が、ここで予期はしていたが目を背けていた問題が発生。完成したバイナリファイルがでかすぎ問題です。実はxv6のファイルシステム上では80kbくらいを越えるファイルが作れないのです。
まあでも予期はしていただけに解決策は用意していました。この完成したmin-rtをconsoleのようなデバイスファイルとして作ることです。consoleデバイスがreadアクションでユーザー入力を返すように、デバイスとして実装したmin-rtのreadアクションで_binary_min_rt_startから読み込んだ値を返せば、アドホックな分岐などのあまりトリッキーなことをせずに綺麗にリンクできます。ちょっとバグも埋め込んだりはしましたが、なんとか最終発表の1時間前には完成しました。

f:id:nullpo_head:20150324092158j:plain

多分どの代でも1回は冗談で言っていたであろう、「OSを作ってそのうえでレイトレ完動」が実現してしまいました。。
次はなんだろう、多分どの代でも一回は出るであろう冗談は「raytraceという1命令だけ作ってハードウェアレイトレする」ですかね。。割と対極にあるしCPUなんて作り飽きたぜ!って後輩がいれば挑戦してみるのはいいかもしれませんね。

書き残し、およびもっと技術的なことについて

GAIA版xv6には、上では書ききれてない変更がまだたくさんあります。たとえばb-inaryさんによってシェルのreadlineが強くなってたり、僕もpwdコマンド追加してたりmhによってhaltシステムコールが増えてたり。ともかくユーザーランドは割と魔改造されてるので気になる方はソースを直接見ていただければと思います。
そして上では割と軽いノリで「だいたい何をしたか」を記述するのに注力したので、OS移植の詳細は割と省いています。書ききれていない難しい箇所 or 興味深い箇所がまだまだたくさんあったりします。*5 GAIAやMIPSカーネル予約レジスタのk0, k1レジスタが必要な理由とか、興味深いことやハマりどころがまだいくつかあるので、いつかまとめられたらなーと思います。特にMIPS移植の際のMIPSに関する情報、ノウハウについてはどこかにまとめる必要性を感じています。。

感想

FPGA上へのOS移植は、やはり楽しかったです。OSの仕組みとx86MIPSについてかなり勉強になりました。CPU実験本筋でCPUも作ったしアセンブラも作ったしX班でOSも移植したしでかなり色々経験しました。 ただ振り返ってみればCPU実験にしてはこじんまりとしたことしかしなかったなという反省もあります。xv6移植に関しては、(もちろん簡単ではないことなのだけど)○○くらいのタスク量でやれそうだなという予想で始まって実際にその通りに達成して、「自分の想定内で想定通りの働きをしただけ」、という少し寂しい感想がないでもないです。実際作った線表から2日以上ずれたことなかったし。ここまで大きくなるのか!と驚かされたuccや、CPU実験であるにも関わらず割り込みもMMUも実装したGAIAコアのような、「本当にできるのか?」という感じの挑戦をしたかったかな、と少し思います。Linuxに初めから、とは言わずも、ucLinuxくらいには挑戦していればよかったかもしれない。
もっともX班の活動はこれで終わりではなく、今はうどんくんが「OS移植班全体の野望」という所のLinuxを動かすための算段を、wasabizと考えています。こっちは文句なしで難しいし実現できるか正直わからないので、頑張りたいなと思っている次第であります。
あと全然違う話ですがMIPS移植完成させねば。昨日久しぶりにMIPS版xv6を触り、TLB周りの処理を修正してinitcodeまで起動させました。初ユーザープログラムです。追試やら課題やらを回避しつつ4月初頭には完成させたいですね。

...

以上でCPU実験まとめ終わりです。後輩の方、興味を持った方、ぜひぜひCPUを作ったりOSを移植したりしてみてくださいませー

最後にX班のメンバーをまとめておきます。

...

*1:僕らの学科はほかにも心温まる話が溢れている。たとえば1回目の講義で緩くHaskellに入門したと思ったら次の週には初めて名前を聞くモナドを駆使した超ヘビーな課題を解かされ、3回目にはつい先日入門したはずのHaskellで言語処理系を書かされる

*2:本当は数百MBのDRAMがついてるのだが動かした人はいない。DRAM遅いし。

*3:USBもあるが制御が大変になる

*4:詳細がwasabiz.hatenablog.comにあります。

*5:たとえば割り込みのtrapasm.Sの先頭。割り込みが発生してトラップフレームをスタックに積む際、必ずsp以降ではなくsp - 4以降から格納します。最初はspから積んでいたのですがそれではごく稀にバグが出てしまっていました。これはspより先を使わない規約にしているつもりだったのに、callの際にどうしても1命令幅分だけspより先の領域を使うことがあり、そこで割り込みが発生した時にその領域をつぶしてしまっていたからというものでした。他にもGAIAではブートステージでx86のように4MBページ拡張を使って初期ページディレクトリーを確保することができないため、現在のpcが0x0000hogeでも0x080000hogeでも動くように作ったPICのようなCコードで初期ページディレクトリーを作ったり、少し面白い実装になっています。

モバイル環境では外部アダプタを使わない方がいい|Surface Pro2 あるいはモバイルノートwindows8にオススメなHyper-Vネットワーク構成

このブログSurfaceのことばっか書いてるなと思い始めたnullpo_headです。今回の話題は「Surface Pro またはwindows8が入ったモバイルノートにオススメなHyper-Vのネットワーク構成」です。まぁほとんどタイトルとおんなじですね。人生なんてそんなもんです。

 

今回の話の核は

1. Hyper-Vのネットワークスイッチは、普通外部アダプタを作成してそれを仮想マシンにつなげるよう解説されるが、これは回線が安定しているサーバー機を前提とした構成なのでモバイル環境とめっちゃ相性が悪い。無線回線が切り替わるたびにアダプタが死んだりする。

2. なので内部ネットワークアダプタを作って、それをWindowsのICS機能でインターネットにつないでお手軽ネットワーク構成を作りましょう

 

という2点です。あ、1に関連する現象として、移動してWifi環境が切り替わるときにネットワークアダプタがしばしば死んでしまうというものがありますので、今回の記事は「SurfaceやノートPCでHyper-Vをオンにするとネットワークアダプタが時々死んでしまう現象を解決する」とも言えます。こっちの方がこの問題に悩まされている人々がググるときに役に立つかもしれません。(あと、hyper-vの外部アダプタを作っている状態だとau wi-fiがつながらないとかいう問題もあったらしいですね)

以下詳細です。

 

まずHyper-Vの通常推奨されるネットワーク構成がモバイル環境には向かないという話を書くんですが、そのために一応Hyper-Vのネットワークについてさらっとふれておきます。

Hyper-Vは名前の通りハイパーバイザ型に分類される仮想化環境で、OSよりも上位(レイヤ的には下位)で動くというのはよく聞く話ですね。

f:id:nullpo_head:20131126015143p:plain

VirtualBoxなどのホストOS型はあくまでOSの上で動くアプリケーションですが、ハイパーバイザ型は一味違い、OSよりもハードウェア側に位置することでゲストOSの高速化を図ります。

それでネットワークの構成も、VMware playerやVirtual BoxのようなホストOS型とは少し違ってきます。
f:id:nullpo_head:20131126015147p:plain

ホストOS型の時はただのアプリケーションだったので、普通にアプリケーションとしてインターネットと通信していればよかったのですが、Hyper-VはホストOSよりも偉いために、逆にホストOSやゲストOSにネットワークアダプタを割り当ててあげることになります。Hyper-VはホストOSから物理NICを奪い取り、ホストOSとゲストOSのそれぞれに仮想的なアダプタを作って、そこへ実際のNICへ通信を流してあげるのです。

これがHyper-Vにおける基本的なネットワーク構成です。

 

で、ここからが本題です。この基本的な構成が実はモバイルPCには向かないという話です。この構成を作るために必要な、「ホストOSから物理NICの権限を奪い取り、ホストOSのアダプタを仮想アダプタにすげかえる」という処理、それなりに大変なんですね。

この構成を実際にHyper-Vで作る操作を行うためには、Hyper-Vマネージャより仮想スイッチを作成し、「外部ネットワークアダプタ」を作成します。この手順はいたるところで解説されている一般的な手順です。

が、「このとき、物理ネットワークインターフェイスに以前割り当てられていたTCP/IPのパラメータは、一時的にネットワーク接続が停止したあと、仮想ネット ワークに複製される。しかし、どういうわけかパラメータの複製に失敗することがある。そうすると、仮想ネットワークはDHCPクライアントとなり、以前の IPアドレスは失われてしまう。この結果、ネットワークにDHCPサーバがいなければIPアドレスは割り当てられず、いっさいの通信ができなくなるのだ。 データセンターに配置した物理サーバをリモート管理している場合は、管理もできなくなる。」

 とAscii.jpさんの連載記事の中の一記事、

「遠隔操作時に失敗すると悲惨なことに? Hyper-Vのインストールはネットワークに注意しよう!」(http://ascii.jp/elem/000/000/553/553016/)

でも紹介されているように、操作時に時々ネットワークの接続を失うことがあります。運悪くこの状態になってしまうと、適当にアダプタのオンとオフを切り替えたりして復旧させねばなりません。

Hyper-Vはもともとサーバーにインストールされることが前提とされた製品ですから、セットアップ時に一回遭遇するくらいなら大した問題ではありません。しかし運が悪いことに、モバイル環境ではWifiなどネットワーク環境が切り替わるたびにこの不幸な状態に似た症状に陥ることがあるっぽいのです。

実際僕は大学を行き来しているうちに、2日に一回はネットワークアダプタが死んでました。。。(ずばりこのセットアップ時のものと同じ現象なのかどうかは寡聞にして知りませんが)

 

そこでこのある意味大がかりなネットワーク構成はすぱっとあきらめ、モバイル環境に適切な構成に切り替えましょう。

 

1. 内部ネットワークアダプタを作る

f:id:nullpo_head:20131126022834p:plain

Hyper-Vマネージャを起動し、右側メニューにある仮想スイッチマネージャから図のように内部スイッチを選択し、作成します。そしてお目当ての仮想マシンのネットワークアダプタにこれを割り当てておきましょう。

この内部ネットワークアダプタというものは、仮想マシンとホストOSの間だけをつなぐもので、インターネットにはつながりません。ですのでHyper-Vが物理マシンのNICを横取りする必要がなく、先ほど説明したような大掛かりな構成が作られません。作られた接続は、コントロールパネルのネットワーク接続一覧にひょこっと現れます。これを作っただけでは仮想マシンはホストOSとネットワーク的に接続されただけで、まだインターネットにはつながっていないのでこれをインターネットにつなげます。

 

2. ネットワーク接続の共有を使って、作成した内部ネットワークアダプタをインターネットにつなぐ

コントロールパネルの「コントロール パネル\ネットワークとインターネット\ネットワーク接続」を開くと、元からあるWi-Fiなどと並んで先ほど作成した内部ネットワークアダプタが表示されていると思います。

f:id:nullpo_head:20131126023954p:plain

あとは図のようにWi-Fiなど普段使っている回線のプロパティを表示し、共有タブから接続の共有をオンにしましょう。これで仮想マシンもインターネットにつながるようになると思います。オテガル!

 

この構成ならばホストOSのネットワーク構成が変わらないので、ハイパーバイザ型の仮想化でもライトに使うことができると思います。多分。ちょっとネットワークいじらなきゃなってときでも共有を解除するだけですべて元通りです。

ちなみにこれはSurfaceを例にしてるために有線LANアダプタがないんですが、普段から有線も無線も使うよ!って人はブリッジ接続などを作ればいいと思います。なんにせよネットワーク環境が変わるたびにアダプタが死なないよう祈る必要はなくなるのでいい感じなんじゃないでしょうか。また、仮想マシンを外部に公開したいときは、ポートの開放も設定から普通にできますので特に問題ないと思われます。

 

以上で今回の話は終わりです。モバイルノートPCでもHyper-Vをがんがん動かしましょう!!

 

そういえば:買ってまだ数か月のSurface Pro初代もメモリ8gb欲しいぞ~~~~~~~~~~(;´Д`)

 

 

参考文献:

Hyper-Vのネットワークを理解する -外部ネットワーク- | WindowsServer管理者への道

http://ebi.dyndns.biz/windowsadmin/2013/04/18/hyper-v%E3%81%AE%E3%83%8D%E3%83%83%E3%83%88%E3%83%AF%E3%83%BC%E3%82%AF%E3%82%92%E7%90%86%E8%A7%A3%E3%81%99%E3%82%8B-%E5%A4%96%E9%83%A8%E3%83%8D%E3%83%83%E3%83%88%E3%83%AF%E3%83%BC%E3%82%AF/

・ASCII.jp:Hyper-Vのインストールはネットワークに注意しよう! (1/2)|Windows Serverで学ぶサーバOS入門

http://ascii.jp/elem/000/000/553/553016/

Hyper-V - Wikipedia

http://ja.wikipedia.org/wiki/Hyper-V

Surface Proで(あるいはもしかするとwin8のモバイルノートPCでも)休止状態から復帰できなくなったことへの応急処置

ちょっと前から自分のSurface Pro(初代)が長時間スリープさせた後の復帰で、復帰前の状態を復元できずにただの再起動となってしまうことが起きてました。最初はちょくちょくだったのですがだんだんと頻度が上がっていき、最近はもう100%です。めっちゃ困ります。

結論から言うとこれはwindows8.1にアップデートしてから生じている現象(ログの日付によれば)のようで、多分winのバグです、そのうち治るんじゃないでしょうか。でも不便なまま過ごすわけにもいかないので、とりあえずの応急処置として

・コンパネの「コントロール パネル\ハードウェアとサウンド\電源オプション\システム設定」から行けるところで高速スタートアップを無効に設定する

ことでこの現象は抑えられます。副作用として、まぁ当たり前ですけど起動が前より若干遅く感じられます。あと休止状態からの復帰も若干遅くなります(デフォルトだとスリープのまま2時間たつと休止状態に移行しているようです)

早く改善されるといいですね。

 

以下問題の切り分けの経緯について

これの解決にあたってwindowsのエラーを扱う方法を少し身に着けたのでその経緯をば。

f:id:nullpo_head:20131124023015p:plainまずwindowsのログの見方です。winではログはイベントビューアというものから見れ、win8系ならwin+xキーでメニューを出せば、その中にイベントビューアというものがもうあるとおもいます。これをクリックすればさまざまなログが見れるイベントビューアなるものが起動します。GUIなので使い方に困ることは特にないでしょう。

そして、これのwindowsログの中に「システム」というものがあります。ここに今回欲しいログが吐かれるわけです。

 

 あとはこのエラーの中からめぼしいものを探せば

「システムは正常にシャットダウンする前に再起動しました。このエラーは、システムの応答の停止、クラッシュ、または予期しない電源の遮断により発生する可能性があります。」というログと、「Windows はエラー ステータス 0xC0000411 の休止状態から再開できませんでした。」というログが得られます。あとはこれを手がかりにしてググればなんとかなりますね。

まとめると、「イベントビューアでログを見て、ググる。以上」という感じです。いえい。

 

 

参考文献

1.Cannot resume from hibernate on Surface Pro 2

同じエラーで苦しむ人々。ただし僕と違ってSurface Pro2です。おのれMSめ、日本の初代発売から3ヵ月くらいで2を投下しおって。。。PowerCoverでたらくれ。。。

http://social.technet.microsoft.com/Forums/windows/en-US/bb19d1bb-2dbb-4748-8d85-e5be49689953/cannot-resume-from-hibernate-on-surface-pro-2?forum=w8itprogeneral

2.Windows 8 Pro (64bit) Failing to resume from Sleep (/Hibernate?) - Error ID 41 (Kernel-Power)

こちらはSuface Proではない一般のwindowsPCでの同様の現象の報告です。タイトルにあるいは~を入れたのはこれによります。Surface以外でも起きているかもしれませんので。今回の応急処置はここで見つけたもので、自分で試したところ有効でしたので紹介しました。

http://social.technet.microsoft.com/Forums/de-DE/4828857c-1f53-45bc-9d48-5ca8b34b416a/windows-8-pro-64bit-failing-to-resume-from-sleep-hibernate-error-id-41-kernelpower

 

Windows 8.1 or server 2012 R2 からLinuxクライアントもHyper-Vの動的メモリでhot add memoryを使えるようになった

 

windows8.1にアップデートしたら動的メモリが完璧に動くようになったぞ!!!!!!!

 

f:id:nullpo_head:20131018050751p:plain

まぁ言いたいことは記事タイトルの一行ですべて終わりなんですけど、あまりにも嬉しくて書きました。というかこの記事のためにこのブログを作った。

 

そこかしこで3.8くらいからLinuxHyper-Vの動的メモリに対応していて需要に合わせてメモリを増減できるみたいな記述がされてますが、実はそんなことはなくwindows8およびそれ以前までHyper-VLinuxクライアントの動的メモリ対応が不完全でした。使われていないメモリの縮小には対応していましたが、メモリ要求が増えた時に起動メモリ以上のメモリへ伸長することができなかったんです。しかし8.1に乗っているHyper-Vからはこれが可能になります。上スクショの「割り当てられたメモリ」が「起動メモリ」より多いことに注目。

なおこの機能を使うにはLinux側で適切なフラグが必要なので、カーネルのバージョンを確認しておきましょう。

 

僕は今、

「・Hyper-V上でarch linuxを動かし

・そのarch上ではGUIは一切動かさず待機

・windowsでCygwin/Xを使ってarch上のlxterminalとかを持ってくる

・その他双方向ファイル共有とかでwindowsとlinuxの融合を目指す」

という構成にしていまして、これは「確かに仮想マシンは動いてるけどGnomeみたいなデスクトップ環境も何も動いてないので100MBくらいしか余計なメモリを消費しない」という利点があります。あとはLinux上で動かすアプリケーション分だけのメモリが消費されるだけです。(またWindows8による快適なタッチ操作が行えます。SurfaceいいよSurface。)ところが、固定メモリ消費だと結局あらかじめメモリを割り当てておく必要があったのでこのメリットが半減だったんですよ。。だから今回のhot-add-memoryはめっちゃうれしいわけです。これで普段の生活がより快適になりそうです!!

 

 

参考文献

・New Hyper-V features in Windows Server 2012 R2

http://www.tudy.ro/2013/06/04/new-hyper-v-features-in-windows-server-2012-r2/

Windows 8 Hyper-Vで自宅鯖

http://engawa.2ch.net/test/read.cgi/mysv/1352818048/ (38 - 46)