同書をmacOSにて開発した際のソースコード。
下のイメージはは30日目終了時の記念撮影。エミュレータ実行のため、vram(シート)に少し異常あり。(基本動作に問題はない)
8日目までの開発は、Qittaに投稿されている『30日でできる!OS自作入門』を macOS Catalina で実行するを参照。9日目以降は著者ソースコードを参照。
(余程のミスをしない限り)コードに問題があっても、コンパイラが親切にエラーを出力してくれる。Haribote OSが壊れる、開発PCがフリーズするということはない。
- あくまで私的利用目的
- 2セクション分を1つのプロジェクトとして一括作業している部分あり
- 該当セクション終了後にミスを発見・訂正している部分あり。該当セクション時点での簡単なOS動作確認上の不具合は確認されなかった。(下記除く)
- 多くのコメントを割愛。残したコメントは想定外の文字化けを避けるため英語
- コメントは
//
を優先利用 - 途中で細かな記述方法の変更あり
- PC: MacBook Pro 13-inch 2017
- OS: macOS Catalina 10.15.7
- コンパイラ: GCC(i386-elf-gcc) 9.2.0, NASM 2.15.05
- イメージ作成: mformat 4.0.25, mcopy 4.0.25
- エミュレータ: QEMU 5.1.0
- エディタ: Visual Studio Code 1.51 (何でも良いと思うが、UTF-8標準設定のものが無難)
Homebrewから各ソフトウェアをインストールする際、最新のXcodeが必要。最新版Xcodeでは、ターミナルからXcode Command Line Toolのインストールができなくなっており、Apple開発者サイト経由ですることになる。
2020年11月時点で既にCatalinaのアップデートmacOS Big Sur 11
が公開されており、加えてアップル独自開発CPUM1
搭載のPCも流通している。Big Surでも、(Intel Core ix系搭載のPCであれば、)必要なソフトウェア(GCC, NASM, QEMU, etc.)のインストール・動作ができれば、開発を進められそうである。
問題memory 128MB
と表示される。
対応
エミュレータが自動で割り当てるメモリー量だと解釈。プログラム・OS自体に問題はないと判断し、無視して開発を継続。
問題HariMain()
内for(;;)
直下にシートを更新するプログラムが無いと、動作が遅くなる。PIC/PITもしくはCPUクロック数に原因があると推測される。
対応
10秒後ではなく、カウンタ数を常に表示。動作上の意味は無いが10秒後にカウンタ数を表示するプログラムは残してある。尚、この問題はharib11f
で高速カウンタを消去し、if文内のio_sti()
をio_stihlt()
に戻した段階で自然解決される。
void HariMain(void) {
…
for (;;) {
count++;
// このあたり
}
}
問題asmhead.nas
に指定の画面モードをするも、黒い画面が表示されるのみ。コンパイル時のエラーはなし。
対応
harib11eのVBE設定プログラム導入で自然解決される。特に意味はないが、解像度は0x101
を利用して開発を進めた。
問題task_b_main
内for(;;)
直下にシートを更新するプログラムが無いと、動作が遅くなる。harib10c~harib11eと類似した問題。
対応
前回同様、カウンタを常に表示。(if (fifo32_status(&fifo) == 0)
)内のio_sti()
をio_stihlt()
としてもスムーズな動作はするが、前者と比べてカウントスピードは約1/50になる。
問題task_b_main
内for(;;)
直下にシートを更新するプログラムが無いと、動作が遅くなる。前項同様の問題。
対応
前項同様、カウンタを常に表示。この問題もharib14b
でカウンタを削除した段階で自動解決される。
問題<string.h>
がincludeできず、strcmp
が使えない。
対応sprintf
に倣い、関数を自作。新たにmyfunction.c
を作成し、同ファイルに関数を記述。新規関数・ファイル追加に伴いbootpack.h
とMakefile
に追加記述を施す。strcmp
のプログラムはAppleのオープンソースサイトで公開されている。
問題strncmp
が使えない。
対応strcmp
同様、myfunction.c
に関数自作。bootpack.h
に関数定義も追加。参照: Appleのオープンソースサイト。
問題asm_cons_putchar
の番地が本記載のものと異なる。
対応Makefile
内bootpack.hrb
を生成するコマンドに-Xlinker -Map=bootpack.map
オプションを追加し、マップファイルを生成。bootpack.map
に記載されているasm_cons_putchar
の番地を調べ、その値をhlt.nas
内be3
値と入れ替える。ちなみに自分が実行した際の番地は、c64
であった。この値を使用してharib17c
を実行した際、正常に「A」が表示された。よくわかない場合、harib17e
までスキップすれば、番地を調べることなく、プログラムを実行できるようになる。
問題a.hrb
とhello3.hrb
の生成。
対応
『30日でできる!OS自作入門』のメモを参照。「アプリケーション用リンカスクリプト」をapp.ld
として保存し、a.hrb
、hello3.hrb
生成時に、これをリンカスクリプトとして利用。リンカスクリプトについては自分も未理解。
問題Shift + F1
を押しただけでは強制終了しない。(0x3d
が入力されない。)
対応
Macのキーボード設計による問題。Shift + fn + F1
で強制終了できる。
問題rand()
が使えない。
対応stars.c
内にStack Overflowを参照してrand()
を実装。結果的に同書と同じ星が配置された。
問題F11
はmacOSにより既にリザーブされている。
対応F11
の代わりにF11(0x58)
を使用する。
問題noodle.hrb
生成時、以下のエラーが発生される。
/usr/local/Cellar/i386-elf-gcc/9.2.0/lib/gcc/i386-elf/9.2.0/../../../../i386-elf/bin/ld: section .data VMA [0000000000000400,000000000000040f] overlaps section .text VMA [0000000000000030,000000000000048f]
collect2: error: ld returned 1 exit status
make: *** [noodle.hrb] Error 1
対応
良くわからないが、.data
の一部が.text
の番地に書き込みされようとしているのが原因。app.ld
をapp2.ld
として複製し、0x0400
を0x0500
と書き換えるとコンパイルに成功した。(.text
の終了番地が0x48f
のためそれより大きい値を代入。)
尚、この時自身のソースコードtimer.c:72
に不要なコード(if (t == 0) { break; }
)があることを発見し、この行を削除。この行を削除しないとタイマーのカウントは1秒で止まる。加えてこの行を削除することにより、アプリ実行後task_aのウィンドウに戻るとカーソルが点滅しなくなる不具合も解決された。
問題
キーボード入力の条件判定if (s[0] != 0)
でBackspace
、Enter
の入力も&key_win->task->fifo
へ送信くれるはずだが、うまく送信されない。(Backspace
およびEnter
が効かない)
対応harib22h
までのBackspace
、Enter
用条件判定を残し、その中でfifo32_put()
を実行する。
問題
著者開発のobj2bim
が使えないため、無駄なファイルとのリンクを解けない。
対応
結果的にharib24d
よりもファイルサイズが大きくなるが、無視して継続。
問題
著者開発のライブラリアンgolib00
が使えないため、ライブラリを作れない。
対応
GNUのアーカイブユーティリティar
を使う。Haribote OSでは、macOS標準のar
が使用できないため、elf用i386-elf-ar
(386-elf-binutils
の一つ)を使う。harib24e
と比較し、アプリのファイルサイズが大幅に小さくなった。ライブラリを含めてコンパイルした際、GCCが勝手に必要な関数のみを読み込んでくれたと推測している。
余談であるが、アプリファイル生成の際、GCC実行時
-fno-builtin
と-g
のオプションを外しても正常にコンパイルできた。
問題
使用ソフトウェアが(10年以上前の)Windowsでの開発と異なるため、Makefileが記述が異なる。
対応
詳しくは該当ディレクトリの各Makefileを参照。
問題haribote/mysprintf
はアプリ(noodle.hrb
, sosu.hrb
, etc.)でも使われる。
対応
27日目の学習でライブラリに詳しくなったため、sprintf
, strcmp
, strncmp
をライブラリとして書き出す。新規作成、修正したファイルは以下の通り。必要なくなったファイルは削除している。
# 新規
.
├── lib
│ └── Makefile, sprintf.c, strcmp.c, strncmp.c # `[sprintf.c] => libstdio.a`、`[strcmp.c, strncmp.c] => libstring.a`
└── include
└── stdio.h, string.h
# 修正
.
├── Makefile
├── app.ld # Change: 0x400 -> 0x500
├── app_make.txt
├── haribote
│ └── Makefile, bootpack.h
└── noodle
└── noodle.c
問題__alloca
が自動で呼び出されない。
対応
アプリ用リンカスクリプトにアプリ毎スタックサイズを指定できるようにapp_make.txt
とapp.ld
を変更。
…
ifndef STACK
STACK = 0x500
endif
…
$(APP).hrb : …
… -Wl,'--defsym=__stack=$(STACK)'
…
…
SECTIONS
{
.head 0x0 : {
…
LONG(__stack)
}
…
.data __stack : …
…
sosu2/Makefile
にSTACK = 0x2800
、winhelo/Makefile
, winhelo/Makefile
にSTACK = 0x2000
を追加。(10000=0x2710, 150*50=0x1D4C。)このままでもプログラムは動作するが、指定スタックサイズが必要なメモリサイズより小さい場合にアプリを実行するとOSがフリーズし、強制終了(Shift+fn+F1)もできなくなる。原因は不明だがallocaを使用してバッファを確保すると、アプリプログラムは実行されないものの、強制終了はできるようになった。(apilib.h
へのalloca関数定義を忘れずに。)
// sosu2.c
char *flag = alloca(MAX);
// winhelo.c, winhelo2
char *buf = alloca(150 * 50);
問題
全てのファイルはShift JISではなくUTF-8でエンコードされているため、type ipl10.nas
を実行しても文字化け表示される。
対応
無視。
問題chklang
実行、本記載のバグ(右半分しか表示されない)が発生しない。
対応
無視。
問題
(1) memcmp
が使えない。(2) setjmp.h
が存在しない、setjmp
、longjmp
が読み出せない。
対応
(1)lib/memcmp.c
を作成。内容は著者ソースファイルomake/tolsrc/go_0023s/golibc/memcmp.c
を参照。この関数をlibstring.a
としてライブラリ化。include/string.h
も併せて更新。
(2) include/setjmp.h
を作成、typedef int jmp_buf[3];
を記述し、tek.c
から読み込む。tek.c
では、setjmp
、longjmp
の代わりに__builtin_setjmp
、__builtin_longjmp
を使う。
なおアプリ(.hrb)は著者作成のプログラムを使用してのtek圧縮ができないため、アプリは一切圧縮せず開発継続。
問題sprintf()
で桁数指定(%08d)ができず、(画面表示上での)スコアの上昇がおかしい。
対応
無視。この問題はharib27e
でsetdec8
を導入することにより自動解決される。
問題
(1) strtol
が使えない。 (2) |
が入力できない。
対応
(1) 著者ソースコード(omake/tolsrc/go_0023s/golibc/strtol.c
)を参照し、strtol.c
、strtoul0.c
を作成。libstdlib.a
として書き出し、コンパイル時にアプリとリンク。strtol
に必要なerrno.h
、limits.h
も併せて作成。
(2) 無視。
問題
音がならない。
対応qemu-system-i386
に-soundhw pcspk
を加えてエミュレートした結果、正常に音がでた。しかし、warning: '-soundhw pcspk' is deprecated, please set a backend using '-machine pcspk-audiodev=<name>' instead
の警告を受ける。-machine pcspk-audiodev
に渡すべき<name>
がわからなかったため、そのまま-soundhw pcspk
を使用することに。
音楽ファイルは圧縮したものを著者ソースコードより複製。圧縮前ファイルについては、UTF-8変更したものを保存。
問題bmp.nasm
を流用できない。(jpeg.c
はほぼそのままで利用できる。)
対応bmp.nasm
を適当なディレクトリへ複製。ファイル内の文字化け部分を全削除。最初の方に文字化けを含む%if 0…%endif
ブロックも削除。iconv -f US-ASCII -t UTF-8 bmp.nasm > bmp.nas
を実行してUTF-8形式に変換し、gview
下へ移動。[BITS 32]
、関数接頭字_
を削除。.bpp4
内の.do4.1
ラベル宣言でコロンが抜けているので.do4.1:
と修正。
jpeg.c
はUTF-8形式としてファイルをした後、著者ソースコードをコピー&ペースト。文字化けは鬱陶しいので、その部分は削除。コンパイル時jpeg_decode_yuv
がint
を返さないと警告を受けるので、同関数のreturn;
をコメントアウト。
問題
シリンダ読み込み数。
対応
各バイナリファイルは、本記載のものよりサイズが大きくなる傾向にあり、且アプリの圧縮も行えない。setdec8
導入後、バイナリエディタ(Hex Fiend)を使ってharibote.imgの中身が何バイトまで使用されているか調べると0x02BAA0
であった。結果、シリンダ数: 0x02BAA0 / 18432 = 178848 / 18432 = 9
、余り: 0x02BAA0 % 18432 = 178848 % 18432 = 12960(13k)
となる。圧縮なしで13kを節約するのは無理と判断。10シリンダを読み込む形でipl9.nas => ipl10.nas
とした。