1 /*-
2 * Copyright (c) 2012 NetApp, Inc.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 * $FreeBSD$
27 */
28
29 #include <stdio.h>
30 #include <string.h>
31
32 #include "types.h"
33 #include "mptable.h"
34 #include "acpi.h"
35 #include "dm.h"
36 #include "pci_core.h"
37 #include "vmmapi.h"
38
39 #define MPTABLE_BASE 0xF0000
40
41 /* floating pointer length + maximum length of configuration table */
42 #define MPTABLE_MAX_LENGTH (65536 + 16)
43
44 #define LAPIC_PADDR 0xFEE00000
45 #define LAPIC_VERSION 16
46
47 #define IOAPIC_PADDR 0xFEC00000
48 #define IOAPIC_VERSION 0x11
49
50 #define MP_SPECREV 4
51 #define MPFP_SIG "_MP_"
52
53 /* Configuration header defines */
54 #define MPCH_SIG "PCMP"
55 #define MPCH_OEMID "BHyVe "
56 #define MPCH_OEMID_LEN 8
57 #define MPCH_PRODID "Hypervisor "
58 #define MPCH_PRODID_LEN 12
59
60 /* Processor entry defines */
61 #define MPEP_SIG_FAMILY 6 /* XXX acrn-dm should supply this */
62 #define MPEP_SIG_MODEL 26
63 #define MPEP_SIG_STEPPING 5
64 #define MPEP_SIG \
65 ((MPEP_SIG_FAMILY << 8) | \
66 (MPEP_SIG_MODEL << 4) | \
67 (MPEP_SIG_STEPPING))
68
69 #define MPEP_FEATURES (0xBFEBFBFF) /* XXX Intel i7 */
70
71 /* Number of local intr entries */
72 #define MPEII_NUM_LOCAL_IRQ 2
73
74 /* Bus entry defines */
75 #define MPE_NUM_BUSES 2
76 #define MPE_BUSNAME_LEN 6
77 #define MPE_BUSNAME_ISA "ISA "
78 #define MPE_BUSNAME_PCI "PCI "
79
80 static void *oem_tbl_start;
81 static int oem_tbl_size;
82
83 static uint8_t
mpt_compute_checksum(void * base,size_t len)84 mpt_compute_checksum(void *base, size_t len)
85 {
86 uint8_t *bytes;
87 uint8_t sum;
88
89 for (bytes = base, sum = 0; len > 0; len--)
90 sum += *bytes++;
91
92 return (256 - sum);
93 }
94
95 static void
mpt_build_mpfp(mpfps_t mpfp,vm_paddr_t gpa)96 mpt_build_mpfp(mpfps_t mpfp, vm_paddr_t gpa)
97 {
98 memset(mpfp, 0, sizeof(*mpfp));
99 memcpy(mpfp->signature, MPFP_SIG, 4);
100 mpfp->pap = gpa + sizeof(*mpfp);
101 mpfp->length = 1;
102 mpfp->spec_rev = MP_SPECREV;
103 mpfp->checksum = mpt_compute_checksum(mpfp, sizeof(*mpfp));
104 }
105
106 static void
mpt_build_mpch(mpcth_t mpch)107 mpt_build_mpch(mpcth_t mpch)
108 {
109 memset(mpch, 0, sizeof(*mpch));
110 memcpy(mpch->signature, MPCH_SIG, 4);
111 mpch->spec_rev = MP_SPECREV;
112 memcpy(mpch->oem_id, MPCH_OEMID, MPCH_OEMID_LEN);
113 memcpy(mpch->product_id, MPCH_PRODID, MPCH_PRODID_LEN);
114 mpch->apic_address = LAPIC_PADDR;
115 }
116
117 static void
mpt_build_proc_entries(proc_entry_ptr mpep,int ncpu)118 mpt_build_proc_entries(proc_entry_ptr mpep, int ncpu)
119 {
120 int i;
121 uint64_t guest_pcpu_bitmask = vm_get_cpu_affinity_dm();
122
123 if (guest_pcpu_bitmask == 0) {
124 pr_err("%s,Err: Invalid guest_pcpu_bitmask.\n", __func__);
125 return;
126 }
127
128 pr_info("%s, guest_cpu_bitmask: 0x%x\n", __func__, guest_pcpu_bitmask);
129
130 for (i = 0; i < ncpu; i++) {
131 int pcpu_id = pcpuid_from_vcpuid(guest_pcpu_bitmask, i);
132 int lapic_id;
133
134 if (pcpu_id < 0) {
135 pr_err("%s,Err: pcpu id is not found in guest_pcpu_bitmask.\n", __func__);
136 return;
137 }
138
139 assert(pcpu_id < ACRN_PLATFORM_LAPIC_IDS_MAX);
140 if (pcpu_id >= ACRN_PLATFORM_LAPIC_IDS_MAX) {
141 pr_err("%s,Err: pcpu id %u should be less than ACRN_PLATFORM_LAPIC_IDS_MAX.\n", __func__, pcpu_id);
142 return;
143 }
144
145 lapic_id = lapicid_from_pcpuid(pcpu_id);
146 if (lapic_id == -1) {
147 pr_err("Failed to retrieve the local APIC ID for pCPU %u\n", pcpu_id);
148 return;
149 }
150
151 memset(mpep, 0, sizeof(*mpep));
152 mpep->type = MPCT_ENTRY_PROCESSOR;
153 mpep->apic_id = lapic_id;
154 mpep->apic_version = LAPIC_VERSION;
155 mpep->cpu_flags = PROCENTRY_FLAG_EN;
156 if (i == 0)
157 mpep->cpu_flags |= PROCENTRY_FLAG_BP;
158 mpep->cpu_signature = MPEP_SIG;
159 mpep->feature_flags = MPEP_FEATURES;
160 mpep++;
161 }
162 }
163
164 static void
mpt_build_localint_entries(int_entry_ptr mpie)165 mpt_build_localint_entries(int_entry_ptr mpie)
166 {
167 /* Hardcode LINT0 as ExtINT on all CPUs. */
168 memset(mpie, 0, sizeof(*mpie));
169 mpie->type = MPCT_ENTRY_LOCAL_INT;
170 mpie->int_type = INTENTRY_TYPE_EXTINT;
171 mpie->int_flags = INTENTRY_FLAGS_POLARITY_CONFORM |
172 INTENTRY_FLAGS_TRIGGER_CONFORM;
173 mpie->dst_apic_id = 0xff;
174 mpie->dst_apic_int = 0;
175 mpie++;
176
177 /* Hardcode LINT1 as NMI on all CPUs. */
178 memset(mpie, 0, sizeof(*mpie));
179 mpie->type = MPCT_ENTRY_LOCAL_INT;
180 mpie->int_type = INTENTRY_TYPE_NMI;
181 mpie->int_flags = INTENTRY_FLAGS_POLARITY_CONFORM |
182 INTENTRY_FLAGS_TRIGGER_CONFORM;
183 mpie->dst_apic_id = 0xff;
184 mpie->dst_apic_int = 1;
185 }
186
187 static void
mpt_build_bus_entries(bus_entry_ptr mpeb)188 mpt_build_bus_entries(bus_entry_ptr mpeb)
189 {
190 memset(mpeb, 0, sizeof(*mpeb));
191 mpeb->type = MPCT_ENTRY_BUS;
192 mpeb->bus_id = 0;
193 memcpy(mpeb->bus_type, MPE_BUSNAME_PCI, MPE_BUSNAME_LEN);
194 mpeb++;
195
196 memset(mpeb, 0, sizeof(*mpeb));
197 mpeb->type = MPCT_ENTRY_BUS;
198 mpeb->bus_id = 1;
199 memcpy(mpeb->bus_type, MPE_BUSNAME_ISA, MPE_BUSNAME_LEN);
200 }
201
202 static void
mpt_build_ioapic_entries(io_apic_entry_ptr mpei,int id)203 mpt_build_ioapic_entries(io_apic_entry_ptr mpei, int id)
204 {
205 memset(mpei, 0, sizeof(*mpei));
206 mpei->type = MPCT_ENTRY_IOAPIC;
207 mpei->apic_id = id;
208 mpei->apic_version = IOAPIC_VERSION;
209 mpei->apic_flags = IOAPICENTRY_FLAG_EN;
210 mpei->apic_address = IOAPIC_PADDR;
211 }
212
213 static int
mpt_count_ioint_entries(void)214 mpt_count_ioint_entries(void)
215 {
216 int bus, count;
217
218 count = 0;
219 for (bus = 0; bus <= PCI_BUSMAX; bus++)
220 count += pci_count_lintr(bus);
221
222 /*
223 * Always include entries for the first 16 pins along with a entry
224 * for each active PCI INTx pin.
225 */
226 return (16 + count);
227 }
228
229 static void
mpt_generate_pci_int(int bus,int slot,int pin,int pirq_pin,int ioapic_irq,void * arg)230 mpt_generate_pci_int(int bus, int slot, int pin, int pirq_pin, int ioapic_irq,
231 void *arg)
232 {
233 int_entry_ptr *mpiep, mpie;
234
235 mpiep = arg;
236 mpie = *mpiep;
237 memset(mpie, 0, sizeof(*mpie));
238
239 /*
240 * This is always after another I/O interrupt entry, so cheat
241 * and fetch the I/O APIC ID from the prior entry.
242 */
243 mpie->type = MPCT_ENTRY_INT;
244 mpie->int_type = INTENTRY_TYPE_INT;
245 mpie->src_bus_id = bus;
246 mpie->src_bus_irq = slot << 2 | (pin - 1);
247 mpie->dst_apic_id = mpie[-1].dst_apic_id;
248 mpie->dst_apic_int = ioapic_irq;
249
250 *mpiep = mpie + 1;
251 }
252
253 static void
mpt_build_ioint_entries(int_entry_ptr mpie,int id)254 mpt_build_ioint_entries(int_entry_ptr mpie, int id)
255 {
256 int pin, bus;
257
258 /*
259 * The following config is taken from kernel mptable.c
260 * mptable_parse_default_config_ints(...), for now
261 * just use the default config, tweek later if needed.
262 */
263
264 /* First, generate the first 16 pins. */
265 for (pin = 0; pin < 16; pin++) {
266 memset(mpie, 0, sizeof(*mpie));
267 mpie->type = MPCT_ENTRY_INT;
268 mpie->src_bus_id = 1;
269 mpie->dst_apic_id = id;
270
271 /*
272 * All default configs route IRQs from bus 0 to the first 16
273 * pins of the first I/O APIC with an APIC ID of 2.
274 */
275 mpie->dst_apic_int = pin;
276 switch (pin) {
277 case 0:
278 /* Pin 0 is an ExtINT pin. */
279 mpie->int_type = INTENTRY_TYPE_EXTINT;
280 break;
281 case 2:
282 /* IRQ 0 is routed to pin 2. */
283 mpie->int_type = INTENTRY_TYPE_INT;
284 mpie->src_bus_irq = 0;
285 break;
286 case SCI_INT:
287 /* ACPI SCI is level triggered and active-lo. */
288 mpie->int_flags = INTENTRY_FLAGS_POLARITY_ACTIVELO |
289 INTENTRY_FLAGS_TRIGGER_LEVEL;
290 mpie->int_type = INTENTRY_TYPE_INT;
291 mpie->src_bus_irq = SCI_INT;
292 break;
293 default:
294 /* All other pins are identity mapped. */
295 mpie->int_type = INTENTRY_TYPE_INT;
296 mpie->src_bus_irq = pin;
297 break;
298 }
299 mpie++;
300 }
301
302 /* Next, generate entries for any PCI INTx interrupts. */
303 for (bus = 0; bus <= PCI_BUSMAX; bus++)
304 pci_walk_lintr(bus, mpt_generate_pci_int, &mpie);
305 }
306
307 int
mptable_build(struct vmctx * ctx,int ncpu)308 mptable_build(struct vmctx *ctx, int ncpu)
309 {
310 mpcth_t mpch;
311 bus_entry_ptr mpeb;
312 io_apic_entry_ptr mpei;
313 proc_entry_ptr mpep;
314 mpfps_t mpfp;
315 int_entry_ptr mpie;
316 int ioints, bus;
317 char *curraddr;
318 char *startaddr;
319
320 startaddr = paddr_guest2host(ctx, MPTABLE_BASE, MPTABLE_MAX_LENGTH);
321 if (startaddr == NULL) {
322 pr_err("mptable requires mapped mem\n");
323 return -1;
324 }
325
326 /*
327 * There is no way to advertise multiple PCI hierarchies via MPtable
328 * so require that there is no PCI hierarchy with a non-zero bus
329 * number.
330 */
331 for (bus = 1; bus <= PCI_BUSMAX; bus++) {
332 if (pci_bus_configured(bus)) {
333 pr_err("MPtable is incompatible with "
334 "multiple PCI hierarchies.\r\n");
335 pr_err("MPtable generation can be disabled "
336 "by passing the -Y option to acrn-dm.\r\n");
337 return -1;
338 }
339 }
340
341 curraddr = startaddr;
342 mpfp = (mpfps_t)curraddr;
343 mpt_build_mpfp(mpfp, MPTABLE_BASE);
344 curraddr += sizeof(*mpfp);
345
346 mpch = (mpcth_t)curraddr;
347 mpt_build_mpch(mpch);
348 curraddr += sizeof(*mpch);
349
350 mpep = (proc_entry_ptr)curraddr;
351 mpt_build_proc_entries(mpep, ncpu);
352 curraddr += sizeof(*mpep) * ncpu;
353 mpch->entry_count += ncpu;
354
355 mpeb = (bus_entry_ptr) curraddr;
356 mpt_build_bus_entries(mpeb);
357 curraddr += sizeof(*mpeb) * MPE_NUM_BUSES;
358 mpch->entry_count += MPE_NUM_BUSES;
359
360 /* Don't generate io_apic entry for VM with lapic pt */
361 if (!lapic_pt) {
362 mpei = (io_apic_entry_ptr)curraddr;
363 mpt_build_ioapic_entries(mpei, 0);
364 curraddr += sizeof(*mpei);
365 mpch->entry_count++;
366
367 mpie = (int_entry_ptr) curraddr;
368 ioints = mpt_count_ioint_entries();
369 mpt_build_ioint_entries(mpie, 0);
370 curraddr += sizeof(*mpie) * ioints;
371 mpch->entry_count += ioints;
372 }
373
374 mpie = (int_entry_ptr)curraddr;
375 mpt_build_localint_entries(mpie);
376 curraddr += sizeof(*mpie) * MPEII_NUM_LOCAL_IRQ;
377 mpch->entry_count += MPEII_NUM_LOCAL_IRQ;
378
379 if (oem_tbl_start) {
380 mpch->oem_table_pointer = curraddr - startaddr + MPTABLE_BASE;
381 mpch->oem_table_size = oem_tbl_size;
382 memcpy(curraddr, oem_tbl_start, oem_tbl_size);
383 }
384
385 mpch->base_table_length = curraddr - (char *)mpch;
386 mpch->checksum = mpt_compute_checksum(mpch, mpch->base_table_length);
387
388 return 0;
389 }
390