在实模式下使用BIOS格式化磁盘时出错

时间:2016-07-01 11:11:29

标签: assembly x86 format x86-16 bootloader

我正在大学学习集会。我正在尝试编写个人格式例程,但我遇到了一些问题。例程在引导时启动,但在第一次中断(INT 13h/AH=7)后进入错误流程。打印AH status值表示错误为:

  

检测到0Eh控制数据地址标记(硬盘)

这是我的引导加载程序代码:

[BITS 16]
[ORG 0x7C00]

init:
call main
ret


main:
xor ax, ax
mov ds, ax

mov si, string0
call print
call delay
mov si, string1
call print
call delay
mov si, string2
call print
call delay
mov si, string3
call print
call delay
mov si, string4
call print
call delay
mov si, string5
call print
call delay
mov si, string6
call print
call delay
mov si, string7
call print
call delay
mov si, string8
call print
call delay
mov si, string9
call print
call delay
mov si, string10
call print
call delay
mov si, string11
call print
call delay
mov si, string12
call print
call delay
mov si, string13
call print
call delay
mov si, string14
call print
call delay
mov si, string15
call print
call delay
mov si, string16
call print
call delay
mov si, string17
call print
call delay
mov si, string18
call print
call delay
mov si, string19
call print
call delay
mov si, string20
call print
call delay
mov si, string21
call print
call delay
mov si, string22
call print
call delay
mov si, string23
call print
call delay
mov si, string24
call print
call delay
mov si,string25
call print
call delay

call read_and_print
cmp al,'A'
jne error
call read_and_print
cmp al,'P'
jne error
call read_and_print
cmp al,'O'
jne error
call read_and_print
cmp al,'C'
jne error
call read_and_print
cmp al,'A'
jne error
call read_and_print
cmp al,'L'
jne error
call read_and_print
cmp al,'Y'
jne error
call read_and_print
cmp al,'P'
jne error
call read_and_print
cmp al,'S'
jne error
call read_and_print
cmp al,'E'
jne error


mov si,String27
call print
call menu
mov si,String35
call print
jmp $

menu:

mov si,String30
call print

call only_read
cmp al, 'A'
je zero_routine 
cmp al, 'B'
je exit_routine
jmp menu

exit_routine:
mov si, String29
call print
ret

zero_routine: ;Command Shell;

mov si,String31
call print

call only_read
cmp al, 'A'
je A_Command
cmp al, 'B'
je B_Command
cmp al, 'C'
je exit_routine


A_Command:

xor eax,eax

mov ah,0x00 ; Reset the disk ;
mov dl, 0x80; First Disk ;
int 13h
mov ah,0x01 ; Get Disk Status ;
mov dl, 0x80; First Disk ;
int 13h
cmp ah, 0x00 
jne f_error
mov si,String36
call print
;;;;;;;;;;;;;;;;;;;;;
; AH    07h         ;
; AL    Interleave  ;
; CH    Track       ;
; CL    Sector      ;
; DH    Head        ;
; DL    Drive       ;
;;;;;;;;;;;;;;;;;;;;; 



mov ah, 0x07
mov al, 0x00
mov ch, 0x00
mov dl, 0x80
mov dh, 0x00

call format
jmp zero_routine

B_Command:

xor eax,eax

mov ah,0x00 ; Reset the disk ;
mov dl, 0x81; Second Disk ;
int 13h
mov ah,0x01 ; Get Disk Status ;
mov dl, 0x81; Second Disk ;
int 13h
cmp ah, 0x00 
jne f_error
mov si,String36
call print

;;;;;;;;;;;;;;;;;;;;;
; AH    07h         ;
; AL    Interleave  ;
; CH    Track       ;
; CL    Sector      ;
; DH    Head        ;
; DL    Drive       ;
;;;;;;;;;;;;;;;;;;;;; 


mov ah, 0x07
mov al, 0x00
mov cl, 0x00
mov ch, 0x00
mov dl, 0x81
mov dh, 0x00

