30日でできる!OS自作入門
https://gyazo.com/e890a0e4891f1f9de81499c02618e897
タイトル
30日でできる! OS自作入門
著者
年
2006
リソース
CD-ROM所収の情報
概要
C言語で自作OSをつくる本
マルチタスクでGUIがあるOS
古い本だが有名な本らしく、最近でもやってみた記事が上がっている
書評
環境
macOS + VMのLinuxで作業→macOSでの作業にスイッチ→Windows10での作業にスイッチ
nasmをhighlitするVSCodeのプラグインを入れた 進め方
目標:最後にcommit logを見返したときに、なにをやったのかがわかるようになる
この本では、harib00xという連番のファイルが配布されている
このファイルは001に差分を加えて002にするという方法で作られている
社協においては、チャプターごとにこの差分を目grepして自分で写経していくスタイルを取る
自分で書かないと理解できないため
Chapter 3 32ビットモード突入とC語導入
INT 0x13意味はドキュメント参照
ディスク読み込み/書き込みなどができる
本書の図を見たほうが良い
CH, CL, ALの指定
CH シリンダ番号
80ある
CL セクタ番号
セクタ(扇形)
18ある
DH ヘッド番号
ヘッドは表と裏の2つある
DL ドライブ番号
(磁気)ヘッド
裏からあてるか表からあてるかの2パターン(両面記録)
1セクタは512バイト
最大容量は1440KB
512バイト*80シリンダ*18セクタ*2(両面) = 1440KB
ES:BX:$ ES \times 16 + BX
番地を16bitレジスタBXだけで表そうとすると、64KBまでのメモリしかつかえない 0xFFFF(64KB程度)までしか表せない
$ 2^{16}=65536
PCのメモリは64KBどころではなくもっと多い
kadoyau.icon 2021年現在、個人PCでRAM 32GBは珍しくない
当時は32bit レジスタは存在しなかった
後年、32bitのEBXレジスタが登場してメモリ4GBまで扱えるようになる kadoyau.icon 2021年現在、OSは64bitが普通
上の式でのESがセグメントレジスタ
最大値 0xFFFF * 16 + 0xFFFF = 1114095(約1MB)
当時は1MBあれば十分だった
アセンブラでセグメントレジスタを省略するとDS:を指定したことになる
MOV CX, [1234]はMOV CX,[DS:1234]という意味
カギカッコ[]は]メモリの指定(p.53)
MOV BYTE [688], 123 678番地に123を覚える(8bit)
MOV WORD [678], 123なら16bit
DSを0にしておかないと16倍した値がたされてしまう フロッピーはいい加減でたまに埋めないので5回ぐらいリトライ処理を入れる
p.53 \make.bat run
https://gyazo.com/bf25814d9e61476055c2cb017c0a9401
JAE jump if above or equal p. 54のコードの補足
SIをカウンタとして利用している
p.55 harib00c フロッピーの読み込みエラー処理を入れる
retryセクションにJNC nextが増えた
ADD CL 1 セクタを移動するコード
フロッピーのセクタは18まで(18で一周する)
合計18セクタを読み込みたい
MOV命令をつかってESに0x0020を加算し、1セクタ分すすめる 1セクタは512byte
ESを512/16 = 0x0020すすめると、バッファアドレスの計算によって512(1セクタ)すすむ JBE jump if below or equal ref. JAE
INT命令でAL=17にすれば処理するセクタ数を17にできる p.56 harib00d フロッピーの両面を読み取る
CYLS EQU 10 // CYLS = 10
Cでいう$define
シリンダを1に戻して、ヘッド番号に1を足す
「make install」でディスクにインストールして実際のPCで実行さ
せると、それなりに時間がかかっていることが分かります。うまくいっている証拠ですね
コンピュータが早すぎて一瞬で終わるのでこの実感がわかない
読み解く時の注意
アセンブラは、CSSのように上から実行されていく
このコードでのデータの読み取り方
同心円状に表を読み込む
裏を読み取る
シリンダをすすめて上記を繰り返す
詳説
readLoopにjumpすると、エラーのカウンタSIを初期化してディスク読み込みを行う
セクタが18まではセクタのreadを(readLoop)を繰り返す
18までいったらセクタを1にして(MOV CL, 1)、ヘッダを裏面読み取りに行く(ADD DH,1)
裏も読み取り終わったら、ヘッダを表に戻して(MOV DH,0)、シリンダをすすめる
CYLS回繰り返す
OS本体を書き始める
harib00e
HLT命令だけをするプログラムharibote.nasをかき、naskでアセンブルしてharibote.sysをつくる ディスクイメージに保存
1. ディスクイメージをディスクに書き込む
2. ディスクをWindowsで開いて、haribote.sysを保存
3. ディスクをディスクイメージとして保存
する作業を、Windowsとディスクを使わずにすること
edimg.exeを使うとディスクイメージに保存することができる
haribote.sysをディスクイメージに保存したとき、中身がどこに保存されるか調べる
code:Makefile
# 空のディスクにharibote.sysを書き込む
haribote.img : ipl.bin haribote.sys Makefile
$(EDIMG) imgin:../z_tools/fdimg0at.tek \
wbinimg src:ipl.bin len:512 from:0 to:0 \
copy from:haribote.sys to:@: \
imgout:haribote.img
make imgで生成されるharibote.imgの中身を見る
https://gyazo.com/c4e8677952f37d28ac6c5aa6b8e3b8fc
ファイル名は0x002600に入る
https://gyazo.com/7d3177b459ee5577f07908f64490f5e4
これはharibote.sysの中身と一致する
https://gyazo.com/3a05cd79923f80c7ff8f2ae73e900105
よって、haribote.sysの中身は0x004200以降に入ることがわかった
この情報を使って、ブートセクタからファイルの中身を読み取って実行するようにする
ブートセクタからディスクイメージ中のOS本体を実行させてみる
OS本体であるharibote.sysの中身は0x004200にあったのだから、これを読めば良い
いまのはりぼてOSでは、ブートセクタの先頭が0x8000になるように組んであるので、0x8000 + 0x4200 = 0xc200から読めばプログラムが読める
実効してみると、なにもおきないHLTしかしてないので当然何も起きない
何も起きないと不安
適当な動作をさせて、OS本体の動作を確認する
動いてんのかわからないのでharibote.sysでなんかさせる
画面モードを切り替える
0x13にしてみる
実行結果
https://gyazo.com/e8bd8a2821fda020757a6991b48dcd74
32ビットモードへの準備
CPUにはモードが有り、モードごとに機械語がことなる
例:32bitモード
32bitレジスタが使いやすい
変な機械語で誤動作しない保護機能を使える
モードは起動時に変更することができる
32bitモードではBIOSが使えないので、BIOSを使ってやりたいことを先にやってしまう やりたいこと→キーボードの状態をBIOSから教えてもらう
メモっておく
C言語で関数を定義して実行する
bootpack.cの追加。これを機械語にする必要がある
長い変換の旅が始まる
bootpack.c -> bootpack.gas(gasで読むためのファイル) -> bootpack.nas -> bootpack.obj (機械語)-> bootpack.bim(必要なオブジェクトをくっつけたファイル) → bootpack.hrb (機械語)→ haribote.sys(「BIOS読むアセンブラ」と「C言語を機械語に翻訳したbootpack.hrb」をくっつけたもの)
cc1というgccを改造したコンパイラを使うとgasファイル(gasと言うアセンブラのためのソース)が出る gasをnaskで使える形式に変換
naskでobjを作る。objは他のobjとリンクさせる機械語ファイル
Cの設計者はプログラムの全体をCでかくのではなく、一部アセンブラを使おうとした
「アセンブラで作ったobj」と「Cで生まれたobj」をリンクして使う
このためobjにはアセンブラで書いたobjとくっつけるための情報が入っている
今まではソースから機械語を直接作っていて、リンクが必要ではなかったのでobjは出てきていなかった
bim 必要なobjを全部くっつけた(リンクした)機械語
著者が考案したファイル形式。binary image
OSが必要とする形式にはなっていない不完全な状態
kadoyau.icon ファイルが1つの時にbimは必要なの?
直接objとアセンブラで描いた(asmhed.bin)をくっつけられないのか?
すぐ後で2つになっている
hrb
bimはOS(今回ははりぼてOS)が必要とする形式への加工をする必要がある
加工の例
識別用ヘッダの付与
圧縮
アセンブラで関数を作ってC言語から呼び出す
nasからobjを作っている
C言語ではHLT命令を入れることができないので、アセンブラでかいてCから呼び出す Chapter 4 C言語と画面表示の練習
C言語からメモリに書き込みたい(harib01a)p.85
VRAMに直接書き込む命令_write_mem8を作る
C言語と連携する場合はEAX, ECX, EDXの3つだけは値を変更しても良い
それ以外はC言語部分の機械語がC言語にとって必要な値を記憶させているのでwriteしてはいけない
インテルCPUの変遷
8086 → 80186 → 286(16bit) → 386(32bit) → 486 → Pentium → PentiumPro → PentiumII →PentiumIII → Pentium4 →Itanium(64bit)→ INSTRSET命令で486用とする
このモードでも16 bit レジスタだけを使っていれば8086でも動く機械語は出力される
色を変えてみる(harib01b)
https://gyazo.com/9b117ad9640fab25cde2a17bdfdcefa1https://gyazo.com/af51a98c3c575a70f332f9c40da388a7
16パターン20回繰り返している(左の図は8パターンに見えるが拡大すると16パターンある)
黒・紺・緑・青緑https://gyazo.com/04ddfe767fd5c4892e53f3eb955ac698紅https://gyazo.com/8e472d23e16ce88e045f104d61141948紫https://gyazo.com/107036c713983f34b4fa18da1b78ed9f茶https://gyazo.com/4e6376e0346681e599aaebf5bb8eb509…
コード上は65535/16ぐらい繰り返しているはずだが、表示部は一部ということかな?
ポインタ(harib01c)
write_mem8(i, i& 0x0f)はCでいう*i = i & 0xfと投下
機械語にするとMOV [i], (i & 0x0f)
[i]はサイズを指定しないとMOV命令として成立しない char *pを宣言すれば番地(ポインタ)専用変数で、charだからサイズが指定されて有効
char *pでもint *pでも変数pのサイズ自体は4バイト。記憶したい番地のサイズは変わらない
intをchar *にキャストするのときに出ると言われるエラーがそもそもでていなかった
Chapter 5 構造体と文字表示とGDT/IDT初期化
c王造替
Chapter 6 分割コンパイルと割り込み処理
Chapter 7 FIFOとマウス制御
Chapter 8 マウス制御と32ビットモード切り替え
Chapter 9 メモリ管理
<- Oki
Chapter 10 重ね合わせ処理
Chapter 11 ついにウィンドウ
Chapter 12 タイマ-1
Chapter 13 タイマ-2
Chapter 14 高解像度・キー入力
Chapter 15 マルチタスク-1
Chapter 16 マルチタスク-2
Chapter 17 コンソール
Chapter 18 dirコマンド
Chapter 19 アプリケーション
Chapter 20 API
Chapter 21 OSを守ろう
Chapter 22 C言語でアプリケーションを作ろう
Chapter 23 グラフィックいろいろ
Chapter 24 ウィンドウ操作
Chapter 25 コンソールを増やそう
Chapter 26 ウィンドウ移動の高速化
Chapter 27 LDTとライブラリ
Chapter 28 ファイルと日本語表示
Chapter 29 圧縮と簡単なアプリケーション
Chapter 30 高度なアプリケーション
Chapter 31 開発を終えた後で
全体を通して困ったこと
ソースコードのエンコーディングがSJISなのでVSCodeで開くと毎回文字化けする