個人用雑記

勉強したことを書いていければなーと

30日でできる!OS自作入門(Day 7)

Day 6の勘違いについて

Day 6でマウスが動かないのは動きに対応した画像の移動を作成していないからだと思っていたが、そもそもまだマウスの割り込みすら受け取れない設定だったらしい。ちなみにマウスを動かせるのはDay 8。

キーボードの入力

Day 6ではキーボードの割り込みを受け取ることには成功したわけだが、肝心の何のキーが押されたかを受け取れていないし、何なら一度割り込みが発生したらそのあとずっとHLT命令を実行しているため何もできなくなる。そこで、まずはマウスより先にキーボードの入力を受け取れるように変更する。(これが結果的にマウスの割り込みを学ぶにあたって力になる。)
そもそも、今のコードでは割り込みを一回しか受け付けられないのは割り込みを受け取ったことをPICに返していないからで、割り込みが発生して処理している間は他の割り込みができない仕様になっているからきちんと割り込みを受け取ったことを教えなければいけない。また当然ながら割り込みを受け取ったことはできる限り早くPICに伝え、次の割り込みに対して受け取れる準備をしなければならないため、割り込みでの処理は割り込みを先に終わらせてから実行するべきということになる。

FIFOを使う

割り込み発生時のレジスタの値はスタック、つまりFILO型のデータ構造に収納したわけだが、割り込みの処理はFIFO型のデータ構造で行わなければならない。そうしないといつまでも最初の割り込みでやりたかったことが行われないかもしれないし・・・
可能であればキューにポンポン入れていきたいけれど、そんな便利なデータ構造はない。という感じなのでとりあえずリングバッファを使って対処する。(とはいえバッファサイズを超えた時は拡張するわけではなく諦めてもらうコードになっているけれど)
この辺はまぁ次にデータを入れる位置と、次に取り出すべきデータがどこに入っているかがわかればなんとかなるので単純な実装で実現できる。そして割り込みが発生した時はとりあえずバッファにデータを入れるところまでやっておけばあとは割り込みが発生していない時に適宜そのデータを処理すればいいことになる。

マウスにも拡張する

じゃあすぐにマウスにも適用できるかというとそうでもなくて、マウスはキーボードと違って2つの装置に割り込みの許可をしなくてはいけないらしい。具体的には、
マウス→マウスの制御回路→キーボードの制御回路→CPU
という構造になっていて、まず先にキーボードの制御回路でマウスの制御回路の許可を出してからマウスの制御回路でマウスの許可を出すという手順が必要になる。普通にめんどいし、順番を変えてしまうとマウスの割り込みがキーボードの制御回路よりも先に来た時にうけとれないことになっちゃう。
とはいえ、割り込みの許可さえ出せればあとはキーボードのデータ受け取りとほとんど同じように動かすことができる。違うところとしてはマウスが接続されているPICの位置がCPU→IRQ-2→IRQ-15となっているから、割り込みを受け付けたことをIRQ-15に知らせた後にIRQ-2にも知らせないといけないことくらい。

Day 8へ

表面上は大して何もやってないように見えるけど裏ではOSにほぼ必須といえる機能を作っていて、縁の下の力持ち感がすごい。
エミュレータでマウスぐりぐりしながらキーボード連打しても適切に動いてるしCPUの速さには勝てなかったよ・・・
Day 8ではついにマウスを動かせるようになるらしいけど、先にようやく1週間分終わったし1週間の総まとめみたいなのを作りたい気持ちもある。

そして相変わらず画面の進捗がないので写真もない。

30日でできる!OS自作入門(Day 6)

ファイルの分割