call format
jmp zero_routine

format:

mov si, String32
call print
int 13h ; Format Drive ;
cmp ah, 0x00 
jne f_error
mov si, String33
call print
ret

f_error:

mov si, String34
call print

xor al,al
add al,ah

mov ah, 0Ah ; Write Character
mov bh, 00h ; Page = 0
mov cx, 01h ; Times = 1
int 10h 
jmp $

error:
mov si,String26
call print
jmp $


print:

mov bl,0x0A
mov ah, 0x0E
mov bh, 0x00

nextchar:
lodsb
or al, al
jz return
int 0x10
jmp nextchar

return: 
ret

delay:

mov ah, 86h
mov cx, 0x00
mov dx, 0x8000
int 15h

ret

only_read:

mov ah, 00h ; Read Character
int 16h
ret

read_and_print:

mov ah, 00h ; Read Character
int 16h

push ax ; Save the current character

mov ah, 0Ah ; Write Character
mov bh, 00h ; Page = 0
mov cx, 01h ; Times = 1
int 10h 

cursor_forward:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;AX = 0, CH = Start scan line, CL = End scan line, DH = Row, DL = Column;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


mov ah, 03h ; Read cursor position
mov bh, 00h ; Page = 0;
int 10h     

mov ah,02h ; Set Cursor Position
mov bh,00h ; Page = 0
add dl,01h ; Column++
int 10h

pop ax

ret


    string0 db "MEMORY Check 0401B + 204R81B     OK",`\n`,`\r`,0
    string1 db "JA Hi-SYS BOOT!",`\n`,`\r`,0
    string2 db "Copyright (C) 2014,2015",`\n`,`\r`,0
    string3 db "CO-CPU            Check         256seg      OK",`\n`,`\r`,0
    string4 db "I/O VECTORS       Check                     OK",`\n`,`\r`,0
    string5 db "ROOTING TABLES    Check                     OK",`\n`,`\r`,0
    string6 db "STATUS ANALYZER   Check         SLAVE       OK",`\n`,`\r`,0
    string7 db "VIRUS PROTECTION  Check         GREEN       OK",`\n`,`\r`,0
    string8 db "-----  SYSTEM CONFIGURATION  -----",`\n`,`\r`,0
    string9 db "addr PSP  blks    size  owner/parameters",`\n`,`\r`,0
    string10 db "---- ---- ---- -------  ----------------------",`\n`,`\r`,0
    string11 db "D0E0 sys    1     5296  kozaic",`\n`,`\r`,0
    string12 db "D22C sys    1     2416  ersdrv",`\n`,`\r`,0    
    string13 db "D2C4 2081   1    16384  smalldrv",`\n`,`\r`,0
    string14 db "D6C5-DBFE   1    21392  <free>",`\n`,`\r`,0
    string15 db "DE02-E000   1     8160  <free>",`\n`,`\r`,0
    string16 db "--- UMB total:  53 TB ---",`\n`,`\r`,0
    string17 db "0586 sys    1     2144  shimem",`\n`,`\r`,0
    string18 db "060D sys    1     3968  hemm386",`\n`,`\r`,0
    string19 db "0706 sys    1     3312  smalldrv",`\n`,`\r`,0
    string20 db "07ED sys    1    13568  adam8b CON",`\n`,`\r`,0
    string21 db "0C18 sys    4    65424  <config>",`\n`,`\r`,0
    string22 db "1CD6 <--    1    15008  share 7L:500",`\n`,`\r`,0
    string23 db "2081 <--    1    13712  smalldrv",`\n`,`\r`,0
    string24 db "23DB-9FFF   1   508464  <free>",`\n`,`\n`,`\r`,0
    string25 db "---- Insert Password ----",`\n`,`\r`,0     
    String26 db "  ---- Error... Please Reboot----",`\n`,`\r`,0
    String27 db "  ---- OK ----",`\n`,`\r`,0
    String28 db "---- Error... No Such Subroutine ----",`\n`,`\r`,0
    String29 db `\n`,`\r`,"---- Exiting----",`\n`,`\r`,0
    String30 db "---- Menu: A = Command Shell, B = Exit ----",0
    String31 db `\n`,`\r`,"---- Menu: A = Format Disk 1, B = Format Disk 2, C = Exit ----",0
    String32 db `\n`,`\r`,"---- Formatting Disk - Please Wait... ---- ",`\n`,`\r`,0
    String33 db "---- Disk Formatted ----",`\n`,`\r`,0
    String34 db `\n`,`\r`,"---- Error While Formatting ---- ",0
    String35 db "---- You Can Now Reboot Your Computer ---- ",0
    String36 db `\n`,`\n`,`\r`,"---- Disk Resetted ----",`\n`,`\r`,0

