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.


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