セキュリティ・キャンプ全国大会2019に参加した
タイトルの通りなのですが、セキュリティ・キャンプ全国大会2019を修了したのでその参加記的なのを書いていきます。 前に応募用紙晒しをしたときにも書きましたが私はYトラックのOS開発ゼミのフルスクラッチOSを書こう!というテーマで参加しました。 集中開発コースなのでずっとOSを開発してたわけですが、OSの機能など細かい解説は復習も兼ねてじっくりとやっていきたいので追々scrapboxのほうにまとめていきます。この記事は開発日誌的なものだと思っていただければ良いと思います。
1日目
1日目は顔合わせの日なので開発はしませんでしたが、特別講演やLT大会、それとグループワークがありました。 余談ですが、実はこの日お昼くらいから偏頭痛をこじらせていて、ずっと痛い頭を抱えていたので何があったのかよく覚えていません。悲しい。こんなことにならないようにキャンプ前日はちゃんと休みましょう。
2日目
2日目は開発時間が一番長い日でした。
午前中はuchan先生つきっきりでOSのデバッグをしていました。
uchan先生つきっきりでデバッグしてもらってて心強い
— Δyuk! (@heppoko_yuki) August 14, 2019
バグ消えろーバグ消えろーって念じてる
— Δyuk! (@heppoko_yuki) August 14, 2019
バグの内容は割り込みハンドラの設定後、割り込みがあると再起動してしまうというものでした。再起動の直接的原因はトリプルフォルトというもので、x86の場合ダブルフォルトまでであればダブルフォルト例外を発行しますが、トリプルフォルトの場合は再起動します。おそらく目的の割り込みハンドラだけでなく、例外ハンドラも正しく設定できていないためトリプルフォルトとなっているのだろうと検討をつけ、まずはIDTを設定するコードにバグがないか静的解析を試みました。しかし問題がなさそうに見えたので、今度はsidt命令を使って登録したIDTRやディスクリプタが正しいか確認したところ、ディスクリプタに登録したハンドラ関数のアドレスが正しくないことが判明。実はこの事象、数日前に同じくOS開発ゼミに参加していた突撃隊さんも遭遇していたものを踏んでいたことがわかったのです。結論としてはコンパイルオプションに-fno-picをつければ解決するということだったのですが、もっと詳しく知りたいという方はこちらをご覧ください。
プロトタイプ宣言だけのundefinedな関数について,関数のアドレスを取ろうとしたとき,gccはなぜか知らないがそのアドレスが指すメモリ領域から8バイト読み出すような命令を吐いてしまうというのが問題の本質でした。
— 社会人でもOSを作りたい (@uchan_nos) July 30, 2019
バグが取れてうれしい私↓
バグとれた!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
— Δyuk! (@heppoko_yuki) August 14, 2019
やった!!!!!1
— Δyuk! (@heppoko_yuki) August 14, 2019
dsdhふぃsでぃふはsどいふyhさぢおlh
— Δyuk! (@heppoko_yuki) August 14, 2019
やったああああああああ
— Δyuk! (@heppoko_yuki) August 14, 2019
例外ハンドラが正しく登録出来たことでデバッグもしやすくなりました↓
零除算をするな💩💩 pic.twitter.com/IzMT4WPxbt
— Δyuk! (@heppoko_yuki) August 14, 2019
そして午後からはメモリ管理をしてみようと思い勉強や実装を始めました。メモリ管理をするためには、メモリマップを知らなければなりません。メモリマップはUEFIのBoot ServicesのgetMemoryMap()によって取得できます。
上記の通りメモリマップを取得するプログラムを書いていたのですが、ここで「配列の先頭アドレスのアドレス」を渡さなければいけない箇所を誤って「配列の先頭アドレス」を渡してしまっていたが為に、次の日の午前まで時間を溶かしてしまいました。
3日目
この日は寝坊して、IPAの方と看護師さんが起こしにきました。本当に申し訳ないです。
寝坊
— Δyuk! (@heppoko_yuki) August 14, 2019
起床技術者試験に落ちた後、朝食抜きで始まった開発ですが午前中は先程言ったバグのデバッグをチューターのPG_MANAさんとやっていました。C言語はもう少し人間に優しくなってほしいです。
C言語くそ
— Δyuk! (@heppoko_yuki) August 15, 2019
同じくOS開発ゼミに参加していて、Rustで組み込みOSを自作していたikubakuさんからこんなこんなお言葉を頂きました↓
Rust使いましょう
— ikubaku (@ikubaku10) August 15, 2019
取得できたメモリマップ↓
メモリアロケータ書くよ!! pic.twitter.com/KG0GXv77hP
— Δyuk! (@heppoko_yuki) August 15, 2019
午後は取得できたメモリマップをもとにメモリ管理を実装していくのですが、ページングを利用しているOSではまずページ単位でメモリの割当をするページフレームアロケーターを使い、その中でmalloc()などが細かくメモリの割当をするということがほとんどなそうなので私もそれにならうことにしました。
せっかくページフレームアロケーターを実装するのであればページテーブルの設定も出来たほうがいいと思い、PG_MANAさんに教えてもらいながらページテーブルの設定をしました。
この日の開発は夕食前までで、夕食後は企業紹介やグループワークがありました。
4日目
4日目はしっかり6:30に起床し朝食にありつくことができました。
起床学Ph.D pic.twitter.com/KuNKE3wJ1K
— Δyuk! (@heppoko_yuki) August 15, 2019
そして午前は3日目に設定したページテーブルに合わせて空き領域を4KiBにアラインメントしページフレームのブロックを作りました。
ページフレームはつくれたのであとは配るだけー pic.twitter.com/lIH3LrkWNA
— Δyuk! (@heppoko_yuki) August 16, 2019
また、簡単な実装ではありますがページフレームアロケーターも午前中にできました。
ページフレームアロケーターできた!!! pic.twitter.com/Gq8ee5ti2t
— Δyuk! (@heppoko_yuki) August 16, 2019
Yトラックでは昼食後に成果発表会を行うことになっていたので、午後はその準備をしました。 発表時間は一人2分ととても少なく、あまりいい発表が出来ずお見苦しいところをお見せしてしまいました。
発表会が終わってから夕食まではとりあえず今まで実装してきた機能がすべてちゃんと動作するか確かめてみようと思い、コメントアウトしていた関数をすべてもとに戻し動作確認してみたところ、シリアル通信がqemuでは動くものの実機では正しく動いていないことがわかりそのデバッグをしました。
しかし原因はよく分からずそのまま夕食、企業紹介、グループワークへ。
シリアル通信の設定が悪いのかなと思い、シリアル通信に詳しそうな坂井弘亮師匠に見てもらったところ、コンパイラの最適化でシリアル通信の送信が可能かどうか判断する関数の呼び出しが、1回しか行われていない(ソースコード上ではbusy loopで呼び出してる)のではないかというアドバイスを頂きました。
そこでコンパイルオプションに-O0を追加し動かしてみたのですがこれでもまだ動かず。 講師のuchan先生にも見てもらい、最終的に原因はアセンブリで定義していたinb()関数が間違っていたことであることがわかりました。悲しい。
5日目
5日目は最終日です。他のトラックも含めた成果発表を聞きました。 井上root取っ太郎が面白かったです。
これがね、最終日の偉い人がたくさんいる成果報告会で「ドーン😎」って感じでね!w https://t.co/KfP6MCd9rF pic.twitter.com/717y258GQ0
— 黒林檎 (@r00tapple) August 19, 2019
全体を通しての感想
色んな人が自分のOSのデバッグを手伝ってくれるのが本当に心強いなと思いました。こんな機会なかなかないです。
今までは30日OS自作本やブログ記事、同人誌を見て写してただ動作を確認してみるということが多かったのですが、キャンプではオリジナルなコードもたくさん生やせてやっと自分でOSを作るということがわかった気がします。
5日間お疲れ様でした。
「セキュリティ・キャンプ 全国大会 2019」「セキュリティ・ネクストキャンプ 2019」の全ての日程が無事に終了しました。また来年もよろしくお願いいたします! #seccamp pic.twitter.com/q4ymhy8D6Y
— セキュリティ・キャンプ (@security_camp) 2019年8月17日
6日目?
— Δyuk! (@heppoko_yuki) August 18, 2019
7日目??
これは雲海を眺め飲む焙じ茶 pic.twitter.com/EkWtBfkTnx
— Δyuk! (@heppoko_yuki) August 19, 2019