1  ; Project name : XTIDE Universal BIOS


2  ; Description : Functions for generating LCHS parameters for


3  ; drives with more than 1024 cylinders.


4  ;


5  ; These algorithms are taken from: http://www.mossywell.com/bootsequence


6  ; Take a look at it for more detailed information.


7  ;


8  ; This file is shared with BIOS Drive Information Tool.


9 


10  ;


11  ; XTIDE Universal BIOS and Associated Tools


12  ; Copyright (C) 20092010 by Tomi Tilli, 20112013 by XTIDE Universal BIOS Team.


13  ;


14  ; This program is free software; you can redistribute it and/or modify


15  ; it under the terms of the GNU General Public License as published by


16  ; the Free Software Foundation; either version 2 of the License, or


17  ; (at your option) any later version.


18  ;


19  ; This program is distributed in the hope that it will be useful,


20  ; but WITHOUT ANY WARRANTY; without even the implied warranty of


21  ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the


22  ; GNU General Public License for more details.


23  ; Visit http://www.gnu.org/licenses/oldlicenses/gpl2.0.html


24  ;


25 


26  ; Section containing code


27  SECTION .text


28 


29  %ifdef MODULE_EBIOS


30  ;


31  ; AtaGeometry_GetLbaSectorCountToBXDXAXfromAtaInfoInESSI


32  ; Parameters:


33  ; ES:SI: Ptr to 512byte ATA information read from the drive


34  ; Returns:


35  ; BX:DX:AX: 48bit sector count


36  ; CL: FLGL_DPT_LBA48 if LBA48 supported


37  ; Zero if only LBA28 is supported


38  ; Corrupts registers:


39  ; Nothing


40  ;


41  AtaGeometry_GetLbaSectorCountToBXDXAXfromAtaInfoInESSI:


42  mov bx, Registers_ExchangeDSSIwithESDI


43  call bx ; ATA info now in DS:DI


44  push bx ; We will return via Registers_ExchangeDSSIwithESDI


45 


46  ; Check if LBA48 supported


47  test BYTE [di+ATA6.wSetSup83+1], A6_wSetSup83_LBA48>>8


48  jz SHORT .GetLba28SectorCount


49 


50  ; Get LBA48 sector count


51  mov cl, FLGL_DPT_LBA48


52  mov ax, [di+ATA6.qwLBACnt]


53  mov dx, [di+ATA6.qwLBACnt+2]


54  mov bx, [di+ATA6.qwLBACnt+4]


55  ret


56 


57  .GetLba28SectorCount:


58  xor cl, cl


59  xor bx, bx


60  mov ax, [di+ATA1.dwLBACnt]


61  mov dx, [di+ATA1.dwLBACnt+2]


62  ret


63  %endif ; MODULE_EBIOS


64 


65 


66  ;


67  ; AtaGeometry_GetLCHStoAXBLBHfromAtaInfoInESSIwithTranslateModeInDX


68  ; Parameters:


69  ; DX: Wanted translate mode or TRANSLATEMODE_AUTO to autodetect


70  ; ES:SI: Ptr to 512byte ATA information read from the drive


71  ; Returns:


72  ; AX: Number of LCHS cylinders (1...1027, yes 1027)


73  ; BL: Number of LCHS heads (1...255)


74  ; BH: Number of LCHS sectors per track (1...63)


75  ; CX: Number of bits shifted (0...3)


76  ; DX: CHS Translate Mode


77  ; Corrupts registers:


78  ; Nothing


79  ;


80  AtaGeometry_GetLCHStoAXBLBHfromAtaInfoInESSIwithTranslateModeInDX:


81  call AtaGeometry_GetPCHStoAXBLBHfromAtaInfoInESSI


82 


83  ; Check if user defined translate mode


84  dec dx ; Set ZF if TRANSLATEMODE_LARGE, SF if TRANSLATEMODE_NORMAL


85  jns SHORT .CheckIfLargeTranslationWanted


86  MIN_U ax, MAX_LCHS_CYLINDERS ; TRANSLATEMODE_NORMAL maximum cylinders


87  inc dx


88  .CheckIfLargeTranslationWanted:


89  jz SHORT ConvertPCHfromAXBLtoRevisedEnhancedCHinAXBL


90  dec dx ; Set ZF if TRANSLATEMODE_ASSISTED_LBA


