記事一覧ページへ移動

セキュキャン2022通過したので応募課題を晒す

2023-08-15
2022-06-07

やった~~!!!

ということで、セキュキャン2022、Y4「RISC-V CPU自作ゼミ」に参加させていただきます。めちゃくちゃ嬉しいです。最初に届いたメールは選考結果が発表されたというお知らせだったので、そこからサイトに飛んで、PDFを開いて(どこに結果が書いてあるのかしばらくわからなかった)、自分のIDで検索をかけてヒットした時はそれはもうびっくりしました。n度見しました。

せっかくなので、セキュキャン応募までのざっくりした過程と、応募課題をさらりと晒してみようと思います。

応募のきっかけ

セキュキャンという単語自体は去年とかその辺も聞いてた気がします。おぼえてないですが。ただ、名前の通りセキュリティを専攻する人向けかな~と思って特に何も思わず流し見していました。

そして今年、Cコンパイラゼミの @hsjoihs さんからの助言もあり、セキュリティ限定でないことを知ったので、参加しようと思ったわけです。

なんか書いて思ってたんですけど、このセクションいらなかったかもしれないですね(薄すぎ)

応募はリバースエンジニアリングゼミ→RISC-V CPU自作ゼミ→OS自作ゼミの順です。形式上はこの希望順ですが、実質ぜんぶ第一希望みたいな感じです。Cコンパイラゼミも含めた4択で無限に悩んでいました。

応募までの過程

過程と言うかスケジュールです。エントリー締め切りは05/16 23:59で、課題回答の締め切りは05/23 23:59でした。で、実際に提出した時間はどうだったかというと、エントリーが05/15 17:15あたり、課題回答は曖昧ですが締め切り1時間前くらいに提出したと思います。

前述しましたが、エントリー直前までずっと希望ゼミを悩んでいたので遅くなりました。この影響で課題回答も遅くなってしまいました。嘘です。おおよそ絞ってからもずっと遊んでました。カスです。このせいで、全く触れたこともないSystem Verilog HDLの課題を3日で書く羽目になりました。時間のゆとりはいくらあってもありすぎではないと思います。というのを応募前の自分に言っても意味ないような気がしますが・・・。

まず先に終わらせたのはOS自作ゼミです。OS自作はもともと興味があったので、内容を考えるのにそこまで時間はかかりませんでした。といっても、リングバッファの実装をちまちまいじっていたらそこそこの時間になってしまいました。

次に終わらせたのはリバースエンジニアリングゼミです。こちらは触れたことがない用語の解説をしなければいけなかったのでちょっと大変でした。データシート読み取りも、ただ英語読むだけではわからない部分もちらほらあったので苦戦しました。

最後に終わらせたのはCPU自作ゼミです。。前述の通り、System Verilog HDLを全く知らない状態からなんとか完成させました。HDL自体の構文はもちろん、付属していた信号例の読み方もなんにもわからなくて相当苦労しました。

そもそも問題文に使われていた単語が全く分かりませんでした。アサートもデアサートもノリで理解しました。それに、HDLだけでFIFOを作ることができるというのも知りませんでした。プログラミング言語でいう変数みたいなもので管理できるとは知らず、FIFOを作るならデータを格納するための部品?みたいなのを設計しなきゃいけないのかな~と思ってました。

ただ、この課題は書いててとても楽しかったです。受からなくてもこの課題が出来ただけで有意義だなあと思っていました。こんな苦戦具合だったので、通過したのが驚きです。

課題

受かってない課題公開したところでかな~ともちょっと思いましたが、まあ公開しときます。

プログラムを提出する必要がある課題があるので、これらはGistsに載せておきます。

リバースエンジニアリングゼミ

単語解説では勝てないと思うので、応募のきっかけに注力しました。書いてある通り、応募のモチベーションはBrainuxです。リバースエンジニアリング、めちゃくちゃ面白そうなので、何かしらの機会に学べたらな~と思ってたのですが、今回は叶わなかったようです。

問1

以下の技術用語について解説してください。またどのようなところで使われているかも述べてください。わからない場合は調べて、自分なりに解釈した結果を述べてください。

オームの法則:電圧・電流・抵抗の関係を表す法則。電流と抵抗の積が電圧の値と一致する。

