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

Last change on this file since 568 was 568, checked in by krille_n_@…, 9 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
RevLine 
[150]1; Project name  :   XTIDE Universal BIOS
2; Description   :   IDE Device transfer functions.
3
[376]4;
[445]5; XTIDE Universal BIOS and Associated Tools
[526]6; Copyright (C) 2009-2010 by Tomi Tilli, 2011-2013 by XTIDE Universal BIOS Team.
[376]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.
[445]12;
[376]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
[445]16; GNU General Public License for more details.
[376]17; Visit http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
[445]18;
[376]19
[150]20; Structure containing variables for PIO transfer functions.
21; This struct must not be larger than IDEPACK without INTPACK.
[414]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
[363]26    .bSectorsLeft           resb    1   ; 6, Sectors left to transfer
[218]27                            resb    1   ; 7, IDEPACK.bDeviceControl
[363]28    .bSectorsDone           resb    1   ; 8, Number of sectors xferred
[150]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
[171]39;               (all PIO read and write commands including Identify Device)
[480]40;       ES:SI:  Ptr to data buffer
[150]41;       DS:DI:  Ptr to DPT (in RAMVARS segment)
42;       SS:BP:  Ptr to IDEPACK
43;   Returns:
44;       AH:     INT 13h Error Code
[218]45;       CX:     Number of successfully transferred sectors
[150]46;       CF:     Cleared if success, Set if error
47;   Corrupts registers:
[218]48;       AL, BX, DX, SI, ES
[150]49;--------------------------------------------------------------------
50ALIGN JUMP_ALIGN
51IdeTransfer_StartWithCommandInAL:
[157]52    ; Are we reading or writing?
[171]53    test    al, 16  ; Bit 4 is cleared on all the read commands but set on 3 of the 4 write commands
[242]54    mov     ah, [bp+IDEPACK.bSectorCount]
55    jnz     SHORT WriteToDrive
[171]56    cmp     al, COMMAND_WRITE_MULTIPLE
[242]57    je      SHORT WriteToDrive
58    ; Fall to ReadFromDrive
[150]59
60;--------------------------------------------------------------------
[242]61; ReadFromDrive
[150]62;   Parameters:
[242]63;       AH:     Number of sectors to transfer (1...128)
[480]64;       ES:SI:  Ptr to buffer to receive data
[150]65;       DS:DI:  Ptr to DPT (in RAMVARS segment)
66;       SS:BP:  Ptr to PIOVARS
67;   Returns:
[242]68;       DS:DI:  Ptr to DPT (in RAMVARS segment)
[150]69;       AH:     BIOS Error code
[218]70;       CX:     Number of successfully transferred sectors
[294]71;       CF:     0 if transfer successful
[150]72;               1 if any error
73;   Corrupts registers:
[218]74;       AL, BX, DX, SI, ES
[150]75;--------------------------------------------------------------------
[242]76ReadFromDrive:
77    ; Prepare to read data to ESSI
78    mov     bx, g_rgfnPioRead
79    call    InitializePiovarsInSSBPwithSectorCountInAH
[538]80%ifdef USE_AT
81    jc      SHORT ReturnWithTransferErrorInAH
82%endif
[242]83
84    ; Wait until drive is ready to transfer
85    call    IdeWait_IRQorDRQ                    ; Wait until ready to transfer
[218]86    jc      SHORT ReturnWithTransferErrorInAH
[242]87    xchg    si, di                              ; ES:DI now points buffer
[218]88
[363]89    mov     cx, [bp+PIOVARS.wSectorsInBlock]    ; Max 128
[242]90
[150]91ALIGN JUMP_ALIGN
[242]92.ReadNextBlockFromDrive:
[150]93    mov     dx, [bp+PIOVARS.wDataPort]
[363]94    cmp     [bp+PIOVARS.bSectorsLeft], cl
[242]95    jbe     SHORT .ReadLastBlockFromDrive
[218]96    call    [bp+PIOVARS.fnXfer]
[169]97
[218]98    ; Wait until ready for next block and check for errors
[242]99    xchg    di, si                              ; DS:DI now points DPT
[218]100    call    IdeWait_IRQorDRQ                    ; Wait until ready to transfer
101    jc      SHORT ReturnWithTransferErrorInAH
[242]102    xchg    si, di                              ; ES:DI now points buffer
[169]103
[363]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
[242]108    jmp     SHORT .ReadNextBlockFromDrive
[150]109
110ALIGN JUMP_ALIGN
[242]111.ReadLastBlockFromDrive:
[363]112    mov     cl, [bp+PIOVARS.bSectorsLeft]       ; CH is already zero
[419]113    push    cx
[150]114    call    [bp+PIOVARS.fnXfer]                 ; Transfer possibly partial block
115
[242]116    ; Check for errors in last block
117    mov     di, si                              ; DS:DI now points DPT
118CheckErrorsAfterTransferringLastBlock:
[417]119    mov     bx, TIMEOUT_AND_STATUS_TO_WAIT(TIMEOUT_DRQ, FLG_STATUS_BSY)
[242]120    call    IdeWait_PollStatusFlagInBLwithTimeoutInBH
[419]121    pop     cx  ; [bp+PIOVARS.bSectorsLeft]
122    jc      SHORT ReturnWithTransferErrorInAH
[150]123
[445]124    ; All sectors successfully transferred
[419]125    add     cx, [bp+PIOVARS.bSectorsDone]       ; Never sets CF
126    ret
127
[242]128    ; Return number of successfully read sectors
129ReturnWithTransferErrorInAH:
[370]130%ifdef USE_386
131    movzx   cx, [bp+PIOVARS.bSectorsDone]
132%else
[363]133    mov     cl, [bp+PIOVARS.bSectorsDone]
134    mov     ch, 0                               ; Preserve CF
[370]135%endif
[242]136    ret
137
138
[150]139;--------------------------------------------------------------------
[242]140; WriteToDrive
[150]141;   Parameters:
[242]142;       AH:     Number of sectors to transfer (1...128)
143;       DS:DI:  Ptr to DPT (in RAMVARS segment)
[480]144;       ES:SI:  Ptr to buffer containing data
[150]145;       SS:BP:  Ptr to PIOVARS
146;   Returns:
147;       AH:     BIOS Error code
[218]148;       CX:     Number of successfully transferred sectors
[294]149;       CF:     0 if transfer successful
[150]150;               1 if any error
151;   Corrupts registers:
[218]152;       AL, BX, DX, SI, ES
[150]153;--------------------------------------------------------------------
154ALIGN JUMP_ALIGN
[242]155WriteToDrive:
156    ; Prepare to write data from ESSI
157    mov     bx, g_rgfnPioWrite
158    call    InitializePiovarsInSSBPwithSectorCountInAH
[538]159%ifdef USE_AT
160    jc      SHORT ReturnWithTransferErrorInAH
161%endif
[242]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
[218]166    jc      SHORT ReturnWithTransferErrorInAH
[150]167
[363]168    mov     cx, [bp+PIOVARS.wSectorsInBlock]    ; Max 128
[242]169
[218]170ALIGN JUMP_ALIGN
[242]171.WriteNextBlockToDrive:
[150]172    mov     dx, [bp+PIOVARS.wDataPort]
[363]173    cmp     [bp+PIOVARS.bSectorsLeft], cl
[242]174    jbe     SHORT .WriteLastBlockToDrive
[218]175    call    [bp+PIOVARS.fnXfer]
[169]176
[218]177    ; Wait until ready for next block and check for errors
178    call    IdeWait_IRQorDRQ                    ; Wait until ready to transfer
179    jc      SHORT ReturnWithTransferErrorInAH
[150]180
[363]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
[242]185    jmp     SHORT .WriteNextBlockToDrive
[169]186
[150]187ALIGN JUMP_ALIGN
[242]188.WriteLastBlockToDrive:
[363]189    mov     cl, [bp+PIOVARS.bSectorsLeft]       ; CH is already zero
[419]190    push    cx
[150]191    call    [bp+PIOVARS.fnXfer]                 ; Transfer possibly partial block
[242]192    jmp     SHORT CheckErrorsAfterTransferringLastBlock
[218]193
[150]194
195;--------------------------------------------------------------------
[218]196; InitializePiovarsInSSBPwithSectorCountInAH
[150]197;   Parameters:
[218]198;       AH:     Number of sectors to transfer (1...128)
[150]199;       BX:     Offset to transfer function lookup table
200;       DS:DI:  Ptr to DPT (in RAMVARS segment)
[480]201;       ES:SI:  Ptr to data buffer
[169]202;       SS:BP:  Ptr to PIOVARS
[167]203;   Returns:
[538]204;       ES:SI:  Normalized pointer
205;       AH:     INT 13h Error Code (only when CF set)
[558]206;       CF:     Set if failed to normalize pointer (segment overflow)
[538]207;               Cleared if success
[150]208;   Corrupts registers:
[538]209;       AL, BX, DX
[150]210;--------------------------------------------------------------------
211ALIGN JUMP_ALIGN
[218]212InitializePiovarsInSSBPwithSectorCountInAH:
[473]213    ; Store sizes and Data Port
[363]214    mov     [bp+PIOVARS.bSectorsLeft], ah
[538]215%ifdef USE_AT
216    xchg    dx, ax
217%endif
[473]218    mov     ax, [di+DPT.wBasePort]
219    mov     [bp+PIOVARS.wDataPort], ax
[370]220    eMOVZX  ax, [di+DPT_ATA.bBlockSize]
[363]221    mov     [bp+PIOVARS.wSectorsInBlock], ax
222    mov     [bp+PIOVARS.bSectorsDone], ah       ; Zero
[150]223
224    ; Get transfer function based on bus type
[567]225    mov     al, [di+DPT_ATA.bDevice]
226    add     bx, ax
[493]227%ifdef MODULE_8BIT_IDE_ADVANCED
[567]228    cmp     al, DEVICE_8BIT_XTCF_DMA
[480]229%endif
[150]230    mov     ax, [cs:bx]                         ; Load offset to transfer function
231    mov     [bp+PIOVARS.fnXfer], ax
[480]232
233    ; Normalize pointer for PIO-transfers and convert to physical address for DMA transfers
[493]234%ifdef MODULE_8BIT_IDE_ADVANCED
[480]235    jb      SHORT IdeTransfer_NormalizePointerInESSI
236
237    ; Convert ES:SI to physical address
[568]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
[567]249                        ; Bytes EU Cycles(286)
[491]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;
[567]283%if 0
[491]284                        ; Bytes EU Cycles(808x/286)
285    xor     dx, dx      ; 2     3/2
286    mov     ax, es      ; 2     2/2
[480]287%rep 4
[491]288    shl     ax, 1       ; 8     8/8
289    rcl     dx, 1       ; 8     8/8
[480]290%endrep
[491]291    add     si, ax      ; 2     3/2
292    adc     dl, dh      ; 2     3/2
293    mov     es, dx      ; 2     2/2
294    ;------------------------------------
[567]295                        ; 26    29/26
296%endif ; 0
297%endif
298
299    ret     ; With CF cleared (taken care of by the physical address conversion)
[493]300%endif ; MODULE_8BIT_IDE_ADVANCED
[558]301    ; Fall to IdeTransfer_NormalizePointerInESSI if no MODULE_8BIT_IDE_ADVANCED
[150]302
303
[480]304;--------------------------------------------------------------------
305; IdeTransfer_NormalizePointerInESSI
306;   Parameters:
[538]307;       DH:     Number of sectors to transfer (when USE_AT defined)
[480]308;       ES:SI:  Ptr to be normalized
309;   Returns:
310;       ES:SI:  Normalized pointer (SI = 0...15)
[558]311;       AH:     INT 13h Error Code (when USE_AT defined and normalization was attempted)
312;       CF:     Set if failed to normalize pointer (segment overflow)
[538]313;               Cleared if success
[480]314;   Corrupts registers:
315;       AX, DX
316;--------------------------------------------------------------------
317IdeTransfer_NormalizePointerInESSI:
[538]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
[558]325    eSHL_IM dx, 1
[538]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
[480]333    NORMALIZE_FAR_POINTER   es, si, ax, dx
[538]334%ifdef USE_AT       ; CF is always clear for XT builds
[558]335    ; AH = RET_HD_INVALID (01) if CF set, RET_HD_SUCCESS (00) if not. CF unchanged.
336    sbb     ah, ah
337    neg     ah
[538]338%endif
[480]339    ret
[400]340
[480]341
[538]342
[150]343; Lookup tables to get transfer function based on bus type
344ALIGN WORD_ALIGN
345g_rgfnPioRead:
[473]346        dw      IdePioBlock_ReadFrom16bitDataPort   ; 0, DEVICE_16BIT_ATA
347        dw      IdePioBlock_ReadFrom32bitDataPort   ; 1, DEVICE_32BIT_ATA
[400]348%ifdef MODULE_8BIT_IDE
[480]349        dw      IdePioBlock_ReadFrom8bitDataPort    ; 2, DEVICE_8BIT_ATA
[491]350        dw      IdePioBlock_ReadFromXtideRev1       ; 3, DEVICE_8BIT_XTIDE_REV1
[545]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
[493]354%ifdef MODULE_8BIT_IDE_ADVANCED
[545]355        dw      IdeDmaBlock_ReadFromXTCF            ; 7, DEVICE_8BIT_XTCF_DMA
356%endif ; MODULE_8BIT_IDE_ADVANCED
357%endif ; MODULE_8BIT_IDE
[400]358
[480]359
[473]360g_rgfnPioWrite:
361        dw      IdePioBlock_WriteTo16bitDataPort    ; 0, DEVICE_16BIT_ATA
362        dw      IdePioBlock_WriteTo32bitDataPort    ; 1, DEVICE_32BIT_ATA
[400]363%ifdef MODULE_8BIT_IDE
[480]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
[545]367        dw      IdePioBlock_WriteTo8bitDataPort     ; 5, DEVICE_8BIT_XTCF_PIO8
368        dw      IdePioBlock_WriteTo16bitDataPort    ; 6, DEVICE_8BIT_XTCF_PIO8_WITH_BIU_OFFLOAD
[526]369%ifdef MODULE_8BIT_IDE_ADVANCED
[545]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.