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.


Merge branch 'devel' of ssh://palacios@newskysaw.cs.northwestern.edu//home/palacios...
[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_sym_iface.h>
40
41 #include <devices/pci.h>
42 #include <devices/pci_types.h>
43
44
45 // Hardcoded... Are these standard??
46 #define PCI_CFG_ADDR    0xcf8
47 #define PCI_CFG_DATA    0xcfc
48
49 #define PCI_BUS_MAX  7
50 #define PCI_DEV_MAX 32
51 #define PCI_FN_MAX   7
52
53 #define PCI_DEVICE 0x0
54 #define PCI_PCI_BRIDGE 0x1
55 #define PCI_CARDBUS_BRIDGE 0x2
56
57 #define PCI_HDR_SIZE 256
58
59
60 union pci_addr_reg {
61     uint32_t value;
62     struct {
63         uint_t rsvd1   : 2;
64         uint_t reg     : 6;
65         uint_t func    : 3;
66         uint_t dev     : 5;
67         uint_t bus     : 8;
68         uint_t rsvd2   : 7;
69         uint_t enable  : 1;
70     } __attribute__((packed));
71 } __attribute__((packed));
72
73
74 typedef enum { PT_BAR_NONE,
75                PT_BAR_IO, 
76                PT_BAR_MEM32, 
77                PT_BAR_MEM24, 
78                PT_BAR_MEM64_LOW, 
79                PT_BAR_MEM64_HIGH } pt_bar_type_t;
80
81 struct pt_bar {
82     uint32_t size;
83     pt_bar_type_t type;
84     uint32_t addr;
85
86     uint32_t val;
87 };
88
89 struct pt_dev_state {
90     union {
91         uint8_t config_space[256];
92         struct pci_config_header real_hdr;
93     } __attribute__((packed));
94
95     struct pt_bar phys_bars[6];
96     struct pt_bar virt_bars[6];
97
98     
99     struct vm_device * pci_bus;
100     struct pci_device * pci_dev;
101
102     union pci_addr_reg phys_pci_addr;
103
104     char name[32];
105 };
106
107
108 static inline uint32_t pci_cfg_read32(uint32_t addr) {
109     v3_outdw(PCI_CFG_ADDR, addr);
110     return v3_indw(PCI_CFG_DATA);
111 }
112
113
114
115 static inline void pci_cfg_write32(uint32_t addr, uint32_t val) {
116     v3_outdw(PCI_CFG_ADDR, addr);
117     v3_outdw(PCI_CFG_DATA, val);
118 }
119
120
121
122 static inline uint16_t pci_cfg_read16(uint32_t addr) {
123     v3_outw(PCI_CFG_ADDR, addr);
124     return v3_inw(PCI_CFG_DATA);
125 }
126
127
128
129 static inline void pci_cfg_write16(uint32_t addr, uint16_t val) {
130     v3_outw(PCI_CFG_ADDR, addr);
131     v3_outw(PCI_CFG_DATA, val);
132 }
133
134
135
136 static inline uint8_t pci_cfg_read8(uint32_t addr) {
137     v3_outb(PCI_CFG_ADDR, addr);
138     return v3_inb(PCI_CFG_DATA);
139 }
140
141
142
143 static inline void pci_cfg_write8(uint32_t addr, uint8_t val) {
144     v3_outb(PCI_CFG_ADDR, addr);
145     v3_outb(PCI_CFG_DATA, val);
146 }
147
148
149 // We initialize this 
150 static int pci_bar_init(int bar_num, uint32_t * dst,void * private_data) {
151     struct vm_device * dev = (struct vm_device *)private_data;
152     struct pt_dev_state * state = (struct pt_dev_state *)dev->private_data;
153     const uint32_t bar_base_reg = 4;
154     union pci_addr_reg pci_addr = {state->phys_pci_addr.value};
155     uint32_t bar_val = 0;
156     uint32_t max_val = 0;
157     //addr_t irq_state = 0;
158     struct pt_bar * pbar = &(state->phys_bars[bar_num]);
159
160
161     // should read from cached header
162     pci_addr.reg = bar_base_reg + bar_num;
163
164     PrintDebug("PCI Address = 0x%x\n", pci_addr.value);
165
166     bar_val = pci_cfg_read32(pci_addr.value);
167     pbar->val = bar_val;
168
169     if ((bar_val & 0x3) == 0x1) {
170         int i = 0;
171
172         // IO bar
173         pbar->type = PT_BAR_IO;
174         pbar->addr = PCI_IO_BASE(bar_val);
175
176         max_val = bar_val | PCI_IO_MASK;
177
178         // Cycle the physical bar, to determine the actual size
179         // Disable irqs, to try to prevent accesses to the space via a interrupt handler
180         // This is not SMP safe!!
181         // What we probably want to do is write a 0 to the command register
182         //irq_state = v3_irq_save();
183         
184         pci_cfg_write32(pci_addr.value, max_val);
185         max_val = pci_cfg_read32(pci_addr.value);
186         pci_cfg_write32(pci_addr.value, bar_val);
187
188         //v3_irq_restore(irq_state);
189
190         V3_Print("max_val = %x\n", max_val);
191
192         pbar->size = (uint16_t)~PCI_IO_BASE(max_val) + 1;
193
194         
195         V3_Print("IO Bar with %d (%x) ports %x->%x\n", pbar->size, pbar->size, pbar->addr, pbar->addr + pbar->size);
196         // setup a set of null io hooks
197         // This allows the guest to do passthrough IO to these ports
198         // While still reserving them in the IO map
199         for (i = 0; i < pbar->size; i++) {
200             v3_hook_io_port(dev->vm, pbar->addr + i, NULL, NULL, NULL); 
201         }
202
203     } else {
204
205         // might be memory, might be nothing    
206
207         max_val = bar_val | PCI_MEM_MASK;
208
209         // Cycle the physical bar, to determine the actual size
210         // Disable irqs, to try to prevent accesses to the space via a interrupt handler
211         // This is not SMP safe!!
212         // What we probably want to do is write a 0 to the command register
213         //irq_state = v3_irq_save();
214         
215         pci_cfg_write32(pci_addr.value, max_val);
216         max_val = pci_cfg_read32(pci_addr.value);
217         pci_cfg_write32(pci_addr.value, bar_val);
218
219         //v3_irq_restore(irq_state);
220
221         
222         if (max_val == 0) {
223             pbar->type = PT_BAR_NONE;
224         } else {
225
226             // if its a memory region, setup passthrough mem mapping
227
228             if ((bar_val & 0x6) == 0x0) {
229                 // MEM 32
230                 pbar->type = PT_BAR_MEM32;
231                 pbar->addr = PCI_MEM32_BASE(bar_val);
232                 pbar->size = ~PCI_MEM32_BASE(max_val) + 1;
233
234                 PrintDebug("Adding 32 bit PCI mem region: start=0x%x, end=0x%x\n",
235                            pbar->addr, pbar->addr + pbar->size);
236
237                 v3_add_shadow_mem(dev->vm, 
238                                   pbar->addr, 
239                                   pbar->addr + pbar->size - 1,
240                                   pbar->addr);
241
242             } else if ((bar_val & 0x6) == 0x2) {
243                 // Mem 24
244                 pbar->type = PT_BAR_MEM24;
245                 pbar->addr = PCI_MEM24_BASE(bar_val);
246                 pbar->size = ~PCI_MEM24_BASE(max_val) + 1;
247
248                 v3_add_shadow_mem(dev->vm, 
249                                   pbar->addr, 
250                                   pbar->addr + pbar->size - 1,
251                                   pbar->addr);
252
253             } else if ((bar_val & 0x6) == 0x4) {
254                 // Mem 64
255                 PrintError("64 Bit PCI bars not supported\n");
256                 return -1;
257             } else {
258                 PrintError("Invalid Memory bar type\n");
259                 return -1;
260             }
261
262         }
263     }
264
265
266     // Initially the virtual bars match the physical ones
267     memcpy(&(state->virt_bars[bar_num]), &(state->phys_bars[bar_num]), sizeof(struct pt_bar));
268
269     PrintDebug("bar_num=%d, bar_val=0x%x\n", bar_num, bar_val);
270
271     PrintDebug("phys bar  type=%d, addr=0x%x, size=%d\n", 
272                pbar->type, pbar->addr, 
273                pbar->size);
274
275     PrintDebug("virt bar  type=%d, addr=0x%x, size=%d\n",
276                state->virt_bars[bar_num].type, state->virt_bars[bar_num].addr, 
277                state->virt_bars[bar_num].size);
278
279     // Update the pci subsystem versions
280     *dst = bar_val;
281
282     return 0;
283 }
284
285 static int pt_io_read(uint16_t port, void * dst, uint_t length, void * priv_data) {
286     struct pt_bar * pbar = (struct pt_bar *)priv_data;
287     int port_offset = port % pbar->size;
288
289     if (length == 1) {
290         *(uint8_t *)dst = v3_inb(pbar->addr + port_offset);
291     } else if (length == 2) {
292         *(uint16_t *)dst = v3_inw(pbar->addr + port_offset);
293     } else if (length == 4) {
294         *(uint32_t *)dst = v3_indw(pbar->addr + port_offset);
295     } else {
296         PrintError("Invalid PCI passthrough IO Redirection size read\n");
297         return -1;
298     }
299
300     return length;
301 }
302
303
304 static int pt_io_write(uint16_t port, void * src, uint_t length, void * priv_data) {
305     struct pt_bar * pbar = (struct pt_bar *)priv_data;
306     int port_offset = port % pbar->size;
307     
308     if (length == 1) {
309         v3_outb(pbar->addr + port_offset, *(uint8_t *)src);
310     } else if (length == 2) {
311         v3_outw(pbar->addr + port_offset, *(uint16_t *)src);
312     } else if (length == 4) {
313         v3_outdw(pbar->addr + port_offset, *(uint32_t *)src);
314     } else {
315         PrintError("Invalid PCI passthrough IO Redirection size write\n");
316         return -1;
317     }
318     
319     return length;
320
321 }
322
323
324
325
326
327 static int pci_bar_write(int bar_num, uint32_t * src, void * private_data) {
328     struct vm_device * dev = (struct vm_device *)private_data;
329     struct pt_dev_state * state = (struct pt_dev_state *)dev->private_data;
330     
331     struct pt_bar * pbar = &(state->phys_bars[bar_num]);
332     struct pt_bar * vbar = &(state->virt_bars[bar_num]);
333
334     PrintDebug("Bar update: bar_num=%d, src=0x%x\n", bar_num,*src);
335     PrintDebug("vbar is size=%u, type=%d, addr=0x%x, val=0x%x\n",vbar->size, vbar->type, vbar->addr, vbar->val);
336     PrintDebug("pbar is size=%u, type=%d, addr=0x%x, val=0x%x\n",pbar->size, pbar->type, pbar->addr, pbar->val);
337
338
339
340     if (vbar->type == PT_BAR_NONE) {
341         return 0;
342     } else if (vbar->type == PT_BAR_IO) {
343         int i = 0;
344
345         // unhook old ports
346         for (i = 0; i < vbar->size; i++) {
347             if (v3_unhook_io_port(dev->vm, vbar->addr + i) == -1) {
348                 PrintError("Could not unhook previously hooked port.... %d (0x%x)\n", 
349                            vbar->addr + i, vbar->addr + i);
350                 return -1;
351             }
352         }
353
354         PrintDebug("Setting IO Port range size=%d\n", pbar->size);
355
356         // clear the low bits to match the size
357         *src &= ~(pbar->size - 1);
358
359         // Set reserved bits
360         *src |= (pbar->val & ~PCI_IO_MASK);
361
362         vbar->addr = PCI_IO_BASE(*src); 
363
364         PrintDebug("Cooked src=0x%x\n", *src);
365
366         PrintDebug("Rehooking passthrough IO ports starting at %d (0x%x)\n", 
367                    vbar->addr, vbar->addr);
368
369         if (vbar->addr == pbar->addr) {
370             // Map the io ports as passthrough
371             for (i = 0; i < pbar->size; i++) {
372                 v3_hook_io_port(dev->vm, pbar->addr + i, NULL, NULL, NULL); 
373             }
374         } else {
375             // We have to manually handle the io redirection
376             for (i = 0; i < vbar->size; i++) {
377                 v3_hook_io_port(dev->vm, vbar->addr + i, pt_io_read, pt_io_write, pbar); 
378             }
379         }
380     } else if (vbar->type == PT_BAR_MEM32) {
381         // remove old mapping
382         struct v3_shadow_region * old_reg = v3_get_shadow_region(dev->vm, vbar->addr);
383
384         if (old_reg == NULL) {
385             // uh oh...
386             PrintError("Could not find PCI Passthrough memory redirection region (addr=0x%x)\n", vbar->addr);
387             return -1;
388         }
389
390         v3_delete_shadow_region(dev->vm, old_reg);
391
392         // clear the low bits to match the size
393         *src &= ~(pbar->size - 1);
394
395         // Set reserved bits
396         *src |= (pbar->val & ~PCI_MEM_MASK);
397
398         PrintDebug("Cooked src=0x%x\n", *src);
399
400         vbar->addr = PCI_MEM32_BASE(*src);
401
402         PrintDebug("Adding pci Passthrough remapping: start=0x%x, size=%d, end=0x%x\n", 
403                    vbar->addr, vbar->size, vbar->addr + vbar->size);
404
405         v3_add_shadow_mem(dev->vm, 
406                           vbar->addr, 
407                           vbar->addr + vbar->size - 1,
408                           pbar->addr);
409         
410     } else {
411         PrintError("Unhandled Pasthrough PCI Bar type %d\n", vbar->type);
412         return -1;
413     }
414
415
416     vbar->val = *src;
417     
418
419     return 0;
420 }
421
422
423 static int pt_config_update(uint_t reg_num, void * src, uint_t length, void * private_data) {
424     struct vm_device * dev = (struct vm_device *)private_data;
425     struct pt_dev_state * state = (struct pt_dev_state *)dev->private_data;
426     union pci_addr_reg pci_addr = {state->phys_pci_addr.value};
427
428     pci_addr.reg = reg_num;
429
430     if (length == 1) {
431         pci_cfg_write8(pci_addr.value, *(uint8_t *)src);
432     } else if (length == 2) {
433         pci_cfg_write16(pci_addr.value, *(uint16_t *)src);
434     } else if (length == 4) {
435         pci_cfg_write32(pci_addr.value, *(uint32_t *)src);      
436     }
437
438     
439     return 0;
440 }
441
442
443
444 static int find_real_pci_dev(uint16_t vendor_id, uint16_t device_id, struct pt_dev_state * state) {
445     union pci_addr_reg pci_addr = {0x80000000};
446     uint_t i, j, k, m;    
447
448     union {
449         uint32_t value;
450         struct {
451             uint16_t vendor;
452             uint16_t device;
453         } __attribute__((packed));
454     } __attribute__((packed)) pci_hdr = {0};
455
456
457     //PrintDebug("Scanning PCI busses for vendor=%x, device=%x\n", vendor_id, device_id);
458     for (i = 0, pci_addr.bus = 0; i < PCI_BUS_MAX; i++, pci_addr.bus++) {
459         for (j = 0, pci_addr.dev = 0; j < PCI_DEV_MAX; j++, pci_addr.dev++) {
460             for (k = 0, pci_addr.func = 0; k < PCI_FN_MAX; k++, pci_addr.func++) {
461
462                 v3_outdw(PCI_CFG_ADDR, pci_addr.value);
463                 pci_hdr.value = v3_indw(PCI_CFG_DATA);
464
465                 //PrintDebug("\bus=%d, tvendor=%x, device=%x\n", pci_addr.bus, pci_hdr.vendor, pci_hdr.device);
466
467                 if ((pci_hdr.vendor == vendor_id) && (pci_hdr.device == device_id)) {
468                     uint32_t * cfg_space = (uint32_t *)&state->real_hdr;
469     
470                     state->phys_pci_addr = pci_addr;
471
472                     // Copy the configuration space to the local cached version
473                     for (m = 0, pci_addr.reg = 0; m < PCI_HDR_SIZE; m += 4, pci_addr.reg++) {
474                         cfg_space[pci_addr.reg] = pci_cfg_read32(pci_addr.value);
475                     }
476
477
478                     PrintDebug("Found device %x:%x (bus=%d, dev=%d, func=%d)\n", 
479                                vendor_id, device_id, 
480                                pci_addr.bus, pci_addr.dev, pci_addr.func);
481
482                     return 0;
483                 }
484             }
485         }
486     }
487
488     return -1;
489 }
490
491
492
493 static int setup_virt_pci_dev(struct guest_info * info, struct vm_device * dev) {
494     struct pt_dev_state * state = (struct pt_dev_state *)dev->private_data;
495     struct pci_device * pci_dev = NULL;
496     struct v3_pci_bar bars[6];
497     int bus_num = 0;
498     int i;
499
500     for (i = 0; i < 6; i++) {
501         bars[i].type = PCI_BAR_PASSTHROUGH;
502         bars[i].private_data = dev;
503         bars[i].bar_init = pci_bar_init;
504         bars[i].bar_write = pci_bar_write;
505     }
506
507     pci_dev = v3_pci_register_device(state->pci_bus,
508                                      PCI_STD_DEVICE,
509                                      bus_num, -1, 0, 
510                                      state->name, bars,
511                                      pt_config_update, NULL, NULL, 
512                                      dev);
513     
514     // This will overwrite the bar registers.. but that should be ok.
515     memcpy(pci_dev->config_space, (uint8_t *)&(state->real_hdr), sizeof(struct pci_config_header));
516
517     state->pci_dev = pci_dev;
518
519     v3_sym_map_pci_passthrough(info, pci_dev->bus_num, pci_dev->dev_num, pci_dev->fn_num);
520
521
522     return 0;
523 }
524
525
526 static struct v3_device_ops dev_ops = {
527     .free = NULL,
528     .reset = NULL,
529     .start = NULL,
530     .stop = NULL,
531 };
532
533
534
535 static int irq_handler(struct guest_info * info, struct v3_interrupt * intr, void * private_data) {
536     struct vm_device * dev = (struct vm_device *)private_data;
537     struct pt_dev_state * state = (struct pt_dev_state *)dev->private_data;
538
539 //    PrintDebug("Handling E1000 IRQ %d\n", intr->irq);
540
541     v3_pci_raise_irq(state->pci_bus, 0, state->pci_dev);
542
543     V3_ACK_IRQ(intr->irq);
544
545     return 0;
546 }
547
548
549
550
551 static int passthrough_init(struct guest_info * info, v3_cfg_tree_t * cfg) {
552     struct pt_dev_state * state = V3_Malloc(sizeof(struct pt_dev_state));
553     struct vm_device * dev = NULL;
554     struct vm_device * pci = v3_find_dev(info, v3_cfg_val(cfg, "bus"));
555     char * name = v3_cfg_val(cfg, "name");    
556
557     memset(state, 0, sizeof(struct pt_dev_state));
558
559     if (!pci) {
560         PrintError("Could not find PCI device\n");
561         return -1;
562     }
563     
564     state->pci_bus = pci;
565     strncpy(state->name, name, 32);
566
567
568     dev = v3_allocate_device(name, &dev_ops, state);
569
570     if (v3_attach_device(info, dev) == -1) {
571         PrintError("Could not attach device %s\n", name);
572         return -1;
573     }
574
575
576     if (find_real_pci_dev(atox(v3_cfg_val(cfg, "vendor_id")), 
577                           atox(v3_cfg_val(cfg, "device_id")), 
578                           state) == -1) {
579         PrintError("Could not find PCI Device %s:%s\n", 
580                    v3_cfg_val(cfg, "vendor_id"), 
581                    v3_cfg_val(cfg, "device_id"));
582         return 0;
583     }
584
585     setup_virt_pci_dev(info, dev);
586
587     v3_hook_irq(info, atoi(v3_cfg_val(cfg, "irq")), irq_handler, dev);
588     //    v3_hook_irq(info, 64, irq_handler, dev);
589
590     return 0;
591 }
592
593
594
595
596 device_register("PCI_PASSTHROUGH", passthrough_init)