UART:Universal Asynchronous Receiver / Transmitter。デバイス間の通信に用いられるプロトコル。通信開始時にスタートビット、通信終了時にストップビットと呼ばれるデータを送信するという非同期的(調歩同期式と呼ばれる)な通信を行う。また、誤り検出にパリティビットが含まれることもある。

SPI (Serial Peripheral Interface):クロック同期なシリアルインターフェースの一種。ICチップ等のデバイス間での通信に用いられる。パラレルインターフェースによる通信より低速だが、回路・端子・配線などが少なく、簡単かつ低コストで実装できるという特徴がある。

SDR (ソフトウェア無線):Software-Defined Radio。今までハードウェアとして実装されていた信号処理コンポーネントをソフトウェアとして実装することにより、ハードウェアに変更を加えずに無線通信方式を切り替えることが出来る通信技術。

問2

マイコンのファームウェアをデバッグするためには、どういう方法がありますか?

  • ソースコードが公開されていたら、読む
  • オシロスコープなどを用いて信号を観察
  • シリアル通信等を通してログを出力する

(今気づいたんですけど、これ文字列長が揃ってますね)

問3

電気には直流と交流があります。同じ電圧のとき、どちらが感電したときに危険だと思いますか?その理由と一緒に説明して下さい。また感電はどんな工夫をすれば防げるでしょうか、思いつく限り多く挙げてください。

直感では向きが変わる交流のほうが危険だと思ったが、交流は正弦波であり、平均値でいえばそんなに高く無いのでは?

ここで検索し、Quoraにおける回答から このサイト を得る。「直流と交流とでは、感電の感触が異なる。直流は筋肉がギュッと硬直するのに対し、交流はザワザワと心臓の筋肉が震えるように痙攣する」「交流による感電の危険度は、直流に比べると4~6倍程度高く、50mAの交流電流に感電した場合は死亡する恐れがある。50mAの直流電流に感電した場合は、人体に苦痛を与えるが、感電個所から離れられなくなる程ではない」と書かれているから、「交流のほうが危険」というのが結論らしい。

感電を防ぐ方法:

  • 絶縁体を身につける
  • 触れると感電する箇所を露出させないようにする
  • 必要ない時に電源を落とす
  • 皮膚が濡れているときに作業を行わない(濡れていると抵抗が下がるため)

問4

このデータシートから、以下の情報を読み取ってください。 データシートURL: https://datasheets.raspberrypi.com/rp2040/rp2040-datasheet.pdf rp2040-product-brief.pdf (raspberrypi.com)

「GPIOに5.0Vを入力しようと思います。この機器は正常に動作しますか?」:5.2.3.4 IO Electrical Characteristics (P638) を読む限り、Input Voltage Highのmaximumが5Vを超えない(最大はIOVDD=3.3Vの時、MaximumはIOVDD+0.3だから3.6Vっぽい)ので正常に動作しない

「この機器でSPI通信は使用できますか?」:Chapter 1. Introduction (P9) においてKey Featuresとして2 SPI controllersが挙がっていること、4.4 SPI (P527) に “RP2040 has two identical SPI controllers”と書いてあること等から、使用できる

「IOVDDとDVDDの違いを説明してください」:IOVDD→2.9.1 Digital IO Supply (P179) より、”チップのデジタル入出力に供給される電源。公称電圧1.8~3.3V。必要となる信号レベルに応じてデジタルIOの外部信号レベルを設定する必要がある。全てのデジタルIOは共通の電源およびシグナルレベルで動作する”。DVDD→2.9.2 Digital Core Supply (DVDD) (P180) より、”コアデジタルロジックに供給される電源。公称電圧1.1V。専用のオンチップ電圧レギュレーターが備わっており、IOVDDやその他の1.8~3.3V電源からDVDDを生成することが出来る。オンチップレギュレーターとDVDD供給ピンとの間の接続はオフチップで、必要に応じてDVDDをオフチップ電源から供給することが出来る” 。

