开发操作系统实践(五)——新的引导扇区代码

;########################################################################################
;#                 							      #
;#    软盘引导扇区源代码							       #
;#  1、将引导代码移送至内存9000H:0000处,并转去继续执行			                  #
;#  2、设置段寄存器DS→9000H;ES→磁盘参数表50H;FS→临时数据区9040H;			       #
;#		   GS→磁盘缓冲区9060H;SS,SP→堆栈段9020H:01ffH			      #
;#  3、将磁盘参数表读入内存0050H:0000处,磁盘参数表的位置由格式化程序或系统传送程序设置	       #
;#  4、根据根目录表所在的逻辑扇区号,计算它的物理磁头号、磁道号、逻辑扇区号		       #
;#  5、将根目录表所在的第一个扇区的内容读入内存9060H:0000				      #
;#  6、要想引导系统,必须将引导文件放在根目录表的第一个目录项中。			       #
;#		所以这一步分析根目录表的第一项文件名是否是系统引导文件“LDLoader.sys”	      #
;#  7、计算系统引导文件LDLoader.sys占用的扇区数,目录项偏移20B处是文件的大小		       #
;#  8、将LDLoader.sys文件读入系统内存0070:0000。这里又有一个先决条件,			       #
;#		即LDloader.sys文件放在磁盘用户数据区开头的连续扇区中。		       #
;#  9、JMP 0070H:0000,完成系统引导,转去执行LDLoader.sys。		                  #
;#					最后修改时间:2012年10月26日	                  #
;########################################################################################

;======================宏变量定义区===========================================================================
	SECS_OF_CYLINDER_DISKINFO 	         equ 	0ch		;每磁道扇区数在磁盘参数表中的位置
	HEADS_OF_DISK_DISKINFO		equ	9		;磁盘总的磁头数在磁盘参数表中的位置
	FDT_LBA_NUMBER_DISKINFO		equ	13h		;首张根目录表起始逻辑扇区号在磁盘参数表中的位置
	BYTE_OF_SECTOR_DISKINFO		equ	0eh		;每扇区字节数在磁盘参数表中的位置
	DATA_LOGICNUM_DISKINFO		equ	17h		;磁盘数据区起始逻辑扇区号在磁盘参数表中的位置
	LDLOADER_SIZE_OFFSET		equ	13h		;LDLOADER文件的大小在目录项中的位置
;======================宏变量定义结束=========================================================================

org 0
	jmp Entry
;磁盘参数
	DiskType db 0		;磁盘类型,驱动器号(编号法则为:磁盘的第一个分区为0,第二个为1,依次类推。若为硬盘,则第7位置1
							;也就是若是硬盘第一个分区则设成0x80,软盘则为0x00)
	DiskInfoHead db 0	;磁盘参数表所在的磁头号
	DiskInfoCyl db 0	;磁盘参数表所在的磁道号
	DiskInfoSector db 2	;磁盘参数表所在的扇区号
;将自身移至内存9000h:0000
Entry:
;使DS:SI→7C00H:0000,ES:DI→9000H:0000
	xor si,si
	xor di,di
	mov ax,7c0h
	mov ds,ax
	mov ax,9000h
	mov es,ax
	mov cx,512
	cld
	rep movsb
	jmp 9000h:Start
;主体代码
Start:
;设置段寄存器DS→9000H;ES→磁盘参数表50H;FS→临时数据区9040H;GS→磁盘缓冲区9060H;SS,SP→堆栈段9020H:01ffH
	mov ax,9000h
	mov ds,ax
	mov ax,50h
	mov es,ax
	mov ax,9040h
	mov fs,ax
	mov ax,9060h
	mov gs,ax
	mov ax,9020h
	mov ss,ax
	mov sp,01ffh
;将磁盘参数表读入内存0050:0000
	mov dh,[DiskInfoHead]
	mov ch,[DiskInfoCyl]
	mov cl,[DiskInfoSector]
	push es
	mov bx,50h
	mov es,bx
	mov bx,0
	call ReadDisk
	pop es
	jnc next						;读磁盘成功跳转,否则显示错误信息
NonSysErr:
	mov ax,cs
	mov es,ax
	mov ax,ErrorMSG
	mov bp,ax
	mov cx,SystemName-ErrorMSG
	call TypeMSG
	xor ax,ax
	int 16h
	jmp 0FFFFh:0000
;将根目录表首扇区内容读入内存9060:0000簇列表缓冲区中
next:
	mov eax,[es:FDT_LBA_NUMBER_DISKINFO]		;根目录表起始逻辑扇区号在磁盘参数表第0fh字节处
	call SubDiskAddress				;计算物理磁头、扇区、磁道号
	push es
	mov bx,9060h
	mov es,bx
	xor bx,bx
	call ReadDisk
	pop es
	jc NonSysErr
;检查首张根目录表第一个目录项文件名是否为:“LDLoader.sys”
	mov di,0
	mov si,SystemName
	mov cx,12
CMPstr:
	mov dl,[gs:di]
	mov dh,[ds:si]
	cmp dl,dh
	jne NonSysErr
	inc di
	inc si
