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.


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