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.


fafd30339ab0c32b6280dcfcf10d3d899b78d05f
[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         
196         V3_Print("IO Bar with %d (%x) ports %x->%x\n", pbar->size, pbar->size, pbar->addr, pbar->addr + pbar->size);
197         // setup a set of null io hooks
198         // This allows the guest to do passthrough IO to these ports
199         // While still reserving them in the IO map
200         for (i = 0; i < pbar->size; i++) {
201             v3_hook_io_port(dev->vm, pbar->addr + i, NULL, NULL, NULL); 
202         }
203
204     } else {
205
206         // might be memory, might be nothing    
207
208         max_val = bar_val | PCI_MEM_MASK;
209
210         // Cycle the physical bar, to determine the actual size
211         // Disable irqs, to try to prevent accesses to the space via a interrupt handler
212         // This is not SMP safe!!
213         // What we probably want to do is write a 0 to the command register
214         //irq_state = v3_irq_save();
215         
216         pci_cfg_write32(pci_addr.value, max_val);
217         max_val = pci_cfg_read32(pci_addr.value);
218         pci_cfg_write32(pci_addr.value, bar_val);
219
220         //v3_irq_restore(irq_state);
221
222         
223         if (max_val == 0) {
224             pbar->type = PT_BAR_NONE;
225         } else {
226
227             // if its a memory region, setup passthrough mem mapping
228
229             if ((bar_val & 0x6) == 0x0) {
230                 // MEM 32
231                 pbar->type = PT_BAR_MEM32;
232                 pbar->addr = PCI_MEM32_BASE(bar_val);
233                 pbar->size = ~PCI_MEM32_BASE(max_val) + 1;
234
235                 PrintDebug("Adding 32 bit PCI mem region: start=0x%x, end=0x%x\n",
236                            pbar->addr, pbar->addr + pbar->size);
237
238                 v3_add_shadow_mem(dev->vm, 
239                                   pbar->addr, 
240                                   pbar->addr + pbar->size - 1,
241                                   pbar->addr);
242
243             } else if ((bar_val & 0x6) == 0x2) {
244                 // Mem 24
245                 pbar->type = PT_BAR_MEM24;
246                 pbar->addr = PCI_MEM24_BASE(bar_val);
247                 pbar->size = ~PCI_MEM24_BASE(max_val) + 1;
248
249                 v3_add_shadow_mem(dev->vm, 
250                                   pbar->addr, 
251                                   pbar->addr + pbar->size - 1,
252                                   pbar->addr);
253
254             } else if ((bar_val & 0x6) == 0x4) {
255                 // Mem 64
256                 PrintError("64 Bit PCI bars not supported\n");
257                 return -1;
258             } else {
259                 PrintError("Invalid Memory bar type\n");
260                 return -1;
261             }
262
263         }
264     }
265     
266
267
268
269     // Initially the virtual bars match the physical ones
270     memcpy(&(state->virt_bars[bar_num]), &(state->phys_bars[bar_num]), sizeof(struct pt_bar));
271
272     PrintDebug("bar_num=%d, bar_val=0x%x\n", bar_num, bar_val);
273
274     PrintDebug("phys bar  type=%d, addr=0x%x, size=%d\n", 
275                pbar->type, pbar->addr, 
276                pbar->size);
277
278     PrintDebug("virt bar  type=%d, addr=0x%x, size=%d\n",
279                state->virt_bars[bar_num].type, state->virt_bars[bar_num].addr, 
280                state->virt_bars[bar_num].size);
281
282
283
284     // Update the pci subsystem versions
285     *dst = bar_val;
286
287     return 0;
288 }
289
290 static int pt_io_read(uint16_t port, void * dst, uint_t length, void * priv_data) {
291     struct pt_bar * pbar = (struct pt_bar *)priv_data;
292     int port_offset = port % pbar->size;
293
294     if (length == 1) {
295         *(uint8_t *)dst = v3_inb(pbar->addr + port_offset);
296     } else if (length == 2) {
297         *(uint16_t *)dst = v3_inw(pbar->addr + port_offset);
298     } else if (length == 4) {
299         *(uint32_t *)dst = v3_indw(pbar->addr + port_offset);
300     } else {
301         PrintError("Invalid PCI passthrough IO Redirection size read\n");
302         return -1;
303     }
304
305     return length;
306 }
307
308
309 static int pt_io_write(uint16_t port, void * src, uint_t length, void * priv_data) {
310     struct pt_bar * pbar = (struct pt_bar *)priv_data;
311     int port_offset = port % pbar->size;
312     
313     if (length == 1) {
314         v3_outb(pbar->addr + port_offset, *(uint8_t *)src);
315     } else if (length == 2) {
316         v3_outw(pbar->addr + port_offset, *(uint16_t *)src);
317     } else if (length == 4) {
318         v3_outdw(pbar->addr + port_offset, *(uint32_t *)src);
319     } else {
320         PrintError("Invalid PCI passthrough IO Redirection size write\n");
321         return -1;
322     }
323     
324     return length;
325
326 }
327
328
329
330
331
332 static int pci_bar_write(int bar_num, uint32_t * src, void * private_data) {
333     struct vm_device * dev = (struct vm_device *)private_data;
334     struct pt_dev_state * state = (struct pt_dev_state *)dev->private_data;
335     
336     struct pt_bar * pbar = &(state->phys_bars[bar_num]);
337     struct pt_bar * vbar = &(state->virt_bars[bar_num]);
338
339     PrintDebug("Bar update src=0x%x\n", *src);
340
341     if (vbar->type == PT_BAR_NONE) {
342         return 0;
343     } else if (vbar->type == PT_BAR_IO) {
344         int i = 0;
345
346         // unhook old ports
347         for (i = 0; i < vbar->size; i++) {
348             if (v3_unhook_io_port(dev->vm, vbar->addr + i) == -1) {
349                 PrintError("Could not unhook previously hooked port.... %d (0x%x)\n", 
350                            vbar->addr + i, vbar->addr + i);
351                 return -1;
352             }
353         }
354
355         PrintDebug("Setting IO Port range size=%d\n", pbar->size);
356
357         // clear the low bits to match the size
358         *src &= ~(pbar->size - 1);
359
360         // Set reserved bits
361         *src |= (pbar->val & ~PCI_IO_MASK);
362
363         vbar->addr = PCI_IO_BASE(*src); 
364
365         PrintDebug("Cooked src=0x%x\n", *src);
366
367         PrintDebug("Rehooking passthrough IO ports starting at %d (0x%x)\n", 
368                    vbar->addr, vbar->addr);
369
370         if (vbar->addr == pbar->addr) {
371             // Map the io ports as passthrough
372             for (i = 0; i < pbar->size; i++) {
373                 v3_hook_io_port(dev->vm, pbar->addr + i, NULL, NULL, NULL); 
374             }
375         } else {
376             // We have to manually handle the io redirection
377             for (i = 0; i < vbar->size; i++) {
378                 v3_hook_io_port(dev->vm, vbar->addr + i, pt_io_read, pt_io_write, pbar); 
379             }
380         }
381     } else if (vbar->type == PT_BAR_MEM32) {
382         // remove old mapping
383         struct v3_shadow_region * old_reg = v3_get_shadow_region(dev->vm, vbar->addr);
384
385         if (old_reg == NULL) {
386             // uh oh...
387             PrintError("Could not find PCI Passthrough memory redirection region (addr=0x%x)\n", vbar->addr);
388             return -1;
389         }
390
391         v3_delete_shadow_region(dev->vm, old_reg);
392
393         // clear the low bits to match the size
394         *src &= ~(pbar->size - 1);
395
396         // Set reserved bits
397         *src |= (pbar->val & ~PCI_MEM_MASK);
398
399         PrintDebug("Cooked src=0x%x\n", *src);
400
401         vbar->addr = PCI_MEM32_BASE(*src);
402
403         PrintDebug("Adding pci Passthrough remapping: start=0x%x, size=%d, end=0x%x\n", 
404                    vbar->addr, vbar->size, vbar->addr + vbar->size);
405
406         v3_add_shadow_mem(dev->vm, 
407                           vbar->addr, 
408                           vbar->addr + vbar->size - 1,
409                           pbar->addr);
410         
411     } else {
412         PrintError("Unhandled Pasthrough PCI Bar type %d\n", vbar->type);
413         return -1;
414     }
415
416
417     vbar->val = *src;
418     
419
420     return 0;
421 }
422
423
424 static int pt_config_update(uint_t reg_num, void * src, uint_t length, void * private_data) {
425     struct vm_device * dev = (struct vm_device *)private_data;
426     struct pt_dev_state * state = (struct pt_dev_state *)dev->private_data;
427     union pci_addr_reg pci_addr = {state->phys_pci_addr.value};
428
429     pci_addr.reg = reg_num;
430
431     if (length == 1) {
432         pci_cfg_write8(pci_addr.value, *(uint8_t *)src);
433     } else if (length == 2) {
434         pci_cfg_write16(pci_addr.value, *(uint16_t *)src);
435     } else if (length == 4) {
436         pci_cfg_write32(pci_addr.value, *(uint32_t *)src);      
437     }
438
439     
440     return 0;
441 }
442
443
444
445 static int find_real_pci_dev(uint16_t vendor_id, uint16_t device_id, struct pt_dev_state * state) {
446     union pci_addr_reg pci_addr = {0x80000000};
447     uint_t i, j, k, m;    
448
449     union {
450         uint32_t value;
451         struct {
452             uint16_t vendor;
453             uint16_t device;
454         } __attribute__((packed));
455     } __attribute__((packed)) pci_hdr = {0};
456
457
458     //PrintDebug("Scanning PCI busses for vendor=%x, device=%x\n", vendor_id, device_id);
459     for (i = 0, pci_addr.bus = 0; i < PCI_BUS_MAX; i++, pci_addr.bus++) {
460         for (j = 0, pci_addr.dev = 0; j < PCI_DEV_MAX; j++, pci_addr.dev++) {
461             for (k = 0, pci_addr.func = 0; k < PCI_FN_MAX; k++, pci_addr.func++) {
462
463                 v3_outdw(PCI_CFG_ADDR, pci_addr.value);
464                 pci_hdr.value = v3_indw(PCI_CFG_DATA);
465
466                 //PrintDebug("\bus=%d, tvendor=%x, device=%x\n", pci_addr.bus, pci_hdr.vendor, pci_hdr.device);
467
468                 if ((pci_hdr.vendor == vendor_id) && (pci_hdr.device == device_id)) {
469                     uint32_t * cfg_space = (uint32_t *)&state->real_hdr;
470     
471                     state->phys_pci_addr = pci_addr;
472
473                     // Copy the configuration space to the local cached version
474                     for (m = 0, pci_addr.reg = 0; m < PCI_HDR_SIZE; m += 4, pci_addr.reg++) {
475                         cfg_space[pci_addr.reg] = pci_cfg_read32(pci_addr.value);
476                     }
477
478
479                     PrintDebug("Found device %x:%x (bus=%d, dev=%d, func=%d)\n", 
480                                vendor_id, device_id, 
481                                pci_addr.bus, pci_addr.dev, pci_addr.func);
482
483                     return 0;
484                 }
485             }
486         }
487     }
488
489     return -1;
490 }
491
492
493
494 static int setup_virt_pci_dev(struct guest_info * info, struct vm_device * dev) {
495     struct pt_dev_state * state = (struct pt_dev_state *)dev->private_data;
496     struct pci_device * pci_dev = NULL;
497     struct v3_pci_bar bars[6];
498     int bus_num = 0;
499     int i;
500
501     for (i = 0; i < 6; i++) {
502         bars[i].type = PCI_BAR_PASSTHROUGH;
503         bars[i].private_data = dev;
504         bars[i].bar_init = pci_bar_init;
505         bars[i].bar_write = pci_bar_write;
506     }
507
508     pci_dev = v3_pci_register_device(state->pci_bus,
509                                      PCI_STD_DEVICE,
510                                      bus_num, -1, 0, 
511                                      state->name, bars,
512                                      pt_config_update, NULL, NULL, 
513                                      dev);
514     
515     // This will overwrite the bar registers.. but that should be ok.
516     memcpy(pci_dev->config_space, (uint8_t *)&(state->real_hdr), sizeof(struct pci_config_header));
517
518     state->pci_dev = pci_dev;
519
520     v3_sym_map_pci_passthrough(info, pci_dev->bus_num, pci_dev->dev_num, pci_dev->fn_num);
521
522
523     return 0;
524 }
525
526
527 static struct v3_device_ops dev_ops = {
528     .free = NULL,
529     .reset = NULL,
530     .start = NULL,
531     .stop = NULL,
532 };
533
534
535
536 static int irq_handler(struct guest_info * info, struct v3_interrupt * intr, void * private_data) {
537     struct vm_device * dev = (struct vm_device *)private_data;
538     struct pt_dev_state * state = (struct pt_dev_state *)dev->private_data;
539
540 //    PrintDebug("Handling E1000 IRQ %d\n", intr->irq);
541
542     v3_pci_raise_irq(state->pci_bus, 0, state->pci_dev);
543
544     V3_ACK_IRQ(intr->irq);
545
546     return 0;
547 }
548
549
550
551
552 static int passthrough_init(struct guest_info * info, v3_cfg_tree_t * cfg) {
553     struct pt_dev_state * state = V3_Malloc(sizeof(struct pt_dev_state));
554     struct vm_device * dev = NULL;
555     struct vm_device * pci = v3_find_dev(info, v3_cfg_val(cfg, "bus"));
556     char * name = v3_cfg_val(cfg, "name");    
557
558     memset(state, 0, sizeof(struct pt_dev_state));
559
560     if (!pci) {
561         PrintError("Could not find PCI device\n");
562         return -1;
563     }
564     
565     state->pci_bus = pci;
566     strncpy(state->name, name, 32);
567
568
569     dev = v3_allocate_device(name, &dev_ops, state);
570
571     if (v3_attach_device(info, dev) == -1) {
572         PrintError("Could not attach device %s\n", name);
573         return -1;
574     }
575
576
577     if (find_real_pci_dev(atox(v3_cfg_val(cfg, "vendor_id")), 
578                           atox(v3_cfg_val(cfg, "device_id")), 
579                           state) == -1) {
580         PrintError("Could not find PCI Device %s:%s\n", 
581                    v3_cfg_val(cfg, "vendor_id"), 
582                    v3_cfg_val(cfg, "device_id"));
583         return 0;
584     }
585
586     setup_virt_pci_dev(info, dev);
587
588     v3_hook_irq(info, atoi(v3_cfg_val(cfg, "irq")), irq_handler, dev);
589     //    v3_hook_irq(info, 64, irq_handler, dev);
590
591     return 0;
592 }
593
594
595
596
597 device_register("PCI_PASSTHROUGH", passthrough_init)