|
| 1 | +; ============================================================================= |
| 2 | +; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems |
| 3 | +; Copyright (C) 2008-2025 Return Infinity -- see LICENSE.TXT |
| 4 | +; |
| 5 | +; Elastic Network Adapter Driver |
| 6 | +; ============================================================================= |
| 7 | + |
| 8 | + |
| 9 | +; ----------------------------------------------------------------------------- |
| 10 | +; Initialize an ENA NIC |
| 11 | +; IN: RDX = Packed Bus address (as per syscalls/bus.asm) |
| 12 | +net_ena_init: |
| 13 | + push rdi |
| 14 | + push rsi |
| 15 | + push rdx |
| 16 | + push rcx |
| 17 | + push rax |
| 18 | + |
| 19 | + mov rdi, net_table |
| 20 | + xor eax, eax |
| 21 | + mov al, [os_net_icount] |
| 22 | + shl eax, 7 ; Quick multiply by 128 |
| 23 | + add rdi, rax |
| 24 | + |
| 25 | + mov ax, 0x0EC2 ; Driver tag for ena |
| 26 | + mov [rdi+nt_ID], ax |
| 27 | + |
| 28 | + ; Get the Base Memory Address of the device |
| 29 | + mov al, 0 ; Read BAR0 |
| 30 | + call os_bus_read_bar |
| 31 | + mov [rdi+nt_base], rax ; Save the base |
| 32 | + push rax ; Save the base for gathering the MAC later |
| 33 | + |
| 34 | + ; Set PCI Status/Command values |
| 35 | + mov dl, 0x01 ; Read Status/Command |
| 36 | + call os_bus_read |
| 37 | + bts eax, 10 ; Set Interrupt Disable |
| 38 | + bts eax, 2 ; Enable Bus Master |
| 39 | + bts eax, 1 ; Enable Memory Space |
| 40 | + call os_bus_write ; Write updated Status/Command |
| 41 | + |
| 42 | + ; Usually the MAC would be read from the device MMIO here but ENA works differently |
| 43 | + |
| 44 | + ; Set base addresses for TX and RX descriptors |
| 45 | + xor ecx, ecx |
| 46 | + mov cl, byte [os_net_icount] |
| 47 | + shl ecx, 15 |
| 48 | + |
| 49 | + mov rax, os_tx_desc |
| 50 | + add rax, rcx |
| 51 | + mov [rdi+nt_tx_desc], rax |
| 52 | + mov rax, os_rx_desc |
| 53 | + add rax, rcx |
| 54 | + mov [rdi+nt_rx_desc], rax |
| 55 | + |
| 56 | + ; Reset the device |
| 57 | + xor edx, edx |
| 58 | + mov dl, [os_net_icount] |
| 59 | + call net_ena_reset |
| 60 | + |
| 61 | + ; Store call addresses |
| 62 | + mov rax, net_ena_config |
| 63 | + mov [rdi+nt_config], rax |
| 64 | + mov rax, net_ena_transmit |
| 65 | + mov [rdi+nt_transmit], rax |
| 66 | + mov rax, net_ena_poll |
| 67 | + mov [rdi+nt_poll], rax |
| 68 | + |
| 69 | +net_ena_init_error: |
| 70 | + |
| 71 | + pop rax |
| 72 | + pop rcx |
| 73 | + pop rdx |
| 74 | + pop rsi |
| 75 | + pop rdi |
| 76 | + ret |
| 77 | +; ----------------------------------------------------------------------------- |
| 78 | + |
| 79 | + |
| 80 | +; ----------------------------------------------------------------------------- |
| 81 | +; net_ena_reset - Reset an ENA NIC |
| 82 | +; IN: RDX = Interface ID |
| 83 | +; OUT: Nothing, all registers preserved |
| 84 | +net_ena_reset: |
| 85 | + push rdi |
| 86 | + push rsi |
| 87 | + push rax |
| 88 | + |
| 89 | + ; Gather Base Address from net_table |
| 90 | + mov rsi, net_table |
| 91 | + xor eax, eax |
| 92 | + mov al, [os_net_icount] |
| 93 | + shl eax, 7 ; Quick multiply by 128 |
| 94 | + add rsi, rax |
| 95 | + add rsi, 16 |
| 96 | + mov rsi, [rsi] |
| 97 | + mov rdi, rsi |
| 98 | + |
| 99 | + ; Stop queues if they are running |
| 100 | + |
| 101 | + ; Check ENA_DEV_STS.READY |
| 102 | + mov eax, [rsi+ENA_DEV_STS] |
| 103 | + test eax, 1 |
| 104 | + ; poll bit with timeout |
| 105 | + |
| 106 | + ; Check versions |
| 107 | + mov eax, [rsi+ENA_VERSION] |
| 108 | + mov eax, [rsi+ENA_CONTROLLER_VERSION] |
| 109 | + |
| 110 | + ; Check capabilities |
| 111 | + mov eax, [rsi+ENA_CAPS] |
| 112 | + mov eax, [rsi+ENA_CAPS_EXT] |
| 113 | + |
| 114 | + ; Set device memory |
| 115 | + mov rax, 0x600000 |
| 116 | + mov [rsi+ENA_AQ_BASE_LO], eax |
| 117 | + shr rax, 32 |
| 118 | + mov [rsi+ENA_AQ_BASE_HI], eax |
| 119 | + mov rax, 0x610000 |
| 120 | + mov [rsi+ENA_ACQ_BASE_LO], eax |
| 121 | + shr rax, 32 |
| 122 | + mov [rsi+ENA_ACQ_BASE_HI], eax |
| 123 | + mov rax, 0x620000 |
| 124 | + mov [rsi+ENA_AENQ_BASE_LO], eax |
| 125 | + shr rax, 32 |
| 126 | + mov [rsi+ENA_AENQ_BASE_HI], eax |
| 127 | + |
| 128 | + ; Create Admin Queue |
| 129 | + ; Admin Submission Queue (AQ) |
| 130 | + ; Admin Completion Queue (ACQ) |
| 131 | + |
| 132 | + ; Check ENA_DEV_STS.READY |
| 133 | + |
| 134 | + ; Build an Admin command |
| 135 | + ; opcode ENA_ADMIN_GET_FEATURE = 0x0009 |
| 136 | + ; feat_id ENA_ADMIN_DEVICE_ATTRIBUTES = 1 |
| 137 | + ; Put it in the queue |
| 138 | + ; Wait for completion |
| 139 | + ; Check head has changed |
| 140 | + ; Verify command |
| 141 | + ; Verify status (ENA_ADMIN_SUCCESS) |
| 142 | + ; MAC Address at offset 0x0 of returned data |
| 143 | + |
| 144 | + pop rax |
| 145 | + pop rsi |
| 146 | + pop rdi |
| 147 | + ret |
| 148 | +; ----------------------------------------------------------------------------- |
| 149 | + |
| 150 | + |
| 151 | +; ----------------------------------------------------------------------------- |
| 152 | +; net_ena_config - |
| 153 | +; IN: RAX = Base address to store packets |
| 154 | +; RDX = Interface ID |
| 155 | +; OUT: Nothing |
| 156 | +net_ena_config: |
| 157 | + push rdi |
| 158 | + push rcx |
| 159 | + push rax |
| 160 | + |
| 161 | + pop rax |
| 162 | + pop rcx |
| 163 | + pop rdi |
| 164 | + ret |
| 165 | +; ----------------------------------------------------------------------------- |
| 166 | + |
| 167 | + |
| 168 | +; ----------------------------------------------------------------------------- |
| 169 | +; net_ena_transmit - Transmit a packet via an ENA NIC |
| 170 | +; IN: RSI = Location of packet |
| 171 | +; RDX = Interface ID |
| 172 | +; RCX = Length of packet |
| 173 | +; OUT: Nothing |
| 174 | +net_ena_transmit: |
| 175 | + push rdi |
| 176 | + push rbx |
| 177 | + push rax |
| 178 | + |
| 179 | + mov rdi, [rdx+nt_tx_desc] ; Transmit Descriptor Base Address |
| 180 | + |
| 181 | + pop rax |
| 182 | + pop rbx |
| 183 | + pop rdi |
| 184 | + ret |
| 185 | +; ----------------------------------------------------------------------------- |
| 186 | + |
| 187 | + |
| 188 | +; ----------------------------------------------------------------------------- |
| 189 | +; net_ena_poll - Polls the ENA NIC for a received packet |
| 190 | +; IN: RDX = Interface ID |
| 191 | +; OUT: RDI = Location of stored packet |
| 192 | +; RCX = Length of packet |
| 193 | +net_ena_poll: |
| 194 | + push rsi ; Used for the base MMIO of the NIC |
| 195 | + push rbx |
| 196 | + push rax |
| 197 | + |
| 198 | + mov rdi, [rdx+nt_rx_desc] |
| 199 | + mov rsi, [rdx+nt_base] ; Load the base MMIO of the NIC |
| 200 | + |
| 201 | +net_ena_poll_end: |
| 202 | + pop rax |
| 203 | + pop rbx |
| 204 | + pop rsi |
| 205 | + ret |
| 206 | +; ----------------------------------------------------------------------------- |
| 207 | + |
| 208 | + |
| 209 | +; ----------------------------------------------------------------------------- |
| 210 | +; net_ena_ack_int - Acknowledge an internal interrupt of the Intel 8254x NIC |
| 211 | +; IN: Nothing |
| 212 | +; OUT: RAX = Ethernet status |
| 213 | +;net_ena_ack_int: |
| 214 | +; push rdi |
| 215 | +; |
| 216 | +; pop rdi |
| 217 | +; ret |
| 218 | +; ----------------------------------------------------------------------------- |
| 219 | + |
| 220 | + |
| 221 | +; Register list (All registers should be accessed as 32-bit values) |
| 222 | + |
| 223 | +; General Control Registers |
| 224 | + |
| 225 | +ENA_VERSION equ 0x00 |
| 226 | +ENA_CONTROLLER_VERSION equ 0x04 |
| 227 | +ENA_CAPS equ 0x08 |
| 228 | +ENA_CAPS_EXT equ 0x0C |
| 229 | +ENA_AQ_BASE_LO equ 0x10 |
| 230 | +ENA_AQ_BASE_HI equ 0x14 |
| 231 | +ENA_AQ_CAPS equ 0x18 |
| 232 | +ENA_ACQ_BASE_LO equ 0x20 |
| 233 | +ENA_ACQ_BASE_HI equ 0x24 |
| 234 | +ENA_ACQ_CAPS equ 0x28 |
| 235 | +ENA_AQ_DB equ 0x2C |
| 236 | +ENA_ACQ_TAIL equ 0x30 |
| 237 | +ENA_AENQ_CAPS equ 0x34 |
| 238 | +ENA_AENQ_BASE_LO equ 0x38 |
| 239 | +ENA_AENQ_BASE_HI equ 0x3C |
| 240 | +ENA_AENQ_HEAD_DB equ 0x40 |
| 241 | +ENA_AENQ_TAIL equ 0x44 |
| 242 | +ENA_INTR_MASK equ 0x4C |
| 243 | +ENA_DEV_CTL equ 0x54 |
| 244 | +ENA_DEV_STS equ 0x58 |
| 245 | +ENA_MMIO_REG_READ equ 0x5C |
| 246 | +ENA_MMIO_RESP_LO equ 0x60 |
| 247 | +ENA_MMIO_RESP_HI equ 0x64 |
| 248 | +ENA_RSS_IND_ENTRY_UPDATE equ 0x68 |
| 249 | + |
| 250 | + |
| 251 | +; Register bits |
| 252 | + |
| 253 | + |
| 254 | + |
| 255 | +; ============================================================================= |
| 256 | +; EOF |
0 commit comments