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 patch on 64bit passthrough pci
[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     if (pexp_rom_base->size) {
747         // remove old mapping
748         struct v3_shadow_region * old_reg = v3_get_shadow_region(dev->vm, V3_MEM_CORE_ANY, vexp_rom_base->addr);
749         
750         if (old_reg == NULL) {
751             // uh oh...
752             PrintError("Could not find PCI Passthrough exp_rom_base redirection region (addr=0x%x)\n", vexp_rom_base->addr);
753             
754             return -1;
755         }
756     
757         v3_delete_shadow_region(dev->vm, old_reg);
758     }//if size > 0
759     
760     // clear the low bits to match the size
761     *src &= ~(pexp_rom_base->size - 1);
762     
763     // Set reserved bits
764     *src |= (pexp_rom_base->val & ~PCI_MEM_MASK);
765     
766     PrintDebug("Cooked src=0x%x\n", *src);
767     vexp_rom_base->addr = PCI_EXP_ROM_BASE(*src);
768     
769
770     if (pexp_rom_base->size) {
771         PrintDebug("Adding pci Passthrough exp_rom_base remapping: start=0x%x, size=%u, end=0x%x\n", 
772                    vexp_rom_base->addr, vexp_rom_base->size, vexp_rom_base->addr + vexp_rom_base->size);
773         
774         int ret = -1;
775         
776         if ((ret = v3_add_shadow_mem(dev->vm, V3_MEM_CORE_ANY, 
777                                      vexp_rom_base->addr, 
778                                      vexp_rom_base->addr + vexp_rom_base->size - 1,
779                                      pexp_rom_base->addr))) {
780             PrintError("Fail to add pci Passthrough exp_rom_base remapping: start=0x%x, size=%u, end=0x%x\n", 
781                        vexp_rom_base->addr, vexp_rom_base->size, vexp_rom_base->addr + vexp_rom_base->size);
782             
783             return -1;
784         }
785     } //if size > 0
786
787     
788     vexp_rom_base->val = *src;
789     
790     return 0;
791 }
792
793
794 static int find_real_pci_dev(uint16_t vendor_id, uint16_t device_id, struct pt_dev_state * state) {
795     union pci_addr_reg pci_addr = {0x80000000};
796     uint_t i, j, k, m;    
797
798     union {
799         uint32_t value;
800         struct {
801             uint16_t vendor;
802             uint16_t device;
803         } __attribute__((packed));
804     } __attribute__((packed)) pci_hdr = {0};
805
806     //PrintDebug("Scanning PCI busses for vendor=%x, device=%x\n", vendor_id, device_id);
807     for (i = 0, pci_addr.bus = 0; i < PCI_BUS_MAX; i++, pci_addr.bus++) {
808         for (j = 0, pci_addr.dev = 0; j < PCI_DEV_MAX; j++, pci_addr.dev++) {
809             for (k = 0, pci_addr.func = 0; k < PCI_FN_MAX; k++, pci_addr.func++) {
810
811                 v3_outdw(PCI_CFG_ADDR, pci_addr.value);
812                 pci_hdr.value = v3_indw(PCI_CFG_DATA);
813
814                 //PrintDebug("\bus=%d, tvendor=%x, device=%x\n", pci_addr.bus, pci_hdr.vendor, pci_hdr.device);
815
816                 if ((pci_hdr.vendor == vendor_id) && (pci_hdr.device == device_id)) {
817                     uint32_t * cfg_space = (uint32_t *)&state->real_hdr;
818     
819                     state->phys_pci_addr = pci_addr;
820
821                     // Copy the configuration space to the local cached version
822                     for (m = 0, pci_addr.reg = 0; m < PCI_HDR_SIZE; m += 4, pci_addr.reg++) {
823                         cfg_space[pci_addr.reg] = pci_cfg_read32(pci_addr.value);
824                     }
825
826
827                     PrintDebug("Found device %x:%x (bus=%d, dev=%d, func=%d)\n", 
828                                vendor_id, device_id, 
829                                pci_addr.bus, pci_addr.dev, pci_addr.func);
830
831                     return 0;
832                 }
833             }
834         }
835     }
836
837     return -1;
838 }
839
840
841
842 static int setup_virt_pci_dev(struct v3_vm_info * vm_info, struct vm_device * dev) {
843     struct pt_dev_state * state = (struct pt_dev_state *)dev->private_data;
844     struct pci_device * pci_dev = NULL;
845     struct v3_pci_bar bars[6];
846     int bus_num = 0;
847     int i;
848
849     for (i = 0; i < 6; i++) {
850         bars[i].type = PCI_BAR_PASSTHROUGH;
851         bars[i].private_data = dev;
852         bars[i].bar_init = pci_bar_init;
853         bars[i].bar_write = pci_bar_write;
854     }
855
856     //Zheng:03/19/2010 
857     pci_dev = v3_pci_register_device(state->pci_bus,
858                                      PCI_STD_DEVICE,
859                                      bus_num, -1, 0, 
860                                      state->name, bars,
861                                      pt_config_update,
862                                      NULL,
863                                      pci_exp_rom_base_write,               
864                                      dev);
865 #if 0 
866     pci_dev = v3_pci_register_device(state->pci_bus,
867                                      PCI_STD_DEVICE,
868                                      bus_num, -1, 0, 
869                                      state->name, bars,
870                                      pt_config_update, NULL, NULL, 
871                                      dev);
872 #endif //if 0 old v3_pci_register_device
873
874     // This will overwrite the bar registers.. but that should be ok.
875     memcpy(pci_dev->config_space, (uint8_t *)&(state->real_hdr), sizeof(struct pci_config_header));
876
877     state->pci_dev = pci_dev;
878
879     //Zheng 03/19/2010
880     pci_exp_rom_base_init(pci_dev);
881
882     v3_sym_map_pci_passthrough(vm_info, pci_dev->bus_num, pci_dev->dev_num, pci_dev->fn_num);
883
884
885     return 0;
886 }
887
888
889 static struct v3_device_ops dev_ops = {
890     .free = NULL,
891     .reset = NULL,
892     .start = NULL,
893     .stop = NULL,
894 };
895
896
897
898 static int irq_handler(struct v3_vm_info * vm, struct v3_interrupt * intr, void * private_data) {
899     struct vm_device * dev = (struct vm_device *)private_data;
900     struct pt_dev_state * state = (struct pt_dev_state *)dev->private_data;
901
902
903 #if 0 //hacking
904 static long irq_time = 0;
905     if(intr->irq == 64)
906                 irq_time ++;
907     if(irq_time % 10 == 0)
908               PrintError("Handling IRQ %d, time: %ld\n", intr->irq, irq_time);
909
910     PrintError("Handling IRQ %d, time: %ld\n", intr->irq, irq_time);
911
912 #endif
913 //    PrintDebug("Handling E1000 IRQ %d\n", intr->irq);
914
915     v3_pci_raise_irq(state->pci_bus, 0, state->pci_dev);
916
917     V3_ACK_IRQ(intr->irq);
918
919     return 0;
920 }
921
922
923
924
925 static int passthrough_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
926     struct pt_dev_state * state = V3_Malloc(sizeof(struct pt_dev_state));
927     struct vm_device * dev = NULL;
928     struct vm_device * pci = v3_find_dev(vm, v3_cfg_val(cfg, "bus"));
929     char * name = v3_cfg_val(cfg, "name");    
930
931
932     memset(state, 0, sizeof(struct pt_dev_state));
933
934     if (!pci) {
935         PrintError("Could not find PCI device\n");
936         return -1;
937     }
938     
939     state->pci_bus = pci;
940     strncpy(state->name, name, 32);
941
942
943     dev = v3_allocate_device(name, &dev_ops, state);
944
945     if (v3_attach_device(vm, dev) == -1) {
946         PrintError("Could not attach device %s\n", name);
947         return -1;
948     }
949
950
951     if (find_real_pci_dev(atox(v3_cfg_val(cfg, "vendor_id")), 
952                           atox(v3_cfg_val(cfg, "device_id")), 
953                           state) == -1) {
954         PrintError("Could not find PCI Device %s:%s\n", 
955                    v3_cfg_val(cfg, "vendor_id"), 
956                    v3_cfg_val(cfg, "device_id"));
957         return 0;
958     }
959
960     setup_virt_pci_dev(vm, dev);
961
962     v3_hook_irq(vm, atoi(v3_cfg_val(cfg, "irq")), irq_handler, dev);
963     //    v3_hook_irq(info, 64, irq_handler, dev);
964
965     return 0;
966 }
967
968
969
970
971 device_register("PCI_PASSTHROUGH", passthrough_init)