MFC 300654,300655,300708

300654
    hyperv/vmbus: Rework SynIC setup and teardown

    - Avoid bit fields.
    - Fix SINT setup (preserve required bits).

    MFC after:  1 week
    Sponsored by:       Microsoft OSTC
    Differential Revision:      https://reviews.freebsd.org/D6529

300655
    hyperv: Preserve required bits when disable Hypercall

    MFC after:  1 week
    Sponsored by:       Microsoft OSTC
    Differential Revision:      https://reviews.freebsd.org/D6530

300708
    hyperv: Rework guest id settings according to Hyper-V spec

    MFC after:  1 week
    Sponsored by:       Microsoft OSTC
    Differential Revision:      https://reviews.freebsd.org/D6553
This commit is contained in:
Sepherosa Ziehau 2016-06-23 08:09:44 +00:00
parent 555199507c
commit fdcca00bff
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/stable/10/; revision=302128
3 changed files with 132 additions and 102 deletions

View File

@ -52,34 +52,24 @@ __FBSDID("$FreeBSD$");
#define HYPERV_INTERFACE 0x31237648 /* HV#1 */
/*
* The guest OS needs to register the guest ID with the hypervisor.
* The guest ID is a 64 bit entity and the structure of this ID is
* specified in the Hyper-V specification:
*
* http://msdn.microsoft.com/en-us/library/windows/
* hardware/ff542653%28v=vs.85%29.aspx
*
* While the current guideline does not specify how FreeBSD guest ID(s)
* need to be generated, our plan is to publish the guidelines for
* FreeBSD and other guest operating systems that currently are hosted
* on Hyper-V. The implementation here conforms to this yet
* unpublished guidelines.
*
* Bit(s)
* 63 - Indicates if the OS is Open Source or not; 1 is Open Source
* 62:56 - Os Type: FreeBSD is 0x02
* 55:48 - Distro specific identification
* 47:16 - FreeBSD kernel version number
* 15:0 - Distro specific identification
*/
#define HYPERV_GUESTID_OSS (0x1ULL << 63)
#define HYPERV_GUESTID_FREEBSD (0x02ULL << 56)
#define HYPERV_GUESTID(id) \
(HYPERV_GUESTID_OSS | HYPERV_GUESTID_FREEBSD | \
(((uint64_t)(((id) & 0xff0000) >> 16)) << 48) |\
(((uint64_t)__FreeBSD_version) << 16) | \
((uint64_t)((id) & 0x00ffff)))
#define HYPERV_FREEBSD_BUILD 0ULL
#define HYPERV_FREEBSD_VERSION ((uint64_t)__FreeBSD_version)
#define HYPERV_FREEBSD_OSID 0ULL
#define MSR_HV_GUESTID_BUILD_FREEBSD \
(HYPERV_FREEBSD_BUILD & MSR_HV_GUESTID_BUILD_MASK)
#define MSR_HV_GUESTID_VERSION_FREEBSD \
((HYPERV_FREEBSD_VERSION << MSR_HV_GUESTID_VERSION_SHIFT) & \
MSR_HV_GUESTID_VERSION_MASK)
#define MSR_HV_GUESTID_OSID_FREEBSD \
((HYPERV_FREEBSD_OSID << MSR_HV_GUESTID_OSID_SHIFT) & \
MSR_HV_GUESTID_OSID_MASK)
#define MSR_HV_GUESTID_FREEBSD \
(MSR_HV_GUESTID_BUILD_FREEBSD | \
MSR_HV_GUESTID_VERSION_FREEBSD | \
MSR_HV_GUESTID_OSID_FREEBSD | \
MSR_HV_GUESTID_OSTYPE_FREEBSD)
struct hypercall_ctx {
void *hc_addr;
@ -321,8 +311,8 @@ hyperv_init(void *dummy __unused)
return;
}
/* Write guest id */
wrmsr(HV_X64_MSR_GUEST_OS_ID, HYPERV_GUESTID(0));
/* Set guest id */
wrmsr(MSR_HV_GUEST_OS_ID, MSR_HV_GUESTID_FREEBSD);
if (hyperv_features & HV_FEATURE_MSR_TIME_REFCNT) {
/* Register virtual timecount */
@ -390,11 +380,14 @@ SYSINIT(hypercall_ctor, SI_SUB_DRIVERS, SI_ORDER_FIRST, hypercall_create, NULL);
static void
hypercall_destroy(void *arg __unused)
{
uint64_t hc;
if (hypercall_context.hc_addr == NULL)
return;
/* Disable Hypercall */
wrmsr(MSR_HV_HYPERCALL, 0);
hc = rdmsr(MSR_HV_HYPERCALL);
wrmsr(MSR_HV_HYPERCALL, (hc & MSR_HV_HYPERCALL_RSVD_MASK));
hypercall_memfree();
if (bootverbose)

View File

@ -61,6 +61,7 @@ __FBSDID("$FreeBSD$");
#include <dev/hyperv/include/hyperv.h>
#include <dev/hyperv/vmbus/hv_vmbus_priv.h>
#include <dev/hyperv/vmbus/hyperv_reg.h>
#include <dev/hyperv/vmbus/vmbus_var.h>
#include <contrib/dev/acpica/include/acpi.h>
@ -210,100 +211,97 @@ static void
vmbus_synic_setup(void *xsc)
{
struct vmbus_softc *sc = xsc;
int cpu;
hv_vmbus_synic_simp simp;
hv_vmbus_synic_siefp siefp;
hv_vmbus_synic_scontrol sctrl;
hv_vmbus_synic_sint shared_sint;
cpu = PCPU_GET(cpuid);
int cpu = curcpu;
uint64_t val, orig;
uint32_t sint;
/*
* Setup the Synic's message page
* Save virtual processor id.
*/
simp.as_uint64_t = rdmsr(HV_X64_MSR_SIMP);
simp.u.simp_enabled = 1;
simp.u.base_simp_gpa =
VMBUS_PCPU_GET(sc, message_dma.hv_paddr, cpu) >> PAGE_SHIFT;
wrmsr(HV_X64_MSR_SIMP, simp.as_uint64_t);
VMBUS_PCPU_GET(sc, vcpuid, cpu) = rdmsr(MSR_HV_VP_INDEX);
/*
* Setup the Synic's event page
* Setup the SynIC message.
*/
siefp.as_uint64_t = rdmsr(HV_X64_MSR_SIEFP);
siefp.u.siefp_enabled = 1;
siefp.u.base_siefp_gpa =
VMBUS_PCPU_GET(sc, event_flag_dma.hv_paddr, cpu) >> PAGE_SHIFT;
wrmsr(HV_X64_MSR_SIEFP, siefp.as_uint64_t);
/*HV_SHARED_SINT_IDT_VECTOR + 0x20; */
shared_sint.as_uint64_t = 0;
shared_sint.u.vector = sc->vmbus_idtvec;
shared_sint.u.masked = FALSE;
shared_sint.u.auto_eoi = TRUE;
wrmsr(HV_X64_MSR_SINT0 + HV_VMBUS_MESSAGE_SINT,
shared_sint.as_uint64_t);
wrmsr(HV_X64_MSR_SINT0 + HV_VMBUS_TIMER_SINT,
shared_sint.as_uint64_t);
/* Enable the global synic bit */
sctrl.as_uint64_t = rdmsr(HV_X64_MSR_SCONTROL);
sctrl.u.enable = 1;
wrmsr(HV_X64_MSR_SCONTROL, sctrl.as_uint64_t);
orig = rdmsr(MSR_HV_SIMP);
val = MSR_HV_SIMP_ENABLE | (orig & MSR_HV_SIMP_RSVD_MASK) |
((VMBUS_PCPU_GET(sc, message_dma.hv_paddr, cpu) >> PAGE_SHIFT) <<
MSR_HV_SIMP_PGSHIFT);
wrmsr(MSR_HV_SIMP, val);
/*
* Set up the cpuid mapping from Hyper-V to FreeBSD.
* The array is indexed using FreeBSD cpuid.
* Setup the SynIC event flags.
*/
VMBUS_PCPU_GET(sc, vcpuid, cpu) = rdmsr(HV_X64_MSR_VP_INDEX);
orig = rdmsr(MSR_HV_SIEFP);
val = MSR_HV_SIEFP_ENABLE | (orig & MSR_HV_SIEFP_RSVD_MASK) |
((VMBUS_PCPU_GET(sc, event_flag_dma.hv_paddr, cpu) >> PAGE_SHIFT) <<
MSR_HV_SIEFP_PGSHIFT);
wrmsr(MSR_HV_SIEFP, val);
/*
* Configure and unmask SINT for message and event flags.
*/
sint = MSR_HV_SINT0 + HV_VMBUS_MESSAGE_SINT;
orig = rdmsr(sint);
val = sc->vmbus_idtvec | MSR_HV_SINT_AUTOEOI |
(orig & MSR_HV_SINT_RSVD_MASK);
wrmsr(sint, val);
/*
* Configure and unmask SINT for timer.
*/
sint = MSR_HV_SINT0 + HV_VMBUS_TIMER_SINT;
orig = rdmsr(sint);
val = sc->vmbus_idtvec | MSR_HV_SINT_AUTOEOI |
(orig & MSR_HV_SINT_RSVD_MASK);
wrmsr(sint, val);
/*
* All done; enable SynIC.
*/
orig = rdmsr(MSR_HV_SCONTROL);
val = MSR_HV_SCTRL_ENABLE | (orig & MSR_HV_SCTRL_RSVD_MASK);
wrmsr(MSR_HV_SCONTROL, val);
}
static void
vmbus_synic_teardown(void *arg)
{
hv_vmbus_synic_sint shared_sint;
hv_vmbus_synic_simp simp;
hv_vmbus_synic_siefp siefp;
shared_sint.as_uint64_t = rdmsr(
HV_X64_MSR_SINT0 + HV_VMBUS_MESSAGE_SINT);
shared_sint.u.masked = 1;
uint64_t orig;
uint32_t sint;
/*
* Disable the interrupt 0
* Disable SynIC.
*/
wrmsr(
HV_X64_MSR_SINT0 + HV_VMBUS_MESSAGE_SINT,
shared_sint.as_uint64_t);
shared_sint.as_uint64_t = rdmsr(
HV_X64_MSR_SINT0 + HV_VMBUS_TIMER_SINT);
shared_sint.u.masked = 1;
orig = rdmsr(MSR_HV_SCONTROL);
wrmsr(MSR_HV_SCONTROL, (orig & MSR_HV_SCTRL_RSVD_MASK));
/*
* Disable the interrupt 1
* Mask message and event flags SINT.
*/
wrmsr(
HV_X64_MSR_SINT0 + HV_VMBUS_TIMER_SINT,
shared_sint.as_uint64_t);
simp.as_uint64_t = rdmsr(HV_X64_MSR_SIMP);
simp.u.simp_enabled = 0;
simp.u.base_simp_gpa = 0;
sint = MSR_HV_SINT0 + HV_VMBUS_MESSAGE_SINT;
orig = rdmsr(sint);
wrmsr(sint, orig | MSR_HV_SINT_MASKED);
wrmsr(HV_X64_MSR_SIMP, simp.as_uint64_t);
/*
* Mask timer SINT.
*/
sint = MSR_HV_SINT0 + HV_VMBUS_TIMER_SINT;
orig = rdmsr(sint);
wrmsr(sint, orig | MSR_HV_SINT_MASKED);
siefp.as_uint64_t = rdmsr(HV_X64_MSR_SIEFP);
siefp.u.siefp_enabled = 0;
siefp.u.base_siefp_gpa = 0;
/*
* Teardown SynIC message.
*/
orig = rdmsr(MSR_HV_SIMP);
wrmsr(MSR_HV_SIMP, (orig & MSR_HV_SIMP_RSVD_MASK));
wrmsr(HV_X64_MSR_SIEFP, siefp.as_uint64_t);
/*
* Teardown SynIC event flags.
*/
orig = rdmsr(MSR_HV_SIEFP);
wrmsr(MSR_HV_SIEFP, (orig & MSR_HV_SIEFP_RSVD_MASK));
}
static int

View File

@ -29,9 +29,48 @@
#ifndef _HYPERV_REG_H_
#define _HYPERV_REG_H_
#define MSR_HV_GUEST_OS_ID 0x40000000
#define MSR_HV_GUESTID_BUILD_MASK 0xffffULL
#define MSR_HV_GUESTID_VERSION_MASK 0x0000ffffffff0000ULL
#define MSR_HV_GUESTID_VERSION_SHIFT 16
#define MSR_HV_GUESTID_OSID_MASK 0x00ff000000000000ULL
#define MSR_HV_GUESTID_OSID_SHIFT 48
#define MSR_HV_GUESTID_OSTYPE_MASK 0x7f00000000000000ULL
#define MSR_HV_GUESTID_OSTYPE_SHIFT 56
#define MSR_HV_GUESTID_OPENSRC 0x8000000000000000ULL
#define MSR_HV_GUESTID_OSTYPE_LINUX \
((0x01ULL << MSR_HV_GUESTID_OSTYPE_SHIFT) | MSR_HV_GUESTID_OPENSRC)
#define MSR_HV_GUESTID_OSTYPE_FREEBSD \
((0x02ULL << MSR_HV_GUESTID_OSTYPE_SHIFT) | MSR_HV_GUESTID_OPENSRC)
#define MSR_HV_HYPERCALL 0x40000001
#define MSR_HV_HYPERCALL_ENABLE 0x0001ULL
#define MSR_HV_HYPERCALL_RSVD_MASK 0x0ffeULL
#define MSR_HV_HYPERCALL_PGSHIFT 12
#define MSR_HV_VP_INDEX 0x40000002
#define MSR_HV_SCONTROL 0x40000080
#define MSR_HV_SCTRL_ENABLE 0x0001ULL
#define MSR_HV_SCTRL_RSVD_MASK 0xfffffffffffffffeULL
#define MSR_HV_SIEFP 0x40000082
#define MSR_HV_SIEFP_ENABLE 0x0001ULL
#define MSR_HV_SIEFP_RSVD_MASK 0x0ffeULL
#define MSR_HV_SIEFP_PGSHIFT 12
#define MSR_HV_SIMP 0x40000083
#define MSR_HV_SIMP_ENABLE 0x0001ULL
#define MSR_HV_SIMP_RSVD_MASK 0x0ffeULL
#define MSR_HV_SIMP_PGSHIFT 12
#define MSR_HV_SINT0 0x40000090
#define MSR_HV_SINT_VECTOR_MASK 0x00ffULL
#define MSR_HV_SINT_RSVD1_MASK 0xff00ULL
#define MSR_HV_SINT_MASKED 0x00010000ULL
#define MSR_HV_SINT_AUTOEOI 0x00020000ULL
#define MSR_HV_SINT_RSVD2_MASK 0xfffffffffffc0000ULL
#define MSR_HV_SINT_RSVD_MASK (MSR_HV_SINT_RSVD1_MASK | \
MSR_HV_SINT_RSVD2_MASK)
#endif /* !_HYPERV_REG_H_ */