91  jz SHORT .UseAssistedLBA


92  ; TRANSLATEMODE_AUTO set


93 


94  %ifndef MODULE_EBIOS


95  ; Since we do not have EBIOS functions, we might as well use the faster


96  ; LARGE mode for small drives. Assisted LBA provides more capacity for


97  ; larger drives.


98  ; Generate LCHS using simple bit shift algorithm (ECHS) if


99  ; 8192 or less cylinders.


100  cmp ax, 8192


101  jbe SHORT ConvertPCHfromAXBLtoEnhancedCHinAXBL


102  %else


103  ; Check if the drive is within the limits of NORMAL addressing.


104  ; If it is, then no CHS translation is necessary.


105  cmp ax, MAX_LCHS_CYLINDERS


106  jbe SHORT ConvertPCHfromAXBLtoEnhancedCHinAXBL


107  %endif


108 


109  ; If we have EBIOS functions, we should always use Assisted LBA


110  ; for drives with LBA support. Otherwise the EBIOS functions are


111  ; useless since we never do LBA to PCHS translation.


112  ; Even if we do not have EBIOS functions, we must do this check


113  ; since user might have forced LBA mode even though the drive does


114  ; not support LBA addressing.


115  test BYTE [es:si+ATA1.wCaps+1], A1_wCaps_LBA>>8


116  jz SHORT ConvertPCHfromAXBLtoRevisedEnhancedCHinAXBL


117 


118  ; Assisted LBA provides most capacity but translation algorithm is


119  ; slower. The speed difference doesn't matter on AT systems.


120  .UseAssistedLBA:


121  ; Fall to GetSectorCountToDXAXfromCHSinAXBLBH


122 


123 


124  ;


125  ; GetSectorCountToDXAXfromCHSinAXBLBH


126  ; Parameters:


127  ; AX: Number of cylinders (1...16383)


128  ; BL: Number of heads (1...255)


129  ; BH: Number of sectors per track (1...63)


130  ; Returns:


131  ; DX:AX: Total number of CHS addressable sectors


132  ; Corrupts registers:


133  ; BX


134  ;


135  GetSectorCountToDXAXfromCHSinAXBLBH:


136  xchg ax, bx


137  mul ah ; AX = Heads * Sectors per track


138  mul bx


139  ; Fall to ConvertChsSectorCountFromDXAXtoLbaAssistedLCHSinAXBLBH


140 


141 


142  ;


143  ; LBA assist calculation (or Assisted LBA)


144  ;


145  ; This algorithm translates PCHS sector count up to largest possible


146  ; LCHS sector count (1024, 255, 63). Note that INT 13h interface allows


147  ; 256 heads but DOS supports up to 255 head. That is why BIOSes never


148  ; use 256 heads.


149  ;


150  ; LCHS parameters generated here require the drive to use LBA addressing.


151  ;


152  ; Here is the algorithm:


153  ; If cylinders > 8192


154  ; Variable CH = Total CHS Sectors / 63


155  ; Divide (CH  1) by 1024 and add 1


156  ; Round the result up to the nearest of 16, 32, 64, 128 and 255. This is the value to be used for the number of heads.


157  ; Divide CH by the number of heads. This is the value to be used for the number of cylinders.


158  ;


159  ; ConvertChsSectorCountFromDXAXtoLbaAssistedLCHSinAXBLBH:


160  ; Parameters:


161  ; DX:AX: Total number of PCHS sectors for CHS addressing


162  ; (max = 16383 * 16 * 63 = 16,514,064)


163  ; Returns:


164  ; AX: Number of cylinders (?...1027)


165  ; BL: Number of heads (16, 32, 64, 128 or 255)


166  ; BH: Number of sectors per track (always 63)


167  ; CX: Number of bits shifted (0)


168  ; DX: TRANSLATEMODE_ASSISTED_LBA


169  ; Corrupts registers:


170  ; Nothing


171  ;


172  ConvertChsSectorCountFromDXAXtoLbaAssistedLCHSinAXBLBH:


173  ; Value CH = Total sector count / 63


174  ; Max = 16,514,064 / 63 = 262128


175  mov cx, LBA_ASSIST_SPT ; CX = 63


176 


177  ;  Math_DivDXAXbyCX inlined (and slightly modified) since it's only used here


178  xor bx, bx


179  xchg bx, ax


