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.


added writable register list
[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         for (i = 0; i < length; i++) {
301             *((uint8_t *)dst + i) = 0xff;
302         }
303
304         return length;
305     }
306
307     for (i = 0; i < length; i++) {
308         *((uint8_t *)dst + i) = pci_dev->config_space[reg_num + i];
309     }
310     
311     return length;
312 }
313
314
315 static inline int is_cfg_reg_writable(uchar_t header_type, int reg_num) {
316     if (header_type == 0x00) {
317         switch (reg_num) {
318             case 0x00:
319             case 0x01:
320             case 0x02:
321             case 0x03:
322             case 0x08:
323             case 0x09:
324             case 0x0a:
325             case 0x0b:
326             case 0x0e:
327             case 0x3d:
328                 return 0;
329                            
330            default:
331                return 1;
332  
333             // case (non writable reg list):
334             
335             default:
336                 return 1;
337         }
338     } else {
339         // PCI to PCI Bridge = 0x01
340         // CardBus Bridge = 0x02
341
342         // huh?
343         PrintError("Invalid PCI Header type (0x%.2x)\n", header_type);
344
345         return -1;
346     }
347 }
348
349
350 static int data_port_write(ushort_t port, void * src, uint_t length, struct vm_device * vmdev) {
351     struct pci_internal * pci_state = (struct pci_internal *)vmdev->private_data;
352     struct pci_device * pci_dev = NULL;
353     uint_t reg_num = pci_state->addr_reg.reg_num + (port & 0x3);
354     int i;
355
356     PrintDebug("Writing PCI Data register. bus = %d, dev = %d, reg = %d (%x) addr_reg = %x\n", 
357                pci_state->addr_reg.bus_num, 
358                pci_state->addr_reg.dev_num, 
359                reg_num, reg_num, 
360                pci_state->addr_reg.val);
361
362
363     pci_dev = get_device(&(pci_state->bus_list[0]), pci_state->addr_reg.dev_num);
364     
365     if (pci_dev == NULL) {
366         PrintError("Writing configuration space for non-present device (dev_num=%d)\n", 
367                    pci_state->addr_reg.dev_num); 
368         return -1;
369     }
370     
371
372     for (i = 0; i < length; i++) {
373         uint_t cur_reg = reg_num + i;
374         
375         if (is_cfg_reg_writable(pci_dev->config_header.header_type, cur_reg)) {
376             pci_dev->config_space[cur_reg] = *((uint8_t *)src + i);
377
378             if ((cur_reg >= 0x10) && (cur_reg < 0x28)) {
379                 // BAR Reg
380                 int bar_reg = (cur_reg & ~0x3) - 0x10;
381
382                 if (pci_dev->bar[bar_reg].bar_update) {
383                     pci_dev->bar_update_flag = 1;               
384                     pci_dev->bar[bar_reg].updated = 1;
385                 }
386             } else if ((cur_reg >= 0x30) && (cur_reg < 0x34)) {
387                 pci_dev->ext_rom_updated = 1;
388             } else if ((cur_reg == 0x04) || (cur_reg == 0x05)) {
389                 // COMMAND update
390             } else if (cur_reg == 0x0f) {
391                 // BIST update
392                 pci_dev->config_header.BIST = 0x00;
393             }
394         }
395     }
396
397     if (pci_dev->config_update) {
398         pci_dev->config_update(pci_dev, reg_num, length);
399     }
400
401     // Scan for BAR updated
402     if (pci_dev->bar_update_flag) {
403         for (i = 0; i < 6; i++) {
404             if (pci_dev->bar[i].updated) {
405                 int bar_offset = 0x10 + 4 * i;
406
407                 *(uint32_t *)pci_dev->config_space + bar_offset) &= pci_dev->bar[i].mask;
408
409                 if (pci_dev->bar[i].bar_update) {
410                     pci_dev->bar[i].bar_update(pci_dev, i);
411                 }
412                 pci_dev->bar[i].updated = 0;
413             }
414         }
415         pci_dev->bar_update_flag = 0;
416     }
417
418     if ((pci_dev->ext_rom_update_flag) && (pci_dev->ext_rom_update)) {
419         pci_dev->ext_rom_update(pci_dev);
420         pci_dev->ext_rom_update_flag = 0;
421     }
422
423
424     return length;
425 }
426
427
428
429 static int pci_reset_device(struct vm_device * dev) {
430     PrintDebug("pci: reset device\n");    
431     return 0;
432 }
433
434
435 static int pci_start_device(struct vm_device * dev) {
436     PrintDebug("pci: start device\n");
437     return 0;
438 }
439
440
441 static int pci_stop_device(struct vm_device * dev) {
442     PrintDebug("pci: stop device\n");  
443     return 0;
444 }
445
446
447
448 static int pci_deinit_device(struct vm_device * dev) {
449     int i = 0;
450     
451     for (i = 0; i < 4; i++){
452         v3_dev_unhook_io(dev, CONFIG_ADDR_PORT + i);
453         v3_dev_unhook_io(dev, CONFIG_DATA_PORT + i);
454     }
455     
456     return 0;
457 }
458
459
460
461
462 static int init_i440fx(struct vm_device * dev) {
463     struct pci_device * pci_dev = v3_pci_register_device(dev, 0, "i440FX", 0, 
464                                                          NULL, NULL, NULL);
465     
466     if (!pci_dev) {
467         return -1;
468     }
469     
470     pci_dev->config_header.vendor_id = 0x8086;
471     pci_dev->config_header.device_id = 0x1237;
472     pci_dev->config_header.revision = 0x0002;
473     pci_dev->config_header.subclass = 0x00; //  SubClass: host2pci
474     pci_dev->config_header.class = 0x06;    // Class: PCI bridge
475     pci_dev->config_header.header_type = 0x00;
476
477     pci_dev->bus_num = 0;
478     
479     return 0;
480 }
481
482
483
484 static void init_pci_busses(struct pci_internal * pci_state) {
485     int i;
486
487     for (i = 0; i < PCI_BUS_COUNT; i++) {
488         pci_state->bus_list[i].bus_num = i;
489         pci_state->bus_list[i].devices.rb_node = NULL;
490         memset(pci_state->bus_list[i].dev_map, 0, sizeof(pci_state->bus_list[i].dev_map));
491     }
492 }
493
494
495
496 static int pci_init_device(struct vm_device * dev) {
497     struct pci_internal * pci_state = (struct pci_internal *)dev->private_data;;
498     int i = 0;
499     
500     PrintDebug("pci: init_device\n");
501
502     // JRL: Fix this....
503     //    dev->vm->pci = dev;   //should be in vmm_config.c
504     
505     pci_state->addr_reg.val = 0; 
506
507     init_pci_busses(pci_state);
508
509     if (init_i440fx(dev) == -1) {
510         PrintError("Could not intialize i440fx\n");
511         return -1;
512     }
513
514     PrintDebug("Sizeof config header=%d\n", sizeof(struct pci_config_header));
515     
516     for (i = 0; i < 4; i++) {
517         v3_dev_hook_io(dev, CONFIG_ADDR_PORT + i, &addr_port_read, &addr_port_write);
518         v3_dev_hook_io(dev, CONFIG_DATA_PORT + i, &data_port_read, &data_port_write);
519     }
520
521     return 0;
522 }
523
524
525 static struct vm_device_ops dev_ops = {
526     .init = pci_init_device, 
527     .deinit = pci_deinit_device,
528     .reset = pci_reset_device,
529     .start = pci_start_device,
530     .stop = pci_stop_device,
531 };
532
533
534 struct vm_device * v3_create_pci() {
535     struct pci_internal * pci_state = V3_Malloc(sizeof(struct pci_internal));
536     
537     PrintDebug("PCI internal at %p\n",(void *)pci_state);
538     
539     struct vm_device * device = v3_create_device("PCI", &dev_ops, pci_state);
540     
541     return device;
542 }
543
544
545
546 static inline int init_bars(struct pci_device * pci_dev) {
547     int i = 0;
548
549     for (i = 0; i < 6; i++) {
550         int bar_offset = 0x10 + 4 * i;
551
552         if (pci_dev->bar[i].type == PCI_BAR_IO) {
553             *(uint32_t *)(pci_dev->config_space + bar_offset) = 0x00000001;
554         } else if (pci_dev->bar[i].type == PCI_BAR_MEM32) {
555             pci_dev->bar[i].mask = (pci_dev->bar[i].num_pages << 12) - 1;
556             pci_dev->bar[i].mask |= 0xf; // preserve the configuration flags
557              
558             *(uint32_t *)(pci_dev->config_space + bar_offset) = 0x00000008;
559             
560             if (pci_dev->bar[i].mem_hook) {
561                 // clear the prefetchable flag...
562                 *(uint8_t *)(pci_dev->config_space + bar_offset) &= ~0x00000008;
563             }
564         } else if (pci_dev->bar[i].type == PCI_BAR_MEM16) {
565             PrintError("16 Bit memory ranges not supported (reg: %d)\n", i);
566         } else if (pci_dev->bar[i].type == PCI_BAR_NONE) {
567             *(uint32_t *)(pci_dev->config_space + bar_offset) = 0x00000000;
568         } else {
569             PrintError("Invalid BAR type for bar #%d\n", i);
570             return -1;
571         }
572             
573
574     }
575 }
576
577
578
579 // if dev_num == -1, auto assign 
580 struct pci_device * v3_pci_register_device(struct vm_device * pci,
581                                            uint_t bus_num,
582                                            const char * name,
583                                            int dev_num,
584                                            struct v3_pci_bar * bars,
585                                            int (*config_update)(struct pci_device * pci_dev, uint_t reg_num, int length),
586                                            int (*cmd_update)(struct pci_dev *pci_dev, uchar_t io_enabled, uchar_t mem_enabled),
587                                            int (*bar_update)(struct pci_device * pci_dev, uint_t bar),
588                                            void * private_data) {
589
590     struct pci_internal * pci_state = (struct pci_internal *)pci->private_data;
591     struct pci_bus * bus = &(pci_state->bus_list[bus_num]);
592     struct pci_device * pci_dev = NULL;
593     int i;
594
595     if (dev_num > MAX_BUS_DEVICES) {
596         PrintError("Requested Invalid device number (%d)\n", dev_num);
597         return NULL;
598     }
599
600     if (dev_num == -1) {
601         if ((dev_num = get_free_dev_num(bus)) == -1) {
602             PrintError("No more available PCI slots on bus %d\n", bus->bus_num);
603             return NULL;
604         }
605     }
606     
607     if (get_device(bus, dev_num) != NULL) {
608         PrintError("PCI Device already registered at slot %d on bus %d\n", 
609                    dev_num, bus->bus_num);
610         return NULL;
611     }
612
613     
614     pci_dev = (struct pci_device *)V3_Malloc(sizeof(struct pci_device));
615
616     if (pci_dev == NULL) {
617         return NULL;
618     }
619
620     memset(pci_dev, 0, sizeof(struct pci_device));
621     
622     
623     pci_dev->bus_num = bus_num;
624     pci_dev->dev_num = dev_num;
625
626     strncpy(pci_dev->name, name, sizeof(pci_dev->name));
627     pci_dev->vm_dev = pci;
628
629     // register update callbacks
630     pci_dev->config_update = config_update;
631     pci_dev->bar_update = bar_update;
632
633     pci_dev->priv_data = private_data;
634
635     
636     //copy bars
637     for (i = 0; i < 6; i ++){
638       pci_dev->bar[i].type = bars[i].type;
639       pci_dev->bar[i].num_resources = bars[i].num_resources;
640       pci_dev->bar[i].bar_update = bars[i].bar_update;
641     }
642
643     if (init_bars(pci_dev) == -1) {
644         PrintError("could not initialize bar registers\n");
645         return NULL;
646     }
647
648     pci_dev->cmd_update = cmd_update;
649     pci_dev->ext_rom_update = ext_rom_update;
650
651     // add the device
652     add_device_to_bus(bus, pci_dev);
653
654     
655 #ifdef DEBUG_PCI
656     pci_dump_state(pci_state);
657 #endif
658
659     return pci_dev;
660 }
661
662
663