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