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.


lots of fixes
[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 src=0x%x\n", *src);
335
336     if (vbar->type == PT_BAR_NONE) {
337         return 0;
338     } else if (vbar->type == PT_BAR_IO) {
339         int i = 0;
340
341         // unhook old ports
342         for (i = 0; i < vbar->size; i++) {
343             if (v3_unhook_io_port(dev->vm, vbar->addr + i) == -1) {
344                 PrintError("Could not unhook previously hooked port.... %d (0x%x)\n", 
345                            vbar->addr + i, vbar->addr + i);
346                 return -1;
347             }
348         }
349
350         PrintDebug("Setting IO Port range size=%d\n", pbar->size);
351
352         // clear the low bits to match the size
353         *src &= ~(pbar->size - 1);
354
355         // Set reserved bits
356         *src |= (pbar->val & ~PCI_IO_MASK);
357
358         vbar->addr = PCI_IO_BASE(*src); 
359
360         PrintDebug("Cooked src=0x%x\n", *src);
361
362         PrintDebug("Rehooking passthrough IO ports starting at %d (0x%x)\n", 
363                    vbar->addr, vbar->addr);
364
365         if (vbar->addr == pbar->addr) {
366             // Map the io ports as passthrough
367             for (i = 0; i < pbar->size; i++) {
368                 v3_hook_io_port(dev->vm, pbar->addr + i, NULL, NULL, NULL); 
369             }
370         } else {
371             // We have to manually handle the io redirection
372             for (i = 0; i < vbar->size; i++) {
373                 v3_hook_io_port(dev->vm, vbar->addr + i, pt_io_read, pt_io_write, pbar); 
374             }
375         }
376     } else if (vbar->type == PT_BAR_MEM32) {
377         // remove old mapping
378         struct v3_shadow_region * old_reg = v3_get_shadow_region(dev->vm, vbar->addr);
379
380         if (old_reg == NULL) {
381             // uh oh...
382             PrintError("Could not find PCI Passthrough memory redirection region (addr=0x%x)\n", vbar->addr);
383             return -1;
384         }
385
386         v3_delete_shadow_region(dev->vm, old_reg);
387
388         // clear the low bits to match the size
389         *src &= ~(pbar->size - 1);
390
391         // Set reserved bits
392         *src |= (pbar->val & ~PCI_MEM_MASK);
393
394         PrintDebug("Cooked src=0x%x\n", *src);
395
396         vbar->addr = PCI_MEM32_BASE(*src);
397
398         PrintDebug("Adding pci Passthrough remapping: start=0x%x, size=%d, end=0x%x\n", 
399                    vbar->addr, vbar->size, vbar->addr + vbar->size);
400
401         v3_add_shadow_mem(dev->vm, 
402                           vbar->addr, 
403                           vbar->addr + vbar->size - 1,
404                           pbar->addr);
405         
406     } else {
407         PrintError("Unhandled Pasthrough PCI Bar type %d\n", vbar->type);
408         return -1;
409     }
410
411
412     vbar->val = *src;
413     
414
415     return 0;
416 }
417
418
419 static int pt_config_update(uint_t reg_num, void * src, uint_t length, void * private_data) {
420     struct vm_device * dev = (struct vm_device *)private_data;
421     struct pt_dev_state * state = (struct pt_dev_state *)dev->private_data;
422     union pci_addr_reg pci_addr = {state->phys_pci_addr.value};
423
424     pci_addr.reg = reg_num;
425
426     if (length == 1) {
427         pci_cfg_write8(pci_addr.value, *(uint8_t *)src);
428     } else if (length == 2) {
429         pci_cfg_write16(pci_addr.value, *(uint16_t *)src);
430     } else if (length == 4) {
431         pci_cfg_write32(pci_addr.value, *(uint32_t *)src);      
432     }
433
434     
435     return 0;
436 }
437
438
439
440 static int find_real_pci_dev(uint16_t vendor_id, uint16_t device_id, struct pt_dev_state * state) {
441     union pci_addr_reg pci_addr = {0x80000000};
442     uint_t i, j, k, m;    
443
444     union {
445         uint32_t value;
446         struct {
447             uint16_t vendor;
448             uint16_t device;
449         } __attribute__((packed));
450     } __attribute__((packed)) pci_hdr = {0};
451
452
453     //PrintDebug("Scanning PCI busses for vendor=%x, device=%x\n", vendor_id, device_id);
454     for (i = 0, pci_addr.bus = 0; i < PCI_BUS_MAX; i++, pci_addr.bus++) {
455         for (j = 0, pci_addr.dev = 0; j < PCI_DEV_MAX; j++, pci_addr.dev++) {
456             for (k = 0, pci_addr.func = 0; k < PCI_FN_MAX; k++, pci_addr.func++) {
457
458                 v3_outdw(PCI_CFG_ADDR, pci_addr.value);
459                 pci_hdr.value = v3_indw(PCI_CFG_DATA);
460
461                 //PrintDebug("\bus=%d, tvendor=%x, device=%x\n", pci_addr.bus, pci_hdr.vendor, pci_hdr.device);
462
463                 if ((pci_hdr.vendor == vendor_id) && (pci_hdr.device == device_id)) {
464                     uint32_t * cfg_space = (uint32_t *)&state->real_hdr;
465     
466                     state->phys_pci_addr = pci_addr;
467
468                     // Copy the configuration space to the local cached version
469                     for (m = 0, pci_addr.reg = 0; m < PCI_HDR_SIZE; m += 4, pci_addr.reg++) {
470                         cfg_space[pci_addr.reg] = pci_cfg_read32(pci_addr.value);
471                     }
472
473
474                     PrintDebug("Found device %x:%x (bus=%d, dev=%d, func=%d)\n", 
475                                vendor_id, device_id, 
476                                pci_addr.bus, pci_addr.dev, pci_addr.func);
477
478                     return 0;
479                 }
480             }
481         }
482     }
483
484     return -1;
485 }
486
487
488
489 static int setup_virt_pci_dev(struct guest_info * info, struct vm_device * dev) {
490     struct pt_dev_state * state = (struct pt_dev_state *)dev->private_data;
491     struct pci_device * pci_dev = NULL;
492     struct v3_pci_bar bars[6];
493     int bus_num = 0;
494     int i;
495
496     for (i = 0; i < 6; i++) {
497         bars[i].type = PCI_BAR_PASSTHROUGH;
498         bars[i].private_data = dev;
499         bars[i].bar_init = pci_bar_init;
500         bars[i].bar_write = pci_bar_write;
501     }
502
503     pci_dev = v3_pci_register_device(state->pci_bus,
504                                      PCI_STD_DEVICE,
505                                      bus_num, -1, 0, 
506                                      state->name, bars,
507                                      pt_config_update, NULL, NULL, 
508                                      dev);
509     
510     // This will overwrite the bar registers.. but that should be ok.
511     memcpy(pci_dev->config_space, (uint8_t *)&(state->real_hdr), sizeof(struct pci_config_header));
512
513     state->pci_dev = pci_dev;
514
515     v3_sym_map_pci_passthrough(info, pci_dev->bus_num, pci_dev->dev_num, pci_dev->fn_num);
516
517
518     return 0;
519 }
520
521
522 static struct v3_device_ops dev_ops = {
523     .free = NULL,
524     .reset = NULL,
525     .start = NULL,
526     .stop = NULL,
527 };
528
529
530
531 static int irq_handler(struct guest_info * info, struct v3_interrupt * intr, void * private_data) {
532     struct vm_device * dev = (struct vm_device *)private_data;
533     struct pt_dev_state * state = (struct pt_dev_state *)dev->private_data;
534
535 //    PrintDebug("Handling E1000 IRQ %d\n", intr->irq);
536
537     v3_pci_raise_irq(state->pci_bus, 0, state->pci_dev);
538
539     V3_ACK_IRQ(intr->irq);
540
541     return 0;
542 }
543
544
545
546
547 static int passthrough_init(struct guest_info * info, v3_cfg_tree_t * cfg) {
548     struct pt_dev_state * state = V3_Malloc(sizeof(struct pt_dev_state));
549     struct vm_device * dev = NULL;
550     struct vm_device * pci = v3_find_dev(info, v3_cfg_val(cfg, "bus"));
551     char * name = v3_cfg_val(cfg, "name");    
552
553     memset(state, 0, sizeof(struct pt_dev_state));
554
555     if (!pci) {
556         PrintError("Could not find PCI device\n");
557         return -1;
558     }
559     
560     state->pci_bus = pci;
561     strncpy(state->name, name, 32);
562
563
564     dev = v3_allocate_device(name, &dev_ops, state);
565
566     if (v3_attach_device(info, dev) == -1) {
567         PrintError("Could not attach device %s\n", name);
568         return -1;
569     }
570
571
572     if (find_real_pci_dev(atox(v3_cfg_val(cfg, "vendor_id")), 
573                           atox(v3_cfg_val(cfg, "device_id")), 
574                           state) == -1) {
575         PrintError("Could not find PCI Device %s:%s\n", 
576                    v3_cfg_val(cfg, "vendor_id"), 
577                    v3_cfg_val(cfg, "device_id"));
578         return 0;
579     }
580
581     setup_virt_pci_dev(info, dev);
582
583     v3_hook_irq(info, atoi(v3_cfg_val(cfg, "irq")), irq_handler, dev);
584     //    v3_hook_irq(info, 64, irq_handler, dev);
585
586     return 0;
587 }
588
589
590
591
592 device_register("PCI_PASSTHROUGH", passthrough_init)