Subversion Repositories Kolibri OS

Rev

Rev 6842 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  2. ;;                                                              ;;
  3. ;; Copyright (C) KolibriOS team 2004-2024. All rights reserved. ;;
  4. ;; Distributed under terms of the GNU General Public License    ;;
  5. ;;                                                              ;;
  6. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  7.  
  8.  
  9. ; HDD driver
  10.  
  11. struct HD_DATA
  12. hdpos   dw  ?
  13. hdid    dw  ?
  14. hdbase  dw  ?
  15. hd48    dw  ?
  16. sectors dq  ?
  17. ends
  18. ;-----------------------------------------------------------------
  19. iglobal
  20. align 4
  21. ide_callbacks:
  22.     dd  ide_callbacks.end - ide_callbacks
  23.     dd  0   ; no close function
  24.     dd  0   ; no closemedia function
  25.     dd  ide_querymedia
  26.     dd  ide_read
  27.     dd  ide_write
  28.     dd  0   ; no flush function
  29.     dd  0   ; use default cache size
  30. .end:
  31.  
  32. hd0_data    HD_DATA     1,  0
  33. hd1_data    HD_DATA     2,  16
  34. hd2_data    HD_DATA     3,  0
  35. hd3_data    HD_DATA     4,  16
  36. hd4_data    HD_DATA     5,  0
  37. hd5_data    HD_DATA     6,  16
  38. hd6_data    HD_DATA     7,  0
  39. hd7_data    HD_DATA     8,  16
  40. hd8_data    HD_DATA     9,  0
  41. hd9_data    HD_DATA     10, 16
  42. hd10_data   HD_DATA     11, 0
  43. hd11_data   HD_DATA     12, 16
  44.  
  45. ide_mutex_table:
  46.     dd  ide_channel1_mutex
  47.     dd  ide_channel2_mutex
  48.     dd  ide_channel3_mutex
  49.     dd  ide_channel4_mutex
  50.     dd  ide_channel5_mutex
  51.     dd  ide_channel6_mutex
  52. endg
  53. ;-----------------------------------------------------------------
  54. uglobal
  55. ide_mutex               MUTEX
  56. ide_channel1_mutex      MUTEX
  57. ide_channel2_mutex      MUTEX
  58. ide_channel3_mutex      MUTEX
  59. ide_channel4_mutex      MUTEX
  60. ide_channel5_mutex      MUTEX
  61. ide_channel6_mutex      MUTEX
  62. blockSize:
  63. rb 4
  64. sector:
  65. rb 6
  66. allow_dma_access        db ?
  67. IDE_common_irq_param    db ?
  68. eventPointer            dd ?
  69. eventID                 dd ?
  70. endg
  71. ;-----------------------------------------------------------------
  72. ide_read:
  73.         mov     al, 25h     ; READ DMA EXT
  74.         jmp     ide_read_write
  75.  
  76. ide_write:
  77.         mov     al, 35h     ; WRITE DMA EXT
  78. proc ide_read_write stdcall uses esi edi ebx, \
  79.         hd_data, buffer, startsector:qword, numsectors
  80.         ; hd_data = pointer to hd*_data
  81.         ; buffer = pointer to buffer with/for data
  82.         ; startsector = 64-bit start sector
  83.         ; numsectors = pointer to number of sectors on input,
  84.         ;  must be filled with number of sectors really read/written
  85. locals
  86. sectors_todo    dd      ?
  87. channel_lock    dd      ?
  88. endl
  89.         mov     bl, al
  90. ; get number of requested sectors and say that no sectors were read yet
  91.         mov     ecx, [numsectors]
  92.         mov     eax, [ecx]
  93.         mov     dword [ecx], 0
  94.         mov     [sectors_todo], eax
  95. ; acquire the global lock
  96.         mov     ecx, ide_mutex
  97.         call    mutex_lock
  98.         mov     ecx, [hd_data]
  99.         movzx   ecx, [ecx+HD_DATA.hdpos]
  100.         dec     ecx
  101.         shr     ecx, 1
  102.         shl     ecx, 2
  103.         mov     ecx, [ecx + ide_mutex_table]
  104.         mov     [channel_lock], ecx
  105.         call    mutex_lock
  106. ; prepare worker procedures variables
  107.         mov     esi, [buffer]
  108.         mov     edi, esi
  109.         mov     ecx, [hd_data]
  110.         movzx   eax, [ecx+HD_DATA.hdbase]
  111.         mov     [hdbase], eax
  112.         mov     ax, [ecx+HD_DATA.hdid]
  113.         mov     [hdid], eax
  114.         mov     eax, dword [startsector]
  115.         mov     [sector], eax
  116.         cmp     [ecx+HD_DATA.hd48], 0
  117.         jz      .LBA28
  118.         mov     ax, word [startsector+4]
  119.         mov     [sector+4], ax
  120.         movzx   ecx, [ecx+HD_DATA.hdpos]
  121.         mov     [hdpos], ecx
  122.         dec     ecx
  123.         shr     ecx, 2
  124.         imul    ecx, sizeof.IDE_DATA
  125.         add     ecx, IDE_controller_1
  126.         mov     [IDE_controller_pointer], ecx
  127.         mov     eax, [hdpos]
  128.         dec     eax
  129.         and     eax, 11b
  130.         shr     eax, 1
  131.         add     eax, ecx
  132.         cmp     [eax+IDE_DATA.dma_hdd_channel_1], 1
  133.         jz      .next
  134.         dec     ebx     ; READ/WRITE SECTOR(S) EXT
  135. ; LBA48 supports max 10000h sectors per time
  136. ; loop until all sectors will be processed
  137. .next:
  138.         mov     ecx, 8000h
  139.         cmp     ecx, [sectors_todo]
  140.         jbe     @f
  141.         mov     ecx, [sectors_todo]
  142. @@:
  143.         mov     [blockSize], ecx
  144.         push    ecx
  145.         call    IDE_transfer
  146.         pop     ecx
  147.         jc      .out
  148.         mov     eax, [numsectors]
  149.         add     [eax], ecx
  150.         sub     [sectors_todo], ecx
  151.         jz      .out
  152.         add     [sector], ecx
  153.         adc     word [sector+4], 0
  154.         jmp     .next
  155.  
  156. .LBA28:
  157.         add     eax, [sectors_todo]
  158.         add     eax, 0xF0000000
  159.         jc      .out
  160.         sub     bl, 5   ; READ/WRITE SECTOR(S)
  161. ; LBA28 supports max 256 sectors per time
  162. ; loop until all sectors will be processed
  163. .next28:
  164.         mov     ecx, 256
  165.         cmp     ecx, [sectors_todo]
  166.         jbe     @f
  167.         mov     ecx, [sectors_todo]
  168. @@:
  169.         mov     [blockSize], ecx
  170.         push    ecx
  171.         call    IDE_transfer.LBA28
  172.         pop     ecx
  173.         jc      .out
  174.         mov     eax, [numsectors]
  175.         add     [eax], ecx
  176.         sub     [sectors_todo], ecx
  177.         jz      .out
  178.         add     [sector], ecx
  179.         jmp     .next28
  180.  
  181. ; loop is done, either due to error or because everything is done
  182. ; release the global lock and return the corresponding status
  183. .out:
  184.         sbb     eax, eax
  185.         push    eax
  186.         mov     ecx, [channel_lock]
  187.         call    mutex_unlock
  188.         mov     ecx, ide_mutex
  189.         call    mutex_unlock
  190.         pop     eax
  191.         ret
  192. endp
  193. ;-----------------------------------------------------------------
  194. proc ide_querymedia stdcall, hd_data, mediainfo
  195.         mov     eax, [mediainfo]
  196.         mov     edx, [hd_data]
  197.         mov     [eax+DISKMEDIAINFO.Flags], 0
  198.         mov     [eax+DISKMEDIAINFO.SectorSize], 512
  199.         mov     ecx, dword[edx+HD_DATA.sectors]
  200.         mov     dword[eax+DISKMEDIAINFO.Capacity], ecx
  201.         mov     ecx, dword[edx+HD_DATA.sectors+4]
  202.         mov     dword[eax+DISKMEDIAINFO.Capacity+4], ecx
  203.         xor     eax, eax
  204.         ret
  205. endp
  206. ;-----------------------------------------------------------------
  207. ; input: esi -> buffer, bl = command, [sector], [blockSize]
  208. ; output: esi -> next block in buffer
  209. ; for pio read esi equal edi
  210. IDE_transfer:
  211.         mov     edx, [hdbase]
  212.         add     edx, 6
  213.         mov     al, byte [hdid]
  214.         add     al, 224
  215.         out     dx, al  ; select the desired drive
  216.         call    save_hd_wait_timeout
  217.         inc     edx
  218. @@:
  219.         call    check_hd_wait_timeout
  220.         jc      .hd_error
  221.         in      al, dx
  222.         test    al, 128 ; ready for command?
  223.         jnz     @b
  224.         pushfd          ; fill the ports
  225.         cli
  226.         mov     edx, [hdbase]
  227.         inc     edx
  228.         inc     edx
  229.         mov     al, [blockSize+1]
  230.         out     dx, al  ; Sector count (15:8)
  231.         inc     edx
  232.         mov     eax, [sector+3]
  233.         out     dx, al  ; LBA (31:24)
  234.         inc     edx
  235.         shr     eax, 8
  236.         out     dx, al  ; LBA (39:32)
  237.         inc     edx
  238.         shr     eax, 8
  239.         out     dx, al  ; LBA (47:40)
  240.         sub     edx, 3
  241.         mov     al, [blockSize]
  242.         out     dx, al  ; Sector count (7:0)
  243.         inc     edx
  244.         mov     eax, [sector]
  245.         out     dx, al  ; LBA (7:0)
  246.         inc     edx
  247.         shr     eax, 8
  248.         out     dx, al  ; LBA (15:8)
  249.         inc     edx
  250.         shr     eax, 8
  251.         out     dx, al  ; LBA (23:16)
  252.         inc     edx
  253.         mov     al, byte [hdid]
  254.         add     al, 224
  255.         out     dx, al
  256.         test    bl, 1
  257.         jz      .PIO
  258. ; DMA
  259.         mov     dword [esp], 0x1000
  260.         call    kernel_alloc
  261.         mov     edi, eax
  262.         push    eax
  263.         shl     dword [blockSize], 9
  264.         mov     eax, esi
  265.         add     eax, [blockSize]
  266.         push    eax
  267. ; check buffer pages physical addresses and fill the scatter-gather list
  268. ; buffer may be not aligned and may have size not divisible by page size
  269. ; [edi] = block physical address, [edi+4] = block size in bytes
  270. ; block addresses can not cross 10000h borders
  271.         mov     ecx, esi
  272.         and     ecx, 0xFFF
  273.         jz      .aligned
  274.         mov     eax, esi
  275.         call    get_pg_addr
  276.         add     eax, ecx
  277.         neg     ecx
  278.         add     ecx, 0x1000
  279.         mov     [edi], eax
  280.         cmp     ecx, [blockSize]
  281.         jnc     .end
  282.         mov     [edi+4], ecx
  283.         add     esi, 0x1000
  284.         add     edi, 8
  285.         sub     [blockSize], ecx
  286. .aligned:
  287.         mov     eax, esi
  288.         call    get_pg_addr
  289.         mov     ecx, eax
  290.         mov     [edi], eax
  291.         and     ecx, 0xFFFF
  292.         neg     ecx
  293.         add     ecx, 0x10000
  294.         cmp     [blockSize], ecx
  295.         jnc     @f
  296.         mov     ecx, [blockSize]
  297.         and     ecx, 0xF000
  298.         jz      .end
  299. @@:
  300.         push    ecx
  301. @@:
  302.         add     esi, 0x1000
  303.         add     eax, 0x1000
  304.         sub     ecx, 0x1000
  305.         jz      @f
  306.         mov     edx, eax
  307.         mov     eax, esi
  308.         call    get_pg_addr
  309.         cmp     eax, edx
  310.         jz      @b
  311. @@:
  312.         pop     edx
  313.         sub     edx, ecx
  314.         mov     [edi+4], edx
  315.         add     edi, 8
  316.         sub     [blockSize], edx
  317.         jnz     .aligned
  318.         sub     edi, 8
  319.         jmp     @f
  320.  
  321. .end:
  322.         mov     ecx, [blockSize]
  323.         mov     [edi+4], ecx
  324. @@:
  325.         mov     byte [edi+7], 80h   ; list end
  326.         pop     esi
  327.         pop     edi
  328. ; select controller Primary or Secondary
  329.         mov     ecx, [IDE_controller_pointer]
  330.         mov     dx, [ecx+IDE_DATA.RegsBaseAddres]
  331.         mov     eax, [hdpos]
  332.         dec     eax
  333.         test    eax, 10b
  334.         jz      @f
  335.         add     edx, 8
  336. @@:
  337.         add     edx, 2      ; Bus Master IDE Status register
  338.         mov     al, 6
  339.         out     dx, al      ; clear Error bit and Interrupt bit
  340.  
  341.         add     edx, 2      ; Bus Master IDE PRD Table Address
  342.         mov     eax, edi
  343.         call    get_pg_addr
  344.         out     dx, eax     ; send scatter-gather list physical address
  345.  
  346.         push    edx
  347.         mov     edx, [hdbase]
  348.         add     edx, 7      ; ATACommand
  349.         mov     al, bl
  350.         out     dx, al      ; Start hard drive
  351.         pop     edx
  352.  
  353.         sub     edx, 4      ; Bus Master IDE Command register
  354.         mov     al, 1       ; set direction
  355.         cmp     bl, 35h     ; write
  356.         jz      @f
  357.         add     al, 8       ; read
  358. @@:
  359.         out     dx, al      ; Start Bus Master
  360.         mov     [IDE_common_irq_param], 14
  361.         mov     eax, [hdpos]
  362.         dec     eax
  363.         test    eax, 10b
  364.         jz      @f
  365.         inc     [IDE_common_irq_param]
  366. @@:
  367.         push    edi esi ebx
  368.         xor     ecx, ecx
  369.         xor     esi, esi
  370.         call    create_event
  371.         mov     [eventPointer], eax
  372.         mov     [eventID], edx
  373.         sti
  374.         mov     ebx, edx
  375.         mov     ecx, 300
  376.         call    wait_event_timeout
  377.         test    eax, eax
  378.         jnz     @f
  379.         dbgstr 'IDE DMA IRQ timeout'
  380.         mov     [IDE_common_irq_param], 0
  381.         mov     eax, [eventPointer]
  382.         mov     ebx, [eventID]
  383.         call    destroy_event
  384.         mov     [eventPointer], 0
  385. @@:
  386.         pop     ebx esi
  387.         call    kernel_free
  388.         cmp     [eventPointer], 0
  389.         jz      .hd_error
  390.         ret
  391.  
  392. .LBA28:
  393.         mov     edx, [hdbase]
  394.         add     edx, 6
  395.         mov     al, byte [hdid]
  396.         add     al, 224
  397.         out     dx, al  ; select the desired drive
  398.         call    save_hd_wait_timeout
  399.         inc     edx
  400. @@:
  401.         call    check_hd_wait_timeout
  402.         jc      .hd_error
  403.         in      al, dx
  404.         test    al, 128 ; ready for command?
  405.         jnz     @b
  406.         pushfd          ; fill the ports
  407.         cli
  408.         mov     edx, [hdbase]
  409.         inc     edx
  410.         inc     edx
  411.         mov     al, [blockSize]
  412.         out     dx, al  ; Sector count (7:0)
  413.         inc     edx
  414.         mov     eax, [sector]
  415.         out     dx, al  ; LBA (7:0)
  416.         inc     edx
  417.         shr     eax, 8
  418.         out     dx, al  ; LBA (15:8)
  419.         inc     edx
  420.         shr     eax, 8
  421.         out     dx, al  ; LBA (23:16)
  422.         inc     edx
  423.         shr     eax, 8
  424.         add     al, byte [hdid]
  425.         add     al, 224
  426.         out     dx, al  ; LBA (27:24)
  427. .PIO:
  428.         inc     edx     ; ATACommand
  429.         mov     al, bl
  430.         out     dx, al  ; Start hard drive
  431.         popfd
  432. .sectorTransfer:
  433.         call    save_hd_wait_timeout
  434.         in      al, dx
  435.         in      al, dx
  436.         in      al, dx
  437.         in      al, dx
  438. @@:
  439.         call    check_hd_wait_timeout
  440.         jc      .hd_error
  441.         in      al, dx
  442.         test    al, 8   ; ready for transfer?
  443.         jz      @b
  444.         cmp     [hd_setup], 1   ; do not mark error for setup request
  445.         jz      @f
  446.         test    al, 1   ; previous command ended up with an error
  447.         jnz     .pio_error
  448. @@:
  449.         pushfd
  450.         cli
  451.         cld
  452.         mov     ecx, 256
  453.         mov     edx, [hdbase]
  454.         cmp     bl, 30h
  455.         jnc     .write
  456.         rep insw
  457.         jmp     @f
  458.  
  459. .write:
  460.         rep outsw
  461. @@:
  462.         popfd
  463.         add     edx, 7
  464.         dec     dword [blockSize]
  465.         jnz     .sectorTransfer
  466.         ret
  467.  
  468. .pio_error:
  469.         dbgstr 'IDE PIO transfer error'
  470. .hd_error:
  471.         cmp     bl, 30h
  472.         jnc     hd_write_error
  473. ;-----------------------------------------------------------------
  474. hd_read_error:
  475.         dbgstr 'HD read error'
  476.         stc
  477.         ret
  478. ;-----------------------------------------------------------------
  479. hd_write_error:
  480.         dbgstr 'HD write error'
  481.         stc
  482.         ret
  483. ;-----------------------------------------------------------------
  484. save_hd_wait_timeout:
  485.         mov     eax, [timer_ticks]
  486.         add     eax, 300        ; 3 sec timeout
  487.         mov     [hd_wait_timeout], eax
  488.         ret
  489. ;-----------------------------------------------------------------
  490. check_hd_wait_timeout:
  491.         mov     eax, [timer_ticks]
  492.         cmp     [hd_wait_timeout], eax
  493.         jc      @f
  494.         ret
  495.  
  496. @@:
  497.         dbgstr 'IDE device timeout'
  498.         stc
  499.         ret
  500. ;-----------------------------------------------------------------
  501. align 4
  502. IDE_irq_14_handler:
  503. IDE_irq_15_handler:
  504. IDE_common_irq_handler:
  505. ; Most of the time, we are here because we have requested
  506. ; a DMA transfer for the corresponding drive.
  507. ; However,
  508. ; a) we can be here because IDE IRQ is shared with some other device,
  509. ;    that device has actually raised IRQ,
  510. ;    it has nothing to do with IDE;
  511. ; b) we can be here because IDE controller just does not want
  512. ;    to be silent and reacts to something even though
  513. ;    we have, in theory, disabled IRQs.
  514. ; If the interrupt corresponds to our current request,
  515. ; remove the interrupt request and raise the event for the waiting code.
  516. ; In the case a), just return zero - not our interrupt.
  517. ; In the case b), remove the interrupt request and hope for the best.
  518. ; DEBUGF 1, 'K : IDE_irq_handler %x\n', [IDE_common_irq_param]:2
  519.         mov     ecx, [esp+4]
  520.         mov     dx, [ecx+IDE_DATA.RegsBaseAddres]
  521.         add     edx, 2  ; Bus Master IDE Status register
  522.         in      al, dx
  523.         test    al, 4
  524.         jnz     .interrupt_from_primary
  525.         add     edx, 8
  526.         in      al, dx
  527.         test    al, 4
  528.         jnz     .interrupt_from_secondary
  529.         xor     eax, eax ; not our interrupt
  530.         ret
  531.  
  532. .interrupt_from_primary:
  533.         out     dx, al  ; clear Interrupt bit
  534.         sub     edx, 2
  535.         xor     eax, eax
  536.         out     dx, al  ; clear Bus Master IDE Command register
  537.         mov     dx, [ecx+IDE_DATA.BAR0_val]
  538.         add     edx, 7
  539.         in      al, dx  ; read status register
  540.         cmp     [IDE_common_irq_param], 14
  541.         jz      .raise
  542. .exit_our:
  543.         mov     al, 1
  544.         ret
  545.  
  546. .interrupt_from_secondary:
  547.         out     dx, al  ; clear Interrupt bit
  548.         sub     edx, 2
  549.         xor     eax, eax
  550.         out     dx, al  ; clear Bus Master IDE Command register
  551.         mov     dx, [ecx+IDE_DATA.BAR2_val]
  552.         add     edx, 7
  553.         in      al, dx  ; read status register
  554.         cmp     [IDE_common_irq_param], 15
  555.         jnz     .exit_our
  556. .raise:
  557.         cmp     ecx, [IDE_controller_pointer]
  558.         jnz     .exit_our
  559.         pushad
  560.         mov     eax, [eventPointer]
  561.         mov     ebx, [eventID]
  562.         xor     edx, edx
  563.         xor     esi, esi
  564.         call    raise_event
  565.         popad
  566.         mov     al, 1   ; remove the interrupt request
  567.         ret
  568.