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.


Update NE2000 to receive broadcast packets,
[palacios.git] / palacios / src / devices / 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) 2009, Lei Xia <lxia@northwestern.edu> 
11  * Copyright (c) 2009, The V3VEE Project <http://www.v3vee.org> 
12  * All rights reserved.
13  *
14  * Author: Lei Xia <lxia@northwestern.edu>
15  *
16  * This is free software.  You are permitted to use,
17  * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
18  */
19  
20 /*
21 * Virtual NE2K Network Card 
22 */
23
24 #include <devices/pci.h>
25 #include <devices/ne2k.h>
26 #include <palacios/vmm.h>
27 #include <palacios/vmm_types.h>
28 #include <palacios/vmm_io.h>
29 #include <palacios/vmm_debug.h>
30 #include <palacios/vmm_string.h>
31
32 #ifndef DEBUG_NE2K
33 #undef PrintDebug
34 #define PrintDebug(fmts, args...)
35 #endif
36
37 //#define TEST_PERFORMANCE 0
38
39 typedef enum {NIC_READY, NIC_REG_POSTED} nic_state_t;
40
41 struct ne2k_context{
42     struct guest_info *vm;
43     nic_state_t dev_state;
44
45     struct ne2k_regs regs;
46     uchar_t mac[6];
47     uchar_t mem[NE2K_MEM_SIZE];
48     struct pci_device *pci_dev;
49     struct vm_device *pci;
50 };
51
52 #define NUM_NE2K 10
53
54 struct vm_device *ne2ks[NUM_NE2K];      //the array of virtual network cards
55
56 static int nic_no = 0;
57
58 #if TEST_PERFORMANCE
59 static uint32_t exit_num = 0;
60 static uint32_t int_num = 0; 
61 #endif
62
63 #define compare_mac(src, dst) ({ \
64         ((src[0] == dst[0]) && \
65           (src[1] == dst[1]) && \
66           (src[2] == dst[2]) && \
67           (src[3] == dst[3]) && \
68           (src[4] == dst[4]) && \
69           (src[5] == dst[5]))? 1:0; \
70         })
71
72 extern int V3_Send_pkt(uchar_t *buf, int length);
73 extern int V3_Register_pkt_event(int (*netif_input)(uchar_t * pkt, uint_t size));
74
75 #ifdef DEBUG_NE2K
76 static void dump_state(struct vm_device *dev)
77 {
78   int i;
79   uchar_t *p;
80   struct ne2k_context *nic_state = (struct ne2k_context *)dev->private_data;
81
82   PrintDebug("====NE2000: Dumping state Begin ==========\n");
83   PrintDebug("Registers:\n");
84
85   p = (uchar_t *)&nic_state->regs;
86   for(i = 0; i < sizeof(struct ne2k_regs); i++)
87      PrintDebug("Regs[%d] = 0x%2x\n", i, (int)p[i]);    
88   
89   PrintDebug("Memory:\n");      
90   for(i = 0; i < 32; i++)
91         PrintDebug("0x%02x ", nic_state->mem[i]);
92   PrintDebug("\n");
93   PrintDebug("====NE2000: Dumping state End==========\n");
94 }
95 #endif
96
97 #if 0
98 //no-pci version
99 static void ne2k_update_irq(struct vm_device *dev)
100 {
101     int isr;
102     struct ne2k_context *nic_state = (struct ne2k_context *)dev->private_data;
103     struct guest_info *guest = dev->vm;
104         
105     isr = ((nic_state->regs.isr & nic_state->regs.imr) & 0x7f);
106
107     if ((isr & 0x7f) != 0x0) {
108         v3_raise_irq(guest, NIC_DEF_IRQ);
109         PrintDebug("Ne2k: RaiseIrq: isr: 0x%02x imr: 0x%02x\n", nic_state->regs.isr, nic_state->regs.imr);
110     }   
111 }
112
113 #endif
114
115 #if 1
116 //pci version
117 static void ne2k_update_irq(struct vm_device *dev)
118 {
119     int isr;
120     struct ne2k_context *nic_state = (struct ne2k_context *)dev->private_data;
121     struct pci_device *pdev = nic_state->pci_dev;
122     int irqline = 0;
123
124     if (pdev == NULL){
125         PrintDebug("Ne2k: Device %p is not attached to any PCI Bus\n", nic_state);
126         irqline = NE2K_DEF_IRQ;
127     } else {
128         irqline = pdev->config_header.intr_line;
129     }
130         
131     isr = ((nic_state->regs.isr & nic_state->regs.imr) & 0x7f);
132     
133     if (irqline == 0){
134         PrintError("Ne2k: IRQ_LINE: %d\n", irqline);
135         return;
136     }
137
138     PrintDebug("Ne2k: RaiseIrq: isr: 0x%02x imr: 0x%02x\n", nic_state->regs.isr, nic_state->regs.imr);
139     PrintDebug("ne2k_update_irq: irq_line: %d\n", irqline);
140
141     if ((isr & 0x7f) != 0x0) {
142         v3_raise_irq(nic_state->vm, irqline);
143         PrintDebug("Ne2k: RaiseIrq: isr: 0x%02x imr: 0x%02x\n", nic_state->regs.isr, nic_state->regs.imr);
144
145         #if TEST_PERFORMANCE
146         if ((++int_num) % 50 == 0)
147              PrintError("Ne2k: Total Exit: %d, INT: %d\n", (int)exit_num, int_num);
148         #endif
149     }   
150 }
151
152 #endif
153
154 static void init_ne2k_context(struct vm_device *dev)
155 {
156     struct ne2k_context *nic_state = (struct ne2k_context *)dev->private_data;
157     int i;
158     uchar_t mac[6] = {0x52, 0x54, 0x0, 0x12, 0x34, (0x60 + nic_no)};
159
160     nic_state->vm = dev->vm;
161
162     nic_state->regs.isr = ENISR_RESET;
163     nic_state->regs.imr = 0x00;
164     nic_state->regs.cmd = 0x22;
165
166     for (i = 0; i < 5; i++)
167         nic_state->regs.macaddr[i] = nic_state->mac[i] = mac[i];
168
169     nic_state->regs.macaddr[5] = nic_state->mac[5] = mac[5] + nic_no;
170
171     for (i = 0; i < 8; i++)
172         nic_state->regs.mult[i] = 0xff;
173
174     for(i = 0; i < 32; i++) {
175         nic_state->mem[i] = 0xff;
176     }
177
178     memcpy(nic_state->mem, nic_state->mac, 6);
179     nic_state->mem[14] = 0x57;
180     nic_state->mem[15] = 0x57;
181
182 #ifdef DEBUG_NE2K
183     dump_state(dev);
184 #endif
185
186 }
187
188 static int ne2k_send_packet(struct vm_device *dev, uchar_t *pkt, int length)
189 {
190     int i;
191   
192     PrintDebug("\nNe2k: Sending Packet\n");
193
194     for (i = 0; i<length; i++)
195         PrintDebug("%x ",pkt[i]);
196     PrintDebug("\n");
197         
198     return V3_Send_pkt(pkt, length);
199 }
200
201 static int ne2k_rxbuf_full(struct vm_device *dev)
202 {
203     int empty, index, boundary;
204     struct ne2k_context *nic_state = (struct ne2k_context *)dev->private_data;
205
206     index = nic_state->regs.curpag << 8;
207     boundary = nic_state->regs.boundary << 8;
208     if (index < boundary)
209         empty = boundary - index;
210     else
211         empty = ((nic_state->regs.pgstop - nic_state->regs.pgstart) << 8) - (index - boundary);
212         
213     if (empty < (MAX_ETH_FRAME_SIZE + 4))
214         return 1;
215         
216     return 0;
217 }
218
219 #define MIN_BUF_SIZE 60
220
221 static void ne2k_receive(struct vm_device *dev, const uchar_t *pkt, int length)
222 {
223     struct ne2k_context *nic_state = (struct ne2k_context *)dev->private_data;
224     struct ne2k_regs *nregs = &(nic_state->regs);
225     uchar_t *p;
226     uint32_t total_len, next, len, index, empty;
227     uchar_t buf[60];
228     uint32_t start, stop;
229
230     start = nregs->pgstart << 8;
231     stop = nregs->pgstop << 8;
232    
233     if (nregs->cmd & NE2K_STOP)
234         return;
235
236     if (ne2k_rxbuf_full(dev)){
237          PrintError("Ne2k: received buffer overflow\n");
238         return;
239     }
240
241     //packet too small, expand it
242     if (length < MIN_BUF_SIZE) {
243         memcpy(buf, pkt, length);
244         memset(buf + length, 0, MIN_BUF_SIZE - length);
245         pkt = buf;
246         length = MIN_BUF_SIZE;
247     }
248
249     index = nregs->curpag << 8;
250     //header, 4 bytes
251     total_len = length + 4;
252     //address for next packet (4 bytes for CRC)
253     next = index + ((total_len + 4 + 255) & ~0xff);
254     if (next >= stop)
255         next -= stop - start;
256
257     p = nic_state->mem + index;
258     nregs->rsr = ENRSR_RXOK;
259
260     if (pkt[0] & 0x01)
261         nregs->rsr |= ENRSR_PHY;
262         
263     p[0] = nregs->rsr;
264     p[1] = next >> 8;
265     p[2] = total_len;
266     p[3] = total_len >> 8;
267     index += 4;
268
269     while (length > 0) {
270         if (index <= stop)
271             empty = stop - index;
272         else
273             empty = 0;
274         len = length;
275         if (len > empty)
276             len = empty;
277         memcpy(nic_state->mem + index, pkt, len);
278         pkt += len;
279         index += len;
280         if (index == stop)
281             index = start;
282         length -= len;
283     }
284     nregs->curpag = next >> 8;
285
286     nregs->isr |= ENISR_RX;
287     ne2k_update_irq(dev);
288 }
289
290 static int ne2k_hook_iospace(struct vm_device *vmdev, addr_t base_addr, int size, int type, void *data);
291
292 static struct pci_device * pci_ne2k_init(struct vm_device *vmdev, 
293                                 struct vm_device *pci,  
294                                 int bus_no, 
295                                 int dev_num,
296                                 int fn_num,
297                                 int (*io_read)(ushort_t port, void * dst, uint_t length, struct vm_device * dev),
298                                 int (*io_write)(ushort_t port, void * src, uint_t length, struct vm_device * dev))
299 {
300     uchar_t *pci_conf;
301     struct pci_device *pdev;
302     struct v3_pci_bar ne2k_bar;
303
304     ne2k_bar.type = PCI_BAR_IO;
305     ne2k_bar.num_ports = 0x100;
306     ne2k_bar.default_base_port = 0xc100;
307     ne2k_bar.io_read = io_read;
308     ne2k_bar.io_write = io_write;
309   
310     pdev = v3_pci_register_device(vmdev, 
311                                 PCI_STD_DEVICE, 
312                                 bus_no, 
313                                 dev_num, 
314                                 fn_num,
315                                 "NE2000", 
316                                 &ne2k_bar, 
317                                 NULL, NULL, NULL, vmdev);
318
319     if (pdev == NULL){
320        PrintError("NIC: Register to PCI bus failed\n");
321        return NULL;
322     }
323
324     pci_conf = pdev->config_space;
325         
326     pci_conf[0x00] = 0xec; // Realtek 8029
327     pci_conf[0x01] = 0x10;
328     pci_conf[0x02] = 0x29;
329     pci_conf[0x03] = 0x80;
330     pci_conf[0x0a] = 0x00; // ethernet network controller
331     pci_conf[0x0b] = 0x02;
332     pci_conf[0x0e] = 0x00; // header_type
333     pci_conf[0x3d] = 1; // interrupt pin 0
334     pci_conf[0x3c] = 11; //default IRQ Line
335
336     pdev->vm_dev = vmdev;
337     
338     return pdev;
339 }
340
341 static int netif_input(uchar_t *pkt, uint_t size)
342 {
343   struct ne2k_context *nic_state;
344   struct ne2k_regs *nregs;
345   static const uchar_t brocast_mac[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
346   int i;
347   
348   PrintDebug("\nNe2k: Packet Received:\nSource:");
349   for (i = 6; i < 12; i++) {
350         PrintDebug("%x ", pkt[i]);
351   }
352   PrintDebug("\n");
353   for(i= 0; i<size; i++)
354         PrintDebug("%x ", pkt[i]);
355   
356
357   for (i = 0; i < NUM_NE2K; i++){
358         if (ne2ks[i] != NULL) {
359                 nic_state = (struct ne2k_context *)ne2ks[i]->private_data;
360                 nregs = &(nic_state->regs);
361                         
362                 if (nregs->rcr & 0x10) {//promiscuous mode
363                         ne2k_receive(ne2ks[i], pkt, size);
364                 } else {
365                        if (compare_mac(pkt,  brocast_mac) && (nregs->rcr & 0x04)){ //broadcast packet
366                                 ne2k_receive(ne2ks[i], pkt, size);
367                        } else if (pkt[0] & 0x01) {
368                              //TODO: multicast packet
369                              if (nregs->rcr & 0x08)
370                                     ne2k_receive(ne2ks[i], pkt, size);
371                        } else if (compare_mac(pkt, nic_state->mac)){
372                                 ne2k_receive(ne2ks[i], pkt, size);
373                        } else 
374                         continue;
375                }
376         }
377     }
378
379   return 0;
380 }
381
382
383 static inline uint16_t cpu2le16(uint16_t val)
384 {
385     uint16_t p;
386     uchar_t *p1 = (uchar_t *)&p;
387
388     p1[0] = val;
389     p1[1] = val >> 8;
390
391     return p;
392 }
393
394
395 static inline uint32_t cpu2le32(uint32_t val)
396 {
397     uint32_t p;
398     uchar_t *p1 = (uchar_t *)&p;
399
400     p1[0] = val;
401     p1[1] = val >> 8;
402     p1[2] = val >> 16;
403     p1[3] = val >> 24;
404
405     return p;
406 }
407
408 static inline uint16_t le16_to_cpu(const uint16_t *p)
409 {
410     const uchar_t *p1 = (const uchar_t *)p;
411     return p1[0] | (p1[1] << 8);
412 }
413
414 static inline uint32_t le32_to_cpu(const uint32_t *p)
415 {
416     const uchar_t *p1 = (const uchar_t *)p;
417     return p1[0] | (p1[1] << 8) | (p1[2] << 16) | (p1[3] << 24);
418 }
419
420 static void 
421 ne2k_mem_writeb(struct ne2k_context *nic_state, 
422                         uint32_t addr,
423                         uint32_t val)
424 {
425     uchar_t tmp;
426
427     tmp = (uchar_t) (val & 0x000000ff);
428     if (addr < 32 || (addr >= NE2K_PMEM_START && addr < NE2K_MEM_SIZE)) {
429         nic_state->mem[addr] = tmp;
430     }
431
432     PrintDebug("wmem addr: %x val: %x\n", addr, val);
433 }
434
435 static void 
436 ne2k_mem_writew(struct ne2k_context *nic_state, 
437                         uint32_t addr,
438                         uint32_t val)
439 {
440     addr &= ~1; //XXX: check exact behaviour if not even
441     if (addr < 32 ||
442         (addr >= NE2K_PMEM_START && addr < NE2K_MEM_SIZE)) {
443         *(ushort_t *)(nic_state->mem + addr) = cpu2le16(val);
444     }
445
446     PrintDebug("wmem addr: %x val: %x\n", addr, val);
447 }
448
449 static void 
450 ne2k_mem_writel(struct ne2k_context *nic_state,
451                         uint32_t addr,
452                         uint32_t val)
453 {
454     addr &= ~1; // XXX: check exact behaviour if not even
455     if (addr < 32 ||
456         (addr >= NE2K_PMEM_START && addr < NE2K_MEM_SIZE)) {
457         *(uint32_t *)(nic_state->mem + addr) = cpu2le32(val);
458     }
459
460     PrintDebug("wmem addr: %x val: %x\n", addr, val);
461 }
462
463 static uchar_t 
464 ne2k_mem_readb(struct ne2k_context *nic_state, uint32_t addr)
465 {
466     PrintDebug("rmem addr: %x\n", addr);
467         
468     if (addr < 32 ||
469         (addr >= NE2K_PMEM_START && addr < NE2K_MEM_SIZE)) {
470         return nic_state->mem[addr];
471     } else {
472         return 0xff;
473     }
474 }
475
476 static ushort_t
477 ne2k_mem_readw(struct ne2k_context *nic_state, uint32_t addr)
478 {
479     PrintDebug("rmem addr: %x\n", addr);
480         
481     addr &= ~1; //XXX: check exact behaviour if not even 
482     if (addr < 32 ||
483         (addr >= NE2K_PMEM_START && addr < NE2K_MEM_SIZE)) {
484         return (ushort_t)le16_to_cpu((ushort_t *)(nic_state->mem + addr));
485     } else {
486         return 0xffff;
487     }
488 }
489
490 static uint32_t 
491 ne2k_mem_readl(struct ne2k_context *nic_state, uint32_t addr)
492 {
493     PrintDebug("rmem addr: %x\n", addr);
494
495     addr &= ~1; //XXX: check exact behaviour if not even
496     if (addr < 32 ||
497         (addr >= NE2K_PMEM_START && addr < NE2K_MEM_SIZE)) {
498         return (uint32_t)le32_to_cpu((uint32_t *)(nic_state->mem + addr));
499     } else {
500         return 0xffffffff;
501     }
502 }
503
504 static void 
505 ne2k_dma_update(struct vm_device *dev, int len)
506 {               
507     struct ne2k_context *nic_state = (struct ne2k_context *)dev->private_data;
508         
509     nic_state->regs.rsar += len;
510     // wrap
511     if (nic_state->regs.rsar == nic_state->regs.pgstop)
512         nic_state->regs.rsar = nic_state->regs.pgstart;
513
514     if (nic_state->regs.rbcr <= len) {
515         nic_state->regs.rbcr = 0;
516         nic_state->regs.isr |= ENISR_RDC;
517         ne2k_update_irq(dev);
518     } else {
519         nic_state->regs.rbcr -= len;
520     }
521 }
522
523
524 //for data port read/write
525 static int ne2k_data_read(ushort_t port,
526                         void * dst,
527                         uint_t length,
528                         struct vm_device *dev)
529 {
530         uint32_t val;
531         struct ne2k_context *nic_state = (struct ne2k_context *)dev->private_data;
532
533         // current dma address
534         uint32_t addr = nic_state->regs.rsar;
535
536         switch(length){
537                 case 1:
538                         val = ne2k_mem_readb(nic_state, addr);
539                         break;
540                 case 2:
541                         val = ne2k_mem_readw(nic_state, addr);
542                         break;
543                 case 4:
544                         val = ne2k_mem_readl(nic_state, addr);
545                         break;
546                 default:
547                         PrintError("ne2k_data_read error: invalid length %d\n", length);
548                         val = 0x0;
549         }
550
551         ne2k_dma_update(dev, length);
552
553         memcpy(dst, &val, length);
554
555         PrintDebug("ne2k_read: port:0x%x (%u bytes): 0x%x", port & 0x1f,length, val);
556
557         #if TEST_PERFORMANCE
558         if ((++exit_num) % 50 == 0)
559         PrintError("Ne2k-Ne2k: Total Exit: %d, INT: %d\n", (int)exit_num, int_num);
560         #endif
561
562         return length;
563 }
564
565 static int ne2k_data_write(ushort_t port,
566                                                         void * src,
567                                                         uint_t length,
568                                                         struct vm_device *dev)
569 {
570         uint32_t val;
571         struct ne2k_context *nic_state = (struct ne2k_context *)dev->private_data;
572
573         if (nic_state->regs.rbcr == 0)
574                 return length;
575
576         memcpy(&val, src, length);
577
578         uint32_t addr = nic_state->regs.rsar;
579         
580         switch (length){
581                 case 1:
582                         ne2k_mem_writeb(nic_state, addr, val);
583                         break;
584                 case 2:
585                         ne2k_mem_writew(nic_state, addr, val);
586                         break;
587                 case 4:
588                         ne2k_mem_writel(nic_state, addr, val);
589                         break;
590                 default:
591                         PrintError("nic_data_write error: invalid length %d\n", length);
592                 }
593         
594         ne2k_dma_update(dev, length);
595
596         PrintDebug("ne2k_write: port:0x%x (%u bytes): 0x%x\n", port & 0x1f,length, val);
597
598         #if TEST_PERFORMANCE
599         if ((++exit_num) % 50 == 0)
600                 PrintError("Ne2k-Ne2k: Total Exit: %d, INT: %d\n", (int)exit_num, int_num);
601         #endif
602                         
603         return length;
604 }
605
606 static int ne2k_reset_device(struct vm_device * dev)
607 {
608   
609   PrintDebug("vnic: reset device\n");
610
611   init_ne2k_context(dev);
612
613   return 0;
614 }
615
616
617 //for 0xc11f port
618 static int ne2k_reset_port_read(ushort_t port,
619                                                         void * dst,
620                                                         uint_t length,
621                                                        struct vm_device *dev)
622 {
623         uint32_t val = 0x0;
624
625         memcpy(dst, &val, length);
626
627         PrintDebug("ne2k_read: port:0x%x (%u bytes): 0x%x\n", port,length, val);
628
629         ne2k_reset_device(dev);
630
631         #if TEST_PERFORMANCE
632         if ((++exit_num) % 50 == 0)
633                 PrintError("Ne2k-Ne2k: Total Exit: %d, INT: %d\n", (int)exit_num, int_num);
634         #endif
635
636         return length;
637 }
638
639 static int ne2k_reset_port_write(ushort_t port,
640                                                         void * src,
641                                                         uint_t length,
642                                                         struct vm_device *dev)
643 {
644         uint32_t val;
645
646         memcpy(&val, src, length);
647
648         PrintDebug("ne2k_write: port:0x%x (%u bytes): 0x%x\n", port,length, val);
649
650         #if TEST_PERFORMANCE
651         if ((++exit_num) % 50 == 0)
652                 PrintError("Ne2k-Ne2k: Total Exit: %d, INT: %d\n", (int)exit_num, int_num);
653         #endif
654                         
655         return length;
656 }
657
658 static int ne2k_ioport_write(ushort_t port,
659                         void * src,
660                         uint_t length,
661                         struct vm_device *dev)
662 {
663     uchar_t  page;
664     struct ne2k_context *nic_state = (struct ne2k_context* )dev->private_data;
665     uchar_t val;
666     int index;
667         
668     if (length == 1) {
669           memcpy(&val, src, 1);
670     } else {
671           PrintError("ne2k_write error: length %d\n", length);  
672           return length;
673     }
674
675     PrintDebug("ne2k_write: port:0x%x  val: 0x%x\n", port, (int)val);
676         
677     port &= 0x1f;
678
679     if (port == 0x10)
680         return ne2k_data_write(port, src, length, dev);
681
682     if (port == 0x1f)
683         return ne2k_reset_port_write(port, src, length, dev);
684                 
685     if (port == EN0_COMMAND) {
686         nic_state->regs.cmd = val;
687         if (!(val & NE2K_STOP)) {
688             nic_state->regs.isr &= ~ENISR_RESET; 
689             if ((val & (NE2K_DMAREAD | NE2K_DMAWRITE)) &&
690                         nic_state->regs.rbcr == 0) {
691                 nic_state->regs.isr |= ENISR_RDC;
692                 ne2k_update_irq(dev);
693             }
694             if (val & NE2K_TRANSMIT) {
695                 index = (nic_state->regs.tpsr << 8);
696                 if (index >= NE2K_PMEM_END)
697                     index -= NE2K_PMEM_SIZE;
698                 if (index + nic_state->regs.tbcr <= NE2K_PMEM_END) {
699                     ne2k_send_packet(dev, nic_state->mem + index, nic_state->regs.tbcr);
700                 }
701                 nic_state->regs.tsr = ENTSR_PTX;
702                 nic_state->regs.isr |= ENISR_TX;
703                 nic_state->regs.cmd &= ~NE2K_TRANSMIT;
704                 ne2k_update_irq(dev);
705             }
706         }
707     } else {
708         page = nic_state->regs.cmd >> 6;
709         if(page == 0){
710                 switch(port) {
711                         case EN0_STARTPG:
712                             nic_state->regs.pgstart = val;
713                             break;
714                         case EN0_STOPPG:
715                             nic_state->regs.pgstop = val;
716                             break;
717                         case EN0_BOUNDARY:
718                             nic_state->regs.boundary = val;
719                             break;
720                         case EN0_TPSR:
721                             nic_state->regs.tpsr = val;
722                             break;
723                         case EN0_TCNTLO:
724                             nic_state->regs.tbcr = (nic_state->regs.tbcr & 0xff00) | val;
725                             break;
726                         case EN0_TCNTHI:
727                             nic_state->regs.tbcr = (nic_state->regs.tbcr & 0x00ff) | (val << 8);
728                             break;
729                         case EN0_ISR:
730                             nic_state->regs.isr &= ~(val & 0x7f);
731                             ne2k_update_irq(dev);
732                             break;
733                         case EN0_RSARLO:
734                             nic_state->regs.rsar = (nic_state->regs.rsar & 0xff00) | val;
735                             break;
736                         case EN0_RSARHI:
737                             nic_state->regs.rsar = (nic_state->regs.rsar & 0x00ff) | (val << 8);
738                             break;
739                         case EN0_RCNTLO:
740                             nic_state->regs.rbcr = (nic_state->regs.rbcr & 0xff00) | val;
741                             break;
742                         case EN0_RCNTHI:
743                             nic_state->regs.rbcr = (nic_state->regs.rbcr & 0x00ff) | (val << 8);
744                             break;
745                         case EN0_RXCR:
746                             nic_state->regs.rcr = val;
747                             break;
748                         case EN0_TXCR:
749                              nic_state->regs.tcr = val;
750                         case EN0_DCFG:
751                             nic_state->regs.dcr = val;
752                             break;      
753                         case EN0_IMR:
754                             nic_state->regs.imr = val;
755                              //PrintError("ne2k_write error: write IMR:0x%x\n", (int)val);
756                             ne2k_update_irq(dev);
757                             break;
758                         default:
759                              PrintError("ne2k_write error: invalid port:0x%x\n", port);
760                              break;
761                         }
762                 }
763          if(page == 1){
764                 switch(port) {
765                         case EN1_PHYS ... EN1_PHYS + 5:
766                             nic_state->regs.phys[port - EN1_PHYS] = val;
767                             break;
768                         case EN1_CURPAG:
769                             nic_state->regs.curpag = val;
770                             break;
771                         case EN1_MULT ... EN1_MULT + 7:
772                             // PrintError("ne2k_write error: write EN_MULT:0x%x\n", (int)val);
773                             nic_state->regs.mult[port - EN1_MULT] = val;
774                             break;
775                         default:
776                              PrintError("ne2k_write error: invalid port:0x%x\n", port);
777                              break;
778                         }
779                 }
780         if(page == 2){
781                 switch(port) {
782                          case EN2_LDMA0:
783                             nic_state->regs.clda = (nic_state->regs.clda & 0xff00) | val;
784                             break;
785                          case EN2_LDMA1:
786                             nic_state->regs.clda = (nic_state->regs.clda & 0x00ff) | (val << 8);
787                             break;
788                          case EN2_RNPR:
789                             nic_state->regs.rnpp = val;
790                             break;
791                          case EN2_LNRP:
792                             nic_state->regs.lnpp = val;
793                             break;
794                          case EN2_ACNT0:
795                             nic_state->regs.addcnt = (nic_state->regs.addcnt & 0xff00) | val;
796                             break;
797                          case EN2_ACNT1: 
798                             nic_state->regs.addcnt = (nic_state->regs.addcnt & 0x00ff) | (val << 8);
799                             break;
800                          default:
801                             PrintError("ne2k_write error: invalid port:0x%x\n", port);
802                             break;
803                         }
804                 }
805     }
806
807     #if TEST_PERFORMANCE
808     if ((++exit_num) % 50 == 0)
809         PrintError("Ne2k-Ne2k: Total Exit: %d, INT: %d\n", (int)exit_num, int_num);
810     #endif
811
812     return length;
813         
814 }
815
816 static int ne2k_ioport_read(ushort_t port,
817                         void * dst,
818                         uint_t length,
819                         struct vm_device *dev)
820 {
821     uchar_t page, ret, offset;
822
823     struct ne2k_context *nic_state = (struct ne2k_context* )dev->private_data;
824
825     if (length > 1) {
826           PrintError("ne2k_read error: length %d\n", length);
827           return length;
828     }
829
830     offset = port;
831     port &= 0x1f;
832
833     if (port == 0x10)
834         return ne2k_data_read(port, dst, length, dev);
835
836     if (port == 0x1f)
837         return ne2k_reset_port_read(port, dst, length, dev);
838
839     if (port == EN0_COMMAND) {
840         ret = nic_state->regs.cmd;
841     } else {
842         page = nic_state->regs.cmd >> 6;
843         if (page == 0){
844             switch(port) {              
845                  case EN0_CLDALO:
846                     ret = nic_state->regs.clda & 0x00ff;
847                     break;
848                  case EN0_CLDAHI:
849                     ret = (nic_state->regs.clda & 0xff00) >> 8;
850                     break;
851                  case EN0_BOUNDARY:
852                     ret = nic_state->regs.boundary;
853                     break;
854                  case EN0_TSR:
855                     ret = nic_state->regs.tsr;
856                     break;
857                  case EN0_NCR:
858                     ret = nic_state->regs.ncr;
859                     break;
860                  case EN0_FIFO:
861                     ret = nic_state->regs.fifo;
862                     break;
863                  case EN0_ISR:
864                     ret = nic_state->regs.isr;
865                     ne2k_update_irq(dev);
866                     break;
867                  case EN0_CRDALO:
868                     ret = nic_state->regs.crda & 0x00ff;
869                     break;
870                  case EN0_CRDAHI:
871                     ret = (nic_state->regs.crda & 0xff00) >> 8;
872                     break;
873                  case EN0_RSR:
874                     ret = nic_state->regs.rsr;
875                     break;
876                  case EN0_COUNTER0:
877                      ret = nic_state->regs.cntr & 0x000000ff;
878                      break;
879                  case EN0_COUNTER1:
880                     ret = (nic_state->regs.cntr & 0x0000ff00) >> 8;
881                      break;     
882                  case EN0_COUNTER2:
883                     ret = (nic_state->regs.cntr & 0x00ff0000) >> 16;
884                      break;
885                  default:
886                     PrintError("ne2k_read error: invalid port:0x%x\n", port);
887                     ret = 0x00;
888                     break;
889            }
890         }
891          if (page == 1){
892            switch(port) {
893                  case EN1_PHYS ... EN1_PHYS + 5:
894                     ret = nic_state->regs.phys[port - EN1_PHYS];
895                     break;
896                  case EN1_CURPAG:
897                     ret = nic_state->regs.curpag;
898                     break;
899                  case EN1_MULT ... EN1_MULT + 7:
900                     ret = nic_state->regs.mult[port - EN1_MULT];
901                     break;
902                  default:
903                     PrintError("ne2k_read error: invalid port:0x%x\n", port);
904                     ret = 0x00;
905                     break;
906            }
907          }
908          if (page == 2){
909            switch(port) {
910                  case EN2_STARTPG:
911                     ret = nic_state->regs.pgstart;
912                     break;
913                  case EN2_STOPPG:
914                     ret = nic_state->regs.pgstop;
915                     break;
916                  case EN2_RNPR:
917                     ret = nic_state->regs.rnpp;
918                     break;
919                  case EN2_LNRP:
920                     ret = nic_state->regs.lnpp;
921                     break;
922                  case EN2_TPSR:
923                     ret = nic_state->regs.tpsr;
924                     break;
925                  case EN2_ACNT0:
926                     ret = nic_state->regs.addcnt & 0x00ff;
927                     break;
928                  case EN2_ACNT1: 
929                     ret = (nic_state->regs.addcnt & 0xff00) >> 8;
930                     break;
931                  case EN2_RCR:
932                     ret = nic_state->regs.rcr;
933                     break;
934                  case EN2_TCR:
935                     ret = nic_state->regs.tcr;
936                     break;
937                  case EN2_DCR:
938                     ret = nic_state->regs.dcr;
939                     break;
940                  case EN2_IMR:
941                     ret = nic_state->regs.imr;
942                     break;
943                  default:
944                     PrintError("ne2k_read error: invalid port:0x%x\n", port);
945                     ret = 0x00;
946                     break;
947            }
948          }
949     }
950
951     memcpy(dst, &ret, 1);
952
953     PrintDebug("ne2k_read: port:0x%x  val: 0x%x\n", offset, (int)ret);
954
955     #if TEST_PERFORMANCE
956     if ((++exit_num) % 50 == 0)
957         PrintError("Ne2k-Ne2k: Total Exit: %d, INT: %d\n", (int)exit_num, int_num);
958     #endif
959
960     return length;
961
962 }
963
964
965 static int ne2k_start_device(struct vm_device *dev)
966 {
967   PrintDebug("vnic: start device\n");
968   
969   return 0;
970 }
971
972
973 static int ne2k_stop_device(struct vm_device *dev)
974 {
975   PrintDebug("vnic: stop device\n");
976   
977   return 0;
978 }
979
980 static void  init_global_setting()
981 {       
982   int i;
983   
984   V3_Register_pkt_event(&netif_input);
985   
986   for (i = 0; i < NUM_NE2K; i++)
987         ne2ks[i] = NULL;
988
989 }
990
991 static int ne2k_hook_iospace(struct vm_device *vmdev, addr_t base_addr, int size, int type, void *data)
992 {
993   int i;
994
995   if (base_addr <= 0)
996         return -1;
997
998   PrintDebug("In NIC%d: Hook IO space starting from %x\n", nic_no, (int) base_addr);
999
1000   for (i = 0; i < 16; i++){     
1001         v3_dev_hook_io(vmdev, base_addr + i, &ne2k_ioport_read, &ne2k_ioport_write);
1002   }
1003   v3_dev_hook_io(vmdev, base_addr + NIC_DATA_PORT, &ne2k_data_read, &ne2k_data_write);
1004   v3_dev_hook_io(vmdev, base_addr + NIC_RESET_PORT, &ne2k_reset_port_read, &ne2k_reset_port_write);
1005
1006   return 0;
1007
1008 }
1009
1010 static int ne2k_init_device(struct vm_device * vmdev) 
1011 {
1012   struct vm_device *pci = NULL;
1013   struct pci_device *pdev = NULL;
1014   struct ne2k_context *nic_state = (struct ne2k_context *)vmdev->private_data;
1015
1016   PrintDebug("ne2k%d: init_device\n",  nic_no);
1017
1018   if (nic_no == 0) // only initiate once
1019         init_global_setting();
1020
1021   init_ne2k_context(vmdev);
1022
1023   pci = nic_state->pci;
1024
1025   if (pci != NULL) {
1026         PrintDebug("Ne2k: attach ne2k to the pci %p\n", pci);
1027         pdev = pci_ne2k_init(vmdev, pci, 0, -1, 0,  &ne2k_ioport_read, &ne2k_ioport_write);
1028         if (pdev == NULL)
1029                 PrintError("Ne2k: initiate failure, failure to attach ne2k to the bus %p\n", pci);
1030   } else {
1031         PrintDebug("Ne2k: Not attached to any pci\n");
1032         ne2k_hook_iospace(vmdev, NE2K_DEF_BASE_ADDR, 100, 0, NULL);
1033   }
1034
1035   nic_state->pci_dev = pdev;  
1036   ne2ks[nic_no ++] = vmdev;
1037
1038   #ifdef DEBUG_NE2K
1039   dump_state(vmdev);
1040   #endif
1041
1042   return 0;
1043 }
1044
1045
1046
1047 static int ne2k_deinit_device(struct vm_device *vmdev)
1048 {
1049   int i;
1050   
1051   for (i = 0; i<16; i++){               
1052         v3_dev_unhook_io(vmdev, NE2K_DEF_BASE_ADDR + i);
1053   }
1054
1055   v3_dev_unhook_io(vmdev, NE2K_DEF_BASE_ADDR + NIC_DATA_PORT);
1056   v3_dev_unhook_io(vmdev, NE2K_DEF_BASE_ADDR + NIC_RESET_PORT);
1057   
1058   return 0;
1059 }
1060
1061
1062 static struct vm_device_ops dev_ops = { 
1063   .init = ne2k_init_device, 
1064   .deinit = ne2k_deinit_device,
1065   .reset = ne2k_reset_device,
1066   .start = ne2k_start_device,
1067   .stop = ne2k_stop_device,
1068 };
1069
1070
1071 struct vm_device *v3_create_ne2k(struct vm_device *pci) 
1072 {
1073   struct ne2k_context * nic_state = V3_Malloc(sizeof(struct ne2k_context));
1074
1075   memset(nic_state, 0, sizeof(struct ne2k_context));
1076
1077   PrintDebug("NE2K internal at %p\n", (void *)nic_state);
1078
1079   nic_state->pci = pci;
1080
1081   struct vm_device *device = v3_create_device("NE2K", &dev_ops, nic_state);
1082
1083   return device;
1084 }
1085