005-完成ipl

       上次完成了启动盘,我们已经成功把启动区加载到了内存中,当然了,这512字节的空间肯定是不可能够我们写一个完整的操作系统的,所以,我们操作系统的其他部分肯定得在别的地方写,那么,ipl的任务就应该是把软盘这1440KB的内容全部加载到内存中,不过这里有一个相当严重的问题,就是我们在实模式下,只有20位寻址空间,换句话说,我们只能访问1MB的内存,所以暂时还没办法把所有的数据都放到内存中,暂时我们先只放10个柱面的内容到内存中。交给操作系统的内存部分是0x8000到0x9fbff,不过,虽然ipl的部分事先被加载到了0x7c00的位置,但是,它仍然作为软盘数据的一部分,这部分的数据在以后是有可能会用到的,因此,我们还是把0x8000到0x81ff的内存空间留给它,把剩下的内容从0x8200开始储存。

       我们按照扇区-磁头-柱面的顺序变更来读取软盘(也就是C0-H0-S1, C0-H0-S2, ……C0-H0-S18, C0-H1-S1, …… C0-H1-S18, C1-H0-S1, ……这样的顺序)一直读到C9-H1-S18。下面是改过后的ipl。


	org 0x7c00
	jmp entry
	db 0x90
	db "HELLOIPL"
	dw 512
	db 1
	dw 1
	db 2
	dw 224
	dw 2880
	db 0xf0
	dw 9
	dw 18
	dw 2
	dd 0
	dd 2880
	db 0, 0, 0x29
	db 0xffffffff
	db "HELLO-OS   "
	db "FAT12   "
	resb 18
	
entry:
	mov ax, 0
	mov ss, ax
	mov sp, 0x7c00
	mov ds, ax
	
	mov ax, 0x0820
	mov es, ax		;缓冲地址段地址
	mov ch, 0		; 柱面号
	mov dh, 0		; 磁头号
	mov cl, 2		; 扇区号
readloop:
	mov si, 0
retry:
	mov ah, 0x02
	mov al, 1		; 处理1个扇区
	mov bx, 0		; 缓冲地址基址
	mov dl, 0		; 驱动器号
	int 0x13		; 0x13号中断,ah=0x2时读盘,内容读取到es:bx中
	jnc succeed		; 如果进位符是1表示读取错误,jnc表示进位符为0
	add si, 1
	cmp si, 5
	jae error
	mov ah, 0
	mov dl, 0	
	int 0x13	    ; 0x13号中断 ah=0, dl=0时系统复位
	jmp retry
next:
	mov ax, es
	add ax, 0x20
	mov es, ax
	add cl, 1
	cmp cl, 18
	jbe readloop
	mov cl, 1
	add dh, 1
	cmp dh, 2
	jb  readloop
	mov dh, 0
	add ch, 1
	cmp ch, 10
	jb  readloop
	mov [0xff0], ch
	jmp 0xc200
succeed:
	mov si, msg_succeed
	jmp putloop
error:
	mov si,msg_error
putloop:
	mov al, [si]
	add si, 1
	cmp al, 0
	
	je  next
	mov ah, 0x0e
	mov bx, 15
	int 0x10
	jmp putloop
msg_error:
	db 0x0d, 0x0a
	db "load error"
	db 0x0a, 0
msg_succeed:
	db 0x0d, 0x0a
	db "load success "
	db 0x0a, 0
	
	resb 0x7dfe-$
	db 0x55, 0xaa
	
	

       24-27行是寄存器的初始化,ss和sp这两个寄存器在本程序里还用不到,只不过写上合适的值方便以后添加程序。29-30行初始化了缓冲地址寄存器es,这是因为我们要设置数据的起点,由于我们要把数据加载到0x8200位置,所以数据的起点就是这里,段寄存器就指向这里。13号BIOS中断时有关软盘操作的,当al为1时进行读盘操作,将会把dl表示的驱动器中的内容存放到[es:bx]中;当al为0时进行重新读盘操作。36-49行尝试读盘,si寄存器存放的是尝试读盘的次数,所以在35行初始化为0,当尝试5次都失败时将放弃读取,输出错误信息,而读取成功后,就会跳转到next标签下。50-64行通过不断循环36-49行的指令,把10个扇区的数据全部载入内存中。65行向内存0xff0处保存了一个数据,这个数据是目前读取的扇区数,这也是为了以后拓展这个程序用的,可以方便地知道之前加载了多少数据。执行到66行时,程序应当将10个扇区都加载完毕了,跳转到0xc200处,没错,0xc200已经超出ipl的范围了,这就是给操作系统的一个引子,我们就应当把操作系统加载到这个位置,由于ipl之前已经把这些内容都加载到内存中了,所以,接下来就可以直接执行操作系统的内容了,接下来我们来写操作系统,很简单的,输出一行文字就好。

org 0xc200
	
osEntry:
	mov ax, 0
	mov ds, ax
	mov si, msg
putloop:
	mov al, [si]
	add si, 1
	cmp al, 0
	je  fin
	mov ah, 0xe
	mov bx, 15
	int 0x10
	jmp putloop
	
fin:
	hlt
	jmp fin
	
msg:
	db 0x0d, 0x0a
	db "Hello World!"
	db 0x0d, 0x0a, 0

       在输出了一系列的加载成功以后,又输出了Hello World!,这就表示,我们的操作系统已经加载出来了。

       所以,ipl的使命基本就是这样,但是现在还不是很完善,这个以后再去修改,在较长的一段时间就会保持这样,接下来的任务就要转向我们的操作系统内核了。下次将介绍在操作系统加载后如何进入保护模式,以便利用32位寻址空间,访问4GB的内存。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章