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.


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