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.


fixed a number of bugs due to the update
[palacios.git] / palacios / src / devices / vnic.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
25
26
27 #include <devices/vnic.h>
28 #include <palacios/vmm.h>
29 #include <palacios/vmm_types.h>
30 #include <palacios/vmm_io.h>
31 #include <palacios/vmm_debug.h>
32
33 #define DEBUG_NIC
34
35 #ifndef DEBUG_NIC
36 #undef PrintDebug()
37 #define PrintDebug(fmts, args...)
38 #endif
39
40 typedef enum {NIC_READY, NIC_REG_POSTED} nic_state_t;
41
42 struct nic_regs {
43     uchar_t cmd;
44     uchar_t pgstart;
45     uchar_t pgstop;
46     ushort_t clda;
47     uchar_t boundary;
48     uchar_t tsr;
49     uchar_t tpsr;
50     uchar_t ncr;
51     ushort_t tbcr;
52     uchar_t fifo;
53     uchar_t isr;
54     ushort_t crda;
55     ushort_t rsar;
56     ushort_t rbcr;
57     uchar_t rsr;
58     uchar_t rcr;
59     uint32_t cntr;
60     uchar_t tcr;
61     uchar_t dcr;
62     uchar_t imr;
63     
64     uchar_t phys[6]; //mac address 
65     uchar_t curpag;
66     uchar_t mult[8]; //multicast mask array 
67     uchar_t rnpp;
68     uchar_t lnpp;
69     ushort_t addcnt;
70     
71     uchar_t macaddr[6];
72 };
73
74 struct nic_context{
75     struct guest_info *vm;
76
77     nic_state_t dev_state;
78
79     struct nic_regs regs;
80
81     uchar_t mac[6]; //the mac address of this nic
82
83     uchar_t mem[NE2K_MEM_SIZE]; 
84 };
85
86 struct vm_device *current_vnic;
87
88 #define compare_mac(src, dst) ({                \
89             ( (src[0] == dst[0]) &&             \
90               (src[1] == dst[1]) &&             \
91               (src[2] == dst[2]) &&             \
92               (src[3] == dst[3]) &&             \
93               (src[4] == dst[4]) &&             \
94               (src[5] == dst[5]) ) ? 1 : 0;     \
95         })
96
97
98
99
100 static int vnic_mem_write(struct nic_context * nic_state, 
101                           uint32_t addr,
102                           void * src, uint_t length) {
103     
104     PrintDebug("wmem addr: %x val: %x\n", addr, val);
105
106     if ((addr < NE2K_PMEM_START) || (addr > NE2K_MEM_SIZE))
107
108     switch (length) {
109         case 1: {
110             uchar_t val = *(uchar_t *)src;
111             
112         }
113         case 2:
114         case 4:
115     }
116
117 }
118
119
120 static void vnic_mem_writeb(struct nic_context * nic_state, 
121                             uint32_t addr,
122                             uint32_t val) {
123     uchar_t tmp = (uchar_t) (val & 0x000000ff);
124
125     if ( (addr < 32) || 
126          ((addr >= NE2K_PMEM_START && addr) < NE2K_MEM_SIZE) ) {
127         nic_state->mem[addr] = tmp;
128     }
129
130     PrintDebug("wmem addr: %x val: %x\n", addr, val);
131 }
132
133 static void vnic_mem_writew(struct nic_context * nic_state, 
134                             uint32_t addr,
135                             uint32_t val) {
136
137     addr &= ~1; //XXX: check exact behaviour if not even
138
139     if ( (addr < 32) ||
140          ((addr >= NE2K_PMEM_START && addr) < NE2K_MEM_SIZE)) {
141         *(ushort_t *)(nic_state->mem + addr) = cpu2le16(val);
142     }
143
144     PrintDebug("wmem addr: %x val: %x\n", addr, val);
145 }
146
147 static void vnic_mem_writel(struct nic_context * nic_state,
148                             uint32_t addr,
149                             uint32_t val) {
150     addr &= ~1; // XXX: check exact behaviour if not even
151
152     if ( (addr < 32) ||
153          ( (addr >= NE2K_PMEM_START) && (addr < NE2K_MEM_SIZE) ) ) {
154         *(uint32_t *)(nic_state->mem + addr) = cpu2le32(val);
155     }
156     
157     PrintDebug("wmem addr: %x val: %x\n", addr, val);
158 }
159
160 static uchar_t vnic_mem_readb(struct nic_context * nic_state, uint32_t addr) {
161     PrintDebug("rmem addr: %x\n", addr);
162         
163     if ( (addr < 32) ||
164          ( (addr >= NE2K_PMEM_START) && (addr < NE2K_MEM_SIZE)) ) {
165         return nic_state->mem[addr];
166     } else {
167         return 0xff;
168     }
169 }
170
171 static ushort_t vnic_mem_readw(struct nic_context * nic_state, uint32_t addr) {
172     PrintDebug("rmem addr: %x\n", addr);
173         
174     addr &= ~1; //XXX: check exact behaviour if not even 
175
176     if ( (addr < 32) ||
177          ( (addr >= NE2K_PMEM_START) && (addr < NE2K_MEM_SIZE))) {
178         return (ushort_t)le16_to_cpu((ushort_t *)(nic_state->mem + addr));
179     } else {
180         return 0xffff;
181     }
182 }
183
184 static uint32_t vnic_mem_readl(struct nic_context * nic_state, uint32_t addr) {
185     PrintDebug("rmem addr: %x\n", addr);
186
187     addr &= ~1; //XXX: check exact behaviour if not even
188
189     if ( (addr < 32) ||
190          ( (addr >= NE2K_PMEM_START && addr < NE2K_MEM_SIZE))) {
191         return (uint32_t)le32_to_cpu((uint32_t *)(nic_state->mem + addr));
192     } else {
193         return 0xffffffff;
194     }
195 }
196
197
198
199
200 static void dump_state(struct vm_device * dev) {
201     int i = 0;
202     uchar_t * p = NULL;
203     struct nic_context * nic_state = (struct nic_context *)dev->private_data;
204
205     PrintDebug("====VNIC: Dumping state Begin ==========\n");
206     PrintDebug("Registers:\n");
207
208     p = (uchar_t *)&nic_state->regs;
209  
210     for (i = 0; i < sizeof(struct nic_regs); i++) {
211         PrintDebug("Regs[i] = 0x%2x\n", (int)p[i]);     
212     }
213
214     PrintDebug("Memory:\n");    
215     
216     for (i = 0; i < 32; i++) {
217         PrintDebug("0x%02x ", nic_state->mem[i]);
218     }
219
220     PrintDebug("\n");
221     PrintDebug("====VNIC: Dumping state End==========\n");
222 }
223
224 static void vnic_update_irq(struct vm_device * dev) {
225     struct nic_context * nic_state = (struct nic_context *)dev->private_data;
226     struct guest_info * guest = dev->vm;
227
228     int isr = ((nic_state->regs.isr & nic_state->regs.imr) & 0x7f);
229
230     if ((isr & 0x7f) != 0x0) {
231         v3_raise_irq(guest, NIC_IRQ);
232         PrintDebug("VNIC: RaiseIrq: isr: 0x%02x imr: 0x%02x\n", nic_state->regs.isr, nic_state->regs.imr);
233     }   
234 }
235
236 static void init_vnic_context(struct vm_device * dev) {
237     struct nic_context *nic_state = (struct nic_context *)dev->private_data;
238     int i;
239     uchar_t mac[6] = {0x52, 0x54, 0x0, 0x12, 0x34, 0x56};
240
241     nic_state->vm = dev->vm;
242
243     nic_state->regs.isr = ENISR_RESET;
244     nic_state->regs.imr = 0x00;
245     nic_state->regs.cmd = 0x22;
246
247     for (i = 0; i < 6; i++) {
248         nic_state->regs.macaddr[i] = nic_state->mac[i] = mac[i];
249     }
250
251     for (i = 0; i < 8; i++) {
252         nic_state->regs.mult[i] = 0xff;
253     }
254
255     for(i = 0; i < 32; i++) {
256         nic_state->mem[i] = 0xff;
257     }
258
259     memcpy(nic_state->mem, nic_state->mac, 6);
260     nic_state->mem[14] = 0x57;
261     nic_state->mem[15] = 0x57;
262
263     dump_state(dev);
264 }
265
266
267 static int vnic_send_packet(struct vm_device *dev, uchar_t *pkt, int length) {
268     int i;
269   
270     PrintDebug("\nVNIC: Sending Packet\n");
271
272     for (i = 0; i<length; i++) {
273         PrintDebug("%x ",pkt[i]);
274     }
275
276     PrintDebug("\n");
277         
278     return V3_SEND_PKT(pkt, length);
279 }
280
281
282 struct vm_device * get_rx_dev(uchar_t * dst_mac) {
283     struct nic_context * nic_state = (struct nic_context *)current_vnic->private_data;
284     struct nic_regs * nregs = &(nic_state->regs);
285
286     static const uchar_t brocast_mac[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
287
288     if (nregs->rcr & 0x10) {
289         // promiscuous model    
290     } else {
291         if (compare_mac(dst_mac,  brocast_mac)) { //broadcast address
292             if (!(nregs->rcr & 0x04)) {
293                 return NULL;
294             }
295         } else if (dst_mac[0] & 0x01) {
296             // multicast packet, not fully done here
297             // ==========
298             if (!(nregs->rcr & 0x08)) {
299                 return NULL;
300             }
301         } else if (!compare_mac(dst_mac, nic_state->mac)) {
302             return NULL;
303         } else {
304             // TODO: ELSE??
305         }
306     }
307
308     return current_vnic;
309 }
310
311 static int vnic_rxbuf_full(struct vm_device * dev) {
312     int empty, index, boundary;
313     struct nic_context * nic_state = (struct nic_context *)dev->private_data;
314
315     index = nic_state->regs.curpag << 8;
316     boundary = nic_state->regs.boundary << 8;
317     if (index < boundary) {
318         empty = boundary - index;
319     } else {
320         empty = ((nic_state->regs.pgstop - nic_state->regs.pgstart) << 8) - (index - boundary);
321     }
322
323     if (empty < (MAX_ETH_FRAME_SIZE + 4)) {
324         return 1;
325     }
326
327     return 0;
328 }
329
330 #define MIN_BUF_SIZE 60
331
332 static void vnic_receive(struct vm_device * dev, const uchar_t * pkt, int length) {
333     struct nic_context * nic_state = (struct nic_context *)dev->private_data;
334     struct nic_regs * nregs = &(nic_state->regs);
335
336     uchar_t * p = NULL;
337     uint32_t total_len = 0; 
338     uint32_t next = 0;
339     uint32_t len = 0;
340     uint32_t index = 0;
341     uint32_t empty = 0;
342     uchar_t buf[60];
343     uint32_t start = nregs->pgstart << 8;
344     uint32_t stop = nregs->pgstop << 8;
345         
346     //PrintDebug("VNIC: received packet, len=%d\n", length);
347    
348     if (nregs->cmd & NE2K_STOP) {
349         return;
350     }
351
352     if (vnic_rxbuf_full(dev)){
353         PrintDebug("VNIC: received buffer overflow\n");
354         return;
355     }
356
357     // if too small buffer, expand it
358     if (length < MIN_BUF_SIZE) {
359         memcpy(buf, pkt, length);
360         memset(buf + length, 0, MIN_BUF_SIZE - length);
361
362         pkt = buf;
363
364         length = MIN_BUF_SIZE;
365     }
366
367     index = nregs->curpag << 8;
368
369     // 4 bytes header 
370     total_len = length + 4;
371
372     // address for next packet (4 bytes for CRC)
373     next = index + ((total_len + 4 + 255) & ~0xff);
374
375     if (next >= stop) {
376         next -= stop - start;
377     }
378
379     p = nic_state->mem + index;
380     nregs->rsr = ENRSR_RXOK;
381
382     if (pkt[0] & 0x01) {
383         nregs->rsr |= ENRSR_PHY;
384     }
385
386     p[0] = nregs->rsr;
387     p[1] = next >> 8;
388     p[2] = total_len;
389     p[3] = total_len >> 8;
390
391     index += 4;
392
393     while (length > 0) {
394         if (index <= stop) {
395             empty = stop - index;
396         } else {
397             empty = 0;
398         }
399
400         len = length;
401
402         if (len > empty) {
403             len = empty;
404         }
405
406         memcpy(nic_state->mem + index, pkt, len);
407         pkt += len;
408         index += len;
409
410         if (index == stop) {
411             index = start;
412         }
413
414         length -= len;
415     }
416
417     nregs->curpag = next >> 8;
418
419     nregs->isr |= ENISR_RX;
420     vnic_update_irq(dev);
421 }
422
423 // =====begin here
424 #if 0
425 void pci_vnic_init(PCIBus * bus, NICInfo * nd, int devfn)
426 {
427     PCINE2000State * d = NULL;
428     NE2000State * s  = NULL;
429     uint8_t * pci_conf = NULL;
430     struct pci_device * pdev = pci_register_device(bus,
431                                                    "NE2000", sizeof(PCINE2000State),
432                                                    devfn,
433                                                    NULL, NULL);
434     pci_conf = d->dev.config;
435
436     pci_conf[0x00] = 0xec; // Realtek 8029
437     pci_conf[0x01] = 0x10;
438     pci_conf[0x02] = 0x29;
439     pci_conf[0x03] = 0x80;
440     pci_conf[0x0a] = 0x00; // ethernet network controller
441     pci_conf[0x0b] = 0x02;
442     pci_conf[0x0e] = 0x00; // header_type
443     pci_conf[0x3d] = 1; // interrupt pin 0
444
445     pci_register_io_region(&d->dev, 0, 0x100,
446                            PCI_ADDRESS_SPACE_IO, ne2000_map);
447     s = &d->ne2000;
448
449     s->irq = d->dev.irq[0];
450
451     s->pci_dev = (PCIDevice *)d;
452
453     memcpy(s->macaddr, nd->macaddr, 6);
454
455     ne2000_reset(s);
456
457     s->vc = qemu_new_vlan_client(nd->vlan, ne2000_receive,
458                                  ne2000_can_receive, s);
459
460     snprintf(s->vc->info_str, sizeof(s->vc->info_str),
461              "ne2000 pci macaddr=%02x:%02x:%02x:%02x:%02x:%02x",
462              s->macaddr[0],
463              s->macaddr[1],
464              s->macaddr[2],
465              s->macaddr[3],
466              s->macaddr[4],
467              s->macaddr[5]);
468
469     /* XXX: instance number ? */
470     register_savevm("ne2000", 0, 3, ne2000_save, ne2000_load, s);
471 }
472 #endif
473 //End Here====================================
474
475 static int netif_input(uchar_t * pkt, uint_t size) {
476   uint_t i;
477   struct vm_device * dev = NULL;
478   
479   PrintDebug("\nVNIC: Packet Received:\nSource:");
480   
481   for (i = 6; i < 12; i++) {
482       PrintDebug("%x ", pkt[i]);
483   }
484
485   dev = get_rx_dev(pkt);
486
487   if (dev == NULL) {
488       return 0;
489   }
490   PrintDebug("\n");
491
492   for(i = 0; i < size; i++) {
493       PrintDebug("%x ", pkt[i]);
494   }
495
496   vnic_receive(dev, pkt, size);
497
498   return 0;
499 }
500
501
502 static int vnic_ioport_write(ushort_t port,
503                              void * src,
504                              uint_t length,
505                              struct vm_device * dev) {
506     uchar_t  page = 0;
507     struct nic_context *nic_state = (struct nic_context* )dev->private_data;
508     uchar_t val = 0;
509     int index;
510         
511     if (length == 1) {
512         memcpy(&val, src, 1);
513     } else {
514         PrintDebug("vnic_write error: length %d\n", length);  
515         return length;
516     }
517         
518     port &= 0x1f;
519         
520     PrintDebug("vnic_write: port:0x%x (%u bytes): 0x%x\n", port, length, (int)val);
521         
522     if (port == EN0_COMMAND) {
523         nic_state->regs.cmd = val;
524         
525         if (!(val & NE2K_STOP)) {
526             nic_state->regs.isr &= ~ENISR_RESET; 
527
528             if ((val & (NE2K_DMAREAD | NE2K_DMAWRITE)) &&
529                 nic_state->regs.rbcr == 0) {
530                 nic_state->regs.isr |= ENISR_RDC;
531                 vnic_update_irq(dev);
532             }
533
534
535             if (val & NE2K_TRANSMIT) {
536                 index = (nic_state->regs.tpsr << 8);
537
538                 if (index >= NE2K_PMEM_END) {
539                     index -= NE2K_PMEM_SIZE;
540                 }
541
542                 if (index + nic_state->regs.tbcr <= NE2K_PMEM_END) {
543                     vnic_send_packet(dev, nic_state->mem + index, nic_state->regs.tbcr);
544                 }
545
546                 nic_state->regs.tsr = ENTSR_PTX;
547                 nic_state->regs.isr |= ENISR_TX;
548                 nic_state->regs.cmd &= ~NE2K_TRANSMIT;
549
550                 vnic_update_irq(dev);
551             }
552         }
553
554     } else {
555         page = nic_state->regs.cmd >> 6;
556
557         if (page == 0){
558
559             switch(port) {
560                 case EN0_STARTPG:
561                     nic_state->regs.pgstart = val;
562                     break;
563                 case EN0_STOPPG:
564                     nic_state->regs.pgstop = val;
565                     break;
566                 case EN0_BOUNDARY:
567                     nic_state->regs.boundary = val;
568                     break;
569                 case EN0_TPSR:
570                     nic_state->regs.tpsr = val;
571                     break;
572                 case EN0_TCNTLO:
573                     nic_state->regs.tbcr = (nic_state->regs.tbcr & 0xff00) | val;
574                     break;
575                 case EN0_TCNTHI:
576                     nic_state->regs.tbcr = (nic_state->regs.tbcr & 0x00ff) | (val << 8);
577                     break;
578                 case EN0_ISR:
579                     nic_state->regs.isr &= ~(val & 0x7f);
580                     vnic_update_irq(dev);
581                     break;
582                 case EN0_RSARLO:
583                     nic_state->regs.rsar = (nic_state->regs.rsar & 0xff00) | val;
584                     break;
585                 case EN0_RSARHI:
586                     nic_state->regs.rsar = (nic_state->regs.rsar & 0x00ff) | (val << 8);
587                     break;
588                 case EN0_RCNTLO:
589                     nic_state->regs.rbcr = (nic_state->regs.rbcr & 0xff00) | val;
590                     break;
591                 case EN0_RCNTHI:
592                     nic_state->regs.rbcr = (nic_state->regs.rbcr & 0x00ff) | (val << 8);
593                     break;
594                 case EN0_RXCR:
595                     nic_state->regs.rcr = val;
596                     break;
597                 case EN0_TXCR:
598                     nic_state->regs.tcr = val;
599                 case EN0_DCFG:
600                     nic_state->regs.dcr = val;
601                     break;      
602                 case EN0_IMR:
603                     nic_state->regs.imr = val;
604                     vnic_update_irq(dev);
605                     break;
606                 default:
607                     PrintDebug("vnic_write error: invalid port:0x%x\n", port);
608                     break;
609             }
610         }
611
612
613         if (page == 1) {
614
615             switch(port) {
616                 case EN1_PHYS ... EN1_PHYS + 5:
617                     nic_state->regs.phys[port - EN1_PHYS] = val;
618                     break;
619                 case EN1_CURPAG:
620                     nic_state->regs.curpag = val;
621                     break;
622                 case EN1_MULT ... EN1_MULT + 7:
623                     nic_state->regs.mult[port - EN1_MULT] = val;
624                     break;
625                 default:
626                     PrintDebug("vnic_write error: invalid port:0x%x\n", port);
627                     break;
628             }
629         }
630
631
632         if (page == 2) {
633
634             switch(port) {
635                 case EN2_LDMA0:
636                     nic_state->regs.clda = (nic_state->regs.clda & 0xff00) | val;
637                     break;
638                 case EN2_LDMA1:
639                     nic_state->regs.clda = (nic_state->regs.clda & 0x00ff) | (val << 8);
640                     break;
641                 case EN2_RNPR:
642                     nic_state->regs.rnpp = val;
643                     break;
644                 case EN2_LNRP:
645                     nic_state->regs.lnpp = val;
646                     break;
647                 case EN2_ACNT0:
648                     nic_state->regs.addcnt = (nic_state->regs.addcnt & 0xff00) | val;
649                     break;
650                 case EN2_ACNT1: 
651                     nic_state->regs.addcnt = (nic_state->regs.addcnt & 0x00ff) | (val << 8);
652                     break;
653                 default:
654                     PrintDebug("vnic_write error: invalid port:0x%x\n", port);
655                     break;
656             }
657         }
658     }
659
660     //dump_state(dev);
661         
662     return length;
663         
664 }
665
666 static int vnic_ioport_read(ushort_t port, void * dst, uint_t length, struct vm_device *dev) {
667     uchar_t page = 0;
668     int val = 0;
669
670     struct nic_context *nic_state = (struct nic_context* )dev->private_data;
671
672     if (length > 1) {
673         PrintDebug("vnic_read error: length %d\n", length);
674         valurn length;
675     }
676
677     port &= 0x1f;
678
679     if (port == EN0_COMMAND) {
680         val = nic_state->regs.cmd;
681     } else {
682         page = nic_state->regs.cmd >> 6;
683
684         if (page == 0) {
685
686             switch (port) {             
687                 case EN0_CLDALO:
688                     val = nic_state->regs.clda & 0x00ff;
689                     break;
690                 case EN0_CLDAHI:
691                     val = (nic_state->regs.clda & 0xff00) >> 8;
692                     break;
693                 case EN0_BOUNDARY:
694                     val = nic_state->regs.boundary;
695                     break;
696                 case EN0_TSR:
697                     val = nic_state->regs.tsr;
698                     break;
699                 case EN0_NCR:
700                     val = nic_state->regs.ncr;
701                     break;
702                 case EN0_FIFO:
703                     val = nic_state->regs.fifo;
704                     break;
705                 case EN0_ISR:
706                     val = nic_state->regs.isr;
707                     vnic_update_irq(dev);
708                     break;
709                 case EN0_CRDALO:
710                     val = nic_state->regs.crda & 0x00ff;
711                     break;
712                 case EN0_CRDAHI:
713                     val = (nic_state->regs.crda & 0xff00) >> 8;
714                     break;
715                 case EN0_RSR:
716                     val = nic_state->regs.rsr;
717                     break;
718                 case EN0_COUNTER0:
719                     val = nic_state->regs.cntr & 0x000000ff;
720                     break;
721                 case EN0_COUNTER1:
722                     val = (nic_state->regs.cntr & 0x0000ff00) >> 8;
723                     break;      
724                 case EN0_COUNTER2:
725                     val = (nic_state->regs.cntr & 0x00ff0000) >> 16;
726                     break;
727                 default:
728                     PrintDebug("vnic_read error: invalid port:0x%x\n", port);
729                     val = 0x00;
730                     break;
731             }
732
733         } else if (page == 1) {
734
735             switch(port) {
736                 case EN1_PHYS ... EN1_PHYS + 5:
737                     val = nic_state->regs.phys[port - EN1_PHYS];
738                     break;
739                 case EN1_CURPAG:
740                     val = nic_state->regs.curpag;
741                     break;
742                 case EN1_MULT ... EN1_MULT + 7:
743                     val = nic_state->regs.mult[port - EN1_MULT];
744                     break;
745                 default:
746                     PrintDebug("vnic_read error: invalid port:0x%x\n", port);
747                     val = 0x00;
748                     break;
749             }
750
751         } else if (page == 2) {
752
753             switch(port) {
754                 case EN2_STARTPG:
755                     val = nic_state->regs.pgstart;
756                     break;
757                 case EN2_STOPPG:
758                     val = nic_state->regs.pgstop;
759                     break;
760                 case EN2_RNPR:
761                     val = nic_state->regs.rnpp;
762                     break;
763                 case EN2_LNRP:
764                     val = nic_state->regs.lnpp;
765                     break;
766                 case EN2_TPSR:
767                     val = nic_state->regs.tpsr;
768                     break;
769                 case EN2_ACNT0:
770                     val = nic_state->regs.addcnt & 0x00ff;
771                     break;
772                 case EN2_ACNT1: 
773                     val = (nic_state->regs.addcnt & 0xff00) >> 8;
774                     break;
775                 case EN2_RCR:
776                     val = nic_state->regs.rcr;
777                     break;
778                 case EN2_TCR:
779                     val = nic_state->regs.tcr;
780                     break;
781                 case EN2_DCR:
782                     val = nic_state->regs.dcr;
783                     break;
784                 case EN2_IMR:
785                     val = nic_state->regs.imr;
786                     break;
787                 default:
788                     PrintDebug("vnic_read error: invalid port:0x%x\n", port);
789                     val = 0x00;
790                     break;
791             }
792         }
793     }
794
795     memcpy(dst, &val, 1);
796
797     PrintDebug("vnic_read: port:0x%x (%u bytes): 0x%x\n", port,length, (uint32_t)val);
798
799     //dump_state(dev);
800
801     return length;
802
803 }
804
805
806
807
808 static void vnic_dma_update(struct vm_device * dev, int len) {          
809     struct nic_context *nic_state = (struct nic_context *)dev->private_data;
810         
811     nic_state->regs.rsar += len;
812     // wrap
813
814     if (nic_state->regs.rsar == nic_state->regs.pgstop) {
815         nic_state->regs.rsar = nic_state->regs.pgstart;
816     }
817
818     if (nic_state->regs.rbcr <= len) {
819         nic_state->regs.rbcr = 0;
820         nic_state->regs.isr |= ENISR_RDC;
821
822         vnic_update_irq(dev);
823     } else {
824         nic_state->regs.rbcr -= len;
825     }
826 }
827
828
829 //for data port read/write
830 static int vnic_data_read(ushort_t port,
831                           void * dst,
832                           uint_t length,
833                           struct vm_device * dev) {
834     uint32_t val = 0;
835     struct nic_context *nic_state = (struct nic_context *)dev->private_data;
836
837     // current dma address
838     uint32_t addr = nic_state->regs.rsar;
839
840     switch (length) {
841         case 1:
842             val = vnic_mem_readb(nic_state, addr);
843             break;
844         case 2:
845             val = vnic_mem_readw(nic_state, addr);
846             break;
847         case 4:
848             val = vnic_mem_readl(nic_state, addr);
849             break;
850         default:
851             PrintDebug("vnic_data_read error: invalid length %d\n", length);
852             val = 0x0;
853     }
854
855     vnic_dma_update(dev, length);
856
857     memcpy(dst, &val, length);
858
859     PrintDebug("vnic_read: port:0x%x (%u bytes): 0x%x", port & 0x1f,length, val);
860
861     return length;
862 }
863
864 static int vnic_data_write(ushort_t port,
865                            void * src,
866                            uint_t length,
867                            struct vm_device * dev) {
868     uint32_t val = 0;
869     struct nic_context * nic_state = (struct nic_context *)dev->private_data;
870
871     uint32_t addr = nic_state->regs.rsar;
872
873     if (nic_state->regs.rbcr == 0) {
874         return length;
875     }
876
877     memcpy(&val, src, length);
878
879     //determine the starting address of reading/writing
880     //addr= ??
881         
882     switch (length) {
883         case 1:
884             vnic_mem_writeb(nic_state, addr, val);
885             break;
886         case 2:
887             vnic_mem_writew(nic_state, addr, val);
888             break;
889         case 4:
890             vnic_mem_writel(nic_state, addr, val);
891             break;
892         default:
893             PrintDebug("nic_data_write error: invalid length %d\n", length);
894     }
895         
896     vnic_dma_update(dev, length);
897
898     PrintDebug("vnic_write: port:0x%x (%u bytes): 0x%x\n", port & 0x1f,length, val);
899                         
900     return length;
901 }
902
903 static int vnic_reset_device(struct vm_device * dev) {
904   
905     PrintDebug("vnic: reset device\n");
906
907     init_vnic_context(dev);
908
909     return 0;
910 }
911
912
913 //for 0xc11f port
914 static int vnic_reset_port_read(ushort_t port, void * dst, uint_t length, struct vm_device * dev) {
915     uint32_t val = 0;
916
917     PrintDebug("vnic_read: port:0x%x (%u bytes): 0x%x\n", port,length, val);
918     memcpy(dst, &val, length);
919
920     vnic_reset_device(dev);
921
922     return length;
923 }
924
925 static int vnic_reset_port_write(ushort_t port, void * src, uint_t length, struct vm_device * dev) {
926     uint32_t val = 0;
927
928     PrintDebug("vnic_write: port:0x%x (%u bytes): 0x%x\n", port,length, val);
929     memcpy(&val, src, length);
930                         
931     return length;
932 }
933
934
935 static int vnic_start_device(struct vm_device * dev) {
936     PrintDebug("vnic: start device\n");  
937     return 0;
938 }
939
940
941 static int vnic_stop_device(struct vm_device * dev) {
942     PrintDebug("vnic: stop device\n");
943     return 0;
944 }
945
946 static void  init_phy_network() {       
947     V3_REGISTER_PKT_DELIVERY(&netif_input);
948 }
949
950 static int vnic_init_device(struct vm_device * dev) {
951   int i;
952
953   PrintDebug("vnic: init_device\n");
954
955   init_phy_network();
956   init_vnic_context(dev);
957
958   current_vnic = dev;  
959
960   for (i = 0; i < 16; i++) {    
961       v3_dev_hook_io(dev, NIC_BASE_ADDR + i, &vnic_ioport_read, &vnic_ioport_write);
962   }
963
964   v3_dev_hook_io(dev, NIC_BASE_ADDR + NIC_DATA_PORT, &vnic_data_read, &vnic_data_write);
965   v3_dev_hook_io(dev, NIC_BASE_ADDR + NIC_RESET_PORT, &vnic_reset_port_read, &vnic_reset_port_write);
966
967   return 0;
968 }
969
970
971
972 static int vnic_deinit_device(struct vm_device * dev) {
973     int i;
974   
975     for (i = 0; i < 16; i++){           
976         v3_dev_unhook_io(dev, NIC_BASE_ADDR + i);
977     }
978
979     v3_dev_unhook_io(dev, NIC_BASE_ADDR + NIC_DATA_PORT);
980     v3_dev_unhook_io(dev, NIC_BASE_ADDR + NIC_RESET_PORT);
981
982     //vnic_reset_device(dev);
983   
984     return 0;
985 }
986
987
988 static struct vm_device_ops dev_ops = { 
989     .init = vnic_init_device, 
990     .deinit = vnic_deinit_device,
991     .reset = vnic_reset_device,
992     .start = vnic_start_device,
993     .stop = vnic_stop_device,
994 };
995
996
997 struct vm_device * v3_create_vnic() {
998     struct nic_context * nic_state = V3_Malloc(sizeof(struct nic_context));
999
1000     //memset(nic_state, 0, sizeof(struct nic_context));
1001
1002     //PrintDebug("VNIC internal at %x\n",(int)nic_state);
1003
1004     struct vm_device *device = v3_create_device("VNIC", &dev_ops, nic_state);
1005
1006     return device;
1007 }
1008