Subversion Repositories Kolibri OS

Rev

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

  1. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  2. ;;                                                              ;;
  3. ;; Copyright (C) KolibriOS team 2004-2021. All rights reserved. ;;
  4. ;; Distributed under terms of the GNU General Public License    ;;
  5. ;;                                                              ;;
  6. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  7.  
  8. $Revision$
  9.  
  10. PCI_REG_STATUS_COMMAND = 0x0004
  11. PCI_REG_BAR5 = 0x0024
  12.  
  13. AHCI_DBGLVL = 0 ; debug output verbosity level. 0 - less verbose, 1 - more verbose
  14.  
  15. ; different SATA device signatures
  16. SATA_SIG_ATA    = 0x00000101    ; SATA drive
  17. SATA_SIG_ATAPI  = 0xEB140101    ; SATAPI drive
  18. SATA_SIG_SEMB   = 0xC33C0101    ; Enclosure management bridge
  19. SATA_SIG_PM     = 0x96690101    ; Port multiplier
  20.  
  21. ; Device type constants
  22. AHCI_DEV_NULL   = 0
  23. AHCI_DEV_SATA   = 1
  24. AHCI_DEV_SEMB   = 2
  25. AHCI_DEV_PM     = 3
  26. AHCI_DEV_SATAPI = 4
  27.  
  28. ; ATA commands
  29. ATA_IDENTIFY         = 0xEC
  30. ATA_CMD_READ_DMA_EX  = 0x25
  31. ATA_CMD_WRITE_DMA_EX = 0x35
  32.  
  33. ; ATA constants
  34. ATA_DEV_BUSY    = 0x80
  35. ATA_DEV_DRQ     = 0x08
  36.  
  37. ; ATAPI commands
  38. ATAPI_IDENTIFY  = 0xA1
  39.  
  40. PRDT_MAX_ENTRIES = 16 ;65535
  41.  
  42. ; bit_ prefix means that its index of bit
  43. ; format: bit_AHCI_STR_REG_BIT
  44. bit_AHCI_HBA_CAP2_BOH   = 0        ; Supports BIOS/OS Handoff
  45.  
  46. bit_AHCI_HBA_BOHC_BOS  = 0         ; BIOS-Owned Semaphore (BIOS owns controller)
  47. bit_AHCI_HBA_BOHC_OOS  = 1         ; OS-Owned Semaphore (OS owns controller)
  48. bit_AHCI_HBA_BOHC_BB   = 4         ; BIOS Busy (polling bit while BIOS cleans up
  49.  
  50. bit_AHCI_HBA_GHC_AHCI_ENABLE      = 31  ; Enable AHCI mode
  51. bit_AHCI_HBA_GHC_RESET            = 0   ; Reset HBA
  52. bit_AHCI_HBA_GHC_INTERRUPT_ENABLE = 1   ; Enable interrupts from the HBA
  53.  
  54. bit_AHCI_HBA_PxCMD_ST    = 0
  55. bit_AHCI_HBA_PxCMD_FRE   = 4
  56. bit_AHCI_HBA_PxCMD_FR    = 14
  57. bit_AHCI_HBA_PxCMD_CR    = 15
  58. bit_AHCI_HBA_PxIS_TFES   = 30
  59.  
  60. AHCI_HBA_PxCMD_ST    = 1 shl 0
  61. AHCI_HBA_PxCMD_FRE   = 1 shl 4
  62. AHCI_HBA_PxCMD_FR    = 1 shl 14
  63. AHCI_HBA_PxCMD_CR    = 1 shl 15
  64.  
  65. bit_AHCI_H2D_FLAG_CMD    = 7
  66.  
  67. AHCI_HBA_PxSSTS_DET         = 0xF
  68. AHCI_HBA_PORT_IPM_ACTIVE    = 1
  69. AHCI_HBA_PxSSTS_DET_PRESENT = 3
  70.  
  71. AHCI_MAX_PORTS = 32        ;
  72. ;HBA_MEMORY_SIZE = 0x1100
  73.  
  74. AHCI_PORT_TIMEOUT = 1000000
  75.  
  76. ; Frame Information Structure Types
  77. FIS_TYPE_REG_H2D    = 0x27 ; Register FIS - host to device
  78. FIS_TYPE_REG_D2H    = 0x34 ; Register FIS - device to host
  79. FIS_TYPE_DMA_ACT    = 0x39 ; DMA activate FIS - device to host
  80. FIS_TYPE_DMA_SETUP  = 0x41 ; DMA setup FIS - bidirectional
  81. FIS_TYPE_DATA       = 0x46 ; Data FIS - bidirectional
  82. FIS_TYPE_BIST       = 0x58 ; BIST activate FIS - bidirectional
  83. FIS_TYPE_PIO_SETUP  = 0x5F ; PIO setup FIS - device to host
  84. FIS_TYPE_DEV_BITS   = 0xA1 ; Set device bits FIS - device to host
  85.  
  86. ; Generic Host Control registers
  87. struct HBA_MEM
  88.         cap                   dd ?                    ; 0x00, Host capabilities
  89.         ghc                   dd ?                    ; 0x04, Global host control
  90.         is                    dd ?                    ; 0x08, Interrupt status
  91.         pi                    dd ?                    ; 0x0C, Port implemented
  92.         version               dd ?                    ; 0x10, Version
  93.         ccc_ctl               dd ?                    ; 0x14, Command completion coalescing control
  94.         ccc_pts               dd ?                    ; 0x18, Command completion coalescing ports
  95.         em_loc                dd ?                    ; 0x1C, Enclosure management location
  96.         em_ctl                dd ?                    ; 0x20, Enclosure management control
  97.         cap2                  dd ?                    ; 0x24, Host capabilities extended
  98.         bohc                  dd ?                    ; 0x28, BIOS/OS handoff control and status
  99.         reserved              rb (0xA0-HBA_MEM.reserved)        ; 0x2C - 0x9F, Reserved
  100.         vendor                rb (0x100-HBA_MEM.vendor)         ; 0xA0 - 0xFF, Vendor specific
  101.         ports                 rb (sizeof.HBA_PORT*AHCI_MAX_PORTS) ; 0x100 - 0x10FF, Port control registers, max AHCI_MAX_PORTS
  102. ends
  103.  
  104. ; Port Control registers
  105. struct HBA_PORT
  106.         command_list_base_l      dd ?                 ; 0x00, command list base address, 1K-byte aligned
  107.         command_list_base_h      dd ?                 ; 0x04, command list base address upper 32 bits, used on 64 bit systems
  108.         fis_base_l               dd ?                 ; 0x08, FIS base address, 256-byte aligned
  109.         fis_base_h               dd ?                 ; 0x0C, FIS base address upper 32 bits, used on 64 bit systems
  110.         interrupt_status         dd ?                 ; 0x10
  111.         interrupt_enable         dd ?                 ; 0x14
  112.         command                  dd ?                 ; 0x18, command and status
  113.         reserved0                dd ?                 ; 0x1C
  114.         task_file_data           dd ?                 ; 0x20
  115.         signature                dd ?                 ; 0x24
  116.         sata_status              dd ?                 ; 0x28, SATA status (SCR0:SStatus)
  117.         sata_control             dd ?                 ; 0x2C, SATA control (SCR2:SControl)
  118.         sata_error               dd ?                 ; 0x30, SATA error (SCR1:SError)
  119.         sata_active              dd ?                 ; 0x34, SATA active (SCR3:SActive)
  120.         command_issue            dd ?                 ; 0x38
  121.         sata_notification        dd ?                 ; 0x3C, SATA notification (SCR4:SNotification)
  122.         fis_based_switch_control dd ?                 ; 0x40
  123.         reserved1                rd 11                ; 0x44 - 0x6F
  124.         vendor                   rd 4                 ; 0x70 - 0x7F, vendor specific
  125. ends
  126.  
  127. ; Command header structure, size = 32 bytes
  128. struct HBA_CMD_HDR
  129.     flags1       db ? ; 0bPWACCCCC, P - Prefetchable, W - Write (1: H2D, 0: D2H)
  130.                        ; A - ATAPI, C - Command FIS length in DWORDS, 2 ~ 16
  131.    
  132.     flags2       db ? ; 0bPPPPRCB(Re), P - Port multiplier port, R - Reserved,
  133.                        ; C - Clear busy upon R_OK, B - BIST, Re - Reset
  134.    
  135.     prdtl         dw ? ; Physical region descriptor table length in entries
  136.     prdbc         dd ? ; Physical region descriptor byte count transferred
  137.     ctba          dd ? ; Command table descriptor base address
  138.     ctbau         dd ? ; Command table descriptor base address upper 32 bits
  139.                   rd 4 ; Reserved
  140. ends
  141.  
  142. ; Physical region descriptor table entry, size = 16 bytes
  143. struct HBA_PRDT_ENTRY
  144.     dba           dd ?  ; Data base address
  145.     dbau          dd ?  ; Data base address upper 32 bits
  146.                   dd ?  ; Reserved
  147.     flags        dd ?  ; 0bIR..RD..D, I (1 bit) - Interrupt on completion,
  148.                         ; R (9 bits) - Reserved, D (22 bits) - Byte count, 4M max
  149. ends
  150.  
  151. struct HBA_CMD_TBL
  152.     cfis          rb 64 ; 0x00, Command FIS
  153.     acmd          rb 16 ; 0x40, ATAPI command, 12 or 16 bytes
  154.                   rb 48 ; 0x50, Reserved
  155.     prdt_entry    HBA_PRDT_ENTRY  ; 0x80, Physical region descriptor table entries, 0 ~ 65535
  156.                         ; so, this structure is variable-length
  157. ends
  158.  
  159. ; Contains virtual mappings for port phys memory regions
  160. struct PORT_DATA
  161.     clb           dd ? ; Command list base
  162.     fb            dd ? ; FIS base
  163.     ctba_arr      rd 32 ; ctba_arr[0] = clb[0].ctba, ... and so on.
  164.     port          dd ? ; address of correspoding HBA_PORT structure
  165.     portno        dd ? ; port index, 0..31
  166.     drive_type    db ? ; drive type
  167.     sector_count  dq ? ; number of sectors
  168.     ctr_ptr       dd ? ; pointer to controller to which port belongs
  169. ends
  170.  
  171. ; Register FIS – Host to Device
  172. struct FIS_REG_H2D
  173.         fis_type      db ?       ; FIS_TYPE_REG_H2D
  174.         flags        db ?       ; 0bCRRRPPPP, C - 1: Command, 0: Control
  175.                                  ; R - Reserved, P - Port multiplier
  176.  
  177.         command       db ?       ; Command register
  178.         featurel      db ?       ; Feature register, 7:0
  179.  
  180.         lba0          db ?       ; LBA low register, 7:0
  181.         lba1          db ?       ; LBA mid register, 15:8
  182.         lba2          db ?       ; LBA high register, 23:16
  183.         device        db ?       ; Device register
  184.  
  185.         lba3          db ?       ; LBA register, 31:24
  186.         lba4          db ?       ; LBA register, 39:32
  187.         lba5          db ?       ; LBA register, 47:40
  188.         featureh      db ?       ; Feature register, 15:8
  189.  
  190.         countl        db ?       ; Count register, 7:0
  191.         counth        db ?       ; Count register, 15:8
  192.         icc           db ?       ; Isochronous command completion
  193.         control       db ?       ; Control register
  194.  
  195.                       rb 4       ; Reserved
  196. ends
  197.  
  198. ; Register FIS – Device to Host
  199. struct FIS_REG_D2H
  200.     fis_type      db ?           ; FIS_TYPE_REG_D2H
  201.  
  202.     flags        db ?           ; 0bRIRPPPP, P - Port multiplier, R - Reserved
  203.                                  ; I - Interrupt bit
  204.  
  205.     status        db ?           ; Status register
  206.     error         db ?           ; Error register
  207.  
  208.     lba0          db ?           ; LBA low register, 7:0
  209.     lba1          db ?           ; LBA mid register, 15:8
  210.     lba2          db ?           ; LBA high register, 23:16
  211.     device        db ?           ; Device register
  212.  
  213.     lba3          db ?           ; LBA register, 31:24
  214.     lba4          db ?           ; LBA register, 39:32
  215.     lba5          db ?           ; LBA register, 47:40
  216.                   db ?           ; Reserved
  217.  
  218.     countl        db ?           ; Count register, 7:0
  219.     counth        db ?           ; Count register, 15:8
  220.                   rb 2           ; Reserved
  221.  
  222.                   rb 4           ; Reserved
  223. ends
  224.  
  225. ; Data FIS – Bidirectional
  226. struct FIS_DATA
  227.     fis_type      db ?           ; FIS_TYPE_DATA
  228.     flags        db ?           ; 0bRRRRPPPP, R - Reserved, P - Port multiplier
  229.                   rb 2           ; Reserved
  230.     ; DWORD 1 ~ N (?)
  231.     data          rd 1           ; Payload
  232. ends
  233.  
  234. ; PIO Setup – Device to Host
  235. struct FIS_PIO_SETUP
  236.     fis_type      db ?           ; FIS_TYPE_PIO_SETUP
  237.  
  238.     flags        db ?           ; 0bRIDRPPPP, P - Port multiplier, R - Reserved
  239.                                  ; I - Interrupt bit, D - Data transfer direction, 1 - device to host
  240.  
  241.     status        db ?           ; Status register
  242.     error         db ?           ; Error register
  243.  
  244.     lba0          db ?           ; LBA low register, 7:0
  245.     lba1          db ?           ; LBA mid register, 15:8
  246.     lba2          db ?           ; LBA high register, 23:16
  247.     device        db ?           ; Device register
  248.  
  249.     lba3          db ?           ; LBA register, 31:24
  250.     lba4          db ?           ; LBA register, 39:32
  251.     lba5          db ?           ; LBA register, 47:40
  252.                   db ?           ; Reserved
  253.  
  254.     countl        db ?           ; Count register, 7:0
  255.     counth        db ?           ; Count register, 15:8
  256.                   db ?           ; Reserved
  257.     e_status      db ?           ; New value of status register
  258.  
  259.     tc            dw ?           ; Transfer count
  260.                   rb 2           ; Reserved
  261. ends
  262.  
  263. ; DMA Setup – Device to Host
  264. struct FIS_DMA_SETUP
  265.     fis_type      db ?           ; FIS_TYPE_DMA_SETUP
  266.     flags        db ?           ; 0bAIDRPPPP, A - Auto-activate. Specifies if DMA Activate FIS is needed,
  267.                                  ; I - Interrupt bit, D - Data transfer direction, 1 - device to host,
  268.                                  ; R - Reserved, P - Port multiplier
  269.  
  270.                   rb 2           ; Reserved
  271.     DMAbufferID   dq ?           ; DMA Buffer Identifier.
  272.                                  ; Used to Identify DMA buffer in host memory.
  273.                                  ; SATA Spec says host specific and not in Spec.
  274.                                  ; Trying AHCI spec might work.
  275.  
  276.                   dd ?           ; Reserved
  277.     DMAbufOffset  dd ?           ; Byte offset into buffer. First 2 bits must be 0
  278.     TransferCount dd ?           ; Number of bytes to transfer. Bit 0 must be 0
  279.                   dd ?           ; Reserved
  280. ends
  281.  
  282. ; Set device bits FIS - device to host
  283. struct FIS_DEV_BITS
  284.     fis_type      db ?           ; FIS_TYPE_DEV_BITS
  285.     flags        db ?           ; 0bNIRRPPPP, N - Notification, I - Interrupt,
  286.                                  ; R - Reserved, P - Port multiplier
  287.    
  288.     status        db ?           ; Status register
  289.     error         db ?           ; Error register
  290.    
  291.     protocol      dd ?           ; Protocol
  292. ends
  293.  
  294. struct HBA_FIS
  295.     dsfis         FIS_DMA_SETUP  ; 0x00, DMA Setup FIS
  296.                   rb 4           ; padding
  297.  
  298.     psfis         FIS_PIO_SETUP  ; 0x20, PIO Setup FIS
  299.                   rb 12          ; padding
  300.  
  301.     rfis          FIS_REG_D2H    ; 0x40, Register - Device to Host FIS
  302.                   rb 4           ; padding
  303.  
  304.     sdbfis        FIS_DEV_BITS   ; 0x58, Set Device Bit FIS
  305.  
  306.     ufis          rb 64          ; 0x60
  307.  
  308.                   rb (0x100 - 0xA0) ; 0xA0, Reserved
  309. ends
  310.  
  311. ; --------------------------------------------------
  312. uglobal
  313.  
  314. align 4
  315.  
  316. ; AHCI controller structure
  317. struct AHCI_CTR
  318.         abar             dd ?    ; pointer to HBA Memory (BAR5) mapped to virtual kernelspace memory
  319.         pcidev           dd ?    ; pointer to corresponding PCIDEV structure
  320.         port_data_arr    rb (sizeof.PORT_DATA*AHCI_MAX_PORTS)
  321.         mutex            MUTEX
  322. ends
  323.  
  324. ctr1_data AHCI_CTR
  325. ctr2_data AHCI_CTR
  326. ctr3_data AHCI_CTR
  327. ctr4_data AHCI_CTR
  328. ctr5_data AHCI_CTR
  329. ctr6_data AHCI_CTR
  330. ctr7_data AHCI_CTR
  331. ctr8_data AHCI_CTR
  332.  
  333. ctr_ptr dd ?
  334. endg
  335.  
  336. iglobal
  337. align 4
  338. ahci_callbacks:
  339.     dd  ahci_callbacks.end - ahci_callbacks
  340.     dd  0   ; no close function
  341.     dd  0   ; no closemedia function
  342.     dd  ahci_querymedia
  343.     dd  ahci_read
  344.     dd  ahci_write
  345.     dd  0   ; no flush function
  346.     dd  0   ; use default cache size
  347. .end:
  348. sata_dev_name      db 'sd', 0, 0, 0
  349. satapi_dev_name    db 'scd', 0, 0, 0
  350. sata_dev_counter   dd 0  ; sata devices counter
  351. satapi_dev_counter dd 0  ; satapi devices (optical drives) counter
  352. ctr_counter        dd 0  ; controllers counter
  353. disk_to_add_name   dd 0  ; local var for ahci_init
  354. endg
  355.  
  356. ; -----------------------------------------------------------------------
  357. ; detect ahci controller and initialize
  358. align 4
  359. ahci_init:
  360.         mov     esi, pcidev_list
  361.         mov     [ctr_ptr], ctr1_data
  362.         mov     [sata_dev_counter], 0
  363. .find_ahci_ctr:
  364.         mov     esi, [esi + PCIDEV.fd]
  365.         cmp     esi, pcidev_list
  366.         jz      .end_find_ahci_ctr
  367.         mov     eax, [esi + PCIDEV.class]
  368.         ;DEBUGF  1, "K: device class = %x\n", eax
  369.         shr     eax, 8 ; shift right because lowest 8 bits if ProgIf field
  370.         cmp     eax, 0x0106 ; 0x01 - Mass Storage Controller class,  0x06 - Serial ATA Controller subclass
  371.         jz      .ahci_ctr_found
  372.         jmp     .find_ahci_ctr
  373.  
  374. .end_find_ahci_ctr:
  375.         cmp     [ctr_counter], 0
  376.         ja      @f
  377.         DEBUGF  1, "K: AHCI: controllers not found\n"
  378. @@:
  379.         ret
  380.  
  381. .ahci_ctr_found:
  382.         push    esi
  383.  
  384.         mov     ecx, [ctr_ptr]
  385.         add     ecx, AHCI_CTR.mutex
  386.         call    mutex_init
  387.  
  388.         mov     ecx, [ctr_ptr]
  389.         mov     [ecx + AHCI_CTR.pcidev], esi
  390.  
  391.         mov     eax, [esi+PCIDEV.class]
  392.         movzx   ebx, byte [esi+PCIDEV.bus]
  393.         movzx   ecx, byte [esi+PCIDEV.devfn]
  394.         shr     ecx, 3 ; get rid of 3 lowest bits (function code), the rest bits is device code
  395.         movzx   edx, byte [esi+PCIDEV.devfn]
  396.         and     edx, 00000111b ; get only 3 lowest bits (function code)
  397.         DEBUGF  1, "K: found AHCI controller, (class, subcl, progif) = %x, bus = %x, device = %x, function = %x\n", eax, ebx, ecx, edx
  398.        
  399.         ; get BAR5 value, it is physical address
  400.         movzx   ebx, [esi + PCIDEV.bus]
  401.         movzx   ebp, [esi + PCIDEV.devfn]
  402.         stdcall pci_read32, ebx, ebp, PCI_REG_BAR5
  403.         DEBUGF  1, "K: AHCI controller MMIO = %x\n", eax
  404.         mov     edi, eax
  405.  
  406.         ; get the size of MMIO region
  407.         stdcall pci_write32, ebx, ebp, PCI_REG_BAR5, 0xFFFFFFFF
  408.         stdcall pci_read32, ebx, ebp, PCI_REG_BAR5
  409.         not     eax
  410.         inc     eax
  411.         DEBUGF  1, "K: AHCI: MMIO region size = 0x%x bytes\n", eax
  412.  
  413.         ; Map MMIO region to virtual memory
  414.         stdcall map_io_mem, edi, eax, PG_SWR + PG_NOCACHE
  415.         push    ecx
  416.         mov     ecx, [ctr_ptr]
  417.         mov     [ecx + AHCI_CTR.abar], eax
  418.         pop     ecx
  419.         DEBUGF  1, "K: AHCI controller BAR5 mapped to virtual addr %x\n", eax
  420.  
  421.         ; Restore the original BAR5 value
  422.         stdcall pci_write32, ebx, ebp, PCI_REG_BAR5, edi
  423.  
  424.         ; Enable dma bus mastering, memory space access, clear the "disable interrupts" bit
  425.         ; Usually, it is already done before us
  426.         movzx   ebx, [esi + PCIDEV.bus]
  427.         movzx   ebp, [esi + PCIDEV.devfn]
  428.         stdcall pci_read32, ebx, ebp, PCI_REG_STATUS_COMMAND
  429.         DEBUGF  1, "K: AHCI: pci_status_command = %x\nEnabling interrupts, DMA bus mastering and memory space access\n", eax
  430.         or      eax, 0x06 ; pci.command |= 0x06 (dma bus mastering + memory space access)
  431.         btr     eax, 10 ; clear the "disable interrupts" bit
  432.         DEBUGF  1, "K: AHCI: pci_status_command = %x\n", eax
  433.         stdcall pci_write32, ebx, ebp, PCI_REG_STATUS_COMMAND, eax
  434.  
  435.         mov     esi, [ctr_ptr]
  436.         mov     esi, [esi + AHCI_CTR.abar]
  437.  
  438.         ; ; Print some register values to debug board
  439.         ; DEBUGF  1, "K: AHCI: HBA.cap = %x, HBA.ghc = %x, HBA_MEM.version = %x\n", [esi + HBA_MEM.cap], [esi + HBA_MEM.ghc], [esi + HBA_MEM.version]
  440.  
  441.         ;-------------------------------------------------------
  442.         ; Request BIOS/OS ownership handoff, if supported. (TODO check correctness)
  443.         ;mov     ebx, [esi + HBA_MEM.cap2]
  444.         ;DEBUGF  1, "K: AHCI: HBA_MEM.cap2 = %x\n", ebx
  445.         bt      [esi + HBA_MEM.cap2], bit_AHCI_HBA_CAP2_BOH
  446.         jnc     .end_handoff
  447.         DEBUGF  1, "K: AHCI: requesting AHCI ownership change...\n"
  448.         bts     [esi + HBA_MEM.bohc], bit_AHCI_HBA_BOHC_OOS
  449.  
  450. .wait_not_bos:
  451.         bt      [esi + HBA_MEM.bohc], bit_AHCI_HBA_BOHC_BOS
  452.         jc      .wait_not_bos
  453.  
  454.         mov     ebx, 3
  455.         call    delay_hs
  456.  
  457.         ; if Bios Busy is still set after 30 mS, wait 2 seconds.
  458.         bt      [esi + HBA_MEM.bohc], bit_AHCI_HBA_BOHC_BB
  459.         jnc     @f
  460.  
  461.         mov     ebx, 200
  462.         call    delay_hs
  463. @@:
  464.         DEBUGF  1, "K: AHCI: ownership change completed.\n"
  465.  
  466. .end_handoff:
  467.         ;-------------------------------------------------------
  468.  
  469.         ; enable the AHCI and reset it
  470.         bts     [esi + HBA_MEM.ghc], bit_AHCI_HBA_GHC_AHCI_ENABLE
  471.         bts     [esi + HBA_MEM.ghc], bit_AHCI_HBA_GHC_RESET
  472.  
  473.         ; wait for reset to complete
  474. .wait_reset:
  475.         bt      [esi + HBA_MEM.ghc], bit_AHCI_HBA_GHC_RESET
  476.         jc      .wait_reset
  477.  
  478.         ; enable the AHCI and interrupts
  479.         bts     [esi + HBA_MEM.ghc], bit_AHCI_HBA_GHC_AHCI_ENABLE
  480.         bts     [esi + HBA_MEM.ghc], bit_AHCI_HBA_GHC_INTERRUPT_ENABLE
  481.         mov     ebx, 2
  482.         call    delay_hs
  483.        
  484.         DEBUGF  1, "K: AHCI: caps: %x %x, ver: %x, ghc: %x, pi: %x\n", [esi + HBA_MEM.cap], [esi + HBA_MEM.cap2], [esi + HBA_MEM.version], [esi + HBA_MEM.ghc], [esi + HBA_MEM.pi]
  485.  
  486.         ; TODO:
  487.         ; calculate irq line
  488.         ; ahciHBA->ghc |= AHCI_GHC_IE;
  489.         ; IDT::RegisterInterruptHandler(irq, InterruptHandler);
  490.         ; ahciHBA->is = 0xffffffff;
  491.  
  492.         xor     ebx, ebx
  493. .detect_drives:
  494.         cmp     ebx, AHCI_MAX_PORTS
  495.         jae     .end_detect_drives
  496.  
  497.         ; if port with index ebx is not implemented then go to next
  498.         mov     ecx, [esi + HBA_MEM.pi]
  499.         bt      ecx, ebx
  500.         jnc     .continue_detect_drives
  501.  
  502.         mov     edi, ebx
  503.         imul    edi, sizeof.HBA_PORT
  504.         add     edi, HBA_MEM.ports
  505.         add     edi, esi
  506.         ; now edi - base of HBA_MEM.ports[ebx]
  507.  
  508.         DEBUGF  1, "K: AHCI: port %d, cmd = %x, ssts = %x\n", ebx, [edi + HBA_PORT.command], [edi + HBA_PORT.sata_status]
  509.  
  510.         ; If port is not idle force it to be idle
  511.         mov     eax, [edi + HBA_PORT.command]
  512.         and     eax, (AHCI_HBA_PxCMD_ST or AHCI_HBA_PxCMD_CR or AHCI_HBA_PxCMD_FRE or AHCI_HBA_PxCMD_FR)
  513.         test    eax, eax
  514.         jz      @f
  515.  
  516.         mov     eax, edi
  517.         DEBUGF  1, "ahci_stop_cmd..\n"
  518.         call    ahci_stop_cmd
  519. @@:
  520.         ; TODO: what is purpose of this block of code ?
  521.         ; Reset port, disable slumber and partial state
  522.         ; mov     [edi + HBA_PORT.sata_control], 0x301
  523.         ; push    ebx
  524.         ; mov     ebx, 5 ; wait 50 ms
  525.         ; call    delay_hs
  526.         ; pop     ebx
  527.         ; mov     [edi + HBA_PORT.sata_control], 0x300
  528.  
  529.         ; if(abar->cap & HBA_MEM_CAP_SSS)
  530.         ; {
  531.         ; abar->ports[i].cmd |= (HBA_PxCMD_SUD | HBA_PxCMD_POD | HBA_PxCMD_ICC);
  532.         ; Sleep(10);
  533.         ; }
  534.         ; rewritten to:
  535.         bt      [esi + HBA_MEM.cap], 27 ; check Supports Staggered Spin-up bit in capabilities
  536.         jnc     @f
  537.         DEBUGF  1, "Supports Staggered Spin-up, spinning up the port..\n"
  538.         or      [edi + HBA_PORT.command], (0x0002 or 0x0004 or 0x10000000)
  539.         push    ebx
  540.         mov     ebx, 10 ; wait 100 ms
  541.         call    delay_hs
  542.         pop     ebx
  543. @@:
  544.         ; Clear interrupt status and error status
  545.         mov     [edi + HBA_PORT.sata_error], 0xFFFFFFFF
  546.         mov     [edi + HBA_PORT.interrupt_status], 0xFFFFFFFF
  547.  
  548.         ; ------------------------------------------
  549.  
  550.         mov     ecx, [edi + HBA_PORT.sata_status]
  551.         shr     ecx, 8
  552.         and     ecx, 0x0F
  553.         cmp     ecx, AHCI_HBA_PORT_IPM_ACTIVE
  554.         jne     .continue_detect_drives
  555.  
  556.         mov     ecx, [edi + HBA_PORT.sata_status]
  557.         and     ecx, AHCI_HBA_PxSSTS_DET
  558.         cmp     ecx, AHCI_HBA_PxSSTS_DET_PRESENT
  559.         jne     .continue_detect_drives
  560.  
  561.         ; DEBUGF  1, "K: AHCI: found drive at port %d, cmd = 0x%x, ssts = 0x%x, signature = 0x%x\n", ebx, [edi + HBA_PORT.command], [edi + HBA_PORT.sata_status], [edi + HBA_PORT.signature]  
  562.  
  563.         mov     ecx, ebx
  564.         imul    ecx, sizeof.PORT_DATA
  565.         add     ecx, AHCI_CTR.port_data_arr
  566.         add     ecx, [ctr_ptr]
  567.         mov     eax, [ctr_ptr]
  568.         mov     [ecx + PORT_DATA.ctr_ptr], eax ; to which controller the port belongs
  569.         stdcall ahci_port_rebase, edi, ebx, ecx
  570.  
  571.         ; DEBUGF  1, "K: AHCI: After REBASING, signature = 0x%x\n", [edi + HBA_PORT.signature]
  572.  
  573.         ; Determine drive type by checking port signature
  574. .switch_sig:
  575.         cmp     [edi + HBA_PORT.signature], SATA_SIG_ATA
  576.         mov     eax, AHCI_DEV_SATA
  577.         jz      .end_switch_sig
  578.  
  579.         cmp     [edi + HBA_PORT.signature], SATA_SIG_ATAPI
  580.         mov     eax, AHCI_DEV_SATAPI
  581.         jz      .end_switch_sig
  582.  
  583.         cmp     [edi + HBA_PORT.signature], SATA_SIG_SEMB
  584.         mov     eax, AHCI_DEV_SEMB
  585.         jz      .end_switch_sig
  586.  
  587.         cmp     [edi + HBA_PORT.signature], SATA_SIG_PM
  588.         mov     eax, AHCI_DEV_PM
  589.         jz      .end_switch_sig
  590.  
  591.         DEBUGF  1, "Unknown device signature\n"
  592.         mov     eax, AHCI_DEV_NULL
  593. .end_switch_sig:
  594.         mov     [ecx + PORT_DATA.drive_type], al
  595.  
  596.         DEBUGF  1, "K: AHCI: found drive on port %u: TYPE = %u\n", ebx, [ecx + PORT_DATA.drive_type]
  597.  
  598.         stdcall ahci_port_identify, ecx
  599.  
  600.         ; register drive as disk in system if it is SATA or SATAPI:
  601.         cmp     [ecx + PORT_DATA.drive_type], AHCI_DEV_SATA
  602.         je      .disk_add_sata
  603.         cmp     [ecx + PORT_DATA.drive_type], AHCI_DEV_SATAPI
  604.         je      .disk_add_satapi
  605.         jne     .after_add_disk ; else skip adding disk code
  606.        
  607. .disk_add_sata:
  608.         push    ecx
  609.         mov     eax, [sata_dev_counter]
  610.         inc     [sata_dev_counter]
  611.         xor     edx, edx
  612.         mov     ecx, 10
  613.         div     ecx ; eax = sata_dev_counter / 10, edx = sata_dev_counter % 10
  614.         test    eax, eax
  615.         jz      .concat_one_digit
  616.         add     al, '0'
  617.         mov     byte [sata_dev_name + 2], al
  618.         add     dl, '0'
  619.         mov     byte [sata_dev_name + 3], dl
  620.         jmp     .endif1
  621. .concat_one_digit:
  622.         add     dl, '0'
  623.         mov     byte [sata_dev_name + 2], dl
  624. .endif1:
  625.         mov     [disk_to_add_name], sata_dev_name
  626.         pop     ecx
  627.         jmp     .disk_add
  628.  
  629. .disk_add_satapi:
  630.         push    ecx
  631.         mov     eax, [satapi_dev_counter]
  632.         inc     [satapi_dev_counter]
  633.         xor     edx, edx
  634.         mov     ecx, 10
  635.         div     ecx ; eax = satapi_dev_counter / 10, edx = satapi_dev_counter % 10
  636.         test    eax, eax
  637.         jz      .concat_one_digit2
  638.         add     al, '0'
  639.         mov     byte [satapi_dev_name + 3], al
  640.         add     dl, '0'
  641.         mov     byte [satapi_dev_name + 4], dl
  642.         jmp     .endif2
  643. .concat_one_digit2:
  644.         add     dl, '0'
  645.         mov     byte [satapi_dev_name + 3], dl
  646. .endif2:
  647.         mov     [disk_to_add_name], satapi_dev_name
  648.         pop     ecx
  649.  
  650. .disk_add:
  651.         DEBUGF  1, "adding '%s'\n", [disk_to_add_name]
  652.  
  653.         push    ecx
  654.         stdcall disk_add, ahci_callbacks, [disk_to_add_name], ecx, 0
  655.         pop     ecx
  656.         test    eax, eax
  657.         jz      .disk_add_fail
  658.         push    ecx
  659.         stdcall disk_media_changed, eax, 1 ; system will scan for partitions on disk
  660.         pop     ecx
  661.  
  662.         jmp     .after_add_disk
  663.  
  664. .disk_add_fail:
  665.         DEBUGF  1, "Failed to add disk\n"
  666. .after_add_disk:
  667.  
  668. .continue_detect_drives:
  669.         inc     ebx
  670.         jmp     .detect_drives
  671.  
  672. .end_detect_drives:
  673.         pop     esi
  674.         add     [ctr_ptr], sizeof.AHCI_CTR
  675.         inc     [ctr_counter]
  676.         cmp     [ctr_counter], 8
  677.         jnz     .find_ahci_ctr
  678.         DEBUGF  1, "AHCI: reached controllers number limit\n"
  679.         ret
  680. ; -------------------------------------------------
  681.  
  682. modelstr  rb 42
  683. ; Identify drive on port ; TODO check
  684. ; in: pdata - address of PORT_DATA structure
  685. proc ahci_port_identify stdcall, pdata: dword
  686.         locals
  687.             cmdslot dd ?
  688.             cmdheader dd ?
  689.             cmdtable  dd ?
  690.             buf_phys  dd ?
  691.             buf_virt  dd ?
  692.         endl
  693.  
  694.         pushad
  695.        
  696.         mov     esi, [pdata] ; esi - address of PORT_DATA struct of port
  697.         stdcall ahci_find_cmdslot, esi
  698.  
  699.         cmp     eax, -1
  700.         jne     .cmdslot_found
  701.  
  702.         DEBUGF  1, "No free cmdslot on port %u\n", [esi + PORT_DATA.portno]
  703.         jmp     .ret
  704.  
  705. .cmdslot_found:
  706.         mov     [cmdslot], eax
  707.         ; DEBUGF  1, "Found free cmdslot %u on port %u\n", [cmdslot], [esi + PORT_DATA.portno]
  708.  
  709.         shl     eax, BSF sizeof.HBA_CMD_HDR
  710.         add     eax, [esi + PORT_DATA.clb]
  711.         mov     [cmdheader], eax ; address of virtual mapping of command header
  712.         mov     eax, [cmdslot]
  713.         mov     eax, [esi + eax*4 + PORT_DATA.ctba_arr]
  714.         mov     [cmdtable], eax ; address of virtual mapping of command table of command header
  715.  
  716.         stdcall _memset, eax, 0, sizeof.HBA_CMD_TBL
  717.  
  718.         call    alloc_page
  719.         mov     [buf_phys], eax
  720.  
  721.         stdcall map_io_mem, eax, 4096, PG_NOCACHE + PG_SWR  ; map to virt memory so we can work with it
  722.         mov     [buf_virt], eax
  723.  
  724.         mov     eax, [cmdtable]
  725.         mov     ebx, [buf_phys]
  726.         mov     dword [eax + HBA_CMD_TBL.prdt_entry + HBA_PRDT_ENTRY.dba], ebx
  727.         mov     dword [eax + HBA_CMD_TBL.prdt_entry + HBA_PRDT_ENTRY.dbau], 0
  728.         and     [eax + HBA_CMD_TBL.prdt_entry + HBA_PRDT_ENTRY.flags], not 0x3FFFFF ; zero out lower 22 bits, they used for byte count
  729.         or      [eax + HBA_CMD_TBL.prdt_entry + HBA_PRDT_ENTRY.flags], 512 - 1 ; reason why -1 see in spec on this field
  730.         ; or      [eax + HBA_CMD_TBL.prdt_entry + HBA_PRDT_ENTRY.flags], 1 shl 31 ; enable interrupt on completion
  731.  
  732.         mov     eax, [cmdheader]
  733.         and     [eax + HBA_CMD_HDR.flags1], not 0x1F ; zero out lower 5 bits, they will be used for cfl
  734.         or      [eax + HBA_CMD_HDR.flags1], (sizeof.FIS_REG_H2D / 4) ; set command fis length in dwords
  735.         movzx   bx, [eax + HBA_CMD_HDR.flags1]
  736.         btr     bx, 6 ; flag W = 0
  737.         mov     [eax + HBA_CMD_HDR.flags1], bl
  738.         movzx   bx, [eax + HBA_CMD_HDR.flags2]
  739.         btr     bx, 2 ; flag C = 0
  740.         mov     [eax + HBA_CMD_HDR.flags2], bl
  741.         mov     [eax + HBA_CMD_HDR.prdtl], 1
  742.  
  743.         mov     eax, [cmdtable]
  744.         mov     byte [eax + HBA_CMD_TBL.cfis + FIS_REG_H2D.fis_type], FIS_TYPE_REG_H2D
  745.         movzx   ebx, byte [eax + HBA_CMD_TBL.cfis + FIS_REG_H2D.flags]
  746.         bts     ebx, bit_AHCI_H2D_FLAG_CMD ; Set Command bit in H2D FIS.
  747.         mov     byte [eax + HBA_CMD_TBL.cfis + FIS_REG_H2D.flags], bl
  748.  
  749.         ; Choose identify command depending on drive type
  750.         mov     byte [eax + HBA_CMD_TBL.cfis + FIS_REG_H2D.command], ATA_IDENTIFY
  751.         cmp     [esi + PORT_DATA.drive_type], AHCI_DEV_SATAPI
  752.         jne     @f
  753.         mov     byte [eax + HBA_CMD_TBL.cfis + FIS_REG_H2D.command], ATAPI_IDENTIFY
  754. @@:
  755.         mov     byte [eax + HBA_CMD_TBL.cfis + FIS_REG_H2D.device], 0
  756.  
  757.         mov     edi, [esi + PORT_DATA.port] ; edi - address of HBA_PORT struct of port
  758.  
  759.         ; Wait on previous command to complete, before issuing new command.
  760.         stdcall ahci_port_wait, edi, AHCI_PORT_TIMEOUT
  761.         ; DEBUGF  1, "eax = %x\n", eax
  762.         ; TODO check eax error value
  763.  
  764.         mov     eax, [cmdslot]
  765.         bts     [edi + HBA_PORT.command_issue], eax ; Issue the command
  766.  
  767.         ; Wait for command completion
  768.         stdcall ahci_port_cmd_wait, edi, eax;, AHCI_PORT_CMD_TIMEOUT
  769.         ; DEBUGF  1, " eax = %x\n", eax
  770.         ; TODO check eax error value
  771.  
  772.         ; DEBUGF  1, "sata_error register = 0x%x\n", [edi + HBA_PORT.sata_error]
  773.         mov     esi, [buf_virt]
  774.         add     esi, 27*2
  775.         mov     edi, modelstr
  776.         mov     ecx, ((46-27)+1)*2
  777.         cld
  778.         rep movsb
  779.         mov     byte [edi], 0
  780.        
  781.         stdcall swap_bytes_in_words, modelstr, (46-27)+1
  782.         DEBUGF  1, "IDENTIFICATION RESULT: MODEL = %s\n", modelstr
  783.  
  784.         mov     esi, [pdata]
  785.         cmp     [esi + PORT_DATA.drive_type], AHCI_DEV_SATAPI
  786.         je      .satapi_get_capacity
  787.  
  788. .sata_get_capacity:
  789.         mov     esi, [buf_virt]
  790.         mov     eax, [esi + 200]
  791.         mov     edx, [esi + 200 + 4]
  792.         DEBUGF 1, "lba48 mode sector count = 0x%x:%x\n", edx, eax
  793.  
  794.         mov     ebx, [pdata]
  795.         mov     dword [ebx + PORT_DATA.sector_count], eax
  796.         mov     dword [ebx + PORT_DATA.sector_count + 4], edx
  797.  
  798.         shrd    eax, edx, 11 ; i.e *512 / 1024 / 1024, 512 - sector size
  799.         DEBUGF  1, "disk capacity = %u MiB ", eax
  800.         shrd    eax, edx, 10 ; / 1024
  801.         DEBUGF  1, "= %u GiB\n", eax
  802.         jmp     .end_get_capacity
  803.  
  804. .satapi_get_capacity:
  805.         mov     eax, [cmdtable]
  806.         mov     ebx, [buf_phys]
  807.         mov     dword [eax + HBA_CMD_TBL.prdt_entry + HBA_PRDT_ENTRY.dba], ebx
  808.         mov     dword [eax + HBA_CMD_TBL.prdt_entry + HBA_PRDT_ENTRY.dbau], 0
  809.         and     [eax + HBA_CMD_TBL.prdt_entry + HBA_PRDT_ENTRY.flags], not 0x3FFFFF ; zero out lower 22 bits, they used for byte count
  810.         or      [eax + HBA_CMD_TBL.prdt_entry + HBA_PRDT_ENTRY.flags], 2048 - 1 ; reason why -1 see in spec on this field
  811.         ; or      [eax + HBA_CMD_TBL.prdt_entry + HBA_PRDT_ENTRY.flags], 1 shl 31 ; enable interrupt on completion
  812.  
  813.         mov     byte [eax + HBA_CMD_TBL.cfis + FIS_REG_H2D.command], 0xA0 ; TODO: move to ATA_PACKET const
  814.         mov     byte [eax + HBA_CMD_TBL.acmd], 0x25 ; means: cmd_table->acmd[0] = ATAPI_READ_CAPACITY >> 8; TODO use consts.
  815.  
  816.         mov     edi, [esi + PORT_DATA.port] ; edi - address of HBA_PORT struct of port
  817.         ; Wait on previous command to complete, before issuing new command.
  818.         stdcall ahci_port_wait, edi, AHCI_PORT_TIMEOUT
  819.         ; DEBUGF  1, "eax = %x\n", eax
  820.         ; TODO check eax error value
  821.         mov     eax, [cmdslot]
  822.         bts     [edi + HBA_PORT.command_issue], eax ; Issue the command
  823.         ; Wait for command completion
  824.         stdcall ahci_port_cmd_wait, edi, eax;, AHCI_PORT_CMD_TIMEOUT
  825.  
  826.         ; DEBUGF  1, ". sata_error register = 0x%x\n", [edi + HBA_PORT.sata_error]
  827.  
  828.         mov     esi, [buf_virt]
  829.         mov     eax, [esi]
  830.         mov     edx, [esi + 4]
  831.         DEBUGF 1, "ATAPI sector count = 0x%x:%x\n", edx, eax
  832.  
  833.         mov     ebx, [pdata]
  834.         mov     dword [ebx + PORT_DATA.sector_count], eax
  835.         mov     dword [ebx + PORT_DATA.sector_count + 4], edx
  836.  
  837.         shrd    eax, edx, 9 ; i.e *2048 / 1024 / 1024, 2048 - sector size
  838.         DEBUGF  1, "ATAPI disk capacity = %u MiB ", eax
  839.         shrd    eax, edx, 10 ; / 1024
  840.         DEBUGF  1, "= %u GiB\n", eax
  841.  
  842.         ; aboba
  843. .end_get_capacity:
  844.  
  845. .ret:
  846.         popad
  847.         ret
  848. endp
  849.  
  850. proc ahci_querymedia stdcall, pdata, mediainfo
  851.         push    ecx edx
  852.         mov     eax, [mediainfo]
  853.         mov     edx, [pdata]
  854.         mov     [eax + DISKMEDIAINFO.Flags], 0
  855.         mov     [eax + DISKMEDIAINFO.SectorSize], 512 ; TODO: use const
  856.         cmp     [edx + PORT_DATA.drive_type], AHCI_DEV_SATAPI
  857.         jne     @f
  858.         mov     [eax + DISKMEDIAINFO.SectorSize], 2048 ; TODO: use const
  859. @@:
  860.         mov     ecx, dword[edx + PORT_DATA.sector_count]
  861.         mov     dword [eax + DISKMEDIAINFO.Capacity], ecx
  862.         mov     ecx, dword[edx + PORT_DATA.sector_count + 4]
  863.         mov     dword [eax + DISKMEDIAINFO.Capacity + 4], ecx
  864.         pop     edx ecx
  865.         xor     eax, eax
  866.         ret
  867. endp
  868.  
  869. ; Read/write sectors, note: currently work for SATA, not SATAPI
  870. ; return value: 0 = success, otherwise = error
  871. proc ahci_rw_sectors stdcall pdata: dword, vbuf: dword, startsector: qword, numsectors: dword, is_write: dword
  872.         locals
  873.             cmdslot dd ?
  874.             cmdheader dd ?
  875.             cmdtable  dd ?
  876.             vbuf_orig dd ?
  877.             vbuf_len  dd ?
  878.             phys_region_start dd ?
  879.             new_phys_region_start dd ?
  880.             cur_prd   dd ?
  881.             cur_phys  dd ?
  882.             dbc       dd ?
  883.             cur_phys_page dd ?
  884.             next_phys_page dd ?
  885.             cur_antioffset dd ?
  886.             prdt_bytes_total dd ?
  887.         endl
  888.  
  889.         pushad
  890.  
  891.         DEBUGF  AHCI_DBGLVL, "    ahci_rw_sectors: buffer = 0x%x, startsector = 0x%x:%x, numsectors = %u, is_write = %u\n", [vbuf], [startsector], [startsector + 4], [numsectors], [is_write]:1
  892.  
  893.         mov     esi, [pdata] ; esi - address of PORT_DATA struct of port
  894.         stdcall ahci_find_cmdslot, esi
  895.         cmp     eax, -1
  896.         jne     .cmdslot_found
  897.  
  898.         DEBUGF  AHCI_DBGLVL, "No free cmdslot on port %u\n", [esi + PORT_DATA.portno]
  899.         jmp     .fail
  900.  
  901. .cmdslot_found:
  902.         mov     [cmdslot], eax
  903.         DEBUGF  AHCI_DBGLVL, "Found free cmdslot %u on port %u\n", [cmdslot], [esi + PORT_DATA.portno]
  904.  
  905.         shl     eax, BSF sizeof.HBA_CMD_HDR
  906.         add     eax, [esi + PORT_DATA.clb]
  907.         mov     [cmdheader], eax ; address of virtual mapping of command header
  908.         mov     eax, [cmdslot]
  909.         mov     eax, [esi + eax*4 + PORT_DATA.ctba_arr]
  910.         mov     [cmdtable], eax ; address of virtual mapping of command table of command header
  911.  
  912.         mov     eax, [cmdheader]
  913.         and     [eax + HBA_CMD_HDR.flags1], not 0x1F ; zero out lower 5 bits, they will be used for cfl
  914.         or      [eax + HBA_CMD_HDR.flags1], (sizeof.FIS_REG_H2D / 4) ; set command fis length in dwords
  915.         movzx   bx, [eax + HBA_CMD_HDR.flags1]
  916.         btr     bx, 6 ; flag W = 0
  917.         cmp     [is_write], 1 ; if is_write then set W flag
  918.         jne     @f
  919.         bts     bx, 6
  920. @@:
  921.         mov     [eax + HBA_CMD_HDR.flags1], bl
  922.         movzx   bx, [eax + HBA_CMD_HDR.flags2]
  923.         btr     bx, 2 ; flag C = 0
  924.         mov     [eax + HBA_CMD_HDR.flags2], bl
  925.  
  926.         mov     eax, [vbuf]
  927.         mov     [vbuf_orig], eax
  928.         mov     ebx, [numsectors]
  929.         shl     ebx, 9 ; *= 512
  930.         mov     [vbuf_len], ebx
  931.         DEBUGF  AHCI_DBGLVL, "vbuf_len = %u bytes\n", ebx
  932.        
  933.         mov     ebx, [vbuf]
  934.         and     ebx, 0xFFF
  935.         mov     eax, [vbuf]
  936.         call    get_pg_addr
  937.         add     eax, ebx
  938.         mov     [phys_region_start], eax
  939.         mov     [prdt_bytes_total], 0
  940.         mov     [cur_prd], 0
  941. .fill_prdt:
  942.         cmp     [vbuf_len], 0
  943.         jbe     .fill_prdt_end
  944.  
  945.         mov     eax, [vbuf]
  946.         call    get_pg_addr
  947.         mov     [cur_phys_page], eax
  948.         mov     eax, [vbuf]
  949.         add     eax, 4096
  950.         call    get_pg_addr
  951.         mov     [next_phys_page], eax
  952.         mov     eax, 4096
  953.         mov     ebx, [vbuf]
  954.         and     ebx, 0xFFF
  955.         sub     eax, ebx
  956.         mov     [cur_antioffset], eax
  957.         mov     eax, [cur_phys_page]
  958.         add     eax, ebx
  959.         mov     [cur_phys], eax
  960.  
  961. .check_if1:
  962.         mov     eax, [vbuf_len]
  963.         cmp     eax, [cur_antioffset]
  964.         ja      .check_if2
  965.  
  966.         mov     eax, [cur_phys]
  967.         sub     eax, [phys_region_start]
  968.         add     eax, [vbuf_len]
  969.         dec     eax
  970.         mov     [dbc], eax
  971.         mov     eax, [next_phys_page]
  972.         mov     [new_phys_region_start], eax
  973.         jmp     .add_prd
  974.  
  975. .check_if2:
  976.         mov     eax, [cur_phys]
  977.         add     eax, [cur_antioffset]
  978.         cmp     eax, [next_phys_page]
  979.         je      .check_if3
  980.  
  981.         mov     eax, [cur_phys]
  982.         add     eax, [cur_antioffset]
  983.         sub     eax, [phys_region_start]
  984.         dec     eax
  985.         mov     [dbc], eax
  986.         mov     eax, [next_phys_page]
  987.         mov     [new_phys_region_start], eax
  988.         jmp     .add_prd
  989.  
  990. .check_if3:
  991.         mov     eax, [cur_phys]
  992.         add     eax, [cur_antioffset]
  993.         sub     eax, [phys_region_start]
  994.         cmp     eax, 4*1024*1024
  995.         jb      .after_ifs
  996.  
  997.         mov     [dbc], 4*1024*1024 - 1
  998.         mov     eax, [phys_region_start]
  999.         add     eax, 4*1024*1024
  1000.         jmp     .add_prd
  1001.  
  1002. .after_ifs:
  1003.         jmp     .step_next
  1004.  
  1005. .add_prd:
  1006.         mov     ebx, [cur_prd]
  1007.         shl     ebx, BSF sizeof.HBA_PRDT_ENTRY
  1008.         add     ebx, [cmdtable]
  1009.         add     ebx, HBA_CMD_TBL.prdt_entry ; now ebx - address of 'th prdt_entry
  1010.  
  1011.         DEBUGF  AHCI_DBGLVL, "Added PRDT entry: dba = 0x%x, dbc = %u\n", [phys_region_start], [dbc]
  1012.         mov     eax, [phys_region_start]
  1013.         mov     [ebx + HBA_PRDT_ENTRY.dba], eax
  1014.         mov     [ebx + HBA_PRDT_ENTRY.dbau], 0
  1015.         and     [ebx + HBA_PRDT_ENTRY.flags], not 0x3FFFFF ; zero out lower 22 bits, they used for byte count
  1016.         mov     eax, [dbc]
  1017.         or      [ebx + HBA_PRDT_ENTRY.flags], eax
  1018.        
  1019.         inc     [cur_prd]
  1020.         mov     eax, [dbc]
  1021.         inc     eax
  1022.         add     [prdt_bytes_total], eax
  1023.         mov     eax, [new_phys_region_start]
  1024.         mov     [phys_region_start], eax
  1025.         cmp     [cur_prd], PRDT_MAX_ENTRIES
  1026.         jne     @f
  1027.         jmp     .fill_prdt_end
  1028. @@:
  1029.        
  1030. .step_next:
  1031.         mov     eax, [vbuf_len]
  1032.         cmp     eax, [cur_antioffset]
  1033.         jbe     @f
  1034.         mov     eax, [cur_antioffset]
  1035. @@:
  1036.         add     [vbuf], eax
  1037.         sub     [vbuf_len], eax
  1038.         jmp     .fill_prdt
  1039.  
  1040. .fill_prdt_end:
  1041.  
  1042.         mov     eax, [cmdheader]
  1043.         mov     ebx, [cur_prd]
  1044.         DEBUGF  AHCI_DBGLVL, " PRDTL = %u\n", ebx
  1045.         mov     [eax + HBA_CMD_HDR.prdtl], bx
  1046.  
  1047.         mov     eax, [prdt_bytes_total]
  1048.         DEBUGF  AHCI_DBGLVL, " prdt_bytes_total = %u\n", eax
  1049.         shr     eax, 9 ; /= 512
  1050.         mov     [numsectors], eax
  1051.  
  1052.         mov     eax, [cmdtable]
  1053.         mov     byte [eax + HBA_CMD_TBL.cfis + FIS_REG_H2D.fis_type], FIS_TYPE_REG_H2D
  1054.         movzx   ebx, byte [eax + HBA_CMD_TBL.cfis + FIS_REG_H2D.flags]
  1055.         bts     ebx, bit_AHCI_H2D_FLAG_CMD ; Set Command bit in H2D FIS.
  1056.         mov     byte [eax + HBA_CMD_TBL.cfis + FIS_REG_H2D.flags], bl
  1057.  
  1058.         mov     byte [eax + HBA_CMD_TBL.cfis + FIS_REG_H2D.command], ATA_CMD_READ_DMA_EX
  1059.         cmp     [is_write], 1
  1060.         jne     @f
  1061.         mov     byte [eax + HBA_CMD_TBL.cfis + FIS_REG_H2D.command], ATA_CMD_WRITE_DMA_EX
  1062. @@:
  1063.         mov     ebx, dword [startsector]
  1064.         mov     byte [eax + HBA_CMD_TBL.cfis + FIS_REG_H2D.lba0], bl
  1065.         shr     ebx, 8
  1066.         mov     byte [eax + HBA_CMD_TBL.cfis + FIS_REG_H2D.lba1], bl
  1067.         shr     ebx, 8
  1068.         mov     byte [eax + HBA_CMD_TBL.cfis + FIS_REG_H2D.lba2], bl
  1069.         mov     byte [eax + HBA_CMD_TBL.cfis + FIS_REG_H2D.device], 1 shl 6 ; LBA mode
  1070.         shr     ebx, 8
  1071.         mov     byte [eax + HBA_CMD_TBL.cfis + FIS_REG_H2D.lba3], bl
  1072.         mov     ebx, dword [startsector + 4]
  1073.         mov     byte [eax + HBA_CMD_TBL.cfis + FIS_REG_H2D.lba4], bl
  1074.         shr     ebx, 8
  1075.         mov     byte [eax + HBA_CMD_TBL.cfis + FIS_REG_H2D.lba5], bl
  1076.  
  1077.         mov     ebx, [numsectors]
  1078.         mov     byte [eax + HBA_CMD_TBL.cfis + FIS_REG_H2D.countl], bl
  1079.         shr     ebx, 8
  1080.         mov     byte [eax + HBA_CMD_TBL.cfis + FIS_REG_H2D.counth], bl
  1081.  
  1082.         mov     edi, [esi + PORT_DATA.port] ; edi - address of HBA_PORT struct of port
  1083.  
  1084.         ; Wait on previous command to complete, before issuing new command.
  1085.         stdcall ahci_port_wait, edi, AHCI_PORT_TIMEOUT
  1086.  
  1087.         mov     eax, [cmdslot]
  1088.         bts     [edi + HBA_PORT.command_issue], eax ; Issue the command
  1089.  
  1090.         ; Wait for command completion
  1091.         stdcall ahci_port_cmd_wait, edi, eax;, AHCI_PORT_CMD_TIMEOUT
  1092.  
  1093.         DEBUGF  AHCI_DBGLVL, "sata_error register = 0x%x\n", [edi + HBA_PORT.sata_error]
  1094.  
  1095.         DEBUGF  AHCI_DBGLVL, "R/W completed\n"
  1096.  
  1097. ;         xor     ecx, ecx
  1098. ;         mov     esi, [vbuf_orig]
  1099. ; .print_data:
  1100. ;         cmp     ecx, 512
  1101. ;         jae     .end_print_data
  1102.  
  1103. ;         mov     al, byte [esi + ecx]
  1104. ;         mov     byte [tmpstr], al
  1105. ;         mov     byte [tmpstr + 1], 0
  1106. ;         DEBUGF  1, "0x%x(%s) ", al:2, tmpstr
  1107.  
  1108. ;         inc     ecx
  1109. ;         jmp     .print_data
  1110. ; .end_print_data:
  1111. ;         DEBUGF  1, "\n"
  1112.  
  1113.         popad
  1114.         ;mov     eax, [cmdheader]
  1115.         ;mov     eax, [eax + HBA_CMD_HDR.prdbc]
  1116.         mov     eax, [numsectors]
  1117.         shl     eax, 9 ; *= 512
  1118.         ret
  1119.  
  1120. .fail:
  1121.         popad
  1122.         xor     eax, eax
  1123.         ret
  1124. endp
  1125. tmpstr    rb 16
  1126.  
  1127. ; Read sectors
  1128. ; return value: 0 = success, otherwise = error
  1129. proc ahci_read stdcall pdata: dword, buffer: dword, startsector: qword, numsectors_ptr:dword
  1130.         locals
  1131.                 numsectors dd ?
  1132.         endl
  1133.  
  1134.         pushad
  1135.  
  1136.         mov     ecx, [pdata]
  1137.         mov     ecx, [ecx + PORT_DATA.ctr_ptr]
  1138.         mov     ecx, [ecx + AHCI_CTR.mutex]
  1139.         call    mutex_lock
  1140.  
  1141.         mov     eax, [numsectors_ptr]
  1142.         mov     eax, [eax]
  1143.         mov     [numsectors], eax
  1144.         DEBUGF  AHCI_DBGLVL, "  ahci_read: buffer = 0x%x, startsector = 0x%x:%x, numsectors = %u\n", [buffer], [startsector], [startsector + 4], eax
  1145.  
  1146.         xor     ecx, ecx ; how many sectors have been read
  1147. .read_loop:
  1148.         cmp     ecx, [numsectors]
  1149.         jae     .read_loop_end
  1150.  
  1151.         ; mov     eax, [buffer]
  1152.         ; call    get_pg_addr
  1153.         ; DEBUGF  1, "buf phys = 0x%x\n", eax
  1154.         ; mov     eax, [buffer]
  1155.         ; add     eax, 4096
  1156.         ; call    get_pg_addr
  1157.         ; DEBUGF  1, "buf + 4096 phys = 0x%x\n", eax
  1158.  
  1159.         mov     ebx, [numsectors]
  1160.         sub     ebx, ecx
  1161.         ; DEBUGF  1, "buffer = 0x%x\n", [buffer]
  1162.         stdcall ahci_rw_sectors, [pdata], [buffer], dword [startsector], dword [startsector + 4], ebx, 0
  1163.         ;; TODO check if eax == 0 ?
  1164.  
  1165.         DEBUGF  AHCI_DBGLVL, "    EAX = 0x%x\n", eax
  1166.  
  1167.         add     [buffer], eax
  1168.         shr     eax, 9 ; /=  512
  1169.         add     ecx, eax
  1170.         add     dword [startsector], eax
  1171.         adc     dword [startsector + 4], 0
  1172.  
  1173.         jmp     .read_loop
  1174. .read_loop_end:
  1175.  
  1176.         mov     ecx, [pdata]
  1177.         mov     ecx, [ecx + PORT_DATA.ctr_ptr]
  1178.         mov     ecx, [ecx + AHCI_CTR.mutex]
  1179.         call    mutex_unlock
  1180.  
  1181.         popad
  1182.         xor     eax, eax
  1183.         ret
  1184. endp
  1185.  
  1186. ; Write sectors
  1187. ; return value: 0 = success, otherwise = error
  1188. proc ahci_write stdcall pdata: dword, buffer: dword, startsector: qword, numsectors_ptr:dword
  1189.         locals
  1190.                 numsectors dd ?
  1191.         endl
  1192.  
  1193.         pushad
  1194.  
  1195.         mov     ecx, [pdata]
  1196.         mov     ecx, [ecx + PORT_DATA.ctr_ptr]
  1197.         mov     ecx, [ecx + AHCI_CTR.mutex]
  1198.         call    mutex_lock
  1199.  
  1200.         mov     eax, [numsectors_ptr]
  1201.         mov     eax, [eax]
  1202.         mov     [numsectors], eax
  1203.         DEBUGF  AHCI_DBGLVL, "  ahci_write: buffer = 0x%x, startsector = 0x%x:%x, numsectors = %u\n", [buffer], [startsector], [startsector + 4], eax
  1204.  
  1205.         xor     ecx, ecx ; how many sectors have been read
  1206. .write_loop:
  1207.         cmp     ecx, [numsectors]
  1208.         jae     .write_loop_end
  1209.  
  1210.         mov     ebx, [numsectors]
  1211.         sub     ebx, ecx
  1212.         stdcall ahci_rw_sectors, [pdata], [buffer], dword [startsector], dword [startsector + 4], ebx, 1
  1213.         ;; TODO check if eax == 0 ?
  1214.  
  1215.         DEBUGF  AHCI_DBGLVL, "    EAX = 0x%x\n", eax
  1216.  
  1217.         add     [buffer], eax
  1218.         shr     eax, 9 ; /=  512
  1219.         add     ecx, eax
  1220.         add     dword [startsector], eax
  1221.         adc     dword [startsector + 4], 0
  1222.  
  1223.         jmp     .write_loop
  1224. .write_loop_end:
  1225.  
  1226.         mov     ecx, [pdata]
  1227.         mov     ecx, [ecx + PORT_DATA.ctr_ptr]
  1228.         mov     ecx, [ecx + AHCI_CTR.mutex]
  1229.         call    mutex_unlock
  1230.  
  1231.         popad
  1232.         xor     eax, eax
  1233.         ret
  1234. endp
  1235.  
  1236. ; Start command engine
  1237. ; in: eax - address of HBA_PORT structure
  1238. ahci_start_cmd:
  1239. .wait_cr: ; Wait until CR (bit15) is cleared
  1240.         bt      [eax + HBA_PORT.command], bit_AHCI_HBA_PxCMD_CR
  1241.         jc      .wait_cr
  1242.  
  1243.         ; Set FRE (bit4) and ST (bit0)
  1244.         bts     [eax + HBA_PORT.command], bit_AHCI_HBA_PxCMD_FRE
  1245.         bts     [eax + HBA_PORT.command], bit_AHCI_HBA_PxCMD_ST
  1246.         ; maybe here call ahci flush cmd ? TODO (see seakernel)
  1247.         ret
  1248.  
  1249. ; Stop command engine
  1250. ; in: eax - address of HBA_PORT structure
  1251. ahci_stop_cmd:
  1252.         btr     [eax + HBA_PORT.command], bit_AHCI_HBA_PxCMD_ST ; Clear ST (bit0)
  1253.         btr     [eax + HBA_PORT.command], bit_AHCI_HBA_PxCMD_FRE ; Clear FRE (bit4)
  1254. .wait_fr_cr: ; Wait until FR (bit14), CR (bit15) are cleared
  1255.         bt      [eax + HBA_PORT.command], bit_AHCI_HBA_PxCMD_FR
  1256.         jc      .wait_fr_cr
  1257.         bt      [eax + HBA_PORT.command], bit_AHCI_HBA_PxCMD_CR
  1258.         jc      .wait_fr_cr
  1259.  
  1260.         ret
  1261.  
  1262. ; waits until the port is no longer busy before issuing a new command
  1263. ; in: [port] - address of HBA_PORT structure
  1264. ; [timeout] - timeout (in iterations)
  1265. ; out: eax = 0 if success, 1 if timeout expired
  1266. proc ahci_port_wait stdcall, port: dword, timeout: dword
  1267.         push    ebx ecx
  1268.         mov     ebx, [port]
  1269.         xor     ecx, ecx
  1270. .wait:
  1271.         cmp     ecx, [timeout]
  1272.         jae     .wait_end
  1273.         mov     eax, [ebx + HBA_PORT.task_file_data]
  1274.         and     eax, ATA_DEV_BUSY or ATA_DEV_DRQ
  1275.         test    eax, eax
  1276.         jz      .wait_end
  1277.         inc     ecx
  1278.         jmp     .wait
  1279. .wait_end:
  1280.         xor     eax, eax
  1281.         DEBUGF  AHCI_DBGLVL, "port wait counter = %u\n", ecx
  1282.         cmp     ecx, [timeout] ; if they equal it means port is hung
  1283.         setz    al
  1284.         pop     ecx ebx
  1285.         ret
  1286. endp
  1287.  
  1288.  
  1289. ; Wait for command completion
  1290. ; in: [port] - address of HBA_PORT structure
  1291. ;     [cmdslot] - number of command slot
  1292. ; out: eax = 0 if success, 1 if error
  1293. proc ahci_port_cmd_wait stdcall, port: dword, cmdslot: dword ;, timeout: dword
  1294.         push    ebx ecx edx
  1295.         mov     ebx, [port]
  1296.         mov     edx, [cmdslot]
  1297.         xor     eax, eax
  1298.         xor     ecx, ecx
  1299. .wait:
  1300.         bt      [ebx + HBA_PORT.command_issue], edx
  1301.         jnc     .wait_end
  1302.         bt      [ebx + HBA_PORT.interrupt_status], bit_AHCI_HBA_PxIS_TFES ; check for Task File Error
  1303.         jc      .error
  1304.         inc     ecx
  1305.         jmp     .wait
  1306. .wait_end:
  1307.         DEBUGF  AHCI_DBGLVL, "port cmd wait counter = %u\n", ecx
  1308.         bt      [ebx + HBA_PORT.interrupt_status], bit_AHCI_HBA_PxIS_TFES ; check for Task File Error
  1309.         jc      .error
  1310.         jmp     .ret
  1311. .error:
  1312.         mov     eax, 1
  1313. .ret:
  1314.         pop     edx ecx ebx
  1315.         ret
  1316. endp
  1317.  
  1318. ; ; The commands may not take effect until the command
  1319. ; ; register is read again by software, because reasons.
  1320. ; ; in: eax - address of HBA_PORT structure
  1321. ; ; out: eax - command register value
  1322. ; ahci_flush_cmd:
  1323. ;         mov     eax, [eax + HBA_PORT.command]
  1324. ;         ret
  1325.  
  1326. ; ; Send command to port
  1327. ; ; in: eax - address of HBA_PORT structure
  1328. ; ;     ebx - index of command slot
  1329. ; ahci_send_cmd:
  1330. ;         push    ecx
  1331. ;         mov     [eax + HBA_PORT.interrupt_status], 0xFFFFFFFF
  1332.        
  1333. ;         mov     cl, bl
  1334. ;         mov     [eax + HBA_PORT.command_issue], 1
  1335. ;         shl     [eax + HBA_PORT.command_issue], cl
  1336.  
  1337. ;         call    ahci_flush_cmd
  1338. ;         pop     ecx
  1339. ;         ret
  1340.  
  1341. ; ---------------------------------------------------------------------------
  1342. ; in: port - address of HBA_PORT structure
  1343. ;     portno - port index (0..31)
  1344. ;     pdata - address of PORT_DATA structure
  1345. ; out:
  1346. ;     rebases port and fills pdata with mappings
  1347. proc ahci_port_rebase stdcall, port: dword, portno: dword, pdata: dword
  1348.         locals
  1349.             phys_page1  dd ?
  1350.             virt_page1  dd ?
  1351.             phys_page23 dd ?
  1352.             virt_page23 dd ?
  1353.             tmp         dd ?
  1354.         endl
  1355.  
  1356.         pushad
  1357.  
  1358.         DEBUGF  1, "Rebasing port %u\n", [portno]
  1359.  
  1360.         mov     eax, [port]
  1361.         call    ahci_stop_cmd
  1362.  
  1363.         ; Command list entry size = 32
  1364.         ; Command list entry maxim count = 32
  1365.         ; Command list maxim size = 32*32 = 1K per port
  1366.         call    alloc_page
  1367.         mov     [phys_page1], eax
  1368.  
  1369.         stdcall map_io_mem, eax, 4096, PG_NOCACHE + PG_SWR  ; map to virt memory so we can work with it
  1370.         mov     [virt_page1], eax
  1371.  
  1372.         mov     esi, [port]
  1373.         mov     ebx, [phys_page1]
  1374.         mov     [esi + HBA_PORT.command_list_base_l], ebx ; set the command list base
  1375.         mov     [esi + HBA_PORT.command_list_base_h], 0  ; zero upper 32 bits of addr cause we are 32 bit os
  1376.  
  1377.         mov     edi, [pdata]
  1378.         mov     ebx, [virt_page1]
  1379.         mov     [edi + PORT_DATA.clb], ebx ; set pdata->clb
  1380.  
  1381.         mov     eax, [port]
  1382.         mov     [edi + PORT_DATA.port], eax ; set pdata->port
  1383.         mov     eax, [portno]               ; set pdata->portno
  1384.         mov     [edi + PORT_DATA.portno], eax
  1385.  
  1386.         stdcall _memset, ebx, 0, 1024 ; zero out the command list
  1387.        
  1388.         ; FIS entry size = 256 bytes per port
  1389.         mov     eax, [phys_page1]
  1390.         add     eax, 1024
  1391.         mov     [esi + HBA_PORT.fis_base_l], eax
  1392.         mov     [esi + HBA_PORT.fis_base_h], 0
  1393.  
  1394.         mov     eax, [virt_page1]
  1395.         add     eax, 1024
  1396.         mov     [edi + PORT_DATA.fb], eax ; set pdata->fb
  1397.         stdcall _memset, eax, 0, 256 ; zero out
  1398.        
  1399.         stdcall alloc_pages, 32*(64 + 16 + 48 + PRDT_MAX_ENTRIES*16)/4096
  1400.         mov     [phys_page23], eax
  1401.         stdcall map_io_mem, eax, 32*(64 + 16 + 48 + PRDT_MAX_ENTRIES*16), PG_NOCACHE + PG_SWR
  1402.         mov     [virt_page23], eax
  1403.  
  1404.         ; Command table size = N*32 per port
  1405.         mov     edx, [edi + PORT_DATA.clb] ; cmdheader array base
  1406.         xor     ecx, ecx
  1407.  
  1408. .for1:
  1409.         cmp     ecx, 32
  1410.         jae     .for1_end
  1411.  
  1412.         mov     ebx, ecx
  1413.         shl     ebx, BSF sizeof.HBA_CMD_HDR
  1414.         add     ebx, edx ; ebx = cmdheader[ecx]
  1415.  
  1416.         mov     [ebx + HBA_CMD_HDR.prdtl], PRDT_MAX_ENTRIES ; prdt entries per command table
  1417.  
  1418.         ; bytes per command table = 64+16+48+PRDT_MAX_ENTRIES*16 = N
  1419.  
  1420.         push    edx
  1421.        
  1422.         ; cmdheader[ecx].ctba = phys_page23 + ecx*N
  1423.         mov     [ebx + HBA_CMD_HDR.ctba], ecx
  1424.         mov     edx, [ebx + HBA_CMD_HDR.ctba]
  1425.         imul    edx, (64+16+48+PRDT_MAX_ENTRIES*16) ; *= N
  1426.         mov     [ebx + HBA_CMD_HDR.ctba], edx
  1427.         mov     eax, [ebx + HBA_CMD_HDR.ctba]
  1428.         mov     edx, [phys_page23]
  1429.         add     [ebx + HBA_CMD_HDR.ctba], edx
  1430.  
  1431.         add     eax, [virt_page23]
  1432.         mov     [tmp], eax  ; tmp = virt_page23 + ecx*N
  1433.         lea     eax, [ecx*4 + edi + PORT_DATA.ctba_arr] ; eax = pdata->ctba_arr[ecx]
  1434.         mov     edx, [tmp]
  1435.         mov     [eax], edx  ; pdata->ctba_arr[ecx] = virt_page23 + ecx*N
  1436.  
  1437.         pop     edx
  1438.  
  1439.         mov     [ebx + HBA_CMD_HDR.ctbau], 0
  1440.         stdcall _memset, [eax], 0, 64+16+48+PRDT_MAX_ENTRIES*16 ; zero out
  1441.  
  1442.         inc     ecx
  1443.         jmp     .for1
  1444. .for1_end:
  1445.        
  1446.         mov     eax, [port]
  1447.         call    ahci_start_cmd
  1448.  
  1449.         DEBUGF  1, "End rebasing port %u\n", [portno]
  1450.         popad
  1451.         ret    
  1452. endp
  1453.  
  1454. ; ----------------------------------------------------------- ; TODO check
  1455. ; Find a free command list slot
  1456. ; in: pdata - address of HBA_PORT structure
  1457. ; out: eax - if not found -1, else slot index
  1458. proc ahci_find_cmdslot stdcall, pdata: dword
  1459.         push    ebx ecx edx esi
  1460.         mov     esi, [pdata]
  1461.         mov     eax, [esi + PORT_DATA.port]
  1462.  
  1463.         ; If not set in SACT and CI, the slot is free
  1464.         mov     ebx, [eax + HBA_PORT.sata_active]
  1465.         or      ebx, [eax + HBA_PORT.command_issue] ; ebx = slots
  1466.  
  1467.         mov     esi, [esi + PORT_DATA.ctr_ptr]
  1468.         mov     esi, [esi + AHCI_CTR.abar]
  1469.         mov     edx, [esi + HBA_MEM.cap]
  1470.         shr     edx, 8
  1471.         and     edx, 0xf
  1472.         ; DEBUGF  1, "Number of Command Slots on each port = %u\n", edx
  1473.         xor     ecx, ecx
  1474. .for1:
  1475.         cmp     ecx, edx
  1476.         jae     .for1_end
  1477.  
  1478.         ; if ((slots&1) == 0) return i;
  1479.         bt      ebx, 0
  1480.         jc      .cont1
  1481.  
  1482.         mov     eax, ecx
  1483.         jmp     .ret
  1484.  
  1485. .cont1:
  1486.         shr     ebx, 1
  1487.         inc     ecx
  1488.         jmp     .for1
  1489. .for1_end:
  1490.         DEBUGF  1, "Cannot find free command list entry\n"
  1491.         mov     eax, -1
  1492. .ret:
  1493.         pop     esi edx ecx ebx
  1494.         ret
  1495. endp
  1496.  
  1497.  
  1498. proc _memset stdcall, dest:dword, val:byte, cnt:dword ; doesnt clobber any registers
  1499.         ;DEBUGF  DBG_INFO, "memset(%x, %u, %u)\n", [dest], [val], [cnt]
  1500.         push    eax ecx edi
  1501.         mov     edi, dword [dest]
  1502.         mov     al, byte [val]
  1503.         mov     ecx, dword [cnt]
  1504.         rep stosb  
  1505.         pop     edi ecx eax
  1506.         ret
  1507. endp
  1508.  
  1509. ; Swaps byte order in words
  1510. ; base - address of first word
  1511. ; len - how many words to swap bytes in
  1512. ; doesnt clobber any registers
  1513. proc swap_bytes_in_words stdcall, base: dword, len: dword
  1514.         push    eax ebx ecx
  1515.         xor     ecx, ecx
  1516.         mov     ebx, [base]
  1517. .loop:
  1518.         cmp     ecx, [len]
  1519.         jae     .loop_end
  1520.         mov     ax, word [ebx + ecx*2]
  1521.         xchg    ah, al
  1522.         mov     word [ebx + ecx*2], ax
  1523.         inc     ecx
  1524.         jmp     .loop
  1525. .loop_end:
  1526.         pop     ecx ebx eax
  1527.         ret
  1528. endp
  1529.