30天自制操作系统---第3天
一,制作真正的IPL(启动程序装载器)
今天的目的是将昨天的启动程序装载器来装载程序。
①:磁盘最初的512字节是启动区。为了装载下一个512字节内容的程序,对之前的程序进行修改,得到了今天的harib00a程序;
②:缓冲区地址 是内存地址。将磁盘里面的程序加载到内存中
; haribote-ipl ; TAB=4 ORG 0x7c00 ; このプログラムがどこに読み込まれるのか ; 以下は標準的なFAT12フォーマットフロッピーディスクのための記述 JMP entry DB 0x90 DB "HARIBOTE" ; ブートセクタの名前を自由に書いてよい(8バイト) DW 512 ; 1セクタの大きさ(512にしなければいけない) DB 1 ; クラスタの大きさ(1セクタにしなければいけない) DW 1 ; FATがどこから始まるか(普通は1セクタ目からにする) DB 2 ; FATの個数(2にしなければいけない) DW 224 ; ルートディレクトリ領域の大きさ(普通は224エントリにする) DW 2880 ; このドライブの大きさ(2880セクタにしなければいけない) DB 0xf0 ; メディアのタイプ(0xf0にしなければいけない) DW 9 ; FAT領域の長さ(9セクタにしなければいけない) DW 18 ; 1トラックにいくつのセクタがあるか(18にしなければいけない) DW 2 ; ヘッドの数(2にしなければいけない) DD 0 ; パーティションを使ってないのでここは必ず0 DD 2880 ; このドライブ大きさをもう一度書く DB 0,0,0x29 ; よくわからないけどこの値にしておくといいらしい DD 0xffffffff ; たぶんボリュームシリアル番号 DB "HARIBOTEOS " ; ディスクの名前(11バイト) DB "FAT12 " ; フォーマットの名前(8バイト) RESB 18 ; とりあえず18バイトあけておく ; プログラム本体 entry: MOV AX,0 ; レジスタ初期化 MOV SS,AX MOV SP,0x7c00 MOV DS,AX ; ディスクを読む ; ===============================这次添加的内容START================================= ;这里就开始了读写磁盘的方式,下面就会更具 驱动器 柱面 扇区 磁头 确定最终读取的位置 MOV AX,0x0820 MOV ES,AX MOV CH,0 ; 柱面0 CH表示的是柱面号 MOV DH,0 ; 磁头0 磁头号 MOV CL,2 ; 扇区2 CL扇区号 MOV AH,0x02 ;AH=0x02 : 读盘(0x03是写磁盘) MOV AL,1 ;1个扇区 AL处理对象的扇区数;(只能同时处理连续的扇区) MOV BX,0 MOV DL,0x00 ;A驱动器 INT 0x13 ;调用磁盘BIOS 注释:调用BIOS磁盘0x13号函数。 JC error ;注释:这次的新指令JC:大意是:如果进位标志是1的话,就跳转。 ;这里特别解释一下:通过上面一连串的配置,再执行INT 0x13 我们就会去读磁盘内容(为什么是读,因为我们AH那个地方配置的0x02),如果读磁盘成功了,那么我们就返回0,如果错误就会返回1。 ;我们这里可以这样理解,从 MOV AX,0x0820 这里到 MOV DL,0x00 都是我们传递给INT 0x13函数的参数(C语言式理解),那么JC error 就是对函数返回值的判断。 ;那我们传递给函数的参数究竟什么意思呢?主要是告诉这个函数我到底去哪个位置读取我想要的数据呢? 毕竟磁盘大如海,想要知道具体去那一片数据还是不容易的。 ;下面来看怎么确定读取磁盘想要的位置:①首先加入有多个驱动器,那么我们要指定从哪个驱动器读取,这就是DL干的事;②然后00000 ;======================================END=========================================== ; 読み終わったけどとりあえずやることないので寝る fin: HLT ; 何かあるまでCPUを停止させる JMP fin ; 無限ループ error: MOV SI,msg putloop: MOV AL,[SI] ADD SI,1 ; SIに1を足す CMP AL,0 JE fin MOV AH,0x0e ; 一文字表示ファンクション MOV BX,15 ; カラーコード INT 0x10 ; ビデオBIOS呼び出し JMP putloop msg: DB 0x0a, 0x0a ; 改行を2つ DB "load error" DB 0x0a ; 改行 DB 0 RESB 0x7dfe-$ ; 0x7dfeまでを0x00で埋める命令 DB 0x55, 0xaa
二:试错
目的:就是为了防止再软盘出现偶尔错误的时候,程序不会立即终止,仍然去尝试再次读取磁盘,才有了第二节的程序:
注释:JNC:进位标志是0的话跳转 JAE大于或等于时跳转
; haribote-ipl ; TAB=4 ORG 0x7c00 ; このプログラムがどこに読み込まれるのか ; 以下は標準的なFAT12フォーマットフロッピーディスクのための記述 JMP entry DB 0x90 DB "HARIBOTE" ; ブートセクタの名前を自由に書いてよい(8バイト) DW 512 ; 1セクタの大きさ(512にしなければいけない) DB 1 ; クラスタの大きさ(1セクタにしなければいけない) DW 1 ; FATがどこから始まるか(普通は1セクタ目からにする) DB 2 ; FATの個数(2にしなければいけない) DW 224 ; ルートディレクトリ領域の大きさ(普通は224エントリにする) DW 2880 ; このドライブの大きさ(2880セクタにしなければいけない) DB 0xf0 ; メディアのタイプ(0xf0にしなければいけない) DW 9 ; FAT領域の長さ(9セクタにしなければいけない) DW 18 ; 1トラックにいくつのセクタがあるか(18にしなければいけない) DW 2 ; ヘッドの数(2にしなければいけない) DD 0 ; パーティションを使ってないのでここは必ず0 DD 2880 ; このドライブ大きさをもう一度書く DB 0,0,0x29 ; よくわからないけどこの値にしておくといいらしい DD 0xffffffff ; たぶんボリュームシリアル番号 DB "HARIBOTEOS " ; ディスクの名前(11バイト) DB "FAT12 " ; フォーマットの名前(8バイト) RESB 18 ; とりあえず18バイトあけておく ; プログラム本体 entry: MOV AX,0 ; レジスタ初期化 MOV SS,AX MOV SP,0x7c00 MOV DS,AX ; ディスクを読む MOV AX,0x0820 MOV ES,AX MOV CH,0 ; 柱面0 CH表示的是柱面号 MOV DH,0 ; 磁头0 磁头号 MOV CL,2 ; 扇区2 CL扇区号 ;===============================这次添加的新内容START================================= MOV SI,0 ; 记录失败次数的寄存器 retry: MOV AH,0x02 ; 读盘(0x03是写磁盘) 注释: 看来每次读写数据,都要进行AH寄存器的配置,不像上面CL,可以保存,只配置一次 MOV AL,1 ; 1扇区 注释:这里是读写扇区的数目,和上面的CL是不同的 MOV BX,0 MOV DL,0x00 ; A驱动器 INT 0x13 ; 调用磁盘BIOS JNC fin ; 没出错的话,就跳转到fine ADD SI,1 ; 往SI+1 CMP SI,5 ; 比较SI与5 JAE error ; SI >= 5 大于5时跳转到error MOV AH,0x00 MOV DL,0x00 ; A驱动器 INT 0x13 ; 重置驱动器 JMP retry ;======================================END=========================================== ; 読み終わったけどとりあえずやることないので寝る fin: HLT ; 何かあるまでCPUを停止させる JMP fin ; 無限ループ error: MOV SI,msg putloop: MOV AL,[SI] ADD SI,1 ; SIに1を足す CMP AL,0 JE fin MOV AH,0x0e ; 一文字表示ファンクション MOV BX,15 ; カラーコード INT 0x10 ; ビデオBIOS呼び出し JMP putloop msg: DB 0x0a, 0x0a ; 改行を2つ DB "load error" DB 0x0a ; 改行 DB 0 RESB 0x7dfe-$ ; 0x7dfeまでを0x00で埋める命令 DB 0x55, 0xaa
本节新添加的代码转化成C语言,大致如下(仅供参考,毕竟也是个菜鸡)
ErrorHandling() { static int SI=0; AH=0x002; AL=1; BX=0; DL=0x00; BOOL VAL=ExecutivDrive() ; if(FALSE == VAL) { 执行fine函数; } else { SI++; } if(SI >= 5) { 执行error函数; } else { AH=0x00; DL=0x00; BOOL VAL =ExecutivDrive();//执行驱动器 if(TRUE == VAL) { ErrorHandling(); } } } ExecutivDrive() { INT 0x13; }
三,读到18扇区
这节的目的主要就是教会我们怎么利用循环读写其他扇区 柱面的内容。 同样的下一届的内容也就自然会了。
; haribote-ipl ; TAB=4 ORG 0x7c00 ; このプログラムがどこに読み込まれるのか ; 以下は標準的なFAT12フォーマットフロッピーディスクのための記述 JMP entry DB 0x90 DB "HARIBOTE" ; ブートセクタの名前を自由に書いてよい(8バイト) DW 512 ; 1セクタの大きさ(512にしなければいけない) DB 1 ; クラスタの大きさ(1セクタにしなければいけない) DW 1 ; FATがどこから始まるか(普通は1セクタ目からにする) DB 2 ; FATの個数(2にしなければいけない) DW 224 ; ルートディレクトリ領域の大きさ(普通は224エントリにする) DW 2880 ; このドライブの大きさ(2880セクタにしなければいけない) DB 0xf0 ; メディアのタイプ(0xf0にしなければいけない) DW 9 ; FAT領域の長さ(9セクタにしなければいけない) DW 18 ; 1トラックにいくつのセクタがあるか(18にしなければいけない) DW 2 ; ヘッドの数(2にしなければいけない) DD 0 ; パーティションを使ってないのでここは必ず0 DD 2880 ; このドライブ大きさをもう一度書く DB 0,0,0x29 ; よくわからないけどこの値にしておくといいらしい DD 0xffffffff ; たぶんボリュームシリアル番号 DB "HARIBOTEOS " ; ディスクの名前(11バイト) DB "FAT12 " ; フォーマットの名前(8バイト) RESB 18 ; とりあえず18バイトあけておく ; プログラム本体 entry: MOV AX,0 ; レジスタ初期化 MOV SS,AX MOV SP,0x7c00 MOV DS,AX ; ディスクを読む MOV AX,0x0820 MOV ES,AX MOV CH,0 ; シリンダ0 MOV DH,0 ; ヘッド0 MOV CL,2 ; セクタ2 readloop: MOV SI,0 ; 失敗回数を数えるレジスタ retry: MOV AH,0x02 ; AH=0x02 : ディスク読み込み MOV AL,1 ; 1セクタ MOV BX,0 MOV DL,0x00 ; Aドライブ INT 0x13 ; 调用磁盘BIOS ;===============================这次添加的新内容START================================= JNC next ; 没有出错就跳转到next ADD SI,1 ; 往SI中+1 注释:把他当作C语言中的临时变量或者说静态变量就好了 CMP SI,5 ; 比较SI与5 JAE error ; SI >= 5 だったらerrorへ MOV AH,0x00 MOV DL,0x00 ; Aドライブ INT 0x13 ; ドライブのリセット JMP retry next: MOV AX,ES ; 把内存地址后移0x200 ADD AX,0x0020 ; 0x0020是十六进制下512除以16的结果。所以这里的意思就是下一个512的地方。我们知道最开始的启动区就是512,我们以512为一个扇区。 MOV ES,AX ; ADD ES,0x020 という命令がないのでこうしている ADD CL,1 ; CL+1 注释: 这里的意思是当读取一个扇区成功后紧接着读下一个扇区。 CMP CL,18 ; 比较CL与18 注释:是否18个扇区都读完了 JBE readloop ; 如果CL <= 18 就跳转到read loop 注释:小于等于就跳转 ;这一段代码主要是为了读完18个扇区,这从最后的CL 与18的比较也能看出来。如果没有读完就返回最上面,如果读完了就继续执行到下面fine中 ;======================================END=========================================== ; 読み終わったけどとりあえずやることないので寝る fin: HLT ; 何かあるまでCPUを停止させる JMP fin ; 無限ループ error: MOV SI,msg putloop: MOV AL,[SI] ADD SI,1 ; SIに1を足す CMP AL,0 JE fin MOV AH,0x0e ; 一文字表示ファンクション MOV BX,15 ; カラーコード INT 0x10 ; ビデオBIOS呼び出し JMP putloop msg: DB 0x0a, 0x0a ; 改行を2つ DB "load error" DB 0x0a ; 改行 DB 0 RESB 0x7dfe-$ ; 0x7dfeまでを0x00で埋める命令 DB 0x55, 0xaa
四,10个柱面
注释:C0-H0-S1(柱面0;磁头0,扇区1的缩写);上一节中每次王CL中+1,更改的就是扇区。这把要读柱面。可以看出,在位看书的i情况下,先行猜测,是在上一节上,在加个循环。来个cmp小于等于10 就行了。(纯属猜测,也不行改了)
; haribote-ipl ; TAB=4 CYLS EQU 10 ; 相当于宏定义,将CYLS的值等于10 ORG 0x7c00 ; このプログラムがどこに読み込まれるのか ; 以下は標準的なFAT12フォーマットフロッピーディスクのための記述 JMP entry DB 0x90 DB "HARIBOTE" ; ブートセクタの名前を自由に書いてよい(8バイト) DW 512 ; 1セクタの大きさ(512にしなければいけない) DB 1 ; クラスタの大きさ(1セクタにしなければいけない) DW 1 ; FATがどこから始まるか(普通は1セクタ目からにする) DB 2 ; FATの個数(2にしなければいけない) DW 224 ; ルートディレクトリ領域の大きさ(普通は224エントリにする) DW 2880 ; このドライブの大きさ(2880セクタにしなければいけない) DB 0xf0 ; メディアのタイプ(0xf0にしなければいけない) DW 9 ; FAT領域の長さ(9セクタにしなければいけない) DW 18 ; 1トラックにいくつのセクタがあるか(18にしなければいけない) DW 2 ; ヘッドの数(2にしなければいけない) DD 0 ; パーティションを使ってないのでここは必ず0 DD 2880 ; このドライブ大きさをもう一度書く DB 0,0,0x29 ; よくわからないけどこの値にしておくといいらしい DD 0xffffffff ; たぶんボリュームシリアル番号 DB "HARIBOTEOS " ; ディスクの名前(11バイト) DB "FAT12 " ; フォーマットの名前(8バイト) RESB 18 ; とりあえず18バイトあけておく ; プログラム本体 entry: MOV AX,0 ; レジスタ初期化 MOV SS,AX MOV SP,0x7c00 MOV DS,AX ; ディスクを読む MOV AX,0x0820 MOV ES,AX MOV CH,0 ; シリンダ0 MOV DH,0 ; 磁头0 MOV CL,2 ; 扇区2 readloop: MOV SI,0 ; 记录失败次数的寄存器 retry: MOV AH,0x02 ; AH=0x02 : ディスク読み込み MOV AL,1 ; 1个扇区 注释:这里是读写扇区的数目,和上面的CL是不同的 MOV BX,0 MOV DL,0x00 ; Aドライブ INT 0x13 ; ディスクBIOS呼び出し JNC next ; エラーがおきなければnextへ ADD SI,1 ; SIに1を足す CMP SI,5 ; SIと5を比較 JAE error ; SI >= 5 だったらerrorへ MOV AH,0x00 MOV DL,0x00 ; Aドライブ INT 0x13 ; ドライブのリセット JMP retry next: MOV AX,ES ; アドレスを0x200進める ADD AX,0x0020 MOV ES,AX ; ADD ES,0x020 という命令がないのでこうしている ADD CL,1 ; CLに1を足す CMP CL,18 ; CLと18を比較 JBE readloop ; CL <= 18 だったらreadloopへ ;===============================这次添加的新内容START================================= MOV CL,1 ;这里为什么读完18个扇区后,读下一个柱面的时候,CL先+1呢? 整个磁盘是一个循环。洗一个柱面从第一个扇区开始读写的。 ADD DH,1 ;有两个磁头,正反面,反正我是这样理解的 CMP DH,2 JB readloop ; 如果DH < 2 就跳转到readloop。 MOV DH,0 ;反面读完了,那么从正面在开始读,磁头便置零了 ADD CH,1 ;好了,柱面也开始+1了 CMP CH,CYLS ; 这里还用了一个宏定义。代表10个柱面 JB readloop ; 如果CH < CYLS 就跳转到readloop ;======================================END=========================================== ; 読み終わったけどとりあえずやることないので寝る fin: HLT ; 何かあるまでCPUを停止させる JMP fin ; 無限ループ error: MOV SI,msg putloop: MOV AL,[SI] ADD SI,1 ; SIに1を足す CMP AL,0 JE fin MOV AH,0x0e ; 一文字表示ファンクション MOV BX,15 ; カラーコード INT 0x10 ; ビデオBIOS呼び出し JMP putloop msg: DB 0x0a, 0x0a ; 改行を2つ DB "load error" DB 0x0a ; 改行 DB 0 RESB 0x7dfe-$ ; 0x7dfeまでを0x00で埋める命令 DB 0x55, 0xaa
到这里是完成了启动区的制作。其实到这里回过头来看下,作者只是将10×2×18×512=184320byte=180KB内容完整无误的装在到内存里面了。这里有个疑问:装载到类里面然后干啥? 我们的程序(C语言的main)就能运行了? 如果我的main不止这个数呢? 哦 这里只是启动区,它可以接着调用main函数? 害这里还是不理解,不能举一反三,真特么的垃圾,接着往后面看:
五,着手开发操作系统
好吧我觉的这节太扯了。表示其实没有真的看懂,大致知道怎么回事。仔细想想又不知道具体是怎么回事。
六,从启动区执行操作系统
对ORG的应用。其他的在地五节已经讲过了
; haribote-ipl ; TAB=4 CYLS EQU 10 ; どこまで読み込むか ORG 0x7c00 ; このプログラムがどこに読み込まれるのか ; 以下は標準的なFAT12フォーマットフロッピーディスクのための記述 JMP entry DB 0x90 DB "HARIBOTE" ; ブートセクタの名前を自由に書いてよい(8バイト) DW 512 ; 1セクタの大きさ(512にしなければいけない) DB 1 ; クラスタの大きさ(1セクタにしなければいけない) DW 1 ; FATがどこから始まるか(普通は1セクタ目からにする) DB 2 ; FATの個数(2にしなければいけない) DW 224 ; ルートディレクトリ領域の大きさ(普通は224エントリにする) DW 2880 ; このドライブの大きさ(2880セクタにしなければいけない) DB 0xf0 ; メディアのタイプ(0xf0にしなければいけない) DW 9 ; FAT領域の長さ(9セクタにしなければいけない) DW 18 ; 1トラックにいくつのセクタがあるか(18にしなければいけない) DW 2 ; ヘッドの数(2にしなければいけない) DD 0 ; パーティションを使ってないのでここは必ず0 DD 2880 ; このドライブ大きさをもう一度書く DB 0,0,0x29 ; よくわからないけどこの値にしておくといいらしい DD 0xffffffff ; たぶんボリュームシリアル番号 DB "HARIBOTEOS " ; ディスクの名前(11バイト) DB "FAT12 " ; フォーマットの名前(8バイト) RESB 18 ; とりあえず18バイトあけておく ; プログラム本体 entry: MOV AX,0 ; レジスタ初期化 MOV SS,AX MOV SP,0x7c00 MOV DS,AX ; ディスクを読む MOV AX,0x0820 MOV ES,AX MOV CH,0 ; シリンダ0 MOV DH,0 ; ヘッド0 MOV CL,2 ; セクタ2 readloop: MOV SI,0 ; 失敗回数を数えるレジスタ retry: MOV AH,0x02 ; AH=0x02 : ディスク読み込み MOV AL,1 ; 1セクタ MOV BX,0 MOV DL,0x00 ; Aドライブ INT 0x13 ; ディスクBIOS呼び出し JNC next ; エラーがおきなければnextへ ADD SI,1 ; SIに1を足す CMP SI,5 ; SIと5を比較 JAE error ; SI >= 5 だったらerrorへ MOV AH,0x00 MOV DL,0x00 ; Aドライブ INT 0x13 ; ドライブのリセット JMP retry next: MOV AX,ES ; アドレスを0x200進める ADD AX,0x0020 MOV ES,AX ; ADD ES,0x020 という命令がないのでこうしている ADD CL,1 ; CLに1を足す CMP CL,18 ; CLと18を比較 JBE readloop ; CL <= 18 だったらreadloopへ MOV CL,1 ADD DH,1 CMP DH,2 JB readloop ; DH < 2 だったらreadloopへ MOV DH,0 ADD CH,1 CMP CH,CYLS JB readloop ; CH < CYLS だったらreadloopへ ; 読み終わったのでharibote.sysを実行だ! ;===============================这次添加的新内容START================================= JMP 0xc200 ;这里就是,将之前说的180KB的内容装进了内存中,并且我们知道了我们的程序在0xc200的位置 ;所以前面做的只是读取,这里有点犯迷糊。仔细想一想,之前是读取磁盘的内容到一个内存中 ;假设他们的地址从0~100,现在我们读完之后,到自己的内存中c200的位置去执行。好吧反正我是觉得挺绕的。 ;另外我们的磁盘大小就是180KB,我想知道如果程序不在这个180 中怎么办?或者180没读完怎么办????? ;======================================END=========================================== error: MOV SI,msg putloop: MOV AL,[SI] ADD SI,1 ; SIに1を足す CMP AL,0 JE fin MOV AH,0x0e ; 一文字表示ファンクション MOV BX,15 ; カラーコード INT 0x10 ; ビデオBIOS呼び出し JMP putloop fin: HLT ; 何かあるまでCPUを停止させる JMP fin ; 無限ループ msg: DB 0x0a, 0x0a ; 改行を2つ DB "load error" DB 0x0a ; 改行 DB 0 RESB 0x7dfe-$ ; 0x7dfeまでを0x00で埋める命令 DB 0x55, 0xaa 七,确认操作系统的执行情况 注释:这节主要的目的是给显示其以色彩。调用显使能 ; haribote-ipl ; TAB=4 CYLS EQU 10 ; どこまで読み込むか ORG 0x7c00 ; このプログラムがどこに読み込まれるのか ; 以下は標準的なFAT12フォーマットフロッピーディスクのための記述 JMP entry DB 0x90 DB "HARIBOTE" ; ブートセクタの名前を自由に書いてよい(8バイト) DW 512 ; 1セクタの大きさ(512にしなければいけない) DB 1 ; クラスタの大きさ(1セクタにしなければいけない) DW 1 ; FATがどこから始まるか(普通は1セクタ目からにする) DB 2 ; FATの個数(2にしなければいけない) DW 224 ; ルートディレクトリ領域の大きさ(普通は224エントリにする) DW 2880 ; このドライブの大きさ(2880セクタにしなければいけない) DB 0xf0 ; メディアのタイプ(0xf0にしなければいけない) DW 9 ; FAT領域の長さ(9セクタにしなければいけない) DW 18 ; 1トラックにいくつのセクタがあるか(18にしなければいけない) DW 2 ; ヘッドの数(2にしなければいけない) DD 0 ; パーティションを使ってないのでここは必ず0 DD 2880 ; このドライブ大きさをもう一度書く DB 0,0,0x29 ; よくわからないけどこの値にしておくといいらしい DD 0xffffffff ; たぶんボリュームシリアル番号 DB "HARIBOTEOS " ; ディスクの名前(11バイト) DB "FAT12 " ; フォーマットの名前(8バイト) RESB 18 ; とりあえず18バイトあけておく ; プログラム本体 entry: MOV AX,0 ; レジスタ初期化 MOV SS,AX MOV SP,0x7c00 MOV DS,AX ; ディスクを読む MOV AX,0x0820 MOV ES,AX MOV CH,0 ; シリンダ0 MOV DH,0 ; ヘッド0 MOV CL,2 ; セクタ2 readloop: MOV SI,0 ; 失敗回数を数えるレジスタ retry: MOV AH,0x02 ; AH=0x02 : ディスク読み込み MOV AL,1 ; 1セクタ MOV BX,0 MOV DL,0x00 ; Aドライブ INT 0x13 ; ディスクBIOS呼び出し JNC next ; エラーがおきなければnextへ ADD SI,1 ; SIに1を足す CMP SI,5 ; SIと5を比較 JAE error ; SI >= 5 だったらerrorへ MOV AH,0x00 MOV DL,0x00 ; Aドライブ INT 0x13 ; ドライブのリセット JMP retry next: MOV AX,ES ; アドレスを0x200進める ADD AX,0x0020 MOV ES,AX ; ADD ES,0x020 という命令がないのでこうしている ADD CL,1 ; CLに1を足す CMP CL,18 ; CLと18を比較 JBE readloop ; CL <= 18 だったらreadloopへ MOV CL,1 ADD DH,1 CMP DH,2 JB readloop ; DH < 2 だったらreadloopへ MOV DH,0 ADD CH,1 CMP CH,CYLS JB readloop ; CH < CYLS だったらreadloopへ ; 読み終わったのでharibote.sysを実行だ! ;===============================这次添加的新内容START================================= MOV [0x0ff0],CH ; 记下IPL读到哪里了。 注释:咱也不知道这里是干啥用的,后面看看再说 ;理解:大致意思是我们当前在哪一个柱面 JMP 0xc200 ;======================================END=========================================== error: MOV SI,msg putloop: MOV AL,[SI] ADD SI,1 ; SIに1を足す CMP AL,0 JE fin MOV AH,0x0e ; 一文字表示ファンクション MOV BX,15 ; カラーコード INT 0x10 ; ビデオBIOS呼び出し JMP putloop fin: HLT ; 何かあるまでCPUを停止させる JMP fin ; 無限ループ msg: DB 0x0a, 0x0a ; 改行を2つ DB "load error" DB 0x0a ; 改行 DB 0 RESB 0x7dfe-$ ; 0x7dfeまでを0x00で埋める命令 DB 0x55, 0xaa
;haribote.nas ; haribote-os ; TAB=4 ;===============================这次添加的新内容START================================= ORG 0xc200 ; 这个程序要被装在到内存的什么地方呢? ;这个意思就是说,我们的程序所有的最初的地方是从这个地址开始的 MOV AL,0x13 ; 这里的AL和之前的启动区的AL 和 AH不大一样。注意区分!这里是VGA显卡,320×200×8位彩色 MOV AH,0x00 INT 0x10 ;没猜错这里的INT就是显卡的 那个BIOS,和之前的CPU的BIOS一样的方式。先设置参数,在调用这里。上面的AH应该就是参数了 ;======================================END=========================================== fin: HLT JMP fin
解释:
八,32位的前期准备
; haribote-os ; TAB=4 ; BOOT_INFO関係 CYLS EQU 0x0ff0 ; 设定启动区 LEDS EQU 0x0ff1 VMODE EQU 0x0ff2 ; 关于颜色数目的信息。颜色的位数 SCRNX EQU 0x0ff4 ; 分辨率的X SCRNY EQU 0x0ff6 ; 分辨率的Y VRAM EQU 0x0ff8 ; 图像缓冲区的开始地址 注释:VRAM是显卡内存 ORG 0xc200 ; 这个程序要装载到的内存的地方 MOV AL,0x13 ; VGA显卡,320x200x8位彩色 MOV AH,0x00 INT 0x10 MOV BYTE [VMODE],8 ; 记录画面模式 MOV WORD [SCRNX],320 MOV WORD [SCRNY],200 MOV DWORD [VRAM],0x000a0000 ; 用BIOS取得键盘上各种LED指示灯的状态 MOV AH,0x02 INT 0x16 ; keyboard BIOS MOV [LEDS],AL fin: HLT JMP fin
九:开始导入C语言
;asmhead.nas ; haribote-os boot asm ; TAB=4 BOTPAK EQU 0x00280000 ; bootpackのロード先 DSKCAC EQU 0x00100000 ; ディスクキャッシュの場所 DSKCAC0 EQU 0x00008000 ; ディスクキャッシュの場所(リアルモード) ; BOOT_INFO関係 CYLS EQU 0x0ff0 ; ブートセクタが設定する LEDS EQU 0x0ff1 VMODE EQU 0x0ff2 ; 色数に関する情報。何ビットカラーか? SCRNX EQU 0x0ff4 ; 解像度のX SCRNY EQU 0x0ff6 ; 解像度のY VRAM EQU 0x0ff8 ; グラフィックバッファの開始番地 ORG 0xc200 ; このプログラムがどこに読み込まれるのか ; 画面モードを設定 MOV AL,0x13 ; VGAグラフィックス、320x200x8bitカラー MOV AH,0x00 INT 0x10 MOV BYTE [VMODE],8 ; 画面モードをメモする(C言語が参照する) MOV WORD [SCRNX],320 MOV WORD [SCRNY],200 MOV DWORD [VRAM],0x000a0000 ; キーボードのLED状態をBIOSに教えてもらう MOV AH,0x02 INT 0x16 ; keyboard BIOS MOV [LEDS],AL ;===============================这次添加的新内容START================================= ;这里就是为了系统能够调用C语言做的准备,但是作者目前没有说,期待之后的补充 ; PICが一切の割り込みを受け付けないようにする ; AT互換機の仕様では、PICの初期化をするなら、 ; こいつをCLI前にやっておかないと、たまにハングアップする ; PICの初期化はあとでやる MOV AL,0xff OUT 0x21,AL NOP ; OUT命令を連続させるとうまくいかない機種があるらしいので OUT 0xa1,AL CLI ; さらにCPUレベルでも割り込み禁止 ; CPUから1MB以上のメモリにアクセスできるように、A20GATEを設定 CALL waitkbdout MOV AL,0xd1 OUT 0x64,AL CALL waitkbdout MOV AL,0xdf ; enable A20 OUT 0x60,AL CALL waitkbdout ; プロテクトモード移行 [INSTRSET "i486p"] ; 486の命令まで使いたいという記述 LGDT [GDTR0] ; 暫定GDTを設定 MOV EAX,CR0 AND EAX,0x7fffffff ; bit31を0にする(ページング禁止のため) OR EAX,0x00000001 ; bit0を1にする(プロテクトモード移行のため) MOV CR0,EAX JMP pipelineflush pipelineflush: MOV AX,1*8 ; 読み書き可能セグメント32bit MOV DS,AX MOV ES,AX MOV FS,AX MOV GS,AX MOV SS,AX ; bootpackの転送 MOV ESI,bootpack ; 転送元 MOV EDI,BOTPAK ; 転送先 MOV ECX,512*1024/4 CALL memcpy ; ついでにディスクデータも本来の位置へ転送 ; まずはブートセクタから MOV ESI,0x7c00 ; 転送元 MOV EDI,DSKCAC ; 転送先 MOV ECX,512/4 CALL memcpy ; 残り全部 MOV ESI,DSKCAC0+512 ; 転送元 MOV EDI,DSKCAC+512 ; 転送先 MOV ECX,0 MOV CL,BYTE [CYLS] IMUL ECX,512*18*2/4 ; シリンダ数からバイト数/4に変換 SUB ECX,512/4 ; IPLの分だけ差し引く CALL memcpy ; asmheadでしなければいけないことは全部し終わったので、 ; あとはbootpackに任せる ; bootpackの起動 MOV EBX,BOTPAK MOV ECX,[EBX+16] ADD ECX,3 ; ECX += 3; SHR ECX,2 ; ECX /= 4; JZ skip ; 転送するべきものがない MOV ESI,[EBX+20] ; 転送元 ADD ESI,EBX MOV EDI,[EBX+12] ; 転送先 CALL memcpy skip: MOV ESP,[EBX+12] ; スタック初期値 JMP DWORD 2*8:0x0000001b waitkbdout: IN AL,0x64 AND AL,0x02 JNZ waitkbdout ; ANDの結果が0でなければwaitkbdoutへ RET memcpy: MOV EAX,[ESI] ADD ESI,4 MOV [EDI],EAX ADD EDI,4 SUB ECX,1 JNZ memcpy ; 引き算した結果が0でなければmemcpyへ RET ; memcpyはアドレスサイズプリフィクスを入れ忘れなければ、ストリング命令でも書ける ALIGNB 16 GDT0: RESB 8 ; ヌルセレクタ DW 0xffff,0x0000,0x9200,0x00cf ; 読み書き可能セグメント32bit DW 0xffff,0x0000,0x9a28,0x0047 ; 実行可能セグメント32bit(bootpack用) DW 0 GDTR0: DW 8*3-1 DD GDT0 ALIGNB 16 bootpack: ;======================================END=========================================== void HariMain(void) { fin: /* ここにHLTを入れたいのだが、C言語ではHLTが使えない! */ goto fin; }