mirror of
https://git.FreeBSD.org/src.git
synced 2024-12-24 11:29:10 +00:00
Prefer x2apic mode when running inside a virtual machine.
Provide a tunable 'machdep.x2apic_desired' to let the administrator override the default behavior. Provide a read-only sysctl 'machdep.x2apic' to let the administrator know whether the kernel is using x2apic or legacy mmio to access local apic. Tested with Parallels Desktop 8 and bhyve hypervisors. Also tested running on bare metal Intel Xeon E5-2658. Obtained from: NetApp Discussed with: jhb, attilio, avg, grehan
This commit is contained in:
parent
e285ef8d28
commit
682b847ede
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/projects/bhyve/; revision=244282
@ -708,6 +708,8 @@ init_secondary(void)
|
||||
wrmsr(MSR_STAR, msr);
|
||||
wrmsr(MSR_SF_MASK, PSL_NT|PSL_T|PSL_I|PSL_C|PSL_D);
|
||||
|
||||
lapic_init_ap();
|
||||
|
||||
/* Disable local APIC just to be sure. */
|
||||
lapic_disable();
|
||||
|
||||
|
@ -209,6 +209,7 @@ int lapic_enable_pmc(void);
|
||||
void lapic_eoi(void);
|
||||
int lapic_id(void);
|
||||
void lapic_init(vm_paddr_t addr);
|
||||
void lapic_init_ap(void);
|
||||
int lapic_intr_pending(u_int vector);
|
||||
void lapic_ipi_raw(register_t icrlo, u_int dest);
|
||||
void lapic_ipi_vectored(u_int vector, int dest);
|
||||
|
@ -50,12 +50,14 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/proc.h>
|
||||
#include <sys/sched.h>
|
||||
#include <sys/smp.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/timeet.h>
|
||||
|
||||
#include <vm/vm.h>
|
||||
#include <vm/pmap.h>
|
||||
|
||||
#include <x86/apicreg.h>
|
||||
#include <machine/atomic.h>
|
||||
#include <machine/cpu.h>
|
||||
#include <machine/cputypes.h>
|
||||
#include <machine/frame.h>
|
||||
@ -158,7 +160,15 @@ volatile lapic_t *lapic;
|
||||
vm_paddr_t lapic_paddr;
|
||||
static u_long lapic_timer_divisor;
|
||||
static struct eventtimer lapic_et;
|
||||
|
||||
static int x2apic;
|
||||
SYSCTL_INT(_machdep, OID_AUTO, x2apic, CTLFLAG_RD, &x2apic, 0, "x2apic mode");
|
||||
|
||||
static int x2apic_desired = -1; /* enable only if running in a VM */
|
||||
TUNABLE_INT("machdep.x2apic_desired", &x2apic_desired);
|
||||
SYSCTL_INT(_machdep, OID_AUTO, x2apic_desired, CTLFLAG_RDTUN,
|
||||
&x2apic_desired, 0,
|
||||
"0 (disable), 1 (enable), -1 (leave it up to the kernel)");
|
||||
|
||||
static void lapic_enable(void);
|
||||
static void lapic_resume(struct pic *pic);
|
||||
@ -247,6 +257,17 @@ lvt_mode(struct lapic *la, u_int pin, uint32_t value)
|
||||
return (value);
|
||||
}
|
||||
|
||||
static void
|
||||
x2apic_init(void)
|
||||
{
|
||||
uint64_t apic_base;
|
||||
|
||||
apic_base = rdmsr(MSR_APICBASE);
|
||||
|
||||
if ((apic_base & APICBASE_X2APIC) == 0)
|
||||
wrmsr(MSR_APICBASE, apic_base | APICBASE_X2APIC);
|
||||
}
|
||||
|
||||
/*
|
||||
* Map the local APIC and setup necessary interrupt vectors.
|
||||
*/
|
||||
@ -256,9 +277,21 @@ lapic_init(vm_paddr_t addr)
|
||||
u_int regs[4];
|
||||
int i, arat;
|
||||
|
||||
if ((cpu_feature2 & CPUID2_X2APIC) != 0 &&
|
||||
(rdmsr(MSR_APICBASE) & APICBASE_X2APIC) != 0) {
|
||||
x2apic = 1;
|
||||
if ((cpu_feature2 & CPUID2_X2APIC) != 0) {
|
||||
if (rdmsr(MSR_APICBASE) & APICBASE_X2APIC)
|
||||
x2apic = 1;
|
||||
else if (x2apic_desired != 0) {
|
||||
/*
|
||||
* The default behavior is to enable x2apic only if
|
||||
* the kernel is executing inside a virtual machine.
|
||||
*/
|
||||
if (vm_guest != VM_GUEST_NO || x2apic_desired == 1)
|
||||
x2apic = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (x2apic) {
|
||||
x2apic_init();
|
||||
if (bootverbose)
|
||||
printf("Local APIC access using x2APIC MSRs\n");
|
||||
} else {
|
||||
@ -317,6 +350,14 @@ lapic_init(vm_paddr_t addr)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
lapic_init_ap(void)
|
||||
{
|
||||
|
||||
if (x2apic)
|
||||
x2apic_init();
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a local APIC instance.
|
||||
*/
|
||||
@ -934,9 +975,26 @@ static void
|
||||
lapic_set_icr(uint64_t value)
|
||||
{
|
||||
|
||||
if (x2apic)
|
||||
/*
|
||||
* Access to x2apic MSR registers is not a serializing condition.
|
||||
*
|
||||
* A number of IPI handlers (e.g. rendezvous, tlb shootdown)
|
||||
* depend on shared state in memory between the cpu that
|
||||
* originated the IPI and the cpus that are the target.
|
||||
*
|
||||
* Insert a memory barrier to ensure that changes to memory
|
||||
* are globally visible to the other cpus.
|
||||
*/
|
||||
if (x2apic) {
|
||||
/*
|
||||
* XXX
|
||||
* Intel's architecture spec seems to suggest that an
|
||||
* "sfence" should be sufficient here but empirically
|
||||
* an "mfence" is required to do the job.
|
||||
*/
|
||||
mb();
|
||||
wrmsr(MSR_APIC_ICR, value);
|
||||
else {
|
||||
} else {
|
||||
lapic->icr_hi = value >> 32;
|
||||
lapic->icr_lo = value;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user