luajitos

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs

rtl8139.c (12702B)


      1 /* RTL8139 Network Card Driver */
      2 #include "rtl8139.h"
      3 #include "terminal.h"
      4 #include <stdint.h>
      5 #include <string.h>
      6 #include <lauxlib.h>
      7 
      8 /* RTL8139 PCI Configuration */
      9 #define RTL8139_VENDOR_ID 0x10EC
     10 #define RTL8139_DEVICE_ID 0x8139
     11 
     12 /* RTL8139 Register Offsets */
     13 #define RTL8139_MAC0       0x00  /* MAC address */
     14 #define RTL8139_MAR0       0x08  /* Multicast filter */
     15 #define RTL8139_TXSTATUS0  0x10  /* Transmit status (4 TXDs) */
     16 #define RTL8139_TXADDR0    0x20  /* Transmit address (4 TXDs) */
     17 #define RTL8139_RXBUF      0x30  /* Receive buffer start address */
     18 #define RTL8139_RXEARLYCNT 0x34  /* Early RX byte count */
     19 #define RTL8139_RXEARLYSTATUS 0x36  /* Early RX status */
     20 #define RTL8139_CHIPCMD    0x37  /* Command register */
     21 #define RTL8139_RXBUFTAIL  0x38  /* Current address of packet read */
     22 #define RTL8139_RXBUFHEAD  0x3A  /* Current buffer address */
     23 #define RTL8139_INTRMASK   0x3C  /* Interrupt mask */
     24 #define RTL8139_INTRSTATUS 0x3E  /* Interrupt status */
     25 #define RTL8139_TXCONFIG   0x40  /* TX config */
     26 #define RTL8139_RXCONFIG   0x44  /* RX config */
     27 #define RTL8139_TIMER      0x48  /* Timer */
     28 #define RTL8139_RXMISSED   0x4C  /* Missed packet counter */
     29 #define RTL8139_CFG9346    0x50  /* 93C46 command register */
     30 #define RTL8139_CONFIG0    0x51  /* Configuration 0 */
     31 #define RTL8139_CONFIG1    0x52  /* Configuration 1 */
     32 #define RTL8139_MSR        0x58  /* Media status register */
     33 #define RTL8139_CONFIG3    0x59  /* Configuration 3 */
     34 #define RTL8139_CONFIG4    0x5A  /* Configuration 4 */
     35 #define RTL8139_MULINT     0x5C  /* Multiple interrupt select */
     36 #define RTL8139_RERID      0x5E  /* PCI revision ID */
     37 #define RTL8139_TSAD       0x60  /* Transmit status of all descriptors */
     38 #define RTL8139_BMCR       0x62  /* Basic mode control register */
     39 #define RTL8139_BMSR       0x64  /* Basic mode status register */
     40 
     41 /* Command register bits */
     42 #define RTL8139_CMD_RESET  0x10
     43 #define RTL8139_CMD_RX_ENABLE 0x08
     44 #define RTL8139_CMD_TX_ENABLE 0x04
     45 #define RTL8139_CMD_BUF_EMPTY 0x01
     46 
     47 /* Interrupt status/mask bits */
     48 #define RTL8139_INT_PCIERR    0x8000  /* PCI error */
     49 #define RTL8139_INT_TIMEOUT   0x4000  /* Timeout */
     50 #define RTL8139_INT_RXFIFO_OVERFLOW 0x0040  /* RX FIFO overflow */
     51 #define RTL8139_INT_RXBUF_OVERFLOW 0x0010  /* RX buffer overflow */
     52 #define RTL8139_INT_TX_OK     0x0004  /* Transmit OK */
     53 #define RTL8139_INT_RX_OK     0x0001  /* Receive OK */
     54 
     55 /* RX Config bits */
     56 #define RTL8139_RXCFG_ACCEPT_PHYS_MATCH 0x00000001
     57 #define RTL8139_RXCFG_ACCEPT_PHYS_MULTICAST 0x00000002
     58 #define RTL8139_RXCFG_ACCEPT_BROADCAST 0x00000008
     59 #define RTL8139_RXCFG_ACCEPT_ALL_PHYS 0x00000001
     60 #define RTL8139_RXCFG_WRAP 0x00000080
     61 #define RTL8139_RXCFG_DMA_UNLIMITED 0x00000700
     62 #define RTL8139_RXCFG_RBLEN_8K 0x00000000
     63 #define RTL8139_RXCFG_RBLEN_16K 0x00000800
     64 #define RTL8139_RXCFG_RBLEN_32K 0x00001000
     65 #define RTL8139_RXCFG_RBLEN_64K 0x00001800
     66 
     67 /* TX Config bits */
     68 #define RTL8139_TXCFG_DMA_UNLIMITED 0x00000700
     69 #define RTL8139_TXCFG_RETRY_COUNT 0x000F0000
     70 
     71 /* Buffer sizes */
     72 #define RTL8139_RX_BUF_SIZE (8192 + 16 + 1500)  /* 8KB + header + MTU */
     73 #define RTL8139_TX_BUF_SIZE 1536
     74 
     75 /* I/O port functions */
     76 static inline void outb(uint16_t port, uint8_t val) {
     77     __asm__ volatile ("outb %0, %1" : : "a"(val), "Nd"(port));
     78 }
     79 
     80 static inline uint8_t inb(uint16_t port) {
     81     uint8_t ret;
     82     __asm__ volatile ("inb %1, %0" : "=a"(ret) : "Nd"(port));
     83     return ret;
     84 }
     85 
     86 static inline void outw(uint16_t port, uint16_t val) {
     87     __asm__ volatile ("outw %0, %1" : : "a"(val), "Nd"(port));
     88 }
     89 
     90 static inline uint16_t inw(uint16_t port) {
     91     uint16_t ret;
     92     __asm__ volatile ("inw %1, %0" : "=a"(ret) : "Nd"(port));
     93     return ret;
     94 }
     95 
     96 static inline void outl(uint16_t port, uint32_t val) {
     97     __asm__ volatile ("outl %0, %1" : : "a"(val), "Nd"(port));
     98 }
     99 
    100 static inline uint32_t inl(uint16_t port) {
    101     uint32_t ret;
    102     __asm__ volatile ("inl %1, %0" : "=a"(ret) : "Nd"(port));
    103     return ret;
    104 }
    105 
    106 /* PCI Configuration Space */
    107 #define PCI_CONFIG_ADDRESS 0xCF8
    108 #define PCI_CONFIG_DATA    0xCFC
    109 
    110 static uint32_t pci_read_config(uint8_t bus, uint8_t slot, uint8_t func, uint8_t offset) {
    111     uint32_t address = (uint32_t)(
    112         (1 << 31) |           /* Enable bit */
    113         (bus << 16) |
    114         (slot << 11) |
    115         (func << 8) |
    116         (offset & 0xFC)
    117     );
    118     outl(PCI_CONFIG_ADDRESS, address);
    119     return inl(PCI_CONFIG_DATA);
    120 }
    121 
    122 static void pci_write_config(uint8_t bus, uint8_t slot, uint8_t func, uint8_t offset, uint32_t value) {
    123     uint32_t address = (uint32_t)(
    124         (1 << 31) |
    125         (bus << 16) |
    126         (slot << 11) |
    127         (func << 8) |
    128         (offset & 0xFC)
    129     );
    130     outl(PCI_CONFIG_ADDRESS, address);
    131     outl(PCI_CONFIG_DATA, value);
    132 }
    133 
    134 /* RTL8139 State */
    135 static struct {
    136     uint16_t io_base;
    137     uint8_t mac_address[6];
    138     uint8_t* rx_buffer;
    139     uint8_t* tx_buffer[4];
    140     int current_tx_desc;
    141     uint16_t rx_buffer_offset;
    142     int initialized;
    143 } rtl8139_state = {0};
    144 
    145 /* Find RTL8139 on PCI bus */
    146 static int rtl8139_find_device(void) {
    147     terminal_writestring("Scanning PCI bus for RTL8139...\n");
    148 
    149     /* Scan PCI bus 0, slots 0-31 */
    150     for (uint8_t slot = 0; slot < 32; slot++) {
    151         uint32_t vendor_device = pci_read_config(0, slot, 0, 0x00);
    152 
    153         /* Skip if no device */
    154         if (vendor_device == 0xFFFFFFFF || vendor_device == 0x00000000) {
    155             continue;
    156         }
    157 
    158         uint16_t vendor_id = vendor_device & 0xFFFF;
    159         uint16_t device_id = (vendor_device >> 16) & 0xFFFF;
    160 
    161         /* Check for RTL8139 */
    162         if (vendor_id == RTL8139_VENDOR_ID && device_id == RTL8139_DEVICE_ID) {
    163             terminal_writestring("Found RTL8139\n");
    164 
    165             /* Get I/O base address from BAR0 */
    166             uint32_t bar0 = pci_read_config(0, slot, 0, 0x10);
    167             rtl8139_state.io_base = bar0 & 0xFFFC;  /* Mask off I/O space bit */
    168 
    169             terminal_writestring("I/O Base configured\n");
    170 
    171             /* Enable bus mastering and I/O space */
    172             uint32_t command = pci_read_config(0, slot, 0, 0x04);
    173             command |= 0x05;  /* Enable I/O space (bit 0) and bus mastering (bit 2) */
    174             pci_write_config(0, slot, 0, 0x04, command);
    175 
    176             return 1;
    177         }
    178     }
    179 
    180     terminal_writestring("RTL8139 not found on PCI bus\n");
    181     return 0;
    182 }
    183 
    184 /* Allocate memory for buffers */
    185 extern void* malloc(size_t size);
    186 
    187 /* Initialize RTL8139 */
    188 int rtl8139_init(void) {
    189     terminal_writestring("Initializing RTL8139 network card...\n");
    190 
    191     /* Find device on PCI bus */
    192     if (!rtl8139_find_device()) {
    193         return -1;
    194     }
    195 
    196     uint16_t io = rtl8139_state.io_base;
    197 
    198     /* Power on */
    199     outb(io + RTL8139_CONFIG1, 0x00);
    200 
    201     /* Software reset */
    202     terminal_writestring("Resetting RTL8139...\n");
    203     outb(io + RTL8139_CHIPCMD, RTL8139_CMD_RESET);
    204 
    205     /* Wait for reset to complete */
    206     int timeout = 1000000;
    207     while ((inb(io + RTL8139_CHIPCMD) & RTL8139_CMD_RESET) && timeout--) {
    208         /* Busy wait */
    209     }
    210 
    211     if (timeout <= 0) {
    212         terminal_writestring("RTL8139 reset timeout!\n");
    213         return -1;
    214     }
    215 
    216     terminal_writestring("Reset complete\n");
    217 
    218     /* Read MAC address */
    219     for (int i = 0; i < 6; i++) {
    220         rtl8139_state.mac_address[i] = inb(io + RTL8139_MAC0 + i);
    221     }
    222 
    223     terminal_writestring("MAC Address read successfully\n");
    224 
    225     /* Allocate receive buffer (must be physically contiguous) */
    226     rtl8139_state.rx_buffer = (uint8_t*)malloc(RTL8139_RX_BUF_SIZE + 16);
    227     if (!rtl8139_state.rx_buffer) {
    228         terminal_writestring("Failed to allocate RX buffer\n");
    229         return -1;
    230     }
    231 
    232     /* Align to 4-byte boundary */
    233     uint32_t rx_phys = (uint32_t)rtl8139_state.rx_buffer;
    234     rx_phys = (rx_phys + 3) & ~3;
    235     rtl8139_state.rx_buffer = (uint8_t*)rx_phys;
    236 
    237     /* Allocate transmit buffers */
    238     for (int i = 0; i < 4; i++) {
    239         rtl8139_state.tx_buffer[i] = (uint8_t*)malloc(RTL8139_TX_BUF_SIZE);
    240         if (!rtl8139_state.tx_buffer[i]) {
    241             terminal_writestring("Failed to allocate TX buffer\n");
    242             return -1;
    243         }
    244     }
    245 
    246     /* Set receive buffer address */
    247     outl(io + RTL8139_RXBUF, (uint32_t)rtl8139_state.rx_buffer);
    248 
    249     /* Set IMR + ISR (enable all interrupts) */
    250     outw(io + RTL8139_INTRMASK, 0x0005);  /* RX OK + TX OK */
    251 
    252     /* Configure RX: accept broadcast, multicast, and physical match packets */
    253     uint32_t rx_config = RTL8139_RXCFG_ACCEPT_BROADCAST |
    254                         RTL8139_RXCFG_ACCEPT_PHYS_MATCH |
    255                         RTL8139_RXCFG_ACCEPT_PHYS_MULTICAST |
    256                         RTL8139_RXCFG_WRAP |
    257                         RTL8139_RXCFG_DMA_UNLIMITED |
    258                         RTL8139_RXCFG_RBLEN_8K;
    259     outl(io + RTL8139_RXCONFIG, rx_config);
    260 
    261     /* Configure TX */
    262     uint32_t tx_config = RTL8139_TXCFG_DMA_UNLIMITED | (0x03 << 24);  /* Max DMA burst, default retry */
    263     outl(io + RTL8139_TXCONFIG, tx_config);
    264 
    265     /* Enable RX and TX */
    266     outb(io + RTL8139_CHIPCMD, RTL8139_CMD_RX_ENABLE | RTL8139_CMD_TX_ENABLE);
    267 
    268     rtl8139_state.current_tx_desc = 0;
    269     rtl8139_state.rx_buffer_offset = 0;
    270     rtl8139_state.initialized = 1;
    271 
    272     terminal_writestring("RTL8139 initialized successfully!\n");
    273     return 0;
    274 }
    275 
    276 /* Send packet */
    277 int rtl8139_send(const uint8_t* data, uint16_t length) {
    278     if (!rtl8139_state.initialized) {
    279         return -1;
    280     }
    281 
    282     if (length > RTL8139_TX_BUF_SIZE - 4) {
    283         return -1;  /* Packet too large */
    284     }
    285 
    286     uint16_t io = rtl8139_state.io_base;
    287     int desc = rtl8139_state.current_tx_desc;
    288 
    289     /* Copy data to TX buffer */
    290     memcpy(rtl8139_state.tx_buffer[desc], data, length);
    291 
    292     /* Set TX address */
    293     outl(io + RTL8139_TXADDR0 + (desc * 4), (uint32_t)rtl8139_state.tx_buffer[desc]);
    294 
    295     /* Set TX status (clears OWN bit and sets length) */
    296     outl(io + RTL8139_TXSTATUS0 + (desc * 4), length);
    297 
    298     /* Move to next descriptor */
    299     rtl8139_state.current_tx_desc = (desc + 1) % 4;
    300 
    301     return length;
    302 }
    303 
    304 /* Receive packet */
    305 int rtl8139_receive(uint8_t* buffer, uint16_t max_length) {
    306     if (!rtl8139_state.initialized) {
    307         return -1;
    308     }
    309 
    310     uint16_t io = rtl8139_state.io_base;
    311 
    312     /* Check if RX buffer is empty */
    313     uint8_t cmd = inb(io + RTL8139_CHIPCMD);
    314     if (cmd & RTL8139_CMD_BUF_EMPTY) {
    315         return 0;  /* No packets */
    316     }
    317 
    318     /* Get current buffer offset */
    319     uint16_t offset = rtl8139_state.rx_buffer_offset;
    320 
    321     /* Read packet header (4 bytes) */
    322     uint16_t* header = (uint16_t*)(rtl8139_state.rx_buffer + offset);
    323     uint16_t status = header[0];
    324     uint16_t length = header[1];
    325 
    326     /* Check if packet is valid */
    327     if (!(status & 0x01)) {  /* ROK bit */
    328         return -1;  /* Bad packet */
    329     }
    330 
    331     /* Remove CRC from length */
    332     length -= 4;
    333 
    334     if (length > max_length) {
    335         length = max_length;
    336     }
    337 
    338     /* Copy packet data (skip 4-byte header) */
    339     memcpy(buffer, rtl8139_state.rx_buffer + offset + 4, length);
    340 
    341     /* Update offset (packet length + header + CRC, aligned to 4 bytes) */
    342     offset = (offset + length + 4 + 4 + 3) & ~3;
    343     offset %= RTL8139_RX_BUF_SIZE;
    344     rtl8139_state.rx_buffer_offset = offset;
    345 
    346     /* Update CAPR (current address of packet read) */
    347     outw(io + RTL8139_RXBUFTAIL, offset - 0x10);
    348 
    349     return length;
    350 }
    351 
    352 /* Get MAC address */
    353 void rtl8139_get_mac(uint8_t mac[6]) {
    354     if (!rtl8139_state.initialized) {
    355         memset(mac, 0, 6);
    356         return;
    357     }
    358     memcpy(mac, rtl8139_state.mac_address, 6);
    359 }
    360 
    361 /* Check if initialized */
    362 int rtl8139_is_initialized(void) {
    363     return rtl8139_state.initialized;
    364 }
    365 
    366 /* Lua binding: Initialize RTL8139 */
    367 int lua_rtl8139_init(lua_State* L) {
    368     int result = rtl8139_init();
    369     lua_pushboolean(L, result == 0);
    370     return 1;
    371 }
    372 
    373 /* Lua binding: Send packet */
    374 int lua_rtl8139_send(lua_State* L) {
    375     size_t length;
    376     const uint8_t* data = (const uint8_t*)luaL_checklstring(L, 1, &length);
    377 
    378     int result = rtl8139_send(data, (uint16_t)length);
    379     lua_pushinteger(L, result);
    380     return 1;
    381 }
    382 
    383 /* Lua binding: Receive packet */
    384 int lua_rtl8139_receive(lua_State* L) {
    385     static uint8_t buffer[2048];
    386     int length = rtl8139_receive(buffer, sizeof(buffer));
    387 
    388     if (length > 0) {
    389         lua_pushlstring(L, (const char*)buffer, length);
    390         return 1;
    391     } else if (length == 0) {
    392         lua_pushnil(L);  /* No packet */
    393         return 1;
    394     } else {
    395         lua_pushnil(L);  /* Error */
    396         return 1;
    397     }
    398 }
    399 
    400 /* Lua binding: Get MAC address */
    401 int lua_rtl8139_get_mac(lua_State* L) {
    402     uint8_t mac[6];
    403     rtl8139_get_mac(mac);
    404 
    405     lua_newtable(L);
    406     for (int i = 0; i < 6; i++) {
    407         lua_pushinteger(L, mac[i]);
    408         lua_rawseti(L, -2, i + 1);
    409     }
    410     return 1;
    411 }