;By Marcus Xing
;boot/include/lib_in_real_mode.inc
;在boot/loader.asm中在实模式下调用的函数
;--------------------------------------------------------------------Read_Sector
Read_Sector:
;C函数原型(实模式下调用,短调用):
;void Read_Sector(byte16 first_sector_index,byte16 read_sector_number);
;注意:
;调用前es:bx必须指向缓冲区,ds指向数据区
;逻辑扇区号转化为系统调用所需参数的公式如下:
;相对扇区号/每磁道扇区号(18)的商Q,余数R
;其中:柱面号=Q>>1,磁头号=Q&1,相对起始扇区号=R+1
;对应的系统调用API如下:
;功能号ah=02
;hal=要读的扇区数
;ch=柱面(磁道)号
;cl=起始扇区号
;dh=磁头号,dl=驱动器号(0表示A盘)
;es:bx缓冲区地址
push bp
mov bp,sp
push ax
push bx
push cx
push dx
push bx ;暂存缓冲区偏移
mov ax,[bp + 6] ;取得要读取的扇区数
push ax ;暂时保存之
mov ax,[bp + 4] ;取得要读的逻辑扇区号
mov bl,18
div bl ;除以每柱面扇区数
mov ch,al
shr ch,1 ;ch<-柱面号
mov dh,al
and dh,1 ;dh<-磁头号
mov cl,ah
inc cl ;cl<-相对扇区号
mov dl,0 ;读A盘
pop ax ;al<-要读的扇区数
pop bx ;恢复缓冲区偏移
.Go_On_Reading:
mov ah,2 ;ah<-功能号
int 13h
jc .Go_On_Reading ;如果cf=1,继续读
pop dx
pop cx
pop bx
pop ax
pop bp
ret
;------------------------------------------------------------------Get_FAT_Entry
Get_FAT_Entry:
;C函数原型(实模式下调用,短调用):
;u16 Get_FAT_Entry(u16 Sector_No_In_Data_Area);
;功能:
;入口参数为数据区的相对扇区号,返回值为相应的FAT的值,以表示还有没有下一个扇区
;ds指向数据区,在此函数中,es:bx=9000h-100h:0用来作为读FAT的缓冲区
push bp
mov bp,sp
push bx
push dx
push es
mov byte [_b_Is_Odd],0 ;作用为局部变量,标记相对FAT的条目索引
;es指向9000h-100h
mov ax,Base_Of_Loader
sub ax,100h
mov es,ax
;1个FAT条目为12位,条目索引*3/2 = *1.5
;ax为相对FAT字节偏移
mov ax,[bp + 4]
mov bx,3
mul bx
mov bx,2
div bx
;判断余数是否为0,是的话为偶,跳转到
;对应标号,否的话把标记变量置1
cmp dx,0
je LABEL_EVEN
mov byte [_b_Is_Odd],1
LABEL_EVEN:
;ax=当前条目在FAT的相对逻辑偏移扇区
;dx=当前条目相对当前扇区的字节偏移
xor dx,dx
mov bx,512
div bx
add ax,1 ;ax自增1,求得相对整个软盘的逻辑扇区偏移
;读2个FAT扇区到缓冲区,一次读2个,
;因为FAT条目可能跨越2个扇区
xor bx,bx
push 2
push ax
call Read_Sector
add sp,4
mov bx,dx ;es:bx指向要求的条目首字节
mov ax,[es:bx] ;把首字节存到ax
cmp byte [_b_Is_Odd],1 ;判断奇偶,奇偶有不同的处理方式
jne LABEL_EVEN2
shr ax,4 ;奇数的处理方式
LABEL_EVEN2: ;偶数的处理方式
and ax,0fffh ;返回值放到ax中
LABEL_DONE:
pop es
pop dx
pop bx
pop bp
ret
;----------------------------------------------------------Disp_Str_In_Real_Mode
Disp_Str_In_Real_Mode:
;C函数原型(实模式下调用,短调用):
;void Disp_Str_In_Real_Mode(const char *p_sz_Str);
;注意:
;在变量_w_Disp_Pos处显示字符串,ds指向数据区,es的值在此函数中指向数据区
push bp
mov bp,sp
push ax
push bx
push cx
push dx
push di
push es
;此BIOS中断API
;功能13H
;功能描述:在Teletype模式下显示字符串
;入口参数:AH=13H
;BH=页码
;BL=属性(若AL=00H或01H)
;CX=显示字符串长度
;(DH、DL)=坐标(行、列)
;ES:BP=显示字符串的地址 AL=显示输出方式
;0——字符串中只含显示字符,其显示属性在BL中。显示后,光标位置不变
;1——字符串中只含显示字符,其显示属性在BL中。显示后,光标位置改变
;2——字符串中含显示字符和显示属性。显示后,光标位置不变
;3——字符串中含显示字符和显示属性。显示后,光标位置改变
;出口参数:无
mov ax,ds
mov es,ax
mov bp,[bp + 4] ;取得要打印的字符串指针
mov al,[es:bp]
cmp al,0ah
jne .3
mov ax,[_w_Disp_Pos_In_RM]
mov bl,80
div bl
inc al
mul bl
mov [_w_Disp_Pos_In_RM],ax
jmp .4
.3:
mov ax,[_w_Disp_Pos_In_RM];得到显示地址
mov bl,80
div bl
mov dh,al ;dh<-行号
mov dl,ah ;dl<-列号
xor cx,cx ;字符串长度计数器
mov di,bp ;做临时指针es:di指向字符串
.1:
mov al,byte [es:di]
cmp al,0 ;遇到0计数结束
je .2
inc cx ;计数器自增1
inc di ;临时指针自增1
jmp .1
.2:
add word [_w_Disp_Pos_In_RM],cx ;显示地址加上字符串长度
mov bx,0007h ;bh表示第0页,bl表示字符颜色
mov ax,1301h ;al为输出方式1
int 10h
.4:
pop es
pop di
pop dx
pop cx
pop bx
pop ax
pop bp
ret
;---------------------------------------------------------------------Kill_Motor
Kill_Motor:
;C函数原型(实模式下调用,短调用):
;void Kill_Motor();
;功能:
;如名字所示,以免马达灯长亮
push ax
push dx
mov dx,03f2h
mov al,0
out dx,al
pop dx
pop ax
ret