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.


a3b926a37c68a83db78d9c8574a1b4206ace2b8b
[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
140
141
142 /*
143 static int push_config(struct pci_front_internal *state, uint8_t *config)
144 {
145     if (v3_host_dev_config_write(state->host_dev, 0, config, 256) != 256) { 
146         return -1;
147     } else {
148         return 0;
149     }
150 }
151 */
152
153 static int pull_config(struct pci_front_internal *state, uint8_t *config)
154 {
155     if (v3_host_dev_read_config(state->host_dev, 0, config, 256) != 256) { 
156         return -1;
157     } else {
158         return 0;
159     }
160 }
161
162
163 static int pci_front_read_mem(struct guest_info * core, 
164                               addr_t              gpa,
165                               void              * dst,
166                               uint_t              len,
167                               void              * priv)
168 {
169     int i;
170     int rc;
171     struct vm_device *dev = (struct vm_device *) priv;
172     struct pci_front_internal *state = (struct pci_front_internal *) dev->private_data;
173
174     PrintDebug(core->vm_info, core, "pci_front (%s): reading 0x%x bytes from gpa 0x%p from host dev 0x%p ...",
175                state->name, len, (void*)gpa, state->host_dev);
176
177     rc = v3_host_dev_read_mem(state->host_dev, gpa, dst, len);
178
179     PrintDebug(core->vm_info, core, " done ... read %d bytes: 0x", rc);
180
181     for (i = 0; i < rc; i++) { 
182         PrintDebug(core->vm_info, core, "%x", ((uint8_t *)dst)[i]);
183     }
184
185     PrintDebug(core->vm_info, core, "\n");
186
187     return rc;
188 }
189
190 static int pci_front_write_mem(struct guest_info * core, 
191                                addr_t              gpa,
192                                void              * src,
193                                uint_t              len,
194                                void              * priv)
195 {
196     int i;
197     int rc;
198     struct vm_device *dev = (struct vm_device *) priv;
199     struct pci_front_internal *state = (struct pci_front_internal *) dev->private_data;
200
201     PrintDebug(core->vm_info, core, "pci_front (%s): writing 0x%x bytes to gpa 0x%p to host dev 0x%p bytes=0x",
202                state->name, len, (void*)gpa, state->host_dev);
203
204     for (i = 0; i < len; i++) { 
205         PrintDebug(core->vm_info, core, "%x", ((uint8_t *)src)[i]);
206     }
207
208     rc = v3_host_dev_write_mem(state->host_dev, gpa, src, len);
209
210     PrintDebug(core->vm_info, core, " %d bytes written\n",rc);
211     
212     return rc;
213 }
214
215
216 static int pci_front_read_port(struct guest_info * core, 
217                                uint16_t            port, 
218                                void              * dst, 
219                                uint_t              len, 
220                                void              * priv_data) 
221 {
222     int i;
223     struct pci_front_internal *state = (struct pci_front_internal *) priv_data;
224     
225     PrintDebug(core->vm_info, core, "pci_front (%s): reading 0x%x bytes from port 0x%x from host dev 0x%p ...",
226                state->name, len, port, state->host_dev);
227
228     int rc = v3_host_dev_read_io(state->host_dev, port, dst, len);
229     
230     PrintDebug(core->vm_info, core, " done ... read %d bytes: 0x", rc);
231
232     for (i = 0; i < rc; i++) { 
233         PrintDebug(core->vm_info, core, "%x", ((uint8_t *)dst)[i]);
234     }
235
236     PrintDebug(core->vm_info, core, "\n");
237
238     return rc;
239     
240 }
241
242 static int pci_front_write_port(struct guest_info * core, 
243                                 uint16_t            port, 
244                                 void              * src, 
245                                 uint_t              len, 
246                                 void              * priv_data) 
247 {
248     int i;
249     struct pci_front_internal *state = (struct pci_front_internal *) priv_data;
250
251     
252     PrintDebug(core->vm_info, core, "pci_front (%s): writing 0x%x bytes to port 0x%x to host dev 0x%p bytes=0x",
253                state->name, len, port, state->host_dev);
254
255     for (i = 0; i < len; i++) { 
256         PrintDebug(core->vm_info, core, "%x", ((uint8_t *)src)[i]);
257     }
258
259     int rc = v3_host_dev_write_io(state->host_dev, port, src, len);
260
261     PrintDebug(core->vm_info, core, " %d bytes written\n",rc);
262     
263     return rc;
264 }
265
266
267
268 //
269 // This is called at registration time for the device
270 // 
271 // We assume that someone has called pull_config to get a local
272 // copy of the config data from the host device by this point
273 //
274 // It might be smarter to do the pull config here since 
275 // in init we may not yet have the host device running... 
276 //
277 // KCH: we need to make sure that we don't hook I/O BARs and Mem BARs that
278 // haven't been configured by anyone yet (e.g. QEMU)
279 static int pci_bar_init(int bar_num, uint32_t * dst, void * private_data) {
280     struct vm_device * dev = (struct vm_device *)private_data;
281     struct pci_front_internal * state = (struct pci_front_internal *)(dev->private_data);
282
283     /*
284     if (pull_config(state,state->config_space)) { 
285         PrintError(dev->vm, VCORE_NONE, "pci_front (%s): cannot initially configure device\n",state->name);
286         v3_remove_device(dev);
287         return -1;
288     }
289     */
290
291     const uint32_t bar_base_reg = 4;   // offset in 32bit words to skip to the first bar
292
293     union pci_addr_reg pci_addr = {state->pci_addr.value};  // my address
294
295     uint32_t bar_val = 0;
296     uint32_t max_val = 0;
297
298     struct pt_bar * pbar = &(state->bars[bar_num]);
299
300     pci_addr.reg = bar_base_reg + bar_num;
301
302     PrintDebug(dev->vm, VCORE_NONE, "pci_front (%s): pci_bar_init: PCI Address = 0x%x\n", state->name, pci_addr.value);
303
304     // This assumees that pull_config() has been previously called and 
305     // we have a local copy of the host device's configuration space
306     //bar_val = *((uint32_t*)(&(state->config_space[(bar_base_reg+bar_num)*4])));
307     v3_host_dev_read_config(state->host_dev, bar_num*4 + 16, &bar_val, 4);
308
309     // Now let's set our copy of the relevant bar accordingly
310     pbar->val = bar_val; 
311
312     // Now we will configure the hooks relevant to this bar
313
314     // We preset this type when we encounter a MEM64 Low BAR
315     // This is a 64 bit memory region that we turn into a memory hook
316     if (pbar->type == PT_BAR_MEM64_HI) {
317         struct pt_bar * lo_pbar = &(state->bars[bar_num - 1]);
318
319         max_val = PCI_MEM64_MASK_HI;
320
321         v3_host_dev_write_config(state->host_dev, bar_num*4 + 16, &max_val, 4);
322         v3_host_dev_read_config(state->host_dev, bar_num*4 + 16, &max_val, 4);
323         v3_host_dev_write_config(state->host_dev, bar_num*4 + 16, &bar_val, 4);
324
325         pbar->size += lo_pbar->size;
326
327         /* this BAR hasn't been mapped yet */
328         if (pbar->addr) {
329             pbar->mapped = 1;
330
331             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",
332                     state->name, 
333                     (void *)(addr_t)pbar->addr, 
334                     (void *)(addr_t)(pbar->addr + pbar->size));
335
336             if (v3_hook_full_mem(dev->vm,
337                         V3_MEM_CORE_ANY,
338                         pbar->addr,
339                         pbar->addr+pbar->size-1,
340                         pci_front_read_mem,
341                         pci_front_write_mem,
342                         dev)<0) { 
343
344                 PrintError(dev->vm, VCORE_NONE, "pci_front (%s): pci_bar_init: failed to hook 64 bit region (0x%p, 0x%p)\n",
345                         state->name, 
346                         (void *)(addr_t)pbar->addr,
347                         (void *)(addr_t)(pbar->addr + pbar->size - 1));
348                 return -1;
349             }
350         }
351
352     } else if ((bar_val & 0x3) == 0x1) {
353         // This an I/O port region which we will turn into a range of hooks
354
355         int i = 0;
356
357         pbar->type = PT_BAR_IO;
358         pbar->addr = PCI_IO_BASE(bar_val);
359
360         max_val = bar_val | PCI_IO_MASK;
361
362         /*
363 uint64_t v3_host_dev_write_config(v3_host_dev_t hdev,
364                                   uint64_t offset,
365                                   void *src,
366                                   uint64_t len)
367                   */
368         
369
370         v3_host_dev_write_config(state->host_dev, bar_num*4 + 16, &max_val, 4);
371         v3_host_dev_read_config(state->host_dev, bar_num*4 + 16, &max_val, 4);
372         v3_host_dev_write_config(state->host_dev, bar_num*4 + 16, &bar_val, 4);
373
374         pbar->size = (uint16_t)~PCI_IO_BASE(max_val) + 1;
375         // ~((bar_val | PCI_IO_MASK) & PCI_IO_MASK) + 1 == ~(PCI_IO_MASK) + 1 == ~(0xfffffffc) + 1 == 0x3 + 1 == 0x4
376
377         if (pbar->addr) {
378             pbar->mapped = 1;
379
380             PrintDebug(dev->vm, VCORE_NONE, "pci_front (%s): pci_bar_init: hooking ports 0x%x through 0x%x\n",
381                     state->name, (uint32_t)pbar->addr, (uint32_t)pbar->addr + pbar->size - 1);
382
383             for (i = 0; i < pbar->size; i++) {
384                 if (v3_dev_hook_io(dev,
385                             pbar->addr + i, 
386                             pci_front_read_port,
387                             pci_front_write_port)<0) {
388                     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));
389                     return -1;
390                 }
391             }
392         }
393
394     } else {
395
396         // might be a 32 bit memory region or an empty bar
397
398         max_val = bar_val | PCI_MEM_MASK;
399         v3_host_dev_write_config(state->host_dev, bar_num*4 + 16, &max_val, 4);
400         v3_host_dev_read_config(state->host_dev, bar_num*4 + 16, &max_val, 4);
401         v3_host_dev_write_config(state->host_dev, bar_num*4 + 16, &bar_val, 4);
402         
403
404         if (max_val == 0) {
405             // nothing, so just ignore it
406             pbar->type = PT_BAR_NONE;
407         } else {
408
409             // memory region - hook it
410
411             if ((bar_val & 0x6) == 0x0) {
412                 // 32 bit memory region
413
414                 pbar->type = PT_BAR_MEM32;
415                 pbar->addr = PCI_MEM32_BASE(bar_val);
416                 pbar->size = ~PCI_MEM32_BASE(max_val) + 1;
417
418                 if (pbar->addr) {
419                     pbar->mapped = 1;
420
421                     PrintDebug(dev->vm, VCORE_NONE, "pci_front (%s): pci_init_bar: adding 32 bit PCI mem region: start=0x%p, end=0x%p\n",
422                             state->name, 
423                             (void *)(addr_t)pbar->addr, 
424                             (void *)(addr_t)(pbar->addr + pbar->size));
425
426                     if (v3_hook_full_mem(dev->vm, 
427                                 V3_MEM_CORE_ANY,
428                                 pbar->addr,
429                                 pbar->addr+pbar->size-1,
430                                 pci_front_read_mem,
431                                 pci_front_write_mem,
432                                 dev) < 0 ) { 
433                         PrintError(dev->vm, VCORE_NONE, "pci_front (%s): pci_init_bar: unable to hook 32 bit memory region 0x%p to 0x%p\n",
434                                 state->name, (void*)(pbar->addr), (void*)(pbar->addr+pbar->size-1));
435                         return -1;
436                     }
437                 }
438
439             } else if ((bar_val & 0x6) == 0x2) {
440
441                 // 24 bit memory region
442
443                 pbar->type = PT_BAR_MEM24;
444                 pbar->addr = PCI_MEM24_BASE(bar_val);
445                 pbar->size = ~PCI_MEM24_BASE(max_val) + 1;
446
447                 if (pbar->addr) {
448                     pbar->mapped = 1;
449
450
451                     if (v3_hook_full_mem(dev->vm, 
452                                 V3_MEM_CORE_ANY,
453                                 pbar->addr,
454                                 pbar->addr+pbar->size-1,
455                                 pci_front_read_mem,
456                                 pci_front_write_mem,
457                                 dev) < 0 ) { 
458                         PrintError(dev->vm, VCORE_NONE, "pci_front (%s): pci_init_bar: unable to hook 24 bit memory region 0x%p to 0x%p\n",
459                                 state->name, (void*)(pbar->addr), (void*)(pbar->addr+pbar->size-1));
460                         return -1;
461                     }
462                 }
463
464             } else if ((bar_val & 0x6) == 0x4) {
465
466                 // partial update of a 64 bit region, no hook done yet
467
468                 struct pt_bar * hi_pbar = &(state->bars[bar_num + 1]);
469
470                 pbar->type = PT_BAR_MEM64_LO;
471                 hi_pbar->type = PT_BAR_MEM64_HI;
472
473                 // Set the low bits, only for temporary storage until we calculate the high BAR
474                 pbar->addr = PCI_MEM64_BASE_LO(bar_val);
475                 pbar->size = ~PCI_MEM64_BASE_LO(max_val) + 1;
476
477                 PrintDebug(dev->vm, VCORE_NONE, "pci_front (%s): pci_bar_init: partial 64 bit update\n",state->name);
478
479             } else {
480                 PrintError(dev->vm, VCORE_NONE, "pci_front (%s): pci_bar_init: invalid memory bar type\n",state->name);
481                 return -1;
482             }
483
484         }
485     }
486
487
488
489     // Update the pci subsystem versions
490     *dst = bar_val;
491
492     return 0;
493 }
494
495
496 //
497 // If the guest modifies a BAR, we expect that pci.c will do the following,
498 // in this order
499 //
500 //    1. notify us via the config_update callback, which we will feed back
501 //       to the host device
502 //    2. notify us of the bar change via the following callback 
503 //
504 // This callback will unhook as needed for the old bar value and rehook
505 // as needed for the new bar value
506 //
507 static int pci_bar_write(int bar_num, uint32_t * src, void * private_data) {
508     struct vm_device * dev = (struct vm_device *)private_data;
509     struct pci_front_internal * state = (struct pci_front_internal *)dev->private_data;
510     
511     struct pt_bar * pbar = &(state->bars[bar_num]);
512
513     PrintDebug(dev->vm, VCORE_NONE, "pci_front (%s): bar update: bar_num=%d, src=0x%x\n", state->name, bar_num, *src);
514     PrintDebug(dev->vm, VCORE_NONE, "pci_front (%s): the current bar has size=%u, type=%d, addr=%p, val=0x%x\n",
515                state->name, pbar->size, pbar->type, (void *)(addr_t)pbar->addr, pbar->val);
516
517     v3_host_dev_write_config(state->host_dev, bar_num*4 + 16, src, 4);
518     v3_host_dev_read_config(state->host_dev, bar_num*4 + 16, &state->config_space[bar_num*4 + 16], 4);
519     if (*src == 0xffffffff || *src == 0) {
520         PrintDebug(dev->vm, VCORE_NONE, "Ignoring BAR write for bar#%d, val=0x%x\n", bar_num, *src);
521         return 0;
522     }
523
524
525
526     if (pbar->type == PT_BAR_NONE) {
527         PrintDebug(dev->vm, VCORE_NONE, "pci_front (%s): bar update is to empty bar - ignored\n",state->name);
528         return 0;
529     } else if (pbar->type == PT_BAR_IO) {
530         int i = 0;
531
532         // unhook old ports
533     if (pbar->mapped) {
534         PrintDebug(dev->vm, VCORE_NONE, "pci_front (%s): unhooking I/O ports 0x%x through 0x%x\n", 
535                 state->name, 
536                 (unsigned)(pbar->addr), (unsigned)(pbar->addr+pbar->size-1));
537         for (i = 0; i < pbar->size; i++) {
538             if (v3_dev_unhook_io(dev, pbar->addr + i) == -1) {
539                 PrintError(dev->vm, VCORE_NONE, "pci_front (%s): could not unhook previously hooked port.... 0x%x\n", 
540                         state->name, 
541                         (uint32_t)pbar->addr + i);
542                 return -1;
543             }
544         }
545     }
546
547         PrintDebug(dev->vm, VCORE_NONE, "pci_front (%s): setting I/O Port range size=%d\n", state->name, pbar->size);
548
549         // 
550         // Not clear if this cooking is needed... why not trust
551         // the write?  Who cares if it wants to suddenly hook more ports?
552         // 
553
554         // clear the low bits to match the size
555         *src &= ~(pbar->size - 1);
556
557         // Set reserved bits
558         *src |= (pbar->val & ~PCI_IO_MASK);
559
560         pbar->addr = PCI_IO_BASE(*src); 
561
562         PrintDebug(dev->vm, VCORE_NONE, "pci_front (%s): cooked src=0x%x\n", state->name, *src);
563
564         PrintDebug(dev->vm, VCORE_NONE, "pci_front (%s): rehooking I/O ports 0x%x through 0x%x\n",
565                    state->name, (unsigned)(pbar->addr), (unsigned)(pbar->addr+pbar->size-1));
566
567     if (pbar->addr) {
568         for (i = 0; i < pbar->size; i++) {
569             if (v3_dev_hook_io(dev,
570                                pbar->addr + i, 
571                                pci_front_read_port, 
572                                pci_front_write_port)<0) { 
573                 PrintError(dev->vm, VCORE_NONE, "pci_front (%s): unable to rehook port 0x%x\n",state->name, (unsigned)(pbar->addr+i));
574                 return -1;
575             }
576         }
577     }
578
579     } else if (pbar->type == PT_BAR_MEM32) {
580
581         if (pbar->mapped) {
582             if (v3_unhook_mem(dev->vm,V3_MEM_CORE_ANY,pbar->addr)<0) { 
583                 PrintError(dev->vm, VCORE_NONE, "pci_front (%s): unable to unhook 32 bit memory region starting at 0x%p\n", 
584                         state->name, (void*)(pbar->addr));
585                 return -1;
586             }
587         }
588
589         // Again, not sure I need to do this cooking...
590
591         // clear the low bits to match the size
592         *src &= ~(pbar->size - 1);
593
594         // Set reserved bits
595         *src |= (pbar->val & ~PCI_MEM_MASK);
596
597         PrintDebug(dev->vm, VCORE_NONE, "pci_front (%s): cooked src=0x%x\n", state->name, *src);
598
599         pbar->addr = PCI_MEM32_BASE(*src);
600
601         PrintDebug(dev->vm, VCORE_NONE, "pci_front (%s): rehooking 32 bit memory region 0x%p through 0x%p\n",
602                    state->name, (void*)(pbar->addr), (void*)(pbar->addr + pbar->size - 1));
603                    
604     if (pbar->addr) {
605         if (v3_hook_full_mem(dev->vm,
606                              V3_MEM_CORE_ANY,
607                              pbar->addr,
608                              pbar->addr+pbar->size-1,
609                              pci_front_read_mem,
610                              pci_front_write_mem,
611                              dev)<0) { 
612             PrintError(dev->vm, VCORE_NONE, "pci_front (%s): unable to rehook 32 bit memory region 0x%p through 0x%p\n",
613                        state->name, (void*)(pbar->addr), (void*)(pbar->addr + pbar->size - 1));
614             return -1;
615         }
616     }
617
618     } else if (pbar->type == PT_BAR_MEM64_LO) {
619         // We only store the written values here, the actual reconfig comes when the high BAR is updated
620
621         // clear the low bits to match the size
622         *src &= ~(pbar->size - 1);
623
624         // Set reserved bits
625         *src |= (pbar->val & ~PCI_MEM_MASK);
626
627         // Temp storage, used when hi bar is written
628         pbar->addr = PCI_MEM64_BASE_LO(*src);
629
630         PrintDebug(dev->vm, VCORE_NONE, "pci_front (%s): handled partial update for 64 bit memory region\n",state->name);
631
632     } else if (pbar->type == PT_BAR_MEM64_HI) {
633         struct pt_bar * lo_vbar = &(state->bars[bar_num - 1]);
634
635     if (pbar->mapped) {
636         if (v3_unhook_mem(dev->vm,V3_MEM_CORE_ANY,pbar->addr)<0) { 
637             PrintError(dev->vm, VCORE_NONE, "pci_front (%s): unable to unhook 64 bit memory region starting at 0x%p\n", 
638                     state->name, (void*)(pbar->addr));
639             return -1;
640         }
641     }
642
643         
644         // We don't set size, because we assume region is less than 4GB
645
646         // Set reserved bits
647         *src |= (pbar->val & ~PCI_MEM64_MASK_HI);
648
649         pbar->addr = PCI_MEM64_BASE_HI(*src);
650         pbar->addr <<= 32;
651         pbar->addr += lo_vbar->addr;
652
653         PrintDebug(dev->vm, VCORE_NONE, "pci_front (%s): rehooking 64 bit memory region 0x%p through 0x%p\n",
654                    state->name, (void*)(pbar->addr), (void*)(pbar->addr + pbar->size - 1));
655                    
656         if (v3_hook_full_mem(dev->vm,
657                              V3_MEM_CORE_ANY,
658                              pbar->addr,
659                              pbar->addr+pbar->size-1,
660                              pci_front_read_mem,
661                              pci_front_write_mem,
662                              dev)<0) { 
663             PrintError(dev->vm, VCORE_NONE, "pci_front (%s): unable to rehook 64 bit memory region 0x%p through 0x%p\n",
664                        state->name, (void*)(pbar->addr), (void*)(pbar->addr + pbar->size - 1));
665             return -1;
666         }
667         
668     } else {
669         PrintError(dev->vm, VCORE_NONE, "pci_front (%s): unhandled PCI bar type %d\n", state->name, pbar->type);
670         return -1;
671     }
672
673     pbar->val = *src;
674     
675     return 0;
676 }
677
678 static int pci_front_cmd_update(struct pci_device *pci_dev, pci_cmd_t cmd, uint64_t arg, void * priv_data)
679 {
680     struct vm_device * dev = (struct vm_device *)priv_data;
681     struct pci_front_internal * state = (struct pci_front_internal *)dev->private_data;
682
683     uint16_t command = (uint16_t)arg;
684
685     PrintDebug(VM_NONE, VCORE_NONE, "pci_front (%s): command update\n", state->name);
686
687     if (v3_host_dev_write_config(state->host_dev, 0x4, &command, 2) != 2) {
688         PrintError(dev->vm, VCORE_NONE, "pci_front (%s): cmd update: unable to write all bytes\n", state->name);
689         return -1;
690     }
691
692     return 0;
693 }
694
695 static int pci_front_config_read(struct pci_device *pci_dev, uint_t reg_num, void * dst, uint_t length, void * priv_data)
696 {
697     struct vm_device * dev = (struct vm_device *)priv_data;
698     struct pci_front_internal * state = (struct pci_front_internal *)dev->private_data;
699     int i;
700
701     memcpy(dst, (void*)&(state->config_space[reg_num]), length);
702
703
704     PrintDebug(VM_NONE, VCORE_NONE, "read callback (%d bytes starting at reg num %x)\n", length, reg_num);
705     for (i = 0; i < length; i++) {
706         PrintDebug(VM_NONE, VCORE_NONE, "byte %d: %x\n", i, state->config_space[reg_num+i]);
707     }
708
709     /*
710     PrintDebug(VM_NONE, VCORE_NONE, "pci_front config space read callback (%d bytes starting at reg num %x) returning:\n", length, reg_num);
711     for (i = 0; i < length/4; i++) {
712         PrintDebug(VM_NONE, VCORE_NONE, "%x\n", *(uint32_t*)(&(state->config_space[reg_num]) + i*4));
713     }
714     */
715
716     
717     
718     return 0;
719 }
720
721
722 static int pci_front_config_update(struct pci_device *pci_dev, uint_t reg_num, void * src, uint_t length, void * private_data) 
723 {
724     int i;
725     struct vm_device * dev = (struct vm_device *)private_data;
726     struct pci_front_internal * state = (struct pci_front_internal *)dev->private_data;
727     union pci_addr_reg pci_addr = {state->pci_addr.value};
728     
729     pci_addr.reg = reg_num >> 2;
730
731     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",
732                state->name, length, pci_addr.value, state->host_dev);
733     
734     for (i = 0; i < length; i++) { 
735         PrintDebug(dev->vm, VCORE_NONE, "%x", ((uint8_t *)src)[i]);
736     }
737
738     PrintDebug(dev->vm, VCORE_NONE, "\n");
739
740     /* first, keep our local copy in sync */
741     memcpy((void*)&state->config_space[pci_addr.value], src, length);
742
743     /* propagate back to the host side */
744     if (v3_host_dev_write_config(state->host_dev,
745                                  pci_addr.value,
746                                  src,
747                                  length) != length) { 
748         PrintError(dev->vm, VCORE_NONE, "pci_front (%s): configuration update: unable to write all bytes\n",state->name);
749         return -1;
750     }
751
752     return 0;
753 }
754
755
756 static int unhook_all_mem(struct pci_front_internal *state)
757 {
758     int bar_num;
759     struct vm_device *bus = state->pci_bus;
760
761
762     for (bar_num=0;bar_num<6;bar_num++) { 
763         struct pt_bar * pbar = &(state->bars[bar_num]);
764
765         PrintDebug(bus->vm, VCORE_NONE, "pci_front (%s): unhooking for bar %d\n", state->name, bar_num);
766
767         if (pbar->type == PT_BAR_MEM32) {
768             if (v3_unhook_mem(bus->vm,V3_MEM_CORE_ANY,pbar->addr)<0) { 
769                 PrintError(bus->vm, VCORE_NONE, "pci_front (%s): unable to unhook 32 bit memory region starting at 0x%p\n", 
770                            state->name, (void*)(pbar->addr));
771                 return -1;
772             }
773         } else  if (pbar->type == PT_BAR_MEM64_HI) {
774
775             if (v3_unhook_mem(bus->vm,V3_MEM_CORE_ANY,pbar->addr)<0) { 
776                 PrintError(bus->vm, VCORE_NONE, "pci_front (%s): unable to unhook 64 bit memory region starting at 0x%p\n", 
777                            state->name, (void*)(pbar->addr));
778                 return -1;
779             }
780         }
781     }
782     
783     return 0;
784 }
785
786
787
788 static int setup_virt_pci_dev(struct v3_vm_info * vm_info, struct vm_device * dev) 
789 {
790     struct pci_front_internal * state = (struct pci_front_internal *)dev->private_data;
791     struct pci_device * pci_dev = NULL;
792     struct v3_pci_bar bars[6];
793     int bus_num = 0;
794     int i;
795
796     for (i = 0; i < 6; i++) {
797         bars[i].type = PCI_BAR_PASSTHROUGH;
798         bars[i].private_data = dev;
799         bars[i].bar_init = pci_bar_init;
800         bars[i].bar_write = pci_bar_write;
801     }
802
803     pci_dev = v3_pci_register_device(state->pci_bus,
804                                      PCI_STD_DEVICE,
805                                      bus_num, -1, 0, 
806                                      state->name, bars,
807                                      pci_front_config_update,
808                                      pci_front_config_read,      
809                                      pci_front_cmd_update,      // no support for command updates
810                                      NULL,      // no support for expansion roms              
811                                      dev);
812
813
814     state->pci_dev = pci_dev;
815
816
817     // EXPANSION ROMS CURRENTLY UNSUPPORTED
818
819     // COMMANDS CURRENTLY UNSUPPORTED
820
821     return 0;
822 }
823
824
825
826 //
827 // Note: potential bug:  not clear what pointer I get here
828 //
829 static int pci_front_free(struct pci_front_internal *state)
830 {
831
832     if (unhook_all_mem(state)<0) { 
833         return -1;
834     }
835
836     // the device manager will unhook the i/o ports for us
837
838     if (state->host_dev) { 
839         v3_host_dev_close(state->host_dev);
840         state->host_dev=0;
841     }
842
843
844     V3_Free(state);
845
846     PrintDebug(state->pci_bus->vm, VCORE_NONE, "pci_front (%s): freed\n",state->name);
847
848     return 0;
849 }
850
851 #ifdef V3_CONFIG_HOST_DEVICE
852 static void pci_front_intr_update_callback(v3_host_dev_t hdev, v3_guest_dev_t gdev, uint8_t irq, int raise)
853 {
854     if (gdev) { 
855
856         struct vm_device *dev = (struct vm_device *) gdev;
857         struct pci_front_internal *state = (struct pci_front_internal *) dev->private_data;
858
859         // We expect the host device will raise and lower irqs as needed, so we
860         // don't need an "acked" irq.  Also, we expect the host is using INTX, not
861         // MSI.  It's doubtful that MSI will work.  
862         // expect: state->pci_dev->irq_type==IRQ_INTX
863     PrintDebug(VM_NONE, VCORE_NONE, "Palacios raising PCI IRQ %x\n", irq);
864         if (raise) { 
865             v3_pci_raise_irq(state->pci_bus, state->pci_dev, irq);
866         } else {
867             v3_pci_lower_irq(state->pci_bus, state->pci_dev, irq);
868         }
869     }
870 }
871 #endif
872
873
874 static struct v3_device_ops dev_ops = {
875 //
876 // Note: potential bug:  not clear what pointer I get here
877 //
878     .free = (int (*)(void*))pci_front_free,
879 };
880
881
882
883
884
885
886
887 static int pci_front_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) 
888 {
889     struct vm_device * dev;
890     struct vm_device * bus;
891     struct pci_front_internal *state;
892     char *dev_id;
893     char *bus_id;
894     char *url;
895
896     
897     if (!(dev_id = v3_cfg_val(cfg, "ID"))) { 
898         PrintError(vm, VCORE_NONE, "pci_front: no id  given!\n");
899         return -1;
900     }
901     
902     if (!(bus_id = v3_cfg_val(cfg, "bus"))) { 
903         PrintError(vm, VCORE_NONE, "pci_front (%s): no bus given!\n",dev_id);
904         return -1;
905     }
906     
907     if (!(url = v3_cfg_val(cfg, "hostdev"))) { 
908         PrintError(vm, VCORE_NONE, "pci_front (%s): no host device url given!\n",dev_id);
909         return -1;
910     }
911     
912     if (!(bus = v3_find_dev(vm,bus_id))) { 
913         PrintError(vm, VCORE_NONE, "pci_front (%s): cannot attach to bus %s\n",dev_id,bus_id);
914         return -1;
915     }
916     
917     if (!(state = V3_Malloc(sizeof(struct pci_front_internal)))) { 
918         PrintError(vm, VCORE_NONE, "pci_front (%s): cannot allocate state for device\n",dev_id);
919         return -1;
920     }
921     
922     memset(state, 0, sizeof(struct pci_front_internal));
923     
924     state->pci_bus = bus;
925     strncpy(state->name, dev_id, 32);
926     
927     if (!(dev = v3_add_device(vm, dev_id, &dev_ops, state))) { 
928         PrintError(vm, VCORE_NONE, "pci_front (%s): unable to add device\n",state->name);
929         return -1;
930     }
931     
932     if (!(state->host_dev=v3_host_dev_open(url,V3_BUS_CLASS_PCI,dev,pci_front_intr_update_callback,vm))) { 
933         PrintError(vm, VCORE_NONE, "pci_front (%s): unable to attach to host device %s\n",state->name, url);
934         v3_remove_device(dev);
935         return -1;
936     }
937
938     if (pull_config(state,state->config_space)) { 
939         PrintError(dev->vm, VCORE_NONE, "pci_front (%s): cannot initially configure device\n",state->name);
940         v3_remove_device(dev);
941         return -1;
942     }
943
944     // setup virtual device for now
945     if (setup_virt_pci_dev(vm,dev)<0) { 
946         PrintError(vm, VCORE_NONE, "pci_front (%s): cannot set up virtual pci device\n", state->name);
947         v3_remove_device(dev);
948         return -1;
949     }
950
951     // We do not need to hook anything here since pci will call
952     // us back via the bar_init functions
953
954     PrintDebug(vm, VCORE_NONE, "pci_front (%s): inited and ready to be Potemkinized\n",state->name);
955
956     return 0;
957
958 }
959
960
961 device_register("PCI_FRONT", pci_front_init)