1 // MPTable generation (on emulators)
2 // DO NOT ADD NEW FEATURES HERE. (See paravirt.c / biostables.c instead.)
3 //
4 // Copyright (C) 2008-2010 Kevin O'Connor <kevin@koconnor.net>
5 // Copyright (C) 2006 Fabrice Bellard
6 //
7 // This file may be distributed under the terms of the GNU LGPLv3 license.
8
9 #include "config.h" // CONFIG_*
10 #include "hw/pci.h" // pci_bdf_to_bus
11 #include "hw/pcidevice.h" // foreachpci
12 #include "hw/pci_regs.h" // PCI_INTERRUPT_PIN
13 #include "malloc.h" // free
14 #include "output.h" // dprintf
15 #include "romfile.h" // romfile_loadint
16 #include "std/mptable.h" // MPTABLE_SIGNATURE
17 #include "string.h" // memset
18 #include "util.h" // MaxCountCPUs
19 #include "x86.h" // cpuid
20
21 void
mptable_setup(void)22 mptable_setup(void)
23 {
24 if (! CONFIG_MPTABLE)
25 return;
26
27 dprintf(3, "init MPTable\n");
28
29 // Config structure in temp area.
30 struct mptable_config_s *config = malloc_tmp(32*1024);
31 if (!config) {
32 warn_noalloc();
33 return;
34 }
35 memset(config, 0, sizeof(*config));
36 config->signature = MPCONFIG_SIGNATURE;
37 config->spec = 4;
38 memcpy(config->oemid, BUILD_CPUNAME8, sizeof(config->oemid));
39 memcpy(config->productid, "0.1 ", sizeof(config->productid));
40 config->lapic = BUILD_APIC_ADDR;
41
42 // Detect cpu info
43 u32 cpuid_signature, ebx, ecx, cpuid_features;
44 cpuid(1, &cpuid_signature, &ebx, &ecx, &cpuid_features);
45 if (! cpuid_signature) {
46 // Use default values.
47 cpuid_signature = 0x600;
48 cpuid_features = 0x201;
49 }
50 int pkgcpus = 1;
51 if (cpuid_features & (1 << 28)) {
52 /* Only populate the MPS tables with the first logical CPU in
53 each package */
54 pkgcpus = (ebx >> 16) & 0xff;
55 pkgcpus = 1 << (__fls(pkgcpus - 1) + 1); /* round up to power of 2 */
56 }
57 u8 apic_version = readl((u8*)BUILD_APIC_ADDR + 0x30) & 0xff;
58
59 // CPU definitions.
60 struct mpt_cpu *cpus = (void*)&config[1], *cpu = cpus;
61 int i;
62 for (i = 0; i < MaxCountCPUs; i+=pkgcpus) {
63 memset(cpu, 0, sizeof(*cpu));
64 cpu->type = MPT_TYPE_CPU;
65 cpu->apicid = i;
66 cpu->apicver = apic_version;
67 /* cpu flags: enabled, bootstrap cpu */
68 cpu->cpuflag = (apic_id_is_present(i) ? 0x01 : 0x00) | ((i==0) ? 0x02 : 0x00);
69 cpu->cpusignature = cpuid_signature;
70 cpu->featureflag = cpuid_features;
71 cpu++;
72 }
73 int entrycount = cpu - cpus;
74
75 // PCI bus
76 struct mpt_bus *buses = (void*)cpu, *bus = buses;
77 if (!hlist_empty(&PCIDevices)) {
78 memset(bus, 0, sizeof(*bus));
79 bus->type = MPT_TYPE_BUS;
80 bus->busid = 0;
81 memcpy(bus->bustype, "PCI ", sizeof(bus->bustype));
82 bus++;
83 entrycount++;
84 }
85
86 /* isa bus */
87 int isabusid = bus - buses;
88 memset(bus, 0, sizeof(*bus));
89 bus->type = MPT_TYPE_BUS;
90 bus->busid = isabusid;
91 memcpy(bus->bustype, "ISA ", sizeof(bus->bustype));
92 bus++;
93 entrycount++;
94
95 /* ioapic */
96 u8 ioapic_id = BUILD_IOAPIC_ID;
97 struct mpt_ioapic *ioapic = (void*)bus;
98 memset(ioapic, 0, sizeof(*ioapic));
99 ioapic->type = MPT_TYPE_IOAPIC;
100 ioapic->apicid = ioapic_id;
101 ioapic->apicver = 0x11;
102 ioapic->flags = 1; // enable
103 ioapic->apicaddr = BUILD_IOAPIC_ADDR;
104 entrycount++;
105
106 /* irqs */
107 struct mpt_intsrc *intsrcs = (void*)&ioapic[1], *intsrc = intsrcs;
108 int dev = -1;
109 unsigned short pinmask = 0;
110
111 struct pci_device *pci;
112 foreachpci(pci) {
113 u16 bdf = pci->bdf;
114 if (pci_bdf_to_bus(bdf) != 0)
115 break;
116 int pin = pci_config_readb(bdf, PCI_INTERRUPT_PIN);
117 int irq = pci_config_readb(bdf, PCI_INTERRUPT_LINE);
118 if (pin == 0)
119 continue;
120 if (dev != pci_bdf_to_busdev(bdf)) {
121 dev = pci_bdf_to_busdev(bdf);
122 pinmask = 0;
123 }
124 if (pinmask & (1 << pin)) /* pin was seen already */
125 continue;
126 pinmask |= (1 << pin);
127 memset(intsrc, 0, sizeof(*intsrc));
128 intsrc->type = MPT_TYPE_INTSRC;
129 intsrc->irqtype = 0; /* INT */
130 intsrc->irqflag = 1; /* active high */
131 intsrc->srcbus = pci_bdf_to_bus(bdf); /* PCI bus */
132 intsrc->srcbusirq = (pci_bdf_to_dev(bdf) << 2) | (pin - 1);
133 intsrc->dstapic = ioapic_id;
134 intsrc->dstirq = irq;
135 intsrc++;
136 }
137
138 int irq0_override = romfile_loadint("etc/irq0-override", 0);
139 for (i = 0; i < 16; i++) {
140 memset(intsrc, 0, sizeof(*intsrc));
141 if (BUILD_PCI_IRQS & (1 << i))
142 continue;
143 intsrc->type = MPT_TYPE_INTSRC;
144 intsrc->irqtype = 0; /* INT */
145 intsrc->irqflag = 0; /* conform to bus spec */
146 intsrc->srcbus = isabusid; /* ISA bus */
147 intsrc->srcbusirq = i;
148 intsrc->dstapic = ioapic_id;
149 intsrc->dstirq = i;
150 if (irq0_override) {
151 /* Destination 2 is covered by irq0->inti2 override (i ==
152 0). Source IRQ 2 is unused */
153 if (i == 0)
154 intsrc->dstirq = 2;
155 else if (i == 2)
156 intsrc--;
157 }
158 intsrc++;
159 }
160
161 /* Local interrupt assignment */
162 intsrc->type = MPT_TYPE_LOCAL_INT;
163 intsrc->irqtype = 3; /* ExtINT */
164 intsrc->irqflag = 0; /* PO, EL default */
165 intsrc->srcbus = isabusid; /* ISA */
166 intsrc->srcbusirq = 0;
167 intsrc->dstapic = 0; /* BSP == APIC #0 */
168 intsrc->dstirq = 0; /* LINTIN0 */
169 intsrc++;
170
171 intsrc->type = MPT_TYPE_LOCAL_INT;
172 intsrc->irqtype = 1; /* NMI */
173 intsrc->irqflag = 0; /* PO, EL default */
174 intsrc->srcbus = isabusid; /* ISA */
175 intsrc->srcbusirq = 0;
176 intsrc->dstapic = 0xff; /* to all local APICs */
177 intsrc->dstirq = 1; /* LINTIN1 */
178 intsrc++;
179 entrycount += intsrc - intsrcs;
180
181 // Finalize config structure.
182 int length = (void*)intsrc - (void*)config;
183 config->entrycount = entrycount;
184 config->length = length;
185 config->checksum -= checksum(config, length);
186
187 // floating pointer structure
188 struct mptable_floating_s floating;
189 memset(&floating, 0, sizeof(floating));
190 floating.signature = MPTABLE_SIGNATURE;
191 floating.physaddr = (u32)config;
192 floating.length = 1;
193 floating.spec_rev = 4;
194 floating.checksum -= checksum(&floating, sizeof(floating));
195 copy_mptable(&floating);
196 free(config);
197 }
198