「SWDポートを使うと何ができますか?」:2.3.4 Debug (P61) より、SRAMもしくは外部フラッシュメモリへのファームウェアロード、実行/停止・ステップ・ブレークポイント設定・その他標準的なARMのデバッグ機能などによるプロセッサ実行の制御、プロセッサのアーキテクチャ的状態へのアクセス、システムバス経由でメモリ・メモリマップドIOへのアクセス等を行うことが出来る

「GPIO 1ポートから標準で何mA出力できますか?またGPIO合計で最大何mAまでの電流を出力できますか?(ただしQSPIポートで使用する電流は考慮しないものとします)」:Chapter 1. Introduction (P9) に「30 GPIO pins, 4 of which can be used as analogue inputs」 つまり1本あたりの電流 _ 30が後者の答えとなる  5.2.2.2 Pin List (P636) より、GPIO0-25はDigital IO (FT) , GPIO26-29はDigital IO / Analogue また、5.2.2.1 Pin Types (P635) より、Digital IO (FT) も Digital IO / Analogue もDefault Drive Strengthが4mA よって、1ポートあたり4mA、GPIO合計で4 _ 30 = 120mA

問5

家電もしくはIoT デバイスを分解したことはありますか。ある場合は分解した機器と、分解しようと思った思いを書いてください。(「ワクワクしたから」等が主となる理由でも問題ありません)

何を分解したかは詳しく覚えていませんが、「基盤を見たい」というモチベーションだけで、家にあったおもちゃ等を分解していました。内部構造について理解できたことはなかったです。

問6

機器内部の eeprom の吸い出しや、ファームウェアアップデータの解析等を行った経験はありますか。ある場合はどのような事を行ったか教えてください。(未経験でも問題ありません)

ありませんが、eepromの吸い出しはやってみたいことの一つです。

問7

何か他にアピールしたいことがあれば、自由に書いてください。書いておきたいことはなんでも書いてください。

そもそもこのコースに応募しようとしたきっかけとして、電子辞書でLinuxをブートさせるBrainuxというプロジェクトの存在があります。

限られたハードウェア等の基礎情報から、オシロスコープやロジックアナライザを活用してバイナリをブートさせるという一連の作業は、自分が持っている低レイヤに対する興味の代名詞のようなもので、どちらの記事もワクワクしながら読んでいました。個人でも自作OSに触れたり、アセンブリでHello Worldしてみたりと低レイヤなことはしていますが、それ以上にこのBrainuxのような、「未知のハードウェアを理解し、制御する」という行為に強い憧れを感じています。

また、私は高専の制御情報工学科に所属しています。部活動としてロボット研究部にも参加しています。どちらもマイコン等を用いたロボットの制御などを行っていますが、その過程でPWM信号やをオシロスコープで覗いたりすることに大きな喜びを感じています。なぜ好きなのか?というと、具体的な言葉で説明しづらいですが、。

以上のように、低レイヤに対する強い興味があり、色々な機械の構造を知るために必要な知識が欲しい!というのが、応募の理由となります。

講義を通して得た知識を使って、個人的にリバースエンジニアリングをしてみたいと思っています。ファミリーコンピュータのようなレトロゲーム機の構造を見てみたいと思っています。ファミコンは技術的制約が非常に多かったため、思い通りの表現をするために技術者が試行錯誤を繰り返し、様々な名作が生み出されました。

個人的に好きなエピソードは旧スクウェアのプログラマであるナーシャ・ジベリ氏が、ファイナルファンタジーにおいてほぼバグのような挙動を利用して8倍速で飛空艇を動かすというエピソードです。また、現代でも、RTAinJapanというイベントで、ファミリーベーシックを用いてアセンブリを記述し、メモリを書き換えてエンディングを呼び出すというRTAが披露されるなど、ファミコンは話題に尽きない名ハードだと思っています。

ファミコンはCPUが6502互換であるということは知っているものの、他のハードウェア的な特徴については全く知りません。今回の講義でリバースエンジニアリングに関する知識を身に着け、ファミコンの構造を理解できたら楽しいだろうなと思っています。 他には、画面が映らなくなった電波時計など、動かない機械をいくつか持っているので、それらを分解して構造を見たり、ROMのデータなどを読み出したりしてみたいです。


RISC-V CPU自作ゼミ

