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.


Ability to add remappable roms for pci front-end devices.
[palacios.git] / palacios / src / devices / pci_front.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) 2011, Peter Dinda <pdinda@northwestern.edu>
11  * Copyright (c) 2008, Jack Lange <jarusl@cs.northwestern.edu>
12  * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org> 
13  * All rights reserved.
14  *
15  * Authors: 
16  *    Peter Dinda <pdinda@northwestern.edu>    (PCI front device forwarding to host dev interface)
17  *    Jack Lange <jarusl@cs.northwestern.edu>  (original PCI passthrough to physical hardware)
18  *
19  * This is free software.  You are permitted to use,
20  * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
21  */
22
23
24 /* 
25   This is front-end PCI device intended to be used together with the
26   host device interface and a *virtual* PCI device implementation in
27   the host OS.  It makes it possible to project such a virtual device
28   into the guest as a PCI device.  It's based on the PCI passthrough
29   device, which projects *physical* PCI devices into the guest.
30
31   If you need to project a non-PCI host-based virtual or physical
32   device into the guest, you should use the generic device.
33
34 */
35
36 /* 
37  * The basic idea is that we do not change the hardware PCI configuration
38  * Instead we modify the guest environment to map onto the physical configuration
39  * 
40  * The pci subsystem handles most of the configuration space, except for the bar registers.
41  * We handle them here, by either letting them go directly to hardware or remapping through virtual hooks
42  * 
43  * Memory Bars are always remapped via the shadow map, 
44  * IO Bars are selectively remapped through hooks if the guest changes them 
45  */
46
47 #include <palacios/vmm.h>
48 #include <palacios/vmm_dev_mgr.h>
49 #include <palacios/vmm_sprintf.h>
50 #include <palacios/vmm_lowlevel.h>
51 #include <palacios/vm_guest.h> 
52 #include <palacios/vmm_symspy.h>
53
54 #include <devices/pci.h>
55 #include <devices/pci_types.h>
56
57 #include <interfaces/vmm_host_dev.h>
58
59
60 #ifndef V3_CONFIG_DEBUG_PCI_FRONT
61 #undef PrintDebug
62 #define PrintDebug(fmt, args...)
63 #endif
64
65
66 // Our own address in PCI-land
67 union pci_addr_reg {
68     uint32_t value;
69     struct {
70         uint_t rsvd1   : 2;
71         uint_t reg     : 6;
72         uint_t func    : 3;
73         uint_t dev     : 5;
74         uint_t bus     : 8;
75         uint_t rsvd2   : 7;
76         uint_t enable  : 1;
77     } __attribute__((packed));
78 } __attribute__((packed));
79
80
81 // identical to PCI passthrough device
82 typedef enum { PT_BAR_NONE,
83                PT_BAR_IO, 
84                PT_BAR_MEM32, 
85                PT_BAR_MEM24, 
86                PT_BAR_MEM64_LO, 
87                PT_BAR_MEM64_HI,
88                PT_EXP_ROM } pt_bar_type_t;
89
90 // identical to PCI passthrough device
91 struct pt_bar {
92     uint32_t size;
93     pt_bar_type_t type;
94
95     /*  We store 64 bit memory bar addresses in the high BAR
96      *  because they are the last to be updated
97      *  This means that the addr field must be 64 bits
98      */
99     uint64_t addr; 
100
101     uint32_t val;
102     uint8_t mapped; 
103 };
104
105
106
107
108 struct pci_front_internal {
109     // this is our local cache of what the host device has
110     union {
111         uint8_t config_space[256];
112         struct pci_config_header real_hdr;
113     } __attribute__((packed));
114     
115     // We do need a representation of the bars
116     // since we need to be made aware when they are written
117     // so that we can change the hooks.
118     //
119     // We assume here that the PCI subsystem, on a bar write
120     // will first send us a config_update, which we forward to
121     // the host dev.   Then it will send us a bar update
122     // which we will use to rehook the device
123     //
124     struct pt_bar bars[6];      // our bars (for update purposes)
125     //
126     // Currently unsupported
127     //
128     //struct pt_bar exp_rom;      // and exp ram areas of the config space, above
129      
130     struct vm_device  *pci_bus;  // what bus we are attached to
131     struct pci_device *pci_dev;  // our representation as a registered PCI device
132
133     union pci_addr_reg pci_addr; // our pci address
134
135     char name[32];
136
137     v3_host_dev_t     host_dev;  // the actual implementation
138
139     void              *rom_hpa;  // where our copy of the rom is in the host (physically cont.)
140     uint64_t           rom_size; // bytes
141     void              *rom_gpa;  // where we are mapping it into the guest
142     
143 };
144
145
146
147 /*
148 static int push_config(struct pci_front_internal *state, uint8_t *config)
149 {
150     if (v3_host_dev_config_write(state->host_dev, 0, config, 256) != 256) { 
151         return -1;
152     } else {
153         return 0;
154     }
155 }
156 */
157
158 static int pull_config(struct pci_front_internal *state, uint8_t *config)
159 {
160     if (v3_host_dev_read_config(state->host_dev, 0, config, 256) != 256) { 
161         return -1;
162     } else {
163         return 0;
164     }
165 }
166
167
168 static int pci_front_read_mem(struct guest_info * core, 
169                               addr_t              gpa,
170                               void              * dst,
171                               uint_t              len,
172                               void              * priv)
173 {
174     int i;
175     int rc;
176     struct vm_device *dev = (struct vm_device *) priv;
177     struct pci_front_internal *state = (struct pci_front_internal *) dev->private_data;
178
179     PrintDebug(core->vm_info, core, "pci_front (%s): reading 0x%x bytes from gpa 0x%p from host dev 0x%p ...",
180                state->name, len, (void*)gpa, state->host_dev);
181
182     rc = v3_host_dev_read_mem(state->host_dev, gpa, dst, len);
183
184     PrintDebug(core->vm_info, core, " done ... read %d bytes: 0x", rc);
185
186     for (i = 0; i < rc; i++) { 
187         PrintDebug(core->vm_info, core, "%x", ((uint8_t *)dst)[i]);
188     }
189
190     PrintDebug(core->vm_info, core, "\n");
191
192     return rc;
193 }
194
195 static int pci_front_write_mem(struct guest_info * core, 
196                                addr_t              gpa,
197                                void              * src,
198                                uint_t              len,
199                                void              * priv)
200 {
201     int i;
202     int rc;
203     struct vm_device *dev = (struct vm_device *) priv;
204     struct pci_front_internal *state = (struct pci_front_internal *) dev->private_data;
205
206     PrintDebug(core->vm_info, core, "pci_front (%s): writing 0x%x bytes to gpa 0x%p to host dev 0x%p bytes=0x",
207                state->name, len, (void*)gpa, state->host_dev);
208
209     for (i = 0; i < len; i++) { 
210         PrintDebug(core->vm_info, core, "%x", ((uint8_t *)src)[i]);
211     }
212
213     rc = v3_host_dev_write_mem(state->host_dev, gpa, src, len);
214
215     PrintDebug(core->vm_info, core, " %d bytes written\n",rc);
216     
217     return rc;
218 }
219
220
221 static int pci_front_read_port(struct guest_info * core, 
222                                uint16_t            port, 
223                                void              * dst, 
224                                uint_t              len, 
225                                void              * priv_data) 
226 {
227     int i;
228     struct pci_front_internal *state = (struct pci_front_internal *) priv_data;
229     
230     PrintDebug(core->vm_info, core, "pci_front (%s): reading 0x%x bytes from port 0x%x from host dev 0x%p ...",
231                state->name, len, port, state->host_dev);
232
233     int rc = v3_host_dev_read_io(state->host_dev, port, dst, len);
234     
235     PrintDebug(core->vm_info, core, " done ... read %d bytes: 0x", rc);
236
237     for (i = 0; i < rc; i++) { 
238         PrintDebug(core->vm_info, core, "%x", ((uint8_t *)dst)[i]);
239     }
240
241     PrintDebug(core->vm_info, core, "\n");
242
243     return rc;
244     
245 }
246
247 static int pci_front_write_port(struct guest_info * core, 
248                                 uint16_t            port, 
249                                 void              * src, 
250                                 uint_t              len, 
251                                 void              * priv_data) 
252 {
253     int i;
254     struct pci_front_internal *state = (struct pci_front_internal *) priv_data;
255
256     
257     PrintDebug(core->vm_info, core, "pci_front (%s): writing 0x%x bytes to port 0x%x to host dev 0x%p bytes=0x",
258                state->name, len, port, state->host_dev);
259
260     for (i = 0; i < len; i++) { 
261         PrintDebug(core->vm_info, core, "%x", ((uint8_t *)src)[i]);
262     }
263
264     int rc = v3_host_dev_write_io(state->host_dev, port, src, len);
265
266     PrintDebug(core->vm_info, core, " %d bytes written\n",rc);
267     
268     return rc;
269 }
270
271
272
273 //
274 // This is called at registration time for the device
275 // 
276 // We assume that someone has called pull_config to get a local
277 // copy of the config data from the host device by this point
278 //
279 // It might be smarter to do the pull config here since 
280 // in init we may not yet have the host device running... 
281 //
282 // KCH: we need to make sure that we don't hook I/O BARs and Mem BARs that
283 // haven't been configured by anyone yet (e.g. QEMU)
284 static int pci_bar_init(int bar_num, uint32_t * dst, void * private_data) {
285     struct vm_device * dev = (struct vm_device *)private_data;
286     struct pci_front_internal * state = (struct pci_front_internal *)(dev->private_data);
287
288     /*
289     if (pull_config(state,state->config_space)) { 
290         PrintError(dev->vm, VCORE_NONE, "pci_front (%s): cannot initially configure device\n",state->name);
291         v3_remove_device(dev);
292         return -1;
293     }
294     */
295
296     const uint32_t bar_base_reg = 4;   // offset in 32bit words to skip to the first bar
297
298     union pci_addr_reg pci_addr = {state->pci_addr.value};  // my address
299
300     uint32_t bar_val = 0;
301     uint32_t max_val = 0;
302
303     struct pt_bar * pbar = &(state->bars[bar_num]);
304
305     pci_addr.reg = bar_base_reg + bar_num;
306
307     PrintDebug(dev->vm, VCORE_NONE, "pci_front (%s): pci_bar_init: PCI Address = 0x%x\n", state->name, pci_addr.value);
308
309     // This assumees that pull_config() has been previously called and 
310     // we have a local copy of the host device's configuration space
311     //bar_val = *((uint32_t*)(&(state->config_space[(bar_base_reg+bar_num)*4])));
312     v3_host_dev_read_config(state->host_dev, bar_num*4 + 16, &bar_val, 4);
313
314     // Now let's set our copy of the relevant bar accordingly
315     pbar->val = bar_val; 
316
317     // Now we will configure the hooks relevant to this bar
318
319     // We preset this type when we encounter a MEM64 Low BAR
320     // This is a 64 bit memory region that we turn into a memory hook
321     if (pbar->type == PT_BAR_MEM64_HI) {
322         struct pt_bar * lo_pbar = &(state->bars[bar_num - 1]);
323
324         max_val = PCI_MEM64_MASK_HI;
325
326         v3_host_dev_write_config(state->host_dev, bar_num*4 + 16, &max_val, 4);
327         v3_host_dev_read_config(state->host_dev, bar_num*4 + 16, &max_val, 4);
328         v3_host_dev_write_config(state->host_dev, bar_num*4 + 16, &bar_val, 4);
329
330         pbar->size += lo_pbar->size;
331
332         /* this BAR hasn't been mapped yet */
333         if (pbar->addr) {
334             pbar->mapped = 1;
335
336             PrintDebug(dev->vm, VCORE_NONE, "pci_front (%s): pci_bar_init: Adding 64 bit PCI mem region: start=0x%p, end=0x%p as a full hook\n",
337                     state->name, 
338                     (void *)(addr_t)pbar->addr, 
339                     (void *)(addr_t)(pbar->addr + pbar->size));
340
341             if (v3_hook_full_mem(dev->vm,
342                         V3_MEM_CORE_ANY,
343                         pbar->addr,
344                         pbar->addr+pbar->size-1,
345                         pci_front_read_mem,
346                         pci_front_write_mem,
347                         dev)<0) { 
348
349                 PrintError(dev->vm, VCORE_NONE, "pci_front (%s): pci_bar_init: failed to hook 64 bit region (0x%p, 0x%p)\n",
350                         state->name, 
351                         (void *)(addr_t)pbar->addr,
352                         (void *)(addr_t)(pbar->addr + pbar->size - 1));
353                 return -1;
354             }
355         }
356
357     } else if ((bar_val & 0x3) == 0x1) {
358         // This an I/O port region which we will turn into a range of hooks
359
360         int i = 0;
361
362         pbar->type = PT_BAR_IO;
363         pbar->addr = PCI_IO_BASE(bar_val);
364
365         max_val = bar_val | PCI_IO_MASK;
366
367         /*
368 uint64_t v3_host_dev_write_config(v3_host_dev_t hdev,
369                                   uint64_t offset,
370                                   void *src,
371                                   uint64_t len)
372                   */
373         
374
375         v3_host_dev_write_config(state->host_dev, bar_num*4 + 16, &max_val, 4);
376         v3_host_dev_read_config(state->host_dev, bar_num*4 + 16, &max_val, 4);
377         v3_host_dev_write_config(state->host_dev, bar_num*4 + 16, &bar_val, 4);
378
379         pbar->size = (uint16_t)~PCI_IO_BASE(max_val) + 1;
380         // ~((bar_val | PCI_IO_MASK) & PCI_IO_MASK) + 1 == ~(PCI_IO_MASK) + 1 == ~(0xfffffffc) + 1 == 0x3 + 1 == 0x4
381
382         if (pbar->addr) {
383             pbar->mapped = 1;
384
385             PrintDebug(dev->vm, VCORE_NONE, "pci_front (%s): pci_bar_init: hooking ports 0x%x through 0x%x\n",
386                     state->name, (uint32_t)pbar->addr, (uint32_t)pbar->addr + pbar->size - 1);
387
388             for (i = 0; i < pbar->size; i++) {
389                 if (v3_dev_hook_io(dev,
390                             pbar->addr + i, 
391                             pci_front_read_port,
392                             pci_front_write_port)<0) {
393                     PrintError(dev->vm, VCORE_NONE, "pci_front (%s): pci_bar_init: unabled to hook I/O port 0x%x\n",state->name, (unsigned)(pbar->addr+i));
394                     return -1;
395                 }
396             }
397         }
398
399     } else {
400
401         // might be a 32 bit memory region or an empty bar
402
403         max_val = bar_val | PCI_MEM_MASK;
404         v3_host_dev_write_config(state->host_dev, bar_num*4 + 16, &max_val, 4);
405         v3_host_dev_read_config(state->host_dev, bar_num*4 + 16, &max_val, 4);
406         v3_host_dev_write_config(state->host_dev, bar_num*4 + 16, &bar_val, 4);
407         
408
409         if (max_val == 0) {
410             // nothing, so just ignore it
411             pbar->type = PT_BAR_NONE;
412         } else {
413
414             // memory region - hook it
415
416             if ((bar_val & 0x6) == 0x0) {
417                 // 32 bit memory region
418
419                 pbar->type = PT_BAR_MEM32;
420                 pbar->addr = PCI_MEM32_BASE(bar_val);
421                 pbar->size = ~PCI_MEM32_BASE(max_val) + 1;
422
423                 if (pbar->addr) {
424                     pbar->mapped = 1;
425
426                     PrintDebug(dev->vm, VCORE_NONE, "pci_front (%s): pci_init_bar: adding 32 bit PCI mem region: start=0x%p, end=0x%p\n",
427                             state->name, 
428                             (void *)(addr_t)pbar->addr, 
429                             (void *)(addr_t)(pbar->addr + pbar->size));
430
431                     if (v3_hook_full_mem(dev->vm, 
432                                 V3_MEM_CORE_ANY,
433                                 pbar->addr,
434                                 pbar->addr+pbar->size-1,
435                                 pci_front_read_mem,
436                                 pci_front_write_mem,
437                                 dev) < 0 ) { 
438                         PrintError(dev->vm, VCORE_NONE, "pci_front (%s): pci_init_bar: unable to hook 32 bit memory region 0x%p to 0x%p\n",
439                                 state->name, (void*)(pbar->addr), (void*)(pbar->addr+pbar->size-1));
440                         return -1;
441                     }
442                 }
443
444             } else if ((bar_val & 0x6) == 0x2) {
445
446                 // 24 bit memory region
447
448                 pbar->type = PT_BAR_MEM24;
449                 pbar->addr = PCI_MEM24_BASE(bar_val);
450                 pbar->size = ~PCI_MEM24_BASE(max_val) + 1;
451
452                 if (pbar->addr) {
453                     pbar->mapped = 1;
454
455
456                     if (v3_hook_full_mem(dev->vm, 
457                                 V3_MEM_CORE_ANY,
458                                 pbar->addr,
459                                 pbar->addr+pbar->size-1,
460                                 pci_front_read_mem,
461                                 pci_front_write_mem,
462                                 dev) < 0 ) { 
463                         PrintError(dev->vm, VCORE_NONE, "pci_front (%s): pci_init_bar: unable to hook 24 bit memory region 0x%p to 0x%p\n",
464                                 state->name, (void*)(pbar->addr), (void*)(pbar->addr+pbar->size-1));
465                         return -1;
466                     }
467                 }
468
469             } else if ((bar_val & 0x6) == 0x4) {
470
471                 // partial update of a 64 bit region, no hook done yet
472
473                 struct pt_bar * hi_pbar = &(state->bars[bar_num + 1]);
474
475                 pbar->type = PT_BAR_MEM64_LO;
476                 hi_pbar->type = PT_BAR_MEM64_HI;
477
478                 // Set the low bits, only for temporary storage until we calculate the high BAR
479                 pbar->addr = PCI_MEM64_BASE_LO(bar_val);
480                 pbar->size = ~PCI_MEM64_BASE_LO(max_val) + 1;
481
482                 PrintDebug(dev->vm, VCORE_NONE, "pci_front (%s): pci_bar_init: partial 64 bit update\n",state->name);
483
484             } else {
485                 PrintError(dev->vm, VCORE_NONE, "pci_front (%s): pci_bar_init: invalid memory bar type\n",state->name);
486                 return -1;
487             }
488
489         }
490     }
491
492
493
494     // Update the pci subsystem versions
495     *dst = bar_val;
496
497     return 0;
498 }
499
500
501 //
502 // If the guest modifies a BAR, we expect that pci.c will do the following,
503 // in this order
504 //
505 //    1. notify us via the config_update callback, which we will feed back
506 //       to the host device
507 //    2. notify us of the bar change via the following callback 
508 //
509 // This callback will unhook as needed for the old bar value and rehook
510 // as needed for the new bar value
511 //
512 static int pci_bar_write(int bar_num, uint32_t * src, void * private_data) {
513     struct vm_device * dev = (struct vm_device *)private_data;
514     struct pci_front_internal * state = (struct pci_front_internal *)dev->private_data;
515     
516     struct pt_bar * pbar = &(state->bars[bar_num]);
517
518     PrintDebug(dev->vm, VCORE_NONE, "pci_front (%s): bar update: bar_num=%d, src=0x%x\n", state->name, bar_num, *src);
519     PrintDebug(dev->vm, VCORE_NONE, "pci_front (%s): the current bar has size=%u, type=%d, addr=%p, val=0x%x\n",
520                state->name, pbar->size, pbar->type, (void *)(addr_t)pbar->addr, pbar->val);
521
522     v3_host_dev_write_config(state->host_dev, bar_num*4 + 16, src, 4);
523     v3_host_dev_read_config(state->host_dev, bar_num*4 + 16, &state->config_space[bar_num*4 + 16], 4);
524     if (*src == 0xffffffff || *src == 0) {
525         PrintDebug(dev->vm, VCORE_NONE, "Ignoring BAR write for bar#%d, val=0x%x\n", bar_num, *src);
526         return 0;
527     }
528
529
530
531     if (pbar->type == PT_BAR_NONE) {
532         PrintDebug(dev->vm, VCORE_NONE, "pci_front (%s): bar update is to empty bar - ignored\n",state->name);
533         return 0;
534     } else if (pbar->type == PT_BAR_IO) {
535         int i = 0;
536
537         // unhook old ports
538     if (pbar->mapped) {
539         PrintDebug(dev->vm, VCORE_NONE, "pci_front (%s): unhooking I/O ports 0x%x through 0x%x\n", 
540                 state->name, 
541                 (unsigned)(pbar->addr), (unsigned)(pbar->addr+pbar->size-1));
542         for (i = 0; i < pbar->size; i++) {
543             if (v3_dev_unhook_io(dev, pbar->addr + i) == -1) {
544                 PrintError(dev->vm, VCORE_NONE, "pci_front (%s): could not unhook previously hooked port.... 0x%x\n", 
545                         state->name, 
546                         (uint32_t)pbar->addr + i);
547                 return -1;
548             }
549         }
550     }
551
552         PrintDebug(dev->vm, VCORE_NONE, "pci_front (%s): setting I/O Port range size=%d\n", state->name, pbar->size);
553
554         // 
555         // Not clear if this cooking is needed... why not trust
556         // the write?  Who cares if it wants to suddenly hook more ports?
557         // 
558
559         // clear the low bits to match the size
560         *src &= ~(pbar->size - 1);
561
562         // Set reserved bits
563         *src |= (pbar->val & ~PCI_IO_MASK);
564
565         pbar->addr = PCI_IO_BASE(*src); 
566
567         PrintDebug(dev->vm, VCORE_NONE, "pci_front (%s): cooked src=0x%x\n", state->name, *src);
568
569         PrintDebug(dev->vm, VCORE_NONE, "pci_front (%s): rehooking I/O ports 0x%x through 0x%x\n",
570                    state->name, (unsigned)(pbar->addr), (unsigned)(pbar->addr+pbar->size-1));
571
572     if (pbar->addr) {
573         for (i = 0; i < pbar->size; i++) {
574             if (v3_dev_hook_io(dev,
575                                pbar->addr + i, 
576                                pci_front_read_port, 
577                                pci_front_write_port)<0) { 
578                 PrintError(dev->vm, VCORE_NONE, "pci_front (%s): unable to rehook port 0x%x\n",state->name, (unsigned)(pbar->addr+i));
579                 return -1;
580             }
581         }
582     }
583
584     } else if (pbar->type == PT_BAR_MEM32) {
585
586         if (pbar->mapped) {
587             if (v3_unhook_mem(dev->vm,V3_MEM_CORE_ANY,pbar->addr)<0) { 
588                 PrintError(dev->vm, VCORE_NONE, "pci_front (%s): unable to unhook 32 bit memory region starting at 0x%p\n", 
589                         state->name, (void*)(pbar->addr));
590                 return -1;
591             }
592         }
593
594         // Again, not sure I need to do this cooking...
595
596         // clear the low bits to match the size
597         *src &= ~(pbar->size - 1);
598
599         // Set reserved bits
600         *src |= (pbar->val & ~PCI_MEM_MASK);
601
602         PrintDebug(dev->vm, VCORE_NONE, "pci_front (%s): cooked src=0x%x\n", state->name, *src);
603
604         pbar->addr = PCI_MEM32_BASE(*src);
605
606         PrintDebug(dev->vm, VCORE_NONE, "pci_front (%s): rehooking 32 bit memory region 0x%p through 0x%p\n",
607                    state->name, (void*)(pbar->addr), (void*)(pbar->addr + pbar->size - 1));
608                    
609     if (pbar->addr) {
610         if (v3_hook_full_mem(dev->vm,
611                              V3_MEM_CORE_ANY,
612                              pbar->addr,
613                              pbar->addr+pbar->size-1,
614                              pci_front_read_mem,
615                              pci_front_write_mem,
616                              dev)<0) { 
617             PrintError(dev->vm, VCORE_NONE, "pci_front (%s): unable to rehook 32 bit memory region 0x%p through 0x%p\n",
618                        state->name, (void*)(pbar->addr), (void*)(pbar->addr + pbar->size - 1));
619             return -1;
620         }
621     }
622
623     } else if (pbar->type == PT_BAR_MEM64_LO) {
624         // We only store the written values here, the actual reconfig comes when the high BAR is updated
625
626         // clear the low bits to match the size
627         *src &= ~(pbar->size - 1);
628
629         // Set reserved bits
630         *src |= (pbar->val & ~PCI_MEM_MASK);
631
632         // Temp storage, used when hi bar is written
633         pbar->addr = PCI_MEM64_BASE_LO(*src);
634
635         PrintDebug(dev->vm, VCORE_NONE, "pci_front (%s): handled partial update for 64 bit memory region\n",state->name);
636
637     } else if (pbar->type == PT_BAR_MEM64_HI) {
638         struct pt_bar * lo_vbar = &(state->bars[bar_num - 1]);
639
640     if (pbar->mapped) {
641         if (v3_unhook_mem(dev->vm,V3_MEM_CORE_ANY,pbar->addr)<0) { 
642             PrintError(dev->vm, VCORE_NONE, "pci_front (%s): unable to unhook 64 bit memory region starting at 0x%p\n", 
643                     state->name, (void*)(pbar->addr));
644             return -1;
645         }
646     }
647
648         
649         // We don't set size, because we assume region is less than 4GB
650
651         // Set reserved bits
652         *src |= (pbar->val & ~PCI_MEM64_MASK_HI);
653
654         pbar->addr = PCI_MEM64_BASE_HI(*src);
655         pbar->addr <<= 32;
656         pbar->addr += lo_vbar->addr;
657
658         PrintDebug(dev->vm, VCORE_NONE, "pci_front (%s): rehooking 64 bit memory region 0x%p through 0x%p\n",
659                    state->name, (void*)(pbar->addr), (void*)(pbar->addr + pbar->size - 1));
660                    
661         if (v3_hook_full_mem(dev->vm,
662                              V3_MEM_CORE_ANY,
663                              pbar->addr,
664                              pbar->addr+pbar->size-1,
665                              pci_front_read_mem,
666                              pci_front_write_mem,
667                              dev)<0) { 
668             PrintError(dev->vm, VCORE_NONE, "pci_front (%s): unable to rehook 64 bit memory region 0x%p through 0x%p\n",
669                        state->name, (void*)(pbar->addr), (void*)(pbar->addr + pbar->size - 1));
670             return -1;
671         }
672         
673     } else {
674         PrintError(dev->vm, VCORE_NONE, "pci_front (%s): unhandled PCI bar type %d\n", state->name, pbar->type);
675         return -1;
676     }
677
678     pbar->val = *src;
679     
680     return 0;
681 }
682
683 static int pci_front_cmd_update(struct pci_device *pci_dev, pci_cmd_t cmd, uint64_t arg, void * priv_data)
684 {
685     struct vm_device * dev = (struct vm_device *)priv_data;
686     struct pci_front_internal * state = (struct pci_front_internal *)dev->private_data;
687
688     uint16_t command = (uint16_t)arg;
689
690     PrintDebug(VM_NONE, VCORE_NONE, "pci_front (%s): command update\n", state->name);
691
692     if (v3_host_dev_write_config(state->host_dev, 0x4, &command, 2) != 2) {
693         PrintError(dev->vm, VCORE_NONE, "pci_front (%s): cmd update: unable to write all bytes\n", state->name);
694         return -1;
695     }
696
697     return 0;
698 }
699
700
701
702 static void remap_rom(struct v3_vm_info *vm, struct pci_front_internal *state, void *new_gpa, int enable)
703 {
704     if (state->rom_gpa) { 
705         // unmap
706         struct v3_mem_region *old_reg = v3_get_mem_region(vm,V3_MEM_CORE_ANY,(addr_t)state->rom_gpa);
707         if (old_reg) { 
708             V3_Print(vm,VCORE_NONE,"pci_front: removing old memory region\n");
709             v3_delete_mem_region(vm,old_reg);
710         } 
711         state->rom_gpa = 0;
712     }
713
714     if (enable) { 
715         if (v3_add_shadow_mem(vm,
716                               V3_MEM_CORE_ANY,
717                               (addr_t)new_gpa,
718                               (addr_t) 
719                               new_gpa+state->rom_size-1,
720                               (addr_t)state->rom_hpa)) {
721             PrintError(vm,VCORE_NONE,"pci_front: cannot add new shadow mapping\n");
722             return;
723         }
724         state->rom_gpa = new_gpa; 
725     } 
726
727     V3_Print(vm,VCORE_NONE,"pci_front: remapped rom to %p (enable=%u)\n",state->rom_gpa,enable) ;
728 }
729
730 #define ROM_ADDR_MASK 0xfffff800
731 #define ROM_ENABLE    0x1
732 #define ROM_BAR_OFFSET 0x30
733
734 static int pci_front_rom_update(struct pci_device * pci_dev, uint32_t * src, void * priv_data)
735 {
736     struct vm_device * dev = (struct vm_device *)priv_data;
737     struct pci_front_internal * state = (struct pci_front_internal *)dev->private_data;
738
739     V3_Print(dev->vm,VCORE_NONE,"pci_front: rom update with value 0x%x\n",*src);
740
741     // the assumption is that the config_write happened before this
742     if (((*src) & ROM_ADDR_MASK) == ROM_ADDR_MASK) { 
743         // this is a write to get the size
744         // we will ignore it and assume the that 
745         // preceding config_write occured, now we just need to do a pull to make
746         // sure we have the right size
747         v3_host_dev_read_config(state->host_dev, 0x30, &state->config_space[0x30], 4);
748     } else {
749         // actually mapping device, address now valid
750         void *addr = (void*)(uint64_t)((*src) & ROM_ADDR_MASK);
751         remap_rom(dev->vm,state,addr,(*src) & ROM_ENABLE);
752     }
753     
754     return 0;
755
756 }
757
758 static int pci_front_config_read(struct pci_device *pci_dev, uint_t reg_num, void * dst, uint_t length, void * priv_data)
759 {
760     struct vm_device * dev = (struct vm_device *)priv_data;
761     struct pci_front_internal * state = (struct pci_front_internal *)dev->private_data;
762     int i;
763
764     memcpy(dst, (void*)&(state->config_space[reg_num]), length);
765
766
767     PrintDebug(VM_NONE, VCORE_NONE, "read callback (%d bytes starting at reg num %x)\n", length, reg_num);
768     for (i = 0; i < length; i++) {
769         PrintDebug(VM_NONE, VCORE_NONE, "byte %d: %x\n", i, state->config_space[reg_num+i]);
770     }
771
772     /*
773     PrintDebug(VM_NONE, VCORE_NONE, "pci_front config space read callback (%d bytes starting at reg num %x) returning:\n", length, reg_num);
774     for (i = 0; i < length/4; i++) {
775         PrintDebug(VM_NONE, VCORE_NONE, "%x\n", *(uint32_t*)(&(state->config_space[reg_num]) + i*4));
776     }
777     */
778
779     
780     
781     return 0;
782 }
783
784
785 static int pci_front_config_update(struct pci_device *pci_dev, uint_t reg_num, void * src, uint_t length, void * private_data) 
786 {
787     int i;
788     struct vm_device * dev = (struct vm_device *)private_data;
789     struct pci_front_internal * state = (struct pci_front_internal *)dev->private_data;
790     union pci_addr_reg pci_addr = {state->pci_addr.value};
791     
792     pci_addr.reg = reg_num >> 2;
793
794     PrintDebug(dev->vm, VCORE_NONE, "pci_front (%s): configuration update: writing 0x%x bytes at offset 0x%x to host device 0x%p, bytes=0x",
795                state->name, length, pci_addr.value, state->host_dev);
796     
797     for (i = 0; i < length; i++) { 
798         PrintDebug(dev->vm, VCORE_NONE, "%x", ((uint8_t *)src)[i]);
799     }
800
801     PrintDebug(dev->vm, VCORE_NONE, "\n");
802
803     /* first, keep our local copy in sync */
804     memcpy((void*)&state->config_space[pci_addr.value], src, length);
805
806     /* propagate back to the host side */
807     if (v3_host_dev_write_config(state->host_dev,
808                                  pci_addr.value,
809                                  src,
810                                  length) != length) { 
811         PrintError(dev->vm, VCORE_NONE, "pci_front (%s): configuration update: unable to write all bytes\n",state->name);
812         return -1;
813     }
814
815     return 0;
816 }
817
818
819 static int unhook_all_mem(struct pci_front_internal *state)
820 {
821     int bar_num;
822     struct vm_device *bus = state->pci_bus;
823
824
825     for (bar_num=0;bar_num<6;bar_num++) { 
826         struct pt_bar * pbar = &(state->bars[bar_num]);
827
828         PrintDebug(bus->vm, VCORE_NONE, "pci_front (%s): unhooking for bar %d\n", state->name, bar_num);
829
830         if (pbar->type == PT_BAR_MEM32) {
831             if (v3_unhook_mem(bus->vm,V3_MEM_CORE_ANY,pbar->addr)<0) { 
832                 PrintError(bus->vm, VCORE_NONE, "pci_front (%s): unable to unhook 32 bit memory region starting at 0x%p\n", 
833                            state->name, (void*)(pbar->addr));
834                 return -1;
835             }
836         } else  if (pbar->type == PT_BAR_MEM64_HI) {
837
838             if (v3_unhook_mem(bus->vm,V3_MEM_CORE_ANY,pbar->addr)<0) { 
839                 PrintError(bus->vm, VCORE_NONE, "pci_front (%s): unable to unhook 64 bit memory region starting at 0x%p\n", 
840                            state->name, (void*)(pbar->addr));
841                 return -1;
842             }
843         }
844     }
845     
846     return 0;
847 }
848
849
850
851 static int setup_virt_pci_dev(struct v3_vm_info * vm_info, struct vm_device * dev) 
852 {
853     struct pci_front_internal * state = (struct pci_front_internal *)dev->private_data;
854     struct pci_device * pci_dev = NULL;
855     struct v3_pci_bar bars[6];
856     int bus_num = 0;
857     int i;
858
859     for (i = 0; i < 6; i++) {
860         bars[i].type = PCI_BAR_PASSTHROUGH;
861         bars[i].private_data = dev;
862         bars[i].bar_init = pci_bar_init;
863         bars[i].bar_write = pci_bar_write;
864     }
865
866     pci_dev = v3_pci_register_device(state->pci_bus,
867                                      PCI_STD_DEVICE,
868                                      bus_num, -1, 0, 
869                                      state->name, bars,
870                                      pci_front_config_update,
871                                      pci_front_config_read,      
872                                      pci_front_cmd_update,     
873                                      pci_front_rom_update,     
874                                      dev);
875
876
877     state->pci_dev = pci_dev;
878
879
880     // COMMANDS CURRENTLY UNSUPPORTED (ignored)
881
882     return 0;
883 }
884
885
886
887 //
888 // Note: potential bug:  not clear what pointer I get here
889 //
890 static int pci_front_free(struct pci_front_internal *state)
891 {
892
893     if (unhook_all_mem(state)<0) { 
894         return -1;
895     }
896
897     // the device manager will unhook the i/o ports for us
898
899     if (state->host_dev) { 
900         v3_host_dev_close(state->host_dev);
901         state->host_dev=0;
902     }
903
904     if (state->rom_hpa) { 
905         V3_FreePages(state->rom_hpa,state->rom_size/PAGE_SIZE + 1);
906     }
907
908     V3_Free(state);
909
910     PrintDebug(state->pci_bus->vm, VCORE_NONE, "pci_front (%s): freed\n",state->name);
911
912     return 0;
913 }
914
915 #ifdef V3_CONFIG_HOST_DEVICE
916 static void pci_front_intr_update_callback(v3_host_dev_t hdev, v3_guest_dev_t gdev, uint8_t irq, int raise)
917 {
918     if (gdev) { 
919
920         struct vm_device *dev = (struct vm_device *) gdev;
921         struct pci_front_internal *state = (struct pci_front_internal *) dev->private_data;
922
923         // We expect the host device will raise and lower irqs as needed, so we
924         // don't need an "acked" irq.  Also, we expect the host is using INTX, not
925         // MSI.  It's doubtful that MSI will work.  
926         // expect: state->pci_dev->irq_type==IRQ_INTX
927     PrintDebug(VM_NONE, VCORE_NONE, "Palacios raising PCI IRQ %x\n", irq);
928         if (raise) { 
929             v3_pci_raise_irq(state->pci_bus, state->pci_dev, irq);
930         } else {
931             v3_pci_lower_irq(state->pci_bus, state->pci_dev, irq);
932         }
933     }
934 }
935 #endif
936
937
938 static struct v3_device_ops dev_ops = {
939 //
940 // Note: potential bug:  not clear what pointer I get here
941 //
942     .free = (int (*)(void*))pci_front_free,
943 };
944
945
946
947
948
949
950
951 static int pci_front_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) 
952 {
953     struct vm_device * dev;
954     struct vm_device * bus;
955     struct pci_front_internal *state;
956     char *dev_id;
957     char *bus_id;
958     char *url;
959     char *rom_id;
960     struct v3_cfg_file *rom_file;
961     v3_cfg_tree_t *rom;
962     void *rom_hpa;
963     uint64_t rom_size;
964
965     
966     
967     if (!(dev_id = v3_cfg_val(cfg, "ID"))) { 
968         PrintError(vm, VCORE_NONE, "pci_front: no id  given!\n");
969
970         return -1;
971     }
972     
973     if (!(bus_id = v3_cfg_val(cfg, "bus"))) { 
974         PrintError(vm, VCORE_NONE, "pci_front (%s): no bus given!\n",dev_id);
975         return -1;
976     }
977     
978     if (!(url = v3_cfg_val(cfg, "hostdev"))) { 
979         PrintError(vm, VCORE_NONE, "pci_front (%s): no host device url given!\n",dev_id);
980         return -1;
981     }
982
983     if (!(rom=v3_cfg_subtree(cfg,"rom"))) { 
984         V3_Print(vm, VCORE_NONE, "pci_front (%s): no expansion block\n",dev_id);
985         rom_file = 0;
986         rom_hpa=0;
987     } else {
988         rom_id = v3_cfg_val(rom,"file");
989         if (!rom_id) { 
990             PrintError(vm, VCORE_NONE, "pci_front (%s): no rom id given\n",dev_id);
991             return -1;
992         } else {
993             rom_file = v3_cfg_get_file(vm,rom_id);
994             if (!rom_file) { 
995                 PrintError(vm,VCORE_NONE, "pci_front (%s): cannot find expansion rom %s\n",dev_id,rom_id);
996                 return -1;
997             } 
998             rom_size = rom_file->size;
999             rom_hpa = V3_AllocPages(rom_size/PAGE_SIZE + 1 );
1000             if (!rom_hpa) { 
1001                 PrintError(vm,VCORE_NONE, "pci_front %s) : cannot allocate space for expansion rom %s\n",dev_id,rom_id);
1002                 return -1;
1003             } 
1004             memcpy(V3_VAddr(rom_hpa),rom_file->data,rom_size);
1005                 
1006         }
1007         V3_Print(vm,VCORE_NONE,"pci_front (%s): rom %s tag %s size 0x%llx hpa %p\n", 
1008                  dev_id,rom_id,rom_file->tag,rom_file->size,rom_hpa);
1009     }
1010         
1011
1012     if (!(bus = v3_find_dev(vm,bus_id))) { 
1013         PrintError(vm, VCORE_NONE, "pci_front (%s): cannot attach to bus %s\n",dev_id,bus_id);
1014         return -1;
1015     }
1016
1017     if (!(state = V3_Malloc(sizeof(struct pci_front_internal)))) { 
1018         PrintError(vm, VCORE_NONE, "pci_front (%s): cannot allocate state for device\n",dev_id);
1019         return -1;
1020     }
1021
1022
1023     memset(state, 0, sizeof(struct pci_front_internal));
1024     
1025     state->pci_bus = bus;
1026     strncpy(state->name, dev_id, 32);
1027     
1028     if (!(dev = v3_add_device(vm, dev_id, &dev_ops, state))) { 
1029         PrintError(vm, VCORE_NONE, "pci_front (%s): unable to add device\n",state->name);
1030         return -1;
1031     }
1032     
1033     if (!(state->host_dev=v3_host_dev_open(url,V3_BUS_CLASS_PCI,dev,pci_front_intr_update_callback,vm))) { 
1034         PrintError(vm, VCORE_NONE, "pci_front (%s): unable to attach to host device %s\n",state->name, url);
1035         v3_remove_device(dev);
1036         return -1;
1037     }
1038
1039     state->rom_gpa = 0 ; // this will be set later by the pull
1040     state->rom_hpa = rom_hpa;
1041     state->rom_size = rom_size;
1042
1043     if (pull_config(state,state->config_space)) { 
1044         PrintError(dev->vm, VCORE_NONE, "pci_front (%s): cannot initially configure device\n",state->name);
1045         v3_remove_device(dev);
1046         return -1;
1047     }
1048
1049     if (state->rom_hpa) { 
1050         // have rom - add it to address space, initially disabled
1051         remap_rom(vm,state,(void*)(uint64_t)*((uint32_t*)&state->config_space[0x30]),0);
1052     }
1053
1054     // setup virtual device for now
1055     if (setup_virt_pci_dev(vm,dev)<0) { 
1056         PrintError(vm, VCORE_NONE, "pci_front (%s): cannot set up virtual pci device\n", state->name);
1057         v3_remove_device(dev);
1058         return -1;
1059     }
1060
1061     // We do not need to hook anything here since pci will call
1062     // us back via the bar_init functions
1063
1064     PrintDebug(vm, VCORE_NONE, "pci_front (%s): inited and ready to be Potemkinized\n",state->name);
1065
1066     return 0;
1067
1068 }
1069
1070
1071 device_register("PCI_FRONT", pci_front_init)