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