With new bigger hard disks available, more often is seen problem with old BIOSes those do not support bigger disks. Special case is Award BIOS 4.51PG prior to 05/1999 that freezes with disks above 34 GB. The only possibility how to boot the computer is to set the disk to "None". Some operating systems can use these disks, but not all of them will correctly set up the chipset registers for fastest operation - so the disk could be slow. And of course, it is not possible to boot from such a disk. The solutions are:
E000:0D0D 89 04 mov [si],ax E000:0D0F 26: 8B 45 02 mov ax,WORD PTR ES:[DI+1*2] ;word 1 = cylinders E000:0D13 26: 8A 75 06 mov dh,BYTE PTR ES:[DI+3*2] ;word 3 = heads E000:0D17 26: 8A 55 0C mov dl,BYTE PTR ES:[DI+6*2] ;word 6 = sectors E000:0D1B 26: F6 45 01 80 test byte ptr es:[di+1],80h ;Is ATA device? E000:0D20 75 29 jnz short @F ;No,skip E000:0D22 26: F6 45 63 02 test byte ptr ES:[DI+49*2+1],2 ;check word 49(LBA) to E000:0D27 74 22 jz short @F ;confirm word 60-61 is valid? E000:0D29 26: 66| 83 7D 78 00 cmp dword ptr ES:[DI+60*2],0 E000:0D2F 74 1A je short @F E000:0D31 26: 66| 83 7D 78 FF cmp dword ptr ES:[DI+60*2],0ffffffffh E000:0D37 74 12 je short @F E000:0D39 52 push dx E000:0D3A 8A C6 mov al,dh E000:0D3C F6 E2 mul dl E000:0D3E 8B C8 mov cx,ax E000:0D40 26: 8B 45 78 mov ax,ES:[DI+60*2] ;word 60 = physical sectors low dword E000:0D44 26: 8B 55 7A mov dx,ES:[DI+61*2] ;word 61 = physical sectors high dword E000:0D48 F7 F1 div cx ;Divide overflow here!!! E000:0D4A 5A pop dx @@: E000:0D4B 89 44 02 mov [si+2],ax E000:0D4E 80 FE 10 cmp dh,16 E000:0D51 0F 87 01B6 ja Set_HDD_none E000:0D55 88 74 04 mov BYTE PTR [si+4],dh ;store heads E000:0D58 88 54 10 mov BYTE PTR [si+10],dl ;store sectorsAll hard disks with capacity above 8.4GB shall report 16383 cylinders, 16 heads and 63 sectors per track. The correct size is read LBA_sectors. Maximum disk size without divide overflow is 65535 * 16 * 63 * 512 = 33822351360 bytes = 34 GB.
E000:0D29 26: 81 7D 7A 03F0 cmp word ptr ES:[DI+61*2],03f0h E000:0D2F 72 02 jb small E000:0D31 B2 FF mov dl,255 E000:0D32 90 small: nop E000:0D33 90 nop E000:0D34 90 nop E000:0D35 90 nop E000:0D36 90 nop E000:0D37 90 nop E000:0D38 90 nop
Later I decided not to remove tests for all ones and all zeroes and did other modification:
E000:0D31 E8 DFA6 call Patch_32GB E000:0D34 90 nop E000:0D35 90 nop E000:0D36 90 nop E000:ECDA Patch_32GB: E000:ECDA 26: 81 7D 7A 03F0 cmp word ptr ES:[DI+61*2],03f0h E000:ECE0 72 02 jb small E000:ECE2 B2 FF mov dl,255 E000:ECE4 small: E000:ECE4 26: 66| 83 7D 78 FF cmp dword ptr ES:[DI+60*2],0ffffffffh E000:ECE9 C3 retn
Now all disks with capacity 37, 40 and 60 GB are correctly autodetected, and it is possible to boot from them.
But new problem arises with disks with capacity over 65535 MB - there is divide overflow in displaying the value on the POST screen, and with displaying the size in "Standard CMOS Setup".
The right solution is more complicated. At first, for HX BIOS, the code is located in different part of ROM, called XGROUP CODE or Extended system BIOS. It can be extracted from the compressed image by Award CBROM utility by executing:
cbrom 5t2.22 /other 4100:0 extractreleased from the compressed BIOS:
cbrom 5t2.22 /other 4100:0 releaseadded to the compressed BIOS:
cbrom 5t2.22 /other 4100:0 awardext.rom
It must be noted that some other BIOSes contain the same code in the main (F000 segment) BIOS.
At first, new variable on the stack HDDSIZE_Unit is created, its value is 2 if HDDSIZE variable contains size in megabytes, and 3 for gigabytes.
HDDSIZE_Unit equ USERINTSTACK+96 ;byte (0220h) HDDSIZE_MB equ 2 HDDSIZE_GB equ 3New procedure for calculating HDD size is created:
SPACE IS HERE: F000:D95E 06A2[00] db 1698 dup (0) ;---------------------------------------------- ;calculate HDD size ;Input : AL = heads of HDD ; AH = sectors of HDD ; CX = cylinders of HDD ;Output: HDDSIZE[bp] = size of HDD ; HDDSIZE_Unit[bp] = unit of HDD's size ;---------------------------------------------- public Cal_HDD_Size F000:D95E Cal_HDD_Size: F000:D95E 66| 50 push eax F000:D960 66| 51 push ecx F000:D962 66| 52 push edx F000:D964 F6 E4 mul ah ;heads * sectors F000:D966 F7 E1 mul cx ; * cylinders F000:D968 66| C1 C8 10 ror eax,16 ;shift high word to low F000:D96C 8B C2 mov ax,dx ;set high word = DX F000:D96E 66| C1 C8 10 ror eax,16 F000:D972 66| 33 D2 xor edx,edx ;clear divided number F000:D975 66| B9 000007A1 mov ecx,1000000/512 ;set diving number F000:D97B 66| F7 F1 div ecx F000:D97E B2 02 mov dl,HDDSIZE_MB ;assume MB (below 0ffffh) F000:D980 66| 3D 0000FFFF cmp eax,0ffffh ;size over 0ffffh F000:D986 72 11 jb short Fill_HDDSIZE_Stack;No,skip F000:D988 66| C1 C8 10 ror eax,16 F000:D98C 8B D0 mov dx,ax F000:D98E 66| C1 C8 10 ror eax,16 F000:D992 B9 03E8 mov cx,1000 ;transfer to GB F000:D995 F7 F1 div cx F000:D997 B2 03 mov dl,HDDSIZE_GB ;set GB string F000:D999 Fill_HDDSIZE_Stack: F000:D999 88 96 0220 mov HDDSIZE_Unit[bp],dl ;set unit of HDD size F000:D99D 89 86 009C mov HDDSIZE[bp],ax ;set HDD size F000:D9A1 66| 5A pop edx F000:D9A3 66| 59 pop ecx F000:D9A5 66| 58 pop eax F000:D9A7 C3 retOld code causing divide overflow during displaying the POST (configuration) screen before boot:
;------------------- ;calculate HDD size ;------------------- -- MACRO F000_call Get_HDD_CMOS_Info X:05D4 0E push cs X:05D5 68 05E0 push ret_addr_1 X:05D8 68 7B4A push offset Get_HDD_CMOS_Info X:05DB EA E000ECC0 jmp far ptr F000_call_proc X:05E0 ret_addr_1 X:05E0 1E push ds X:05E1 53 push bx X:05E2 75 1D jnz short Get_User_Type X:05E4 0F B6 02 movzx ax,byte ptr [bp+si] ;Hdd type no. X:05E7 FE C8 dec al X:05E9 C1 E0 04 shl ax,4 X:05EC BB 56F2 mov bx,offset HDISK_PARMS X:05EF 03 D8 add bx,ax X:05F1 68 F000 push 0f000h X:05F4 1F pop ds X:05F5 0F B6 47 02 movzx ax,byte ptr [bx+2] ;heads X:05F9 0F B6 4F 0E movzx cx,byte ptr [bx+14] ;sectors X:05FD 8B 1F mov bx,[bx] ;cylinders X:05FF EB 0A jmp short Disp_HDD_Size X:0601 Get_User_Type: X:0601 0F B6 43 02 movzx ax,byte ptr [bp+di+2] ;heads X:0605 0F B6 4B 07 movzx cx,byte ptr [bp+di+7] ;sectors X:0609 8B 1B mov bx,[bp+di+0] ;cylinders X:060B Disp_HDD_Size: X:060B C1 E1 02 shl cx,2 X:060E F7 E1 mul cx X:0610 F7 E3 mul bx X:0612 5B pop bx X:0613 1F pop ds X:0614 B9 1E84 mov cx,15625/2 X:0617 F7 F1 div cx ;Divide overflow here!!! X:0619 89 86 009C mov HDDSIZE[bp],ax -- MACRO F000_call Disp_Word_Int5 X:061D 0E push cs X:061F 68 0629 push offset ret_addr_2 X:0621 68 43AA push offset Disp_Word_Int5 X:0624 EA E000ECC0 jmp far ptr F000_call_proc X:0629 ret_addr_2: X:0629 BE 02EC mov si,offset MB_Str X:062C @@: -- MACRO post_func_call Disp_Str_In_BIOS X:062C 0E push cs X:062D 68 0638 push offset ret_addr_3 X:0630 68 6681 push offset Disp_Str_In_BIOS X:0633 EA F0004F32 jmp far ptr Post_call_proc ; (F000:4F32) X:0638 ret_addr_3: X:0638 C3 retNew modified code, using new procedure and variables:
;------------------- ;calculate HDD size ;------------------- -- MACRO F000_call Get_HDD_CMOS_Info X:05D4 0E push cs X:05D5 68 05E0 push ret_addr_1 X:05D8 68 7B4A push offset Get_HDD_CMOS_Info X:05DB EA E000ECC0 jmp far ptr F000_call_proc X:05E0 ret_addr_1 X:05E0 1E push ds X:05E1 53 push bx X:05E2 75 1B jnz short Get_User_Type X:05E4 0F B6 02 movzx ax,byte ptr [bp+si] ;Hdd type no. X:05E7 FE C8 dec al X:05E9 C1 E0 04 shl ax,4 X:05EC BB 52D2 mov bx,offset HDISK_PARMS X:05EF 03 D8 add bx,ax X:05F1 68 F000 push 0f000h X:05F4 1F pop ds X:05F5 8A 47 02 mov al,byte ptr [bx+2] ;heads X:05F8 8A 67 0E mov ah,byte ptr [bx+14] ;sectors X:05FB 8B 0F mov cx,[bx] ;cylinders X:05FD EB 08 jmp short Disp_HDD_Size ; (090E) X:05FF Get_User_Type: X:05FF 8A 43 02 mov al,[bp+di+2] ;heads X:0602 8A 63 07 mov ah,[bp+di+7] ;sectors X:0605 8B 0B mov cx,[bp+di+0] ;cylinders X:0607 Disp_HDD_Size: X:0607 E8 119B call X_Cal_HDD_Size ; (17A5) X:060A 5B pop bx X:060B 1F pop ds X:060C 8B 86 009C mov ax,HDDSIZE[bp] -- MACRO F000_call Disp_Word_Int5 X:0610 0E push cs X:0611 68 061F push offset ret_addr_2 X:0614 68 43AA push offset Disp_Word_Int5 X:0617 EA E000ECC0 jmp far ptr F000_call_proc X:061C 47 42 00 GB_str db 'GB', 0 X:061F ret_addr_2: X:061F BE 02EC mov si,offset MB_Str X:0622 80 BE 0220 02 cmp byte ptr HDDSIZE_Unit[bp],HDDSIZE_MB X:0627 76 03 jbe short @F X:0629 BE 061C mov si,offset GB_Str X:062C @@: -- MACRO post_func_call Disp_Str_In_BIOS X:062C 0E push cs X:062D 68 0638 push offset ret_addr_3 X:0630 68 6681 push offset Disp_Str_In_BIOS X:0633 EA F0004F32 jmp far ptr Post_call_proc ; (F000:4F32) X:0638 ret_addr_3: X:0638 C3 ret
New X_Call_HDD_Size procedure located in XGROUP CODE:
X:17A5 X_Call_HDD_Size proc near -- MACRO F000_call Call_HDD_Size X:17A5 0E push cs X:17A6 68 17B1 push offset ret_addr_x X:17A9 68 D95E push offset Call_HDD_Size X:17AC EA E000ECC0 jmp far F000_call_proc X:17B1 ret_addr_x X:17B1 C3 ret X_Call_HDD_Size endp
The second place with divide overflow is displaying HDD size during manual setup (User setting). The divide overflow occurs in Transfer_Hdd_Parms procedure, it is too long, so I will comment only important place:
F000:7CF1 E9 00C4 jmp Not_Hdd ; (7DB8) ........ F000:7CF9 E9 00BC jmp Not_Hdd ; (7DB8) ........ ........ ;------------------- ;calculate HDD size ;------------------- F000:7D98 51 push cx F000:7D99 32 E4 xor ah,ah F000:7D9B 8A 86 0096 mov al,HEAD[bp] F000:7D9F 32 ED xor ch,ch F000:7DA1 8A 8E 009B mov cl,SECTOR[bp] F000:7DA5 C1 E1 02 shl cx,2 F000:7DA8 F7 E1 mul cx F000:7DAA F7 A6 0094 mul word ptr CYLINDER[bp] F000:7DAE B9 1E84 mov cx,15625/2 F000:7DB1 F7 F1 div cx ;Divide overflow here!!! F000:7DB3 89 86 009C mov HDDSIZE[bp],ax F000:7DB7 59 pop cx F000:7DB8 Not_Hdd: F000:7DB8 5E pop si F000:7DB9 C3 ret
and new version, using new procedure and variables:
F000:7CF1 E9 00B3 jmp Not_Hdd ; (7DA7) ........ F000:7CF9 E9 00AB jmp Not_Hdd ; (7DA7) ........ ........ ;------------------- ;calculate HDD size ;------------------- F000:7D98 8A 86 0096 mov al,HEAD[bp] F000:7D9C 8A A6 009B mov ah,SECTOR[bp] F000:7DA0 8B 8E 0094 mov cx,CYLINDER[bp] F000:7DA4 E8 5BB7 call Cal_HDD_Size ; (D95E) F000:7DA7 Not_Hdd: F000:7DA7 5E pop si F000:7DA8 C3 ret and remaining 17 bytes are not important.
In the old standard setup, the size of HDD is in megabytes, but there is no indication of it. With new routines, the size may be either in MB or GB so it is necessary to display it. The following patch achieves it:
F000:7AFE E8 0032 call Check_If_HDD_Type_Item ; (7B33) F000:7B01 75 23 jnz short Show_User_Exit F000:7B03 E8 BCFF call Read_Item_Value ; (3805)to new code
F000:7AFE E8 0032 call Check_If_HDD_Type_Item ; (7B33) F000:7B01 75 23 jnz short Show_User_Exit F000:7B03 E8 5EA2 call Patch_GB ; (D9A8)and add special "patch" procedure is created at the end of the code:
F000:D9A8 Patch_GB: F000:D9A8 B0 4D mov al,'M' F000:D9AA 80 BE 0220 02 cmp byte ptr HDDSIZE_Unit[bp],HDDSIZE_MB F000:D9AF 76 02 jbe short @F F000:D9B1 B0 47 mov al,'G' F000:D9B3 @@: F000:D9B3 FF B6 0080 push word ptr ATTRIBUTE[bp] F000:D9B7 FF B6 0081 push word ptr CURSOR_X[bp] F000:D9BB 80 86 0081 08 add byte ptr CURSOR_X[bp],8 F000:D9C0 E8 63A3 call VNORMAL ; (3D66) F000:D9C3 E8 63FD call Display_Char ; (3DC3) F000:D9C6 8F 86 0081 pop word ptr CURSOR_X[bp] F000:D9CA 8F 86 0080 pop word ptr ATTRIBUTE[bp] F000:D9CE E8 5E34 call Read_Item_Value ; (3805) F000:D9D1 C3 retn
It will be not so easy to find addresses of VNORMAL and Display_Char procedures. In case they are located in main F000 segment BIOS, the names are VNORMAL and Display_Char respectively. VNORMAL procedure looks like this:
;[]========================================================================[] ;Function : Set the display attrib to NORMAL ; ;Input : None ; ;Output : byte ptr ATTRIBUTE[bp] updated ; ;Registers: All preserved ;[]========================================================================[] F000:3D66 Vnormal proc near F000:3D66 50 push ax F000:3D67 53 push bx F000:3D68 8B 9E 014B mov bx,Color_Offset[bp] F000:3D6C 2E: 8A 07 mov al,cs:[bx].CNORMAL F000:3D6F 88 86 0080 mov ATTRIBUTE[bp],al F000:3D73 5B pop bx F000:3D74 58 pop ax F000:3D75 C3 ret Vnormal endp
Display_Char procedure in the main BIOS. It may slightly differ.
;[]========================================================================[] ;Funtion : Display 1 character on screen ; ;Input : al = ASCII code ; ;Output : CURSOR_X[bp] & CURSOR_Y[bp] changed ; ;Registers: FLAG - Destroyed ; Others - Preserved ;[]========================================================================[] F000:3DC3 Display_Char proc near F000:3DC3 50 push ax F000:3DC4 53 push bx F000:3DC5 51 push cx F000:3DC6 52 push dx F000:3DC7 9C pushf F000:3DC8 80 BE 014D AA cmp byte ptr CALLTYPE[bp],POST_CALL F000:3DCD 75 2E jne short Is_Text_POST F000:3DCF FA cli F000:3DD0 F6 86 01E1 10 test byte ptr Post_Temp_Byte[bp],Text_POST F000:3DD5 75 26 jnz short Is_Text_POST F000:3DD7 8A D8 mov bl,al ;Store display ASCII F000:3DD9 B0 A0 mov al,80*2 ;1 char = 2 bytes F000:3DDB F6 A6 0082 mul byte ptr CURSOR_Y[bp] F000:3DDF 8A 8E 0081 mov cl,CURSOR_X[bp] F000:3DE3 32 ED xor ch,ch F000:3DE5 03 C1 add ax,cx F000:3DE7 03 C1 add ax,cx F000:3DE9 8B F8 mov di,ax F000:3DEB 81 C7 7000 add di,Temp_VGA_Off F000:3DEF B8 0000 mov ax,Temp_VGA_Seg F000:3DF2 8E C0 mov es,ax F000:3DF4 8A A6 0080 mov ah,ATTRIBUTE[bp] ;Get display attribute F000:3DF8 8A C3 mov al,bl F000:3DFA AB stosw F000:3DFB EB 1D jmp short Exit_Display_Char ; (3E1A) F000:3DFD Is_Text_POST: F000:3DFD 50 push ax ;Set cursor position to display item name F000:3DFE 8A 96 0081 mov dl,CURSOR_X[bp] ;get column position F000:3E02 8A B6 0082 mov dh,CURSOR_Y[bp] ;get row position F000:3E06 32 FF xor bh,bh ;first page F000:3E08 B4 02 mov ah,2 ;set cursor position F000:3E0A E8 0017 Call Check_Call_Source ; (3E24) F000:3E0D 58 pop ax F000:3E0E B4 09 mov ah,09h ;write TTY F000:3E10 8A 9E 0080 mov bl,byte ptr ATTRIBUTE[bp] F000:3E14 B9 0001 mov cx,1 F000:3E17 E8 000A Call Check_Call_Source ; (3E24) F000:3E1A Exit_Display_Char: F000:3E1A FE 86 0081 inc byte ptr CURSOR_X[bp] F000:3E1E 9D popf F000:3E1F 5A pop dx F000:3E20 59 pop cx F000:3E21 5B pop bx F000:3E22 58 pop ax F000:3E23 C3 ret Display_Char endp
F000_call_proc is used for calling procedures in F000 segment from other segment
E000:ECC0 F000_call_proc: E000:ECC0 68 EC31 push offset F000_func_end E000:ECC3 50 push ax E000:ECC4 9C pushf E000:ECC5 FA cli E000:ECC6 87 EC xchg bp,sp E000:ECC8 8B 46 04 mov ax,[bp+4] E000:ECCB 87 46 06 xchg [bp+6],ax E000:ECCE 89 46 04 mov [bp+4],ax E000:ECD1 87 EC xchg bp,sp E000:ECD3 9D popf E000:ECD4 58 pop ax E000:ECD5 EA F000EC30 jmp far F000_VECT ; (F000:EC30) .... .... F000:EC30 F000_VECT: F000:EC30 C3 retn F000:EC31 F000_func_end: F000:EC31 CB retf
Post_call_proc is used for calling procedures in E000 segment (POST) from other segment
F000:4F32 Post_call_proc: F000:4F32 68 5C71 push offset POST_func_end F000:4F35 50 push ax F000:4F36 9C pushf F000:4F37 FA cli F000:4F38 87 EC xchg bp,sp F000:4F3A 8B 46 04 mov ax,[bp+4] F000:4F3D 87 46 06 xchg [bp+6],ax F000:4F40 89 46 04 mov [bp+4],ax F000:4F43 87 EC xchg bp,sp F000:4F45 9D popf F000:4F46 58 pop ax F000:4F47 EA E0005C70 jmp far ptr POST_VECT ; (E000:8030) .... .... E000:5C70 POST_VECT: E000:5C70 C3 retn E000:5C71 POST_func_end: E000:5C71 CB retf
Processor speed table - original
E000:34BF 90 8E 80 db 400-256, 398-256, CPU66 ;66x6 E000:34C2 6E 6C 80 db 366-256, 364-256, CPU66 ;66x5.5 E000:34C5 5E 5C B0 db 350-256, 348-256, CPU100 ;100x3.5 E000:34C8 4D 4B 80 db 333-256, 331-256, CPU66 ;66x5 E000:34CB 2C 2A 80 db 300-256, 298-256, CPU66 ;66x4.5 E000:34CE 0A 08 80 db 266-256, 264-256, CPU66 ;66x4 E000:34D1 00 db 0
modified - added 450 MHz (75x6) and removed 350 MHz (100x3.5)
E000:34BF C2 C0 90 db 450-256, 448-256, CPU75 ;75x6 E000:34C2 90 8E 80 db 400-256, 398-256, CPU66 ;66x6 E000:34C5 6E 6C 80 db 366-256, 364-256, CPU66 ;66x5.5 E000:34C8 4D 4B 80 db 333-256, 331-256, CPU66 ;66x5
All modifications are done by the same way as are done in newer Award BIOSes (after 04/1999), and if possible, the routines are the same.
E000:0EDF 26: F6 45 6A 04 test byte ptr ES:[DI+53*2],4 ;test word 88 is valid? E000:0EE4 74 18 jz short Ultra_DMA_Exit E000:0EE6 26: 8A 85 00B0 mov al,ES:[DI+88*2] ;Get Ultra DMA mode value E000:0EEB A8 01 test al,1 ;test supported? E000:0EED 74 0F jz short Ultra_DMA_Exit ;Not support then skip E000:0EEF 32 C9 xor cl,cl E000:0EF1 Ultra_DMA_Loop: E000:0EF1 D0 E8 shr al,1 E000:0EF3 73 02 jnc short @F E000:0EF5 8A E1 mov ah,cl E000:0EF7 @@: E000:0EF7 FE C1 inc cl E000:0EF9 80 F9 08 cmp cl,8 E000:0EFC 72 F3 jb short Ultra_DMA_Loop E000:0EFE Ultra_DMA_Exit: E000:0EFE 88 22 mov byte ptr [bp+si],ah E000:0F00 26: 8B 55 62 mov dx,ES:[DI+49*2] E000:0F04 66| C1 E2 10 shl edx,16 E000:0F08 F8 clc E000:0F09 EB 08 jmp short exit_ok
Modified code:
E000:0EF1 E8 DDF7 call Ultra_DMA_Loop E000:0EF4 B0 02 mov al,2 ;default mode 2 E000:0EF6 38 C4 cmp ah,al ;HDD ultra DMA mode over chipset supported E000:0EF8 76 02 jbe short @F ;No,skip E000:0EFA 88 C4 mov ah,al ;Yes,limitation by chipset E000:0EFC @@: E000:0EFC 90 nop E000:0EFD 90 nop
New code at the end of the code in E000 segment:
E000:ECEB Ultra_DMA_Loop: E000:ECEB D0 E8 shr al,1 E000:ECED 73 02 jnc short @F E000:ECEF 8A E1 mov ah,cl E000:ECF1 @@: E000:ECF1 FE C1 inc cl E000:ECF3 80 F9 08 cmp cl,8 E000:ECF6 72 F3 jb short Ultra_DMA_Loop E000:ECF8 Ultra_DMA_Exit: E000:ECF8 retPetr Soucek, 07-Jul-2002