mptbl.c revision 259837
1193323Sed/*- 2193323Sed * Copyright (c) 2012 NetApp, Inc. 3193323Sed * All rights reserved. 4193323Sed * 5193323Sed * Redistribution and use in source and binary forms, with or without 6193323Sed * modification, are permitted provided that the following conditions 7193323Sed * are met: 8193323Sed * 1. Redistributions of source code must retain the above copyright 9193323Sed * notice, this list of conditions and the following disclaimer. 10193323Sed * 2. Redistributions in binary form must reproduce the above copyright 11193323Sed * notice, this list of conditions and the following disclaimer in the 12193323Sed * documentation and/or other materials provided with the distribution. 13193323Sed * 14193323Sed * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND 15193323Sed * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16193323Sed * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17193323Sed * ARE DISCLAIMED. IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE 18193323Sed * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19193323Sed * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20218893Sdim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21198090Srdivacky * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22234353Sdim * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23234353Sdim * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24193323Sed * SUCH DAMAGE. 25193323Sed * 26193323Sed * $FreeBSD: stable/10/usr.sbin/bhyve/mptbl.c 259837 2013-12-24 19:10:56Z jhb $ 27193323Sed */ 28193323Sed 29193323Sed#include <sys/cdefs.h> 30193323Sed__FBSDID("$FreeBSD: stable/10/usr.sbin/bhyve/mptbl.c 259837 2013-12-24 19:10:56Z jhb $"); 31193323Sed 32193323Sed#include <sys/types.h> 33193323Sed#include <sys/errno.h> 34193323Sed#include <x86/mptable.h> 35205218Srdivacky 36193323Sed#include <stdio.h> 37193323Sed#include <string.h> 38221345Sdim 39193323Sed#include "bhyverun.h" 40193323Sed#include "mptbl.h" 41193323Sed 42193323Sed#define MPTABLE_BASE 0xF0000 43193323Sed 44193323Sed/* floating pointer length + maximum length of configuration table */ 45193323Sed#define MPTABLE_MAX_LENGTH (65536 + 16) 46193323Sed 47193323Sed#define LAPIC_PADDR 0xFEE00000 48193323Sed#define LAPIC_VERSION 16 49193323Sed 50193323Sed#define IOAPIC_PADDR 0xFEC00000 51193323Sed#define IOAPIC_VERSION 0x11 52193323Sed 53234353Sdim#define MP_SPECREV 4 54193323Sed#define MPFP_SIG "_MP_" 55201360Srdivacky 56201360Srdivacky/* Configuration header defines */ 57201360Srdivacky#define MPCH_SIG "PCMP" 58201360Srdivacky#define MPCH_OEMID "BHyVe " 59221345Sdim#define MPCH_OEMID_LEN 8 60201360Srdivacky#define MPCH_PRODID "Hypervisor " 61201360Srdivacky#define MPCH_PRODID_LEN 12 62201360Srdivacky 63201360Srdivacky/* Processor entry defines */ 64193323Sed#define MPEP_SIG_FAMILY 6 /* XXX bhyve should supply this */ 65193323Sed#define MPEP_SIG_MODEL 26 66193323Sed#define MPEP_SIG_STEPPING 5 67193323Sed#define MPEP_SIG \ 68193323Sed ((MPEP_SIG_FAMILY << 8) | \ 69193323Sed (MPEP_SIG_MODEL << 4) | \ 70193323Sed (MPEP_SIG_STEPPING)) 71193323Sed 72193323Sed#define MPEP_FEATURES (0xBFEBFBFF) /* XXX Intel i7 */ 73193323Sed 74193323Sed/* Number of i/o intr entries */ 75193323Sed#define MPEII_MAX_IRQ 16 76193323Sed 77193323Sed/* Bus entry defines */ 78193323Sed#define MPE_NUM_BUSES 2 79193323Sed#define MPE_BUSNAME_LEN 6 80193323Sed#define MPE_BUSNAME_ISA "ISA " 81193323Sed#define MPE_BUSNAME_PCI "PCI " 82193323Sed 83193323Sedstatic void *oem_tbl_start; 84193574Sedstatic int oem_tbl_size; 85193323Sed 86193323Sedstatic uint8_t 87193323Sedmpt_compute_checksum(void *base, size_t len) 88193323Sed{ 89193323Sed uint8_t *bytes; 90193323Sed uint8_t sum; 91193323Sed 92194178Sed for(bytes = base, sum = 0; len > 0; len--) { 93193323Sed sum += *bytes++; 94201360Srdivacky } 95193323Sed 96193323Sed return (256 - sum); 97193323Sed} 98193323Sed 99201360Srdivackystatic void 100201360Srdivackympt_build_mpfp(mpfps_t mpfp, vm_paddr_t gpa) 101201360Srdivacky{ 102201360Srdivacky 103201360Srdivacky memset(mpfp, 0, sizeof(*mpfp)); 104201360Srdivacky memcpy(mpfp->signature, MPFP_SIG, 4); 105201360Srdivacky mpfp->pap = gpa + sizeof(*mpfp); 106201360Srdivacky mpfp->length = 1; 107201360Srdivacky mpfp->spec_rev = MP_SPECREV; 108201360Srdivacky mpfp->checksum = mpt_compute_checksum(mpfp, sizeof(*mpfp)); 109201360Srdivacky} 110201360Srdivacky 111193323Sedstatic void 112193323Sedmpt_build_mpch(mpcth_t mpch) 113193323Sed{ 114194178Sed 115193323Sed memset(mpch, 0, sizeof(*mpch)); 116193574Sed memcpy(mpch->signature, MPCH_SIG, 4); 117193574Sed mpch->spec_rev = MP_SPECREV; 118193574Sed memcpy(mpch->oem_id, MPCH_OEMID, MPCH_OEMID_LEN); 119193574Sed memcpy(mpch->product_id, MPCH_PRODID, MPCH_PRODID_LEN); 120193323Sed mpch->apic_address = LAPIC_PADDR; 121193323Sed} 122193323Sed 123193323Sedstatic void 124193323Sedmpt_build_proc_entries(proc_entry_ptr mpep, int ncpu) 125193323Sed{ 126193323Sed int i; 127193323Sed 128193323Sed for (i = 0; i < ncpu; i++) { 129193323Sed memset(mpep, 0, sizeof(*mpep)); 130193574Sed mpep->type = MPCT_ENTRY_PROCESSOR; 131193574Sed mpep->apic_id = i; // XXX 132193574Sed mpep->apic_version = LAPIC_VERSION; 133193574Sed mpep->cpu_flags = PROCENTRY_FLAG_EN; 134193574Sed if (i == 0) 135193574Sed mpep->cpu_flags |= PROCENTRY_FLAG_BP; 136193574Sed mpep->cpu_signature = MPEP_SIG; 137193574Sed mpep->feature_flags = MPEP_FEATURES; 138193323Sed mpep++; 139193323Sed } 140193323Sed} 141193323Sed 142193323Sedstatic void 143193323Sedmpt_build_bus_entries(bus_entry_ptr mpeb) 144193323Sed{ 145193323Sed 146193323Sed memset(mpeb, 0, sizeof(*mpeb)); 147193323Sed mpeb->type = MPCT_ENTRY_BUS; 148193574Sed mpeb->bus_id = 0; 149193574Sed memcpy(mpeb->bus_type, MPE_BUSNAME_PCI, MPE_BUSNAME_LEN); 150193574Sed mpeb++; 151193574Sed 152193574Sed memset(mpeb, 0, sizeof(*mpeb)); 153193574Sed mpeb->type = MPCT_ENTRY_BUS; 154193574Sed mpeb->bus_id = 1; 155193574Sed memcpy(mpeb->bus_type, MPE_BUSNAME_ISA, MPE_BUSNAME_LEN); 156193323Sed} 157193323Sed 158193323Sedstatic void 159193323Sedmpt_build_ioapic_entries(io_apic_entry_ptr mpei, int id) 160193323Sed{ 161203954Srdivacky 162193323Sed memset(mpei, 0, sizeof(*mpei)); 163193323Sed mpei->type = MPCT_ENTRY_IOAPIC; 164193323Sed mpei->apic_id = id; 165193323Sed mpei->apic_version = IOAPIC_VERSION; 166193323Sed mpei->apic_flags = IOAPICENTRY_FLAG_EN; 167193323Sed mpei->apic_address = IOAPIC_PADDR; 168193323Sed} 169193574Sed 170193574Sedstatic void 171193323Sedmpt_build_ioint_entries(int_entry_ptr mpie, int num_pins, int id) 172193323Sed{ 173193323Sed int pin; 174193323Sed 175193323Sed /* 176193323Sed * The following config is taken from kernel mptable.c 177193323Sed * mptable_parse_default_config_ints(...), for now 178193323Sed * just use the default config, tweek later if needed. 179194178Sed */ 180193323Sed 181193574Sed /* Run through all 16 pins. */ 182193323Sed for (pin = 0; pin < num_pins; pin++) { 183193323Sed memset(mpie, 0, sizeof(*mpie)); 184193323Sed mpie->type = MPCT_ENTRY_INT; 185193323Sed mpie->src_bus_id = 1; 186193323Sed mpie->dst_apic_id = id; 187193323Sed 188193323Sed /* 189193323Sed * All default configs route IRQs from bus 0 to the first 16 190194178Sed * pins of the first I/O APIC with an APIC ID of 2. 191194178Sed */ 192193323Sed mpie->dst_apic_int = pin; 193193323Sed switch (pin) { 194193323Sed case 0: 195193574Sed /* Pin 0 is an ExtINT pin. */ 196193323Sed mpie->int_type = INTENTRY_TYPE_EXTINT; 197193323Sed break; 198193323Sed case 2: 199193323Sed /* IRQ 0 is routed to pin 2. */ 200193323Sed mpie->int_type = INTENTRY_TYPE_INT; 201193323Sed mpie->src_bus_irq = 0; 202193323Sed break; 203193323Sed case 5: 204193323Sed case 10: 205193323Sed case 11: 206193323Sed /* 207193323Sed * PCI Irqs set to level triggered. 208193574Sed */ 209193323Sed mpie->int_flags = INTENTRY_FLAGS_TRIGGER_LEVEL; 210193323Sed mpie->src_bus_id = 0; 211193323Sed /* fall through.. */ 212193323Sed default: 213193323Sed /* All other pins are identity mapped. */ 214193323Sed mpie->int_type = INTENTRY_TYPE_INT; 215193574Sed mpie->src_bus_irq = pin; 216193323Sed break; 217193323Sed } 218193323Sed mpie++; 219193323Sed } 220193323Sed 221193323Sed} 222193323Sed 223193323Sedvoid 224193323Sedmptable_add_oemtbl(void *tbl, int tblsz) 225193323Sed{ 226193323Sed 227193323Sed oem_tbl_start = tbl; 228193323Sed oem_tbl_size = tblsz; 229193323Sed} 230193323Sed 231193323Sedint 232193323Sedmptable_build(struct vmctx *ctx, int ncpu) 233193323Sed{ 234193323Sed mpcth_t mpch; 235193323Sed bus_entry_ptr mpeb; 236193323Sed io_apic_entry_ptr mpei; 237193323Sed proc_entry_ptr mpep; 238193323Sed mpfps_t mpfp; 239193323Sed int_entry_ptr mpie; 240193323Sed char *curraddr; 241193323Sed char *startaddr; 242193323Sed 243193323Sed startaddr = paddr_guest2host(ctx, MPTABLE_BASE, MPTABLE_MAX_LENGTH); 244193323Sed if (startaddr == NULL) { 245193323Sed printf("mptable requires mapped mem\n"); 246198090Srdivacky return (ENOMEM); 247198090Srdivacky } 248198090Srdivacky 249198090Srdivacky curraddr = startaddr; 250198090Srdivacky mpfp = (mpfps_t)curraddr; 251198090Srdivacky mpt_build_mpfp(mpfp, MPTABLE_BASE); 252193323Sed curraddr += sizeof(*mpfp); 253205218Srdivacky 254193323Sed mpch = (mpcth_t)curraddr; 255193323Sed mpt_build_mpch(mpch); 256193323Sed curraddr += sizeof(*mpch); 257193323Sed 258193323Sed mpep = (proc_entry_ptr)curraddr; 259193323Sed mpt_build_proc_entries(mpep, ncpu); 260193323Sed curraddr += sizeof(*mpep) * ncpu; 261193323Sed mpch->entry_count += ncpu; 262193323Sed 263193323Sed mpeb = (bus_entry_ptr) curraddr; 264193323Sed mpt_build_bus_entries(mpeb); 265193323Sed curraddr += sizeof(*mpeb) * MPE_NUM_BUSES; 266193323Sed mpch->entry_count += MPE_NUM_BUSES; 267193323Sed 268193323Sed mpei = (io_apic_entry_ptr)curraddr; 269193323Sed mpt_build_ioapic_entries(mpei, 0); 270193323Sed curraddr += sizeof(*mpei); 271193323Sed mpch->entry_count++; 272193323Sed 273193323Sed mpie = (int_entry_ptr) curraddr; 274193323Sed mpt_build_ioint_entries(mpie, MPEII_MAX_IRQ, 0); 275193323Sed curraddr += sizeof(*mpie) * MPEII_MAX_IRQ; 276193323Sed mpch->entry_count += MPEII_MAX_IRQ; 277193323Sed 278193323Sed if (oem_tbl_start) { 279193323Sed mpch->oem_table_pointer = curraddr - startaddr + MPTABLE_BASE; 280193323Sed mpch->oem_table_size = oem_tbl_size; 281193323Sed memcpy(curraddr, oem_tbl_start, oem_tbl_size); 282193323Sed } 283193323Sed 284193323Sed mpch->base_table_length = curraddr - (char *)mpch; 285193323Sed mpch->checksum = mpt_compute_checksum(mpch, mpch->base_table_length); 286193323Sed 287193323Sed return (0); 288193323Sed} 289198090Srdivacky