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 updates
[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     int reg_offset = port & 0x3;
231     uint8_t * reg_addr = ((uint8_t *)&(pci_state->addr_reg.val)) + reg_offset;
232
233     PrintDebug("Reading PCI Address Port (%x): %x\n", port, pci_state->addr_reg.val);
234
235     if (length == 4) {
236         if (reg_offset != 0) {
237             PrintError("Invalid Address Port Read\n");
238             return -1;
239         }
240         *(uint32_t *)dst = *(uint32_t *)reg_addr;
241     } else if (length == 2) {
242         if (reg_offset > 2) {
243             PrintError("Invalid Address Port Read\n");
244             return -1;
245         }
246         *(uint16_t *)dst = *(uint16_t *)reg_addr;
247     } else if (length == 1) {
248         *(uint8_t *)dst = *(uint8_t *)reg_addr;
249     } else {
250         PrintError("Invalid read length (%d) for PCI address register\n", length);
251         return -1;
252     }
253     
254
255     return length;
256 }
257
258
259 static int addr_port_write(ushort_t port, void * src, uint_t length, struct vm_device * dev) {
260     struct pci_internal * pci_state = (struct pci_internal *)dev->private_data;
261     int reg_offset = port & 0x3; 
262     uint8_t * reg_addr = ((uint8_t *)&(pci_state->addr_reg.val)) + reg_offset;
263
264     if (length == 4) {
265         if (reg_offset != 0) {
266             PrintError("Invalid Address Port Write\n");
267             return -1;
268         }
269
270         *(uint32_t *)reg_addr = *(uint32_t *)src;
271     } else if (length == 2) {
272         if (reg_offset > 2) {
273             PrintError("Invalid Address Port Write\n");
274             return -1;
275         }
276
277         *(uint16_t *)reg_addr = *(uint16_t *)src;
278     } else if (length == 1) {
279         *(uint8_t *)reg_addr = *(uint8_t *)src;
280     } else {
281         PrintError("Invalid write length (%d) for PCI address register\n", length);
282         return -1;
283     }
284
285     PrintDebug("Writing PCI Address Port(%x): %x\n", port, pci_state->addr_reg.val);    
286
287
288     return length;
289 }
290
291
292 static int data_port_read(ushort_t port, void * dst, uint_t length, struct vm_device * vmdev) {
293     struct pci_internal * pci_state =  (struct pci_internal *)vmdev->private_data;;
294     struct pci_device * pci_dev = NULL;
295     uint_t reg_num = pci_state->addr_reg.reg_num;
296
297         
298     PrintDebug("Reading PCI Data register. bus = %d, dev = %d, reg = %d (%x)\n", 
299                pci_state->addr_reg.bus_num, 
300                pci_state->addr_reg.dev_num, 
301                reg_num);
302
303     
304     if (port != CONFIG_DATA_PORT) {
305         PrintError("Weird Data port Read: %x\n", port);
306         return -1;
307     }
308
309     pci_dev = get_device(&(pci_state->bus_list[0]), pci_state->addr_reg.dev_num);
310     
311     if (pci_dev == NULL) {
312         //*(uint32_t *)dst = 0xffffffff;
313
314         PrintError("Reading configuration space for non-present device (dev_num=%d)\n", 
315                    pci_state->addr_reg.dev_num); 
316
317         return -1;
318     }
319
320     // Header register
321     if (reg_num < 0x40) {
322         return read_pci_header(pci_dev, reg_num, dst, length);
323     }
324
325     if (pci_dev->config_read) {
326         return pci_dev->config_read(pci_dev, reg_num, dst, length);
327     }
328
329
330     if (length == 4) {
331         *(uint32_t *)dst = *(uint32_t *)(pci_dev->config_space + reg_num - 0x40);
332     } else if (length == 2) {
333         *(uint16_t *)dst = *(uint16_t *)(pci_dev->config_space + reg_num - 0x40);
334     } else if (length == 1) {
335         *(uint8_t *)dst = pci_dev->config_space[reg_num - 0x40];
336     } else {
337         PrintError("Invalid Read length (%d) for PCI data register", length);
338         return -1;
339     }
340         
341     return length;
342 }
343
344
345 static int data_port_write(ushort_t port, void * src, uint_t length, struct vm_device * vmdev) {
346     struct pci_internal * pci_state = (struct pci_internal *)vmdev->private_data;;
347     struct pci_device * pci_dev = NULL;
348     uint_t reg_num = pci_state->addr_reg.reg_num;
349     
350     
351     PrintDebug("Writing PCI Data register. bus = %d, dev = %d, reg = %d (%x)\n", 
352                pci_state->addr_reg.bus_num, 
353                pci_state->addr_reg.dev_num, 
354                reg_num);
355
356     if (port != CONFIG_DATA_PORT) {
357         PrintError("Weird Data port Write: %x\n", port);
358         return -1;
359     }
360
361
362     pci_dev = get_device(&(pci_state->bus_list[0]), pci_state->addr_reg.dev_num);
363     
364     if (pci_dev == NULL) {
365         PrintError("Writing configuration space for non-present device (dev_num=%d)\n", 
366                    pci_state->addr_reg.dev_num); 
367         return -1;
368     }
369     
370     // Header register
371     if (reg_num < 0x40) {
372         return write_pci_header(pci_dev, reg_num, src, length);
373     }
374     
375
376     if (pci_dev->config_write) {
377         return pci_dev->config_write(pci_dev, reg_num, src, length);
378     }
379
380
381     if (length == 4) {
382         *(uint32_t *)(pci_dev->config_space + reg_num - 0x40) = *(uint32_t *)src;
383     } else if (length == 2) {
384         *(uint16_t *)(pci_dev->config_space + reg_num - 0x40) = *(uint16_t *)src;
385     } else if (length == 1) {
386         pci_dev->config_space[reg_num - 0x40] = *(uint8_t *)src;
387     } else {
388         PrintError("Invalid Write length (%d) for PCI data register", length);
389         return -1;
390     }
391         
392     return length;
393 }
394
395
396
397 static int pci_reset_device(struct vm_device * dev) {
398     PrintDebug("pci: reset device\n");    
399     return 0;
400 }
401
402
403 static int pci_start_device(struct vm_device * dev) {
404     PrintDebug("pci: start device\n");
405     return 0;
406 }
407
408
409 static int pci_stop_device(struct vm_device * dev) {
410     PrintDebug("pci: stop device\n");  
411     return 0;
412 }
413
414
415
416 static int pci_deinit_device(struct vm_device * dev) {
417     int i = 0;
418     
419     for (i = 0; i < 4; i++){
420         v3_dev_unhook_io(dev, CONFIG_ADDR_PORT + i);
421         v3_dev_unhook_io(dev, CONFIG_DATA_PORT + i);
422     }
423     
424     return 0;
425 }
426
427
428
429
430 static int init_i440fx(struct vm_device * dev) {
431     struct pci_device * pci_dev = v3_pci_register_device(dev, 0, "i440FX", 0, 
432                                                          NULL, NULL, NULL, NULL);
433     
434     if (!pci_dev) {
435         return -1;
436     }
437     
438     pci_dev->header.vendor_id = 0x8086;
439     pci_dev->header.device_id = 0x1237;
440     pci_dev->header.revision = 0x0002;
441     pci_dev->header.subclass = 0x00; //  SubClass: host2pci
442     pci_dev->header.class = 0x06;    // Class: PCI bridge
443     pci_dev->header.header_type = 0x00;
444
445     pci_dev->bus_num = 0;
446     
447     return 0;
448 }
449
450
451
452 static void init_pci_busses(struct pci_internal * pci_state) {
453     int i;
454
455     for (i = 0; i < PCI_BUS_COUNT; i++) {
456         pci_state->bus_list[i].bus_num = i;
457         pci_state->bus_list[i].devices.rb_node = NULL;
458         memset(pci_state->bus_list[i].dev_map, 0, sizeof(pci_state->bus_list[i].dev_map));
459     }
460 }
461
462
463
464 static int pci_init_device(struct vm_device * dev) {
465     struct pci_internal * pci_state = (struct pci_internal *)dev->private_data;;
466     int i = 0;
467     
468     PrintDebug("pci: init_device\n");
469
470     // JRL: Fix this....
471     //    dev->vm->pci = dev;   //should be in vmm_config.c
472     
473     pci_state->addr_reg.val = 0; 
474
475     init_pci_busses(pci_state);
476
477     if (init_i440fx(dev) == -1) {
478         PrintError("Could not intialize i440fx\n");
479         return -1;
480     }
481     
482     for (i = 0; i < 4; i++) {
483         v3_dev_hook_io(dev, CONFIG_ADDR_PORT + i, &addr_port_read, &addr_port_write);
484         v3_dev_hook_io(dev, CONFIG_DATA_PORT + i, &data_port_read, &data_port_write);
485     }
486
487     return 0;
488 }
489
490
491 static struct vm_device_ops dev_ops = {
492     .init = pci_init_device, 
493     .deinit = pci_deinit_device,
494     .reset = pci_reset_device,
495     .start = pci_start_device,
496     .stop = pci_stop_device,
497 };
498
499
500 struct vm_device * v3_create_pci() {
501     struct pci_internal * pci_state = V3_Malloc(sizeof(struct pci_internal));
502     
503     PrintDebug("PCI internal at %p\n",(void *)pci_state);
504     
505     struct vm_device * device = v3_create_device("PCI", &dev_ops, pci_state);
506     
507     return device;
508 }
509
510
511
512
513
514 // if dev_num == -1, auto assign 
515 struct pci_device * v3_pci_register_device(struct vm_device * pci,
516                                            uint_t bus_num,
517                                            const char * name,
518                                            int dev_num,
519                                            int (*config_read)(struct pci_device * pci_dev, uint_t reg_num, void * dst, int len),
520                                            int (*config_write)(struct pci_device * pci_dev, uint_t reg_num, void * src, int len),
521                                            int (*bar_update)(struct pci_device * pci_dev, uint_t bar_reg, uint32_t val),
522                                            void * private_data) {
523
524     struct pci_internal * pci_state = (struct pci_internal *)pci->private_data;
525     struct pci_bus * bus = &(pci_state->bus_list[bus_num]);
526     struct pci_device * pci_dev = NULL;
527
528     if (dev_num > MAX_BUS_DEVICES) {
529         PrintError("Requested Invalid device number (%d)\n", dev_num);
530         return NULL;
531     }
532
533     if (dev_num == -1) {
534         if ((dev_num = get_free_dev_num(bus)) == -1) {
535             PrintError("No more available PCI slots on bus %d\n", bus->bus_num);
536             return NULL;
537         }
538     }
539     
540     if (get_device(bus, dev_num) != NULL) {
541         PrintError("PCI Device already registered at slot %d on bus %d\n", 
542                    dev_num, bus->bus_num);
543         return NULL;
544     }
545
546     
547     pci_dev = (struct pci_device *)V3_Malloc(sizeof(struct pci_device));
548
549     if (pci_dev == NULL) {
550         return NULL;
551     }
552
553     memset(pci_dev, 0, sizeof(struct pci_device));
554         
555     
556     pci_dev->bus_num = bus_num;
557     pci_dev->dev_num = dev_num;
558
559     strncpy(pci_dev->name, name, sizeof(pci_dev->name));
560     pci_dev->vm_dev = pci;
561
562     pci_dev->config_read = config_read;
563     pci_dev->config_write = config_write;
564     pci_dev->bar_update = bar_update;
565
566     pci_dev->priv_data = private_data;
567
568     // add the device
569     add_device_to_bus(bus, pci_dev);
570     
571 #ifdef DEBUG_PCI
572     pci_dump_state(pci_state);
573 #endif
574
575     return pci_dev;
576 }
577
578
579
580 #ifdef DEBUG_PCI
581
582 static void pci_dump_state(struct pci_internal * pci_state) {
583     struct rb_node * node = v3_rb_first(&(pci_state->bus_list[0].devices));
584     struct pci_device * tmp_dev = NULL;
585     
586     PrintDebug("===PCI: Dumping state Begin ==========\n");
587     
588     do {
589         tmp_dev = rb_entry(node, struct pci_device, dev_tree_node);
590
591         PrintDebug("PCI Device Number: %d (%s):\n", tmp_dev->dev_num,  tmp_dev->name);
592         PrintDebug("irq = %d\n", tmp_dev->header.irq_line);
593         PrintDebug("Vend ID: 0x%x\n", tmp_dev->header.vendor_id);
594         PrintDebug("Device ID: 0x%x\n", tnp_dev->header.device_id);
595
596     } while ((node = v3_rb_next(node)));
597     
598     PrintDebug("====PCI: Dumping state End==========\n");
599 }
600
601 #endif