mptbl.c revision 259301
118334Speter/*- 252284Sobrien * Copyright (c) 2012 NetApp, Inc. 318334Speter * All rights reserved. 450397Sobrien * 518334Speter * Redistribution and use in source and binary forms, with or without 618334Speter * modification, are permitted provided that the following conditions 718334Speter * are met: 818334Speter * 1. Redistributions of source code must retain the above copyright 918334Speter * notice, this list of conditions and the following disclaimer. 1018334Speter * 2. Redistributions in binary form must reproduce the above copyright 1118334Speter * notice, this list of conditions and the following disclaimer in the 1218334Speter * documentation and/or other materials provided with the distribution. 1318334Speter * 1418334Speter * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND 1518334Speter * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1618334Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1718334Speter * ARE DISCLAIMED. IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE 1818334Speter * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1918334Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2018334Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2118334Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2218334Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2318334Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2450397Sobrien * SUCH DAMAGE. 2518334Speter * 2618334Speter * $FreeBSD: stable/10/usr.sbin/bhyve/mptbl.c 259301 2013-12-13 06:59:18Z grehan $ 2750397Sobrien */ 2818334Speter 2918334Speter#include <sys/cdefs.h> 3018334Speter__FBSDID("$FreeBSD: stable/10/usr.sbin/bhyve/mptbl.c 259301 2013-12-13 06:59:18Z grehan $"); 3118334Speter 3250397Sobrien#include <sys/types.h> 3350397Sobrien#include <sys/errno.h> 3418334Speter#include <x86/mptable.h> 3518334Speter 3618334Speter#include <stdio.h> 3718334Speter#include <string.h> 3818334Speter 3918334Speter#include "bhyverun.h" 4018334Speter#include "mptbl.h" 4118334Speter 4250397Sobrien#define MPTABLE_BASE 0xF0000 4318334Speter 4450397Sobrien/* floating pointer length + maximum length of configuration table */ 4550397Sobrien#define MPTABLE_MAX_LENGTH (65536 + 16) 4650397Sobrien 4750397Sobrien#define LAPIC_PADDR 0xFEE00000 4850397Sobrien#define LAPIC_VERSION 16 4950397Sobrien 5050397Sobrien#define IOAPIC_PADDR 0xFEC00000 5150397Sobrien#define IOAPIC_VERSION 0x11 5252284Sobrien 5350397Sobrien#define MP_SPECREV 4 5450397Sobrien#define MPFP_SIG "_MP_" 5550397Sobrien 5650397Sobrien/* Configuration header defines */ 5750397Sobrien#define MPCH_SIG "PCMP" 5850397Sobrien#define MPCH_OEMID "BHyVe " 5950397Sobrien#define MPCH_OEMID_LEN 8 6050397Sobrien#define MPCH_PRODID "Hypervisor " 6150397Sobrien#define MPCH_PRODID_LEN 12 6250397Sobrien 6350397Sobrien/* Processor entry defines */ 6450397Sobrien#define MPEP_SIG_FAMILY 6 /* XXX bhyve should supply this */ 6550397Sobrien#define MPEP_SIG_MODEL 26 6650397Sobrien#define MPEP_SIG_STEPPING 5 6750397Sobrien#define MPEP_SIG \ 6850397Sobrien ((MPEP_SIG_FAMILY << 8) | \ 6950397Sobrien (MPEP_SIG_MODEL << 4) | \ 7050397Sobrien (MPEP_SIG_STEPPING)) 7150397Sobrien 7250397Sobrien#define MPEP_FEATURES (0xBFEBFBFF) /* XXX Intel i7 */ 7350397Sobrien 7450397Sobrien/* Number of i/o intr entries */ 7550397Sobrien#define MPEII_MAX_IRQ 16 7650397Sobrien 7750397Sobrien/* Define processor entry struct since <x86/mptable.h> gets it wrong */ 7850397Sobrientypedef struct BPROCENTRY { 7950397Sobrien u_char type; 8050397Sobrien u_char apic_id; 8150397Sobrien u_char apic_version; 8250397Sobrien u_char cpu_flags; 8350397Sobrien uint32_t cpu_signature; 8450397Sobrien uint32_t feature_flags; 8550397Sobrien uint32_t reserved1; 8650397Sobrien uint32_t reserved2; 8750397Sobrien} *bproc_entry_ptr; 8850397SobrienCTASSERT(sizeof(struct BPROCENTRY) == 20); 8950397Sobrien 9050397Sobrien/* Bus entry defines */ 9150397Sobrien#define MPE_NUM_BUSES 2 9252284Sobrien#define MPE_BUSNAME_LEN 6 9352284Sobrien#define MPE_BUSNAME_ISA "ISA " 9452284Sobrien#define MPE_BUSNAME_PCI "PCI " 9552284Sobrien 9618334Speterstatic void *oem_tbl_start; 9718334Speterstatic int oem_tbl_size; 9818334Speter 9918334Speterstatic uint8_t 10018334Spetermpt_compute_checksum(void *base, size_t len) 10118334Speter{ 10218334Speter uint8_t *bytes; 10318334Speter uint8_t sum; 10418334Speter 10518334Speter for(bytes = base, sum = 0; len > 0; len--) { 10618334Speter sum += *bytes++; 10718334Speter } 10818334Speter 10918334Speter return (256 - sum); 11018334Speter} 11118334Speter 11218334Speterstatic void 11350397Sobrienmpt_build_mpfp(mpfps_t mpfp, vm_paddr_t gpa) 11418334Speter{ 11518334Speter 11618334Speter memset(mpfp, 0, sizeof(*mpfp)); 11718334Speter memcpy(mpfp->signature, MPFP_SIG, 4); 11818334Speter mpfp->pap = gpa + sizeof(*mpfp); 11918334Speter mpfp->length = 1; 12050397Sobrien mpfp->spec_rev = MP_SPECREV; 12118334Speter mpfp->checksum = mpt_compute_checksum(mpfp, sizeof(*mpfp)); 12218334Speter} 12318334Speter 12418334Speterstatic void 12518334Spetermpt_build_mpch(mpcth_t mpch) 12618334Speter{ 12750397Sobrien 12850397Sobrien memset(mpch, 0, sizeof(*mpch)); 12950397Sobrien memcpy(mpch->signature, MPCH_SIG, 4); 13052284Sobrien mpch->spec_rev = MP_SPECREV; 13152284Sobrien memcpy(mpch->oem_id, MPCH_OEMID, MPCH_OEMID_LEN); 13252284Sobrien memcpy(mpch->product_id, MPCH_PRODID, MPCH_PRODID_LEN); 13352284Sobrien mpch->apic_address = LAPIC_PADDR; 13418334Speter} 13518334Speter 13618334Speterstatic void 13752284Sobrienmpt_build_proc_entries(bproc_entry_ptr mpep, int ncpu) 13852284Sobrien{ 13918334Speter int i; 14052284Sobrien 14118334Speter for (i = 0; i < ncpu; i++) { 14252284Sobrien memset(mpep, 0, sizeof(*mpep)); 14352284Sobrien mpep->type = MPCT_ENTRY_PROCESSOR; 14452284Sobrien mpep->apic_id = i; // XXX 14552284Sobrien mpep->apic_version = LAPIC_VERSION; 14618334Speter mpep->cpu_flags = PROCENTRY_FLAG_EN; 14752284Sobrien if (i == 0) 14852284Sobrien mpep->cpu_flags |= PROCENTRY_FLAG_BP; 14918334Speter mpep->cpu_signature = MPEP_SIG; 15052284Sobrien mpep->feature_flags = MPEP_FEATURES; 15152284Sobrien mpep++; 15252284Sobrien } 15352284Sobrien} 15418334Speter 15552284Sobrienstatic void 15652284Sobrienmpt_build_bus_entries(bus_entry_ptr mpeb) 15752284Sobrien{ 15852284Sobrien 15952284Sobrien memset(mpeb, 0, sizeof(*mpeb)); 16052284Sobrien mpeb->type = MPCT_ENTRY_BUS; 16118334Speter mpeb->bus_id = 0; 16218334Speter memcpy(mpeb->bus_type, MPE_BUSNAME_PCI, MPE_BUSNAME_LEN); 16352284Sobrien mpeb++; 16418334Speter 16518334Speter memset(mpeb, 0, sizeof(*mpeb)); 16618334Speter mpeb->type = MPCT_ENTRY_BUS; 16750397Sobrien mpeb->bus_id = 1; 16818334Speter memcpy(mpeb->bus_type, MPE_BUSNAME_ISA, MPE_BUSNAME_LEN); 16918334Speter} 17018334Speter 17118334Speterstatic void 17218334Spetermpt_build_ioapic_entries(io_apic_entry_ptr mpei, int id) 17318334Speter{ 17418334Speter 17518334Speter memset(mpei, 0, sizeof(*mpei)); 17618334Speter mpei->type = MPCT_ENTRY_IOAPIC; 17718334Speter mpei->apic_id = id; 17818334Speter mpei->apic_version = IOAPIC_VERSION; 17918334Speter mpei->apic_flags = IOAPICENTRY_FLAG_EN; 18018334Speter mpei->apic_address = IOAPIC_PADDR; 18118334Speter} 18250397Sobrien 18318334Speterstatic void 18418334Spetermpt_build_ioint_entries(int_entry_ptr mpie, int num_pins, int id) 18518334Speter{ 18618334Speter int pin; 18718334Speter 18818334Speter /* 18918334Speter * The following config is taken from kernel mptable.c 19018334Speter * mptable_parse_default_config_ints(...), for now 19118334Speter * just use the default config, tweek later if needed. 19218334Speter */ 19318334Speter 19450397Sobrien /* Run through all 16 pins. */ 19518334Speter for (pin = 0; pin < num_pins; pin++) { 19618334Speter memset(mpie, 0, sizeof(*mpie)); 19718334Speter mpie->type = MPCT_ENTRY_INT; 19818334Speter mpie->src_bus_id = 1; 19918334Speter mpie->dst_apic_id = id; 20018334Speter 20118334Speter /* 20218334Speter * All default configs route IRQs from bus 0 to the first 16 20318334Speter * pins of the first I/O APIC with an APIC ID of 2. 20418334Speter */ 20518334Speter mpie->dst_apic_int = pin; 20650397Sobrien switch (pin) { 20718334Speter case 0: 20818334Speter /* Pin 0 is an ExtINT pin. */ 20918334Speter mpie->int_type = INTENTRY_TYPE_EXTINT; 21018334Speter break; 21118334Speter case 2: 21218334Speter /* IRQ 0 is routed to pin 2. */ 21318334Speter mpie->int_type = INTENTRY_TYPE_INT; 21418334Speter mpie->src_bus_irq = 0; 21518334Speter break; 21618334Speter case 5: 21718334Speter case 10: 21818334Speter case 11: 21918334Speter /* 22018334Speter * PCI Irqs set to level triggered. 22118334Speter */ 22218334Speter mpie->int_flags = INTENTRY_FLAGS_TRIGGER_LEVEL; 22318334Speter mpie->src_bus_id = 0; 22418334Speter /* fall through.. */ 22518334Speter default: 22618334Speter /* All other pins are identity mapped. */ 22750397Sobrien mpie->int_type = INTENTRY_TYPE_INT; 22818334Speter mpie->src_bus_irq = pin; 22918334Speter break; 23018334Speter } 23118334Speter mpie++; 23218334Speter } 23318334Speter 23418334Speter} 23518334Speter 23618334Spetervoid 23718334Spetermptable_add_oemtbl(void *tbl, int tblsz) 23818334Speter{ 23918334Speter 24018334Speter oem_tbl_start = tbl; 24118334Speter oem_tbl_size = tblsz; 24218334Speter} 24318334Speter 24418334Speterint 24518334Spetermptable_build(struct vmctx *ctx, int ncpu) 24618334Speter{ 24718334Speter mpcth_t mpch; 24818334Speter bus_entry_ptr mpeb; 24918334Speter io_apic_entry_ptr mpei; 25018334Speter bproc_entry_ptr mpep; 25118334Speter mpfps_t mpfp; 25218334Speter int_entry_ptr mpie; 25318334Speter char *curraddr; 25418334Speter char *startaddr; 25518334Speter 25618334Speter startaddr = paddr_guest2host(ctx, MPTABLE_BASE, MPTABLE_MAX_LENGTH); 25718334Speter if (startaddr == NULL) { 25818334Speter printf("mptable requires mapped mem\n"); 25918334Speter return (ENOMEM); 26018334Speter } 26118334Speter 26218334Speter curraddr = startaddr; 26318334Speter mpfp = (mpfps_t)curraddr; 26418334Speter mpt_build_mpfp(mpfp, MPTABLE_BASE); 26518334Speter curraddr += sizeof(*mpfp); 26618334Speter 26718334Speter mpch = (mpcth_t)curraddr; 26818334Speter mpt_build_mpch(mpch); 26918334Speter curraddr += sizeof(*mpch); 27018334Speter 27118334Speter mpep = (bproc_entry_ptr)curraddr; 27218334Speter mpt_build_proc_entries(mpep, ncpu); 27318334Speter curraddr += sizeof(*mpep) * ncpu; 27418334Speter mpch->entry_count += ncpu; 27518334Speter 27618334Speter mpeb = (bus_entry_ptr) curraddr; 27718334Speter mpt_build_bus_entries(mpeb); 27818334Speter curraddr += sizeof(*mpeb) * MPE_NUM_BUSES; 27918334Speter mpch->entry_count += MPE_NUM_BUSES; 28018334Speter 28118334Speter mpei = (io_apic_entry_ptr)curraddr; 28218334Speter mpt_build_ioapic_entries(mpei, 0); 28318334Speter curraddr += sizeof(*mpei); 28418334Speter mpch->entry_count++; 28518334Speter 28618334Speter mpie = (int_entry_ptr) curraddr; 28718334Speter mpt_build_ioint_entries(mpie, MPEII_MAX_IRQ, 0); 28818334Speter curraddr += sizeof(*mpie) * MPEII_MAX_IRQ; 28918334Speter mpch->entry_count += MPEII_MAX_IRQ; 29018334Speter 29150397Sobrien if (oem_tbl_start) { 29250397Sobrien mpch->oem_table_pointer = curraddr - startaddr + MPTABLE_BASE; 29350397Sobrien mpch->oem_table_size = oem_tbl_size; 29450397Sobrien memcpy(curraddr, oem_tbl_start, oem_tbl_size); 29550397Sobrien } 29650397Sobrien 29750397Sobrien mpch->base_table_length = curraddr - (char *)mpch; 29850397Sobrien mpch->checksum = mpt_compute_checksum(mpch, mpch->base_table_length); 29950397Sobrien 30050397Sobrien return (0); 30152284Sobrien} 30252284Sobrien