1 of 30

最適な画面モードの設定で苦戦した話

@Egh2Deywos

2 of 30

目次

  • 自己紹介
  • 背景
  • 手順
  • やってみた
  • バグ倒しの旅
  • デモ
  • まとめ

3 of 30

自己紹介

  • 伊藤 太清(いとう たいせい)
  • 大学でドローンを使った被災地探索について研究
  • 自動車関係のエンジニア
  • 趣味:自作OS、歴史、神話、宗教、比較言語学、サンスクリット語、etc.

4 of 30

背景

  • X86アーキテクチャでレガシーBIOSを使ったOSを作っている
  • 画面の解像度や使える色は画面モードを指定することで決まる
  • 30日本のharibote OSでは基本的に画面モード0x0105を使用
    • 幅1024ピクセル
    • 高さ768ピクセル
    • 1ピクセル当たり1バイト(最大256色)

モニターの性能を最大限生かせない・・・

最適な画面モードを設定しよう!!!

5 of 30

手順

https://wiki.osdev.org/VESA_Video_Modes

を参考にやってみた

基本的な流れ

  1. 利用可能な画面モードの一覧を取得
  2. 最適な画面モードを探す
  3. 最適な画面モードに移行

6 of 30

手順

https://wiki.osdev.org/VESA_Video_Modes

を参考にやってみた

基本的な流れ

  • 利用可能な画面モードの一覧を取得
  • 最適な画面モードを探す
  • 最適な画面モードに移行

7 of 30

手順 1.利用可能な画面モードの一覧を取得

ES:DIにこの構造体が書き込まれる

利用可能画面モード番号の配列

0X0100

0X0101

0X0102

0X0103

0X0104

0X0105

0XFFFF

8 of 30

手順

https://wiki.osdev.org/VESA_Video_Modes

を参考にやってみた

基本的な流れ

  • 利用可能な画面モードの一覧を取得
  • 最適な画面モードを探す
  • 最適な画面モードに移行

9 of 30

手順 2.最適な画面モードを探す

INT 0x10, AX=0x4F01, CX=mode, ES:DI=256byte buffer

ES:DIに、画面モードに関する情報が書き込まれる

  • 画面の幅のピクセル数
  • 画面の高さのピクセル数
  • bits per pixel

その他いろいろ

10 of 30

手順 2.最適な画面モードを探す

「最適」をどう定義する?

best_mode;

for each mode {

if(0x18 <= mode.bits_per_pixel){

if(best_mode.width <= mode.width && best_mode.height <=mode.height){

best_mode = mode;

}

}

}

11 of 30

手順

https://wiki.osdev.org/VESA_Video_Modes

を参考にやってみた

基本的な流れ

  • 利用可能な画面モードの一覧を取得
  • 最適な画面モードを探す
  • 最適な画面モードに移行

12 of 30

手順 3.最適な画面モードに移行

INT 0x10, AX=0x4f02, BX=mode(+0x4000)

ここはharibote OSと同様

やってみよう!

13 of 30

やってみた

  • QEMU→成功
  • Virtual Box→成功

Virtual Boxでの実行結果

14 of 30

やってみた

  • QEMU→成功
  • Virtual Box→成功
  • 実機→失敗…

手順1,2,3ができているかどうか、順番に確かめてみよう!

実機での実行結果

15 of 30

バグ倒しの旅

手順1.利用可能な画面モードの一覧を取得できているかどうか

video mode = 0x0000

video mode = 0x0000

video mode = 0x0000

video mode = 0x0000

video mode = 0x0000

video mode = 0x0000

video mode = 0x0000

video mode = 0x0000

ううっ…

16 of 30

バグ倒しの旅

VideoModePtr[1]がセグメント、VideoModePtr[0]がオフセットだった

17 of 30

バグ倒しの旅

VideoModePtr = 0xc00090b9

これがそのまま物理アドレスだと思ってた(というか上位16ビットを無視してた)

セグメント0xc000、オフセット0x90b9という意味だった。

ここを直して画面モードの一覧を取得できるようになった!

さらに、手順2もうまくいった!(実機での最適な画面モードは0x017fだった)

18 of 30

バグ倒しの旅

しかし!!!

19 of 30

バグ倒しの旅

  • 画面モード情報の構造体は0x600番地に書き込んでた
  • 全ての画面モードを調べた後、再度BIOSを呼び出して�最適な画面モード情報を書き直していた
  • bits per pixelが0x00であるにも関わらず0x017fが�最適な画面モードとして選択されている

同一の画面モードの情報を複数回取得しているのがまずい?

20 of 30

バグ倒しの旅

best_mode;

for each mode {

modeの画面モード情報を0x700番地に書き込み

if(0x18 <= mode.bits_per_pixel){

if(best_mode.width <= mode.width && best_mode.height <=mode.height){

best_mode = mode;

0x700番地の画面モード情報を0x600番地に書き写す

}

}

}

同一の画面モードの情報取得を一回で済ませられるように変更

21 of 30

バグ倒しの旅

やったー!!!

いよいよ画面切替!

22 of 30

バグ倒しの旅

画面が使えない

シリアルポートない

printデバッグできない

ううっ…

23 of 30

バグ倒しの旅

VRAMの物理アドレスはわかっている(0xe0000000番地)

32ビットモードに入ってからの処理を全て削除し、VRAMに直接書き込み

具体的には、0xe0000000番地から0xe0200000番地まで0xffを書き込みまくった

24 of 30

バグ倒しの旅

画面モード切替は成功していることが分かった

→ではどこでバグってる?

25 of 30

バグ倒しの旅

実験を繰り返した結果、マウスを有効化するinit_mouse()関数がトリガーだった

init_mouse()を実行する

画面が表示されない

init_mouse()を実行しない

画面が表示される

init_mouse()関数の中身を確認してみる

26 of 30

バグ倒しの旅

マウスを使うためにいろいろやり取りしてる

27 of 30

バグ倒しの旅

マウスとのやり取りはキーボード制御回路を通して行う

28 of 30

バグ倒しの旅

キーボード制御回路への送信はこんな感じ

もしかしてここで無限ループに陥ってる?

無限ループに陥っているとしたらなぜ?

割り込みが禁止されていないのでは?

初期化前にcli、初期化後にstiしてみた

29 of 30

バグ倒しの旅

やったー!!!

30 of 30

まとめ

  • 実機で最適な画面モードが選択できた
  • 画面やシリアルポートのありがたみがわかった
  • あれだけのバグがありながらちゃんと表示できてしまった仮想マシン…

今後の課題

  • 描画速度が落ちる懸念