mptbl.c revision 262350
1169689Skan/*-
2169689Skan * Copyright (c) 2012 NetApp, Inc.
390075Sobrien * All rights reserved.
4132718Skan *
590075Sobrien * Redistribution and use in source and binary forms, with or without
6132718Skan * modification, are permitted provided that the following conditions
790075Sobrien * are met:
890075Sobrien * 1. Redistributions of source code must retain the above copyright
990075Sobrien *    notice, this list of conditions and the following disclaimer.
1090075Sobrien * 2. Redistributions in binary form must reproduce the above copyright
11132718Skan *    notice, this list of conditions and the following disclaimer in the
1290075Sobrien *    documentation and/or other materials provided with the distribution.
1390075Sobrien *
1490075Sobrien * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND
1590075Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1690075Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17132718Skan * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE
18169689Skan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19169689Skan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2090075Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2190075Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2290075Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2390075Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2490075Sobrien * SUCH DAMAGE.
2590075Sobrien *
2690075Sobrien * $FreeBSD: stable/10/usr.sbin/bhyve/mptbl.c 262350 2014-02-23 00:46:05Z jhb $
2790075Sobrien */
2890075Sobrien
29169689Skan#include <sys/cdefs.h>
3090075Sobrien__FBSDID("$FreeBSD: stable/10/usr.sbin/bhyve/mptbl.c 262350 2014-02-23 00:46:05Z jhb $");
3190075Sobrien
3290075Sobrien#include <sys/types.h>
3390075Sobrien#include <sys/errno.h>
34117395Skan#include <x86/mptable.h>
35117395Skan
36117395Skan#include <stdio.h>
37117395Skan#include <string.h>
3890075Sobrien
3990075Sobrien#include "acpi.h"
4090075Sobrien#include "bhyverun.h"
41169689Skan#include "mptbl.h"
42169689Skan
4390075Sobrien#define MPTABLE_BASE		0xF0000
44169689Skan
45169689Skan/* floating pointer length + maximum length of configuration table */
46169689Skan#define	MPTABLE_MAX_LENGTH	(65536 + 16)
47169689Skan
48132718Skan#define LAPIC_PADDR		0xFEE00000
49169689Skan#define LAPIC_VERSION 		16
5090075Sobrien
5190075Sobrien#define IOAPIC_PADDR		0xFEC00000
5290075Sobrien#define IOAPIC_VERSION		0x11
5390075Sobrien
5490075Sobrien#define MP_SPECREV		4
5590075Sobrien#define MPFP_SIG		"_MP_"
5690075Sobrien
5790075Sobrien/* Configuration header defines */
5890075Sobrien#define MPCH_SIG		"PCMP"
5990075Sobrien#define MPCH_OEMID		"BHyVe   "
6090075Sobrien#define MPCH_OEMID_LEN          8
6190075Sobrien#define MPCH_PRODID             "Hypervisor  "
6290075Sobrien#define MPCH_PRODID_LEN         12
6390075Sobrien
6490075Sobrien/* Processor entry defines */
6590075Sobrien#define MPEP_SIG_FAMILY		6	/* XXX bhyve should supply this */
6690075Sobrien#define MPEP_SIG_MODEL		26
6790075Sobrien#define MPEP_SIG_STEPPING	5
6890075Sobrien#define MPEP_SIG		\
6990075Sobrien	((MPEP_SIG_FAMILY << 8) | \
7090075Sobrien	 (MPEP_SIG_MODEL << 4)	| \
7190075Sobrien	 (MPEP_SIG_STEPPING))
7290075Sobrien
7390075Sobrien#define MPEP_FEATURES           (0xBFEBFBFF) /* XXX Intel i7 */
7490075Sobrien
7590075Sobrien/* Number of local intr entries */
7690075Sobrien#define	MPEII_NUM_LOCAL_IRQ	2
7790075Sobrien
7890075Sobrien/* Number of i/o intr entries */
7990075Sobrien#define	MPEII_MAX_IRQ		24
8090075Sobrien
8190075Sobrien/* Bus entry defines */
8290075Sobrien#define MPE_NUM_BUSES		2
8390075Sobrien#define MPE_BUSNAME_LEN		6
8490075Sobrien#define MPE_BUSNAME_ISA		"ISA   "
8590075Sobrien#define MPE_BUSNAME_PCI		"PCI   "
8690075Sobrien
8790075Sobrienstatic void *oem_tbl_start;
8890075Sobrienstatic int oem_tbl_size;
8990075Sobrien
9090075Sobrienstatic uint8_t
91169689Skanmpt_compute_checksum(void *base, size_t len)
92169689Skan{
93169689Skan	uint8_t	*bytes;
94169689Skan	uint8_t	sum;
95169689Skan
96169689Skan	for(bytes = base, sum = 0; len > 0; len--) {
97169689Skan		sum += *bytes++;
9890075Sobrien	}
9990075Sobrien
10090075Sobrien	return (256 - sum);
10190075Sobrien}
102169689Skan
10390075Sobrienstatic void
10490075Sobrienmpt_build_mpfp(mpfps_t mpfp, vm_paddr_t gpa)
10590075Sobrien{
10690075Sobrien
10790075Sobrien	memset(mpfp, 0, sizeof(*mpfp));
108169689Skan	memcpy(mpfp->signature, MPFP_SIG, 4);
10990075Sobrien	mpfp->pap = gpa + sizeof(*mpfp);
11090075Sobrien	mpfp->length = 1;
11190075Sobrien	mpfp->spec_rev = MP_SPECREV;
11290075Sobrien	mpfp->checksum = mpt_compute_checksum(mpfp, sizeof(*mpfp));
11390075Sobrien}
114169689Skan
11590075Sobrienstatic void
11690075Sobrienmpt_build_mpch(mpcth_t mpch)
11790075Sobrien{
11890075Sobrien
11990075Sobrien	memset(mpch, 0, sizeof(*mpch));
120169689Skan	memcpy(mpch->signature, MPCH_SIG, 4);
12190075Sobrien	mpch->spec_rev = MP_SPECREV;
12290075Sobrien	memcpy(mpch->oem_id, MPCH_OEMID, MPCH_OEMID_LEN);
12390075Sobrien	memcpy(mpch->product_id, MPCH_PRODID, MPCH_PRODID_LEN);
12490075Sobrien	mpch->apic_address = LAPIC_PADDR;
12590075Sobrien}
126169689Skan
12790075Sobrienstatic void
12890075Sobrienmpt_build_proc_entries(proc_entry_ptr mpep, int ncpu)
12990075Sobrien{
13090075Sobrien	int i;
13190075Sobrien
132169689Skan	for (i = 0; i < ncpu; i++) {
13390075Sobrien		memset(mpep, 0, sizeof(*mpep));
13490075Sobrien		mpep->type = MPCT_ENTRY_PROCESSOR;
13590075Sobrien		mpep->apic_id = i; // XXX
13690075Sobrien		mpep->apic_version = LAPIC_VERSION;
13790075Sobrien		mpep->cpu_flags = PROCENTRY_FLAG_EN;
138169689Skan		if (i == 0)
13990075Sobrien			mpep->cpu_flags |= PROCENTRY_FLAG_BP;
14090075Sobrien		mpep->cpu_signature = MPEP_SIG;
14190075Sobrien		mpep->feature_flags = MPEP_FEATURES;
14290075Sobrien		mpep++;
14390075Sobrien	}
144169689Skan}
14590075Sobrien
14690075Sobrienstatic void
14790075Sobrienmpt_build_localint_entries(int_entry_ptr mpie)
14890075Sobrien{
14990075Sobrien
150169689Skan	/* Hardcode LINT0 as ExtINT on all CPUs. */
15190075Sobrien	memset(mpie, 0, sizeof(*mpie));
15290075Sobrien	mpie->type = MPCT_ENTRY_LOCAL_INT;
15390075Sobrien	mpie->int_type = INTENTRY_TYPE_EXTINT;
15490075Sobrien	mpie->int_flags = INTENTRY_FLAGS_POLARITY_CONFORM |
15590075Sobrien	    INTENTRY_FLAGS_TRIGGER_CONFORM;
15690075Sobrien	mpie->dst_apic_id = 0xff;
15790075Sobrien	mpie->dst_apic_int = 0;
158169689Skan	mpie++;
15990075Sobrien
16090075Sobrien	/* Hardcode LINT1 as NMI on all CPUs. */
16190075Sobrien	memset(mpie, 0, sizeof(*mpie));
16290075Sobrien	mpie->type = MPCT_ENTRY_LOCAL_INT;
16390075Sobrien	mpie->int_type = INTENTRY_TYPE_NMI;
164169689Skan	mpie->int_flags = INTENTRY_FLAGS_POLARITY_CONFORM |
16590075Sobrien	    INTENTRY_FLAGS_TRIGGER_CONFORM;
16690075Sobrien	mpie->dst_apic_id = 0xff;
16790075Sobrien	mpie->dst_apic_int = 1;
16890075Sobrien}
16990075Sobrien
170169689Skanstatic void
17190075Sobrienmpt_build_bus_entries(bus_entry_ptr mpeb)
17290075Sobrien{
17390075Sobrien
17490075Sobrien	memset(mpeb, 0, sizeof(*mpeb));
17590075Sobrien	mpeb->type = MPCT_ENTRY_BUS;
176169689Skan	mpeb->bus_id = 0;
17790075Sobrien	memcpy(mpeb->bus_type, MPE_BUSNAME_PCI, MPE_BUSNAME_LEN);
17890075Sobrien	mpeb++;
17990075Sobrien
18090075Sobrien	memset(mpeb, 0, sizeof(*mpeb));
18190075Sobrien	mpeb->type = MPCT_ENTRY_BUS;
182169689Skan	mpeb->bus_id = 1;
18390075Sobrien	memcpy(mpeb->bus_type, MPE_BUSNAME_ISA, MPE_BUSNAME_LEN);
18490075Sobrien}
18590075Sobrien
18690075Sobrienstatic void
18790075Sobrienmpt_build_ioapic_entries(io_apic_entry_ptr mpei, int id)
188169689Skan{
18990075Sobrien
19090075Sobrien	memset(mpei, 0, sizeof(*mpei));
19190075Sobrien	mpei->type = MPCT_ENTRY_IOAPIC;
19290075Sobrien	mpei->apic_id = id;
19390075Sobrien	mpei->apic_version = IOAPIC_VERSION;
194169689Skan	mpei->apic_flags = IOAPICENTRY_FLAG_EN;
19590075Sobrien	mpei->apic_address = IOAPIC_PADDR;
19690075Sobrien}
19790075Sobrien
19890075Sobrienstatic void
19990075Sobrienmpt_build_ioint_entries(int_entry_ptr mpie, int num_pins, int id)
200169689Skan{
20190075Sobrien	int pin;
20290075Sobrien
20390075Sobrien	/*
20490075Sobrien	 * The following config is taken from kernel mptable.c
20590075Sobrien	 * mptable_parse_default_config_ints(...), for now
206169689Skan	 * just use the default config, tweek later if needed.
20790075Sobrien	 */
20890075Sobrien
20990075Sobrien	/* Run through all 16 pins. */
21090075Sobrien	for (pin = 0; pin < num_pins; pin++) {
21190075Sobrien		memset(mpie, 0, sizeof(*mpie));
21290075Sobrien		mpie->type = MPCT_ENTRY_INT;
21390075Sobrien		mpie->src_bus_id = 1;
214169689Skan		mpie->dst_apic_id = id;
21590075Sobrien
21690075Sobrien		/*
21790075Sobrien		 * All default configs route IRQs from bus 0 to the first 16
21890075Sobrien		 * pins of the first I/O APIC with an APIC ID of 2.
21990075Sobrien		 */
220169689Skan		mpie->dst_apic_int = pin;
22190075Sobrien		switch (pin) {
22290075Sobrien		case 0:
22390075Sobrien			/* Pin 0 is an ExtINT pin. */
22490075Sobrien			mpie->int_type = INTENTRY_TYPE_EXTINT;
22590075Sobrien			break;
226169689Skan		case 2:
22790075Sobrien			/* IRQ 0 is routed to pin 2. */
22890075Sobrien			mpie->int_type = INTENTRY_TYPE_INT;
22990075Sobrien			mpie->src_bus_irq = 0;
23090075Sobrien			break;
23190075Sobrien		case SCI_INT:
232169689Skan			/* ACPI SCI is level triggered and active-lo. */
23390075Sobrien			mpie->int_flags = INTENTRY_FLAGS_POLARITY_ACTIVELO |
23490075Sobrien			    INTENTRY_FLAGS_TRIGGER_LEVEL;
23590075Sobrien			mpie->int_type = INTENTRY_TYPE_INT;
23690075Sobrien			mpie->src_bus_irq = SCI_INT;
23790075Sobrien			break;
23890075Sobrien		case 5:
23990075Sobrien		case 10:
24090075Sobrien		case 11:
24190075Sobrien			/*
242169689Skan			 * PCI Irqs set to level triggered and active-lo.
24390075Sobrien			 */
24490075Sobrien			mpie->int_flags = INTENTRY_FLAGS_POLARITY_ACTIVELO |
24590075Sobrien			    INTENTRY_FLAGS_TRIGGER_LEVEL;
24690075Sobrien			mpie->src_bus_id = 0;
24790075Sobrien			/* fall through.. */
248169689Skan		default:
24990075Sobrien			/* All other pins are identity mapped. */
25090075Sobrien			mpie->int_type = INTENTRY_TYPE_INT;
25190075Sobrien			mpie->src_bus_irq = pin;
25290075Sobrien			break;
25390075Sobrien		}
254169689Skan		mpie++;
25590075Sobrien	}
25690075Sobrien
25790075Sobrien}
25890075Sobrien
25990075Sobrienvoid
260169689Skanmptable_add_oemtbl(void *tbl, int tblsz)
26190075Sobrien{
26290075Sobrien
263107590Sobrien	oem_tbl_start = tbl;
264107590Sobrien	oem_tbl_size = tblsz;
265107590Sobrien}
266107590Sobrien
267107590Sobrienint
26890075Sobrienmptable_build(struct vmctx *ctx, int ncpu)
26990075Sobrien{
270169689Skan	mpcth_t			mpch;
27190075Sobrien	bus_entry_ptr		mpeb;
27290075Sobrien	io_apic_entry_ptr	mpei;
273107590Sobrien	proc_entry_ptr		mpep;
274107590Sobrien	mpfps_t			mpfp;
275107590Sobrien	int_entry_ptr		mpie;
276107590Sobrien	char 			*curraddr;
277107590Sobrien	char 			*startaddr;
27890075Sobrien
27990075Sobrien	startaddr = paddr_guest2host(ctx, MPTABLE_BASE, MPTABLE_MAX_LENGTH);
280169689Skan	if (startaddr == NULL) {
28190075Sobrien		printf("mptable requires mapped mem\n");
28290075Sobrien		return (ENOMEM);
28390075Sobrien	}
28490075Sobrien
28590075Sobrien	curraddr = startaddr;
286169689Skan	mpfp = (mpfps_t)curraddr;
28790075Sobrien	mpt_build_mpfp(mpfp, MPTABLE_BASE);
28890075Sobrien	curraddr += sizeof(*mpfp);
28990075Sobrien
29090075Sobrien	mpch = (mpcth_t)curraddr;
29190075Sobrien	mpt_build_mpch(mpch);
292169689Skan	curraddr += sizeof(*mpch);
29390075Sobrien
29490075Sobrien	mpep = (proc_entry_ptr)curraddr;
29590075Sobrien	mpt_build_proc_entries(mpep, ncpu);
29690075Sobrien	curraddr += sizeof(*mpep) * ncpu;
29790075Sobrien	mpch->entry_count += ncpu;
298169689Skan
29990075Sobrien	mpeb = (bus_entry_ptr) curraddr;
30090075Sobrien	mpt_build_bus_entries(mpeb);
301107590Sobrien	curraddr += sizeof(*mpeb) * MPE_NUM_BUSES;
302107590Sobrien	mpch->entry_count += MPE_NUM_BUSES;
303107590Sobrien
304107590Sobrien	mpei = (io_apic_entry_ptr)curraddr;
305107590Sobrien	mpt_build_ioapic_entries(mpei, 0);
30690075Sobrien	curraddr += sizeof(*mpei);
30790075Sobrien	mpch->entry_count++;
308169689Skan
30990075Sobrien	mpie = (int_entry_ptr) curraddr;
31090075Sobrien	mpt_build_ioint_entries(mpie, MPEII_MAX_IRQ, 0);
311107590Sobrien	curraddr += sizeof(*mpie) * MPEII_MAX_IRQ;
312107590Sobrien	mpch->entry_count += MPEII_MAX_IRQ;
313107590Sobrien
314107590Sobrien	mpie = (int_entry_ptr)curraddr;
315107590Sobrien	mpt_build_localint_entries(mpie);
31690075Sobrien	curraddr += sizeof(*mpie) * MPEII_NUM_LOCAL_IRQ;
31790075Sobrien	mpch->entry_count += MPEII_NUM_LOCAL_IRQ;
318169689Skan
31990075Sobrien	if (oem_tbl_start) {
32090075Sobrien		mpch->oem_table_pointer = curraddr - startaddr + MPTABLE_BASE;
32190075Sobrien		mpch->oem_table_size = oem_tbl_size;
32290075Sobrien		memcpy(curraddr, oem_tbl_start, oem_tbl_size);
32390075Sobrien	}
324169689Skan
32590075Sobrien	mpch->base_table_length = curraddr - (char *)mpch;
32690075Sobrien	mpch->checksum = mpt_compute_checksum(mpch, mpch->base_table_length);
32790075Sobrien
32890075Sobrien	return (0);
32990075Sobrien}
33090075Sobrien