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