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.


updated pci to simplify callback setup
[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
92
93 #ifdef DEBUG_PCI
94
95 static void pci_dump_state(struct pci_internal * pci_state) {
96     struct rb_node * node = v3_rb_first(&(pci_state->bus_list[0].devices));
97     struct pci_device * tmp_dev = NULL;
98     
99     PrintDebug("===PCI: Dumping state Begin ==========\n");
100     
101     do {
102         tmp_dev = rb_entry(node, struct pci_device, dev_tree_node);
103
104         PrintDebug("PCI Device Number: %d (%s):\n", tmp_dev->dev_num,  tmp_dev->name);
105         PrintDebug("irq = %d\n", tmp_dev->config_header.intr_line);
106         PrintDebug("Vend ID: 0x%x\n", tmp_dev->config_header.vendor_id);
107         PrintDebug("Device ID: 0x%x\n", tmp_dev->config_header.device_id);
108
109     } while ((node = v3_rb_next(node)));
110     
111     PrintDebug("====PCI: Dumping state End==========\n");
112 }
113
114 #endif
115
116
117
118
119 // Scan the dev_map bitmap for the first '0' bit
120 static int get_free_dev_num(struct pci_bus * bus) {
121     int i, j;
122
123     for (i = 0; i < sizeof(bus->dev_map); i++) {
124         if (bus->dev_map[i] != 0xff) {
125             // availability
126             for (j = 0; j < 8; j++) {
127                 if (!(bus->dev_map[i] & (0x1 << j))) {
128                     return i * 8 + j;
129                 }
130             }
131         }
132     }
133
134     return -1;
135 }
136
137 static void allocate_dev_num(struct pci_bus * bus, int dev_num) {
138     int major = dev_num / 8;
139     int minor = dev_num % 8;
140
141     bus->dev_map[major] |= (0x1 << minor);
142 }
143
144
145
146 static inline 
147 struct pci_device * __add_device_to_bus(struct pci_bus * bus, struct pci_device * dev) {
148
149   struct rb_node ** p = &(bus->devices.rb_node);
150   struct rb_node * parent = NULL;
151   struct pci_device * tmp_dev = NULL;
152
153   while (*p) {
154     parent = *p;
155     tmp_dev = rb_entry(parent, struct pci_device, dev_tree_node);
156
157     if (dev->dev_num < tmp_dev->dev_num) {
158       p = &(*p)->rb_left;
159     } else if (dev->dev_num > tmp_dev->dev_num) {
160       p = &(*p)->rb_right;
161     } else {
162       return tmp_dev;
163     }
164   }
165
166   rb_link_node(&(dev->dev_tree_node), parent, p);
167
168   return NULL;
169 }
170
171
172 static inline 
173 struct pci_device * add_device_to_bus(struct pci_bus * bus, struct pci_device * dev) {
174
175   struct pci_device * ret = NULL;
176
177   if ((ret = __add_device_to_bus(bus, dev))) {
178     return ret;
179   }
180
181   v3_rb_insert_color(&(dev->dev_tree_node), &(bus->devices));
182
183   allocate_dev_num(bus, dev->dev_num);
184
185   return NULL;
186 }
187
188
189 static struct pci_device * get_device(struct pci_bus * bus, int dev_num) {
190     struct rb_node * n = bus->devices.rb_node;
191     struct pci_device * dev = NULL;
192
193     while (n) {
194         dev = rb_entry(n, struct pci_device, dev_tree_node);
195         
196         if (dev_num < dev->dev_num) {
197             n = n->rb_left;
198         } else if (dev_num > dev->dev_num) {
199             n = n->rb_right;
200         } else {
201             return dev;
202         }
203     }
204     
205     return NULL;
206 }
207
208
209
210
211
212
213
214 static int addr_port_read(ushort_t port, void * dst, uint_t length, struct vm_device * dev) {
215     struct pci_internal * pci_state = (struct pci_internal *)dev->private_data;
216     int reg_offset = port & 0x3;
217     uint8_t * reg_addr = ((uint8_t *)&(pci_state->addr_reg.val)) + reg_offset;
218
219     PrintDebug("Reading PCI Address Port (%x): %x\n", port, pci_state->addr_reg.val);
220
221     if (length == 4) {
222         if (reg_offset != 0) {
223             PrintError("Invalid Address Port Read\n");
224             return -1;
225         }
226         *(uint32_t *)dst = *(uint32_t *)reg_addr;
227     } else if (length == 2) {
228         if (reg_offset > 2) {
229             PrintError("Invalid Address Port Read\n");
230             return -1;
231         }
232         *(uint16_t *)dst = *(uint16_t *)reg_addr;
233     } else if (length == 1) {
234         *(uint8_t *)dst = *(uint8_t *)reg_addr;
235     } else {
236         PrintError("Invalid read length (%d) for PCI address register\n", length);
237         return -1;
238     }
239     
240
241     return length;
242 }
243
244
245 static int addr_port_write(ushort_t port, void * src, uint_t length, struct vm_device * dev) {
246     struct pci_internal * pci_state = (struct pci_internal *)dev->private_data;
247     int reg_offset = port & 0x3; 
248     uint8_t * reg_addr = ((uint8_t *)&(pci_state->addr_reg.val)) + reg_offset;
249
250
251     if (length == 4) {
252         if (reg_offset != 0) {
253             PrintError("Invalid Address Port Write\n");
254             return -1;
255         }
256
257         PrintDebug("Writing PCI 4 bytes Val=%x\n",  *(uint32_t *)src);
258
259         *(uint32_t *)reg_addr = *(uint32_t *)src;
260     } else if (length == 2) {
261         if (reg_offset > 2) {
262             PrintError("Invalid Address Port Write\n");
263             return -1;
264         }
265
266         PrintDebug("Writing PCI 2 byte Val=%x\n",  *(uint16_t *)src);
267
268         *(uint16_t *)reg_addr = *(uint16_t *)src;
269     } else if (length == 1) {
270         PrintDebug("Writing PCI 1 byte Val=%x\n",  *(uint8_t *)src);
271         *(uint8_t *)reg_addr = *(uint8_t *)src;
272     } else {
273         PrintError("Invalid write length (%d) for PCI address register\n", length);
274         return -1;
275     }
276
277     PrintDebug("Writing PCI Address Port(%x): %x\n", port, pci_state->addr_reg.val);
278
279
280     return length;
281 }
282
283
284 static int data_port_read(ushort_t port, void * dst, uint_t length, struct vm_device * vmdev) {
285     struct pci_internal * pci_state =  (struct pci_internal *)vmdev->private_data;;
286     struct pci_device * pci_dev = NULL;
287     uint_t reg_num = pci_state->addr_reg.reg_num + (port & 0x3);
288     int i;
289
290     PrintDebug("Reading PCI Data register. bus = %d, dev = %d, reg = %d (%x), cfg_reg = %x\n", 
291                pci_state->addr_reg.bus_num, 
292                pci_state->addr_reg.dev_num, 
293                reg_num, reg_num, 
294                pci_state->addr_reg.val);
295
296
297     pci_dev = get_device(&(pci_state->bus_list[0]), pci_state->addr_reg.dev_num);
298     
299     if (pci_dev == NULL) {
300         //*(uint32_t *)dst = 0xffffffff;
301
302         PrintError("Reading configuration space for non-present device (dev_num=%d)\n", 
303                    pci_state->addr_reg.dev_num); 
304
305         return -1;
306     }
307
308     for (i = 0; i < length; i++) {
309         *((uint8_t *)dst + i) = pci_dev->config_space[reg_num + i];
310     }
311     
312     return length;
313 }
314
315
316 static inline int is_cfg_reg_writable(uchar_t header_type, int reg_num) {
317     if (header_type == 0x00) {
318         switch (reg_num) {
319             // case (non writable reg list):
320             
321             default:
322                 return 1;
323         }
324     } else {
325         // PCI to PCI Bridge = 0x01
326         // CardBus Bridge = 0x02
327
328         // huh?
329         PrintError("Invalid PCI Header type (0x%.2x)\n", header_type);
330
331         return -1;
332     }
333 }
334
335
336 static int data_port_write(ushort_t port, void * src, uint_t length, struct vm_device * vmdev) {
337     struct pci_internal * pci_state = (struct pci_internal *)vmdev->private_data;;
338     struct pci_device * pci_dev = NULL;
339     uint_t reg_num = pci_state->addr_reg.reg_num + (port & 0x3);
340     int i;
341
342     PrintDebug("Writing PCI Data register. bus = %d, dev = %d, reg = %d (%x) addr_reg = %x\n", 
343                pci_state->addr_reg.bus_num, 
344                pci_state->addr_reg.dev_num, 
345                reg_num, reg_num, 
346                pci_state->addr_reg.val);
347
348
349     pci_dev = get_device(&(pci_state->bus_list[0]), pci_state->addr_reg.dev_num);
350     
351     if (pci_dev == NULL) {
352         PrintError("Writing configuration space for non-present device (dev_num=%d)\n", 
353                    pci_state->addr_reg.dev_num); 
354         return -1;
355     }
356     
357
358     for (i = 0; i < length; i++) {
359         if (is_cfg_reg_writable(pci_dev->config_header.header_type, reg_num)) {
360             pci_dev->config_space[reg_num + i] = *((uint8_t *)src + i);
361         }
362     }
363
364     if (pci_dev->config_update) {
365         pci_dev->config_update(pci_dev, reg_num, length);
366     }
367     
368     return length;
369 }
370
371
372
373 static int pci_reset_device(struct vm_device * dev) {
374     PrintDebug("pci: reset device\n");    
375     return 0;
376 }
377
378
379 static int pci_start_device(struct vm_device * dev) {
380     PrintDebug("pci: start device\n");
381     return 0;
382 }
383
384
385 static int pci_stop_device(struct vm_device * dev) {
386     PrintDebug("pci: stop device\n");  
387     return 0;
388 }
389
390
391
392 static int pci_deinit_device(struct vm_device * dev) {
393     int i = 0;
394     
395     for (i = 0; i < 4; i++){
396         v3_dev_unhook_io(dev, CONFIG_ADDR_PORT + i);
397         v3_dev_unhook_io(dev, CONFIG_DATA_PORT + i);
398     }
399     
400     return 0;
401 }
402
403
404
405
406 static int init_i440fx(struct vm_device * dev) {
407     struct pci_device * pci_dev = v3_pci_register_device(dev, 0, "i440FX", 0, 
408                                                          NULL, NULL);
409     
410     if (!pci_dev) {
411         return -1;
412     }
413     
414     pci_dev->config_header.vendor_id = 0x8086;
415     pci_dev->config_header.device_id = 0x1237;
416     pci_dev->config_header.revision = 0x0002;
417     pci_dev->config_header.subclass = 0x00; //  SubClass: host2pci
418     pci_dev->config_header.class = 0x06;    // Class: PCI bridge
419     pci_dev->config_header.header_type = 0x00;
420
421     pci_dev->bus_num = 0;
422     
423     return 0;
424 }
425
426
427
428 static void init_pci_busses(struct pci_internal * pci_state) {
429     int i;
430
431     for (i = 0; i < PCI_BUS_COUNT; i++) {
432         pci_state->bus_list[i].bus_num = i;
433         pci_state->bus_list[i].devices.rb_node = NULL;
434         memset(pci_state->bus_list[i].dev_map, 0, sizeof(pci_state->bus_list[i].dev_map));
435     }
436 }
437
438
439
440 static int pci_init_device(struct vm_device * dev) {
441     struct pci_internal * pci_state = (struct pci_internal *)dev->private_data;;
442     int i = 0;
443     
444     PrintDebug("pci: init_device\n");
445
446     // JRL: Fix this....
447     //    dev->vm->pci = dev;   //should be in vmm_config.c
448     
449     pci_state->addr_reg.val = 0; 
450
451     init_pci_busses(pci_state);
452
453     if (init_i440fx(dev) == -1) {
454         PrintError("Could not intialize i440fx\n");
455         return -1;
456     }
457     
458     for (i = 0; i < 4; i++) {
459         v3_dev_hook_io(dev, CONFIG_ADDR_PORT + i, &addr_port_read, &addr_port_write);
460         v3_dev_hook_io(dev, CONFIG_DATA_PORT + i, &data_port_read, &data_port_write);
461     }
462
463     return 0;
464 }
465
466
467 static struct vm_device_ops dev_ops = {
468     .init = pci_init_device, 
469     .deinit = pci_deinit_device,
470     .reset = pci_reset_device,
471     .start = pci_start_device,
472     .stop = pci_stop_device,
473 };
474
475
476 struct vm_device * v3_create_pci() {
477     struct pci_internal * pci_state = V3_Malloc(sizeof(struct pci_internal));
478     
479     PrintDebug("PCI internal at %p\n",(void *)pci_state);
480     
481     struct vm_device * device = v3_create_device("PCI", &dev_ops, pci_state);
482     
483     return device;
484 }
485
486
487
488
489
490 // if dev_num == -1, auto assign 
491 struct pci_device * v3_pci_register_device(struct vm_device * pci,
492                                            uint_t bus_num,
493                                            const char * name,
494                                            int dev_num,
495                                            int (*config_update)(struct pci_device * pci_dev, uint_t reg_num, int length),
496                                            void * private_data) {
497
498     struct pci_internal * pci_state = (struct pci_internal *)pci->private_data;
499     struct pci_bus * bus = &(pci_state->bus_list[bus_num]);
500     struct pci_device * pci_dev = NULL;
501
502     if (dev_num > MAX_BUS_DEVICES) {
503         PrintError("Requested Invalid device number (%d)\n", dev_num);
504         return NULL;
505     }
506
507     if (dev_num == -1) {
508         if ((dev_num = get_free_dev_num(bus)) == -1) {
509             PrintError("No more available PCI slots on bus %d\n", bus->bus_num);
510             return NULL;
511         }
512     }
513     
514     if (get_device(bus, dev_num) != NULL) {
515         PrintError("PCI Device already registered at slot %d on bus %d\n", 
516                    dev_num, bus->bus_num);
517         return NULL;
518     }
519
520     
521     pci_dev = (struct pci_device *)V3_Malloc(sizeof(struct pci_device));
522
523     if (pci_dev == NULL) {
524         return NULL;
525     }
526
527     memset(pci_dev, 0, sizeof(struct pci_device));
528         
529     
530     pci_dev->bus_num = bus_num;
531     pci_dev->dev_num = dev_num;
532
533     strncpy(pci_dev->name, name, sizeof(pci_dev->name));
534     pci_dev->vm_dev = pci;
535
536     pci_dev->config_update = config_update;
537
538     pci_dev->priv_data = private_data;
539
540     // add the device
541     add_device_to_bus(bus, pci_dev);
542     
543 #ifdef DEBUG_PCI
544     pci_dump_state(pci_state);
545 #endif
546
547     return pci_dev;
548 }
549
550
551