こちらも、RISC-Vはもちろん、CPUそのものに対する理解がまだ浅いので、FPGAに興味を持ったきっかけなどをしっかり書きました。あと、RISC-Vの好きなところをアピールしました。こんな理由でRISC-Vを好む人間、どれくらい居るんですかね・・・

問1

あなたがRISC-Vに命令を追加する場合、どのような命令(群)を追加してみたいかを、その命令の仕様 (ニーモニック、フォーマット、動作) とともに説明してください。

パリティチェックコマンド

parity reg, IMM とすると、regのチェックサムと即値を比較する

parity reg とすると、0~6bitのチェックサムと7bitを比較する(例えばASCIIコードのパリティチェックに使うことが出来る)

問2

今までに使ったことがあるCPU (x86_64, Arm, PIC, AVR, RL78, RX, RISC-V, etc... なんでもOK) について自由に記述してください。

AVR:Arduinoで

ARM:主にRaspberry Piで 最近はロボコンでSTM32経由でも使用している

H8:学校の授業でH8/3069Fを使用しているため gccが対応しているから自分でビルドして、H8マイコンで動作する実行ファイル(ELF)を生成しようと試みている

x86_64:最も使用しているCPU OS自作のためにIA-64の定義書をみたり、スタックセグメントレジスタのような、汎用レジスタ以外のレジスタを調べたりした

下に行くほど深く・長く使っているもので、AVR以外はアセンブリを読んだことがあります(ARMは本当に少しですが)

また、x86_64ではアセンブリを書いたこともあります(Linuxからシステムコールを通して標準出力したり、自作OSの過程で特殊なレジスタを書き換えたりするために書きました)

問3

以下のポート定義を持つ幅8bit、深さ1024段のFIFOをSystemVerilogで記述してください。記述内容としては、付属のテストを使ってIcarus Verilogでテストをパスすることを目標とします。
(どういう考え方をしたか評価しますので、テストをパスしない内容でもご応募いただければと思います)
逆にテストが足りないと思ったり、付属のテストベンチが使いにくいと思ったのであれば、追加していただいても構いません。

使用可能なSystemVerilogの言語機能はIcarus Verilogでシミュレーションが可能な範囲 (`-g2012` オプションを指定して使えるSystemVerilog 2012のサブセット) とします。
また、記述したコードの動作について日本語で説明してください。

ただし、モジュールの入出力信号のvalid/ready/dataで終わる信号については、以下の制約を満たすものとします。

* 全ての信号はクロック入力の立ち上がりエッジに同期しているものとする。
* valid/readyともに正論理 (1'b0:デアサート、ネゲート, 1'b1: アサート) とする。
* validがアサートされている場合のみ、dataの内容は有効とする。
* validは一度アサートされたら、対応するreadyがアサートされるまでデアサートしてはならない。
* 対応するvalid/readyの両方がアサートされているサイクルでのみデータの入出力が成立する。
* validをアサートする場合は、対応するreadyに関係なくアサートしなければならない。
  * 例えば、readyがアサートされたらvalidをアサートするという条件にしてはならない。 (デッドロックを防ぐため)
* readyは任意のタイミングでアサート・デアサートしてよい.
* 補足:validはデータを出す側がデータが有効であることを表す信号、readyはデータを受け取る側が今のサイクルでデータを受け取れることを表す信号です。

信号のタイミング例はテストベンチに同梱の fifo_waveform.png を参考にしてください。

valid/readyの対応関係は、ARMが定義しているAMBA 4 AXI4-StreamにおけるTVALID/TREADY信号の制約と同等です。参考: https://developer.arm.com/documentation/ihi0051/a/

詳細はプログラムにコメントとして記述しています。

resetのアサート時にoutputを初期化、in_validのアサート時にFIFOのバッファに値を追加、clockの立ち上がり時、FIFOのバッファに値がある場合は先頭の(最初に追加された)値を出力する

Gistsfifo.sv を提出しました)

問4

本講義を受講するにあたってアピールしておきたいことがあれば自由に記述してください。

自由記述ということなので、このコースに応募しようとしたきっかけと、RISC-Vの好きな所を少しだけ書こうと思います。

