source: xtideuniversalbios/trunk/XTIDE_Universal_BIOS/Src/Device/IDE/IdeTransfer.asm@ 577

Last change on this file since 577 was 568, checked in by krille_n_@…, 10 years ago

Changes:

  • SerDrive: Using named pipe mode (serdrive -p) now works under Windows XP/2000/Server 2003.
  • checksum.pl: Added a compatibility fix for 3Com 3C503 cards.
  • XTIDECFG will now scan every possible segment address to find and load the BIOS and/or its settings from EEPROM. This should simplify things for people using combined option ROMs.
  • Fixed a bug from r521 in BootSector.asm where the BIOS would not display a timeout error if it failed to load the boot sector from harddrive.
  • Fixed a bug from r541 in CompatibleDPT.asm where CompatibleDPT_CreateDeviceParameterTableExtensionToESBXfromDPTinDSSI would generate an invalid checksum in the DPTE.
  • Optimizations and other fixes.
File size: 12.1 KB
Line 
1; Project name : XTIDE Universal BIOS
2; Description : IDE Device transfer functions.
3
4;
5; XTIDE Universal BIOS and Associated Tools
6; Copyright (C) 2009-2010 by Tomi Tilli, 2011-2013 by XTIDE Universal BIOS Team.
7;
8; This program is free software; you can redistribute it and/or modify
9; it under the terms of the GNU General Public License as published by
10; the Free Software Foundation; either version 2 of the License, or
11; (at your option) any later version.
12;
13; This program is distributed in the hope that it will be useful,
14; but WITHOUT ANY WARRANTY; without even the implied warranty of
15; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16; GNU General Public License for more details.
17; Visit http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
18;
19
20; Structure containing variables for PIO transfer functions.
21; This struct must not be larger than IDEPACK without INTPACK.
22struc PIOVARS ; Must not be larger than 9 bytes! See IDEPACK in RamVars.inc.
23 .wDataPort resb 2 ; 0-1, IDE Data Port
24 .fnXfer resb 2 ; 2-3, Offset to transfer function
25 .wSectorsInBlock resb 2 ; 4-5, Block size in sectors
26 .bSectorsLeft resb 1 ; 6, Sectors left to transfer
27 resb 1 ; 7, IDEPACK.bDeviceControl
28 .bSectorsDone resb 1 ; 8, Number of sectors xferred
29endstruc
30
31
32; Section containing code
33SECTION .text
34
35;--------------------------------------------------------------------
36; IdeTransfer_StartWithCommandInAL
37; Parameters:
38; AL: IDE command that was used to start the transfer
39; (all PIO read and write commands including Identify Device)
40; ES:SI: Ptr to data buffer
41; DS:DI: Ptr to DPT (in RAMVARS segment)
42; SS:BP: Ptr to IDEPACK
43; Returns:
44; AH: INT 13h Error Code
45; CX: Number of successfully transferred sectors
46; CF: Cleared if success, Set if error
47; Corrupts registers:
48; AL, BX, DX, SI, ES
49;--------------------------------------------------------------------
50ALIGN JUMP_ALIGN
51IdeTransfer_StartWithCommandInAL:
52 ; Are we reading or writing?
53 test al, 16 ; Bit 4 is cleared on all the read commands but set on 3 of the 4 write commands
54 mov ah, [bp+IDEPACK.bSectorCount]
55 jnz SHORT WriteToDrive
56 cmp al, COMMAND_WRITE_MULTIPLE
57 je SHORT WriteToDrive
58 ; Fall to ReadFromDrive
59
60;--------------------------------------------------------------------
61; ReadFromDrive
62; Parameters:
63; AH: Number of sectors to transfer (1...128)
64; ES:SI: Ptr to buffer to receive data
65; DS:DI: Ptr to DPT (in RAMVARS segment)
66; SS:BP: Ptr to PIOVARS
67; Returns:
68; DS:DI: Ptr to DPT (in RAMVARS segment)
69; AH: BIOS Error code
70; CX: Number of successfully transferred sectors
71; CF: 0 if transfer successful
72; 1 if any error
73; Corrupts registers:
74; AL, BX, DX, SI, ES
75;--------------------------------------------------------------------
76ReadFromDrive:
77 ; Prepare to read data to ESSI
78 mov bx, g_rgfnPioRead
79 call InitializePiovarsInSSBPwithSectorCountInAH
80%ifdef USE_AT
81 jc SHORT ReturnWithTransferErrorInAH
82%endif
83
84 ; Wait until drive is ready to transfer
85 call IdeWait_IRQorDRQ ; Wait until ready to transfer
86 jc SHORT ReturnWithTransferErrorInAH
87 xchg si, di ; ES:DI now points buffer
88
89 mov cx, [bp+PIOVARS.wSectorsInBlock] ; Max 128
90
91ALIGN JUMP_ALIGN
92.ReadNextBlockFromDrive:
93 mov dx, [bp+PIOVARS.wDataPort]
94 cmp [bp+PIOVARS.bSectorsLeft], cl
95 jbe SHORT .ReadLastBlockFromDrive
96 call [bp+PIOVARS.fnXfer]
97
98 ; Wait until ready for next block and check for errors
99 xchg di, si ; DS:DI now points DPT
100 call IdeWait_IRQorDRQ ; Wait until ready to transfer
101 jc SHORT ReturnWithTransferErrorInAH
102 xchg si, di ; ES:DI now points buffer
103
104 ; Increment number of successfully read sectors
105 mov cx, [bp+PIOVARS.wSectorsInBlock]
106 sub [bp+PIOVARS.bSectorsLeft], cl
107 add [bp+PIOVARS.bSectorsDone], cl
108 jmp SHORT .ReadNextBlockFromDrive
109
110ALIGN JUMP_ALIGN
111.ReadLastBlockFromDrive:
112 mov cl, [bp+PIOVARS.bSectorsLeft] ; CH is already zero
113 push cx
114 call [bp+PIOVARS.fnXfer] ; Transfer possibly partial block
115
116 ; Check for errors in last block
117 mov di, si ; DS:DI now points DPT
118CheckErrorsAfterTransferringLastBlock:
119 mov bx, TIMEOUT_AND_STATUS_TO_WAIT(TIMEOUT_DRQ, FLG_STATUS_BSY)
120 call IdeWait_PollStatusFlagInBLwithTimeoutInBH
121 pop cx ; [bp+PIOVARS.bSectorsLeft]
122 jc SHORT ReturnWithTransferErrorInAH
123
124 ; All sectors successfully transferred
125 add cx, [bp+PIOVARS.bSectorsDone] ; Never sets CF
126 ret
127
128 ; Return number of successfully read sectors
129ReturnWithTransferErrorInAH:
130%ifdef USE_386
131 movzx cx, [bp+PIOVARS.bSectorsDone]
132%else
133 mov cl, [bp+PIOVARS.bSectorsDone]
134 mov ch, 0 ; Preserve CF
135%endif
136 ret
137
138
139;--------------------------------------------------------------------
140; WriteToDrive
141; Parameters:
142; AH: Number of sectors to transfer (1...128)
143; DS:DI: Ptr to DPT (in RAMVARS segment)
144; ES:SI: Ptr to buffer containing data
145; SS:BP: Ptr to PIOVARS
146; Returns:
147; AH: BIOS Error code
148; CX: Number of successfully transferred sectors
149; CF: 0 if transfer successful
150; 1 if any error
151; Corrupts registers:
152; AL, BX, DX, SI, ES
153;--------------------------------------------------------------------
154ALIGN JUMP_ALIGN
155WriteToDrive:
156 ; Prepare to write data from ESSI
157 mov bx, g_rgfnPioWrite
158 call InitializePiovarsInSSBPwithSectorCountInAH
159%ifdef USE_AT
160 jc SHORT ReturnWithTransferErrorInAH
161%endif
162
163 ; Always poll when writing first block (IRQs are generated for following blocks)
164 mov bx, TIMEOUT_AND_STATUS_TO_WAIT(TIMEOUT_DRQ, FLG_STATUS_DRQ)
165 call IdeWait_PollStatusFlagInBLwithTimeoutInBH
166 jc SHORT ReturnWithTransferErrorInAH
167
168 mov cx, [bp+PIOVARS.wSectorsInBlock] ; Max 128
169
170ALIGN JUMP_ALIGN
171.WriteNextBlockToDrive:
172 mov dx, [bp+PIOVARS.wDataPort]
173 cmp [bp+PIOVARS.bSectorsLeft], cl
174 jbe SHORT .WriteLastBlockToDrive
175 call [bp+PIOVARS.fnXfer]
176
177 ; Wait until ready for next block and check for errors
178 call IdeWait_IRQorDRQ ; Wait until ready to transfer
179 jc SHORT ReturnWithTransferErrorInAH
180
181 ; Increment number of successfully written sectors
182 mov cx, [bp+PIOVARS.wSectorsInBlock]
183 sub [bp+PIOVARS.bSectorsLeft], cl
184 add [bp+PIOVARS.bSectorsDone], cl
185 jmp SHORT .WriteNextBlockToDrive
186
187ALIGN JUMP_ALIGN
188.WriteLastBlockToDrive:
189 mov cl, [bp+PIOVARS.bSectorsLeft] ; CH is already zero
190 push cx
191 call [bp+PIOVARS.fnXfer] ; Transfer possibly partial block
192 jmp SHORT CheckErrorsAfterTransferringLastBlock
193
194
195;--------------------------------------------------------------------
196; InitializePiovarsInSSBPwithSectorCountInAH
197; Parameters:
198; AH: Number of sectors to transfer (1...128)
199; BX: Offset to transfer function lookup table
200; DS:DI: Ptr to DPT (in RAMVARS segment)
201; ES:SI: Ptr to data buffer
202; SS:BP: Ptr to PIOVARS
203; Returns:
204; ES:SI: Normalized pointer
205; AH: INT 13h Error Code (only when CF set)
206; CF: Set if failed to normalize pointer (segment overflow)
207; Cleared if success
208; Corrupts registers:
209; AL, BX, DX
210;--------------------------------------------------------------------
211ALIGN JUMP_ALIGN
212InitializePiovarsInSSBPwithSectorCountInAH:
213 ; Store sizes and Data Port
214 mov [bp+PIOVARS.bSectorsLeft], ah
215%ifdef USE_AT
216 xchg dx, ax
217%endif
218 mov ax, [di+DPT.wBasePort]
219 mov [bp+PIOVARS.wDataPort], ax
220 eMOVZX ax, [di+DPT_ATA.bBlockSize]
221 mov [bp+PIOVARS.wSectorsInBlock], ax
222 mov [bp+PIOVARS.bSectorsDone], ah ; Zero
223
224 ; Get transfer function based on bus type
225 mov al, [di+DPT_ATA.bDevice]
226 add bx, ax
227%ifdef MODULE_8BIT_IDE_ADVANCED
228 cmp al, DEVICE_8BIT_XTCF_DMA
229%endif
230 mov ax, [cs:bx] ; Load offset to transfer function
231 mov [bp+PIOVARS.fnXfer], ax
232
233 ; Normalize pointer for PIO-transfers and convert to physical address for DMA transfers
234%ifdef MODULE_8BIT_IDE_ADVANCED
235 jb SHORT IdeTransfer_NormalizePointerInESSI
236
237 ; Convert ES:SI to physical address
238%ifdef USE_386
239
240 mov dx, es
241 xor ax, ax
242 shld ax, dx, 4
243 shl dx, 4
244 add si, dx
245 adc al, ah
246 mov es, ax
247
248%elifdef USE_186
249 ; Bytes EU Cycles(286)
250 mov ax, es ; 2 2
251 rol ax, 4 ; 3 9
252 mov dx, ax ; 2 2
253 and ax, BYTE 0Fh; 3 3
254 xor dx, ax ; 2 2
255 add si, dx ; 2 2
256 adc al, ah ; 2 2
257 mov es, ax ; 2 2
258 ;------------------------------------
259 ; 18 24
260%else ; 808x
261 ; Bytes EU Cycles(808x)
262 mov al, 4 ; 2 4
263 mov dx, es ; 2 2
264 xchg cx, ax ; 1 3
265 rol dx, cl ; 2 24
266 mov cx, dx ; 2 2
267 xchg cx, ax ; 1 3
268 and ax, BYTE 0Fh; 3 4
269 xor dx, ax ; 2 3
270 add si, dx ; 2 3
271 adc al, ah ; 2 3
272 mov es, ax ; 2 2
273 ;------------------------------------
274 ; 21 53
275;
276; Judging by the Execution Unit cycle count the above block of code is
277; apparently slower. However, the shifts and rotates in the block below
278; execute faster than the Bus Interface Unit on an 8088 can fetch them,
279; thus causing the EU to starve. The difference in true execution speed
280; (if any) might not be worth the extra 5 bytes.
281; In other words, we could use a real world test here.
282;
283%if 0
284 ; Bytes EU Cycles(808x/286)
285 xor dx, dx ; 2 3/2
286 mov ax, es ; 2 2/2
287%rep 4
288 shl ax, 1 ; 8 8/8
289 rcl dx, 1 ; 8 8/8
290%endrep
291 add si, ax ; 2 3/2
292 adc dl, dh ; 2 3/2
293 mov es, dx ; 2 2/2
294 ;------------------------------------
295 ; 26 29/26
296%endif ; 0
297%endif
298
299 ret ; With CF cleared (taken care of by the physical address conversion)
300%endif ; MODULE_8BIT_IDE_ADVANCED
301 ; Fall to IdeTransfer_NormalizePointerInESSI if no MODULE_8BIT_IDE_ADVANCED
302
303
304;--------------------------------------------------------------------
305; IdeTransfer_NormalizePointerInESSI
306; Parameters:
307; DH: Number of sectors to transfer (when USE_AT defined)
308; ES:SI: Ptr to be normalized
309; Returns:
310; ES:SI: Normalized pointer (SI = 0...15)
311; AH: INT 13h Error Code (when USE_AT defined and normalization was attempted)
312; CF: Set if failed to normalize pointer (segment overflow)
313; Cleared if success
314; Corrupts registers:
315; AX, DX
316;--------------------------------------------------------------------
317IdeTransfer_NormalizePointerInESSI:
318; Normalization can cause segment overflow if it is done when not needed
319; (I don't know if any software calls with such seg:off address).
320; This does not apply to XT systems since nothing will write to main BIOS ROM.
321; On AT systems things are quite different, even in protected mode the address
322; is passed in seg:offset form and HMA is accessible in real mode.
323%ifdef USE_AT
324 xor dl, dl
325 eSHL_IM dx, 1
326 dec dx ; Prevents normalization when bytes + offset will be zero
327 add dx, si
328 jc SHORT .NormalizationRequired
329 ret
330.NormalizationRequired:
331%endif ; USE_AT
332
333 NORMALIZE_FAR_POINTER es, si, ax, dx
334%ifdef USE_AT ; CF is always clear for XT builds
335 ; AH = RET_HD_INVALID (01) if CF set, RET_HD_SUCCESS (00) if not. CF unchanged.
336 sbb ah, ah
337 neg ah
338%endif
339 ret
340
341
342
343; Lookup tables to get transfer function based on bus type
344ALIGN WORD_ALIGN
345g_rgfnPioRead:
346 dw IdePioBlock_ReadFrom16bitDataPort ; 0, DEVICE_16BIT_ATA
347 dw IdePioBlock_ReadFrom32bitDataPort ; 1, DEVICE_32BIT_ATA
348%ifdef MODULE_8BIT_IDE
349 dw IdePioBlock_ReadFrom8bitDataPort ; 2, DEVICE_8BIT_ATA
350 dw IdePioBlock_ReadFromXtideRev1 ; 3, DEVICE_8BIT_XTIDE_REV1
351 dw IdePioBlock_ReadFrom16bitDataPort ; 4, DEVICE_8BIT_XTIDE_REV2
352 dw IdePioBlock_ReadFrom8bitDataPort ; 5, DEVICE_8BIT_XTCF_PIO8
353 dw IdePioBlock_ReadFrom16bitDataPort ; 6, DEVICE_8BIT_XTCF_PIO8_WITH_BIU_OFFLOAD
354%ifdef MODULE_8BIT_IDE_ADVANCED
355 dw IdeDmaBlock_ReadFromXTCF ; 7, DEVICE_8BIT_XTCF_DMA
356%endif ; MODULE_8BIT_IDE_ADVANCED
357%endif ; MODULE_8BIT_IDE
358
359
360g_rgfnPioWrite:
361 dw IdePioBlock_WriteTo16bitDataPort ; 0, DEVICE_16BIT_ATA
362 dw IdePioBlock_WriteTo32bitDataPort ; 1, DEVICE_32BIT_ATA
363%ifdef MODULE_8BIT_IDE
364 dw IdePioBlock_WriteTo8bitDataPort ; 2, DEVICE_8BIT_ATA
365 dw IdePioBlock_WriteToXtideRev1 ; 3, DEVICE_8BIT_XTIDE_REV1
366 dw IdePioBlock_WriteToXtideRev2 ; 4, DEVICE_8BIT_XTIDE_REV2
367 dw IdePioBlock_WriteTo8bitDataPort ; 5, DEVICE_8BIT_XTCF_PIO8
368 dw IdePioBlock_WriteTo16bitDataPort ; 6, DEVICE_8BIT_XTCF_PIO8_WITH_BIU_OFFLOAD
369%ifdef MODULE_8BIT_IDE_ADVANCED
370 dw IdeDmaBlock_WriteToXTCF ; 7, DEVICE_8BIT_XTCF_DMA
371%endif ; MODULE_8BIT_IDE_ADVANCED
372%endif ; MODULE_8BIT_IDE
Note: See TracBrowser for help on using the repository browser.