《linux0.11完全注释》学习笔记1.1——system模块载入函数read_it分析

System模块在磁盘上的位置紧接着setup.s所在扇区,即0磁道0磁头3扇区。该模块被读到内存地址0x10000开始处,模块长度0x30000。读入该模块的代码被封装到了read_it函数中。
由于实模式下段偏移寄存器只有16位,最多寻址0x10000内的地址,所以无法在不改变段寄存器的情况下读入整个system模块。程序选择的方法是每次读入0x10000,然后将段寄存器加上这个偏移,反复执行直到读完。
在一次大小为0x10000读取中,程序要比较剩余需要读取的扇区数a和当前磁道、磁头下剩余可读扇区数b的大小。如果a>b,则读取b个扇区;否则读取a个扇区。一次读取完成后,要重新设置当前磁道号、磁头号和扇区号,以及内存缓冲区位置,包括段寄存器和段偏移。
循环过程中各关键变量的名字如下:track=当前磁道号,head=当前磁头号,sread=当前已读扇区数,ES:bx=缓冲区头部位置,al=一次读取中需要读取的扇区数。
函数的关键流程图如下:
read_it函数关键逻辑
附上汇编代码:

read_it:                        !在进入函数之前es被初始化为0x1000
	mov ax,es
	test ax,#0x0fff         !测试es低12位是否为0,实模式下ES还有四位隐藏位。实际测试低16位是否为0,即测试es是否位于64kb边界。test指令对两个操作数位与,若结果为0则ZF标志位置位。
die:	jne die			! es must be at 64kB boundary 若ZF=0,死机;否则初始化段偏移bx=0
	xor bx,bx		! bx is starting address within segment
rp_read:                        !开始进入读循环,循环终止条件为es=ENDSEG(0x4000)
	mov ax,es
	cmp ax,#ENDSEG		! have we loaded all yet?
	jb ok1_read
	ret
ok1_read:
	seg cs                  !表示下一条指令的操作数sectors(每磁道最大扇区数)地址在代码段中
	mov ax,sectors
	sub ax,sread            
	mov cx,ax               !cx=sectors-sread,求得当前磁道剩余未读扇区数
	shl cx,#9               !cx左移9位,即cx*512转化成字节数
	add cx,bx               !检测cx+bx是否超过了64kb(16位寄存器)。若超过,即无法一次性将磁盘剩余扇区全部读进,需重新计算可读扇区
	jnc ok2_read            !两条指令判断若cx+bx<=64kb,则直接读取磁盘剩余扇区,ax=磁盘剩余扇区数
	je ok2_read
	xor ax,ax               !若cx+bx>64kb,则重新计算可读扇区数ax=(64kb-bx)>>9
	sub ax,bx               !ax-bx,这里ax=0,所以等价于64kb-bx。无符号数相减的神奇规则!作者在许多地方都使用了这种巧妙的处理,比如在管道中计算可读数据大小。
	shr ax,#9
ok2_read:
	call read_track         !实际的读操作函数,利用了bios int13中断。
	mov cx,ax      
	add ax,sread            !读完之后更新sread
	seg cs
	cmp ax,sectors          !sread=sectors?当前磁道扇区是否已经读完?
	jne ok3_read            
	mov ax,#1              
	sub ax,head             !若磁道扇区已经读完,则试图将磁头号递增,并判断磁头号是否越界。软盘最多两个磁头号0,1。所以判断当前磁头号是否为1可知磁头号是否到达边界。无论哪种情况执行该指令后ax中存放的是应该更新的磁头号
	jne ok4_read            !若磁头号未越界,则递增磁头号;否则递增磁道号,并重置磁头号
	inc track
ok4_read:
	mov head,ax
	xor ax,ax
ok3_read:
	mov sread,ax            !这三条指令更新bx的值,bx<-bx+cx,cx是上次读取的字节数
	shl cx,#9
	add bx,cx
	jnc rp_read             !若bx+cx>=64kb,则要递增段寄存器ES,并重置段偏移bx
	mov ax,es
	add ax,#0x1000
	mov es,ax
	xor bx,bx
	jmp rp_read

read_track:
	push ax
	push bx
	push cx
	push dx
	mov dx,track
	mov cx,sread
	inc cx
	mov ch,dl
	mov dx,head
	mov dh,dl
	mov dl,#0
	and dx,#0x0100
	mov ah,#2
	int 0x13
	jc bad_rt
	pop dx
	pop cx
	pop bx
	pop ax
	ret
bad_rt:	mov ax,#0
	mov dx,#0
	int 0x13
	pop dx
	pop cx
	pop bx
	pop ax
	jmp read_track
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值