2024.10.10
将来は卵1パックの価格が2倍に? 多くの日本人が知らない世界の新潮流、「動物福祉」とは
リンクをコピー
記事をブックマーク
金津穂氏(以下、金津):次にMMUについて見ていきます。Armの場合、TTBR(Translate Table Base Register)というページテーブルを保持するレジスタが2つありまして、これがIntel 64におけるCR3レジスタとほぼ同等になっています。ここにページテーブルを登録して、実際にページウォークを実行します。
このTTBRですね。ここ「x」って書いてあるんですけど、TTBRはTTBR0とTTBR1があって、それもそれぞれException Levelごとに存在します。
例えばTTBR0はアドレス0番から256TB目のアドレスまでの48-bitの仮想アドレス空間を保持、TTBR1のほうは0xFFFF0000_00000000から0xFFFF_FFFFFFFFまでの256TBを保持する。そういったかたちで仮想アドレスを分離して、それぞれにユーザーアプリケーションとカーネルを置くといったかたちで、カーネル用のページテーブルとユーザー用のページテーブルを別々に登録することができます。ただし、HypervisorとSecure MonitorのEL2とEL3にはTTBR0しか存在しません。
MMUの設定はTCRというレジスタで実行します。このTCRについて見ていきます。TCRはこの図のとおり64-bitの長さを持っているレジスタになっています。まず1つ目、ここの0番目から5番目の6-bitのT0SZ(T0サイズ)、16-bit目から21-bit目のT1SZ(T1サイズ)を見てください。ここ6-bitでテーブルのページの最初のレベルとページの粒度などを指定できます。ページの粒度などを指定すると何が起きるかは、また後ほど説明します。
ほかにも、物理アドレス、バーチャルアドレスは最大48-bitなんですけど、これは単に48-bitに限ることなく、いくつかの出力サイズを指定することができまして、最小で32-bitの物理アドレスを前提にしたものがIPA sizeで指定できます。
また、TG0、TG1というのがあるんですけど、ここの2-bitでページの変換の粒度を指定することができます。
ページの変換の粒度が指定できるとはどういうことかといいますと、Intel同様、Armv8は4-Levelのページウォークができるのですが、ここの4-Levelのページテーブルの中でも粒度をこのように、L1PTが1GBのブロック、L2PTが2MBのブロック、L3のPTが4KBのブロックを指定するようにすると、オフセットアドレスは12-bitになりまして、この場合はIntelと同じ4KBページになります。
ただし、同じ4段階でも最初のページテーブルのエントリすべてがL2のページテーブルを指すようにして、L2のPTは32MBブロック、L3PTは16KBのブロック指定にすると、オフセットアドレスが14-bitに変更されて、この場合ページがなんと4段階ですが16KBページに変わります。
このようにIntelと異なって、ページの段数を減らさなくても、いくつか、4KB、16KB、また64KBのようなページの粒度が変更するといったことが特徴の1つになります。
ではページテーブルに登録するエントリについて見ていきます。ページテーブルに登録できるエントリは、まず次のレベルのページテーブルを指定するテーブルディスクリプタ。これは段数0番目から2番目に指定できます。末尾のbitは「11」で、真ん中にnext-level table addrを登録しています。
また、ブロックエントリが1から2番目とLevel3、最後のページテーブルの段数で、それぞれ末尾のbitが「01」「11」と変えられています。また、ページフォールトを起こすためのinvalid entryは末尾が「0」のときになっています。
ここのブロックエントリなんですけど、このブロックエントリにはupper attr(attribute)とlower attr(attribute)という2つメモリ属性を設定するビットがありまして、ここにそれぞれUnprivileged eXecute Never、Privileged eXecute Neverなど、あるいはlower attrにはAccess Flag(AF)、Shareable Attribute(SH)、Access Permission(AP)、Secure bit(NS)などなど、ページの共有の許可とか実行の許可とか、そういったもののパーミッションについてのビットを立てることができます。
また、一番末尾。この2から4ビット目のindex(idx)というところには、MAIRというレジスタに対するインデックスを指定できます。このレジスタは8-bitのエントリを8つ持った8×8の合計64-bitのレジスタなんですけど、このテーブルの中に登録されているメモリタイプを使うことによって、特定のエントリがキャッシュ可能かどうかということが細かく指定できます。
先ほどのここのページのところにある、TCRのMMU設定レジスタの中にあるこのORGNとIRGN、この2つのビットについて見ていきます。ここのビットの設定の仕方によって、変換テーブルをキャッシュ可能なメモリに載せるかどうかといった変換したときの状態、TLBとかのキャッシュの状態を設定することができます。それぞれ「non-cacheable」「write-back write-allocate」「write-through」「write-back。ただしwrite-allocateができない」といった、4つの状態を指定することが可能になっています。
最後にMMUのコード例を見ていきます。これはとても簡単なコードです。MSRという特殊な権限レジスタを設定するコードで、X0に例えばページテーブルのポインタを設定しておきますと、このページテーブルポインタをTTBR0に書き込む。また、TTBR1に書き込む。最後にX2というところにTCRのレジスタの設定を書いておきまして、これをTCRに書き込む。こうすることでMMUの設定が完了します。ただし、そのあとに命令同期バリア、Instruction Synchronization Barrier(ISB)という命令で一度同期しないと、正しく書き込みが終わらない可能性があります。
そのあと一度System Control Register(SCTLR)、特殊なシステム制御レジスタ、これをいっぺんX0レジスタに書き出しまして、これの最下位ビットを立ててまた書き戻すことによって、MMUが有効化します。MMUを有効化したあともISBを発行しなければなりません。
ということで、ここまでまとめてみます。AArch64では昔のAArch32と違ってモードがすっきりしています。かつてのArmはAcorn社の時代の遺産のために複雑なモードを持っていて、ほかのOSやPCでは使いづらいものでした。これがAArch64ではException Levelに統合されまして、とてもわかりやすくなっています。
またIntelに比べて、例外のときの退避用レジスタ、ページテーブルを保持するポインタなど便利なレジスタがたくさんあるので、わりと今から既存のOSを実装するのと違って、フルスクラッチで実装する場合にはIntelよりも楽に素直に実装できるんじゃないかなという所感です。
では、ちょっとした落ち穂拾いですけど、AArch64に対して、OSの実装おける周辺機器の情報取得などについてザッと話しておきます。
AArch64について周辺機器の情報を取るためには、現在、2つ方法があります。まずデバイスツリーによる方法。もう1つがACPIによる情報です。それぞれ見ていきます。
まずデバイスツリーです。大昔のMacとかIBMとかそこらへんで共通して作成されたファームウェアである「Open Firmware」というポシャった仕組みがあるんですけど、これは、そのOpen Firmwareに由来しています。
dtsというところにC言語の構造体みたいな書き方で、デバイスの接続の構造とかバスの構造とかを記述します。これをdtcというコンパイラでblobにしてしまって、これをLinuxの起動時にオプションで渡して読み込んでしまうとカーネルがデバイスの構造を読み取ることができるため、適切なドライバを読み取ることができます。
これは基本的に組み込みでよく使われていて、LinuxのソースツリーやArmに限らず、MIPS、PowerPCなど向けにも含めて、わんさとdtsが入っています。
次にACPIです。これはみなさんが使っているIntel MISC PCでよく使われています。現在UEFIコンソーシアムというところで規格化されていまして、UEFIのシステムは基本的には標準搭載になっています。ACPI自体はUEFIの中で規格されているのと、UEFI自体も、AArch64向けリファレンス実装もありますし、Intel向けのリファレンス実装もあります。これは電源管理にも利用されていまして、サスペンドだとかリブートだとか、そういったときにもACPIを読みます。
ACPIでは、AMLと呼ばれる言語で記述したマシン構成などをファームウェアにストアしておくと、OSはインタプリタを使ってこのAMLを呼び出すことによって電源管理をしたりだとかデバイス構成を読み取るといったことができます。
このインタプリタ、いちから実装するのは面倒くさいんですけど、Intelが標準実装を持っていまして、これは誰でも使えます。ACPI-CAというんですけど、これを使えば自作OSでもだいたいうまくいくはずです。けれども例えばOpenBSDは「ACPI-CAはバグっている」と主張して、自力でインタプリタ実装をしたりとかしています。
次にブートについて見ていきます。具体的にはブートシーケンスではなく、Armのブートに使われるファームウェアなどについて見ていこうと思います。IntelではBIOSかUEFI BIOSが最初のブートコードとして実行されますが、Armではどのような実装が存在するのでしょうか?
まず1番に挙げられるのはU-Bootです。これは多くの組み込みのボード、SoCで利用されていまして、ご家庭のBUFFALOとかのルーターでは基本的にU-Bootが使われています。これは簡単なプロンプトを内蔵していてスクリプトを埋め込むなどもできるので、かなり高度なことができるようになっています。
例えばTFTPを通じてネットワークブートしたり、あとはブートのときにデバイス上のディップスイッチなどの状態を読み取って、それによって起動スイッチを替えるなど、そういったことも可能になっています。
そして先ほど挙げたUEFI。これも最近Armで使えるようになっています。UEFIはもともと2000年頃、Itanium64というIntelのポシャった64-bit ISA向けでしたが、現在ではさまざまな標準実装が存在しており、コンソーシアムにも幅広い会社、各種業界団体が所属していますので、今後より広く使われていくんじゃないかなと思います。
これはアーキテクチャに非依存でProtocolと呼ばれる構造体のやりとりによってAPIを呼び出すといった構造が特徴です。基本的には実装というよりも、このProtocolを用いたファームウェアとプログラムのやりとりのインターフェースを規定しています。このProtocol自体もUEFI Driverを自分で実装すれば拡張することが可能です。
もうすでにサーバ向け・デスクトップ向け、そういったもののArm SoCでUEFI実装が存在しています。NDAの問題で、まだApple Siliconは情報が出ていませんけど、もしかしたらApple EFIの拡張でセキュアブートなども実装するかもしれません。もしApple SiliconがEFIなどを使っているとしたら、今後ArmでもUEFIを使った何かコードを書く機会も増えるんじゃないでしょうか。(追記:Apple Silicon は残念ながら EFI ではなく Apple が iOS などで用いている iBoot を利用しているようです。)
また、有名なオープンソースファームウェアとしてcorebootというものがあります。corebootはペイロードとしてほかのファームウェア実装を2段目に読み込むことが特徴になっていまして、U-Boot、UEFIのペイロードも存在します。
では最後に、すでにAArch64で動作するOSについてまとめていこうと思います。だいたいおおよそみなさん知っているとは思うんですけど、LinuxだったりFreeBSD、NetBSD、OpenBSD、DragonFlyBSDといった各種BSD系はだいたいAArch64に対応してきています。
ただしtnishinagaさんも指摘したとおり、Intel PCと異なって、製造・アーキテクチャそれぞれがいろいろ違うので、Arm ISAに対応しているからといって必ずすべてボード・SoCで実装されていて動くとは限りません。ただ、基本的なコアのプロセッサーのアーキテクチャ部分はだいたい対応しているということです。
ほかにいくつかマイナーかつメジャーっぽいOSを挙げてみると、例えばL4マイクロカーネル。本家実装L4Ka::Pistachioはまだ対応してないんですけど、seL4を言われる形式証明をつけたL4マイクロカーネルはなんとAArch64に対応しています。Raspberry Pi3だと動かせるみたいで、公式にもRaspberry Pi3ドキュメントが存在しているので、ぜひみなさん使ってみてください。
それからOSv unikernelというKernel/VM畑の人がいくつか遊んでいた unikernelが存在しているんですけど、これなぜか華為の人たちがAArch64の実装がまだiPhoneしかなかった頃にめちゃくちゃコミットしていて、現在AArch64の実装がなんとAmazon Lambdaで使われているFirecracker、これで動くそうです。激アツですね。
unikernel自体はかなり実装が小さくて、またOSv自体がC++のかなり最近のバージョン使ってけっこうスリムな実装になっていて読みやすいと思うので、ぜひみなさん一度OSv unikernelを試してみてください。コンパイルもLinux上であれば、スクリプトを一発叩くだけで自動でやってくれます。
AArch64には限りませんけど、ほかに、Armで動作するOSも紹介します。基本的にはAArch64、商用に使われるLinuxなどは対応しているんですけど、マイナー、ドマイナーなOSとかは、わりと無視されがちです。例えばRust実装で有名なRedox microkernelはマイナーの中でもかなりメジャーなほうなんですけれども、x64しか対応していません。
一方、かつてApple Macに実装されかけたHaikuOSというBeOSの後継。これはAArch64になぜか対応しています。
ほかには、Windows NTを完全互換することを目指しているReactOSというかなり尖ったOSがあるんですけど、ReactOSはなにをトチ狂ったのかArm実装が存在しています。これを使うともしかしたらまだArm実装できていないようなWindowsのアプリケーションもうまく動く可能性もあります。
ただし、AArch64実装は存在しません。まだARMv7以前の問題になっています。なので、今からHaikuOSじゃなくてReactOSにAArch64実装をコミットするのはかなりおもしろいチャレンジじゃないかなと思います。学生さんとか来年「Google Summer of Code」とかで実装すると、きっといい感じに楽しいんじゃないでしょうか。
司会者:ありがとうございました。TwitterとかYouTube Liveのコメントを見ていて、とくにMMU周り難しくてついていけないみたいな声がいくつかあったんですけど、ここらへんはあれですよね。金津さん、OSを実際に触ったことがないとけっこう難しいから、「へえ」ってわかればいいぐらいですね。きっと経験ないと。
金津:そうですね。一度Intelのページウォークとかのところ、レジスタの設定とかをひととおりやったことがある人だと多少わかるんじゃないかな。あと、Intel64よりも、CR3以外のもいくつかレジスタがあって、便利ということがわかるんじゃないかなと思うんですけど、ちょっと自分の資料の作り方も悪くて、なかなかわかりづらかったかなと思います。
司会者:いやいや、とてもわかりやすかったです。
金津:ただ、あれですよ、基本的にArmのマニュアルはけっこうシンプルで、割り込みも20ページあるPDFだったりとか、アドレス変換についても「Address Translation」というタイトルで10数ページか20ページぐらいのPDFでサクッとまとまっているので、これじっくり読むのでけっこう勉強になるんじゃないかなと思うので、このPDFを読むときに私の資料を参考にしつつ読んでいただければと思います。
司会者:ありがとうございます。
金津:ありがとうございました。
2024.11.13
週3日働いて年収2,000万稼ぐ元印刷屋のおじさん 好きなことだけして楽に稼ぐ3つのパターン
2024.11.11
自分の「本質的な才能」が見つかる一番簡単な質問 他者から「すごい」と思われても意外と気づかないのが才能
2024.11.13
“退職者が出た時の会社の対応”を従業員は見ている 離職防止策の前に見つめ直したい、部下との向き合い方
2024.11.12
自分の人生にプラスに働く「イライラ」は才能 自分の強みや才能につながる“良いイライラ”を見分けるポイント
2023.03.21
民間宇宙開発で高まる「飛行機とロケットの衝突」の危機...どうやって回避する?
2024.11.11
気づいたら借金、倒産して身ぐるみを剥がされる経営者 起業に「立派な動機」を求められる恐ろしさ
2024.11.11
「退職代行」を使われた管理職の本音と葛藤 メディアで話題、利用者が右肩上がり…企業が置かれている現状とは
2024.11.18
20名の会社でGoogleの採用を真似するのはもったいない 人手不足の時代における「脱能力主義」のヒント
2024.11.12
先週まで元気だったのに、突然辞める「びっくり退職」 退職代行サービスの影響も?上司と部下の“すれ違い”が起きる原因
2024.11.14
よってたかってハイリスクのビジネスモデルに仕立て上げるステークホルダー 「社会的理由」が求められる時代の起業戦略