source: xtideuniversalbios/trunk/XTIDE_Universal_BIOS/Src/VariablesAndDPTs/AtaGeometry.asm @ 612

Last change on this file since 612 was 612, checked in by krille_n_, 3 years ago

Changes:

  • BIOSDRVS builds again (broken since r609). Also removed the last remnants of RESERVE_DIAGNOSTIC_CYLINDER from BIOSDRVS that I missed in r606.
  • Put in a limit on the P-CHS cylinder count in an attempt to improve compatibility with some CF cards that violates the ATA specification. The limit applies only to the BIOS. BIOSDRVS will continue to show the true cylinder count since we might want to add code later to warn the user when encountering incompatible drives like these.
  • Optimized the bug fix in r611.
  • Updated the copyright notices in XTIDECFG and BIOSDRVS.
File size: 13.7 KB
Line 
1; Project name  :   XTIDE Universal BIOS
2; Description   :   Functions for generating L-CHS parameters for
3;                   drives with more than 1024 cylinders.
4;
5;                   These algorithms are taken from: http://www.mossywell.com/boot-sequence
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) 2009-2010 by Tomi Tilli, 2011-2013 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/old-licenses/gpl-2.0.html
24;
25
26; Section containing code
27SECTION .text
28
29%ifdef MODULE_EBIOS
30;--------------------------------------------------------------------
31; AtaGeometry_GetLbaSectorCountToBXDXAXfromAtaInfoInESSI
32;   Parameters:
33;       ES:SI:  Ptr to 512-byte ATA information read from the drive
34;   Returns:
35;       BX:DX:AX:   48-bit sector count
36;       CL:         FLGL_DPT_LBA48 if LBA48 supported
37;                   Zero if only LBA28 is supported
38;   Corrupts registers:
39;       Nothing
40;--------------------------------------------------------------------
41AtaGeometry_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 512-byte ATA information read from the drive
71;   Returns:
72;       AX:     Number of L-CHS cylinders (1...1027, yes 1027)
73;       BL:     Number of L-CHS heads (1...255)
74;       BH:     Number of L-CHS sectors per track (1...63)
75;       CX:     Number of bits shifted (0...3)
76;       DX:     CHS Translate Mode
77;   Corrupts registers:
78;       Nothing
79;--------------------------------------------------------------------
80AtaGeometry_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    call    AtaGeometry_LimitAXtoMaximumLCylinders  ; 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 L-CHS 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 P-CHS 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;--------------------------------------------------------------------
135GetSectorCountToDXAXfromCHSinAXBLBH:
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 P-CHS sector count up to largest possible
146; L-CHS 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; L-CHS 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 P-CHS 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;--------------------------------------------------------------------
172ConvertChsSectorCountFromDXAXtoLbaAssistedLCHSinAXBLBH:
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.
222ReturnLCHSinAXBLBH:
223    ret
224
225
226;--------------------------------------------------------------------
227; AtaGeometry_GetPCHStoAXBLBHfromAtaInfoInESSI
228;   Parameters:
229;       ES:SI:  Ptr to 512-byte ATA information read from the drive
230;   Returns:
231;       AX:     Number of P-CHS cylinders (1...16383)
232;       BL:     Number of P-CHS heads (1...16)
233;       BH:     Number of P-CHS sectors per track (1...63)
234;   Corrupts registers:
235;       Nothing
236;--------------------------------------------------------------------
237AtaGeometry_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%ifndef EXCLUDE_FROM_BIOSDRVS   ; We want the true value in BIOSDRVS
242    ; Some CF cards (for example Sandisk Ultra 16/32 GB) violates
243    ; the ATA specification by reporting more than 16383 cylinders.
244    MIN_U   ax, MAX_PCHS_CYLINDERS      ; Limit the count to avoid problems.
245%endif
246    ret
247
248
249;--------------------------------------------------------------------
250; Revised Enhanced CHS calculation (Revised ECHS)
251;
252; This algorithm translates P-CHS sector count to L-CHS sector count
253; with bit shift algorithm. Since 256 heads are not allowed
254; (DOS limit), this algorithm makes translations so that maximum of
255; 240 L-CHS heads can be used. This makes the maximum addressable capacity
256; to 7,927,234,560 bytes ~ 7.38 GiB. LBA addressing needs to be used to
257; get more capacity.
258;
259; L-CHS parameters generated here require the drive to use CHS addressing.
260;
261; Here is the algorithm:
262; If cylinders > 8192 and heads = 16
263;  Heads = 15
264;  Cylinders = cylinders * 16 / 15 (losing the fraction component)
265;  Do a standard ECHS translation
266;
267; *FIXME* The above algorithm seems to be conflicting with info found here
268; https://web.archive.org/web/20000817071418/http://www.firmware.com:80/support/bios/over4gb.htm
269; which says that Revised ECHS is used when the cylinder count is > 8191.
270;
271; ConvertPCHfromAXBLtoRevisedEnhancedCHinAXBL:
272;   Parameters:
273;       AX:     Number of P-CHS cylinders (8193...16383)
274;       BL:     Number of P-CHS heads (1...16)
275;   Returns:
276;       AX:     Number of L-CHS cylinders (?...1024)
277;       BL:     Number of L-CHS heads (?...240)
278;       CX:     Number of bits shifted (0...3)
279;       DX:     TRANSLATEMODE_NORMAL or TRANSLATEMODE_LARGE
280;   Corrupts registers:
281;       Nothing
282;--------------------------------------------------------------------
283ConvertPCHfromAXBLtoRevisedEnhancedCHinAXBL:
284    ; Generate L-CHS using simple bit shift algorithm (ECHS) if
285    ; 8192 or less cylinders
286    call    AtaGeometry_IsDriveSmallEnoughForECHS
287    jc      SHORT ConvertPCHfromAXBLtoEnhancedCHinAXBL
288
289    eMOVZX  cx, bl  ; CX = 16
290    dec     bx      ; Heads = 15
291    mul     cx      ; DX:AX = Cylinders * 16
292    dec     cx      ; CX = 15
293    div     cx      ; AX = (Cylinders * 16) / 15
294    ; Fall to ConvertPCHfromAXBLtoEnhancedCHinAXBL
295
296
297;--------------------------------------------------------------------
298; Enhanced CHS calculation (ECHS)
299;
300; This algorithm translates P-CHS sector count to L-CHS sector count
301; with simple bit shift algorithm. Since 256 heads are not allowed
302; (DOS limit), this algorithm require that there are at most 8192
303; P-CHS cylinders. This makes the maximum addressable capacity
304; to 4,227,858,432 bytes ~ 3.94 GiB. Use Revised ECHS or Assisted LBA
305; algorithms if there are more than 8192 P-CHS cylinders.
306;
307; L-CHS parameters generated here require the drive to use CHS addressing.
308;
309; Here is the algorithm:
310;  Multiplier = 1
311;  Cylinder = Cylinder - 1
312;  Is Cylinder < 1024? If not:
313;  Do a right bitwise rotation on the cylinder (i.e., divide by 2)
314;  Do a left bitwise rotation on the multiplier (i.e., multiply by 2)
315;  Use the multiplier on the Cylinder and Head values to obtain the translated values.
316;
317; ConvertPCHfromAXBLtoEnhancedCHinAXBL:
318;   Parameters:
319;       AX:     Number of P-CHS cylinders (1...8192, or up to 17475 if fell from above)
320;       BL:     Number of P-CHS heads (1...16)
321;   Returns:
322;       AX:     Number of L-CHS cylinders (?...1024)
323;       BL:     Number of L-CHS heads (?...128, or up to 240 if fell from above)
324;       CX:     Number of bits shifted (0...3)
325;       DX:     TRANSLATEMODE_NORMAL or TRANSLATEMODE_LARGE
326;   Corrupts registers:
327;       Nothing
328;--------------------------------------------------------------------
329ConvertPCHfromAXBLtoEnhancedCHinAXBL:
330    cwd                 ; Assume TRANSLATEMODE_NORMAL
331    xor     cx, cx      ; No bits to shift initially
332.ShiftIfMoreThan1024Cylinder:
333    cmp     ax, MAX_LCHS_CYLINDERS
334    jbe     SHORT ReturnLCHSinAXBLBH
335    shr     ax, 1       ; Halve cylinders
336    eSHL_IM bl, 1       ; Double heads
337    inc     cx          ; Increment bit shift count
338    mov     dl, TRANSLATEMODE_LARGE
339    jmp     SHORT .ShiftIfMoreThan1024Cylinder
340
341
342;--------------------------------------------------------------------
343; Checks should LARGE mode L-CHS be calculated with ECHS or Revised ECHS
344; algorithm. Revised ECHS is needed for drives with 8193 or more cylinders
345; AND 16 heads.
346;
347; AtaGeometry_IsDriveSmallEnoughForECHS:
348;   Parameters:
349;       AX:     Number of P-Cylinders
350;       BL:     Number of P-Heads
351;   Returns:
352;       CF:     Clear if Reviced ECHS is necessary
353;               Set if ECHS is enough
354;   Corrupts registers:
355;       Nothing
356;--------------------------------------------------------------------
357AtaGeometry_IsDriveSmallEnoughForECHS:
358    ; Generate L-CHS using simple bit shift algorithm (ECHS) if
359    ; 8192 or less cylinders. Use Revised ECHS if 8193 or more cylinders
360    ; AND 16 heads.
361    cmp     ax, 8193
362    jb      SHORT .RevisedECHSisNotNeeded
363    cmp     bl, 16  ; Drives with 8193 or more cylinders can report 15 heads
364.RevisedECHSisNotNeeded:
365    ret
366
367
368;--------------------------------------------------------------------
369; AtaGeometry_LimitAXtoMaximumLCylinders
370;   Parameters:
371;       AX:     Number of total L-CHS cylinders (1...1027)
372;   Returns:
373;       AX:     Number of usable L-CHS cylinders (1...1024)
374;   Corrupts registers:
375;       Nothing
376;--------------------------------------------------------------------
377AtaGeometry_LimitAXtoMaximumLCylinders:
378    MIN_U   ax, MAX_LCHS_CYLINDERS
379    ret
380
Note: See TracBrowser for help on using the repository browser.