このコースに応募しようとしたきっかけは、FPGAに対する憧れと、RISC-Vの技術的特徴に興味を持っているからです。何と言っても、RISC-Vの特徴はISAがロイヤリティーフリーである・カスタマイズ可能であることだと思っています。様々なOSSによって我々の生活が支えられているように、RISC-VもCPU界を根強く支える存在になったら良いなと考えています。

そもそもCPUを自作するという点でFPGAには興味がありましたが、特に惹かれたのはこれらのツイートです:

FPGAでゲーム機を再現するというのには非常に興味を覚えました。私は技術的制約の中プログラマが試行錯誤して名作を生み出したファミコンに、ゲーマーとしても技術者としても興味があり、FPGAでファミコン互換機が作れたら楽しそうだろうな・・・と思ったのも、応募しようとしたきっかけの一つとなります。

CPUのアーキテクチャに詳しいとは思っていませんが、それでもCPUアーキテクチャの好き嫌いはあります。

そもそも自分は主にC言語を書く人間で、この際は基本的にclang-formatのお世話になっています。clang-formatには「AlignConsecutiveXXX」(XXXにはMacroとかAssignmentとかが入る)というルールがあり、これを使うことで代入文のイコールなどを垂直方向に揃えることが出来ます。私はこの垂直に揃えられたソースコードが大好物で、clang-formatがなくても揃えられるときは頑張って揃えようとしています。

さて、私は完全な興味本位で自分の書いたプログラムをビルドし、objdumpなどを使って機械語を読むことがあります。x86_64では左の機械語にまとまりはありません。1バイトのときもあれば、4バイトの時もあります。しかし、Raspberry Pi(Arm)上でビルドしたプログラムをobjdumpで覗くと、全て4バイトで揃っています!

RISC-Vマシンには触れたことはなく、Compiler Explorerで読んだ限りですが、こちらも固定長で、見ていて嬉しくなることができます。 ということで、「RISCである(+ある程度身近である)」という点で、私が好きなCPUアーキテクチャはArmとRISC-Vです。

OS自作ゼミ

OS自作に関しては未踏ジュニアにも応募したので、やりたいことの方向性はおおよそ決まっていました。よければそれについてのブログも見てください。

選択課題に両方解答してますが、これは両方解答したかったからです(面白そうなので)。

課題A

OS自作ゼミで挑戦してみたいことを教えてください。また、それを実現するために必要となる実装や調査はどのようなものになるか、あなたの予想を教えてください。間違っていても大丈夫です。

未踏ジュニアに、「キーボードから手を離さずにすべての操作を完結することが出来るOS」というプロジェクトで応募しました。その際、プロトタイプを開発しました。

ブートローダーとカーネルを全てRustで開発していて、今後もRustを使うつもりです。このOSにはまだ実装していない機能が山ほどありますが、主に自作OS用の自作ソフト(ELF形式)を、マルチタスクで動作させる機能を実装しようと思っています。おおまかに実装すべきは以下の通りです:

  • システムコール
  • スケジュール管理システム
  • ELF読み取り(ヘッダのパース等)
  • (ターミナル関連の実装)

課題B

テキストエディタでコードを書いているとして、キーボードのキーを押してから画面に文字が表示される間の処理の流れを説明してください。また、そのなかで、あなたが大事だと思うOSの処理をいくつか取り上げて説明してください。

大まかに言うと、

  1. キーボードからPCに、キー押下状態が送信される(USBだったりPS/2だったりを通して)
  2. OSが割り込みなどを利用して押されたキーを検出
  3. エディタがOSの機能を用いてそれを取得、テキストを変更+再描画(描画についてもっと詳しく)

まず何と言っても割り込み処理は重要です。これ以外にはポーリングと呼ばれる、いわゆる無限ループで定期的にキー入力をチェックする方法があるが、これは入力を見逃してしまう可能性があってまずいです。特にこのような通信系においては、いつでも再送信してもらえるとは限らないため、取りこぼしが発生しないようにする必要があります。

また、OSとしての機能とは厳密に違うかもしれませんが、この処理においてエディタ自体はキーボードの入力プロトコルなどを知る必要はありません。後述しますが、OSの本質とも言えるこの要素も非常に重要であると思っています。

課題C

C言語で整数を要素に持つ固定長のリングバッファを実装してください。

