2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4 * Copyright (c) 2012 NetApp, Inc.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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.
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
31 #include <sys/cdefs.h>
32 __FBSDID("$FreeBSD$");
34 #include <sys/types.h>
35 #include <sys/errno.h>
36 #include <x86/mptable.h>
47 #define MPTABLE_BASE 0xE0000
49 /* floating pointer length + maximum length of configuration table */
50 #define MPTABLE_MAX_LENGTH (65536 + 16)
52 #define LAPIC_PADDR 0xFEE00000
53 #define LAPIC_VERSION 16
55 #define IOAPIC_PADDR 0xFEC00000
56 #define IOAPIC_VERSION 0x11
59 #define MPFP_SIG "_MP_"
61 /* Configuration header defines */
62 #define MPCH_SIG "PCMP"
63 #define MPCH_OEMID "BHyVe "
64 #define MPCH_OEMID_LEN 8
65 #define MPCH_PRODID "Hypervisor "
66 #define MPCH_PRODID_LEN 12
68 /* Processor entry defines */
69 #define MPEP_SIG_FAMILY 6 /* XXX bhyve should supply this */
70 #define MPEP_SIG_MODEL 26
71 #define MPEP_SIG_STEPPING 5
73 ((MPEP_SIG_FAMILY << 8) | \
74 (MPEP_SIG_MODEL << 4) | \
77 #define MPEP_FEATURES (0xBFEBFBFF) /* XXX Intel i7 */
79 /* Number of local intr entries */
80 #define MPEII_NUM_LOCAL_IRQ 2
82 /* Bus entry defines */
83 #define MPE_NUM_BUSES 2
84 #define MPE_BUSNAME_LEN 6
85 #define MPE_BUSNAME_ISA "ISA "
86 #define MPE_BUSNAME_PCI "PCI "
88 static void *oem_tbl_start
;
89 static int oem_tbl_size
;
92 mpt_compute_checksum(void *base
, size_t len
)
97 for(bytes
= base
, sum
= 0; len
> 0; len
--) {
105 mpt_build_mpfp(mpfps_t mpfp
, vm_paddr_t gpa
)
108 memset(mpfp
, 0, sizeof(*mpfp
));
109 memcpy(mpfp
->signature
, MPFP_SIG
, 4);
110 mpfp
->pap
= gpa
+ sizeof(*mpfp
);
112 mpfp
->spec_rev
= MP_SPECREV
;
113 mpfp
->checksum
= mpt_compute_checksum(mpfp
, sizeof(*mpfp
));
117 mpt_build_mpch(mpcth_t mpch
)
120 memset(mpch
, 0, sizeof(*mpch
));
121 memcpy(mpch
->signature
, MPCH_SIG
, 4);
122 mpch
->spec_rev
= MP_SPECREV
;
123 memcpy(mpch
->oem_id
, MPCH_OEMID
, MPCH_OEMID_LEN
);
124 memcpy(mpch
->product_id
, MPCH_PRODID
, MPCH_PRODID_LEN
);
125 mpch
->apic_address
= LAPIC_PADDR
;
129 mpt_build_proc_entries(proc_entry_ptr mpep
, int ncpu
)
133 for (i
= 0; i
< ncpu
; i
++) {
134 memset(mpep
, 0, sizeof(*mpep
));
135 mpep
->type
= MPCT_ENTRY_PROCESSOR
;
136 mpep
->apic_id
= i
; // XXX
137 mpep
->apic_version
= LAPIC_VERSION
;
138 mpep
->cpu_flags
= PROCENTRY_FLAG_EN
;
140 mpep
->cpu_flags
|= PROCENTRY_FLAG_BP
;
141 mpep
->cpu_signature
= MPEP_SIG
;
142 mpep
->feature_flags
= MPEP_FEATURES
;
148 mpt_build_localint_entries(int_entry_ptr mpie
)
151 /* Hardcode LINT0 as ExtINT on all CPUs. */
152 memset(mpie
, 0, sizeof(*mpie
));
153 mpie
->type
= MPCT_ENTRY_LOCAL_INT
;
154 mpie
->int_type
= INTENTRY_TYPE_EXTINT
;
155 mpie
->int_flags
= INTENTRY_FLAGS_POLARITY_CONFORM
|
156 INTENTRY_FLAGS_TRIGGER_CONFORM
;
157 mpie
->dst_apic_id
= 0xff;
158 mpie
->dst_apic_int
= 0;
161 /* Hardcode LINT1 as NMI on all CPUs. */
162 memset(mpie
, 0, sizeof(*mpie
));
163 mpie
->type
= MPCT_ENTRY_LOCAL_INT
;
164 mpie
->int_type
= INTENTRY_TYPE_NMI
;
165 mpie
->int_flags
= INTENTRY_FLAGS_POLARITY_CONFORM
|
166 INTENTRY_FLAGS_TRIGGER_CONFORM
;
167 mpie
->dst_apic_id
= 0xff;
168 mpie
->dst_apic_int
= 1;
172 mpt_build_bus_entries(bus_entry_ptr mpeb
)
175 memset(mpeb
, 0, sizeof(*mpeb
));
176 mpeb
->type
= MPCT_ENTRY_BUS
;
178 memcpy(mpeb
->bus_type
, MPE_BUSNAME_PCI
, MPE_BUSNAME_LEN
);
181 memset(mpeb
, 0, sizeof(*mpeb
));
182 mpeb
->type
= MPCT_ENTRY_BUS
;
184 memcpy(mpeb
->bus_type
, MPE_BUSNAME_ISA
, MPE_BUSNAME_LEN
);
188 mpt_build_ioapic_entries(io_apic_entry_ptr mpei
, int id
)
191 memset(mpei
, 0, sizeof(*mpei
));
192 mpei
->type
= MPCT_ENTRY_IOAPIC
;
194 mpei
->apic_version
= IOAPIC_VERSION
;
195 mpei
->apic_flags
= IOAPICENTRY_FLAG_EN
;
196 mpei
->apic_address
= IOAPIC_PADDR
;
200 mpt_count_ioint_entries(void)
205 for (bus
= 0; bus
<= PCI_BUSMAX
; bus
++)
206 count
+= pci_count_lintr(bus
);
209 * Always include entries for the first 16 pins along with a entry
210 * for each active PCI INTx pin.
216 mpt_generate_pci_int(int bus
, int slot
, int pin
, int pirq_pin __unused
,
217 int ioapic_irq
, void *arg
)
219 int_entry_ptr
*mpiep
, mpie
;
223 memset(mpie
, 0, sizeof(*mpie
));
226 * This is always after another I/O interrupt entry, so cheat
227 * and fetch the I/O APIC ID from the prior entry.
229 mpie
->type
= MPCT_ENTRY_INT
;
230 mpie
->int_type
= INTENTRY_TYPE_INT
;
231 mpie
->src_bus_id
= bus
;
232 mpie
->src_bus_irq
= slot
<< 2 | (pin
- 1);
233 mpie
->dst_apic_id
= mpie
[-1].dst_apic_id
;
234 mpie
->dst_apic_int
= ioapic_irq
;
240 mpt_build_ioint_entries(int_entry_ptr mpie
, int id
)
245 * The following config is taken from kernel mptable.c
246 * mptable_parse_default_config_ints(...), for now
247 * just use the default config, tweek later if needed.
250 /* First, generate the first 16 pins. */
251 for (pin
= 0; pin
< 16; pin
++) {
252 memset(mpie
, 0, sizeof(*mpie
));
253 mpie
->type
= MPCT_ENTRY_INT
;
254 mpie
->src_bus_id
= 1;
255 mpie
->dst_apic_id
= id
;
258 * All default configs route IRQs from bus 0 to the first 16
259 * pins of the first I/O APIC with an APIC ID of 2.
261 mpie
->dst_apic_int
= pin
;
264 /* Pin 0 is an ExtINT pin. */
265 mpie
->int_type
= INTENTRY_TYPE_EXTINT
;
268 /* IRQ 0 is routed to pin 2. */
269 mpie
->int_type
= INTENTRY_TYPE_INT
;
270 mpie
->src_bus_irq
= 0;
273 /* ACPI SCI is level triggered and active-lo. */
274 mpie
->int_flags
= INTENTRY_FLAGS_POLARITY_ACTIVELO
|
275 INTENTRY_FLAGS_TRIGGER_LEVEL
;
276 mpie
->int_type
= INTENTRY_TYPE_INT
;
277 mpie
->src_bus_irq
= SCI_INT
;
280 /* All other pins are identity mapped. */
281 mpie
->int_type
= INTENTRY_TYPE_INT
;
282 mpie
->src_bus_irq
= pin
;
288 /* Next, generate entries for any PCI INTx interrupts. */
289 for (bus
= 0; bus
<= PCI_BUSMAX
; bus
++)
290 pci_walk_lintr(bus
, mpt_generate_pci_int
, &mpie
);
294 mptable_add_oemtbl(void *tbl
, int tblsz
)
298 oem_tbl_size
= tblsz
;
302 mptable_build(struct vmctx
*ctx
, int ncpu
)
306 io_apic_entry_ptr mpei
;
314 startaddr
= paddr_guest2host(ctx
, MPTABLE_BASE
, MPTABLE_MAX_LENGTH
);
315 if (startaddr
== NULL
) {
316 EPRINTLN("mptable requires mapped mem");
321 * There is no way to advertise multiple PCI hierarchies via MPtable
322 * so require that there is no PCI hierarchy with a non-zero bus
325 for (bus
= 1; bus
<= PCI_BUSMAX
; bus
++) {
326 if (pci_bus_configured(bus
)) {
327 EPRINTLN("MPtable is incompatible with "
328 "multiple PCI hierarchies.");
329 EPRINTLN("MPtable generation can be disabled "
330 "by passing the -Y option to bhyve(8).");
335 curraddr
= startaddr
;
336 mpfp
= (mpfps_t
)curraddr
;
337 mpt_build_mpfp(mpfp
, MPTABLE_BASE
);
338 curraddr
+= sizeof(*mpfp
);
340 mpch
= (mpcth_t
)curraddr
;
341 mpt_build_mpch(mpch
);
342 curraddr
+= sizeof(*mpch
);
344 mpep
= (proc_entry_ptr
)curraddr
;
345 mpt_build_proc_entries(mpep
, ncpu
);
346 curraddr
+= sizeof(*mpep
) * ncpu
;
347 mpch
->entry_count
+= ncpu
;
349 mpeb
= (bus_entry_ptr
) curraddr
;
350 mpt_build_bus_entries(mpeb
);
351 curraddr
+= sizeof(*mpeb
) * MPE_NUM_BUSES
;
352 mpch
->entry_count
+= MPE_NUM_BUSES
;
354 mpei
= (io_apic_entry_ptr
)curraddr
;
355 mpt_build_ioapic_entries(mpei
, 0);
356 curraddr
+= sizeof(*mpei
);
359 mpie
= (int_entry_ptr
) curraddr
;
360 ioints
= mpt_count_ioint_entries();
361 mpt_build_ioint_entries(mpie
, 0);
362 curraddr
+= sizeof(*mpie
) * ioints
;
363 mpch
->entry_count
+= ioints
;
365 mpie
= (int_entry_ptr
)curraddr
;
366 mpt_build_localint_entries(mpie
);
367 curraddr
+= sizeof(*mpie
) * MPEII_NUM_LOCAL_IRQ
;
368 mpch
->entry_count
+= MPEII_NUM_LOCAL_IRQ
;
371 mpch
->oem_table_pointer
= curraddr
- startaddr
+ MPTABLE_BASE
;
372 mpch
->oem_table_size
= oem_tbl_size
;
373 memcpy(curraddr
, oem_tbl_start
, oem_tbl_size
);
376 mpch
->base_table_length
= curraddr
- (char *)mpch
;
377 mpch
->checksum
= mpt_compute_checksum(mpch
, mpch
->base_table_length
);