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.


Apply Zheng's 64bit pci passthrough patch
[palacios.git] / palacios / src / devices / pci_passthrough.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) 2008, Jack Lange <jarusl@cs.northwestern.edu>
11  * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org> 
12  * All rights reserved.
13  *
14  * Author: Jack Lange <jarusl@cs.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 /* This is the generic passthrough PCI virtual device */
22
23 /* 
24  * The basic idea is that we do not change the hardware PCI configuration
25  * Instead we modify the guest environment to map onto the physical configuration
26  * 
27  * The pci subsystem handles most of the configuration space, except for the bar registers.
28  * We handle them here, by either letting them go directly to hardware or remapping through virtual hooks
29  * 
30  * Memory Bars are always remapped via the shadow map, 
31  * IO Bars are selectively remapped through hooks if the guest changes them 
32  */
33
34 #include <palacios/vmm.h>
35 #include <palacios/vmm_dev_mgr.h>
36 #include <palacios/vmm_sprintf.h>
37 #include <palacios/vmm_lowlevel.h>
38 #include <palacios/vm_guest.h> // must include this to avoid dependency issue
39 #include <palacios/vmm_symspy.h>
40
41 #include <devices/pci.h>
42 #include <devices/pci_types.h>
43
44 // Hardcoded... Are these standard??
45 #define PCI_CFG_ADDR    0xcf8
46 #define PCI_CFG_DATA    0xcfc
47
48 #define PCI_BUS_MAX  7
49 #define PCI_DEV_MAX 32
50 #define PCI_FN_MAX   7
51
52 #define PCI_DEVICE 0x0
53 #define PCI_PCI_BRIDGE 0x1
54 #define PCI_CARDBUS_BRIDGE 0x2
55
56 #define PCI_HDR_SIZE 256
57
58
59 union pci_addr_reg {
60     uint32_t value;
61     struct {
62         uint_t rsvd1   : 2;
63         uint_t reg     : 6;
64         uint_t func    : 3;
65         uint_t dev     : 5;
66         uint_t bus     : 8;
67         uint_t rsvd2   : 7;
68         uint_t enable  : 1;
69     } __attribute__((packed));
70 } __attribute__((packed));
71
72
73 typedef enum { PT_BAR_NONE,
74                PT_BAR_IO, 
75                PT_BAR_MEM32, 
76                PT_BAR_MEM24, 
77                PT_BAR_MEM64_LOW, 
78                PT_BAR_MEM64_HIGH } pt_bar_type_t;
79
80 struct pt_bar {
81     uint32_t size;
82     pt_bar_type_t type;
83     uint32_t addr;
84
85     uint32_t val;
86 };
87
88
89 //Zheng 03/15/2010
90 struct pt_exp_rom_base {
91     uint32_t size;
92     uint32_t addr;
93     uint32_t val;
94 };
95
96 struct pt_dev_state {
97     union {
98         uint8_t config_space[256];
99         struct pci_config_header real_hdr;
100     } __attribute__((packed));
101
102     struct pt_bar phys_bars[6];
103     struct pt_bar virt_bars[6];
104
105    //Zheng 03/19/2010
106     struct pt_exp_rom_base phys_exp_rom_base;
107     struct pt_exp_rom_base virt_exp_rom_base;
108      
109     struct vm_device * pci_bus;
110     struct pci_device * pci_dev;
111
112     union pci_addr_reg phys_pci_addr;
113
114     char name[32];
115 };
116
117
118 static inline uint32_t pci_cfg_read32(uint32_t addr) {
119     v3_outdw(PCI_CFG_ADDR, addr);
120     return v3_indw(PCI_CFG_DATA);
121 }
122
123
124
125 static inline void pci_cfg_write32(uint32_t addr, uint32_t val) {
126     v3_outdw(PCI_CFG_ADDR, addr);
127     v3_outdw(PCI_CFG_DATA, val);
128 }
129
130
131
132 static inline uint16_t pci_cfg_read16(uint32_t addr) {
133     v3_outw(PCI_CFG_ADDR, addr);
134     return v3_inw(PCI_CFG_DATA);
135 }
136
137
138
139 static inline void pci_cfg_write16(uint32_t addr, uint16_t val) {
140     v3_outw(PCI_CFG_ADDR, addr);
141     v3_outw(PCI_CFG_DATA, val);
142 }
143
144
145
146 static inline uint8_t pci_cfg_read8(uint32_t addr) {
147     v3_outb(PCI_CFG_ADDR, addr);
148     return v3_inb(PCI_CFG_DATA);
149 }
150
151
152
153 static inline void pci_cfg_write8(uint32_t addr, uint8_t val) {
154     v3_outb(PCI_CFG_ADDR, addr);
155     v3_outb(PCI_CFG_DATA, val);
156 }
157
158
159 //Zheng: 03/15/2010
160 static inline bool is_pci_mem64_high_bar(struct pt_bar *prev_pbar)
161 {
162     return ((prev_pbar) && 
163             (prev_pbar->type == PT_BAR_MEM64_LOW));
164 }
165
166
167 //Zheng: 03/19/2010
168 static int pci_exp_rom_base_init(struct pci_device *pci_dev) {
169
170     struct vm_device *dev = (struct vm_device *)(pci_dev->priv_data);   
171     struct pt_dev_state * state = (struct pt_dev_state *)dev->private_data;
172     const uint32_t exp_rom_base_reg = 12;
173     union pci_addr_reg pci_addr = {state->phys_pci_addr.value};
174     uint32_t exp_rom_base_val = 0;
175     uint32_t max_val = 0;
176
177     uint32_t *dst = ((uint32_t *)(&(pci_dev->config_space[4 * exp_rom_base_reg])));
178
179     struct pt_exp_rom_base *pexp_rom_base = &(state->phys_exp_rom_base);
180     //    struct pt_exp_rom_base *vexp_rom_base = &(state->virt_exp_rom_base);
181
182     // should read from cached header
183     pci_addr.reg = exp_rom_base_reg;
184
185     exp_rom_base_val = pci_cfg_read32(pci_addr.value);
186     pexp_rom_base->val = exp_rom_base_val; 
187
188     max_val = exp_rom_base_val | PCI_EXP_ROM_BASE_MASK;
189     
190     // Cycle the physical bar, to determine the actual size
191     // Disable irqs, to try to prevent accesses to the space via a interrupt handler
192     // This is not SMP safe!!
193     // What we probably want to do is write a 0 to the command register
194     //irq_state = v3_irq_save();
195     
196     pci_cfg_write32(pci_addr.value, max_val);
197     max_val = pci_cfg_read32(pci_addr.value);
198     pci_cfg_write32(pci_addr.value, exp_rom_base_val);
199     
200     //v3_irq_restore(irq_state);
201     
202     
203     if (max_val == 0) {
204         PrintDebug("The real device doesn't implement the Exp_Rom_Base\n");
205     } else {
206         
207         // if its a memory region, setup passthrough mem mapping
208         pexp_rom_base->addr = PCI_EXP_ROM_BASE(exp_rom_base_val);
209         pexp_rom_base->size = ~PCI_EXP_ROM_BASE(max_val) + 1;
210         
211         PrintDebug("Adding 32 bit PCI mem region: start=0x%x, end=0x%x\n",
212                    pexp_rom_base->addr, pexp_rom_base->addr + pexp_rom_base->size);
213
214         v3_add_shadow_mem(dev->vm, V3_MEM_CORE_ANY, 
215                           pexp_rom_base->addr, 
216                           pexp_rom_base->addr + pexp_rom_base->size - 1,
217                           pexp_rom_base->addr);
218     }
219     
220
221     // Initially the virtual bars match the physical ones
222     memcpy(&(state->virt_exp_rom_base), &(state->phys_exp_rom_base), sizeof(struct pt_exp_rom_base));
223
224     PrintDebug("exp_rom_base_val=0x%x\n", exp_rom_base_val);
225
226     PrintDebug("phys exp_rom_base: addr=0x%x, size=%u\n", 
227                pexp_rom_base->addr, 
228                pexp_rom_base->size);
229
230     PrintDebug("virt exp_rom_base: addr=0x%x, size=%u\n",
231                state->virt_exp_rom_base.addr, 
232                state->virt_exp_rom_base.size);
233
234
235     // Update the pci subsystem versions
236     *dst = exp_rom_base_val;
237
238     return 0;
239 }
240
241
242 // We initialize this 
243 static int pci_bar_init(int bar_num, uint32_t * dst, void * private_data) {
244     struct vm_device * dev = (struct vm_device *)private_data;
245     struct pt_dev_state * state = (struct pt_dev_state *)dev->private_data;
246     const uint32_t bar_base_reg = 4;
247     union pci_addr_reg pci_addr = {state->phys_pci_addr.value};
248     uint32_t bar_val = 0;
249     uint32_t max_val = 0;
250     //addr_t irq_state = 0;
251     struct pt_bar * pbar = &(state->phys_bars[bar_num]);
252     //    struct pt_bar * vbar = &(state->virt_bars[bar_num]);
253
254     struct pt_bar *prev_pbar = bar_num > 0 ? 
255         (&(state->phys_bars[bar_num - 1])) :
256         NULL;
257
258     struct pt_bar *prev_vbar = bar_num > 0 ? 
259         (&(state->virt_bars[bar_num - 1])) :
260         NULL;
261
262     // should read from cached header
263     pci_addr.reg = bar_base_reg + bar_num;
264
265     PrintDebug("PCI Address = 0x%x\n", pci_addr.value);
266
267     bar_val = pci_cfg_read32(pci_addr.value);
268     pbar->val = bar_val; 
269
270     if (is_pci_mem64_high_bar(prev_pbar)) {
271
272         max_val = PCI_MEM64_HIGH_MASK32;
273
274         pci_cfg_write32(pci_addr.value, max_val);
275         max_val = pci_cfg_read32(pci_addr.value);
276         pci_cfg_write32(pci_addr.value, bar_val);
277
278         pbar->type = PT_BAR_MEM64_HIGH;
279         pbar->addr = PCI_MEM64_BASE_HIGH(bar_val);
280
281         uint64_t mem64_bar_size = 
282             (~(PCI_MEM64_BASE((((uint64_t)max_val) << PCI_MEM64_BASE_HIGH_SHIFT) | (prev_pbar->size)))) + 1;
283         
284
285         pbar->size = 
286             (mem64_bar_size >> PCI_MEM64_BASE_HIGH_SHIFT) & 
287             PCI_MEM64_HIGH_MASK32;
288         prev_pbar->size = (uint32_t)mem64_bar_size;
289         prev_vbar->size = (uint32_t)mem64_bar_size;
290
291         uint64_t mem64_addr = 
292             (((uint64_t)(pbar->addr)) << PCI_MEM64_BASE_HIGH_SHIFT) |  
293             (prev_pbar->addr);
294
295         PrintDebug("Adding 64 bit PCI mem region: start=0x%llx, end=0x%llx\n",
296                    mem64_addr, mem64_addr + mem64_bar_size);
297         
298         int ret = -1;
299         if ((ret = (v3_add_shadow_mem(dev->vm, V3_MEM_CORE_ANY, 
300                                       mem64_addr, 
301                                       mem64_addr + mem64_bar_size - 1,
302                                       mem64_addr)))) {
303
304             PrintDebug("Fail to insert shadow region (0x%llx, 0x%llx)  -> 0x%llx\n",
305                        mem64_addr,
306                        mem64_addr + mem64_bar_size - 1,
307                        mem64_addr);
308
309             return -1;
310
311         }
312
313         goto done;
314         
315     } //MEM64_HIGH
316
317
318     if ((bar_val & 0x3) == 0x1) {
319         int i = 0;
320
321         // IO bar
322         pbar->type = PT_BAR_IO;
323         pbar->addr = PCI_IO_BASE(bar_val);
324
325         max_val = bar_val | PCI_IO_MASK;
326
327         // Cycle the physical bar, to determine the actual size
328         // Disable irqs, to try to prevent accesses to the space via a interrupt handler
329         // This is not SMP safe!!
330         // What we probably want to do is write a 0 to the command register
331         //irq_state = v3_irq_save();
332         
333         pci_cfg_write32(pci_addr.value, max_val);
334         max_val = pci_cfg_read32(pci_addr.value);
335         pci_cfg_write32(pci_addr.value, bar_val);
336
337         //v3_irq_restore(irq_state);
338
339         V3_Print("max_val = %x\n", max_val);
340
341         pbar->size = (uint16_t)~PCI_IO_BASE(max_val) + 1;
342
343         
344         V3_Print("IO Bar with %d (%x) ports %x->%x\n", pbar->size, pbar->size, pbar->addr, pbar->addr + pbar->size);
345         // setup a set of null io hooks
346         // This allows the guest to do passthrough IO to these ports
347         // While still reserving them in the IO map
348         for (i = 0; i < pbar->size; i++) {
349             v3_hook_io_port(dev->vm, pbar->addr + i, NULL, NULL, NULL); 
350         }
351
352     } else {
353
354         // might be memory, might be nothing    
355
356         max_val = bar_val | PCI_MEM_MASK;
357
358         // Cycle the physical bar, to determine the actual size
359         // Disable irqs, to try to prevent accesses to the space via a interrupt handler
360         // This is not SMP safe!!
361         // What we probably want to do is write a 0 to the command register
362         //irq_state = v3_irq_save();
363         
364         pci_cfg_write32(pci_addr.value, max_val);
365         max_val = pci_cfg_read32(pci_addr.value);
366         pci_cfg_write32(pci_addr.value, bar_val);
367
368         //v3_irq_restore(irq_state);
369
370         
371         if (max_val == 0) {
372             pbar->type = PT_BAR_NONE;
373         } else {
374
375             // if its a memory region, setup passthrough mem mapping
376
377             if ((bar_val & 0x6) == 0x0) {
378                 // MEM 32
379                 pbar->type = PT_BAR_MEM32;
380                 pbar->addr = PCI_MEM32_BASE(bar_val);
381                 pbar->size = ~PCI_MEM32_BASE(max_val) + 1;
382
383                 PrintDebug("Adding 32 bit PCI mem region: start=0x%x, end=0x%x\n",
384                            pbar->addr, pbar->addr + pbar->size);
385
386                 v3_add_shadow_mem(dev->vm, V3_MEM_CORE_ANY,
387                                   pbar->addr, 
388                                   pbar->addr + pbar->size - 1,
389                                   pbar->addr);
390
391             } else if ((bar_val & 0x6) == 0x2) {
392                 // Mem 24
393                 pbar->type = PT_BAR_MEM24;
394                 pbar->addr = PCI_MEM24_BASE(bar_val);
395                 pbar->size = ~PCI_MEM24_BASE(max_val) + 1;
396
397                 v3_add_shadow_mem(dev->vm, V3_MEM_CORE_ANY,
398                                   pbar->addr, 
399                                   pbar->addr + pbar->size - 1,
400                                   pbar->addr);
401
402             } else if ((bar_val & 0x6) == 0x4) {
403                 // Mem 64
404                 /*
405                 PrintError("64 Bit PCI bars not supported\n");
406                 return -1;
407                 */
408
409                 //Zheng 03/15/2010
410                 pbar->type = PT_BAR_MEM64_LOW;
411                 pbar->addr = PCI_MEM32_BASE(bar_val);
412                 /*temperary size, which will be corrected 
413                   in the MEM_HIGH bar initialization*/
414                 pbar->size = PCI_MEM32_BASE(max_val);
415
416             } else {
417                 PrintError("Invalid Memory bar type\n");
418                 return -1;
419             }
420
421         }
422     }
423
424  done:
425
426     // Initially the virtual bars match the physical ones
427     memcpy(&(state->virt_bars[bar_num]), &(state->phys_bars[bar_num]), sizeof(struct pt_bar));
428
429     PrintDebug("bar_num=%d, bar_val=0x%x\n", bar_num, bar_val);
430
431     PrintDebug("phys bar  type=%d, addr=0x%x, size=%d\n", 
432                pbar->type, pbar->addr, 
433                pbar->size);
434
435     PrintDebug("virt bar  type=%d, addr=0x%x, size=%d\n",
436                state->virt_bars[bar_num].type, state->virt_bars[bar_num].addr, 
437                state->virt_bars[bar_num].size);
438
439     // Update the pci subsystem versions
440     *dst = bar_val;
441
442     return 0;
443 }
444
445 static int pt_io_read(struct guest_info * core, uint16_t port, void * dst, uint_t length, void * priv_data) {
446     struct pt_bar * pbar = (struct pt_bar *)priv_data;
447     int port_offset = port % pbar->size;
448
449     if (length == 1) {
450         *(uint8_t *)dst = v3_inb(pbar->addr + port_offset);
451     } else if (length == 2) {
452         *(uint16_t *)dst = v3_inw(pbar->addr + port_offset);
453     } else if (length == 4) {
454         *(uint32_t *)dst = v3_indw(pbar->addr + port_offset);
455     } else {
456         PrintError("Invalid PCI passthrough IO Redirection size read\n");
457         return -1;
458     }
459
460     return length;
461 }
462
463
464 static int pt_io_write(struct guest_info * core, uint16_t port, void * src, uint_t length, void * priv_data) {
465     struct pt_bar * pbar = (struct pt_bar *)priv_data;
466     int port_offset = port % pbar->size;
467     
468     if (length == 1) {
469         v3_outb(pbar->addr + port_offset, *(uint8_t *)src);
470     } else if (length == 2) {
471         v3_outw(pbar->addr + port_offset, *(uint16_t *)src);
472     } else if (length == 4) {
473         v3_outdw(pbar->addr + port_offset, *(uint32_t *)src);
474     } else {
475         PrintError("Invalid PCI passthrough IO Redirection size write\n");
476         return -1;
477     }
478     
479     return length;
480
481 }
482
483
484
485
486
487 static int pci_bar_write(int bar_num, uint32_t * src, void * private_data) {
488     struct vm_device * dev = (struct vm_device *)private_data;
489     struct pt_dev_state * state = (struct pt_dev_state *)dev->private_data;
490     
491     struct pt_bar * pbar = &(state->phys_bars[bar_num]);
492     struct pt_bar * vbar = &(state->virt_bars[bar_num]);
493
494     PrintDebug("Bar update: bar_num=%d, src=0x%x\n", bar_num,*src);
495     PrintDebug("vbar is size=%u, type=%d, addr=0x%x, val=0x%x\n",vbar->size, vbar->type, vbar->addr, vbar->val);
496     PrintDebug("pbar is size=%u, type=%d, addr=0x%x, val=0x%x\n",pbar->size, pbar->type, pbar->addr, pbar->val);
497
498
499
500     if (vbar->type == PT_BAR_NONE) {
501         return 0;
502     } else if (vbar->type == PT_BAR_IO) {
503         int i = 0;
504
505         // unhook old ports
506         for (i = 0; i < vbar->size; i++) {
507             if (v3_unhook_io_port(dev->vm, vbar->addr + i) == -1) {
508                 PrintError("Could not unhook previously hooked port.... %d (0x%x)\n", 
509                            vbar->addr + i, vbar->addr + i);
510                 return -1;
511             }
512         }
513
514         PrintDebug("Setting IO Port range size=%d\n", pbar->size);
515
516         // clear the low bits to match the size
517         *src &= ~(pbar->size - 1);
518
519         // Set reserved bits
520         *src |= (pbar->val & ~PCI_IO_MASK);
521
522         vbar->addr = PCI_IO_BASE(*src); 
523
524         PrintDebug("Cooked src=0x%x\n", *src);
525
526         PrintDebug("Rehooking passthrough IO ports starting at %d (0x%x)\n", 
527                    vbar->addr, vbar->addr);
528
529         if (vbar->addr == pbar->addr) {
530             // Map the io ports as passthrough
531             for (i = 0; i < pbar->size; i++) {
532                 v3_hook_io_port(dev->vm, pbar->addr + i, NULL, NULL, NULL); 
533             }
534         } else {
535             // We have to manually handle the io redirection
536             for (i = 0; i < vbar->size; i++) {
537                 v3_hook_io_port(dev->vm, vbar->addr + i, pt_io_read, pt_io_write, pbar); 
538             }
539         }
540     } else if (vbar->type == PT_BAR_MEM32) {
541         // remove old mapping
542         struct v3_shadow_region * old_reg = v3_get_shadow_region(dev->vm, V3_MEM_CORE_ANY, vbar->addr);
543
544         if (old_reg == NULL) {
545             // uh oh...
546             PrintError("Could not find PCI Passthrough memory redirection region (addr=0x%x)\n", vbar->addr);
547             return -1;
548         }
549
550         v3_delete_shadow_region(dev->vm, old_reg);
551
552         // clear the low bits to match the size
553         *src &= ~(pbar->size - 1);
554
555         // Set reserved bits
556         *src |= (pbar->val & ~PCI_MEM_MASK);
557
558         PrintDebug("Cooked src=0x%x\n", *src);
559
560         vbar->addr = PCI_MEM32_BASE(*src);
561
562         PrintDebug("Adding pci Passthrough remapping: start=0x%x, size=%d, end=0x%x\n", 
563                    vbar->addr, vbar->size, vbar->addr + vbar->size);
564
565         v3_add_shadow_mem(dev->vm, V3_MEM_CORE_ANY, 
566                           vbar->addr, 
567                           vbar->addr + vbar->size - 1,
568                           pbar->addr);
569
570     } else if (vbar->type == PT_BAR_MEM64_LOW) {
571         //Zheng: 03/15/2010
572
573         PrintDebug("Uncooked MEM64_LOW src=0x%x\n", *src);
574
575         // clear the low bits to match the size
576         *src &= ~(pbar->size - 1);
577
578         // Set reserved bits
579         *src |= (pbar->val & ~PCI_MEM_MASK);
580
581         PrintDebug("Cooked MEM64_LOW src=0x%x\n", *src);
582
583         vbar->addr = PCI_MEM32_BASE(*src);
584
585     } else if (vbar->type == PT_BAR_MEM64_HIGH) {
586
587         //Zheng: 03/15/2010
588         // remove old mapping
589
590         if (bar_num == 0) {
591             PrintError("The first bar register could not be of type PT_BAR_MEM64_HIGH\n");
592             return -1;
593         }
594
595         struct pt_bar * prev_pbar = &(state->phys_bars[bar_num - 1]);
596         struct pt_bar * prev_vbar = &(state->virt_bars[bar_num - 1]);
597
598
599         addr_t valid_vbar_mem64_addr = 
600             (addr_t)(((((uint64_t)vbar->addr) << PCI_MEM64_BASE_HIGH_SHIFT) & 
601                       (PCI_MEM64_HIGH_MASK64)) | 
602                      (prev_vbar->addr));
603
604         struct v3_shadow_region * old_reg = 
605             v3_get_shadow_region(dev->vm, V3_MEM_CORE_ANY, valid_vbar_mem64_addr);
606
607         if (old_reg == NULL) {
608
609             PrintError("Could not find PCI Passthrough memory redirection region (addr=0x%lx)\n", valid_vbar_mem64_addr);
610
611             return -1;
612         }
613
614         v3_delete_shadow_region(dev->vm, old_reg);
615
616         uint64_t mem64_src = 
617             ((((uint64_t)(*src)) << PCI_MEM64_BASE_HIGH_SHIFT) & 
618              (PCI_MEM64_HIGH_MASK64)) | 
619             (prev_vbar->val);
620
621         uint64_t mem64_bar_size = 
622             ((((uint64_t)(pbar->size)) << PCI_MEM64_BASE_HIGH_SHIFT) & 
623              (PCI_MEM64_HIGH_MASK64)) | 
624             (prev_pbar->size);
625             
626         // clear the low bits to match the size
627         mem64_src &= ~(mem64_bar_size - 1);
628
629         uint64_t mem64_pbar_val = 
630             ((((uint64_t)(pbar->val)) << PCI_MEM64_BASE_HIGH_SHIFT) & 
631              (PCI_MEM64_HIGH_MASK64)) | 
632             (prev_pbar->val);
633             
634         // Set reserved bits
635         mem64_src |= (mem64_pbar_val & ~PCI_MEM64_MASK);
636
637         PrintDebug("Cooked mem64_src=0x%llx\n", mem64_src);
638
639         prev_vbar->val = (uint32_t)mem64_src;
640
641         *src = (uint32_t)((mem64_src & PCI_MEM64_HIGH_MASK64) >> 
642                 PCI_MEM64_BASE_HIGH_SHIFT);
643
644         uint64_t mem64_vbar_addr = PCI_MEM64_BASE(mem64_src);
645         prev_vbar->addr = (uint32_t)(mem64_vbar_addr);
646         vbar->addr = 
647             (uint32_t)(((uint64_t)(mem64_vbar_addr)) >> PCI_MEM64_BASE_HIGH_SHIFT);
648
649         PrintDebug("Adding pci Passthrough remapping: start=0x%llx, size=0x%llu, end=0x%llx\n", 
650                    mem64_vbar_addr, mem64_bar_size, mem64_vbar_addr + mem64_bar_size);
651
652         uint64_t mem64_pbar_addr = 
653             (((uint64_t)(pbar->addr)) << PCI_MEM64_BASE_HIGH_SHIFT) |
654             (prev_pbar->addr);
655
656         int ret = -1;
657         if ((ret = (v3_add_shadow_mem(dev->vm, V3_MEM_CORE_ANY,
658                                      mem64_vbar_addr, 
659                                      mem64_vbar_addr + mem64_bar_size - 1,
660                                      mem64_pbar_addr)))) {
661             PrintDebug("Fail to insert shadow region (0x%llx, 0x%llx)  -> 0x%llx\n",
662                            mem64_vbar_addr,
663                            mem64_vbar_addr + mem64_bar_size - 1,
664                            mem64_pbar_addr);
665
666             return -1;
667         }
668         
669     } else {
670         PrintError("Unhandled Pasthrough PCI Bar type %d\n", vbar->type);
671         return -1;
672     }
673
674     vbar->val = *src;
675     
676     return 0;
677 }
678
679
680 #if 0 //Zheng: 03/19/2010
681 static int pt_config_update(uint_t reg_num, void * src, uint_t length, void * private_data) {
682     struct vm_device * dev = (struct vm_device *)private_data;
683     struct pt_dev_state * state = (struct pt_dev_state *)dev->private_data;
684     union pci_addr_reg pci_addr = {state->phys_pci_addr.value};
685
686     pci_addr.reg = reg_num;
687
688     if (length == 1) {
689         pci_cfg_write8(pci_addr.value, *(uint8_t *)src);
690     } else if (length == 2) {
691         pci_cfg_write16(pci_addr.value, *(uint16_t *)src);
692     } else if (length == 4) {
693         pci_cfg_write32(pci_addr.value, *(uint32_t *)src);      
694     }
695
696     
697     return 0;
698 }
699
700 #endif //old pt_config_update
701
702
703 //Zheng: 03/19/2010
704 static int pt_config_update(uint_t reg_num, void * src, uint_t length, void * private_data) {
705     struct vm_device * dev = (struct vm_device *)private_data;
706     struct pt_dev_state * state = (struct pt_dev_state *)dev->private_data;
707     union pci_addr_reg pci_addr = {state->phys_pci_addr.value};
708
709     pci_addr.reg = reg_num >> 2;
710     uint32_t org_val = pci_cfg_read32(pci_addr.value);
711     uint_t offset = reg_num & 0x3;
712
713     uint32_t cooked_val = org_val;
714     if (length == 1) {
715         *(((uint8_t *)(&cooked_val)) + offset) = *((uint8_t *)src); 
716     } else if (length == 2) {
717         *((uint16_t *)(((uint8_t *)(&cooked_val)) + offset)) = *((uint16_t *)src); 
718     } else if (length == 4) {
719         *((uint32_t *)(((uint8_t *)(&cooked_val)) + offset)) = *((uint32_t *)src); 
720     }
721
722     pci_cfg_write32(pci_addr.value, cooked_val);
723         
724     *(((uint32_t *)(state->pci_dev->config_space)) + pci_addr.reg) = pci_cfg_read32(pci_addr.value);
725     
726     return 0;
727 }
728
729
730 //Zheng 03/19/2010
731
732 static int pci_exp_rom_base_write(struct pci_device *pci_dev) {
733     struct vm_device * dev = (struct vm_device *)(pci_dev->priv_data);
734     struct pt_dev_state * state = (struct pt_dev_state *)dev->private_data;
735     
736     struct pt_exp_rom_base * pexp_rom_base = &(state->phys_exp_rom_base);
737     struct pt_exp_rom_base * vexp_rom_base = &(state->virt_exp_rom_base);
738
739     const uint32_t exp_rom_base_reg = 12;
740     uint32_t *src = ((uint32_t *)(&(pci_dev->config_space[4 * exp_rom_base_reg])));
741
742     PrintDebug("exp_rom_base update: src=0x%x\n", *src);
743     PrintDebug("vexp_rom_base is size=%u, addr=0x%x, val=0x%x\n",vexp_rom_base->size, vexp_rom_base->addr, vexp_rom_base->val);
744     PrintDebug("pexp_rom_base is size=%u, addr=0x%x, val=0x%x\n",pexp_rom_base->size, pexp_rom_base->addr, pexp_rom_base->val);
745
746     // remove old mapping
747     struct v3_shadow_region * old_reg = v3_get_shadow_region(dev->vm, V3_MEM_CORE_ANY, vexp_rom_base->addr);
748     
749     if (old_reg == NULL) {
750         // uh oh...
751         PrintError("Could not find PCI Passthrough exp_rom_base redirection region (addr=0x%x)\n", vexp_rom_base->addr);
752
753         return -1;
754     }
755     
756     v3_delete_shadow_region(dev->vm, old_reg);
757     
758     // clear the low bits to match the size
759     *src &= ~(pexp_rom_base->size - 1);
760     
761     // Set reserved bits
762     *src |= (pexp_rom_base->val & ~PCI_MEM_MASK);
763     
764     PrintDebug("Cooked src=0x%x\n", *src);
765     vexp_rom_base->addr = PCI_EXP_ROM_BASE(*src);
766     
767     PrintDebug("Adding pci Passthrough exp_rom_base remapping: start=0x%x, size=%u, end=0x%x\n", 
768                vexp_rom_base->addr, vexp_rom_base->size, vexp_rom_base->addr + vexp_rom_base->size);
769
770     int ret = -1;
771
772     if ((ret = v3_add_shadow_mem(dev->vm, V3_MEM_CORE_ANY, 
773                                  vexp_rom_base->addr, 
774                                  vexp_rom_base->addr + vexp_rom_base->size - 1,
775                                  pexp_rom_base->addr))) {
776         PrintError("Fail to add pci Passthrough exp_rom_base remapping: start=0x%x, size=%u, end=0x%x\n", 
777                vexp_rom_base->addr, vexp_rom_base->size, vexp_rom_base->addr + vexp_rom_base->size);
778
779         return -1;
780     }
781     
782     vexp_rom_base->val = *src;
783     
784     return 0;
785 }
786
787
788 static int find_real_pci_dev(uint16_t vendor_id, uint16_t device_id, struct pt_dev_state * state) {
789     union pci_addr_reg pci_addr = {0x80000000};
790     uint_t i, j, k, m;    
791
792     union {
793         uint32_t value;
794         struct {
795             uint16_t vendor;
796             uint16_t device;
797         } __attribute__((packed));
798     } __attribute__((packed)) pci_hdr = {0};
799
800     //PrintDebug("Scanning PCI busses for vendor=%x, device=%x\n", vendor_id, device_id);
801     for (i = 0, pci_addr.bus = 0; i < PCI_BUS_MAX; i++, pci_addr.bus++) {
802         for (j = 0, pci_addr.dev = 0; j < PCI_DEV_MAX; j++, pci_addr.dev++) {
803             for (k = 0, pci_addr.func = 0; k < PCI_FN_MAX; k++, pci_addr.func++) {
804
805                 v3_outdw(PCI_CFG_ADDR, pci_addr.value);
806                 pci_hdr.value = v3_indw(PCI_CFG_DATA);
807
808                 //PrintDebug("\bus=%d, tvendor=%x, device=%x\n", pci_addr.bus, pci_hdr.vendor, pci_hdr.device);
809
810                 if ((pci_hdr.vendor == vendor_id) && (pci_hdr.device == device_id)) {
811                     uint32_t * cfg_space = (uint32_t *)&state->real_hdr;
812     
813                     state->phys_pci_addr = pci_addr;
814
815                     // Copy the configuration space to the local cached version
816                     for (m = 0, pci_addr.reg = 0; m < PCI_HDR_SIZE; m += 4, pci_addr.reg++) {
817                         cfg_space[pci_addr.reg] = pci_cfg_read32(pci_addr.value);
818                     }
819
820
821                     PrintDebug("Found device %x:%x (bus=%d, dev=%d, func=%d)\n", 
822                                vendor_id, device_id, 
823                                pci_addr.bus, pci_addr.dev, pci_addr.func);
824
825                     return 0;
826                 }
827             }
828         }
829     }
830
831     return -1;
832 }
833
834
835
836 static int setup_virt_pci_dev(struct v3_vm_info * vm_info, struct vm_device * dev) {
837     struct pt_dev_state * state = (struct pt_dev_state *)dev->private_data;
838     struct pci_device * pci_dev = NULL;
839     struct v3_pci_bar bars[6];
840     int bus_num = 0;
841     int i;
842
843     for (i = 0; i < 6; i++) {
844         bars[i].type = PCI_BAR_PASSTHROUGH;
845         bars[i].private_data = dev;
846         bars[i].bar_init = pci_bar_init;
847         bars[i].bar_write = pci_bar_write;
848     }
849
850     //Zheng:03/19/2010 
851     pci_dev = v3_pci_register_device(state->pci_bus,
852                                      PCI_STD_DEVICE,
853                                      bus_num, -1, 0, 
854                                      state->name, bars,
855                                      pt_config_update,
856                                      NULL,
857                                      pci_exp_rom_base_write,               
858                                      dev);
859 #if 0 
860     pci_dev = v3_pci_register_device(state->pci_bus,
861                                      PCI_STD_DEVICE,
862                                      bus_num, -1, 0, 
863                                      state->name, bars,
864                                      pt_config_update, NULL, NULL, 
865                                      dev);
866 #endif //if 0 old v3_pci_register_device
867
868     // This will overwrite the bar registers.. but that should be ok.
869     memcpy(pci_dev->config_space, (uint8_t *)&(state->real_hdr), sizeof(struct pci_config_header));
870
871     state->pci_dev = pci_dev;
872
873     //Zheng 03/19/2010
874     pci_exp_rom_base_init(pci_dev);
875
876     v3_sym_map_pci_passthrough(vm_info, pci_dev->bus_num, pci_dev->dev_num, pci_dev->fn_num);
877
878
879     return 0;
880 }
881
882
883 static struct v3_device_ops dev_ops = {
884     .free = NULL,
885     .reset = NULL,
886     .start = NULL,
887     .stop = NULL,
888 };
889
890
891
892 static int irq_handler(struct v3_vm_info * vm, struct v3_interrupt * intr, void * private_data) {
893     struct vm_device * dev = (struct vm_device *)private_data;
894     struct pt_dev_state * state = (struct pt_dev_state *)dev->private_data;
895
896
897 #if 0 //hacking
898 static long irq_time = 0;
899     if(intr->irq == 64)
900                 irq_time ++;
901     if(irq_time % 10 == 0)
902               PrintError("Handling IRQ %d, time: %ld\n", intr->irq, irq_time);
903
904     PrintError("Handling IRQ %d, time: %ld\n", intr->irq, irq_time);
905
906 #endif
907 //    PrintDebug("Handling E1000 IRQ %d\n", intr->irq);
908
909     v3_pci_raise_irq(state->pci_bus, 0, state->pci_dev);
910
911     V3_ACK_IRQ(intr->irq);
912
913     return 0;
914 }
915
916
917
918
919 static int passthrough_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
920     struct pt_dev_state * state = V3_Malloc(sizeof(struct pt_dev_state));
921     struct vm_device * dev = NULL;
922     struct vm_device * pci = v3_find_dev(vm, v3_cfg_val(cfg, "bus"));
923     char * name = v3_cfg_val(cfg, "name");    
924
925
926     memset(state, 0, sizeof(struct pt_dev_state));
927
928     if (!pci) {
929         PrintError("Could not find PCI device\n");
930         return -1;
931     }
932     
933     state->pci_bus = pci;
934     strncpy(state->name, name, 32);
935
936
937     dev = v3_allocate_device(name, &dev_ops, state);
938
939     if (v3_attach_device(vm, dev) == -1) {
940         PrintError("Could not attach device %s\n", name);
941         return -1;
942     }
943
944
945     if (find_real_pci_dev(atox(v3_cfg_val(cfg, "vendor_id")), 
946                           atox(v3_cfg_val(cfg, "device_id")), 
947                           state) == -1) {
948         PrintError("Could not find PCI Device %s:%s\n", 
949                    v3_cfg_val(cfg, "vendor_id"), 
950                    v3_cfg_val(cfg, "device_id"));
951         return 0;
952     }
953
954     setup_virt_pci_dev(vm, dev);
955
956     v3_hook_irq(vm, atoi(v3_cfg_val(cfg, "irq")), irq_handler, dev);
957     //    v3_hook_irq(info, 64, irq_handler, dev);
958
959     return 0;
960 }
961
962
963
964
965 device_register("PCI_PASSTHROUGH", passthrough_init)