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.


reworked PCI bus implmentation -- moved to mask based implementation -- added capabil...
[palacios.git] / palacios / src / devices / piix3.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, Jack Lange <jarusl@cs.northwestern.edu>
11  * Copyright (c) 2009, The V3VEE Project <http://www.v3vee.org> 
12  * All rights reserved.
13  *
14  * Author: Jack Lange <jarusl@cs.northwestern.edu>
15  *
16  * This is free software.  You are permitted to use,
17  * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
18  */ 
19  
20
21 #include <palacios/vmm.h>
22 #include <palacios/vmm_dev_mgr.h>
23 #include <palacios/vmm_intr.h>
24
25 #include <devices/pci.h>
26 #include <devices/southbridge.h>
27
28
29 struct iort_reg {
30     union {
31         uint8_t value;
32         struct {
33             uint8_t times_16bit   : 2;
34             uint8_t enable_16bit  : 1;
35             uint8_t times_8bit    : 3;
36             uint8_t enable_8bit   : 1;
37             uint8_t dmaac         : 1;
38         } __attribute__((packed));
39     } __attribute__((packed));
40 } __attribute__((packed));
41
42 struct xbcs_reg {
43     union {
44         uint16_t value;
45         struct {
46             uint8_t rtc_addr_en        : 1;
47             uint8_t kb_ctrl_en         : 1;
48             uint8_t bioscs_wprot_en    : 1;
49             uint8_t rsvd1              : 1;
50             uint8_t irq12_mouse_fn_en  : 1;
51             uint8_t coproc_err_fn_en   : 1;
52             uint8_t lower_bios_en      : 1;
53             uint8_t ext_bios_en        : 1;
54             uint8_t apic_chip_sel      : 1;
55             uint8_t piix_rsvd          : 7;
56         } __attribute__((packed));
57     } __attribute__((packed));
58 } __attribute__((packed));
59
60
61 struct pirq_route_ctrl_req {
62     union {
63         uint8_t value;
64         struct {
65             uint8_t irq_routing        : 4;
66             uint8_t rsvd               : 3;
67             uint8_t irq_route_en       : 1;
68         } __attribute__((packed));
69     } __attribute__((packed));
70 } __attribute__((packed));
71
72 struct top_of_mem_reg {
73     union {
74         uint8_t value;
75         struct {
76             uint8_t rsvd1                    : 1;
77     uint8_t isadma_reg_fwd_en        : 1;
78             uint8_t piix_rsvd                : 1;
79             uint8_t isadma_lo_bios_fwd_en    : 1;
80             uint8_t top_of_mem               : 4;
81         } __attribute__((packed));
82     } __attribute__((packed));
83 } __attribute__((packed));
84
85 // Miscellaneous Status register
86 struct misc_stat_reg {
87     union {
88         uint16_t value;
89         struct {
90             uint8_t isa_clk_div              : 1;
91             uint8_t piix_rsvd1               : 1;
92             uint8_t pci_hdr_type_en          : 1;
93             uint8_t rsvd1                    : 1;
94             uint8_t usb_en                   : 1;
95             uint8_t rsvd2                    : 1;
96             uint8_t ext_sm_mode_en           : 1;
97             uint8_t nb_retry_en              : 1;
98             uint8_t rsvd3                    : 7;
99             uint8_t serr_gen_delayed_tranx   : 1;
100         } __attribute__((packed));
101     } __attribute__((packed));
102 } __attribute__((packed));
103
104
105
106 // Motherboard Device IRQ route control register
107 struct mb_irq_ctrl_reg {
108     union {
109         uint8_t value;
110         struct {
111             uint8_t irq_routing              : 4;
112             uint8_t rsvd                     : 1;
113             uint8_t irq0_en                  : 1;
114             uint8_t irq_sharing_en           : 1;
115             uint8_t irq_routing_en           : 1;
116         } __attribute__((packed));
117     } __attribute__((packed));
118 } __attribute__((packed));
119
120 // Motherboard Device DMA control register
121 struct mb_dma_ctrl_reg {
122     union {
123         uint8_t value;
124         struct {
125             uint8_t type_f_dma_routing       : 3;
126             uint8_t piix_rsvd                : 1;
127             uint8_t rsvd                     : 3;
128             uint8_t type_f_dma_buf_en        : 1;
129         } __attribute__((packed));
130     } __attribute__((packed));
131 } __attribute__((packed));
132
133
134 // Programmable Chip Select Control Register
135 struct prg_chip_sel_ctrl_reg {
136     union {
137         uint16_t value;
138         struct {
139             uint8_t pcs_addr_mask            : 2;
140             uint16_t pcs_addr                : 14;
141         } __attribute__((packed));
142     } __attribute__((packed));
143 } __attribute__((packed));
144
145
146 // APIC base address relocation register
147 struct apic_base_addr_reg {
148     union {
149         uint8_t value;
150         struct {
151             uint8_t y_base_addr             : 2;
152             uint8_t x_base_addr             : 4;
153             uint8_t a12_mask                : 1;
154             uint8_t rsvd                    : 1;
155         } __attribute__((packed));
156     } __attribute__((packed));
157 } __attribute__((packed));
158
159
160 // Deterministic Latency control register
161 struct deter_lat_ctrl_reg {
162     union {
163         uint8_t value;
164         struct {
165             uint8_t delayed_trans_en        : 1;
166             uint8_t pass_release_en         : 1;
167             uint8_t usb_pass_release_en     : 1;
168             uint8_t serr_gen_trans_tmout_en : 1;
169             uint8_t rsvd                    : 4;
170         } __attribute__((packed));
171     } __attribute__((packed));
172 } __attribute__((packed));
173
174 // SMI Control Register
175 struct smi_ctrl_reg {
176     union {
177         uint8_t value;
178         struct {
179             uint8_t smi_gate               : 1;
180             uint8_t stpclk_sig_en          : 1;
181             uint8_t stpclk_scaling_en      : 1;
182             uint8_t fast_off_tmr_freeze    : 2;
183             uint8_t rsvd                   : 3;
184         } __attribute__((packed));
185     } __attribute__((packed));
186 } __attribute__((packed));
187
188 // SMI Enable register
189 struct smi_enable_reg {
190     union {
191         uint16_t value;
192         struct {
193             uint8_t irq1_smi_en            : 1; // (keyboard irq)
194             uint8_t irq3_smi_en            : 1; // (COM1/COM3/Mouse irq)
195             uint8_t irq4_smi_en            : 1; // (COM2/COM4/Mouse irq)
196             uint8_t irq8_smi_en            : 1; // (RTC irq)
197             uint8_t irq12_smi_en           : 1; // (PS/2 mouse irq)
198             uint8_t fast_off_tmr_en        : 1;
199             uint8_t ext_smi_en             : 1;
200             uint8_t apic_wr_smi_en         : 1;
201             uint8_t legacy_usb_smi_en      : 1;
202             uint8_t rsvd                   : 7;
203         } __attribute__((packed));
204     } __attribute__((packed));
205 } __attribute__((packed));
206
207
208 // System Event Enable register
209 struct sys_evt_en_reg {
210     union {
211         uint32_t value;
212         struct {
213             uint8_t firq0_en               : 1;
214             uint8_t firq1_en               : 1;
215             uint8_t rsvd1                  : 1;
216             uint8_t firq3_en               : 1;
217             uint8_t firq4_en               : 1;
218             uint8_t firq5_en               : 1;
219             uint8_t firq6_en               : 1;
220             uint8_t firq7_en               : 1;
221             uint8_t firq8_en               : 1;
222             uint8_t firq9_en               : 1;
223             uint8_t firq10_en              : 1;
224             uint8_t firq11_en              : 1;
225             uint8_t firq12_en              : 1;
226             uint8_t firq13_en              : 1;
227             uint8_t firq14_en              : 1;
228             uint8_t firq15_en              : 1;
229             uint16_t rsvd2                 : 12;
230             uint8_t fast_off_apic_en       : 1;
231             uint8_t fast_off_nmi_en        : 1;
232             uint8_t intr_en                : 1;
233             uint8_t fast_off_smi_en        : 1;
234         } __attribute__((packed));
235     } __attribute__((packed));
236 } __attribute__((packed));
237
238
239 // SMI Request Register
240 struct smi_req_reg {
241     union {
242         uint16_t value;
243         struct {
244             uint8_t irq1_req_smi_stat      : 1;
245             uint8_t irq3_req_smi_stat      : 1;
246             uint8_t irq4_req_smi_stat      : 1;
247             uint8_t irq8_req_smi_stat      : 1;
248             uint8_t irq12_req_smi_stat     : 1;
249             uint8_t fast_off_tmr_exp_stat  : 1;
250             uint8_t extsmi_stat            : 1;
251             uint8_t apm_smi_stat           : 1;
252             uint8_t legacy_usb_smi_stat    : 1;
253             uint8_t rsvd                   : 7;
254         } __attribute__((packed));
255     } __attribute__((packed));
256 } __attribute__((packed));
257
258
259 struct piix3_config_space {
260     uint8_t rsvd1[12];            // 0x40 - 0x4b
261
262     // ISA I/O Recovery timer register
263     uint8_t iort;                 // 0x4c        (default 0x4d)
264     uint8_t rsvd2;                // 0x4d
265
266     // X-Bus Chip select register
267     uint16_t xbcs;                // 0x4e - 0x4f (default: 0x03)
268     uint8_t rsvd3[16];            // 0x50 - 0x5f
269
270     // pirq route control register (IRQs A-D)
271     uint8_t pirq_rc[4];           // 0x60 - 0x63 (default: 0x80) 
272     uint8_t rsvd4[5];             // 0x64 - 0x68
273
274     // top of memory register
275     uint8_t top_of_mem;           // 0x69        (default: 0x02)
276
277     // Miscellaneous status register
278     uint16_t mstat;               // 0x6A - 0x6B (default: undefined)
279     uint8_t rsvd5[4];             // 0x6c - 0x6f
280
281     // Motherboard device IRQ route control register
282     uint8_t mbirq0;                // 0x70        (default: 0x80)
283     uint8_t rsvd6;                 // 0x71 (piix only)
284     uint8_t rsvd7[4];              // 0x72 - 0x75
285
286     // Motherboard Device DMA Control registers
287     uint8_t mbdma0;                // 0x76        (default: 0x0c)
288     uint8_t mbdma1;                // 0x77        (default: 0x0c)
289
290     // Programmable Chip Select Control Register  
291     uint16_t pcsc;                 // 0x78 - 0x79 (default: 0x0002)
292     uint8_t rsvd8[6];              // 0x7A - 0x7F
293
294     // APIC base address relocation register
295     uint8_t apicbase;              // 0x80        (default: 0x00)
296     uint8_t rsvd9;                 // 0x81
297
298
299     // Deterministic Latency control register
300     uint8_t dlc;                   // 0x82        (default: 0x00)
301     uint8_t rsvd10[29];            // 0x83 - 0x9f
302
303
304     // SMI Control Register
305     uint8_t smicntl;               // 0xa0        (default: 0x08)
306     uint8_t rsvd11;                // 0xa1
307
308     // SMI Enable register
309     uint16_t smien;                // 0xa2 - 0xa3 (default: 0x0000)
310
311     // System Event Enable register
312     uint32_t see;                  // 0xa4 - 0xa7 (default: 0x00000000)
313
314     // Fast off timer register
315     uint8_t ftmr;                  // 0xa8        (default: 0x0f)
316     uint8_t rsvd12;                // 0xa9
317
318     // SMI Request Register
319     uint16_t smireq;               // 0xaa - 0xab (default: 0x0000)
320
321     // Clock Scale stpclk low timer
322     uint8_t ctltmr;                // 0xac        (default: 0x00)
323     uint8_t rsvd13;                // 0xad
324
325     // Slock Scale STPCLK high timer
326     uint8_t cthtmr;                // 0xae        (default: 0x00)
327
328 } __attribute__((packed));
329
330
331
332 static int reset_piix3(struct v3_southbridge * piix3) {
333     struct pci_device * pci_dev = piix3->southbridge_pci;
334     struct piix3_config_space * piix3_cfg = (struct piix3_config_space *)(pci_dev->config_data);
335
336     pci_dev->config_header.command = 0x0007; // master, memory and I/O
337     pci_dev->config_header.status = 0x0200;
338
339     piix3_cfg->iort = 0x4d;
340     piix3_cfg->xbcs = 0x0003;
341     piix3_cfg->pirq_rc[0] = 0x80;
342     piix3_cfg->pirq_rc[1] = 0x80;
343     piix3_cfg->pirq_rc[2] = 0x80;
344     piix3_cfg->pirq_rc[3] = 0x80;
345     piix3_cfg->top_of_mem = 0x02;
346     piix3_cfg->mbirq0 = 0x80;
347     piix3_cfg->mbdma0 = 0x0c;
348     piix3_cfg->mbdma1 = 0x0c;
349     piix3_cfg->pcsc = 0x0002;
350     piix3_cfg->apicbase = 0x00;
351     piix3_cfg->dlc = 0x00;
352     piix3_cfg->smicntl = 0x08;
353     piix3_cfg->smien = 0x0000;
354     piix3_cfg->see = 0x00000000;
355     piix3_cfg->ftmr = 0x0f;
356     piix3_cfg->smireq = 0x0000;
357     piix3_cfg->ctltmr = 0x00;
358     piix3_cfg->cthtmr = 0x00;
359
360     return 0;
361 }
362
363
364 //irq is pirq_rc[intr_pin + pci_dev_num - 1] & 0xf
365 /*
366 struct pirq_rc_reg {
367        uint8_t irq         : 4;
368        uint8_t rsvd        : 3;
369        uint8_t disabled    : 1; // (1=disabled, 0=enabled)
370 }
371 */
372
373
374 static int raise_pci_irq(struct pci_device * pci_dev, void * dev_data, struct v3_irq * vec) {
375     struct v3_southbridge * piix3 = dev_data;
376     struct pci_device * piix3_pci = piix3->southbridge_pci;
377     struct piix3_config_space * piix3_cfg = (struct piix3_config_space *)(piix3_pci->config_data);
378     int intr_pin = pci_dev->config_header.intr_pin - 1;
379     int irq_index = (intr_pin + pci_dev->dev_num - 1) & 0x3;
380     struct v3_irq irq; // Make a copy of the irq state because we will switch the irq number
381
382     irq.ack = vec->ack;
383     irq.private_data = vec->private_data;
384
385     /*
386     PrintError("Raising PCI dev %d intr %d via IOAPIC as IRQ %d and via PIRQ as IRQ %d on VM %p\n", 
387                pci_dev->dev_num, pci_dev->config_header.intr_pin, 
388                16+irq_index,
389                piix3_cfg->pirq_rc[irq_index], piix3->vm);
390     */
391
392     // deliver first by PIRQ, if it exists
393     //
394     if (piix3_cfg->pirq_rc[irq_index] < 16) {
395         irq.irq = piix3_cfg->pirq_rc[irq_index] & 0xf;
396
397         //      V3_Print("Raising PIIX IRQ %d\n", irq.irq);
398         v3_raise_acked_irq(piix3->vm, irq);
399     } else {
400       // not an error
401     }
402
403     // deliver next via the PCI0 to ioapic mapping defined in the 
404     // mptable (ioapic, pins 16->19 are used for PCI0)
405     // ideally this would check to verify that an ioapic is actually available
406     irq.irq = (irq_index + 1) + 16;
407     //    V3_Print("Raising PIIX IRQ (#2) %d\n", irq.irq);
408     v3_raise_acked_irq(piix3->vm, irq);
409     
410
411     return 0;
412 }
413
414
415
416 static int lower_pci_irq(struct pci_device * pci_dev, void * dev_data, struct v3_irq * vec) {
417     struct v3_southbridge * piix3 = dev_data;
418     struct pci_device * piix3_pci = piix3->southbridge_pci;
419     struct piix3_config_space * piix3_cfg = (struct piix3_config_space *)(piix3_pci->config_data);
420     int intr_pin = pci_dev->config_header.intr_pin - 1;
421     int irq_index = (intr_pin + pci_dev->dev_num - 1) & 0x3;
422     struct v3_irq irq; // Make a copy of the irq state because we will switch the irq number
423
424     irq.ack = vec->ack;
425     irq.private_data = vec->private_data;
426     //    PrintError("Lowering PCI IRQ %d\n", piix3_cfg->pirq_rc[irq_index]);
427
428     // First, lower the pin on the ioapic
429     irq.irq = (irq_index + 1) + 16;
430     v3_lower_acked_irq(piix3->vm, irq);
431     
432     // Next, lower whatever we asserted by the PIRQs
433     if (piix3_cfg->pirq_rc[irq_index] < 16) {
434         irq.irq = piix3_cfg->pirq_rc[irq_index] & 0xf;
435         v3_lower_acked_irq(piix3->vm, irq);
436     } else {
437       // not an error
438     }
439
440     return 0;
441 }
442
443
444
445 static int piix_free(struct v3_southbridge * piix3) {
446
447     // unregister pci
448
449     V3_Free(piix3);
450     return 0;
451 }
452
453
454 static struct v3_device_ops dev_ops = {
455     .free = (int (*)(void *))piix_free,
456 };
457
458
459
460
461 static int setup_pci(struct v3_southbridge * piix3) {
462     struct pci_device * pci_dev = NULL;
463     struct v3_pci_bar bars[6];
464     int i;
465     int bus_num = 0;
466
467     for (i = 0; i < 6; i++) {
468         bars[i].type = PCI_BAR_NONE;
469     }
470
471     pci_dev = v3_pci_register_device(piix3->pci_bus, PCI_MULTIFUNCTION, 
472                                      bus_num, -1, 0, 
473                                      "PIIX3", bars, 
474                                      NULL, NULL, NULL, NULL, piix3);
475     if (pci_dev == NULL) {
476         PrintError("Could not register PCI Device for PIIX3\n");
477         return -1;
478     }
479
480     pci_dev->config_header.vendor_id = 0x8086;
481     pci_dev->config_header.device_id = 0x7000; // PIIX4 is 0x7001
482     pci_dev->config_header.class = PCI_CLASS_BRIDGE;
483     pci_dev->config_header.subclass = PCI_BRIDGE_SUBCLASS_PCI_ISA; 
484
485     piix3->southbridge_pci = pci_dev;
486
487     v3_pci_set_irq_bridge(piix3->pci_bus, bus_num, raise_pci_irq, lower_pci_irq, piix3);
488
489     reset_piix3(piix3);
490
491     return 0;
492 }
493
494 static int piix3_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
495     struct v3_southbridge * piix3 = (struct v3_southbridge *)V3_Malloc(sizeof(struct v3_southbridge));
496     struct vm_device * dev = NULL;
497     struct vm_device * pci = v3_find_dev(vm, v3_cfg_val(cfg, "bus"));
498     char * dev_id = v3_cfg_val(cfg, "ID");
499
500     if (!pci) {
501         PrintError("Could not find PCI device\n");
502         return -1;
503     }
504
505     piix3->pci_bus = pci;
506     piix3->type = V3_SB_PIIX3;
507     piix3->vm = vm;
508     
509     dev = v3_add_device(vm, dev_id, &dev_ops, piix3);
510
511     if (dev == NULL) {
512         PrintError("Could not attach device %s\n", dev_id);
513         V3_Free(piix3);
514         return -1;
515     }
516
517     PrintDebug("Created PIIX3\n");
518
519     if (setup_pci(piix3) == -1) {
520         v3_remove_device(dev);
521         return -1;
522     }
523
524     return 0;
525 }
526
527
528 device_register("PIIX3", piix3_init)