和CPU说话05
2017.7.8断断续续看了几天书,收获不多,脑子里翻来覆去就是自己的系统到底该怎么做。
MLGB的,MS-DOS1.0版本,1981年8月发布,仅支持单面软盘。它到底是怎么做到的?
哪里能找到这东西的解剖版啊,我好想弄明白怎么不用int 13 控制软驱...
前段时间逐条注释int 13,这几天也暂停了,工作量太大了,未知的东西也太多了,今天发一段代码上来,万一哪个有空的兄弟帮提点一下也能省我好多功夫。
文件中0000EC5B处应该是int 13的入口
实模式下内存F000:0000~F000:FFFF 反汇编代码:
文件附后。
我自己的注释也发一发,虽然还没完成,虽然可能仅仅是起了个头:
;Int 13h
jmp a
a:
cmp ah,0x4a
jc b ;CF进位时跳转(意思是小于4a跳转?)
cmp ah,0x4d
ja b ;无符号大于跳转
pushaw ;将8个通用寄存器入栈
push es
push ds
push cs
pop ds ;ds=cs
cld ;正向?
push word 0xece9;这里暂且不用管他的具体数值,因为读写磁盘不用到这里
jmp word 0x3c0c ;
b:
push es ;读写软盘时跳到这里
push ax
push bx
push cx
push dx
call onecall ;第一CALL
cmp al,0x0 ;al==[:336h] 查证后 al=0
jz c ;好像是为0跳转
call twocall ;******这里应该暂时不用管 因为 还没有到这里******
c: ;第一CALL al===0后跳到这里 等于前边什么都没做
; 在 EBDA(Extended BIOS Data Area)扩展BIOS数据区
pop dx
pop cx
pop bx
pop ax
pop es
push ax
push cx
push dx ;
push bx
push dx
push bp
push si
push di
push es ;bp+6
push ds ;bp+4
push cs ;这两步是设置DS=CS
pop ds
cld
test dl,0x80 ;TEST dl,bl 与 AND dl,bl 差不多,根据结果设置标志寄存器,结果本身不会保存
;这里应该是判断是选择什么驱动器的,因为80~ff是硬盘 80h 的2进制是 1000 0000
jnz 0xecc8 ;这里的意思是大于80h 就跳转暂时我不读写硬盘,先不管跳哪
push word 0xece9;bp+2
jmp word 0x3288 ;我们如果读写软盘,就会从这里起跳
d:
push bp
mov bp,sp
push si
push di
sub sp,byte +0x16 ;这里是啥意思啊? 栈指针减16h(22),留出22个内存?
mov bx, ;bx=ax这是什么意思?好像这个内存值是ax的值
shr bx,0x8 ;bl=ah假如是ax值 ,那么这里就是取aH的值,int13入口 哈哈
mov ,bl ;入口值ah存入
mov si, ;si=ax
and si,0xff ;si低位清零
mov al, ;al=dl 但是这里不太清楚是高位还是低位***???应该是低位
mov ah, ;ah=cl
mov cl, ;cl=al
mov dx, ;dx=cx
shr dx,0x8 ;dl=ch
mov ,dx ;cx存入
cmp bl,0x8 ;将入口值ah与8比
jc e ;借位时跳转读写都是小于8 所以这里跳转
e:
cmp bl,0x1
jc 0x3309 ;小于1跳转? 很明显读写值大于1,所以暂且不管他
jna word 0x3382 ;无符号不大于跳转,意思是小于等于跳转,暂且不管他
cmp bl,0x5
jz word 0x36cc ;等于5时跳转,还是不管他
cmp bl,0x4
jna word f ;无符号不大于跳转,意思是小于等于跳转,啊哈哈 是他是他就是他
f:
mov ch,cl ;ch=al(入口值,要读写的扇区数)
mov dl, ;dl=cl(入口值,起始扇区号)
mov ,dl ;cl(入口值,起始扇区号)存入
mov ,ah ;cl(入口值,起始扇区号)存入
mov dx, ;dx=dx(入口值,
shr dx,0x8 ;dl=dh(入口值,磁头号)
mov ,dl ;dh(入口值,磁头号)存入
mov ,al ;dl(入口值,驱动器号)存入
cmp al,0x1 ;此时al=入口的dl值驱动器号*****??????????
ja 0x33c9 ;无符号大于1跳转,我用1号软驱读写,不管他
cmp dl,0x1 ;此时dl=磁头号 也就是入口时的dh,与1比
ja 0x33c9 ;大于跳,我应该只读写两面,也就是0~1,所以这个不管他
test cl,cl ;测试要读写的扇区数
jz 0x33c9 ;为0跳,我要读写肯定不为0,所以不管他
cmp cl,0x48 ;测试要读写的扇区数是否大于48h
jna g;0x33f3 ;小于等于就跳 就跳
g:
movzx ax, ;高位扩展为0 即 ax=0000+dl(dl为入口值)
call gcall ;word 0x3264应该快接近真相了吧
test ax,ax ;ax=1或者0,这是从71h端口读出的一个数值处理后得到
jz word 0x3500 ;为0时跳,***暂时先不理会***
;假设ax=1,执行下列命令
movzx dx, ;高位扩展为0 即 dx=0000+dl(dl为入口值)
mov ax,dx ;ax=dl(dl为入口值)
call g2call ;word 0x30a9
test ax,ax
g2call:
push bp
mov bp,sp
push bx
push dx
mov bx,ax ;bx=dl(dl为入口值)
mov dx,0x3e
mov ax,0x40
call onecalltwo ;word 0x16b8 又去查bios数据区;
;40:003e表示磁盘驱动器的搜索状态。
;如果这些位中有一位为0,则表示在搜索磁道之前,必须重新校准相应的驱动器。
;位4-6未使用,位7为中断标志位,为1表示中断发生
;BIOS数据区说明 https://wenku.baidu.com/view/5c865a2aeff9aef8941e06d8.html
mov ah,al ;ah=al=多少呢? 暂时先不理会***
test bx,bx ;bx=dl(dl为入口值)
jz 0x30c1 ;dl不为0,不跳
shr al,1 ;因为不是0号驱动器,所以al右移1位?
and al,0x1 ;保留1号驱动的搜索状态
jnz Ncalibration ;0x30c9 ;看是否需要重新校准? 不为0则跳,为0则往下执行校准
xor ah,ah
jmp short 0x30e5
Ncalibration:
mov dx,0x90 ;dx上一步值为0x3e,再上一步dx=0000+dl(dl为入口值)
test bx,bx ;bx=dl(dl为入口值)
jz 0x30d3 ;dl不为0,不跳
mov dx,0x91
mov ax,0x40
call onecalltwo ;word 0x16b8 又去查bios数据区;
;40:0091 字节 驱动器1介质状态
xor ah,ah
sar ax,0x4 ;SAR是算术右移指令,功能是将操作数右移,符号位保持不变
;作用是将AX中的数右移4位,这样就是取al的高4位
;第4位 介质已知 5 需要双倍速率
;第6~7位磁盘数据传送速率00:500K/S 01:300K/S 10:250K/S 11:保留
;https://wenku.baidu.com/view/9ba4d2f5ba0d4a7302763a48.html
and al,0x1 ;此意是查介质是否已知,但是不知道是0为已知还是1为已知
jz 0x30c5 ;介质是否已知,反正为0跳转,跳了以后会xor ah,ah 然后接下下步
mov ax,0x1
lea sp, ;介质是否已知,都会跳到这里,不同的是ax=0或者1,到这里我有点接不下去了
pop dx
pop bx
pop bp
ret ;g2call的 ret
;好想放弃了,2万行左右的代码,我这里只看了200来行,花了十来天了
;查不到的东西越来越多,好难啊。。。到底该从哪学??
gcall:
push bp
mov bp,sp
push dx ;dx=00dh,入栈(入口值,磁头号)
mov dx,ax ;dx=00dl,(入口值,驱动器号) 操他妈的换来换去有意思?
mov ax,0x10 ;ax=0x10
call gcallcall ;word 0x1714 ;
test dx,dx ;dx还是=00dl (入口值,驱动器号)
jnz port70 ;0x3279 ;我要写的是1号软驱,所以这里不为0,跳
shr al,0x4 ;dl不为0,到不了这一步 上一步就ret了
jmp short 0x327b
port70:
and al,0xf ;将al高4位置0
test al,al ;
setnz al ;Sets the byte in the operand to 1 if the Zero Flag is clear
;otherwise sets the operand to 0
;如果ZF标志位为0,al=1 如果ZF标志位为1,al=0
xor ah,ah ;ah=0
lea sp, ;例行放屁
pop dx
pop bp
ret ;gcall完结点,返回g
gcallcall:
push bp
mov bp,sp
push dx ;dx=00dl,入栈(入口值,驱动器号)
mov ah,0x70 ;ax=0x7010
cmp al,0x80 ;al=0x10,和0x80比
jc here ;0x1720 ;借位跳转,这里是跳的
mov ah,0x72
here: ;第一次端口读写操作
movzx dx,ah ;高位扩展为0,即 dx=00ah=0x0070
out dx,al ;给70h端口赋值 0x10 ****** 此端口写入数据后不知道会发生什么
;70h端口好像是CMOS的端口,给这个端口写入"9,8,7,4,2,0"分别是读年月日,时秒分进71h端口
;这里到底是不是CMOS的端口呢??
;写入0x10 即从0x10处读取数值,这个数值是什么?就不知道是什么意思了
;CMOSRAM 内容:https://wenku.baidu.com/view/de597a671ed9ad51f01df274.html?re=view
;Bits 7-4 = Drive 0 type
;Bits 3-0 = Drive 1 type
movzx dx,ah ;高位扩展为0,即 dx=00ah=0x0070
inc dx ;dx=0x0071
in al,dx ;读取71h端口一个数进al
sub ah,ah ;ah=0
lea sp, ;这是在脱裤子放屁吗,lea指令将一个近地址指针写入到指定的寄存器
;这里即将ss:的地址赋值给sp,而sp的值本来就是这个嘛
pop dx ;dx=00dl(入口值,驱动器号)
pop bp
ret ;gcallcall 的 ret
onecall:
push bp ;保存bp
mov bp,sp ;bp=sp 等于栈指针此时的数值,6 这之前push了6个寄存器,最后一个是bp
mov dx,0xe
mov ax,0x40
call onecallone
mov dx,0x366
call onecalltwo
mov sp,bp
pop bp
ret
onecallone: ;此时dx=0xeax=0x40
;bios数据查询程序,这里查字 单元
push bx
push bp
mov bp,sp ;等于栈指针此时的数值,6 这之前push了8个寄存器,最后一个是bp
mov bx,dx
mov es,ax
mov ax, ;ax= 这里是BIOS数据区的一个数值,不知道是什么
pop bp
pop bx
ret
onecalltwo: ;此时dx=0x366 ax==9fc0
;第二次dx=0x3e ax=0x40
;bios数据查询程序,这里查字节 单元
push bx
push bp
mov bp,sp
mov bx,dx
mov es,ax ;es==9fc0
mov al, ;al===0
pop bp
pop bx
ret
twocall:
push bp
mov bp,sp
mov dx,0xe
mov ax,0x40
call onecallone
mov dx,0x368
call onecalltwo
mov sp,bp
pop bp
ret
2017.7.8
页:
[1]