今天要做什么?
(1)分享
我们上面已经说过INT 0x13这种指令(调用BIOS的INT指令),我们知道这是调用BIOS的0x13函数,但还不明白它到底是干什么用的:
AH = 0x02;# 读盘
AH = 0x03;# 写盘
AH = 0x04 ;# 校验
AH = 0x0c;# 寻道
AL = 处理对象的扇区数;(只能同时处理连续的扇区)
CH = 柱面号;&0xff;
CL = 扇区号(0-5)|(柱面号&0x300)》》2;
DH = 磁头号;
DL = 驱动器号;
ES:BX = 缓冲地址;(校验及寻道时不使用)
返回值:
FLASC.CF ==0: 没有错误,AH==0
FLAGS.CF ==1:有错误,错误号码存入AH内(与重置(reset)功能一样)
我们这次用的是AH =0x02,是读盘的意思。
返回值那一栏里的FLACS.CF 意识是进位标志,也就是说,调用这个函数后,如果没错,进位标志就是0,如果有错,进位标志就是1.
进位标志是一个只能储存1位信息的寄存器,除此之外,CPU还有其他几个只有1位的寄存器,像这种1位寄存器我们称之为标志(在英文中就是flag)。
如果有软盘,希望大家能把他拆开看看,拆开后可以看到,中间有黑色圆盘(磁性胶片),环状区域有80个柱面。我们有正面(磁头0)和反面(磁头1号)两个磁头。软盘分为18份,每一份称为一个扇区,一个圆环有18个扇区。
综上所述。一个软盘有80个柱面,2个磁头,18个扇区,且一个扇区有512字节。
一张软盘的容量是:80*2*512 = 1474560 Byte =1440KB
含有IPL的启动区,位于C0-H0-S1(柱面0,磁头0,扇区1的缩写),写一个扇区是C0-H0-S2,待会要对这个扇区进行操作。
缓冲区地址:这是个内存地址,表明我们要把从软盘上读出的数据装载到内存的哪个位置。
如果能用一个寄存器来表示内存地址的话,会很方便,但是一个BX只能表示0-oxffff的值,也就是0-65535,最大才65536/1024=64k,64k内存太小了。
为了解决这个问题,新增了一个EBX的寄存器(最大4G)内存,在中间的过渡时期是设计了一个起辅助作用的段寄存器(segment register)用ES:BX(MOV AL,[ES,BX])这种方式来表示地址(理解:先用ES寄存器指定一个大致的地址,然后再用BX来指定其中一个具体地址)
16位实模式下的地址线通常是20位,也就是(最大寻址)oxfffff。当计算地址超过这个范围时,会发生回绕(因处理器不同)
段位寄存器的计算需要先把值赋值给通用寄存器。
0xFFFF*16+oxffff = 1114095 =>0xffff0+0xffff = 0x10ffef
常用用法(DS可以省略,所以DS必须先指定为0,否则地址就要加上这个数的16倍)
MOV CX,[1234],其实是MOV CX,[DS:1234];
MOV AL,[SI] 也就是 MOV AL,[DS:SI]的意思
在正常程序中,要读下一个扇区,只需要给CL+1,给ES 加上0x20(扇区大小512/16进制)就行了。CL是扇区号,ES指定读入地址。
C0-H0-S18的下一扇区,是磁盘反面的C0-H1-SQ,从0xa400读入吧
指令JB:条件跳转指令(jump if below)意思差不多是 如果小于的话,就跳转
指令EQU:相当于C语言的#define命令,用来声明常量,用来声明常数。
“CYLS EQU 10”意思是“CYLS = 10”.EQU是equal的缩写
辅导资源 第三天的笔记,建议手打!!!
; haribote-ipl
; TAB =4
CYLS EQU 10 ; 声明CYLS=10
ORG 0x7c00 ; 指明程序装载地址
; 标准FAT12 格式软盘专用的代码 Stand FAT12 format flppy code
JMP entry
DB 0x90
DB "HARIBOTE" ;启动扇区名称(8字节)
DW 512 ;每个扇区(sector)大小(必须512字节)
DB 1 ; 簇(cluster)大小 必须为一个扇区
DW 1 ; FAT起始位置(一般为第一个扇区)
DB 2 ; FAT个数(必须为2)
DW 224 ; 根目录大小(一般为224项)
DW 2880 ; 该磁盘大小(必须为2880扇区1440*1024/512)
DB 0xf0 ; 跳过引导扇区,必须为0xf0
DW 9 ; 跳过引导扇区后的第一个数据分区,必须为9?
DW 18 ; 该磁盘的扇区数,必须为18
DW 2 ; 磁头每个扇区扇区数,必须为2?
DD 0 ;不适用分区,必须为0
DD 2880 ;重写一次磁盘大小
DB 0,0,0x29 ;磁盘号,卷标,磁盘长度??必须为0x29
DD 0xffffffff ;磁盘序列号,必须为0xffffffff
DB "HARIBOTEOS " ;磁盘名称,必须为11字,不足填空格
DB "FAT12 " ;磁盘格式名称(必须为8字?,不足填空格)
RESB 18 ;先空出18字节
; 程序主体
entry:
MOV AX,0 ;初始化寄存器
MOV SS,AX
MOV SP,0x7c00
MOV DS,AX
;读磁盘 读入10个柱面
MOV AX, 0x0820
MOV es,AX
MOV CH,0 ; 柱面0
MOV DH,0 ; 磁头
MOV CL,2 ; 扇区2
readloop:
MOV SI,0 ; 缓冲区偏移 记录失败次数
retry:
MOV AH,0x02 ; 读入磁盘
MOV AL,1 ; 1个扇区
MOV bx,0 ;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 ;往CL里加1
MOV ES,AX ;因为没有ADD ES,0x020指令,所以这里稍微绕个弯
ADD CL,1 ;CL加1
CMP CL,18 ;比较CL与18
JBE readloop ;如果CL<=18.则跳转至readloo
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 ;如果CL <=18跳转到readloop
; 读取完毕,跳转到haribote.sys执行!
MOV [0x0ff0],CH ; IPLがどこまで読んだのかをメモ
JMP 0xc200
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 ; 换行两次
DB "load error"
DB 0x0a ; 换行
DB 0
RESB 0x7dfe-$ ; 填写0x00直到0x001fe
DB 0x55, 0xaa
本人今天上班,所以分享较少,后面多多加油!