180  xchg dx, ax


181  div cx


182  xchg ax, bx


183  div cx


184  mov dx, bx


185  ; 


186 


187  push ax


188  push dx ; Value CH stored for later use


189 


190  ; BX:DX:AX = Value CH  1


191  ; Max = 262128  1 = 262127


192  xor bx, bx


193  sub ax, BYTE 1


194  sbb dx, bx


195 


196  ; AX = Number of heads = ((Value CH  1) / 1024) + 1


197  ; Max = (262127 / 1024) + 1 = 256


198  call Size_DivideSizeInBXDXAXby1024 ; Preserves CX and returns with BH cleared


199  pop dx


200  inc ax ; + 1


201 


202  ; Heads must be 16, 32, 64, 128 or 255 (round up to the nearest)


203  ; Max = 255


204  mov bl, 16 ; Min number of heads


205  .CompareNextValidNumberOfHeads:


206  cmp ax, bx


207  jbe SHORT .NumberOfHeadsNowInBX


208  eSHL_IM bx, 1 ; Double number of heads


209  jpo SHORT .CompareNextValidNumberOfHeads ; Reached 256 heads?


210  dec bx ; If so, limit heads to 255


211  .NumberOfHeadsNowInBX:


212 


213  ; DX:AX = Number of cylinders = Value CH (without  1) / number of heads


214  ; Max = 262128 / 255 = 1027


215  pop ax ; Value CH back to DX:AX


216  div bx


217 


218  xchg bh, cl ; Sectors per Track to BH, zero to CL (CX)


219  mov dl, TRANSLATEMODE_ASSISTED_LBA


220  ; All combinations of value CH from 1 to 262128 divided by number of heads


221  ; (16/32/64/128/255) has been verified to return with DH cleared.


222  ReturnLCHSinAXBLBH:


223  ret


224 


225 


226  ;


227  ; AtaGeometry_GetPCHStoAXBLBHfromAtaInfoInESSI


228  ; Parameters:


229  ; ES:SI: Ptr to 512byte ATA information read from the drive


230  ; Returns:


231  ; AX: Number of PCHS cylinders (1...16383)


232  ; BL: Number of PCHS heads (1...16)


233  ; BH: Number of PCHS sectors per track (1...63)


234  ; Corrupts registers:


235  ; Nothing


236  ;


237  AtaGeometry_GetPCHStoAXBLBHfromAtaInfoInESSI:


238  mov ax, [es:si+ATA1.wCylCnt] ; Cylinders (1...16383)


239  mov bl, [es:si+ATA1.wHeadCnt] ; Heads (1...16)


240  mov bh, [es:si+ATA1.wSPT] ; Sectors per Track (1...63)


241  ret


242 


243 


244  ;


245  ; Revised Enhanced CHS calculation (Revised ECHS)


246  ;


247  ; This algorithm translates PCHS sector count to LCHS sector count


248  ; with bit shift algorithm. Since 256 heads are not allowed


249  ; (DOS limit), this algorithm makes translations so that maximum of


250  ; 240 LCHS heads can be used. This makes the maximum addressable capacity


251  ; to 7,927,234,560 bytes ~ 7.38 GiB. LBA addressing needs to be used to


252  ; get more capacity.


253  ;


254  ; LCHS parameters generated here require the drive to use CHS addressing.


255  ;


256  ; Here is the algorithm:


257  ; If cylinders > 8192 and heads = 16


258  ; Heads = 15


259  ; Cylinders = cylinders * 16 / 15 (losing the fraction component)


260  ; Do a standard ECHS translation


261  ;


262  ; *FIXME* The above algorithm seems to be conflicting with info found here


263  ; https://web.archive.org/web/20000817071418/http://www.firmware.com:80/support/bios/over4gb.htm


264  ; which says that Revised ECHS is used when the cylinder count is > 8191.


265  ;


266  ; ConvertPCHfromAXBLtoRevisedEnhancedCHinAXBL:


267  ; Parameters:


268  ; AX: Number of PCHS cylinders (8193...16383)


269  ; BL: Number of PCHS heads (1...16)


270  ; Returns:


271  ; AX: Number of LCHS cylinders (?...1024)


272  ; BL: Number of LCHS heads (?...240)


273  ; CX: Number of bits shifted (0...3)


274  ; DX: TRANSLATEMODE_NORMAL or TRANSLATEMODE_LARGE


