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.


pci_front bugfix - do not propagate cmd reg write twice
[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 #ifdef V3_CONFIG_DEBUG_PCI_FRONT
686     struct vm_device * dev = (struct vm_device *)priv_data;
687     struct pci_front_internal * state = (struct pci_front_internal *)dev->private_data;
688
689     uint16_t command = (uint16_t)arg;
690 #endif
691
692     PrintDebug(VM_NONE, VCORE_NONE, "pci_front (%s): command update 0x%x\n", state->name,command);
693
694     // Note that the config_update corresponding to this callback 
695     // has occurred before this request, and so has already been delivered 
696     // to the host_dev interface.   
697     //
698     // We do not need to handle the special semantics of cmd_update here
699     // hence nothing...
700
701     return 0;
702 }
703
704
705
706 static void remap_rom(struct v3_vm_info *vm, struct pci_front_internal *state, void *new_gpa, int enable)
707 {
708     if (state->rom_gpa) { 
709         // unmap
710         struct v3_mem_region *old_reg = v3_get_mem_region(vm,V3_MEM_CORE_ANY,(addr_t)state->rom_gpa);
711         if (old_reg) { 
712             V3_Print(vm,VCORE_NONE,"pci_front: removing old memory region\n");
713             v3_delete_mem_region(vm,old_reg);
714         } 
715         state->rom_gpa = 0;
716     }
717
718     if (enable) { 
719         if (v3_add_shadow_mem(vm,
720                               V3_MEM_CORE_ANY,
721                               (addr_t)new_gpa,
722                               (addr_t) 
723                               new_gpa+state->rom_size-1,
724                               (addr_t)state->rom_hpa)) {
725             PrintError(vm,VCORE_NONE,"pci_front: cannot add new shadow mapping\n");
726             return;
727         }
728         state->rom_gpa = new_gpa; 
729     } 
730
731     V3_Print(vm,VCORE_NONE,"pci_front: remapped rom to %p (enable=%u)\n",state->rom_gpa,enable) ;
732 }
733
734 #define ROM_ADDR_MASK 0xfffff800
735 #define ROM_ENABLE    0x1
736 #define ROM_BAR_OFFSET 0x30
737
738 static int pci_front_rom_update(struct pci_device * pci_dev, uint32_t * src, void * priv_data)
739 {
740     struct vm_device * dev = (struct vm_device *)priv_data;
741     struct pci_front_internal * state = (struct pci_front_internal *)dev->private_data;
742
743     V3_Print(dev->vm,VCORE_NONE,"pci_front: rom update with value 0x%x\n",*src);
744
745     // the assumption is that the config_write happened before this
746     if (((*src) & ROM_ADDR_MASK) == ROM_ADDR_MASK) { 
747         // this is a write to get the size
748         // we will ignore it and assume the that 
749         // preceding config_write occured, now we just need to do a pull to make
750         // sure we have the right size
751         v3_host_dev_read_config(state->host_dev, 0x30, &state->config_space[0x30], 4);
752     } else {
753         // actually mapping device, address now valid
754         void *addr = (void*)(uint64_t)((*src) & ROM_ADDR_MASK);
755         remap_rom(dev->vm,state,addr,(*src) & ROM_ENABLE);
756     }
757     
758     return 0;
759
760 }
761
762 static int pci_front_config_read(struct pci_device *pci_dev, uint_t reg_num, void * dst, uint_t length, void * priv_data)
763 {
764     struct vm_device * dev = (struct vm_device *)priv_data;
765     struct pci_front_internal * state = (struct pci_front_internal *)dev->private_data;
766     int i;
767
768     memcpy(dst, (void*)&(state->config_space[reg_num]), length);
769
770
771     PrintDebug(VM_NONE, VCORE_NONE, "read callback (%d bytes starting at reg num %x)\n", length, reg_num);
772     for (i = 0; i < length; i++) {
773         PrintDebug(VM_NONE, VCORE_NONE, "byte %d: %x\n", i, state->config_space[reg_num+i]);
774     }
775
776     return 0;
777 }
778
779
780 static int pci_front_config_update(struct pci_device *pci_dev, uint_t reg_num, void * src, uint_t length, void * private_data) 
781 {
782     int i;
783     struct vm_device * dev = (struct vm_device *)private_data;
784     struct pci_front_internal * state = (struct pci_front_internal *)dev->private_data;
785     union pci_addr_reg pci_addr = {state->pci_addr.value};
786     
787     pci_addr.reg = reg_num >> 2;
788
789     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",
790                state->name, length, pci_addr.value, state->host_dev);
791     
792     for (i = 0; i < length; i++) { 
793         PrintDebug(dev->vm, VCORE_NONE, "%x", ((uint8_t *)src)[i]);
794     }
795
796     PrintDebug(dev->vm, VCORE_NONE, "\n");
797
798     /* first, keep our local copy in sync */
799     memcpy((void*)&state->config_space[pci_addr.value], src, length);
800
801     /* propagate back to the host side */
802     if (v3_host_dev_write_config(state->host_dev,
803                                  pci_addr.value,
804                                  src,
805                                  length) != length) { 
806         PrintError(dev->vm, VCORE_NONE, "pci_front (%s): configuration update: unable to write all bytes\n",state->name);
807         return -1;
808     }
809
810     return 0;
811 }
812
813
814 static int unhook_all_mem(struct pci_front_internal *state)
815 {
816     int bar_num;
817     struct vm_device *bus = state->pci_bus;
818
819
820     for (bar_num=0;bar_num<6;bar_num++) { 
821         struct pt_bar * pbar = &(state->bars[bar_num]);
822
823         PrintDebug(bus->vm, VCORE_NONE, "pci_front (%s): unhooking for bar %d\n", state->name, bar_num);
824
825         if (pbar->type == PT_BAR_MEM32) {
826             if (v3_unhook_mem(bus->vm,V3_MEM_CORE_ANY,pbar->addr)<0) { 
827                 PrintError(bus->vm, VCORE_NONE, "pci_front (%s): unable to unhook 32 bit memory region starting at 0x%p\n", 
828                            state->name, (void*)(pbar->addr));
829                 return -1;
830             }
831         } else  if (pbar->type == PT_BAR_MEM64_HI) {
832
833             if (v3_unhook_mem(bus->vm,V3_MEM_CORE_ANY,pbar->addr)<0) { 
834                 PrintError(bus->vm, VCORE_NONE, "pci_front (%s): unable to unhook 64 bit memory region starting at 0x%p\n", 
835                            state->name, (void*)(pbar->addr));
836                 return -1;
837             }
838         }
839     }
840     
841     return 0;
842 }
843
844
845
846 static int setup_virt_pci_dev(struct v3_vm_info * vm_info, struct vm_device * dev) 
847 {
848     struct pci_front_internal * state = (struct pci_front_internal *)dev->private_data;
849     struct pci_device * pci_dev = NULL;
850     struct v3_pci_bar bars[6];
851     int bus_num = 0;
852     int i;
853
854     for (i = 0; i < 6; i++) {
855         bars[i].type = PCI_BAR_PASSTHROUGH;
856         bars[i].private_data = dev;
857         bars[i].bar_init = pci_bar_init;
858         bars[i].bar_write = pci_bar_write;
859     }
860
861     pci_dev = v3_pci_register_device(state->pci_bus,
862                                      PCI_STD_DEVICE,
863                                      bus_num, -1, 0, 
864                                      state->name, bars,
865                                      pci_front_config_update,
866                                      pci_front_config_read,      
867                                      pci_front_cmd_update,     
868                                      pci_front_rom_update,     
869                                      dev);
870
871
872     state->pci_dev = pci_dev;
873
874
875     // COMMANDS CURRENTLY UNSUPPORTED (ignored)
876
877     return 0;
878 }
879
880
881
882 //
883 // Note: potential bug:  not clear what pointer I get here
884 //
885 static int pci_front_free(struct pci_front_internal *state)
886 {
887
888     if (unhook_all_mem(state)<0) { 
889         return -1;
890     }
891
892     // the device manager will unhook the i/o ports for us
893
894     if (state->host_dev) { 
895         v3_host_dev_close(state->host_dev);
896         state->host_dev=0;
897     }
898
899     if (state->rom_hpa) { 
900         V3_FreePages(state->rom_hpa,state->rom_size/PAGE_SIZE + 1);
901     }
902
903     V3_Free(state);
904
905     PrintDebug(state->pci_bus->vm, VCORE_NONE, "pci_front (%s): freed\n",state->name);
906
907     return 0;
908 }
909
910 #ifdef V3_CONFIG_HOST_DEVICE
911 static void pci_front_intr_update_callback(v3_host_dev_t hdev, v3_guest_dev_t gdev, uint8_t irq, int raise)
912 {
913     if (gdev) { 
914
915         struct vm_device *dev = (struct vm_device *) gdev;
916         struct pci_front_internal *state = (struct pci_front_internal *) dev->private_data;
917
918         // We expect the host device will raise and lower irqs as needed, so we
919         // don't need an "acked" irq.  Also, we expect the host is using INTX, not
920         // MSI.  It's doubtful that MSI will work.  
921         // expect: state->pci_dev->irq_type==IRQ_INTX
922     PrintDebug(VM_NONE, VCORE_NONE, "Palacios raising PCI IRQ %x\n", irq);
923         if (raise) { 
924             v3_pci_raise_irq(state->pci_bus, state->pci_dev, irq);
925         } else {
926             v3_pci_lower_irq(state->pci_bus, state->pci_dev, irq);
927         }
928     }
929 }
930 #endif
931
932
933 static struct v3_device_ops dev_ops = {
934 //
935 // Note: potential bug:  not clear what pointer I get here
936 //
937     .free = (int (*)(void*))pci_front_free,
938 };
939
940
941
942
943
944
945
946 static int pci_front_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) 
947 {
948     struct vm_device * dev;
949     struct vm_device * bus;
950     struct pci_front_internal *state;
951     char *dev_id;
952     char *bus_id;
953     char *url;
954     char *rom_id;
955     struct v3_cfg_file *rom_file;
956     v3_cfg_tree_t *rom;
957     void *rom_hpa=0;
958     uint64_t rom_size=0;
959
960     
961     
962     if (!(dev_id = v3_cfg_val(cfg, "ID"))) { 
963         PrintError(vm, VCORE_NONE, "pci_front: no id  given!\n");
964
965         return -1;
966     }
967     
968     if (!(bus_id = v3_cfg_val(cfg, "bus"))) { 
969         PrintError(vm, VCORE_NONE, "pci_front (%s): no bus given!\n",dev_id);
970         return -1;
971     }
972     
973     if (!(url = v3_cfg_val(cfg, "hostdev"))) { 
974         PrintError(vm, VCORE_NONE, "pci_front (%s): no host device url given!\n",dev_id);
975         return -1;
976     }
977
978     if (!(rom=v3_cfg_subtree(cfg,"rom"))) { 
979         V3_Print(vm, VCORE_NONE, "pci_front (%s): no expansion block\n",dev_id);
980         rom_file = 0;
981         rom_hpa=0;
982     } else {
983         rom_id = v3_cfg_val(rom,"file");
984         if (!rom_id) { 
985             PrintError(vm, VCORE_NONE, "pci_front (%s): no rom id given\n",dev_id);
986             return -1;
987         } else {
988             rom_file = v3_cfg_get_file(vm,rom_id);
989             if (!rom_file) { 
990                 PrintError(vm,VCORE_NONE, "pci_front (%s): cannot find expansion rom %s\n",dev_id,rom_id);
991                 return -1;
992             } 
993             rom_size = rom_file->size;
994             rom_hpa = V3_AllocPages(rom_size/PAGE_SIZE + 1 );
995             if (!rom_hpa) { 
996                 PrintError(vm,VCORE_NONE, "pci_front %s) : cannot allocate space for expansion rom %s\n",dev_id,rom_id);
997                 return -1;
998             } 
999             memcpy(V3_VAddr(rom_hpa),rom_file->data,rom_size);
1000                 
1001         }
1002         V3_Print(vm,VCORE_NONE,"pci_front (%s): rom %s tag %s size 0x%llx hpa %p\n", 
1003                  dev_id,rom_id,rom_file->tag,rom_file->size,rom_hpa);
1004     }
1005         
1006
1007     if (!(bus = v3_find_dev(vm,bus_id))) { 
1008         PrintError(vm, VCORE_NONE, "pci_front (%s): cannot attach to bus %s\n",dev_id,bus_id);
1009         return -1;
1010     }
1011
1012     if (!(state = V3_Malloc(sizeof(struct pci_front_internal)))) { 
1013         PrintError(vm, VCORE_NONE, "pci_front (%s): cannot allocate state for device\n",dev_id);
1014         return -1;
1015     }
1016
1017
1018     memset(state, 0, sizeof(struct pci_front_internal));
1019     
1020     state->pci_bus = bus;
1021     strncpy(state->name, dev_id, 32);
1022     
1023     if (!(dev = v3_add_device(vm, dev_id, &dev_ops, state))) { 
1024         PrintError(vm, VCORE_NONE, "pci_front (%s): unable to add device\n",state->name);
1025         return -1;
1026     }
1027     
1028     if (!(state->host_dev=v3_host_dev_open(url,V3_BUS_CLASS_PCI,dev,pci_front_intr_update_callback,vm))) { 
1029         PrintError(vm, VCORE_NONE, "pci_front (%s): unable to attach to host device %s\n",state->name, url);
1030         v3_remove_device(dev);
1031         return -1;
1032     }
1033
1034     state->rom_gpa = 0 ; // this will be set later by the pull
1035     state->rom_hpa = rom_hpa;
1036     state->rom_size = rom_size;
1037
1038     if (pull_config(state,state->config_space)) { 
1039         PrintError(dev->vm, VCORE_NONE, "pci_front (%s): cannot initially configure device\n",state->name);
1040         v3_remove_device(dev);
1041         return -1;
1042     }
1043
1044     if (state->rom_hpa) { 
1045         // have rom - add it to address space, initially disabled
1046         remap_rom(vm,state,(void*)(uint64_t)*((uint32_t*)&state->config_space[0x30]),0);
1047     }
1048
1049     // setup virtual device for now
1050     if (setup_virt_pci_dev(vm,dev)<0) { 
1051         PrintError(vm, VCORE_NONE, "pci_front (%s): cannot set up virtual pci device\n", state->name);
1052         v3_remove_device(dev);
1053         return -1;
1054     }
1055
1056     // We do not need to hook anything here since pci will call
1057     // us back via the bar_init functions
1058
1059     PrintDebug(vm, VCORE_NONE, "pci_front (%s): inited and ready to be Potemkinized\n",state->name);
1060
1061     return 0;
1062
1063 }
1064
1065
1066 device_register("PCI_FRONT", pci_front_init)