Kevin O'Connor | 84ad59a | 2008-07-04 05:47:26 -0400 | [diff] [blame] | 1 | // MPTable generation (on emulators) |
| 2 | // |
Kevin O'Connor | 2929c35 | 2009-07-25 13:48:27 -0400 | [diff] [blame] | 3 | // Copyright (C) 2008,2009 Kevin O'Connor <kevin@koconnor.net> |
Kevin O'Connor | 84ad59a | 2008-07-04 05:47:26 -0400 | [diff] [blame] | 4 | // Copyright (C) 2006 Fabrice Bellard |
| 5 | // |
Kevin O'Connor | b1b7c2a | 2009-01-15 20:52:58 -0500 | [diff] [blame] | 6 | // This file may be distributed under the terms of the GNU LGPLv3 license. |
Kevin O'Connor | 84ad59a | 2008-07-04 05:47:26 -0400 | [diff] [blame] | 7 | |
| 8 | #include "util.h" // dprintf |
Kevin O'Connor | 9521e26 | 2008-07-04 13:04:29 -0400 | [diff] [blame] | 9 | #include "config.h" // CONFIG_* |
Kevin O'Connor | 3574644 | 2009-02-27 20:54:51 -0500 | [diff] [blame] | 10 | #include "mptable.h" // MPTABLE_SIGNATURE |
Kevin O'Connor | 86916ce | 2009-11-14 13:34:27 -0500 | [diff] [blame] | 11 | #include "paravirt.h" // qemu_cfg_irq0_override |
Gleb Natapov | 928d4df | 2009-12-24 14:29:43 +0200 | [diff] [blame] | 12 | #include "pci.h" |
| 13 | #include "pci_regs.h" |
Kevin O'Connor | c0ad0e8 | 2009-11-09 19:20:21 -0500 | [diff] [blame] | 14 | |
Kevin O'Connor | 84ad59a | 2008-07-04 05:47:26 -0400 | [diff] [blame] | 15 | void |
| 16 | mptable_init(void) |
| 17 | { |
Kevin O'Connor | d381702 | 2008-07-12 12:46:07 -0400 | [diff] [blame] | 18 | if (! CONFIG_MPTABLE) |
| 19 | return; |
| 20 | |
Kevin O'Connor | 7b49cd9 | 2008-11-08 10:35:26 -0500 | [diff] [blame] | 21 | dprintf(3, "init MPTable\n"); |
| 22 | |
Kevin O'Connor | 86916ce | 2009-11-14 13:34:27 -0500 | [diff] [blame] | 23 | // Allocate memory |
Kevin O'Connor | 8c8a880 | 2009-07-29 19:44:42 -0400 | [diff] [blame] | 24 | int length = (sizeof(struct mptable_config_s) |
Kevin O'Connor | a26df9b | 2009-10-09 09:42:11 -0400 | [diff] [blame] | 25 | + sizeof(struct mpt_cpu) * MaxCountCPUs |
Gleb Natapov | 928d4df | 2009-12-24 14:29:43 +0200 | [diff] [blame] | 26 | + sizeof(struct mpt_bus) * 2 |
Kevin O'Connor | 3574644 | 2009-02-27 20:54:51 -0500 | [diff] [blame] | 27 | + sizeof(struct mpt_ioapic) |
Gleb Natapov | 928d4df | 2009-12-24 14:29:43 +0200 | [diff] [blame] | 28 | + sizeof(struct mpt_intsrc) * 34); |
Kevin O'Connor | 8c8a880 | 2009-07-29 19:44:42 -0400 | [diff] [blame] | 29 | struct mptable_config_s *config = malloc_fseg(length); |
| 30 | struct mptable_floating_s *floating = malloc_fseg(sizeof(*floating)); |
| 31 | if (!config || !floating) { |
Kevin O'Connor | 3574644 | 2009-02-27 20:54:51 -0500 | [diff] [blame] | 32 | dprintf(1, "No room for MPTABLE!\n"); |
Kevin O'Connor | 86916ce | 2009-11-14 13:34:27 -0500 | [diff] [blame] | 33 | free(config); |
| 34 | free(floating); |
Kevin O'Connor | 3574644 | 2009-02-27 20:54:51 -0500 | [diff] [blame] | 35 | return; |
| 36 | } |
Kevin O'Connor | 84ad59a | 2008-07-04 05:47:26 -0400 | [diff] [blame] | 37 | |
Kevin O'Connor | 3574644 | 2009-02-27 20:54:51 -0500 | [diff] [blame] | 38 | /* floating pointer structure */ |
Kevin O'Connor | 3574644 | 2009-02-27 20:54:51 -0500 | [diff] [blame] | 39 | memset(floating, 0, sizeof(*floating)); |
Kevin O'Connor | 3574644 | 2009-02-27 20:54:51 -0500 | [diff] [blame] | 40 | floating->signature = MPTABLE_SIGNATURE; |
| 41 | floating->physaddr = (u32)config; |
| 42 | floating->length = 1; |
| 43 | floating->spec_rev = 4; |
Kevin O'Connor | 523e5a9 | 2009-07-04 13:46:33 -0400 | [diff] [blame] | 44 | floating->checksum -= checksum(floating, sizeof(*floating)); |
Kevin O'Connor | 84ad59a | 2008-07-04 05:47:26 -0400 | [diff] [blame] | 45 | |
Kevin O'Connor | 3574644 | 2009-02-27 20:54:51 -0500 | [diff] [blame] | 46 | // Config structure. |
| 47 | memset(config, 0, sizeof(*config)); |
| 48 | config->signature = MPCONFIG_SIGNATURE; |
Kevin O'Connor | 3574644 | 2009-02-27 20:54:51 -0500 | [diff] [blame] | 49 | config->spec = 4; |
| 50 | memcpy(config->oemid, CONFIG_CPUNAME8, sizeof(config->oemid)); |
| 51 | memcpy(config->productid, "0.1 ", sizeof(config->productid)); |
Kevin O'Connor | 3574644 | 2009-02-27 20:54:51 -0500 | [diff] [blame] | 52 | config->lapic = BUILD_APIC_ADDR; |
| 53 | |
Kevin O'Connor | 86916ce | 2009-11-14 13:34:27 -0500 | [diff] [blame] | 54 | // Detect cpu info |
Kevin O'Connor | e97ca7b | 2009-06-21 09:10:28 -0400 | [diff] [blame] | 55 | u32 cpuid_signature, ebx, ecx, cpuid_features; |
| 56 | cpuid(1, &cpuid_signature, &ebx, &ecx, &cpuid_features); |
Kevin O'Connor | 86916ce | 2009-11-14 13:34:27 -0500 | [diff] [blame] | 57 | int pkgcpus = 1; |
| 58 | if (cpuid_features & (1 << 28)) { |
| 59 | /* Only populate the MPS tables with the first logical CPU in |
| 60 | each package */ |
| 61 | pkgcpus = (ebx >> 16) & 0xff; |
| 62 | pkgcpus = 1 << (__fls(pkgcpus - 1) + 1); /* round up to power of 2 */ |
| 63 | } |
Kevin O'Connor | c0ad0e8 | 2009-11-09 19:20:21 -0500 | [diff] [blame] | 64 | |
Kevin O'Connor | 86916ce | 2009-11-14 13:34:27 -0500 | [diff] [blame] | 65 | // CPU definitions. |
| 66 | struct mpt_cpu *cpus = (void*)&config[1], *cpu = cpus; |
| 67 | int i; |
| 68 | for (i = 0; i < MaxCountCPUs; i+=pkgcpus) { |
Kevin O'Connor | 3574644 | 2009-02-27 20:54:51 -0500 | [diff] [blame] | 69 | memset(cpu, 0, sizeof(*cpu)); |
| 70 | cpu->type = MPT_TYPE_CPU; |
| 71 | cpu->apicid = i; |
| 72 | cpu->apicver = 0x11; |
| 73 | /* cpu flags: enabled, bootstrap cpu */ |
Kevin O'Connor | 86916ce | 2009-11-14 13:34:27 -0500 | [diff] [blame] | 74 | cpu->cpuflag = (i < CountCPUs) | ((i == 0) << 1); |
Kevin O'Connor | e97ca7b | 2009-06-21 09:10:28 -0400 | [diff] [blame] | 75 | if (cpuid_signature) { |
| 76 | cpu->cpusignature = cpuid_signature; |
| 77 | cpu->featureflag = cpuid_features; |
| 78 | } else { |
| 79 | cpu->cpusignature = 0x600; |
| 80 | cpu->featureflag = 0x201; |
| 81 | } |
Kevin O'Connor | 86916ce | 2009-11-14 13:34:27 -0500 | [diff] [blame] | 82 | cpu++; |
Kevin O'Connor | 84ad59a | 2008-07-04 05:47:26 -0400 | [diff] [blame] | 83 | } |
Kevin O'Connor | 86916ce | 2009-11-14 13:34:27 -0500 | [diff] [blame] | 84 | int entrycount = cpu - cpus; |
Kevin O'Connor | c0ad0e8 | 2009-11-09 19:20:21 -0500 | [diff] [blame] | 85 | |
Kevin O'Connor | 84ad59a | 2008-07-04 05:47:26 -0400 | [diff] [blame] | 86 | /* isa bus */ |
Kevin O'Connor | 86916ce | 2009-11-14 13:34:27 -0500 | [diff] [blame] | 87 | struct mpt_bus *bus = (void*)cpu; |
Kevin O'Connor | 3574644 | 2009-02-27 20:54:51 -0500 | [diff] [blame] | 88 | memset(bus, 0, sizeof(*bus)); |
| 89 | bus->type = MPT_TYPE_BUS; |
Gleb Natapov | 928d4df | 2009-12-24 14:29:43 +0200 | [diff] [blame] | 90 | bus->busid = 1; |
Kevin O'Connor | 3574644 | 2009-02-27 20:54:51 -0500 | [diff] [blame] | 91 | memcpy(bus->bustype, "ISA ", sizeof(bus->bustype)); |
Kevin O'Connor | 86916ce | 2009-11-14 13:34:27 -0500 | [diff] [blame] | 92 | entrycount++; |
Kevin O'Connor | 84ad59a | 2008-07-04 05:47:26 -0400 | [diff] [blame] | 93 | |
Gleb Natapov | 928d4df | 2009-12-24 14:29:43 +0200 | [diff] [blame] | 94 | bus++; |
| 95 | memset(bus, 0, sizeof(*bus)); |
| 96 | bus->type = MPT_TYPE_BUS; |
| 97 | bus->busid = 0; |
| 98 | memcpy(bus->bustype, "PCI ", sizeof(bus->bustype)); |
| 99 | entrycount++; |
| 100 | |
Kevin O'Connor | 84ad59a | 2008-07-04 05:47:26 -0400 | [diff] [blame] | 101 | /* ioapic */ |
Kevin O'Connor | a26df9b | 2009-10-09 09:42:11 -0400 | [diff] [blame] | 102 | u8 ioapic_id = CountCPUs; |
Kevin O'Connor | 3574644 | 2009-02-27 20:54:51 -0500 | [diff] [blame] | 103 | struct mpt_ioapic *ioapic = (void*)&bus[1]; |
| 104 | memset(ioapic, 0, sizeof(*ioapic)); |
| 105 | ioapic->type = MPT_TYPE_IOAPIC; |
| 106 | ioapic->apicid = ioapic_id; |
| 107 | ioapic->apicver = 0x11; |
| 108 | ioapic->flags = 1; // enable |
| 109 | ioapic->apicaddr = BUILD_IOAPIC_ADDR; |
Kevin O'Connor | 86916ce | 2009-11-14 13:34:27 -0500 | [diff] [blame] | 110 | entrycount++; |
Kevin O'Connor | 84ad59a | 2008-07-04 05:47:26 -0400 | [diff] [blame] | 111 | |
| 112 | /* irqs */ |
Kevin O'Connor | 86916ce | 2009-11-14 13:34:27 -0500 | [diff] [blame] | 113 | struct mpt_intsrc *intsrcs = (void*)&ioapic[1], *intsrc = intsrcs; |
Gleb Natapov | 928d4df | 2009-12-24 14:29:43 +0200 | [diff] [blame] | 114 | int bdf, max, dev = -1; |
| 115 | unsigned short mask = 0, pinmask; |
| 116 | |
| 117 | foreachpci(bdf, max) { |
| 118 | int pin = pci_config_readb(bdf, PCI_INTERRUPT_PIN); |
| 119 | int irq = pci_config_readb(bdf, PCI_INTERRUPT_LINE); |
| 120 | if (pin == 0) |
| 121 | continue; |
| 122 | if (dev != pci_bdf_to_dev(bdf)) { |
| 123 | dev = pci_bdf_to_dev(bdf); |
| 124 | pinmask = 0; |
| 125 | } |
| 126 | if (pinmask & (1 << pin)) /* pin was seen already */ |
| 127 | continue; |
| 128 | pinmask |= (1 << pin); |
| 129 | mask |= (1 << irq); |
Kevin O'Connor | b64db30 | 2009-07-29 19:20:03 -0400 | [diff] [blame] | 130 | memset(intsrc, 0, sizeof(*intsrc)); |
| 131 | intsrc->type = MPT_TYPE_INTSRC; |
Gleb Natapov | 928d4df | 2009-12-24 14:29:43 +0200 | [diff] [blame] | 132 | intsrc->irqtype = 0; /* INT */ |
| 133 | intsrc->irqflag = 1; /* active high */ |
| 134 | intsrc->srcbus = 0; /* PCI bus */ |
| 135 | intsrc->srcbusirq = (dev << 2) | (pin - 1); |
| 136 | intsrc->dstapic = ioapic_id; |
| 137 | intsrc->dstirq = irq; |
| 138 | intsrc++; |
| 139 | } |
| 140 | |
| 141 | for (i = 0; i < 16; i++) { |
| 142 | memset(intsrc, 0, sizeof(*intsrc)); |
| 143 | if (mask & (1 << i)) |
| 144 | continue; |
| 145 | intsrc->type = MPT_TYPE_INTSRC; |
| 146 | intsrc->irqtype = 0; /* INT */ |
| 147 | intsrc->irqflag = 0; /* conform to bus spec */ |
| 148 | intsrc->srcbus = 1; /* ISA bus */ |
Kevin O'Connor | b64db30 | 2009-07-29 19:20:03 -0400 | [diff] [blame] | 149 | intsrc->srcbusirq = i; |
| 150 | intsrc->dstapic = ioapic_id; |
| 151 | intsrc->dstirq = i; |
Kevin O'Connor | 4d2b619 | 2009-10-08 21:37:21 -0400 | [diff] [blame] | 152 | if (qemu_cfg_irq0_override()) { |
Kevin O'Connor | b64db30 | 2009-07-29 19:20:03 -0400 | [diff] [blame] | 153 | /* Destination 2 is covered by irq0->inti2 override (i == |
| 154 | 0). Source IRQ 2 is unused */ |
| 155 | if (i == 0) |
| 156 | intsrc->dstirq = 2; |
| 157 | else if (i == 2) |
| 158 | intsrc--; |
| 159 | } |
| 160 | intsrc++; |
Kevin O'Connor | 84ad59a | 2008-07-04 05:47:26 -0400 | [diff] [blame] | 161 | } |
Kevin O'Connor | 86916ce | 2009-11-14 13:34:27 -0500 | [diff] [blame] | 162 | entrycount += intsrc - intsrcs; |
Kevin O'Connor | 84ad59a | 2008-07-04 05:47:26 -0400 | [diff] [blame] | 163 | |
Kevin O'Connor | b021a57 | 2009-11-14 13:49:06 -0500 | [diff] [blame] | 164 | /* Local interrupt assignment */ |
| 165 | intsrc->type = MPT_TYPE_LOCAL_INT; |
| 166 | intsrc->irqtype = 3; /* ExtINT */ |
| 167 | intsrc->irqflag = 0; /* PO, EL default */ |
Gleb Natapov | 928d4df | 2009-12-24 14:29:43 +0200 | [diff] [blame] | 168 | intsrc->srcbus = 1; /* ISA */ |
Kevin O'Connor | b021a57 | 2009-11-14 13:49:06 -0500 | [diff] [blame] | 169 | intsrc->srcbusirq = 0; |
| 170 | intsrc->dstapic = 0; /* BSP == APIC #0 */ |
| 171 | intsrc->dstirq = 0; /* LINTIN0 */ |
| 172 | intsrc++; |
| 173 | entrycount++; |
| 174 | |
| 175 | intsrc->type = MPT_TYPE_LOCAL_INT; |
| 176 | intsrc->irqtype = 1; /* NMI */ |
| 177 | intsrc->irqflag = 0; /* PO, EL default */ |
Gleb Natapov | 928d4df | 2009-12-24 14:29:43 +0200 | [diff] [blame] | 178 | intsrc->srcbus = 1; /* ISA */ |
Kevin O'Connor | b021a57 | 2009-11-14 13:49:06 -0500 | [diff] [blame] | 179 | intsrc->srcbusirq = 0; |
| 180 | intsrc->dstapic = 0; /* BSP == APIC #0 */ |
| 181 | intsrc->dstirq = 1; /* LINTIN1 */ |
| 182 | intsrc++; |
| 183 | entrycount++; |
| 184 | |
Kevin O'Connor | 86916ce | 2009-11-14 13:34:27 -0500 | [diff] [blame] | 185 | // Finalize config structure. |
| 186 | config->entrycount = entrycount; |
Kevin O'Connor | b64db30 | 2009-07-29 19:20:03 -0400 | [diff] [blame] | 187 | config->length = (void*)intsrc - (void*)config; |
Kevin O'Connor | 523e5a9 | 2009-07-04 13:46:33 -0400 | [diff] [blame] | 188 | config->checksum -= checksum(config, config->length); |
Kevin O'Connor | 84ad59a | 2008-07-04 05:47:26 -0400 | [diff] [blame] | 189 | |
Kevin O'Connor | 2929c35 | 2009-07-25 13:48:27 -0400 | [diff] [blame] | 190 | dprintf(1, "MP table addr=%p MPC table addr=%p size=%d\n", |
Kevin O'Connor | b64db30 | 2009-07-29 19:20:03 -0400 | [diff] [blame] | 191 | floating, config, config->length); |
Kevin O'Connor | 84ad59a | 2008-07-04 05:47:26 -0400 | [diff] [blame] | 192 | } |