リングバッファということなので、1周はさせないとテストとして甘いよな~と思ったので追加しました。また、バッファがいっぱいの状態で追加しようとした時・バッファが空の状態で取り出そうとした時のテストも記述しています。

提供したリングバッファのひな形の関数定義における改善点として、「pop/push時のエラー判定ができない」というものがあります。push時のエラー判定(バッファがいっぱいだった時)はboolを返すことで、pop時のエラー判定(バッファが空だった時)はRustのOption型のようなものを実装することで解決しました(これにともなって定義済みのテストを少しだけ変えていますが、本質的な部分は変えていないはずです)。

課題D(選択問題)

なぜコンピューターにはOSが必要とされていると思いますか?現代の、もしくは将来のOSが果たすべき役割はどのようなものだと考えますか?この設問には正解はありませんので、あなたの考えを自由に記述してください。

OSの存在意義はリソース分配・ブラックボックス化だと思っています。リソース分配というのはメモリ・CPU時間の分配のことで、ブラックボックス化はハードウェアアクセス・マルチタスク等をOS任せにすることが出来るということです。

極論を言ってしまえば、OSがなくてもソフトウェアがキーボード・マウス・GPUなどを適宜制御すれば、OSなしで3Dゲームを作成することも(おそらく、理論上は)不可能ではないはずです。実際、ファミコンにOSというものはなく、memory-mapped IOを読み書きしていました。

しかし、現在はWindows上でUnityを使ってゲーム開発をすることが少なくありません。Unityを使うにあたって、GPUの制御について考える必要はあるでしょうか?多分無いと思いますが、ではなぜゲームを作成するのにGPUのことを考えなくてよいのでしょうか?なぜなら、その部分はUnityがいい感じにやってくれるからです。これにより、ユーザーは本質的な「ゲーム開発」に専念できます。そして、これと同じことはOSにも言えると思っています。

これからのOS、特にパーソナルコンピュータ向けのOSであれば、さらに多くのデバイスに対応する必要があると思います。既存の規格を用いたデバイスへの対応は、デバイスの開発者がOS向けのドライバを書くことによって実現します。しかし、全く新しい規格を用いたデバイスへの対応は、まずOSが対応してくれないとドライバすら書けないのでは?と思っています。デバイスドライバは詳しくないので間違ってたら申し訳ないですが、ユーザーはもちろん、開発者にとって細かいデバイスの制御に付いて考えるという責務を排除する、という役割は大切だと思います。

課題E

x86系CPUのメモリ管理機構が持つ「ページング」と呼ばれる仕組みを用いて実現されるOSの機能を1つ挙げ、その機能の概要と詳しい仕組みを説明してください。取り上げるOSの機能は既存の機能でも、独創的な機能でも良いです。

Segmentation fault:許可されていないメモリ区間への読み書きを弾く

例えば、bashから文字列リテラルを書き換えようとするプログラムを起動すると、Segmentation faultが表示されて落ちます

課題F

その他、何かあれば自由に書いてください。これまでにあなたが行ってきた自作OSやシステムプログラミングに関連するリポジトリや、関連する活動へのリンク、OS自作へかける熱い想いなど、なんでもOKです。

最近、osdev-jpに参加させて頂きました。そこでも述べましたが、最近はELF形式の勉強と、Linuxにおけるブートプロセスの調査をしています。

また、学生団体FascodeNetworkで、Alter Linuxの開発に一部参加しています。

やりたいことについては課題Aへの回答のとおりですが、この他にも、前述したOSプロトタイプはUEFIをcrateに頼っている(最初は自力でやろうとしたけど出来なかった)ため、フルスクラッチで書き直すことや、OS自作ゼミの紹介で触れられていた「大規模なコードの読み方」にも興味があります。


応募した内容はここまでです。OS自作ゼミやCPU自作ゼミみたいに、実際に手を動かす課題が特に楽しかったです。色々知らないことも知ることが出来て、課題だけでも良い経験になったと思います。

終わりに

繰り返しになりますが、ほんとに受かって良かったです。課題解くだけでめちゃくちゃ勉強になって楽しかったです。

もちろん、受かって終わりではないので、ここからも頑張っていこうと思います。CPUのきもちになって、RISC-Vを理解してこようと思います。


Comments

Powered by Giscus