Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


added new copyright and license
[palacios.git] / palacios / src / geekos / ne2k.c
1 /*
2  * This file is part of the Palacios Virtual Machine Monitor developed
3  * by the V3VEE Project with funding from the United States National 
4  * Science Foundation and the Department of Energy.  
5  *
6  * The V3VEE Project is a joint project between Northwestern University
7  * and the University of New Mexico.  You can find out more at 
8  * http://www.v3vee.org
9  *
10  * Copyright (c) 2008, Matt Wojcik
11  * Copyright (c) 2008, Peter Kamm
12  * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org> 
13  * All rights reserved.
14  *
15  * Author: Matt Wojcik
16  * Author: Peter Kamm
17  *
18  * This is free software.  You are permitted to use,
19  * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
20  */
21
22 #include <geekos/ne2k.h>
23 #include <geekos/debug.h>
24 #include <geekos/io.h>
25 #include <geekos/irq.h>
26 #include <geekos/malloc.h>
27 #include <geekos/string.h>
28 #include <uip/uip.h>
29 #include <uip/uip_arp.h>
30
31 #define DEBUG 1
32 #define TX_START_BUFF   0x40
33 #define RX_START_BUFF   0x4c
34 #define RX_END_BUFF     0x80
35
36 static uint_t next = (RX_START_BUFF << 8);
37 static uint_t received = 0;
38 static uint_t send_done = 1;
39
40 struct NE2K_REGS* regs;
41
42 struct callback {
43   int (*packet_received)(struct NE2K_Packet_Info *info, uchar_t *packet);
44 } callbacks;
45
46 #if DEBUG
47 static void Dump_Registers()
48 {
49   uint_t data;
50   PrintBoth("Dumping NIC registers for page %x...\n", (In_Byte(NE2K_CR) & 0xc0) >> 6);
51   uint_t i = 0;
52   for(i = 0; i <= 0x0f; i += 0x01) {
53     data = In_Byte(NE2K_BASE_ADDR+i);
54     PrintBoth("\t%x: %x\n", NE2K_BASE_ADDR + i, data);
55   }
56 }
57 #endif
58
59 static void NE2K_Interrupt_Handler(struct Interrupt_State * state)
60 {
61
62   Begin_IRQ(state);
63   PrintBoth("NIC Interrupt Occured!\n");
64   uchar_t isr_content = In_Byte(NE2K_ISR);
65
66   PrintBoth("Contents of ISR: %x\n", isr_content);
67
68   if(isr_content & 0x01) /* A packet has been received. */
69   {
70         uchar_t current;
71         Out_Byte(NE2K_CR, 0x4a);        /* Page 1 */
72         current = In_Byte(NE2K_CURR);
73         Out_Byte(NE2K_CR, 0x0a);        /* Page 0 */
74         NE2K_Receive();
75
76         /* When CURR equals BNRY, all packets in the receive ring buffer have been read, and
77            the packet received bit in the interrupt status register can be cleared. */
78         if(current == In_Byte(NE2K_BNRY))
79           Out_Byte(NE2K_ISR, 0x01);
80   }
81
82   End_IRQ(state);
83   if(isr_content & 0x02) /* A packet has been successfully transmitted. */
84   {
85     send_done = 1;  
86     Out_Byte(NE2K_ISR, 0x02);
87   }
88
89   //Out_Byte(NE2K_ISR, 0xff); /* Clear all interrupts. */
90 }
91
92 int Init_Ne2k(int (*rcvd_fn)(struct NE2K_Packet_Info *info, uchar_t *packet))
93 {
94   callbacks.packet_received = rcvd_fn;
95
96   PrintBoth("Initializing network card...\n");
97   Out_Byte(NE2K_CR+0x1f, In_Byte(NE2K_CR+0x1f));  /* Reset */
98
99   regs = Malloc(sizeof(struct NE2K_REGS));
100   struct _CR * cr = (struct _CR *)&(regs->cr);
101   struct _RCR * rcr = (struct _RCR*)&(regs->rcr);
102   struct _IMR * imr = (struct _IMR *)&(regs->imr);
103
104   regs->cr = 0x21;
105   regs->dcr = 0x49; /* Word-wide DMA transfer. */
106   regs->isr = 0xff; /* Clear all interrupts. */
107   regs->rcr = 0x20; /* Accept packets shorter than 64 bytes. */
108   regs->tcr = 0x02; /* Internal loopback mode. */
109
110   Out_Byte(NE2K_CR, regs->cr);
111   Out_Byte(NE2K_DCR, regs->dcr);
112   Out_Byte(NE2K_ISR, regs->isr);
113   Out_Byte(NE2K_RCR, regs->rcr);
114   Out_Byte(NE2K_TCR, regs->tcr);
115   Out_Byte(NE2K_IMR, regs->imr);
116
117   /* Remote byte count registers. */
118   Out_Byte(NE2K_RBCR0, 0x00);
119   Out_Byte(NE2K_RBCR1, 0x00);
120   /* Remote start address registers. */
121   Out_Byte(NE2K_RSAR0, 0x00);
122   Out_Byte(NE2K_RSAR1, 0x00);
123
124   Out_Byte(NE2K_TPSR, TX_START_BUFF);           /* Transmit page start register */
125   Out_Byte(NE2K_PSTART, RX_START_BUFF);         /* Page start register */
126   Out_Byte(NE2K_PSTOP, RX_END_BUFF);                    /* Page stop register */
127   Out_Byte(NE2K_BNRY, RX_START_BUFF);           /* Boundary register */ 
128
129   cr->ps = 0x01; /* Switch to reg page 1. */
130   Out_Byte(NE2K_CR, regs->cr);
131   /* Current page register: points to first free page that can be used for packet reception. */
132   Out_Byte(NE2K_CURR, RX_START_BUFF);
133   cr->ps = 0x00; /* Switch to page 0 */
134
135   Out_Byte(NE2K_CR, regs->cr);
136   Out_Byte(NE2K_ISR, regs->isr);
137
138   /* Interrupt mask register: setting a bit to 1 enables the
139      corresponding interrupt in ISR. */
140   imr->prxe = 0x1;
141   imr->ptxe = 0x1;
142   imr->rxee = 0x1;
143   imr->txee = 0x1;
144   imr->ovwe = 0x1;
145   imr->cnte = 0x1;
146   Out_Byte(NE2K_IMR, regs->imr);
147
148   cr->ps = 0x01;  /* Switch to reg page 1 */
149   Out_Byte(NE2K_CR, regs->cr);
150
151   /* Set the physical address of the card to 52:54:00:12:34:58 */
152   Out_Byte(NE2K_CR+0x01, 0x52);
153   Out_Byte(NE2K_CR+0x02, 0x54);
154   Out_Byte(NE2K_CR+0x03, 0x00);
155   Out_Byte(NE2K_CR+0x04, 0x12);
156   Out_Byte(NE2K_CR+0x05, 0x34);
157   Out_Byte(NE2K_CR+0x06, 0x58);
158
159   /* Set the multicast address register to all 1s; accepts all multicast packets */
160   uint_t i;
161   for(i = 0x08; i <= 0x0f; i++) {
162     Out_Byte(NE2K_CR+i, 0xff);
163   }
164
165   regs->cr = 0x21;  //set CR to start value
166   Out_Byte(NE2K_CR, regs->cr);
167
168   regs->tcr = 0x00;
169   Out_Byte(NE2K_TCR, regs->tcr);
170
171   rcr->sep = 0x1;
172   rcr->ar = 0x1;
173   rcr->ab = 0x1;
174   rcr->am = 0x1;
175   rcr->pro = 0x1; /* Promiscuous mode: accept all packets. */
176   rcr->mon = 0x0;
177   Out_Byte(NE2K_RCR, regs->rcr);
178
179   cr->sta = 0x1;  // toggle start bit
180   cr->stp = 0x0;
181   Out_Byte(NE2K_CR, regs->cr);
182
183 #if DEBUG
184   Dump_Registers();
185
186   cr->ps = 0x01;
187   Out_Byte(NE2K_CR, regs->cr);
188   Dump_Registers();
189
190   cr->ps = 0x02;
191   Out_Byte(NE2K_CR, regs->cr);
192   Dump_Registers();
193
194   cr->ps = 0x00;
195   Out_Byte(NE2K_CR, regs->cr);
196 #endif
197
198   Install_IRQ(NE2K_IRQ, NE2K_Interrupt_Handler);
199   Enable_IRQ(NE2K_IRQ);
200 #if 0
201   for(i = 0; i < 0; i++)
202   {
203     NE2K_Transmit(regs);
204     PrintBoth("Transmitting a packet\n");
205   }
206 #endif
207 /*
208   uchar_t src_addr[6] = { 0x52, 0x54, 0x00, 0x12, 0x34, 0x58 };
209   uchar_t dest_addr[6] = { 0x52, 0x54, 0x00, 0x12, 0x34, 0x56 };
210
211   uint_t size = 64;
212   uchar_t *data = Malloc(size);
213   data = "This is a 64-byte string that will be used to test transmission.";
214
215   for(i = 0; i < 0; i++) {
216     NE2K_Send(regs, src_addr, dest_addr, 0x01, data, size);
217   }
218 */
219   //Free(data);  // Why does this crash?
220
221   return 0;
222 }
223
224 /* 
225  * This function is called when there is data in uip_buf that's ready to be sent.
226  * uip_arp_out() is used to translate the destination IP address to a MAC address.
227  * If the corresponding MAC address isn't in the cache, the packet is replaced with
228  * an ARP packet, which is sent out instead.  The original packet will need to be
229  * retransmitted at some point in the future.
230  */
231 int NE2K_Transmit(uint_t size)
232 {
233   uip_arp_out();
234   uchar_t *data;
235   data = Malloc(size);
236
237   /* Based on example code from the uIP documentation... */
238   if(size <= UIP_LLH_LEN + UIP_TCPIP_HLEN) {
239     memcpy(data, &uip_buf[0], size);
240   } else {
241     memcpy(data, &uip_buf[0], UIP_LLH_LEN + UIP_TCPIP_HLEN);
242     memcpy(data + UIP_LLH_LEN + UIP_TCPIP_HLEN, uip_appdata, size - UIP_TCPIP_HLEN - UIP_LLH_LEN);
243   }
244
245   /* Manually copy in the source MAC address for now. */
246   uchar_t src_addr[6] = { 0x52, 0x54, 0x00, 0x12, 0x34, 0x58 };
247   memcpy(data + 6, src_addr, 6);
248   if(*(data+12) != 0x08 || *(data+13) != 0x06)
249   {
250     /* This is not an ARP packet. Fill in te size of the packet manually. */
251     *(data+12) = size & 0xff;
252     *(data+13) = (size >> 8) & 0xff;
253   }
254
255   NE2K_Send_Packet(data, size);
256   Free(data);
257   return 0;
258 }
259
260 int NE2K_Send_Packet(uchar_t *packet, uint_t size)
261 {
262   struct _CR * cr = (struct _CR*)&(regs->cr);
263   regs->cr = 0x21; /* Turn off remote DMA, stop command */
264   cr->stp = 0x0;  /* toggle start on */
265   cr->sta = 0x1;
266   Out_Byte(NE2K_CR, regs->cr);
267   
268   // Read-before-write bug fix?
269   Out_Byte(NE2K_RBCR0, 0x42);
270   Out_Byte(NE2K_RBCR1, 0x00);
271   Out_Byte(NE2K_RSAR0, 0x42);
272   Out_Byte(NE2K_RSAR1, 0x00);
273
274   cr->rd = 0x01;  /* set remote DMA to 'remote read' */
275   Out_Byte(NE2K_CR, regs->cr);
276
277   regs->isr = 0x40;  /* clear 'remote DMA complete' interrupt */
278   Out_Byte(NE2K_ISR, regs->isr);
279   
280   /* Set remote byte count registers */
281   Out_Byte(NE2K_RBCR0, size & 0xff);
282   Out_Byte(NE2K_RBCR1, (size >> 8) & 0xff);
283
284   /* Set transmit byte count registers. */
285   Out_Byte(NE2K_TBCR0, size & 0xff);
286   Out_Byte(NE2K_TBCR1, (size >> 8) & 0xff);
287
288   /* Set remote start address registers to the first page of the transmit ring buffer. */
289   Out_Byte(NE2K_RSAR0, 0x00);
290   Out_Byte(NE2K_RSAR1, TX_START_BUFF);
291
292   cr->rd = 0x02; /* Set remote DMA to 'remote write' */
293   Out_Byte(NE2K_CR, regs->cr);
294
295   /* Push the packet data to into the dataport */
296   uint_t i;
297   for(i = 0; i < size; i += 2) {
298     Out_Word(NE2K_CR + 0x10, (*(packet + i + 1) << 8) | *(packet + i));
299   }
300
301   cr->txp = 0x1; /* Start transmission */
302   Out_Byte(NE2K_CR, regs->cr);
303
304   return 0;
305 }
306
307 #if 1
308 /* Assumes src and dest are arrays of 6 characters. */
309 int NE2K_Send(uchar_t src[], uchar_t dest[], uint_t type, uchar_t *data, uint_t size)
310 {
311   struct _CR * cr = (struct _CR*)&(regs->cr);
312   uint_t packet_size = size + 16;
313   regs->cr = 0x21; /* Turn off remote DMA, stop command */
314   cr->stp = 0x0;  /* toggle start on */
315   cr->sta = 0x1;
316   Out_Byte(NE2K_CR, regs->cr);
317   
318   // Read-before-write bug fix?
319   Out_Byte(NE2K_RBCR0, 0x42);
320   Out_Byte(NE2K_RBCR1, 0x00);
321   Out_Byte(NE2K_RSAR0, 0x42);
322   Out_Byte(NE2K_RSAR1, 0x00);
323
324   cr->rd = 0x01;  /* set remote DMA to 'remote read' */
325   Out_Byte(NE2K_CR, regs->cr);
326
327   regs->isr = 0x40;  /* clear 'remote DMA complete' interrupt */
328   Out_Byte(NE2K_ISR, regs->isr);
329   
330   /* Set remote byte count registers */
331   Out_Byte(NE2K_RBCR0, packet_size & 0xff);
332   Out_Byte(NE2K_RBCR1, (packet_size >> 8) & 0xff);
333
334   /* Set transmit byte count registers. */
335   Out_Byte(NE2K_TBCR0, packet_size & 0xff);
336   Out_Byte(NE2K_TBCR1, (packet_size >> 8) & 0xff);
337
338   /* Set remote start address registers to the first page of the transmit ring buffer. */
339   Out_Byte(NE2K_RSAR0, 0x00);
340   Out_Byte(NE2K_RSAR1, TX_START_BUFF);
341
342   cr->rd = 0x02; /* Set remote DMA to 'remote write' */
343   Out_Byte(NE2K_CR, regs->cr);
344
345   /* Begin pushing the packet into the dataport (located at 0x10 from the base address). */
346   /* Destination Address */
347   Out_Word(NE2K_CR + 0x10, (dest[1] << 8) | dest[0]);
348   Out_Word(NE2K_CR + 0x10, (dest[3] << 8) | dest[2]);
349   Out_Word(NE2K_CR + 0x10, (dest[5] << 8) | dest[4]);
350
351   /* Source Address */
352   Out_Word(NE2K_CR + 0x10, (src[1] << 8) | src[0]);
353   Out_Word(NE2K_CR + 0x10, (src[3] << 8) | src[2]);
354   Out_Word(NE2K_CR + 0x10, (src[5] << 8) | src[4]);
355
356   /* Type */
357   Out_Word(NE2K_CR + 0x10, packet_size);
358
359   /* Packet data */
360   uint_t i;
361   for(i = 0; i < size; i += 2) {
362     Out_Word(NE2K_CR + 0x10, (*(data + i + 1) << 8) | *(data + i));
363   }
364
365   cr->txp = 0x1; /* Start transmission */
366   Out_Byte(NE2K_CR, regs->cr);
367
368   return 0;
369 }
370 #endif
371
372 int NE2K_Receive()
373 {
374   PrintBoth("Packet Received\n");
375
376   Out_Byte(NE2K_CR, 0x22);
377   /* Set RSAR to the start address of the received packet. */
378   Out_Byte(NE2K_RSAR0, next & 0xff);
379   Out_Byte(NE2K_RSAR1, next >> 8);
380   Out_Byte(NE2K_CR, 0x0a);
381
382   /* 
383    * A four byte header is added to the beginning of each received packet by the NIC.
384    * The first byte is the location of the next packet in the ring buffer.
385    * The second byte is the receive status code.
386    * The third and fourth bytes are the size of the packet.
387    */
388
389   uint_t i;
390   uint_t data;
391   data = In_Word(NE2K_CR + 0x10);
392
393 #if DEBUG
394   PrintBoth("\nPacket data:\n\t");
395   PrintBoth("%x ", data);
396 #endif
397
398   /* Get the location of the next packet */
399   next = data & 0xff00;
400
401   /* Retrieve the packet size from the header, and store it in RBCR. */
402   uint_t packet_size =  In_Word(NE2K_CR + 0x10) - 4;
403   uchar_t *packet = Malloc(packet_size);
404   Out_Byte(NE2K_RBCR0, packet_size & 0xff);
405   Out_Byte(NE2K_RBCR1, (packet_size>>8) & 0xff);
406
407 #if DEBUG
408         PrintBoth("packetsize = %x\n\t", packet_size);
409 #endif
410
411   /* Copy the received packet over from the ring buffer. */
412   for(i = 0; i < packet_size; i+=2) {
413     data = In_Word(NE2K_CR + 0x10);
414     *(packet + i) = data & 0x00ff;
415     *(packet + i + 1) = (data & 0xff00) >> 8;
416 #if 0
417     PrintBoth("BNRY = %x\n", In_Byte(NE2K_BNRY));
418     Out_Byte(NE2K_CR, 0x4a);
419     PrintBoth("CURR = %x\n", In_Byte(NE2K_CURR));  
420     Out_Byte(NE2K_CR, 0x0a);
421 #endif
422   }
423
424 //Out_Byte(NE2K_RBCR0, (In_Byte(NE2K_RBCR0))-2);
425 //Out_Byte(NE2K_RSAR0, (In_Byte(NE2K_RSAR0))+2);
426
427   PrintBoth("\n%d packets have been received", ++received);
428   PrintBoth("\n\n");
429
430   Out_Byte(NE2K_ISR, 0x40); /* Clear the remote DMA complete interrupt. */
431
432   /* The BNRY register stores the location of the first packet that hasn't been read yet */
433   Out_Byte(NE2K_BNRY, next >> 8);
434
435   struct NE2K_Packet_Info *info = Malloc(sizeof(struct NE2K_Packet_Info));
436   info->size = packet_size;
437   info->status = 0;
438   memcpy(info->dest, packet, 6);
439   memcpy(info->src, packet + 6, 6);
440   callbacks.packet_received(info, packet);
441
442   return 0;
443 }
444
445
446
447