X-Git-Url: http://v3vee.org/palacios/gitweb/gitweb.cgi?a=blobdiff_plain;f=palacios%2Fsrc%2Fgeekos%2Fne2k.c;h=bebca550f15b66156fcbcba343c341fff6ca0d79;hb=6eecf583b522147ef13faabb634562f6f23bb712;hp=94aa91bcd4987e1c6a3c6386c2f607816e74101b;hpb=a91de70b95f386ce0cb8226cb12966a79adb6c42;p=palacios.git diff --git a/palacios/src/geekos/ne2k.c b/palacios/src/geekos/ne2k.c index 94aa91b..bebca55 100644 --- a/palacios/src/geekos/ne2k.c +++ b/palacios/src/geekos/ne2k.c @@ -3,14 +3,26 @@ #include #include #include +#include +#include +#include #define DEBUG 1 -#define RX_START_BUFF 0x4c +#define TX_START_BUFF 0x40 +#define RX_START_BUFF 0x4c +#define RX_END_BUFF 0x80 +static uint_t next = (RX_START_BUFF << 8); static uint_t received = 0; static uint_t send_done = 1; -uint_t next = (RX_START_BUFF<<8); +struct NE2K_REGS* regs; + +struct callback { + int (*packet_received)(struct NE2K_Packet_Info *info, uchar_t *packet); +} callbacks; + +#if DEBUG static void Dump_Registers() { uint_t data; @@ -21,42 +33,58 @@ static void Dump_Registers() PrintBoth("\t%x: %x\n", NE2K_BASE_ADDR + i, data); } } +#endif static void NE2K_Interrupt_Handler(struct Interrupt_State * state) { + Begin_IRQ(state); PrintBoth("NIC Interrupt Occured!\n"); uchar_t isr_content = In_Byte(NE2K_ISR); - // Out_Byte(NE2K_ISR, 0xff); /* Clear all interrupts */ PrintBoth("Contents of ISR: %x\n", isr_content); - if(isr_content & 0x01) - { - NE2K_Receive(); - Out_Byte(NE2K_ISR, 0x01); -} + + if(isr_content & 0x01) /* A packet has been received. */ + { + uchar_t current; + Out_Byte(NE2K_CR, 0x4a); /* Page 1 */ + current = In_Byte(NE2K_CURR); + Out_Byte(NE2K_CR, 0x0a); /* Page 0 */ + NE2K_Receive(); + + /* When CURR equals BNRY, all packets in the receive ring buffer have been read, and + the packet received bit in the interrupt status register can be cleared. */ + if(current == In_Byte(NE2K_BNRY)) + Out_Byte(NE2K_ISR, 0x01); + } End_IRQ(state); - if(isr_content & 0x02) + if(isr_content & 0x02) /* A packet has been successfully transmitted. */ + { send_done = 1; + Out_Byte(NE2K_ISR, 0x02); + } + //Out_Byte(NE2K_ISR, 0xff); /* Clear all interrupts. */ } -int Init_Ne2k() +int Init_Ne2k(int (*rcvd_fn)(struct NE2K_Packet_Info *info, uchar_t *packet)) { + callbacks.packet_received = rcvd_fn; + PrintBoth("Initializing network card...\n"); - Out_Byte(NE2K_CR+0x1f, In_Byte(NE2K_CR+0x1f)); /* Reset? */ + Out_Byte(NE2K_CR+0x1f, In_Byte(NE2K_CR+0x1f)); /* Reset */ - struct NE2K_REGS* regs = Malloc(sizeof(struct NE2K_REGS)); + regs = Malloc(sizeof(struct NE2K_REGS)); struct _CR * cr = (struct _CR *)&(regs->cr); struct _RCR * rcr = (struct _RCR*)&(regs->rcr); struct _IMR * imr = (struct _IMR *)&(regs->imr); regs->cr = 0x21; - regs->dcr = 0x49; - regs->isr = 0xff; - regs->rcr = 0x20; - regs->tcr = 0x02; + regs->dcr = 0x49; /* Word-wide DMA transfer. */ + regs->isr = 0xff; /* Clear all interrupts. */ + regs->rcr = 0x20; /* Accept packets shorter than 64 bytes. */ + regs->tcr = 0x02; /* Internal loopback mode. */ Out_Byte(NE2K_CR, regs->cr); Out_Byte(NE2K_DCR, regs->dcr); @@ -65,26 +93,29 @@ int Init_Ne2k() Out_Byte(NE2K_TCR, regs->tcr); Out_Byte(NE2K_IMR, regs->imr); + /* Remote byte count registers. */ Out_Byte(NE2K_RBCR0, 0x00); Out_Byte(NE2K_RBCR1, 0x00); + /* Remote start address registers. */ Out_Byte(NE2K_RSAR0, 0x00); Out_Byte(NE2K_RSAR1, 0x00); - Out_Byte(NE2K_TPSR, 0x40); // Set TPSR - Out_Byte(NE2K_PSTART, RX_START_BUFF); // Set PSTART - Out_Byte(NE2K_BNRY, 0x59); // Set BNRY - Out_Byte(NE2K_PSTOP, 0x80); // Set PSTOP + Out_Byte(NE2K_TPSR, TX_START_BUFF); /* Transmit page start register */ + Out_Byte(NE2K_PSTART, RX_START_BUFF); /* Page start register */ + Out_Byte(NE2K_PSTOP, RX_END_BUFF); /* Page stop register */ + Out_Byte(NE2K_BNRY, RX_START_BUFF); /* Boundary register */ - cr->ps = 0x01; //switch to reg page 1 + cr->ps = 0x01; /* Switch to reg page 1. */ Out_Byte(NE2K_CR, regs->cr); + /* Current page register: points to first free page that can be used for packet reception. */ Out_Byte(NE2K_CURR, RX_START_BUFF); - cr->ps = 0x00; + cr->ps = 0x00; /* Switch to page 0 */ Out_Byte(NE2K_CR, regs->cr); - Out_Byte(NE2K_BNRY, RX_START_BUFF); - Out_Byte(NE2K_ISR, regs->isr); + /* Interrupt mask register: setting a bit to 1 enables the + corresponding interrupt in ISR. */ imr->prxe = 0x1; imr->ptxe = 0x1; imr->rxee = 0x1; @@ -93,7 +124,7 @@ int Init_Ne2k() imr->cnte = 0x1; Out_Byte(NE2K_IMR, regs->imr); - cr->ps = 0x01; //switch to reg page 1 + cr->ps = 0x01; /* Switch to reg page 1 */ Out_Byte(NE2K_CR, regs->cr); /* Set the physical address of the card to 52:54:00:12:34:58 */ @@ -104,7 +135,7 @@ int Init_Ne2k() Out_Byte(NE2K_CR+0x05, 0x34); Out_Byte(NE2K_CR+0x06, 0x58); - /* Accept all multicast packets */ + /* Set the multicast address register to all 1s; accepts all multicast packets */ uint_t i; for(i = 0x08; i <= 0x0f; i++) { Out_Byte(NE2K_CR+i, 0xff); @@ -120,51 +151,96 @@ int Init_Ne2k() rcr->ar = 0x1; rcr->ab = 0x1; rcr->am = 0x1; - rcr->pro = 0x1; // promiscuous mode, accept all packets + rcr->pro = 0x1; /* Promiscuous mode: accept all packets. */ rcr->mon = 0x0; Out_Byte(NE2K_RCR, regs->rcr); cr->sta = 0x1; // toggle start bit cr->stp = 0x0; Out_Byte(NE2K_CR, regs->cr); - + +#if DEBUG Dump_Registers(); - cr->ps = NE2K_PAGE1; + cr->ps = 0x01; Out_Byte(NE2K_CR, regs->cr); Dump_Registers(); - cr->ps = NE2K_PAGE2; + cr->ps = 0x02; Out_Byte(NE2K_CR, regs->cr); Dump_Registers(); - cr->ps = NE2K_PAGE0; + cr->ps = 0x00; Out_Byte(NE2K_CR, regs->cr); - - // Reset? -// Out_Byte(NE2K_CR+0x1f, In_Byte(NE2K_CR+0x1f)); +#endif Install_IRQ(NE2K_IRQ, NE2K_Interrupt_Handler); Enable_IRQ(NE2K_IRQ); -/* - for(i = 0; i < 1; i++) +#if 0 + for(i = 0; i < 0; i++) { NE2K_Transmit(regs); PrintBoth("Transmitting a packet\n"); } -*/ +#endif +/* + uchar_t src_addr[6] = { 0x52, 0x54, 0x00, 0x12, 0x34, 0x58 }; + uchar_t dest_addr[6] = { 0x52, 0x54, 0x00, 0x12, 0x34, 0x56 }; + + uint_t size = 64; + uchar_t *data = Malloc(size); + data = "This is a 64-byte string that will be used to test transmission."; + + for(i = 0; i < 0; i++) { + NE2K_Send(regs, src_addr, dest_addr, 0x01, data, size); + } +*/ + //Free(data); // Why does this crash? + return 0; } -int NE2K_Transmit(struct NE2K_REGS *regs) +/* + * This function is called when there is data in uip_buf that's ready to be sent. + * uip_arp_out() is used to translate the destination IP address to a MAC address. + * If the corresponding MAC address isn't in the cache, the packet is replaced with + * an ARP packet, which is sent out instead. The original packet will need to be + * retransmitted at some point in the future. + */ +int NE2K_Transmit(uint_t size) { - while(!send_done); - send_done = 0; + uip_arp_out(); + uchar_t *data; + data = Malloc(size); + + /* Based on example code from the uIP documentation... */ + if(size <= UIP_LLH_LEN + UIP_TCPIP_HLEN) { + memcpy(data, &uip_buf[0], size); + } else { + memcpy(data, &uip_buf[0], UIP_LLH_LEN + UIP_TCPIP_HLEN); + memcpy(data + UIP_LLH_LEN + UIP_TCPIP_HLEN, uip_appdata, size - UIP_TCPIP_HLEN - UIP_LLH_LEN); + } + /* Manually copy in the source MAC address for now. */ + uchar_t src_addr[6] = { 0x52, 0x54, 0x00, 0x12, 0x34, 0x58 }; + memcpy(data + 6, src_addr, 6); + if(*(data+12) != 0x08 || *(data+13) != 0x06) + { + /* This is not an ARP packet. Fill in te size of the packet manually. */ + *(data+12) = size & 0xff; + *(data+13) = (size >> 8) & 0xff; + } + + NE2K_Send_Packet(data, size); + Free(data); + return 0; +} + +int NE2K_Send_Packet(uchar_t *packet, uint_t size) +{ struct _CR * cr = (struct _CR*)&(regs->cr); - uint_t packet_size = 80; - regs->cr = 0x21; - cr->stp = 0x0; //toggle start on + regs->cr = 0x21; /* Turn off remote DMA, stop command */ + cr->stp = 0x0; /* toggle start on */ cr->sta = 0x1; Out_Byte(NE2K_CR, regs->cr); @@ -174,76 +250,136 @@ int NE2K_Transmit(struct NE2K_REGS *regs) Out_Byte(NE2K_RSAR0, 0x42); Out_Byte(NE2K_RSAR1, 0x00); - cr->rd = 0x01; // set remote DMA to 'remote read' + cr->rd = 0x01; /* set remote DMA to 'remote read' */ Out_Byte(NE2K_CR, regs->cr); - regs->isr = 0x40; // clear and set Remote DMA high + regs->isr = 0x40; /* clear 'remote DMA complete' interrupt */ Out_Byte(NE2K_ISR, regs->isr); - Out_Byte(NE2K_RBCR0, packet_size); + /* Set remote byte count registers */ + Out_Byte(NE2K_RBCR0, size & 0xff); + Out_Byte(NE2K_RBCR1, (size >> 8) & 0xff); + + /* Set transmit byte count registers. */ + Out_Byte(NE2K_TBCR0, size & 0xff); + Out_Byte(NE2K_TBCR1, (size >> 8) & 0xff); + + /* Set remote start address registers to the first page of the transmit ring buffer. */ + Out_Byte(NE2K_RSAR0, 0x00); + Out_Byte(NE2K_RSAR1, TX_START_BUFF); + + cr->rd = 0x02; /* Set remote DMA to 'remote write' */ + Out_Byte(NE2K_CR, regs->cr); + + /* Push the packet data to into the dataport */ + uint_t i; + for(i = 0; i < size; i += 2) { + Out_Word(NE2K_CR + 0x10, (*(packet + i + 1) << 8) | *(packet + i)); + } + + cr->txp = 0x1; /* Start transmission */ + Out_Byte(NE2K_CR, regs->cr); + + return 0; +} + +#if 1 +/* Assumes src and dest are arrays of 6 characters. */ +int NE2K_Send(uchar_t src[], uchar_t dest[], uint_t type, uchar_t *data, uint_t size) +{ + struct _CR * cr = (struct _CR*)&(regs->cr); + uint_t packet_size = size + 16; + regs->cr = 0x21; /* Turn off remote DMA, stop command */ + cr->stp = 0x0; /* toggle start on */ + cr->sta = 0x1; + Out_Byte(NE2K_CR, regs->cr); + + // Read-before-write bug fix? + Out_Byte(NE2K_RBCR0, 0x42); Out_Byte(NE2K_RBCR1, 0x00); + Out_Byte(NE2K_RSAR0, 0x42); + Out_Byte(NE2K_RSAR1, 0x00); - Out_Byte(NE2K_TBCR0, packet_size); - Out_Byte(NE2K_TBCR1, 0x00); + cr->rd = 0x01; /* set remote DMA to 'remote read' */ + Out_Byte(NE2K_CR, regs->cr); + + regs->isr = 0x40; /* clear 'remote DMA complete' interrupt */ + Out_Byte(NE2K_ISR, regs->isr); + + /* Set remote byte count registers */ + Out_Byte(NE2K_RBCR0, packet_size & 0xff); + Out_Byte(NE2K_RBCR1, (packet_size >> 8) & 0xff); + /* Set transmit byte count registers. */ + Out_Byte(NE2K_TBCR0, packet_size & 0xff); + Out_Byte(NE2K_TBCR1, (packet_size >> 8) & 0xff); + + /* Set remote start address registers to the first page of the transmit ring buffer. */ Out_Byte(NE2K_RSAR0, 0x00); - Out_Byte(NE2K_RSAR1, 0x40); + Out_Byte(NE2K_RSAR1, TX_START_BUFF); - regs->cr = 0x16; + cr->rd = 0x02; /* Set remote DMA to 'remote write' */ Out_Byte(NE2K_CR, regs->cr); - /* Begin pushing the packet into the dataport (located at 0x10 from the base address) */ - /* Destination address = 52:54:00:12:34:56 */ - Out_Word(NE2K_CR+0x10, 0x5452); - Out_Word(NE2K_CR+0x10, 0x1200); - Out_Word(NE2K_CR+0x10, 0x5634); + /* Begin pushing the packet into the dataport (located at 0x10 from the base address). */ + /* Destination Address */ + Out_Word(NE2K_CR + 0x10, (dest[1] << 8) | dest[0]); + Out_Word(NE2K_CR + 0x10, (dest[3] << 8) | dest[2]); + Out_Word(NE2K_CR + 0x10, (dest[5] << 8) | dest[4]); + + /* Source Address */ + Out_Word(NE2K_CR + 0x10, (src[1] << 8) | src[0]); + Out_Word(NE2K_CR + 0x10, (src[3] << 8) | src[2]); + Out_Word(NE2K_CR + 0x10, (src[5] << 8) | src[4]); - /* Source address = 52:54:00:12:34:58 */ - Out_Word(NE2K_CR+0x10, 0x5452); - Out_Word(NE2K_CR+0x10, 0x1200); - Out_Word(NE2K_CR+0x10, 0x5834); + /* Type */ + Out_Word(NE2K_CR + 0x10, packet_size); - /* Type length and data; currently random data */ + /* Packet data */ uint_t i; - uint_t n = 0; - for(i = 1; i <= packet_size/2-12; i++, n+=2) { - //Out_Word(NE2K_CR+0x10, 0x0f0b); - Out_Word(NE2K_CR+0x10, (n<<8) | (n+1)); + for(i = 0; i < size; i += 2) { + Out_Word(NE2K_CR + 0x10, (*(data + i + 1) << 8) | *(data + i)); } - //regs->isr = 0x40; - //Out_Byte(NE2K_ISR, regs->isr); /* Do we need this here? */ + cr->txp = 0x1; /* Start transmission */ + Out_Byte(NE2K_CR, regs->cr); return 0; } +#endif int NE2K_Receive() { PrintBoth("Packet Received\n"); -// uint_t packet_size = 80; - Out_Byte(NE2K_CR, 0x22); - - Out_Byte(NE2K_RBCR1, 0x00); -// Out_Byte(NE2K_RBCR0, 0x60); - -// Out_Byte(NE2K_RSAR0, 0x42); - Out_Byte(NE2K_RSAR1, next >> 8); + /* Set RSAR to the start address of the received packet. */ Out_Byte(NE2K_RSAR0, next & 0xff); + Out_Byte(NE2K_RSAR1, next >> 8); Out_Byte(NE2K_CR, 0x0a); + /* + * A four byte header is added to the beginning of each received packet by the NIC. + * The first byte is the location of the next packet in the ring buffer. + * The second byte is the receive status code. + * The third and fourth bytes are the size of the packet. + */ + uint_t i; uint_t data; - PrintBoth("\nPacket data:\n\t"); - data = In_Word(NE2K_CR + 0x10); + +#if DEBUG + PrintBoth("\nPacket data:\n\t"); PrintBoth("%x ", data); +#endif - /* The first byte is the page number where the next packet in the ring buffer is stored */ + /* Get the location of the next packet */ next = data & 0xff00; + /* Retrieve the packet size from the header, and store it in RBCR. */ uint_t packet_size = In_Word(NE2K_CR + 0x10) - 4; + uchar_t *packet = Malloc(packet_size); Out_Byte(NE2K_RBCR0, packet_size & 0xff); Out_Byte(NE2K_RBCR1, (packet_size>>8) & 0xff); @@ -251,19 +387,17 @@ int NE2K_Receive() PrintBoth("packetsize = %x\n\t", packet_size); #endif - for(i = 2; i < packet_size; i+=2) { + /* Copy the received packet over from the ring buffer. */ + for(i = 0; i < packet_size; i+=2) { data = In_Word(NE2K_CR + 0x10); - PrintBoth("%x ", data); - + *(packet + i) = data & 0x00ff; + *(packet + i + 1) = (data & 0xff00) >> 8; #if 0 PrintBoth("BNRY = %x\n", In_Byte(NE2K_BNRY)); Out_Byte(NE2K_CR, 0x4a); PrintBoth("CURR = %x\n", In_Byte(NE2K_CURR)); Out_Byte(NE2K_CR, 0x0a); #endif - - if(!(i%10)) - PrintBoth("\n\t"); } //Out_Byte(NE2K_RBCR0, (In_Byte(NE2K_RBCR0))-2); @@ -272,11 +406,21 @@ int NE2K_Receive() PrintBoth("\n%d packets have been received", ++received); PrintBoth("\n\n"); - Out_Byte(NE2K_ISR, 0x40); + Out_Byte(NE2K_ISR, 0x40); /* Clear the remote DMA complete interrupt. */ /* The BNRY register stores the location of the first packet that hasn't been read yet */ Out_Byte(NE2K_BNRY, next >> 8); + struct NE2K_Packet_Info *info = Malloc(sizeof(struct NE2K_Packet_Info)); + info->size = packet_size; + info->status = 0; + memcpy(info->dest, packet, 6); + memcpy(info->src, packet + 6, 6); + callbacks.packet_received(info, packet); + return 0; } + + +