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.


imported updated PCI devicE
[palacios.git] / palacios / src / devices / pci.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) 2009, Lei Xia <lxia@northwestern.edu>
11  * Copyright (c) 2009, Chang Seok Bae <jhuell@gmail.com>
12  * Copyright (c) 2009, Jack Lange <jarusl@cs.northwestern.edu>
13  * Copyright (c) 2009, The V3VEE Project <http://www.v3vee.org> 
14  * All rights reserved.
15  *
16  * Author:  Lei Xia <lxia@northwestern.edu>
17  *          Chang Seok Bae <jhuell@gmail.com>
18  *          Jack Lange <jarusl@cs.northwestern.edu>
19  *
20  * This is free software.  You are permitted to use,
21  * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
22  */ 
23  
24  
25
26 #include <palacios/vmm.h>
27 #include <palacios/vmm_types.h>
28 #include <palacios/vmm_io.h>
29 #include <palacios/vmm_intr.h>
30 #include <palacios/vmm_rbtree.h>
31
32 #include <devices/pci.h>
33 #include <devices/pci_types.h>
34
35 #ifndef DEBUG_PCI
36 #undef PrintDebug
37 #define PrintDebug(fmt, args...)
38 #endif
39
40
41 #define CONFIG_ADDR_PORT    0x0cf8
42 #define CONFIG_DATA_PORT    0x0cfc
43
44
45 #define PCI_BUS_COUNT 1
46
47 // This must always be a multiple of 8
48 #define MAX_BUS_DEVICES 32
49
50 struct pci_addr_reg {
51     union {
52         uint32_t val;
53         struct {
54             uint_t rsvd       : 2;
55             uint_t reg_num    : 6;
56             uint_t fn_num     : 3;
57             uint_t dev_num    : 5;
58             uint_t bus_num    : 8;
59             uint_t rsvd2      : 7;
60             uint_t enable     : 1;
61         } __attribute__((packed));
62     } __attribute__((packed));
63 } __attribute__((packed));
64
65
66
67
68
69 struct pci_bus {
70     int bus_num;
71
72     // Red Black tree containing all attached devices
73     struct rb_root devices;
74
75     // Bitmap of the allocated device numbers
76     uint8_t dev_map[MAX_BUS_DEVICES / 8];
77 };
78
79
80
81 struct pci_internal {
82     // Configuration address register
83     struct pci_addr_reg addr_reg;
84
85     // Attached Busses
86     struct pci_bus bus_list[PCI_BUS_COUNT];
87 };
88
89
90
91 #ifdef PCI_DEBUG
92 static void pci_dump_state(struct pci_internal * pci_state);
93 #endif
94
95 // Scan the dev_map bitmap for the first '0' bit
96 static int get_free_dev_num(struct pci_bus * bus) {
97     int i, j;
98
99     for (i = 0; i < sizeof(bus->dev_map); i++) {
100         if (bus->dev_map[i] != 0xff) {
101             // availability
102             for (j = 0; j < 8; j++) {
103                 if (!(bus->dev_map[i] & (0x1 << j))) {
104                     return i * 8 + j;
105                 }
106             }
107         }
108     }
109
110     return -1;
111 }
112
113 static void allocate_dev_num(struct pci_bus * bus, int dev_num) {
114     int major = dev_num / 8;
115     int minor = dev_num % 8;
116
117     bus->dev_map[major] |= (0x1 << minor);
118 }
119
120
121
122 static inline 
123 struct pci_device * __add_device_to_bus(struct pci_bus * bus, struct pci_device * dev) {
124
125   struct rb_node ** p = &(bus->devices.rb_node);
126   struct rb_node * parent = NULL;
127   struct pci_device * tmp_dev = NULL;
128
129   while (*p) {
130     parent = *p;
131     tmp_dev = rb_entry(parent, struct pci_device, dev_tree_node);
132
133     if (dev->dev_num < tmp_dev->dev_num) {
134       p = &(*p)->rb_left;
135     } else if (dev->dev_num > tmp_dev->dev_num) {
136       p = &(*p)->rb_right;
137     } else {
138       return tmp_dev;
139     }
140   }
141
142   rb_link_node(&(dev->dev_tree_node), parent, p);
143
144   return NULL;
145 }
146
147
148 static inline 
149 struct pci_device * add_device_to_bus(struct pci_bus * bus, struct pci_device * dev) {
150
151   struct pci_device * ret = NULL;
152
153   if ((ret = __add_device_to_bus(bus, dev))) {
154     return ret;
155   }
156
157   v3_rb_insert_color(&(dev->dev_tree_node), &(bus->devices));
158
159   allocate_dev_num(bus, dev->dev_num);
160
161   return NULL;
162 }
163
164
165 static struct pci_device * get_device(struct pci_bus * bus, int dev_num) {
166     struct rb_node * n = bus->devices.rb_node;
167     struct pci_device * dev = NULL;
168
169     while (n) {
170         dev = rb_entry(n, struct pci_device, dev_tree_node);
171         
172         if (dev_num < dev->dev_num) {
173             n = n->rb_left;
174         } else if (dev_num > dev->dev_num) {
175             n = n->rb_right;
176         } else {
177             return dev;
178         }
179     }
180     
181     return NULL;
182 }
183
184
185
186 static int read_pci_header(struct pci_device * pci_dev, int reg_num, void * dst, int length) {
187
188     if (length == 4) {
189         *(uint32_t *)dst = *(uint32_t *)(pci_dev->header_space + reg_num);
190     } else if (length == 2) {
191         *(uint16_t *)dst = *(uint16_t *)(pci_dev->header_space + reg_num);
192     } else if (length == 1) {
193         *(uint8_t *)dst = pci_dev->header_space[reg_num];
194     } else {
195         PrintError("Invalid Read length (%d) for PCI configration header\n", length);
196         return -1;
197     }
198
199     return length;
200 }
201
202
203 static int write_pci_header(struct pci_device * pci_dev, int reg_num, void * src, int length) {
204
205     if (length == 4) {
206         *(uint32_t *)(pci_dev->header_space + reg_num) = *(uint32_t *)src;
207     } else if (length == 2) {
208         *(uint16_t *)(pci_dev->header_space + reg_num) = *(uint16_t *)src;
209     } else if (length == 1) {
210         pci_dev->header_space[reg_num] = *(uint8_t *)src;
211     } else {
212         PrintError("Invalid Read length (%d) for PCI configration header\n", length);
213         return -1;
214     }
215
216     // This is kind of ugly...
217     if ((reg_num >= 0x10) && (reg_num < 0x27)) {
218         int bar_num = (reg_num & ~0x3) - 0x10;
219         uint32_t val = *(uint32_t *)(pci_dev->header_space + (reg_num & ~0x3));
220
221         pci_dev->bar_update(pci_dev, bar_num, val);
222     }
223
224     return length;
225 }
226
227
228 static int addr_port_read(ushort_t port, void * dst, uint_t length, struct vm_device * dev) {
229     struct pci_internal * pci_state = (struct pci_internal *)dev->private_data;
230     
231     if (length != 4) {
232         PrintError("Invalid read length (%d) for PCI address register\n", length);
233         return -1;
234     }
235     
236     PrintDebug("Reading PCI Address Port: %x\n", pci_state->addr_reg.val);
237     *(uint32_t *)dst = pci_state->addr_reg.val;
238
239     return length;
240 }
241
242
243 static int addr_port_write(ushort_t port, void * src, uint_t length, struct vm_device * dev) {
244     struct pci_internal * pci_state = (struct pci_internal *)dev->private_data;
245
246     if (length != 4) {
247         PrintError("Invalid write length (%d) for PCI address register\n", length);
248         return -1;
249     }
250
251     pci_state->addr_reg.val = *(uint32_t *)src;
252     PrintDebug("Writing PCI Address Port: %x\n", pci_state->addr_reg.val);    
253
254     return length;
255 }
256
257
258 static int data_port_read(ushort_t port, void * dst, uint_t length, struct vm_device * vmdev) {
259     struct pci_internal * pci_state =  (struct pci_internal *)vmdev->private_data;;
260     struct pci_device * pci_dev = NULL;
261     uint_t reg_num = pci_state->addr_reg.reg_num;
262
263         
264     PrintDebug("Reading PCI Data register. bus = %d, dev = %d, reg = %d (%x)\n", 
265                pci_state->addr_reg.bus_num, 
266                pci_state->addr_reg.dev_num, 
267                reg_num);
268
269     
270     pci_dev = get_device(&(pci_state->bus_list[0]), pci_state->addr_reg.dev_num);
271     
272     if (pci_dev == NULL) {
273         //*(uint32_t *)dst = 0xffffffff;
274
275         PrintError("Reading configuration space for non-present device (dev_num=%d)\n", 
276                    pci_state->addr_reg.dev_num); 
277
278         return -1;
279     }
280
281     // Header register
282     if (reg_num < 0x40) {
283         return read_pci_header(pci_dev, reg_num, dst, length);
284     }
285
286     if (pci_dev->config_read) {
287         return pci_dev->config_read(pci_dev, reg_num, dst, length);
288     }
289
290
291     if (length == 4) {
292         *(uint32_t *)dst = *(uint32_t *)(pci_dev->config_space + reg_num - 0x40);
293     } else if (length == 2) {
294         *(uint16_t *)dst = *(uint16_t *)(pci_dev->config_space + reg_num - 0x40);
295     } else if (length == 1) {
296         *(uint8_t *)dst = pci_dev->config_space[reg_num - 0x40];
297     } else {
298         PrintError("Invalid Read length (%d) for PCI data register", length);
299         return -1;
300     }
301         
302     return length;
303 }
304
305
306 static int data_port_write(ushort_t port, void * src, uint_t length, struct vm_device * vmdev) {
307     struct pci_internal * pci_state = (struct pci_internal *)vmdev->private_data;;
308     struct pci_device * pci_dev = NULL;
309     uint_t reg_num = pci_state->addr_reg.reg_num;
310     
311     
312     PrintDebug("Writing PCI Data register. bus = %d, dev = %d, reg = %d (%x)\n", 
313                pci_state->addr_reg.bus_num, 
314                pci_state->addr_reg.dev_num, 
315                reg_num);
316
317     pci_dev = get_device(&(pci_state->bus_list[0]), pci_state->addr_reg.dev_num);
318     
319     if (pci_dev == NULL) {
320         PrintError("Writing configuration space for non-present device (dev_num=%d)\n", 
321                    pci_state->addr_reg.dev_num); 
322         return -1;
323     }
324     
325     // Header register
326     if (reg_num < 0x40) {
327         return write_pci_header(pci_dev, reg_num, src, length);
328     }
329     
330
331     if (pci_dev->config_write) {
332         return pci_dev->config_write(pci_dev, reg_num, src, length);
333     }
334
335
336     if (length == 4) {
337         *(uint32_t *)(pci_dev->config_space + reg_num - 0x40) = *(uint32_t *)src;
338     } else if (length == 2) {
339         *(uint16_t *)(pci_dev->config_space + reg_num - 0x40) = *(uint16_t *)src;
340     } else if (length == 1) {
341         pci_dev->config_space[reg_num - 0x40] = *(uint8_t *)src;
342     } else {
343         PrintError("Invalid Write length (%d) for PCI data register", length);
344         return -1;
345     }
346         
347     return length;
348 }
349
350
351
352 static int pci_reset_device(struct vm_device * dev) {
353     PrintDebug("pci: reset device\n");    
354     return 0;
355 }
356
357
358 static int pci_start_device(struct vm_device * dev) {
359     PrintDebug("pci: start device\n");
360     return 0;
361 }
362
363
364 static int pci_stop_device(struct vm_device * dev) {
365     PrintDebug("pci: stop device\n");  
366     return 0;
367 }
368
369
370
371 static int pci_deinit_device(struct vm_device * dev) {
372     int i = 0;
373     
374     for (i = 0; i < 4; i++){
375         v3_dev_unhook_io(dev, CONFIG_ADDR_PORT + i);
376         v3_dev_unhook_io(dev, CONFIG_DATA_PORT + i);
377     }
378     
379     return 0;
380 }
381
382
383
384
385 static int init_i440fx(struct pci_internal * pci_state) {
386
387     struct pci_device * dev = v3_pci_register_device(NULL, 0, "i440FX", 0, 
388                                                      NULL, NULL, NULL, NULL);
389     
390     if (!dev) {
391         return -1;
392     }
393     
394     dev->header.vendor_id = 0x8086;
395     dev->header.device_id = 0x1237;
396     dev->header.revision = 0x0002;
397     dev->header.subclass = 0x00; //  SubClass: host2pci
398     dev->header.class = 0x06;    // Class: PCI bridge
399     dev->header.header_type = 0x00;
400
401     dev->bus_num = 0;
402     
403     return 0;
404 }
405
406
407
408 static void init_pci_busses(struct pci_internal * pci_state) {
409     int i;
410
411     for (i = 0; i < PCI_BUS_COUNT; i++) {
412         pci_state->bus_list[i].bus_num = i;
413         pci_state->bus_list[i].devices.rb_node = NULL;
414         memset(pci_state->bus_list[i].dev_map, 0, sizeof(pci_state->bus_list[i].dev_map));
415     }
416 }
417
418
419
420 static int pci_init_device(struct vm_device * dev) {
421     struct pci_internal * pci_state = (struct pci_internal *)dev->private_data;;
422     int i = 0;
423     
424     PrintDebug("pci: init_device\n");
425
426     // JRL: Fix this....
427     //    dev->vm->pci = dev;   //should be in vmm_config.c
428     
429     pci_state->addr_reg.val = 0; 
430
431     init_pci_busses(pci_state);
432
433     if (init_i440fx(pci_state) == -1) {
434         PrintError("Could not intialize i440fx\n");
435         return -1;
436     }
437     
438     for (i = 0; i < 4; i++) {
439         v3_dev_hook_io(dev, CONFIG_ADDR_PORT + i, &addr_port_read, &addr_port_write);
440         v3_dev_hook_io(dev, CONFIG_DATA_PORT + i, &data_port_read, &data_port_write);
441     }
442
443     return 0;
444 }
445
446
447 static struct vm_device_ops dev_ops = {
448     .init = pci_init_device, 
449     .deinit = pci_deinit_device,
450     .reset = pci_reset_device,
451     .start = pci_start_device,
452     .stop = pci_stop_device,
453 };
454
455
456 struct vm_device * v3_create_pci() {
457     struct pci_internal * pci_state = V3_Malloc(sizeof(struct pci_internal));
458     
459     PrintDebug("PCI internal at %p\n",(void *)pci_state);
460     
461     struct vm_device * device = v3_create_device("PCI", &dev_ops, pci_state);
462     
463     return device;
464 }
465
466
467
468
469
470 /* JRL: TODO This needs to be completely rethought... */
471 struct pci_bus * v3_get_pcibus(struct guest_info * vm, int bus_no) {
472     //    struct pci_internal * pci_state = NULL;
473
474     /*
475       if (vm->pci == NULL) {
476       PrintError("There is no PCI bus in guest %p\n", vm);
477       return NULL;
478       }
479       
480       pci_state = (struct pci_internal *)vm->pci->private_data;
481       
482       if ((bus_no >= 0) && (bus_no < PCI_BUS_COUNT)) {
483       return &(pci_state->bus_list[bus_no]);
484       }
485     */
486     return NULL;
487 }
488
489
490
491
492 // if dev_num == -1, auto assign 
493 struct pci_device * v3_pci_register_device(struct vm_device * dev,
494                                            uint_t bus_num,
495                                            const char * name,
496                                            int dev_num,
497                                            int (*config_read)(struct pci_device * pci_dev, uint_t reg_num, void * dst, int len),
498                                            int (*config_write)(struct pci_device * pci_dev, uint_t reg_num, void * src, int len),
499                                            int (*bar_update)(struct pci_device * pci_dev, uint_t bar_reg, uint32_t val),
500                                            void * private_data) {
501
502     struct pci_internal * pci_state = (struct pci_internal *)dev->private_data;
503     struct pci_bus * bus = &(pci_state->bus_list[bus_num]);
504     struct pci_device * pci_dev = NULL;
505
506     if (dev_num > MAX_BUS_DEVICES) {
507         PrintError("Requested Invalid device number (%d)\n", dev_num);
508         return NULL;
509     }
510
511     if (dev_num == -1) {
512         if ((dev_num = get_free_dev_num(bus)) == -1) {
513             PrintError("No more available PCI slots on bus %d\n", bus->bus_num);
514             return NULL;
515         }
516     }
517     
518     if (get_device(bus, dev_num) != NULL) {
519         PrintError("PCI Device already registered at slot %d on bus %d\n", 
520                    dev_num, bus->bus_num);
521         return NULL;
522     }
523
524     
525     pci_dev = (struct pci_device *)V3_Malloc(sizeof(struct pci_device));
526
527     if (pci_dev == NULL) {
528         return NULL;
529     }
530
531     memset(pci_dev, 0, sizeof(struct pci_device));
532         
533     
534     pci_dev->bus_num = bus_num;
535     pci_dev->dev_num = dev_num;
536
537     strncpy(pci_dev->name, name, sizeof(pci_dev->name));
538     pci_dev->vm_dev = dev;
539
540     pci_dev->config_read = config_read;
541     pci_dev->config_write = config_write;
542     pci_dev->bar_update = bar_update;
543
544     pci_dev->priv_data = private_data;
545
546     // add the device
547     add_device_to_bus(bus, pci_dev);
548     
549 #ifdef DEBUG_PCI
550     pci_dump_state(pci_state);
551 #endif
552
553     return pci_dev;
554 }
555
556
557
558 #ifdef DEBUG_PCI
559
560 static void pci_dump_state(struct pci_internal * pci_state) {
561     struct rb_node * node = v3_rb_first(&(pci_state->bus_list[0].devices));
562     struct pci_device * tmp_dev = NULL;
563     
564     PrintDebug("===PCI: Dumping state Begin ==========\n");
565     
566     do {
567         tmp_dev = rb_entry(node, struct pci_device, dev_tree_node);
568
569         PrintDebug("PCI Device Number: %d (%s):\n", tmp_dev->dev_num,  tmp_dev->name);
570         PrintDebug("irq = %d\n", tmp_dev->header.irq_line);
571         PrintDebug("Vend ID: 0x%x\n", tmp_dev->header.vendor_id);
572         PrintDebug("Device ID: 0x%x\n", tnp_dev->header.device_id);
573
574     } while ((node = v3_rb_next(node)));
575     
576     PrintDebug("====PCI: Dumping state End==========\n");
577 }
578
579 #endif