今までは一つのファイルに全部書いてきたけど、さすがに長くなってきたので分割。実際、自分で何かのプログラムを書く時も基本的にまずメインとなるファイルに全部書いていって、ある程度たまったら必要に応じたファイルへ分割するって方法の方がやりやすいと思う。(それがいいのかはわからないけど・・・)今回は描画関係のファイル、Day 5で出てきたGDT・IDTとかのファイル、それ以外のファイルの3つに分割。
Makefileがあればコマンドは同じまま複数のファイルを同時にコンパイルできるので特につらいことはない感じ。個人的には分割コンパイルの時は同じヘッダファイルを余計に複数回読みこんで時間がかかるのは割けるようにしなきゃなということは一応毎回気を付けている。(#ifndef等でのインクルードガード)

Day 5の続き

Day 5ではGDTとIDTの初期化をしたかったわけだけど、その説明の残りから。だけど、Day 5でほとんど理解してないままDay 6に来たので前回のとまとめて覚えることにした。

GDT・IDTの初期化

まず、GDTの8バイトの中身とIDTの8バイトの中身を構造体として作成。ここでGDTの8バイトは{セグメントの大きさはどのくらいか、セグメントがどの番地から始まるか、セグメントの管理用属性}をそれぞれ20bit、32bit、12bitで表していて、昔との互換性を保つために各bitを格納する位置についてはいろいろめんどくさいことになっているらしい。IDTの8バイトも基本的には似たような感じ・・・
で、このセグメントの情報を書き込む関数の説明が正直覚えないで毎回読み直したほうがマシという感じの情報量なのでとりあえず諦め。簡単に言えば、それぞれの対応したビットを頑張って建てていく感じ。(そもそも今の時代は64bitだし、知っていても使えるとは限らないのではという感じだし・・・)
とはいえセグメントの情報をどんなふうに書き込むのかのイメージはだいぶついたのできっと大丈夫。作っているのがOSであって渡されるのはプログラムのセグメントの情報ということを念頭に頑張れば理解が少しできた。

PIC初期化

GDT・IDTの初期化と同様にPICというものも初期化しないといけないらしい。PICは各割り込みを発生させるデバイスの割り込み信号をCPUに渡す役目を担っている装置。CPU自体は割り込みを1つしか扱えないから複数のデバイスには対応できなくて、PICのおかげで複数のデバイスに対応できる感じっぽい。初期化の内容自体は基本的に仕様でほとんど決まっていて、特に自分が扱う部分はあんまりなかった。いやまぁ、仕様については全然知らないのだけれど・・・
逆にOSごとに設定するのはデバイスからの信号をそれぞれどの割り込み番号としてCPUに通知するかを決めることくらいで、これはPICがCPUに対しては0xcd(=INT命令) 0x??(=割り込み番号、設定できる)という2バイトの命令を渡して、CPUはこの2バイトの機械語をそのまま実行する仕組みになっているため。
こうしてキーボードやマウスといったデバイスをそれぞれ割り込み番号に割り当てればそれに対応した割り込みを受け付ける関数を作ることができるようになる。

割り込みハンドラについて

割り込みが発生したら対応した関数を呼び出してその関数に実行したい内容を書けばいいんだけど、割り込みの終了時にRET命令ではなくIRETD命令を実行しないといけないらしい、何その命令は・・・
IRETD命令を実行しなきゃいけないけれど、それだけを実行すればいいというわけでも無くて、割り込みが発生したら一回今あるレジスタの中身をとりあえずスタックにPUSHして割り込みに対応した関数が終わったら全部POPするという動作が必要。考えてみれば単純で、割り込みと言っている時点でそれまでの処理は一旦置いておいて後でまた再開できるようにしないといけないから、もし割り込みのせいで中身が変わったまま再開したら大変なことになるというイメージ。
あとは今作成した関数をIDTに登録すればはれて外部装置から割り込みを発生させられるようになる。

割り込みは発生するけど・・・

キーボードからの入力は画面に依存しないのでこれで割り込みが発生していることはわかるけど、マウスの移動についてはそもそも対応したマウスの画像が動かないから全くわからない。この辺のマウスの制御についてはDay 7へ・・・

Day 7へ

Day 5の時よりはGDTもIDTも理解している(気がする)。わからないことだらけであるのは事実だし、特にレジスタの名前と対応した内容はそろそろ整理しないとわからないレベルになってる気がする。
この本を買ってそろそろ20日以上は経つけどようやく7日目に入るという事実が怖いんだけど、この本を本当に30日で終わらせられる人は何者なんだろう・・・

30日でできる!OS自作入門(Day 5)

またもや

大分Day 4から期間が空いてしまった・・・今回は完全に怠慢で、本自体はもう6日目の半分くらいまでは読み終わってたり。

構造体

さすがに構造体はすでに勉強してるし、わかっているつもりでいるのでここは流し読み。ただ、はじめ(*binfo).scrnxのようにポインタから参照する書き方で、これで教えるの??と思っていたらその次ページにちゃんとbinfo->scrnxの説明があった。さすがに矢印表記も教えるよね・・・

構造体といえば有名なアレ

※自分の知識を述べているだけなので正確性の保証は0。真相が気になったら調べてください。
OS自作入門とは本質的に何も関係ないけど、例えば下記のコードのような二つの構造体SizeTest1とSizeTest2があった場合、

/*前提としてintは4バイトcharは1バイトとする*/
typedef struct{
    int hoge;
    char fuga;
} SizeTest1;

typedef struct{
    int hoge;
    char fuga1, fuga2, fuga3, fuga4;
} SizeTest2;

上記二つの構造体のサイズはそれぞれどうなるかってお話。直感で言えばintは4バイト、charは1バイトなんだから上は5バイトで下は8バイトのように見えるけど、試しに↓こんなコードで試してみると、

#include<bits/stdc++.h>
using namespace std;

typedef struct{
    int hoge;
    char fuga;
} SizeTest1;

typedef struct{
    int hoge;
    char fuga1, fuga2, fuga3, fuga4;
} SizeTest2;

int main(void){
    cout << sizeof(SizeTest1) << endl;
    cout << sizeof(SizeTest2) << endl;
}

出力結果はどっちも8になる。
こうなる原因は探せばいくらでも出てくると思うけど、アライメント的に4バイトのintと1バイトのcharを一緒の構造体に入れると、大きいサイズの4バイトを基準にしてメモリを取るから、charみたいに1バイトだけつかうと後ろの3バイト分には基本的にもう何も入れられなくてメモリの無駄遣いになりがちっていうお話でした。(逆に言えばSizeTest2みたいにchar4つ入れることはできるしメモリ的に無駄はない。)

だから↓みたいなコードはメモリを余分に使っちゃうから気をつけようね。

/*SizeTest1のサイズは8バイトではなく12バイト*/
typedef struct{
    char fuga1;
    int hoge;
    char fuga2, fuga3, fuga4;
} SizeTest1;

ちなみにこの処理は言語側の規定ではなくて処理系依存らしい。
だいぶ余計な文章が長くなったけど、本題に戻る。

文字出力

Day 4で色のついた四角形はだせるようになったわけだけど、四角形が出せたところで文字にはならないのでOSとしてはまだまだ。しかし、Day 2あたりでやったような文字出力はBIOSの力を借りたからできていただけで、今はもう使えない。文字自体は例えばAならAの形に添った図形と考えれば出力できなくはなさそう・・・
とはいえ毎回文字の形に合わせて図形を作ってその部分だけ色付けて出力なんてやっていられないので、それぞれの文字に対応した出力を先に作ってしまう=フォントを作ることになる。
話はそんなに難しくなくて、下記のように1画素ずつ考えて黒い所と白い所を別の記号にして後はそれに従って色をつけるようにするだけ。
f:id:rei_624:20190423215610p:plain

でもこの本はあくまでOSの自作がメインであってフォントの自作をしたいわけではないのでとりあえずはすでにあるフォントを流用。
そんな感じで文字でも文字列でも出力できるようになった。

変数の値の表示

え、ふつうにprintf("%d",a);のように書けばいいじゃんと考えてしまいがちだけど、printfはOS依存なのでOS自作では使うことができない。一方でsprintfはあくまで指定したメモリの番地に変数の値を指定した書式で文字列として格納するだけだからOSに関係なく用いることができる。(つまり変数の値を表示するにはsprintfと格納した値を表示する別の関数をセットで使う必要がある。)

マウスカーソルも表示できる

マウスカーソルも図形として書くことができるから文字と同じように画面に出力させられる。試しに付属のマウスを少し改変して出力してみた。
f:id:rei_624:20190423220400p:plain

画面の画素数がそもそも少ないからなんか大きく見えるのは気のせい。
一点気をつけなければいけないのは所詮マウスカーソルの形をした図形を出力しただけであって、マウスカーソルを移動させられるわけではないということ。それに今のままだと文字に被った時どっちが先に描画されるかで変わっちゃいそうだし・・・

GDTとIDT

Day 5の内容は実質これだけという気がしなくもない。ちなみに読むまでこの二つの単語はどっちも聞いたことすらなかった。
簡単に言えば(簡単な内容ではないのだけれど。)、GDTはセグメントの設定一覧でIDTは割り込み機能の設定一覧。。。いや、わからない。わからないのでここから数日間の内容を読みつつ理解できなかったらまた帰ってきて勉強しなおす形を取らざるを得なかった。具体例が出てきたらきっとわかる。

まず、セグメンテーション。各プログラムで毎回そのプログラムがメモリのどの番地に読み込まれるのか指定してたらマルチタスクにおいて制限ばかりだし、下手をしたらメモリの衝突まで起こる。そこでセグメンテーションという機能を用いると、メモリを切り分けてそれぞれの先頭アドレスを仮想的に0として扱えるようになる機能。これがあればどんなプログラムでも同じ書き方ができる。というかできなかったら怖くてプログラムなんてできない。
さてここでわからないことが、それぞれのプログラムで必要なメモリはばらばらなのに先にセグメントの一覧を作らなければならないのかという点。解決していない。わからない。また明日以降で・・・
というよりは初期化段階では中身が決まってなくてよくて、後から変更する形なのかな・・・わからない・・・

次に割り込み命令。先ほど出てきたマウスカーソルの移動やキーボードの入力等々は全部いつ起こるかわからないけどいつも入力があるか見るわけにはいかないから、この割り込み命令を使うことでそれぞれの入力に対応できるようになるという感じ。この内容は6日目にあるらしいのでまだ。

Day 6へ

こんな理解で先に進んでいいのだろうかという気しかしないけれど、本を読んでもこれ以上でもこれ以下でもない感じだし、進むしかなさそう。というか構造体の話に対してGDTとIDTの話が短すぎる。

余計な構造体の話を書いていたらいつもよりも長くなってしまった・・・

30日でできる!OS自作入門(Day 4)

C言語入門

さすがにC言語は多少わかるので流し読みで飛ばした。

ポインタについて

ポインタも(自分的には)ある程度理解している(と思っている)ので、読み飛ばそうかとも思ったが、ちゃんと読んだ。僕も最初にC言語を勉強した時は何言ってんだこれ?適当にやったら動いたけどどうしてなのか全然わからんwといった感じで、1年後くらいになってようやく少しずつ理解ができたかな・・・

とくにpとp*の違いについてを、アセンブラでいうECXという"レジスタ"と[ECX]というECX番地の"メモリ"なのかという点で大きく異なっているという説明は、非常に的を射ていながらも初学者にもわかりやすい説明ですごいと感じた。
またちょっと前にTwitterでバズっていたa[2]と2[a]という書き方は本質的に同じという部分も、そりゃそうだよな~と納得ができる感じ。

画面の色

BIOSで指定したモードは8bitカラーモードなので255種類しか色を用意することができない。ただ8bitカラーモードでは0~255に対して対応する色番号をプログラマーが勝手に決められるそうで、例えば色番号0を#000000、色番号255を#ffffffのように決めることが可能。
筆者曰くOSらしい画面にはとりあえず16色あれば十分だとか・・・(これは当時のWindowsがXPとかその辺だったからなのでは・・・)
あるに越したことはないけど、設定方法がわからないのでこれもいつか自作OSを作る時まで投げとこ。

色番号の設定

画面の色が255種類で表さなければならないけど、色自体は指定できることはわかった。ただ色番号を設定するのはC言語だけでは足りなくて、別のアセンブラを書かなければならない。色番号の対応表自体はとりあえずRGBの3つに分けたものを配列に入れるだけ(つまり16色であれば[16 * 3]としてr,g,b,r,g,b...の順に入れていく)で大丈夫。次にこれをアセンブラで書いた関数に渡していくことで色番号の指定が可能になる。
で、肝心のアセンブラで何を書くのかというと、番号で指定した装置にデータを送るという行為。そして画面出力に対応した番号にさっき決めた色番号を送ることで色番号の設定ができる。

ただし、この色番号の設定をしている間は割り込みを禁止しなければならず、割り込みを禁止するためにはその前に現在の割込み許可フラグの値を記録しておく必要がある。(もしかしたらすでに禁止であったかもしれないのでね・・・)今回でもまだ割り込み処理とは何かには言及されなかった。ちなみにこの割り込みフラグはEFLAGSという特別なレジスタの第9ビットが担当しており、やはりアセンブラでなければこの値を読み書きができない。
そしてEAXレジスタに直接EFLAGSの値を入れる命令は存在しないのでここで急にスタックが出てきた。スタックにEFLAGSをPUSHしてそこからEAXへPOPするという動作を通してEAXへEFLAGSの値を入れられるようにしているらしい。

こうして色の指定ができるようになったことでカラフルなOSモドキを作成できるようになった。
f:id:rei_624:20190416021228p:plain

色がつくとさすがに進捗が生まれた気になる。自分では何もしてないのだけれど。

色がついたら当然それっぽい見た目になるように配置することもできる。
f:id:rei_624:20190416021907p:plain

もちろん今は押してもキーボードを触っても何も反応しない本当の意味でのはりぼてOSだけれども。
でもなんか、これを見ると16色じゃ少なくない・・・?という気になるのは僕だけなのだろうか。

Day 5へ

5日目は構造体と文字表記とGDT/IDT初期化らしいけど、ついに聞いたことのない単語が来てしまった。はやめに理解できると、いいな・・・

30日でできる!OS自作入門(Day 3-2)

32bitモード

雑に32bitの利点
・単純に表せる数が増える
・使えるメモリがいっぱい増える
・保護機能を入れ込むことができる
欠点
BIOSを利用できなくなる(BIOSは16bit用の機械語で書かれているから)
16bitモードと32bitモードでは機械語の命令番号も解釈の方法も異なるため全く別物と考えたほうが良い。つまり、32bitモードに移ってからはBIOSは使えなくなるため、BIOSでやっておきたいことは先にやり終えてから32bitモードへ移らなければいけない。

BIOSでやっておきたいこと
・画面モードの設定
・キーボードの状態の取得
・それらに関する情報の保存

C言語の導入

32bitモードに移るとついにC言語でOSを作ることができるようになる。。。が、実はC言語への移行はそう簡単な話ではない。今はまだ難しいことだらけなので後回し。
C言語とブートセクタを組み合わせて使うためには、機械語へ出力(順番的には.gas(gcc系のアセンブラ)→.nas(nask,nasm系のアセンブラ)→.obj(オブジェクトファイル)→.bim(本独自の形式、オブジェクトファイルは単体では動かないので必要な情報を加えたもの)→hrb(欲しかった元のC言語機械語Ver.))する必要がある。
こうして出来上がった機械語をブートセクタの機械語とくっつければC言語で開発したOSが遂に完成する。難しい・・・

C言語でHLT

C言語本来にはHLT命令がないため、アセンブラでHLT関数を定義し、それをC言語のプログラムで利用するという操作をする必要がある。でも、それをしてでもHLT命令を実行させる意味はたくさんある。多分。
アセンブラで関数を定義させておけばC言語側ではとりあえず同じ名前の関数を宣言するだけでよい。

Day4 へ

明日はC言語と画面表示の練習とのことです。C言語自体はチョットワカルくらいなのでどちらかというと画面表示の方に重点を置くべきかなといった感じですね・・・

二つにブログを分割したら思いのほか3-2が短くなってしまった。
そして見返したら何の画像もなかった。(添付するようなものもとくにはない)

30日でできる!OS自作入門(Day 3-1)

さっそく・・・

3日目にして毎日投稿に失敗しました・・・というのも、本自体はちゃんと3日目のタイミングで読んでいたけど内容を理解するのが難しかった&調べていた&大学の講義が始まって忙しくなったという感じです。(数日後、これを書いている時に再度読んでみたら結構すんなり理解出来て感動しています。)

というのも、本の内容が本当のIPL(初期プログラムローダー)を作るということで、今までのようにBIOSが読み込んでくれる512バイトの次の512バイトを読み込んでみるという内容だったのですが、そもそもこの512バイトごとの分け方(=1セクタ)がフロッピーディスク依存なのでは・・・?と疑問に思ってしまったわけです。
この本は書かれた年的にどうしても現在のPCとは異なる部分が結構あって、例えば今ではOSは64bitが当たり前になりつつある中16bitや32bitが当たり前であったり、当然のようにフロッピーディスクを使用したり・・・などなど。実際問題今となってはフロッピーディスクを入手することの方が困難で、もし仮にフロッピーディスク依存の実装であるなら現在の規格にあった知識にすべきだと思ったわけです。

で、結論から先に述べると、現在のHDDも(というか自分のSSDは)1セクタが512バイトでした。(下の画像のセクターあたりのバイト数
)一応、4Kセクタという規格も広まっているみたいです。
f:id:rei_624:20190411015646p:plain

そうであるなら話は簡単で、本の通りに勉強すればいいだけです。

と思いきや・・・

いきなりフロッピーディスクの仕様の解説が始まりました。
シリンダだったりヘッドだったりセクタだったり・・・
で、今の一般的なHDDではどうやらフロッピーディスクのシリンダがトラックにあたり、このトラックを複数重ねたものがシリンダになっているようです。(ややこしい・・・)

このままでは遅々として先に進めないので、いったん本の通りにフロッピーディスクを仮定して進めていき、知識が身についてきていつか自分でOSを作る時に改めて仕様とにらめっこしようと決めました。わからないことはそのうちわかればいい。。。

ディスクからメモリへ

INT 0x13という命令文で指定したディスクの位置から指定したメモリの位置へ読み込みと書き込みができる。(ソースコードを見る限り一回にごそっと1セクタ読み込むことができるみたい・・・?)
ディスクの位置はフロッピーディスクの場合はドライブ、ヘッド、シリンダ、セクタの指定で行う。メモリの位置はEXレジスタとBSレジスタで行う。

フロッピーディスクを全部読み込むには

まずはセクタを1ずつ増やしつつ読み込んでいく。1シリンダ当たり18セクタあるから18セクタまで読み込んだらシリンダを1増やす。
これを今度はシリンダが80あるから80シリンダまで読み込む。80シリンダまで読み込んだら裏側でも同じことをする。といった感じで順々に読み込むことができる。

OS本体を書く

ついにブートセクタを卒業です!
ブートセクタとは別にOS本体となるアセンブリを書いていく。(例ではHLT命令のみ)このOS本体とさっきまで書いていたフロッピーディスクを全部読み込むブートセクタを同じイメージファイルとして保存することでブートセクタからこのOSを実行させることができるようになる。

といえば聞こえはいいが、実はそこまで簡単に行く話ではなくて、このOS本体がどこに保存されるのかという情報がとても大事になってくる。なぜなら、ブートセクタを起動した後このOS本体の入ったアドレスに飛んでこなければならないから。というわけでOS本体とブートセクタを組み合わせたイメージファイルをバイナリエディタで覗いてみて、格納された位置を探し当てて初めてOSをブートセクタから起動できるようになる。

Day 3-2

内容が濃くてどんどん記事が長くなっていくので分割してDay 3-1とDay 3-2としたいと思います。
Day 3-2では32ビットモードへの準備といよいよ開発言語にC言語導入の部分を書く予定です。

読むスピードに対して備忘録つけるスピードが遅すぎる。。。

30日でできる!OS自作入門(Day 2)

テキストエディタの紹介

2日目の冒頭はテキストエディタの紹介としてTeraPadがおすすめされていました。僕のおすすめはVScodeです。

それが言いたかっただけです。

1日目のアセンブラ続き

今の知識量ではまだソースコードのほんの一部分しか理解できないので、とりあえずそのわかる部分をより分かりやすいアセンブラにしていく。
アセンブラの命令の内容がつらつらと書かれているけれど、ある程度は英単語から取られているからそれなりには理解できるなーといった感じ。MOV(E)とかADDとかC(O)MP(ARE)とかとか。(この辺は以前使ったKUE-CHIP2という教育用マイコンアセンブラと似たような命令だったから直感的にもわかりやすい。)

ソースコードを読むと、どうやら画面に出力したい内容をプログラムの下の方に書いておいて、そこから一文字ずつ読んで画面に表示して次の文字に移動ということを繰り返している感じらしい。ただこのままだとプログラムが終了しないから一応0を置いておいて0だったら終了、つまりHLT命令に移動するようにしているっぽい。

こういうソースコードで何をしているかがわかったら、次にやることはとりあえず改変して遊ぶことだと思っているので、やってみました。
f:id:rei_624:20190409013233p:plain

見事に失敗しました。(「"」の出力のためにわざわざアスキーコード調べたのに・・・)
ぶっちゃけ直す方法は全くわからないですけど、今はそれでいいような気がするのでとりあえず失敗できたということを喜ぶ感じで・・・(原因はおそらく改行した時に前の行の終わりのところが次の行の開始になるからだと考えてます。)

[追記](2019.4.09)
一応バックスペースのアスキーコードを戻したい回数表示することで解決はしました。(少なくとも正規の解決方法ではない。)
それともデフォルトの改行の仕様は同じ位置の1行下から始めることになっていて、自動的に左側に戻してくれる機能はOSで実装されているとか・・・?
f:id:rei_624:20190409144841p:plain

[再追記]
解決しました。Windowsの改行コードはCRLFに対してLinuxの改行コードはLFだからGitHubなんかで共同で作業しようとすると困る!という話を耳にしたことはあっても、CRLFとLFの違いについては調べなかったのがあだになった感じ・・・
アスキーコード表の0x0d(=CR、キャリッジリターン)がカーソルを文頭に持ってくれる文字コードのようで、WindowsのCRLFというのはカーソルを先頭に持ってきて改行、Linuxではカーソルを先頭に戻さずに改行という意味で異なっているっぽい。
今回みたいに次の行で先頭から始めたい場合はDB 0x0d, 0x0aのようにCRしてからLFすることで解決できるみたい。

イメージファイルをブートセクタだけにする

OSは起動時に冒頭512バイトしか読み込めないから、まずはその512バイト部分にあたるブートセクタをとりあえずアセンブラで書かなければならない。とはいえ今までのソースコード自体にこのブートセクタ部分は含まれていたので、むしろ余計な部分を除いて最もすっきりとしたソースコードにしたという感じ。

Makefileの準備

毎回毎回naskでアセンブラコンパイラして(Virtual Boxでは必要ないけれど)それをディスクイメージとして焼いて・・・といった諸々のコマンドを一つのコマンドでできるようにMakefileを作る。自分の環境では精々naskで.nasファイルをコンパイラするだけなので必要ないかなーという感じ・・・(Virtual Boxの立ち上げまでやってくれるMakefileなら需要はあるかもしれない。)

Day 3へ

3日目の最初を見る限り内容がかなり濃そうなのでゆっくり数日かけて読んでいきたいなーと思います。
アセンブラ、よかったですね。