275  ; Corrupts registers:


276  ; Nothing


277  ;


278  ConvertPCHfromAXBLtoRevisedEnhancedCHinAXBL:


279  ; Generate LCHS using simple bit shift algorithm (ECHS) if


280  ; 8192 or less cylinders


281  call AtaGeometry_IsDriveSmallEnoughForECHS


282  jc SHORT ConvertPCHfromAXBLtoEnhancedCHinAXBL


283 


284  eMOVZX cx, bl ; CX = 16


285  dec bx ; Heads = 15


286  mul cx ; DX:AX = Cylinders * 16


287  dec cx ; CX = 15


288  div cx ; AX = (Cylinders * 16) / 15


289  ; Fall to ConvertPCHfromAXBLtoEnhancedCHinAXBL


290 


291 


292  ;


293  ; Enhanced CHS calculation (ECHS)


294  ;


295  ; This algorithm translates PCHS sector count to LCHS sector count


296  ; with simple bit shift algorithm. Since 256 heads are not allowed


297  ; (DOS limit), this algorithm require that there are at most 8192


298  ; PCHS cylinders. This makes the maximum addressable capacity


299  ; to 4,227,858,432 bytes ~ 3.94 GiB. Use Revised ECHS or Assisted LBA


300  ; algorithms if there are more than 8192 PCHS cylinders.


301  ;


302  ; LCHS parameters generated here require the drive to use CHS addressing.


303  ;


304  ; Here is the algorithm:


305  ; Multiplier = 1


306  ; Cylinder = Cylinder  1


307  ; Is Cylinder < 1024? If not:


308  ; Do a right bitwise rotation on the cylinder (i.e., divide by 2)


309  ; Do a left bitwise rotation on the multiplier (i.e., multiply by 2)


310  ; Use the multiplier on the Cylinder and Head values to obtain the translated values.


311  ;


312  ; ConvertPCHfromAXBLtoEnhancedCHinAXBL:


313  ; Parameters:


314  ; AX: Number of PCHS cylinders (1...8192, or up to 17475 if fell from above)


315  ; BL: Number of PCHS heads (1...16)


316  ; Returns:


317  ; AX: Number of LCHS cylinders (?...1024)


318  ; BL: Number of LCHS heads (?...128, or up to 240 if fell from above)


319  ; CX: Number of bits shifted (0...3)


320  ; DX: TRANSLATEMODE_NORMAL or TRANSLATEMODE_LARGE


321  ; Corrupts registers:


322  ; Nothing


323  ;


324  ConvertPCHfromAXBLtoEnhancedCHinAXBL:


325  cwd ; Assume TRANSLATEMODE_NORMAL


326  xor cx, cx ; No bits to shift initially


327  .ShiftIfMoreThan1024Cylinder:


328  cmp ax, MAX_LCHS_CYLINDERS


329  jbe SHORT ReturnLCHSinAXBLBH


330  shr ax, 1 ; Halve cylinders


331  eSHL_IM bl, 1 ; Double heads


332  inc cx ; Increment bit shift count


333  mov dl, TRANSLATEMODE_LARGE


334  jmp SHORT .ShiftIfMoreThan1024Cylinder


335 


336 


337  ;


338  ; Checks should LARGE mode LCHS be calculated with ECHS or Revised ECHS


339  ; algorithm. Revised ECHS is needed for drives with 8193 or more cylinders


340  ; AND 16 heads.


341  ;


342  ; AtaGeometry_IsDriveSmallEnoughForECHS:


343  ; Parameters:


344  ; AX: Number of PCylinders


345  ; BL: Number of PHeads


346  ; Returns:


347  ; CF: Clear if Reviced ECHS is necessary


348  ; Set if ECHS is enough


349  ; Corrupts registers:


350  ; Nothing


351  ;


352  AtaGeometry_IsDriveSmallEnoughForECHS:


353  ; Generate LCHS using simple bit shift algorithm (ECHS) if


354  ; 8192 or less cylinders. Use Revised ECHS if 8193 or more cylinders


355  ; AND 16 heads.


356  cmp ax, 8193


357  jb SHORT .RevisedECHSisNotNeeded


358  cmp bl, 16 ; Drives with 8193 or more cylinders can report 15 heads


359  .RevisedECHSisNotNeeded:


360  ret


361 

