From d86f301ecb8c773cde8afc646a8b7ae578b8a232 Mon Sep 17 00:00:00 2001 From: Andreas Baumann Date: Tue, 1 Aug 2017 16:23:09 +0200 Subject: we can receive network events, but the receive buffer remains empty this is because we must enable DMA transfering on the PCI bus (bus master enable) --- src/Makefile | 2 +- src/drivers/net/network.c | 20 +++-- src/drivers/net/network.h | 9 +++ src/drivers/net/rtl8139.c | 200 ++++++++++++++++++++++++++++++++++++++++++---- src/drivers/net/rtl8139.h | 4 + src/kernel/kernel.c | 16 ++++ 6 files changed, 230 insertions(+), 21 deletions(-) (limited to 'src') diff --git a/src/Makefile b/src/Makefile index 9222125..c71cfa8 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1,7 +1,7 @@ CC := gcc DEFINES = -DOS_ABAOS OPT := -O0 -INCLUDES = -I. -Ilibc -Ihardware -Idrivers -Idrivers/hdi -Idrivers/hdi/ps2 -Idrivers/video -Ikernel -Igui +INCLUDES = -I. -Ilibc -Ihardware -Idrivers -Idrivers/hdi -Idrivers/hdi/ps2 -Idrivers/video -Idrivers/net -Ikernel -Igui CFLAGS := -std=c99 -m32 -march=i486 -ffreestanding $(OPT) -g -Werror $(INCLUDES) $(DEFINES) LD := ld LDFLAGS := -lgcc diff --git a/src/drivers/net/network.c b/src/drivers/net/network.c index 46a3295..85bfdf2 100644 --- a/src/drivers/net/network.c +++ b/src/drivers/net/network.c @@ -7,11 +7,12 @@ static network_vtable_t const network_vtable = { { - driver_activate, - driver_deactivate, - driver_deinit, - driver_print_info - } + driver_activate, + driver_deactivate, + driver_deinit, + driver_print_info + }, + network_register_handler }; void network_init( network_t *network, interrupt_t *interrupt, void *context ) @@ -20,9 +21,18 @@ void network_init( network_t *network, interrupt_t *interrupt, void *context ) driver_init( (driver_t *)network, DRIVER_TYPE_NETWORK, interrupt, context ); + network->handler = NULL; + ((driver_t *)network)->vtable = (driver_vtable_t *)&network_vtable; } +void network_register_handler( void *obj, network_event_handler_t handler ) +{ + network_t *network = (network_t *)obj; + + network->handler = handler; +} + char *network_mac_to_string( network_mac_address_t mac, char *buf, size_t buflen ) { snprintf( buf, buflen, "%X:%X:%X:%X:%X:%X", diff --git a/src/drivers/net/network.h b/src/drivers/net/network.h index 8ec17cb..751ca40 100644 --- a/src/drivers/net/network.h +++ b/src/drivers/net/network.h @@ -10,17 +10,26 @@ typedef struct { uint8_t byte[6]; } network_mac_address_t; +typedef struct { +} network_event_t; + +typedef void (*network_event_handler_t)( network_event_t *event, void *context ); + typedef struct { driver_t base; network_mac_address_t mac_address; + network_event_handler_t handler; } network_t; typedef struct { driver_vtable_t base; + void (*register_handler)( void *obj, network_event_handler_t handler ); } network_vtable_t; void network_init( network_t *network, interrupt_t *interrupt, void *context ); +void network_register_handler( void *obj, network_event_handler_t handler ); + char *network_mac_to_string( network_mac_address_t mac, char *buf, size_t buflen ); #endif // NETWORK_H diff --git a/src/drivers/net/rtl8139.c b/src/drivers/net/rtl8139.c index 78a552a..e6898d4 100644 --- a/src/drivers/net/rtl8139.c +++ b/src/drivers/net/rtl8139.c @@ -8,27 +8,34 @@ static rtl8139_vtable_t const rtl8139_vtable = { { - rtl8139_activate, - rtl8139_deactivate, - rtl8139_deinit, - rtl8139_print_name, - rtl8139_print_info + { + rtl8139_activate, + rtl8139_deactivate, + rtl8139_deinit, + rtl8139_print_name, + rtl8139_print_info + }, + network_register_handler } }; // registers #define REG_MAC0 0x00 #define REG_RBSTART 0x30 +#define REG_ERSR 0x36 #define REG_CMD 0x37 +#define REG_CAPR 0x38 #define REG_IMR 0x3C #define REG_ISR 0x3E #define REG_TCR 0x40 #define REG_RCR 0x44 +#define REG_MPC 0x4C // commands for REG_CMD (command register) #define CMD_RESET 0x10 #define CMD_RECEIVER_ENABLE 0x08 #define CMD_TRANSMITTER_ENABLE 0x04 +#define CMD_BUFFER_EMPTY 0x01 // mask for reading the version in from the REG_TCR (transmit configuration register) #define TCR_MODEL_VERSION_AM 0x7C000000 @@ -52,7 +59,10 @@ static rtl8139_vtable_t const rtl8139_vtable = { // values for REG_RCR (receive configuration register) #define RCR_MXDMA_UNLIMITED 0x00000700 +#define RCR_RECEIVE_BUFFER_8K_16 0x00000000 +#define RCR_WRAP 0x00000080 #define RCR_ACCEPT_BROADCAST 0x00000008 +#define RCR_ACCEPT_MULTICAST 0x00000004 #define RCR_ACCEPT_PHYS_MATCH 0x00000002 // values for REG_IMR/REG_ISR (interrupt mask/status registers) @@ -73,8 +83,11 @@ static rtl8139_vtable_t const rtl8139_vtable = { ISR_RECEIVE_BUFFER_OVERFLOW | ISR_TRANSMIT_ERROR | ISR_TRANSMIT_OK | \ ISR_RECEIVE_ERROR | ISR_RECEIVE_OK -// for now we follow the guide line on OSDEV on the size of the receive buffer -#define RECEIVE_BUFFER_SIZE 8192 + 16 +// header +#define PACKET_HEADER_ROK 0x0001 + +// receive buffer, set to 8k + header (16) + wrap (2k) +#define RECEIVE_BUFFER_SIZE 8192 + 16 + 2048 void rtl8139_init( rtl8139_t *rtl8139, pci_device_descriptor_t *descriptor, interrupt_t *interrupt, void *context ) { @@ -90,11 +103,14 @@ void rtl8139_init( rtl8139_t *rtl8139, pci_device_descriptor_t *descriptor, inte port8_init( &rtl8139->MAC_port[i], descriptor->port_base + REG_MAC0 + i ); } port8_init( &rtl8139->CMD_port, descriptor->port_base + REG_CMD ); + port16_init( &rtl8139->CAPR_port, descriptor->port_base + REG_CAPR ); port32_init( &rtl8139->RBSTART_port, descriptor->port_base + REG_RBSTART ); + port8_init( &rtl8139->ERSR_port, descriptor->port_base + REG_ERSR ); port16_init( &rtl8139->IMR_port, descriptor->port_base + REG_IMR ); port16_init( &rtl8139->ISR_port, descriptor->port_base + REG_ISR ); port32_init( &rtl8139->TCR_port, descriptor->port_base + REG_TCR ); port32_init( &rtl8139->RCR_port, descriptor->port_base + REG_RCR ); + port32_init( &rtl8139->MPC_port, descriptor->port_base + REG_MPC ); // software reset, the CR_RESET bit remains high till the // reset is finished @@ -106,7 +122,8 @@ void rtl8139_init( rtl8139_t *rtl8139, pci_device_descriptor_t *descriptor, inte rtl8139->base.mac_address.byte[i] = port8_read( &rtl8139->MAC_port[i] ); } - // enable receiver and transmitter early + // enable receiver and transmitter early (TODO: lowlevel says as later as + // possible, Osdev and others say as early as possible) port8_write( &rtl8139->CMD_port, CMD_RECEIVER_ENABLE | CMD_TRANSMITTER_ENABLE ); // get model @@ -154,20 +171,27 @@ void rtl8139_init( rtl8139_t *rtl8139, pci_device_descriptor_t *descriptor, inte // initialize TCR/RCR (take Lowlevel suggestions: TCR = 0x03000700, RCR = 0x0000070a) port32_write( &rtl8139->TCR_port, TCR_IFG_STANDARD | TCR_MXDMA_2048 ); - port32_write( &rtl8139->RCR_port, RCR_MXDMA_UNLIMITED | RCR_ACCEPT_BROADCAST | RCR_ACCEPT_PHYS_MATCH ); + port32_write( &rtl8139->RCR_port, RCR_MXDMA_UNLIMITED | + RCR_RECEIVE_BUFFER_8K_16 | RCR_WRAP | + RCR_ACCEPT_BROADCAST | RCR_ACCEPT_MULTICAST | RCR_ACCEPT_PHYS_MATCH ); // allocate receive buffer and register it - rtl8139->receive_buffer = (uint8_t *)malloc( RECEIVE_BUFFER_SIZE ); + rtl8139->receive_buffer = (uint8_t *)aligned_alloc( 16, RECEIVE_BUFFER_SIZE + 16 ); + memset( rtl8139->receive_buffer, 0xFE, RECEIVE_BUFFER_SIZE + 16 ); port32_write( &rtl8139->RBSTART_port, (uint32_t)rtl8139->receive_buffer ); + rtl8139->receive_buffer_pos = 0; + + // reset missed packet counter + port32_write( &rtl8139->MPC_port, 0 ); + + interrupt_handler_init( &rtl8139->interrupt_handler, IRQ_BASE + descriptor->interrupt, interrupt, rtl8139_handle_interrupt, rtl8139 ); + interrupts_register_interrupt_handler( rtl8139->interrupt_handler ); // register interrupts we are interested in (we want all and // filter them in the interrupt handler), read ISR to clear // the current values (if there are bits set) port16_write( &rtl8139->IMR_port, ISR_ALL ); (void)port16_read( &rtl8139->ISR_port ); - - interrupt_handler_init( &rtl8139->interrupt_handler, IRQ_BASE + descriptor->interrupt, interrupt, rtl8139_handle_interrupt, rtl8139 ); - interrupts_register_interrupt_handler( rtl8139->interrupt_handler ); rtl8139_print_info( rtl8139 ); @@ -195,14 +219,158 @@ void rtl8139_deinit( void *obj ) free( rtl8139->receive_buffer ); } +static void handle_receive_packet( rtl8139_t *rtl8139 ) +{ + network_event_t event; + rtl8139->base.handler( &event, rtl8139 ); + + while( true ) { + uint8_t data = port8_read( &rtl8139->CMD_port ); + + // still data in the buffer + if( data & CMD_BUFFER_EMPTY ) { + break; + } + + uint8_t *buffer = rtl8139->receive_buffer + rtl8139->receive_buffer_pos; + +#ifdef DEBUG + uint16_t capr = port16_read( &rtl8139->CAPR_port ); + uint32_t rbstart = port32_read( &rtl8139->RBSTART_port ); + uint32_t mpc = port32_read( &rtl8139->MPC_port ); + uint8_t ersr = port8_read( &rtl8139->ERSR_port ); + printf( "rtl8139: ERSR: %X, RBSTART: %X, CAPR: %X, RBPOS: %X, MPC: %X\n", + ersr, rbstart, capr, rtl8139->receive_buffer_pos, mpc ); + printf( "rtl8139: " ); + for( int i = 0; i < 80; i++ ) { + printf( "%X ", rtl8139->receive_buffer[rtl8139->receive_buffer_pos+i] ); + } + puts( "" ); +#endif + + // kprintf("%s: rtl8139_rx() status %4.4x, size %4.4x, cur %4.4x\n", dev->name, rx_status, rx_size, cur_rx); + // kprintf("%s: Frame contents ", dev->name); + // for (i = 0; i < 70; i++) kprintf(" %2.2x", rx_ring[ring_offset + i]); + + + // packet header + uint16_t header = *( (uint16_t *)buffer ); +#ifdef DEBUG + printf( "rtl8139: rcv header %X\n", header ); +#endif + if( ( header & PACKET_HEADER_ROK ) == 0 ) { + printf( "rtl8139: illegal packet header, no ROK\n", header ); + break; + } + buffer += sizeof( uint16_t ); + + // buffer is 16-bit alligned + uint16_t len = *( (uint16_t *)buffer ); + buffer += sizeof( uint16_t ); +#ifdef DEBUG + printf( "rtl8139: rcv len: %d\n", len ); +#endif + + for( int i = 0; i < len; i++ ) { + } + + } + +#if 0 + + while (1) + { + + void* buffer = netcard->rx_buffer + netcard->rx_buffer_offset; + + uint16_t packet_header = *((uint16_t*) buffer); + buffer += 2; + + if ((packet_header & 1) == 0) { + DEBUG_MSG("Paketheader: Kein ROK.\n"); + break; + } + + // Die L�nge enth�lt die CRC-Pr�fsumme, nicht aber den Paketheader + uint16_t length = *((uint16_t*) buffer); + buffer += 2; + + /* + * RECEIVE_BUFFER_SIZE + printf("Empfangen: %d Bytes\n", length); + printf("netcard->rx_buffer_offset = %08x\n", netcard->rx_buffer_offset); + */ + /*int i; + for (i = 0; i < length; i++) { + printf("%02x ", ((char*) buffer)[i]); + } + printf("\n");*/ + + netcard->rx_buffer_offset += 4; + + if (length >= sizeof(struct eth_packet_header)) + { + uint8_t data[length - 4]; + if ((netcard->rx_buffer_offset + length - 4) >= RX_BUFFER_SIZE) { + // FIXME Beim Umbruch gehen Daten kaputt + memcpy(data, buffer, RX_BUFFER_SIZE - netcard->rx_buffer_offset); + memcpy( + data + RX_BUFFER_SIZE - netcard->rx_buffer_offset, + netcard->rx_buffer, + (length - 4) - (RX_BUFFER_SIZE - netcard->rx_buffer_offset) + ); + } else { + memcpy(data, buffer, length - 4); + } + + cdi_net_receive( + (struct cdi_net_device*) netcard, + data, + length - 4); + } + + // Den aktuellen Offset im Lesepuffer anpassen. Jedes Paket ist + // uint32_t-aligned, daher anschlie�end Aufrundung. + netcard->rx_buffer_offset += length; + netcard->rx_buffer_offset = (netcard->rx_buffer_offset + 3) & ~0x3; + + // �berl�ufe abfangen + netcard->rx_buffer_offset %= RX_BUFFER_SIZE; + + write_register_word(netcard, REG_CUR_READ_ADDR, + netcard->rx_buffer_offset - 0x10); + + + + } +#endif +} + uint32_t rtl8139_handle_interrupt( interrupt_handler_t *handler, uint32_t esp ) { rtl8139_t *rtl8139 = (rtl8139_t *)handler->driver; + uint16_t isr = port16_read( &rtl8139->ISR_port ); + //~ uint16_t reset_isr = 0; + + port16_write( &rtl8139->ISR_port, isr ); + #ifdef DEBUG - printf( "RTL8139 INTERRUPT\n" ); + printf( "rtl8139: INTERRUPT: %X\n", isr ); #endif + + if( isr & ISR_RECEIVE_OK ) { + // TODO: manual says, we should reset the ISR bit first, + // then go into a read loop? + handle_receive_packet( rtl8139 ); + + //~ reset_isr |= ISR_RECEIVE_OK; + } + + // reset interrupt lines when consumed + //~ port16_write( &rtl8139->ISR_port, reset_isr ); + return esp; } @@ -217,7 +385,9 @@ void rtl8139_print_info( void *obj ) char buf[20]; char buf2[30]; - snprintf( buf2, 30, "unknown submodel 0x%X", rtl8139->model_id ); + if( rtl8139->model == NULL ) { + snprintf( buf2, 30, "unknown submodel 0x%X", rtl8139->model_id ); + } network_mac_to_string( rtl8139->base.mac_address, buf, 20 ); printf( "rtl8139 NIC type %s\n at I/O base 0x%X, interrupt 0x%X, MAC: %s\n", ( rtl8139->model != NULL ) ? rtl8139->model : buf2, diff --git a/src/drivers/net/rtl8139.h b/src/drivers/net/rtl8139.h index 91a7495..58b2167 100644 --- a/src/drivers/net/rtl8139.h +++ b/src/drivers/net/rtl8139.h @@ -11,15 +11,19 @@ typedef struct { network_t base; port8_t MAC_port[NOF_MAC_REGISTERS]; port32_t RBSTART_port; + port8_t ERSR_port; port8_t CMD_port; + port16_t CAPR_port; port16_t IMR_port; port16_t ISR_port; port32_t TCR_port; port32_t RCR_port; + port32_t MPC_port; pci_device_descriptor_t pci_descriptor; uint32_t model_id; const char *model; uint8_t *receive_buffer; + uint16_t receive_buffer_pos; interrupt_handler_t interrupt_handler; } rtl8139_t; diff --git a/src/kernel/kernel.c b/src/kernel/kernel.c index c1f7cd1..486e04f 100644 --- a/src/kernel/kernel.c +++ b/src/kernel/kernel.c @@ -16,6 +16,7 @@ #include "video.h" #include "pci.h" #include "memorymanagement.h" +#include "network.h" #include "setjmp.h" @@ -35,6 +36,7 @@ static jmp_buf panic_jmp_buf; static void handle_keyboard_event( keyboard_event_t *event, void *context ); static void handle_mouse_event( mouse_event_t *event, void *context ); +static void handle_network_event( network_event_t *event, void *context ); typedef enum { MODE_TEXT, @@ -55,6 +57,7 @@ typedef struct { window_t window2; window_t window3; text_widget_t widget3; + network_t *network; } global_context_t; static global_context_t global_context; @@ -150,6 +153,14 @@ void kernel_main( void ) // TODO: also, what to do if there is more than one driver? global_context.video = (video_t *)driver_manager_find_driver( &global_context.driver_manager, DRIVER_TYPE_VIDEO ); + // network driver testing + global_context.network = (network_t *)driver_manager_find_driver( &global_context.driver_manager, DRIVER_TYPE_NETWORK ); + if( global_context.network == NULL ) { + puts( "No suitable network driver found" ); + } else { + ((network_vtable_t *)( global_context.network->base.vtable ))->register_handler( global_context.network, handle_network_event ); + } + puts( "Activating drivers" ); driver_manager_activate_all( &global_context.driver_manager ); @@ -438,3 +449,8 @@ void __stack_chk_fail( void ) // make gcc happy on noreturn does return for( ;; ); } + +void handle_network_event( network_event_t *event, void *context ) +{ + puts( "NETWORK EVENT" ); +} -- cgit v1.2.3-54-g00ecf