1 个答案:

答案 0 :(得分:9)

这个答案不是试图调试代码,而是建议一种机制来克服这个引导加载程序的严重问题。我意识到这可能无法回答您关于INT 13h/AH=07h的具体问题。

您的原始问题没有提及启动媒体。如果它使用的是软盘/硬盘驱动器,那么您必须关注这些问题:

  • BIOS 仅将启动盘的前512个字节读入内存。
  • 您的代码在最后2个字节中缺少引导扇区签名(0xAA55)。这可能不是某些虚拟机的问题,但通常会导致引导扇区不被许多BIOS视为可启动。
  • 明确设置SS:SP堆栈指针,以免在引导加载程序代码中覆盖它

代码和数据远远超过512字节。 (我相信差不多2k)。虽然BIOS只读取前512个字节(第一个扇区),但没有什么可以阻止您在引导扇区之后手动从扇区加载数据。引导扇区是#1,扇区#2是紧随其后的扇区。您可以使用INT 13/AH=02h来读取磁盘扇区。从Ralf Brown的中断列表中我们发现它是这样定义的:

  

磁盘 - 将扇区读入存储器

AH = 02h
AL = number of sectors to read (must be nonzero)
CH = low eight bits of cylinder number
CL = sector number 1-63 (bits 0-5)
high two bits of cylinder (bits 6-7, hard disk only)
DH = head number
DL = drive number (bit 7 set for hard disk)
ES:BX -> data buffer
     

返回:

CF set on error
if AH = 11h (corrected ECC error), AL = burst length
CF clear if successful
AH = status (see #00234)
AL = number of sectors transferred (only valid if CF set for some
BIOSes)

在您的情况下,我们只读取 DL 寄存器中BIOS传递的启动驱动器中的8个扇区(4096字节)。我们会在BIOS加载的原始512字节后立即将它们读入0x0000:0x7e00的内存中。在引导加载程序的前512个字节之后放置主数据和代码以及在引导加载程序的前512个字节中执行初始化和磁盘读取的代码可能更容易。

我们可以填充引导扇区的前512个字节并添加磁盘签名:

times 510 - ($-$$) db 0            ; Fill empty bytes to pad out first
                                   ;     sector with zeroes
dw 0aa55h                          ; Last 16-bit word of boot sector should be 0xaa55

结果代码可能类似于:

[BITS 16]
[ORG 0x7C00]

init:
xor ax, ax
mov ds, ax        ; DS=0
mov es, ax        ; ES=0
mov ss, ax
mov sp, 7c00h     ; Place SS:SP at 0000h:7c00h
cld

;AH = 02h
;AL = number of sectors to read (must be nonzero). 
;CH = low eight bits of cylinder number
;CL = sector number 1-63 (bits 0-5)
;     Sector numbers start at 1, not 0!
;high two bits of cylinder (bits 6-7, hard disk only)
;DH = head number
;DL = drive number (bit 7 set for hard disk). Passed in by BIOS
;ES:BX -> data buffer. ES set to 0 earlier

mov ax, 0208h     ; AH=2 disk read, AL = number sectors to read = 8 (4k)
mov cx, 0002h     ; CH=Cylinder number 0, CL=sector to start reading = 2
                  ;    Sector 2 = sector right after boot sector
xor dh, dh        ; DH=head number = 0
mov bx, 7e00h     ; ES:BX = memory to read into. ES=0, BX=7e00h right 
                  ;    after the first 512 bytes read by BIOS
int 13h           ; Int 13h/AH=02 disk read
                  ;    Should check carry flag for disk error. Leave
                  ;    as exercise for reader.
call main
ret

times 510 - ($-$$) db 0            ; Fill empty bytes to pad out first
                                   ;     sector with zeroes
dw 0aa55h                          ; Last 16-bit word of boot sector should be 0xaa55

; This label will start at the 513th byte of the file (first byte of sector 2)
main:

mov si, string0
call print
call delay
mov si, string1
call print
call delay
mov si, string2
call print
call delay
mov si, string3
call print
call delay
mov si, string4
call print
call delay
mov si, string5
call print
call delay
mov si, string6
call print
call delay
mov si, string7
call print
call delay
mov si, string8
call print
call delay
mov si, string9
call print
call delay
mov si, string10
call print
call delay
mov si, string11
call print
call delay
mov si, string12
call print
call delay
mov si, string13
call print
call delay
mov si, string14
call print
call delay
mov si, string15
call print
call delay
mov si, string16
call print
call delay
mov si, string17
call print
call delay
mov si, string18
call print
call delay
mov si, string19
call print
call delay
mov si, string20
call print
call delay
mov si, string21
call print
call delay
mov si, string22
call print
call delay
mov si, string23
call print
call delay
mov si, string24
call print
call delay
mov si,string25
call print
call delay

call read_and_print
cmp al,'A'
jne error
call read_and_print
cmp al,'P'
jne error
call read_and_print
cmp al,'O'
jne error
call read_and_print
cmp al,'C'
jne error
call read_and_print
cmp al,'A'
jne error
call read_and_print
cmp al,'L'
jne error
call read_and_print
cmp al,'Y'
jne error
call read_and_print
cmp al,'P'
jne error
call read_and_print
cmp al,'S'
jne error
call read_and_print
cmp al,'E'
jne error


mov si,String27
call print
call menu
mov si,String35
call print
jmp $

menu:

mov si,String30
call print

call only_read
cmp al, 'A'
je zero_routine 
cmp al, 'B'
je exit_routine
jmp menu

exit_routine:
mov si, String29
call print
ret

zero_routine: ;Command Shell;

mov si,String31
call print

call only_read
cmp al, 'A'
je A_Command
cmp al, 'B'
je B_Command
cmp al, 'C'
je exit_routine


A_Command:

xor eax,eax

mov ah,0x00 ; Reset the disk ;
mov dl, 0x80; First Disk ;
int 13h
mov ah,0x01 ; Get Disk Status ;
mov dl, 0x80; First Disk ;
int 13h
cmp ah, 0x00 
jne f_error
mov si,String36
call print
;;;;;;;;;;;;;;;;;;;;;
; AH    07h         ;
; AL    Interleave  ;
; CH    Track       ;
; CL    Sector      ;
; DH    Head        ;
; DL    Drive       ;
;;;;;;;;;;;;;;;;;;;;; 



mov ah, 0x07
mov al, 0x00
mov ch, 0x00
mov dl, 0x80
mov dh, 0x00

call format
jmp zero_routine

B_Command:

xor eax,eax

mov ah,0x00 ; Reset the disk ;
mov dl, 0x81; Second Disk ;
int 13h
mov ah,0x01 ; Get Disk Status ;
mov dl, 0x81; Second Disk ;
int 13h
cmp ah, 0x00 
jne f_error
mov si,String36
call print

;;;;;;;;;;;;;;;;;;;;;
; AH    07h         ;
; AL    Interleave  ;
; CH    Track       ;
; CL    Sector      ;
; DH    Head        ;
; DL    Drive       ;
;;;;;;;;;;;;;;;;;;;;; 


mov ah, 0x07
mov al, 0x00
mov cl, 0x00
mov ch, 0x00
mov dl, 0x81
mov dh, 0x00

call format
jmp zero_routine

format:

mov si, String32
call print
int 13h ; Format Drive ;
cmp ah, 0x00 
jne f_error
mov si, String33
call print
ret

f_error:

mov si, String34
call print

xor al,al
add al,ah

mov ah, 0Ah ; Write Character
mov bh, 00h ; Page = 0
mov cx, 01h ; Times = 1
int 10h 
jmp $

error:
mov si,String26
call print
jmp $


print:

mov bl,0x0A
mov ah, 0x0E
mov bh, 0x00

nextchar:
lodsb
or al, al
jz return
int 0x10
jmp nextchar

return: 
ret

delay:

mov ah, 86h
mov cx, 0x00
mov dx, 0x8000
int 15h

ret

only_read:

mov ah, 00h ; Read Character
int 16h
ret

read_and_print:

mov ah, 00h ; Read Character
int 16h

push ax ; Save the current character

mov ah, 0Ah ; Write Character
mov bh, 00h ; Page = 0
mov cx, 01h ; Times = 1
int 10h 

cursor_forward:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;AX = 0, CH = Start scan line, CL = End scan line, DH = Row, DL = Column;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


mov ah, 03h ; Read cursor position
mov bh, 00h ; Page = 0;
int 10h     

mov ah,02h ; Set Cursor Position
mov bh,00h ; Page = 0
add dl,01h ; Column++
int 10h

pop ax

ret



    string0 db "MEMORY Check 0401B + 204R81B     OK",`\n`,`\r`,0
    string1 db "JA Hi-SYS BOOT!",`\n`,`\r`,0
    string2 db "Copyright (C) 2014,2015",`\n`,`\r`,0
    string3 db "CO-CPU            Check         256seg      OK",`\n`,`\r`,0
    string4 db "I/O VECTORS       Check                     OK",`\n`,`\r`,0
    string5 db "ROOTING TABLES    Check                     OK",`\n`,`\r`,0
    string6 db "STATUS ANALYZER   Check         SLAVE       OK",`\n`,`\r`,0
    string7 db "VIRUS PROTECTION  Check         GREEN       OK",`\n`,`\r`,0
    string8 db "-----  SYSTEM CONFIGURATION  -----",`\n`,`\r`,0
    string9 db "addr PSP  blks    size  owner/parameters",`\n`,`\r`,0
    string10 db "---- ---- ---- -------  ----------------------",`\n`,`\r`,0
    string11 db "D0E0 sys    1     5296  kozaic",`\n`,`\r`,0
    string12 db "D22C sys    1     2416  ersdrv",`\n`,`\r`,0    
    string13 db "D2C4 2081   1    16384  smalldrv",`\n`,`\r`,0
    string14 db "D6C5-DBFE   1    21392  <free>",`\n`,`\r`,0
    string15 db "DE02-E000   1     8160  <free>",`\n`,`\r`,0
    string16 db "--- UMB total:  53 TB ---",`\n`,`\r`,0
    string17 db "0586 sys    1     2144  shimem",`\n`,`\r`,0
    string18 db "060D sys    1     3968  hemm386",`\n`,`\r`,0
    string19 db "0706 sys    1     3312  smalldrv",`\n`,`\r`,0
    string20 db "07ED sys    1    13568  adam8b CON",`\n`,`\r`,0
    string21 db "0C18 sys    4    65424  <config>",`\n`,`\r`,0
    string22 db "1CD6 <--    1    15008  share 7L:500",`\n`,`\r`,0
    string23 db "2081 <--    1    13712  smalldrv",`\n`,`\r`,0
    string24 db "23DB-9FFF   1   508464  <free>",`\n`,`\n`,`\r`,0
    string25 db "---- Insert Password ----",`\n`,`\r`,0     
    String26 db "  ---- Error... Please Reboot----",`\n`,`\r`,0
    String27 db "  ---- OK ----",`\n`,`\r`,0
    String28 db "---- Error... No Such Subroutine ----",`\n`,`\r`,0
    String29 db `\n`,`\r`,"---- Exiting----",`\n`,`\r`,0
    String30 db "---- Menu: A = Command Shell, B = Exit ----",0
    String31 db `\n`,`\r`,"---- Menu: A = Format Disk 1, B = Format Disk 2, C = Exit ----",0
    String32 db `\n`,`\r`,"---- Formatting Disk - Please Wait... ---- ",`\n`,`\r`,0
    String33 db "---- Disk Formatted ----",`\n`,`\r`,0
    String34 db `\n`,`\r`,"---- Error While Formatting ---- ",0
    String35 db "---- You Can Now Reboot Your Computer ---- ",0
    String36 db `\n`,`\n`,`\r`,"---- Disk Resetted ----",`\n`,`\r`,0

特别说明:如果您在某些情况下从CD启动,则不需要这样做。正如@RossRidge在评论中指出的那样:

  

使用&#34;无仿真&#34; El Torito CD-ROM引导规范允许引导加载程序长度超过一个(512字节)扇区。开机。如果事实上它们通常是4个扇区,因为它与物理CD-ROM扇区的大小相同(2048字节)。如果长度不是2048字节物理扇区大小的倍数,那么一些BIOS显然会遇到麻烦

您在问题中汇编的代码非常接近2048字节。如果它变得更大,那么你可能会开始遇到没有被BIOS完全加载的代码/数据。

潜在的格式问题

快速查看格式代码会发现一些问题:

mov ah, 0x07
mov al, 0x00
mov cl, 0x00
mov ch, 0x00
mov dl, 0x81
mov dh, 0x00

call format
jmp zero_routine

format:

mov si, String32
call print
int 13h ; Format Drive ;

问题:

  • 您为Int 13h/AH=7h电话设置了注册表,但未设置 ES:BX 以指向格式缓冲区。 BX 尚未设置为有效的偏移量,并且您的原始代码没有 ES 。该电话的文件是:
  

固定磁盘 - 在GIVEN TRACK(XT,PORT)启动格式化驱动器

AH = 07h
AL = interleave value (XT only)
ES:BX = 512-byte format buffer (see AH=05h)
CH = cylinder number (bits 8,9 in high bits of CL)
CL = sector number
DH = head
DL = drive
     

返回:

AH = status code (see #00234)

格式缓冲区在Int 13h/AH=5h中含糊不清地讨论:

ES:BX -> 512-byte format buffer
the first 2*(sectors/track) bytes contain F,N for each sector
F = sector type
00h for good sector
20h to unassign from alternate location
40h to assign to alternate location
80h for bad sector
N = sector number
  • 严重错误:您可能会覆盖所有注册表,因为format会在print之前调用int 13h。一个简单的解决方法可能是在设置格式的寄存器之前打印格式化字符串。

  • CL 中的扇区号从1开始而不是零。

以下代码甚至没有设置 CL

mov ah, 0x07
mov al, 0x00
mov ch, 0x00
mov dl, 0x80
mov dh, 0x00

call format
jmp zero_routine
  • 我不确定INT 13h / AH = 07h是否适用于XT /旧式便携式设备和早期驱动器以外的设备。我发现有些documentation表明可能是这种情况:
  

INT 13h,07h(7)格式化磁盘从Cylinder固定磁盘开始

     

初始化指定柱面上的每个扇区以及随后的所有扇区   具有扇区地址和大小信息的圆柱体。 只有XT才可以使用   这项服务。

您可能必须使用较低级别的BIOS例程,例如INT 13h/AH=5h FIXED DISK - FORMAT CYLINDER 。即使这样,我也不确定这种低级格式如今适用于硬盘。 可能无需调用此功能。我肯定不知道这一点。自80年代和90年代初以来,我个人通过BIOS尝试过这种低级格式。