loop CMPstr
	inc di
	mov dl,[gs:di]	;检查该目录项最后一个字符是否是0
	cmp dl,0
	jne NonSysErr
;检查文件大小是否大于零,目录项偏移13h处是文件的大小
	mov eax,[gs:LDLOADER_SIZE_OFFSET]
	cmp eax,0
	je NonSysErr	
;下面开始读取LDLoader.sys文件
;1、计算文件占用扇区数
	xor edx,edx
	xor ebx,ebx
	mov bx,[es:BYTE_OF_SECTOR_DISKINFO]
	div ebx
	cmp edx,0
	je next1
	inc eax
next1:
;2、将LDLoader.sys文件占用的扇区数保存在内存9040h:0100h中
	mov [fs:100h],eax
;3、开始读文件LDLoader.sys,读至内存0070:0000开始的内存中
	mov word [fs:104h],70h				;存放文件的段地址
	mov word [fs:106h],0					;偏移地址
	mov ax,0ffffh
	sub ax,[es:BYTE_OF_SECTOR_DISKINFO]		;偏移地址上限
	inc ax
	mov [fs:108h],ax
	mov eax,[es:DATA_LOGICNUM_DISKINFO]
	mov [fs:110h],eax
ReadLBR:
	mov eax,[fs:110h]
	call SubDiskAddress
	push es
	mov es,[fs:104h]
	mov bx,[fs:106h]
	call ReadDisk
	pop es
	mov ax,[fs:106h]
	cmp ax ,[fs:108h]
	jne GoOn
	mov word [fs:106h],0
	add word [fs:104h],1000h
	jmp GoOn2
GoOn:
	mov ax,[es:BYTE_OF_SECTOR_DISKINFO]
	add [fs:106h],ax
GoOn2:
	inc dword [fs:110h]
	dec dword [fs:100h]
	cmp dword [fs:100h],0
	jnz ReadLBR
	jmp 0070h:0000
	
;=============================================================================================
;根据逻辑扇区号计算对应磁盘的磁头号、磁道号、扇区号
;逻辑扇区号与物理扇区换算关系:逻辑扇区按照扇区号、磁头号、柱面号(或磁道号)增长的顺序连续分配
	;假设:LH---LinDos逻辑扇区0的磁头号
	;      LC---LinDos逻辑扇区0的柱面号
	;      LS---LinDos逻辑扇区0的扇区号
	;      NS---每磁道扇区数
	;      NH---磁盘总的磁头数
	;若已知某扇区柱面号C,磁头号H,扇区号S,则其对应的逻辑扇区号RS公式为:
	;	RS=NH*NS*(C-LC)+NS*(H-LH)+(S-DS)
	;若已知某扇区的逻辑扇区号RS,则其对应的柱面号C,磁头号H,扇区号S公式为:
	;	S=(RS MOD NS)+LS
	;	H=((RS DIV NS) MOD NH)+LH
	;	C=((RS DIV NS)DIV NH)+LC
;入口参数:	EAX:逻辑扇区号
;出口参数:	CH—柱面,CL—扇区,DH—磁头
;=============================================================================================
SubDiskAddress:
;1、计算物理扇区号
	xor edx,edx
	xor ecx,ecx
	mov cx,[es:SECS_OF_CYLINDER_DISKINFO]		;磁盘参数表第8字节处,存放着磁盘每磁道扇区数的信息。
	div ecx
	inc edx						;此时EAX中存放的是(RS/NS)的商,EDX中存放的是余数
	mov [fs:150h],dl				;保存物理扇区号
;2、计算磁头号及柱面号
	xor ecx,ecx
	xor edx,edx
	mov cl,[es:HEADS_OF_DISK_DISKINFO]		;磁盘参数表第5字节处,存放着磁盘总的磁头数
	div ecx
	mov dh,dl						;EDX中存放的是((RS / NS) / NH)的余数,也即物理磁头号,EAX中存放中存放的是商,也即柱面号。
	mov ch,al
	mov cl,[fs:150h]
	ret
	
	
;===============================
;读磁盘扇区功能,读入一个扇区
;入:
;    	CH—柱面,CL—扇区,DH—磁头
;	ES:BX=缓冲区地址
;出:	CF=0—操作成功,AH=00H,AL=传输的扇区数
;    	CF=1—操作失败,AH=状态码
;===============================

ReadDisk:
	mov ax,0201h
	mov dl,[DiskType]
	int 13h
ret

;===============================
;显示字符串函数
;入口参数:ES:BP,字符串地址
;	   CX,字符串长度
;
;
;===============================

TypeMSG:
	push cx
	mov ah,3		;调用int 10H 03H功能,获得光标坐标
	mov bh,0
	int 10h
	pop cx
	mov ax,1301h	;调用int 10H 13H功能,显示字符串
	mov bx,0fh
	int 10h
ret


ErrorMSG db "None system or disk error!",13,10,"Press anykey to restart your computer!"
SystemName db "LDLoader.sys"

times 510-($-$$) db 0

dw 0aa55h

发布了13 篇原创文章 · 获赞 5 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/xsff1024/article/details/8266960