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.


e6c12a957abff8effa7318b479575c2914c2ea55
[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
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                           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
491   PrintDebug("\n");
492
493   for(i = 0; i < size; i++) {
494       PrintDebug("%x ", pkt[i]);
495   }
496
497   vnic_receive(dev, pkt, size);
498
499   return 0;
500 }
501
502
503 static int vnic_ioport_write(ushort_t port,
504                              void * src,
505                              uint_t length,
506                              struct vm_device * dev) {
507     uchar_t  page = 0;
508     struct nic_context *nic_state = (struct nic_context* )dev->private_data;
509     uchar_t val = 0;
510     int index;
511         
512     if (length == 1) {
513         memcpy(&val, src, 1);
514     } else {
515         PrintDebug("vnic_write error: length %d\n", length);  
516         return length;
517     }
518         
519     port &= 0x1f;
520         
521     PrintDebug("vnic_write: port:0x%x (%u bytes): 0x%x\n", port, length, (int)val);
522         
523     if (port == EN0_COMMAND) {
524         nic_state->regs.cmd = val;
525         
526         if (!(val & NE2K_STOP)) {
527             nic_state->regs.isr &= ~ENISR_RESET; 
528
529             if ((val & (NE2K_DMAREAD | NE2K_DMAWRITE)) &&
530                 nic_state->regs.rbcr == 0) {
531                 nic_state->regs.isr |= ENISR_RDC;
532                 vnic_update_irq(dev);
533             }
534
535
536             if (val & NE2K_TRANSMIT) {
537                 index = (nic_state->regs.tpsr << 8);
538
539                 if (index >= NE2K_PMEM_END) {
540                     index -= NE2K_PMEM_SIZE;
541                 }
542
543                 if (index + nic_state->regs.tbcr <= NE2K_PMEM_END) {
544                     vnic_send_packet(dev, nic_state->mem + index, nic_state->regs.tbcr);
545                 }
546
547                 nic_state->regs.tsr = ENTSR_PTX;
548                 nic_state->regs.isr |= ENISR_TX;
549                 nic_state->regs.cmd &= ~NE2K_TRANSMIT;
550
551                 vnic_update_irq(dev);
552             }
553         }
554
555     } else {
556         page = nic_state->regs.cmd >> 6;
557
558         if (page == 0){
559
560             switch(port) {
561                 case EN0_STARTPG:
562                     nic_state->regs.pgstart = val;
563                     break;
564                 case EN0_STOPPG:
565                     nic_state->regs.pgstop = val;
566                     break;
567                 case EN0_BOUNDARY:
568                     nic_state->regs.boundary = val;
569                     break;
570                 case EN0_TPSR:
571                     nic_state->regs.tpsr = val;
572                     break;
573                 case EN0_TCNTLO:
574                     nic_state->regs.tbcr = (nic_state->regs.tbcr & 0xff00) | val;
575                     break;
576                 case EN0_TCNTHI:
577                     nic_state->regs.tbcr = (nic_state->regs.tbcr & 0x00ff) | (val << 8);
578                     break;
579                 case EN0_ISR:
580                     nic_state->regs.isr &= ~(val & 0x7f);
581                     vnic_update_irq(dev);
582                     break;
583                 case EN0_RSARLO:
584                     nic_state->regs.rsar = (nic_state->regs.rsar & 0xff00) | val;
585                     break;
586                 case EN0_RSARHI:
587                     nic_state->regs.rsar = (nic_state->regs.rsar & 0x00ff) | (val << 8);
588                     break;
589                 case EN0_RCNTLO:
590                     nic_state->regs.rbcr = (nic_state->regs.rbcr & 0xff00) | val;
591                     break;
592                 case EN0_RCNTHI:
593                     nic_state->regs.rbcr = (nic_state->regs.rbcr & 0x00ff) | (val << 8);
594                     break;
595                 case EN0_RXCR:
596                     nic_state->regs.rcr = val;
597                     break;
598                 case EN0_TXCR:
599                     nic_state->regs.tcr = val;
600                 case EN0_DCFG:
601                     nic_state->regs.dcr = val;
602                     break;      
603                 case EN0_IMR:
604                     nic_state->regs.imr = val;
605                     vnic_update_irq(dev);
606                     break;
607                 default:
608                     PrintDebug("vnic_write error: invalid port:0x%x\n", port);
609                     break;
610             }
611
612         } else if (page == 1) {
613
614             switch(port) {
615                 case EN1_PHYS ... EN1_PHYS + 5:
616                     nic_state->regs.phys[port - EN1_PHYS] = val;
617                     break;
618                 case EN1_CURPAG:
619                     nic_state->regs.curpag = val;
620                     break;
621                 case EN1_MULT ... EN1_MULT + 7:
622                     nic_state->regs.mult[port - EN1_MULT] = val;
623                     break;
624                 default:
625                     PrintDebug("vnic_write error: invalid port:0x%x\n", port);
626                     break;
627             }
628
629         } else if (page == 2) {
630
631             switch(port) {
632                 case EN2_LDMA0:
633                     nic_state->regs.clda = (nic_state->regs.clda & 0xff00) | val;
634                     break;
635                 case EN2_LDMA1:
636                     nic_state->regs.clda = (nic_state->regs.clda & 0x00ff) | (val << 8);
637                     break;
638                 case EN2_RNPR:
639                     nic_state->regs.rnpp = val;
640                     break;
641                 case EN2_LNRP:
642                     nic_state->regs.lnpp = val;
643                     break;
644                 case EN2_ACNT0:
645                     nic_state->regs.addcnt = (nic_state->regs.addcnt & 0xff00) | val;
646                     break;
647                 case EN2_ACNT1: 
648                     nic_state->regs.addcnt = (nic_state->regs.addcnt & 0x00ff) | (val << 8);
649                     break;
650                 default:
651                     PrintDebug("vnic_write error: invalid port:0x%x\n", port);
652                     break;
653             }
654         }
655     }
656
657     //dump_state(dev);
658         
659     return length;
660         
661 }
662
663 static int vnic_ioport_read(ushort_t port, void * dst, uint_t length, struct vm_device *dev) {
664     uchar_t page = 0;
665     int val = 0;
666
667     struct nic_context *nic_state = (struct nic_context* )dev->private_data;
668
669     if (length > 1) {
670         PrintDebug("vnic_read error: length %d\n", length);
671         valurn length;
672     }
673
674     port &= 0x1f;
675
676     if (port == EN0_COMMAND) {
677         val = nic_state->regs.cmd;
678     } else {
679         page = nic_state->regs.cmd >> 6;
680
681         if (page == 0) {
682
683             switch (port) {             
684                 case EN0_CLDALO:
685                     val = nic_state->regs.clda & 0x00ff;
686                     break;
687                 case EN0_CLDAHI:
688                     val = (nic_state->regs.clda & 0xff00) >> 8;
689                     break;
690                 case EN0_BOUNDARY:
691                     val = nic_state->regs.boundary;
692                     break;
693                 case EN0_TSR:
694                     val = nic_state->regs.tsr;
695                     break;
696                 case EN0_NCR:
697                     val = nic_state->regs.ncr;
698                     break;
699                 case EN0_FIFO:
700                     val = nic_state->regs.fifo;
701                     break;
702                 case EN0_ISR:
703                     val = nic_state->regs.isr;
704                     vnic_update_irq(dev);
705                     break;
706                 case EN0_CRDALO:
707                     val = nic_state->regs.crda & 0x00ff;
708                     break;
709                 case EN0_CRDAHI:
710                     val = (nic_state->regs.crda & 0xff00) >> 8;
711                     break;
712                 case EN0_RSR:
713                     val = nic_state->regs.rsr;
714                     break;
715                 case EN0_COUNTER0:
716                     val = nic_state->regs.cntr & 0x000000ff;
717                     break;
718                 case EN0_COUNTER1:
719                     val = (nic_state->regs.cntr & 0x0000ff00) >> 8;
720                     break;      
721                 case EN0_COUNTER2:
722                     val = (nic_state->regs.cntr & 0x00ff0000) >> 16;
723                     break;
724                 default:
725                     PrintDebug("vnic_read error: invalid port:0x%x\n", port);
726                     val = 0x00;
727                     break;
728             }
729
730         } else if (page == 1) {
731
732             switch(port) {
733                 case EN1_PHYS ... EN1_PHYS + 5:
734                     val = nic_state->regs.phys[port - EN1_PHYS];
735                     break;
736                 case EN1_CURPAG:
737                     val = nic_state->regs.curpag;
738                     break;
739                 case EN1_MULT ... EN1_MULT + 7:
740                     val = nic_state->regs.mult[port - EN1_MULT];
741                     break;
742                 default:
743                     PrintDebug("vnic_read error: invalid port:0x%x\n", port);
744                     val = 0x00;
745                     break;
746             }
747
748         } else if (page == 2) {
749
750             switch(port) {
751                 case EN2_STARTPG:
752                     val = nic_state->regs.pgstart;
753                     break;
754                 case EN2_STOPPG:
755                     val = nic_state->regs.pgstop;
756                     break;
757                 case EN2_RNPR:
758                     val = nic_state->regs.rnpp;
759                     break;
760                 case EN2_LNRP:
761                     val = nic_state->regs.lnpp;
762                     break;
763                 case EN2_TPSR:
764                     val = nic_state->regs.tpsr;
765                     break;
766                 case EN2_ACNT0:
767                     val = nic_state->regs.addcnt & 0x00ff;
768                     break;
769                 case EN2_ACNT1: 
770                     val = (nic_state->regs.addcnt & 0xff00) >> 8;
771                     break;
772                 case EN2_RCR:
773                     val = nic_state->regs.rcr;
774                     break;
775                 case EN2_TCR:
776                     val = nic_state->regs.tcr;
777                     break;
778                 case EN2_DCR:
779                     val = nic_state->regs.dcr;
780                     break;
781                 case EN2_IMR:
782                     val = nic_state->regs.imr;
783                     break;
784                 default:
785                     PrintDebug("vnic_read error: invalid port:0x%x\n", port);
786                     val = 0x00;
787                     break;
788             }
789         }
790     }
791
792     memcpy(dst, &val, 1);
793
794     PrintDebug("vnic_read: port:0x%x (%u bytes): 0x%x\n", port,length, (uint32_t)val);
795
796     //dump_state(dev);
797
798     return length;
799
800 }
801
802
803
804
805 static void vnic_dma_update(struct vm_device * dev, int len) {          
806     struct nic_context *nic_state = (struct nic_context *)dev->private_data;
807         
808     nic_state->regs.rsar += len;
809     // wrap
810
811     if (nic_state->regs.rsar == nic_state->regs.pgstop) {
812         nic_state->regs.rsar = nic_state->regs.pgstart;
813     }
814
815     if (nic_state->regs.rbcr <= len) {
816         nic_state->regs.rbcr = 0;
817         nic_state->regs.isr |= ENISR_RDC;
818
819         vnic_update_irq(dev);
820     } else {
821         nic_state->regs.rbcr -= len;
822     }
823 }
824
825
826 //for data port read/write
827 static int vnic_data_read(ushort_t port,
828                           void * dst,
829                           uint_t length,
830                           struct vm_device * dev) {
831     uint32_t val = 0;
832     struct nic_context *nic_state = (struct nic_context *)dev->private_data;
833
834     // current dma address
835     uint32_t addr = nic_state->regs.rsar;
836
837     switch (length) {
838         case 1:
839             val = vnic_mem_readb(nic_state, addr);
840             break;
841         case 2:
842             val = vnic_mem_readw(nic_state, addr);
843             break;
844         case 4:
845             val = vnic_mem_readl(nic_state, addr);
846             break;
847         default:
848             PrintDebug("vnic_data_read error: invalid length %d\n", length);
849             val = 0x0;
850     }
851
852     vnic_dma_update(dev, length);
853
854     memcpy(dst, &val, length);
855
856     PrintDebug("vnic_read: port:0x%x (%u bytes): 0x%x", port & 0x1f, length, val);
857
858     return length;
859 }
860
861 static int vnic_data_write(ushort_t port,
862                            void * src,
863                            uint_t length,
864                            struct vm_device * dev) {
865     uint32_t val = 0;
866     struct nic_context * nic_state = (struct nic_context *)dev->private_data;
867
868     uint32_t addr = nic_state->regs.rsar;
869
870     if (nic_state->regs.rbcr == 0) {
871         return length;
872     }
873
874     memcpy(&val, src, length);
875
876     //determine the starting address of reading/writing
877     //addr= ??
878         
879     switch (length) {
880         case 1:
881             vnic_mem_writeb(nic_state, addr, val);
882             break;
883         case 2:
884             vnic_mem_writew(nic_state, addr, val);
885             break;
886         case 4:
887             vnic_mem_writel(nic_state, addr, val);
888             break;
889         default:
890             PrintDebug("nic_data_write error: invalid length %d\n", length);
891     }
892         
893     vnic_dma_update(dev, length);
894
895     PrintDebug("vnic_write: port:0x%x (%u bytes): 0x%x\n", port & 0x1f,length, val);
896                         
897     return length;
898 }
899
900 static int vnic_reset_device(struct vm_device * dev) {
901   
902     PrintDebug("vnic: reset device\n");
903
904     init_vnic_context(dev);
905
906     return 0;
907 }
908
909
910 //for 0xc11f port
911 static int vnic_reset_port_read(ushort_t port, void * dst, uint_t length, struct vm_device * dev) {
912     uint32_t val = 0;
913
914     PrintDebug("vnic_read: port:0x%x (%u bytes): 0x%x\n", port,length, val);
915     memcpy(dst, &val, length);
916
917     vnic_reset_device(dev);
918
919     return length;
920 }
921
922 static int vnic_reset_port_write(ushort_t port, void * src, uint_t length, struct vm_device * dev) {
923     uint32_t val = 0;
924
925     PrintDebug("vnic_write: port:0x%x (%u bytes): 0x%x\n", port,length, val);
926     memcpy(&val, src, length);
927                         
928     return length;
929 }
930
931
932 static int vnic_start_device(struct vm_device * dev) {
933     PrintDebug("vnic: start device\n");  
934     return 0;
935 }
936
937
938 static int vnic_stop_device(struct vm_device * dev) {
939     PrintDebug("vnic: stop device\n");
940     return 0;
941 }
942
943 static void  init_phy_network() {       
944     V3_REGISTER_PKT_DELIVERY(&netif_input);
945 }
946
947 static int vnic_init_device(struct vm_device * dev) {
948   int i;
949
950   PrintDebug("vnic: init_device\n");
951
952   init_phy_network();
953   init_vnic_context(dev);
954
955   current_vnic = dev;  
956
957   for (i = 0; i < 16; i++) {    
958       v3_dev_hook_io(dev, NIC_BASE_ADDR + i, &vnic_ioport_read, &vnic_ioport_write);
959   }
960
961   v3_dev_hook_io(dev, NIC_BASE_ADDR + NIC_DATA_PORT, &vnic_data_read, &vnic_data_write);
962   v3_dev_hook_io(dev, NIC_BASE_ADDR + NIC_RESET_PORT, &vnic_reset_port_read, &vnic_reset_port_write);
963
964   return 0;
965 }
966
967
968
969 static int vnic_deinit_device(struct vm_device * dev) {
970     int i;
971   
972     for (i = 0; i < 16; i++){           
973         v3_dev_unhook_io(dev, NIC_BASE_ADDR + i);
974     }
975
976     v3_dev_unhook_io(dev, NIC_BASE_ADDR + NIC_DATA_PORT);
977     v3_dev_unhook_io(dev, NIC_BASE_ADDR + NIC_RESET_PORT);
978
979     //vnic_reset_device(dev);
980   
981     return 0;
982 }
983
984
985 static struct vm_device_ops dev_ops = { 
986     .init = vnic_init_device, 
987     .deinit = vnic_deinit_device,
988     .reset = vnic_reset_device,
989     .start = vnic_start_device,
990     .stop = vnic_stop_device,
991 };
992
993
994 struct vm_device * v3_create_vnic() {
995     struct nic_context * nic_state = V3_Malloc(sizeof(struct nic_context));
996
997     //memset(nic_state, 0, sizeof(struct nic_context));
998
999     //PrintDebug("VNIC internal at %x\n",(int)nic_state);
1000
1001     struct vm_device *device = v3_create_device("VNIC", &dev_ops, nic_state);
1002
1003     return device;
1004 }
1005