[转载]修复磁盘0磁道损坏的基本代码及其详解
信息来源:黑客防线code segment 'code'
assume cs:code,ds:code
org 100h
start:
jmp begin
msg1 db 'Please Insert a DISK in drive A:',0ah,0dh
db 'Please any key to continue...',0ah,0dh,'$'
msg2 db 'Format Success!',0ah,0dh,'$'
msg3 db 'Format Failed!',0ah,0dh,'$'
id db 0,0,2,2
db 0,0,4,2
db 0,0,6,2
db 0,0,8,2
db 0,0,10,2
db 0,0,12,2
db 0,0,14,2
db 0,0,16,2
db 0,0,18,2
db 0,0,1,2
db 0,0,3,2
db 0,0,5,2
db 0,0,7,2
db 0,0,9,2
db 0,0,11,2
db 0,0,13,2
db 0,0,15,2
db 0,0,17,2;格式化地址控制标识
date db 0eh dup (0);从此处开始的512个字节用于存放引导程序及BPB
reserved dw 0
db 200h-0eh-2h dup (0)
fat db 0f0h,0ffh,0ffh;从此处开始的512个字节用于存放FAT域
db 200h-3h dup (0)
bedsector db 18 dup (0);用于记录当前扇区是否是坏扇区
bedsectorsize db 0;用于记录坏扇区的大小
bedsectorhead db 0;用于记录坏扇区头的扇区号
bedsectortail db 0;用于记录坏扇区尾的扇区号
goodsectorsize db 0;用于记录好扇区的大小
sumsectorsize db 0;用于记录总扇区的大小
formattimes db 0;用于记录格式化的次数
changeid db 1;用于记录需更改的是磁道号还是磁头号
inccl db 0;用于记录是否出现计算磁头、磁道、扇区号的特殊情况
reformattimes db 0;用于记录重试次数
push_a_b_c_dx proc near
push bx
mov bx,sp
inc bx
inc bx
xchg ax,ss:[bx];交换ax寄存器和返回地址的值
push cx
push dx;到此以完成将ax,bx,cx,dx寄存器的内容压入堆栈
push ax;将返回地址压入堆栈
ret;返回调用程序
push_a_b_c_dx endp;此子程序用于保存4个通用寄存器
pop_d_c_b_ax proc near
pop ax;ax的值为返回地址
pop dx
pop cx
mov bx,sp
inc bx
inc bx
xchg ax,ss:[bx];交换原ax寄存器和返回地址的值
pop bx
ret
pop_d_c_b_ax endp;此子程序用于还原4个通用寄存器
re_disk proc near
call push_a_b_c_dx
xor ax,ax
xor dx,dx
int 13h
call pop_d_c_b_ax
ret
re_disk endp;此子程序用于复位软盘驱动器
newint13 proc near
mov [reformattimes],2;将重复次数写入内存
re_newint13:
push ax
int 13h
jc newint13_error;功能调用出错则跳转到出错例程
pop ax
ret;成功则返回
newint13_error:
pop ax
call re_disk
dec [reformattimes]
jnz re_newint13;复位软盘驱动器后,检测重复次数是否为0,不是则跳转
stc;是则置进位标志,以示功能调用不成功,再返回
ret
newint13 endp
incsector proc near
call push_a_b_c_dx
lea bx,id;得到扇区控制地址标识所在的地址
inc bx
inc bx;使bx指向扇区控制地址标识中的扇区号部分
mov cx,18;置循环次数
loop_inc_id_0_0:
inc byte ptr [bx];使扇区号加1
cmp byte ptr [bx],18
jbe no_above_18;比较扇区号是否小于等于18,是则跳转
mov byte ptr [bx],1;不是,则将扇区号置1
no_above_18:
add bx,4;得到下一个要修改的扇区号的地址
loop loop_inc_id_0_0;循环修改扇区号
call pop_d_c_b_ax
ret
incsector endp
format_succ proc near
lea dx,msg2
mov ah,9
int 21h
ret
format_succ endp;显示格式化成功信息
format_fail proc near
lea dx,msg3
mov ah,9
int 21h
ret
format_fail endp;显示格式化失败信息
writeboot proc near
mov ax,301h
lea bx,date
mov cx,1
xor dx,dx
call newint13
ret;将磁盘引导信息及磁盘参数块信息写入逻辑0扇区即0磁头1磁道1扇区
writeboot endp
writefat_no_ax proc near
lea bx,fat;根据公式:磁道号=(保留扇区数+1)/36取商
re_calculation:;磁头号=((保留扇区数+1)/36的余数)/18取商
push ax;扇区号=((保留扇区数+1)/36的余数)/18取余数
mov cl,36;保留扇区数由调用程序存放在ax寄存器中
div cl;当ax中的值为18的倍数时为特例,需单独处理
mov ch,al;考虑ax=18的情况,磁道号=0 磁头号=1 扇区号=0
xor al,al;这将导致软盘驱动器找不到相应的扇区而失败
xchg al,ah;正确值应为,磁道号=0 磁头号=0 扇区号=18
mov cl,18;要算出正确值,则要处理这种特殊情况
div cl;可以将ax的值减1,再参加运算,这时可以算出
mov dh,al;磁道号=0 磁头号=0 扇区号=17,这显然也是错的
mov cl,ah;为此可以设立一个标志,当扇区号为0时,将标志位置1
pop ax;仅当标志位为1时将扇区号加1,并将标志位置0
cmp cl,0
jne cl_no_equ_0
dec ax
mov byte ptr [inccl],1
jmp re_calculation
cl_no_equ_0:
cmp byte ptr [inccl],1
jne no_inccl_1
inc cl
mov byte ptr [inccl],0
no_inccl_1:
mov ax,301h
xor dl,dl
call newint13
ret
writefat_no_ax endp;此子程序将写FAT表,但差磁道、磁头、扇区号
writefat proc near
mov ax,word ptr cs:[reserved]
inc ax;将保留扇区数加1,得到第一个FAT表的位置
call writefat_no_ax;调用写FAT表子程序
jc write_fat_error;出错则退出
mov ax,word ptr cs:[reserved]
add ax,10; 将保留扇区数加10,得到第二个FAT表的位置
call writefat_no_ax;调用写FAT表子程序
write_fat_error:
ret
writefat endp
setreserved proc near
call push_a_b_c_dx
lea bx,sumsectorsize
mov al,byte ptr [bx]
dec bx;此时bx指向goodsectorsize
mov ah,byte ptr [bx]
sub al,ah;根据公式:保留扇区数=格式化扇区总数-好扇区数
xor ah,ah;计算保留扇区数
lea bx,reserved
mov word ptr [bx],ax
call pop_d_c_b_ax
ret
setreserved endp
setbedsectorinformation proc near
call push_a_b_c_dx
lea bx,bedsector
xor ax,ax;ax的值用于判断是要修改坏扇区头(0),还是坏扇区尾(1)
mov cl,1;cl的值用于循环计数及指示当前扇区号
findbedsector_0_0:
cmp byte ptr [bx],1;比较坏扇区标识,1表示是坏扇区,0表示不是坏扇区
jne no_bedsector_0_0
push bx;保存坏扇区标识地址
lea bx,bedsectorsize;得到坏扇区大小地址
inc byte ptr [bx];将坏扇区大小加1
inc bx;得到坏扇区头地址
cmp ax,1
je no_set_bedsectorhead_0_0;ax=0表示设置坏扇区头
mov ax,1; ax=1表示设置坏扇区尾
mov byte ptr [bx],cl;设置坏扇区头
no_set_bedsectorhead_0_0:
inc bx;得到坏扇区尾地址
mov byte ptr [bx],cl;设置坏扇区尾
pop bx
no_bedsector_0_0:
inc cl;扇区号及循环标识加1
inc bx;得到下一个坏扇区地址
cmp cl,19
jne findbedsector_0_0;循环设置坏扇区大小及头尾标识
call pop_d_c_b_ax
ret
setbedsectorinformation endp
format proc near
mov ax,501h;格式化软盘,磁头号及磁道号由调用者提供
lea bx,id
xor dl,dl
call newint13
ret
format endp
testsector proc near
mov ax,401h;测试指定扇区是否完好,磁道号、磁头号及扇区号由调用者提供
xor dl,dl
call newint13
ret
testsector endp
changeheadortrack proc near
call push_a_b_c_dx
lea bx,changeid;得到更改磁道号或磁头号标识,1表示更改磁头号
mov al,byte ptr [bx];0表示更改磁道号及磁头号
xor ah,ah
xor byte ptr [bx],1;标识取反
mov cx,18;循环修改磁道或磁头号18次
lea bx,id;得到扇区控制地址标识起始地址
add bx,ax;ax的值不是0,就是1,加上起始地址后得到要修改的磁道(AX+0)或磁头地址(AX+1)
loop_change_0_0:
cmp al,1
je changehead_0_0;AL为1则修改磁头号
inc byte ptr [bx]
xor byte ptr [bx+1],1;修改磁头及磁道号
jmp loop_start_0_0
changehead_0_0:
xor byte ptr [bx],1;修改磁头号
loop_start_0_0:
add bx,4;计算得到下一个要修改的地址
loop loop_change_0_0
call pop_d_c_b_ax
ret
changeheadortrack endp
formatandtest proc near
call format;调用格式化磁道例程
pushf;保存标志寄存器
jc format_error_0_0 ;错误则退出
push cx
push bx
mov cx,21;设置初始化坏扇区次数
lea bx,bedsector
init_bedsector_0_0:
mov byte ptr [bx],0;初始化为0
inc bx;指向下一个要修改的地址
loop init_bedsector_0_0
pop bx
pop cx
test_next_sector_0_0:
call testsector;测试扇区
jnc test_succ_0_0;成功则转移,失败则设置坏扇区信息
push bx
lea bx,bedsector
push cx
and cx,0ffh;得到测试扇区号
add bx,cx;得到上次要修改的地址加扇区号
dec bx;得到本次要修改的地址,减1是因为扇区号从1开始偏移地址由0开始
mov byte ptr [bx],1;设置此存储单元代表的扇区为坏扇区
pop cx
pop bx
test_succ_0_0:
inc cl;循环及扇区标识加1
cmp cl,19
jne test_next_sector_0_0;循环设置坏扇区
call setbedsectorinformation;设置坏扇区信息
call sum_goodsectorsize;计算好扇区的大小
cmp byte ptr [goodsectorsize],32;比较好扇区数是否大于等于32
jae goodsecotrsize_jae_32;是则跳转
add_sumsectorsize_18:
add byte ptr [sumsectorsize],18;不是则总扇区数加18
jmp format_error_0_0;完成设置总扇区数
goodsectorsize_jae_32:
mov bl,byte ptr [bedsectorhead];是则得到坏扇区头的扇区号
cmp bl,0;比较是否没有坏扇区
je add_sumsectorsize_18;是则将总扇区数加18
dec bl;不是则将坏扇区头的扇区号减1,得到此次格式化所得的好扇区数
add byte ptr [sumsectorsize],bl;总扇区数加此次所得的好扇区数
format_error_0_0:
popf;还原标志寄存器
ret
formatandtest endp
sum_goodsectorsize proc near
call push_a_b_c_dx
mov ah,18
lea bx,bedsectortail
mov al,byte ptr [bx];得到坏扇区尾,无坏扇区时为0,有则为扇区号
mov dl,al;dl为坏扇区号
sub ah,al;计算得到好扇区数
lea bx,formattimes
mov al,byte ptr [bx];得到格式化次数
lea bx,goodsectorsize
cmp al,1
jne formattimes_no_1;格式化次数不为1时跳转,此时不要修改好扇区数
dec ah;格式化次数为1则好扇区数减1,因为有一个保留扇区
formattimes_no_1:
cmp dl,0
jne have_bedsector_0;坏扇区数不为0则跳转,表示用坏扇区
add byte ptr [bx],ah;无坏扇区则好扇区数加ah,即加18
jmp sum_goodsectorsize_end
have_bedsector_0:
mov dl,byte ptr [bedsectorhead];有坏扇区则的到坏扇区头的扇区号
dec dl;坏扇区头减1表示在坏扇区头前拥有的好扇区数
add byte ptr [bx],dl;原来的好扇区数加上这次得到的好扇区数
cmp byte ptr [bx],32;比较是否有了32个连续的好扇区
jae sum_goodsectorsize_end;有则计算结束
cmp ah,0ffh;没有则比较ah的值是否为0FFh,因为格式化次数为1时好扇区数减了1,倘若没有好扇区,则有可能使ah的值为0FFh
jne ah_no_equ_0ffh
inc ah;ah为0ffh时加1
ah_no_equ_0ffh:
mov byte ptr [bx],ah;将新的连续的好扇区数存放在BX指示的存储单元
sum_goodsectorsize_end:
call pop_d_c_b_ax
ret
sum_goodsectorsize endp
begin:
push cs
push cs
pop ds
pop es;使代码段数据段附加段指向同一段
mov ah,9
lea dx,msg1
int 21h;显示提示信息
mov ah,7
int 21h;等待用户击键
push ds
xor ax,ax
mov ds,ax
mov bx,526h
mov byte ptr [bx],18;设置软盘参数表的每道扇区数为18
mov byte ptr [bx+4],0;设置格式化填充字节为0
pop ds
call re_disk;软驱复位
mov cx,14;因总扇区数占用1个字节,而每次格式化将产生18个扇区,将256/18取商则可得到循环测试不能超过14
reformatandtest:
lea bx,goodsectorsize
mov byte ptr [bx],0
inc bx;bx指向sumsectorsize
mov byte ptr [bx],0
inc bx;bx指向formattimes
mov byte ptr [bx],0
loop_formatandtest:
push cx
lea bx,formattimes
inc byte ptr [bx];格式化次数加1
lea bx,id;得到格式化控制地址标识的起始地址(磁道号地址)
mov ch,byte ptr [bx];设置格式化时用到的磁道号
inc bx;得到格式化控制地址标识中的磁头号地址
mov dh,byte ptr [bx];设置格式化时用到的磁头号
mov cl,1;设置测试磁道时用到的磁道号
call formatandtest;调用格式化及测试磁道子程序
jc error;格式化出错则跳转
lea bx,formattimes
mov ah,byte ptr [bx];得到格式化次数
lea bx,goodsectorsize
mov al,byte ptr [bx];得到好扇区的大小
cmp al,32;比较好扇区大小是否大于等于32(2*FAT+FCT=32)
jae loop_formatandtest_end;大于等于则循环格式化及测试完成
lea bx,bedsectorhead
mov al,byte ptr [bx];得到坏扇区头的扇区号
push si
cmp al,1
pushf;比较扇区号是否为1,并保存标志寄存器
cmp ah,1
pushf;比较格式化次数是否为1,并保存标志寄存器
pop ax;将标志寄存器的值存入ax
pop si;将标志寄存器的值存入si
and ax,si;将ax,si进行与操作,主要用于确定标志位Z是否为0
push ax;保存标志
popf;还原标志寄存器
pop si;还原si寄存器
jne loop_formatandtest1;标志位Z不为0,则继续格式化并测试磁道
call incsector;为0表示0道1扇区损坏,则扇区号加1
pop cx;还原格式化计数器
loop reformatandtest;循环重新格式化0磁头0磁道;请不要使用jmp指令,因为可能会出现18个扇区全部损坏的情况,那样将会陷入死循环
loop_formatandtest1:
call changeheadortrack;更改磁头或磁头、磁道号
pop cx
loop loop_formatandtest;循环格式化并测试磁道
jmp error
loop_formatandtest_end:
pop cx;平衡堆栈
call setreserved;计算保留扇区的大小
call writeboot;写引导扇区
jc error
call writefat;写2个FAT表区
jc error
call format_succ;显示格式化成功信息
jmp program_end
error:
call format_fail;显示格式化失败信息
program_end:
mov ax,4c00h
int 21h;程序正常退出
code ends
end start
页:
[1]