MBR: fix problems when LBA > 65535*sectors.
authorH. Peter Anvin <hpa@zytor.com>
Tue, 10 Apr 2007 22:23:30 +0000 (15:23 -0700)
committerH. Peter Anvin <hpa@zytor.com>
Tue, 10 Apr 2007 22:23:30 +0000 (15:23 -0700)
Fix division overflow bug when LBA > 65535*sectors.  Bug report by
Devin Bayer.

mbr/mbr.S
mbr/oldmbr.asm

index 3eff070..1e6842b 100644 (file)
--- a/mbr/mbr.S
+++ b/mbr/mbr.S
        .text
 
        .globl  bootsec
-stack   = 0x7c00
-driveno        = (stack-6)
-heads  = (stack-8)
-sectors        = (stack-10)
+stack          = 0x7c00
+driveno                = (stack-6)
+sectors                = (stack-8)
+secpercyl      = (stack-10)
 
 BIOS_page = 0x462
 
@@ -89,12 +89,13 @@ next:
        /* Get (C)HS geometry */
        movb    $0x08, %ah
        int     $0x13
+       andw    $0x3f, %cx      /* Sector count */
+       pushw   %cx             /* Save sectors on the stack */
        xorw    %ax, %ax
        movb    %dh, %al        /* dh = number of heads */
        incw    %ax             /* From 0-based to count */
-       pushw   %ax             /* Save heads on the stack */
-       andw    $0x3f, %cx      /* Sector count */
-       pushw   %cx             /* Save sectors on the stack */
+       mulw    %cx             /* Heads*sectors -> sectors per cylinder */
+       pushw   %ax             /* Save sectors/cylinder on the stack */
 
        xorl    %eax, %eax
        pushl   %eax            /* Base */
@@ -112,18 +113,16 @@ read_sector:
 read_sector_cbios:
        movl    %eax, %edx
        shrl    $16, %edx
-       divw    (sectors)
-       incw    %dx
-       movw    %dx, %cx
-       xorw    %dx, %dx
-       divw    (heads)
-       /* dx = head, ax = cylinder */
+       divw    (secpercyl)
+       rorb    %ah
+       rorb    %ah
+       movb    %ah, %cl
        movb    %al, %ch
-       shrw    $2, %ax
-       shrw    %ax
-       andb    $0xc0, %al
-       orb     %al, %cl
-       movb    %dl, %dh
+       movw    %dx, %ax
+       divb    (sectors)
+       movb    %al, %dh
+       incb    %ah
+       orb     %ah, %cl
        movw    $bootsec, %bx
        movw    $0x0201, %ax
        jmp     read_common
index 31bf1fd..f3e6728 100644 (file)
@@ -1,6 +1,6 @@
 ; -----------------------------------------------------------------------
 ;
-;   Copyright 2003-2004 H. Peter Anvin - All Rights Reserved
+;   Copyright 2003-2007 H. Peter Anvin - All Rights Reserved
 ;
 ;   Permission is hereby granted, free of charge, to any person
 ;   obtaining a copy of this software and associated documentation
@@ -81,12 +81,13 @@ next:
 ;
                mov ah,08h                      ; Get drive parameters
                int 13h
+               and cx,3Fh                      ; Max sector number
+               mov [Sectors],cx
                xor ax,ax
                mov al,dh
                inc ax                          ; From 0-based to count
-               mov [Heads],ax
-               and cl,3Fh                      ; Max sector number
-               mov [Sectors],cl
+               mul cx                          ; Heads*Sectors
+               mov [SecPerCyl],ax
                ; Note: we actually don't care about the number of
                ; cylinders, since that's the highest-order division
 
@@ -142,18 +143,18 @@ no_ebios:
                push di
                mov ax,[di+8]
                mov dx,[di+10]
-               div word [Sectors]
-               inc dx
-               mov cx,dx                       ; Sector #
-               xor dx,dx
-               div word [Heads]
-               ; DX = head #, AX = cylinder #
-               mov ch,al
-               shr ax,1
-               shr ax,1
-               and al,0C0h
-               or cl,al
-               mov dh,dl                       ; Head #
+               div word [SecPerCyl]    ; AX = cylinder DX = sec in cyl
+               ror ah,1
+               ror ah,1
+               mov cl,ah
+               mov ch,al                       ; CL = cyl[9:8], CH = cyl[7:0]
+
+               mov ax,dx
+               div byte [Sectors]              ; AL = head AH = sector
+               mov dh,al
+               inc ah
+               or cl,ah                        ; CX = cylinder and sector
+               
                mov dl,[DriveNo]
                mov bx,7C00h
                mov ax,0201h                    ; Read one sector
@@ -207,7 +208,7 @@ dapa:
                dd 0                            ; LBA (MSW)
 
 ; CHS information
-Heads:         dw 0
+SecPerCyl:     dw 0                            ; Heads*Sectors
 Sectors:       dw 0
 
 ; Error messages