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.


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