1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2012 NetApp, Inc. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 * 28 * $FreeBSD$ 29 */ 30 31 #include <sys/cdefs.h> 32 __FBSDID("$FreeBSD$"); 33 34 #include <sys/types.h> 35 #include <sys/errno.h> 36 #include <x86/mptable.h> 37 38 #include <stdio.h> 39 #include <string.h> 40 41 #include "acpi.h" 42 #include "bhyverun.h" 43 #include "mptbl.h" 44 #include "pci_emul.h" 45 46 #define MPTABLE_BASE 0xE0000 47 48 /* floating pointer length + maximum length of configuration table */ 49 #define MPTABLE_MAX_LENGTH (65536 + 16) 50 51 #define LAPIC_PADDR 0xFEE00000 52 #define LAPIC_VERSION 16 53 54 #define IOAPIC_PADDR 0xFEC00000 55 #define IOAPIC_VERSION 0x11 56 57 #define MP_SPECREV 4 58 #define MPFP_SIG "_MP_" 59 60 /* Configuration header defines */ 61 #define MPCH_SIG "PCMP" 62 #define MPCH_OEMID "BHyVe " 63 #define MPCH_OEMID_LEN 8 64 #define MPCH_PRODID "Hypervisor " 65 #define MPCH_PRODID_LEN 12 66 67 /* Processor entry defines */ 68 #define MPEP_SIG_FAMILY 6 /* XXX bhyve should supply this */ 69 #define MPEP_SIG_MODEL 26 70 #define MPEP_SIG_STEPPING 5 71 #define MPEP_SIG \ 72 ((MPEP_SIG_FAMILY << 8) | \ 73 (MPEP_SIG_MODEL << 4) | \ 74 (MPEP_SIG_STEPPING)) 75 76 #define MPEP_FEATURES (0xBFEBFBFF) /* XXX Intel i7 */ 77 78 /* Number of local intr entries */ 79 #define MPEII_NUM_LOCAL_IRQ 2 80 81 /* Bus entry defines */ 82 #define MPE_NUM_BUSES 2 83 #define MPE_BUSNAME_LEN 6 84 #define MPE_BUSNAME_ISA "ISA " 85 #define MPE_BUSNAME_PCI "PCI " 86 87 static void *oem_tbl_start; 88 static int oem_tbl_size; 89 90 static uint8_t 91 mpt_compute_checksum(void *base, size_t len) 92 { 93 uint8_t *bytes; 94 uint8_t sum; 95 96 for(bytes = base, sum = 0; len > 0; len--) { 97 sum += *bytes++; 98 } 99 100 return (256 - sum); 101 } 102 103 static void 104 mpt_build_mpfp(mpfps_t mpfp, vm_paddr_t gpa) 105 { 106 107 memset(mpfp, 0, sizeof(*mpfp)); 108 memcpy(mpfp->signature, MPFP_SIG, 4); 109 mpfp->pap = gpa + sizeof(*mpfp); 110 mpfp->length = 1; 111 mpfp->spec_rev = MP_SPECREV; 112 mpfp->checksum = mpt_compute_checksum(mpfp, sizeof(*mpfp)); 113 } 114 115 static void 116 mpt_build_mpch(mpcth_t mpch) 117 { 118 119 memset(mpch, 0, sizeof(*mpch)); 120 memcpy(mpch->signature, MPCH_SIG, 4); 121 mpch->spec_rev = MP_SPECREV; 122 memcpy(mpch->oem_id, MPCH_OEMID, MPCH_OEMID_LEN); 123 memcpy(mpch->product_id, MPCH_PRODID, MPCH_PRODID_LEN); 124 mpch->apic_address = LAPIC_PADDR; 125 } 126 127 static void 128 mpt_build_proc_entries(proc_entry_ptr mpep, int ncpu) 129 { 130 int i; 131 132 for (i = 0; i < ncpu; i++) { 133 memset(mpep, 0, sizeof(*mpep)); 134 mpep->type = MPCT_ENTRY_PROCESSOR; 135 mpep->apic_id = i; // XXX 136 mpep->apic_version = LAPIC_VERSION; 137 mpep->cpu_flags = PROCENTRY_FLAG_EN; 138 if (i == 0) 139 mpep->cpu_flags |= PROCENTRY_FLAG_BP; 140 mpep->cpu_signature = MPEP_SIG; 141 mpep->feature_flags = MPEP_FEATURES; 142 mpep++; 143 } 144 } 145 146 static void 147 mpt_build_localint_entries(int_entry_ptr mpie) 148 { 149 150 /* Hardcode LINT0 as ExtINT on all CPUs. */ 151 memset(mpie, 0, sizeof(*mpie)); 152 mpie->type = MPCT_ENTRY_LOCAL_INT; 153 mpie->int_type = INTENTRY_TYPE_EXTINT; 154 mpie->int_flags = INTENTRY_FLAGS_POLARITY_CONFORM | 155 INTENTRY_FLAGS_TRIGGER_CONFORM; 156 mpie->dst_apic_id = 0xff; 157 mpie->dst_apic_int = 0; 158 mpie++; 159 160 /* Hardcode LINT1 as NMI on all CPUs. */ 161 memset(mpie, 0, sizeof(*mpie)); 162 mpie->type = MPCT_ENTRY_LOCAL_INT; 163 mpie->int_type = INTENTRY_TYPE_NMI; 164 mpie->int_flags = INTENTRY_FLAGS_POLARITY_CONFORM | 165 INTENTRY_FLAGS_TRIGGER_CONFORM; 166 mpie->dst_apic_id = 0xff; 167 mpie->dst_apic_int = 1; 168 } 169 170 static void 171 mpt_build_bus_entries(bus_entry_ptr mpeb) 172 { 173 174 memset(mpeb, 0, sizeof(*mpeb)); 175 mpeb->type = MPCT_ENTRY_BUS; 176 mpeb->bus_id = 0; 177 memcpy(mpeb->bus_type, MPE_BUSNAME_PCI, MPE_BUSNAME_LEN); 178 mpeb++; 179 180 memset(mpeb, 0, sizeof(*mpeb)); 181 mpeb->type = MPCT_ENTRY_BUS; 182 mpeb->bus_id = 1; 183 memcpy(mpeb->bus_type, MPE_BUSNAME_ISA, MPE_BUSNAME_LEN); 184 } 185 186 static void 187 mpt_build_ioapic_entries(io_apic_entry_ptr mpei, int id) 188 { 189 190 memset(mpei, 0, sizeof(*mpei)); 191 mpei->type = MPCT_ENTRY_IOAPIC; 192 mpei->apic_id = id; 193 mpei->apic_version = IOAPIC_VERSION; 194 mpei->apic_flags = IOAPICENTRY_FLAG_EN; 195 mpei->apic_address = IOAPIC_PADDR; 196 } 197 198 static int 199 mpt_count_ioint_entries(void) 200 { 201 int bus, count; 202 203 count = 0; 204 for (bus = 0; bus <= PCI_BUSMAX; bus++) 205 count += pci_count_lintr(bus); 206 207 /* 208 * Always include entries for the first 16 pins along with a entry 209 * for each active PCI INTx pin. 210 */ 211 return (16 + count); 212 } 213 214 static void 215 mpt_generate_pci_int(int bus, int slot, int pin, int pirq_pin, int ioapic_irq, 216 void *arg) 217 { 218 int_entry_ptr *mpiep, mpie; 219 220 mpiep = arg; 221 mpie = *mpiep; 222 memset(mpie, 0, sizeof(*mpie)); 223 224 /* 225 * This is always after another I/O interrupt entry, so cheat 226 * and fetch the I/O APIC ID from the prior entry. 227 */ 228 mpie->type = MPCT_ENTRY_INT; 229 mpie->int_type = INTENTRY_TYPE_INT; 230 mpie->src_bus_id = bus; 231 mpie->src_bus_irq = slot << 2 | (pin - 1); 232 mpie->dst_apic_id = mpie[-1].dst_apic_id; 233 mpie->dst_apic_int = ioapic_irq; 234 235 *mpiep = mpie + 1; 236 } 237 238 static void 239 mpt_build_ioint_entries(int_entry_ptr mpie, int id) 240 { 241 int pin, bus; 242 243 /* 244 * The following config is taken from kernel mptable.c 245 * mptable_parse_default_config_ints(...), for now 246 * just use the default config, tweek later if needed. 247 */ 248 249 /* First, generate the first 16 pins. */ 250 for (pin = 0; pin < 16; pin++) { 251 memset(mpie, 0, sizeof(*mpie)); 252 mpie->type = MPCT_ENTRY_INT; 253 mpie->src_bus_id = 1; 254 mpie->dst_apic_id = id; 255 256 /* 257 * All default configs route IRQs from bus 0 to the first 16 258 * pins of the first I/O APIC with an APIC ID of 2. 259 */ 260 mpie->dst_apic_int = pin; 261 switch (pin) { 262 case 0: 263 /* Pin 0 is an ExtINT pin. */ 264 mpie->int_type = INTENTRY_TYPE_EXTINT; 265 break; 266 case 2: 267 /* IRQ 0 is routed to pin 2. */ 268 mpie->int_type = INTENTRY_TYPE_INT; 269 mpie->src_bus_irq = 0; 270 break; 271 case SCI_INT: 272 /* ACPI SCI is level triggered and active-lo. */ 273 mpie->int_flags = INTENTRY_FLAGS_POLARITY_ACTIVELO | 274 INTENTRY_FLAGS_TRIGGER_LEVEL; 275 mpie->int_type = INTENTRY_TYPE_INT; 276 mpie->src_bus_irq = SCI_INT; 277 break; 278 default: 279 /* All other pins are identity mapped. */ 280 mpie->int_type = INTENTRY_TYPE_INT; 281 mpie->src_bus_irq = pin; 282 break; 283 } 284 mpie++; 285 } 286 287 /* Next, generate entries for any PCI INTx interrupts. */ 288 for (bus = 0; bus <= PCI_BUSMAX; bus++) 289 pci_walk_lintr(bus, mpt_generate_pci_int, &mpie); 290 } 291 292 void 293 mptable_add_oemtbl(void *tbl, int tblsz) 294 { 295 296 oem_tbl_start = tbl; 297 oem_tbl_size = tblsz; 298 } 299 300 int 301 mptable_build(struct vmctx *ctx, int ncpu) 302 { 303 mpcth_t mpch; 304 bus_entry_ptr mpeb; 305 io_apic_entry_ptr mpei; 306 proc_entry_ptr mpep; 307 mpfps_t mpfp; 308 int_entry_ptr mpie; 309 int ioints, bus; 310 char *curraddr; 311 char *startaddr; 312 313 startaddr = paddr_guest2host(ctx, MPTABLE_BASE, MPTABLE_MAX_LENGTH); 314 if (startaddr == NULL) { 315 fprintf(stderr, "mptable requires mapped mem\n"); 316 return (ENOMEM); 317 } 318 319 /* 320 * There is no way to advertise multiple PCI hierarchies via MPtable 321 * so require that there is no PCI hierarchy with a non-zero bus 322 * number. 323 */ 324 for (bus = 1; bus <= PCI_BUSMAX; bus++) { 325 if (pci_bus_configured(bus)) { 326 fprintf(stderr, "MPtable is incompatible with " 327 "multiple PCI hierarchies.\r\n"); 328 fprintf(stderr, "MPtable generation can be disabled " 329 "by passing the -Y option to bhyve(8).\r\n"); 330 return (EINVAL); 331 } 332 } 333 334 curraddr = startaddr; 335 mpfp = (mpfps_t)curraddr; 336 mpt_build_mpfp(mpfp, MPTABLE_BASE); 337 curraddr += sizeof(*mpfp); 338 339 mpch = (mpcth_t)curraddr; 340 mpt_build_mpch(mpch); 341 curraddr += sizeof(*mpch); 342 343 mpep = (proc_entry_ptr)curraddr; 344 mpt_build_proc_entries(mpep, ncpu); 345 curraddr += sizeof(*mpep) * ncpu; 346 mpch->entry_count += ncpu; 347 348 mpeb = (bus_entry_ptr) curraddr; 349 mpt_build_bus_entries(mpeb); 350 curraddr += sizeof(*mpeb) * MPE_NUM_BUSES; 351 mpch->entry_count += MPE_NUM_BUSES; 352 353 mpei = (io_apic_entry_ptr)curraddr; 354 mpt_build_ioapic_entries(mpei, 0); 355 curraddr += sizeof(*mpei); 356 mpch->entry_count++; 357 358 mpie = (int_entry_ptr) curraddr; 359 ioints = mpt_count_ioint_entries(); 360 mpt_build_ioint_entries(mpie, 0); 361 curraddr += sizeof(*mpie) * ioints; 362 mpch->entry_count += ioints; 363 364 mpie = (int_entry_ptr)curraddr; 365 mpt_build_localint_entries(mpie); 366 curraddr += sizeof(*mpie) * MPEII_NUM_LOCAL_IRQ; 367 mpch->entry_count += MPEII_NUM_LOCAL_IRQ; 368 369 if (oem_tbl_start) { 370 mpch->oem_table_pointer = curraddr - startaddr + MPTABLE_BASE; 371 mpch->oem_table_size = oem_tbl_size; 372 memcpy(curraddr, oem_tbl_start, oem_tbl_size); 373 } 374 375 mpch->base_table_length = curraddr - (char *)mpch; 376 mpch->checksum = mpt_compute_checksum(mpch, mpch->base_table_length); 377 378 return (0); 379 } 380