X-Git-Url: http://v3vee.org/palacios/gitweb/gitweb.cgi?a=blobdiff_plain;f=palacios%2Fsrc%2Fgeekos%2Fne2k.c;h=0b8039bbb6c2a877bcdb6299d46299c6d4e61555;hb=e70e95962c26832628d586e07f9cd1a2e1852d72;hp=3d50978818d5ba3a35127085d63de11f1497ebae;hpb=35f14e06594b9a285c0853ae9a748952d1fdff7f;p=palacios.git diff --git a/palacios/src/geekos/ne2k.c b/palacios/src/geekos/ne2k.c index 3d50978..0b8039b 100644 --- a/palacios/src/geekos/ne2k.c +++ b/palacios/src/geekos/ne2k.c @@ -1,19 +1,44 @@ +/* + * This file is part of the Palacios Virtual Machine Monitor developed + * by the V3VEE Project with funding from the United States National + * Science Foundation and the Department of Energy. + * + * The V3VEE Project is a joint project between Northwestern University + * and the University of New Mexico. You can find out more at + * http://www.v3vee.org + * + * Copyright (c) 2008, Matt Wojcik + * Copyright (c) 2008, Peter Kamm + * Copyright (c) 2008, The V3VEE Project + * All rights reserved. + * + * Author: Matt Wojcik + * Author: Peter Kamm + * + * This is free software. You are permitted to use, + * redistribute, and modify it as specified in the file "V3VEE_LICENSE". + */ + #include #include #include #include #include #include +#include +#include -#define DEBUG 0 +#define DEBUG 1 #define TX_START_BUFF 0x40 #define RX_START_BUFF 0x4c #define RX_END_BUFF 0x80 -uint_t next = (RX_START_BUFF << 8); +static uint_t next = (RX_START_BUFF << 8); static uint_t received = 0; static uint_t send_done = 1; +struct NE2K_REGS* regs; + struct callback { int (*packet_received)(struct NE2K_Packet_Info *info, uchar_t *packet); } callbacks; @@ -31,69 +56,9 @@ static void Dump_Registers() } #endif -static int NE2K_Transmit(struct NE2K_REGS *regs) -{ - while(!send_done); - send_done = 0; - - struct _CR * cr = (struct _CR*)&(regs->cr); - uint_t packet_size = 80; - regs->cr = 0x21; - 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); - - cr->rd = 0x01; // set remote DMA to 'remote read' - Out_Byte(NE2K_CR, regs->cr); - - regs->isr = 0x40; // clear and set Remote DMA high - Out_Byte(NE2K_ISR, regs->isr); - - Out_Byte(NE2K_RBCR0, packet_size); - Out_Byte(NE2K_RBCR1, 0x00); - - Out_Byte(NE2K_TBCR0, packet_size); - Out_Byte(NE2K_TBCR1, 0x00); - - Out_Byte(NE2K_RSAR0, 0x00); - Out_Byte(NE2K_RSAR1, 0x40); - - regs->cr = 0x16; - 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); - - /* 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 length and data; currently random 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)); - } - - //regs->isr = 0x40; - //Out_Byte(NE2K_ISR, regs->isr); /* Do we need this here? */ - - return 0; -} - 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); @@ -129,9 +94,9 @@ 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); @@ -222,7 +187,7 @@ int Init_Ne2k(int (*rcvd_fn)(struct NE2K_Packet_Info *info, uchar_t *packet)) Out_Byte(NE2K_CR, regs->cr); Dump_Registers(); - cr->ps = 0x10; + cr->ps = 0x02; Out_Byte(NE2K_CR, regs->cr); Dump_Registers(); @@ -232,13 +197,14 @@ int Init_Ne2k(int (*rcvd_fn)(struct NE2K_Packet_Info *info, uchar_t *packet)) Install_IRQ(NE2K_IRQ, NE2K_Interrupt_Handler); Enable_IRQ(NE2K_IRQ); - +#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 }; @@ -249,19 +215,103 @@ int Init_Ne2k(int (*rcvd_fn)(struct NE2K_Packet_Info *info, uchar_t *packet)) for(i = 0; i < 0; i++) { NE2K_Send(regs, src_addr, dest_addr, 0x01, data, size); } - +*/ //Free(data); // Why does this crash? return 0; } +/* + * 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) +{ + 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); + 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); + + 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, 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(struct NE2K_REGS *regs, uchar_t src[], uchar_t dest[], uint_t type, uchar_t *data, uint_t size) +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; - 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); @@ -271,10 +321,10 @@ int NE2K_Send(struct NE2K_REGS *regs, uchar_t src[], uchar_t dest[], uint_t type 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); /* Set remote byte count registers */ @@ -285,12 +335,14 @@ int NE2K_Send(struct NE2K_REGS *regs, uchar_t src[], uchar_t dest[], uint_t type 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, 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 */ Out_Word(NE2K_CR + 0x10, (dest[1] << 8) | dest[0]); Out_Word(NE2K_CR + 0x10, (dest[3] << 8) | dest[2]); @@ -304,13 +356,18 @@ int NE2K_Send(struct NE2K_REGS *regs, uchar_t src[], uchar_t dest[], uint_t type /* Type */ Out_Word(NE2K_CR + 0x10, packet_size); + /* Packet data */ uint_t i; for(i = 0; i < size; i += 2) { Out_Word(NE2K_CR + 0x10, (*(data + i + 1) << 8) | *(data + i)); } + cr->txp = 0x1; /* Start transmission */ + Out_Byte(NE2K_CR, regs->cr); + return 0; } +#endif int NE2K_Receive() { @@ -331,10 +388,12 @@ int NE2K_Receive() 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 /* Get the location of the next packet */ next = data & 0xff00;