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