Changeset View
Standalone View
sys/amd64/vmm/intel/vmx.c
/*- | /*- | ||||
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD | * SPDX-License-Identifier: BSD-2-Clause-FreeBSD | ||||
* | * | ||||
* Copyright (c) 2011 NetApp, Inc. | * Copyright (c) 2011 NetApp, Inc. | ||||
* All rights reserved. | * All rights reserved. | ||||
rgrimes: Move this line after the all rights reserved line please, as that is part of NetApp copyright. | |||||
Done Inline ActionsWill fix pmooney_pfmooney.com: Will fix | |||||
Done Inline ActionsBTW: I used other files in bhyve as a guide, where they tended to list the various copyright lines before the "All rights reserved." pmooney_pfmooney.com: BTW: I used other files in bhyve as a guide, where they tended to list the various copyright… | |||||
Not Done Inline ActionsThere are plenty of bad examples in the tree, it is wrong to insert your copyright between another copyright and the words All rights reserved. rgrimes: There are plenty of bad examples in the tree, it is wrong to insert your copyright between… | |||||
* Copyright (c) 2018 Joyent, Inc. | |||||
* | * | ||||
* Redistribution and use in source and binary forms, with or without | * Redistribution and use in source and binary forms, with or without | ||||
* modification, are permitted provided that the following conditions | * modification, are permitted provided that the following conditions | ||||
* are met: | * are met: | ||||
* 1. Redistributions of source code must retain the above copyright | * 1. Redistributions of source code must retain the above copyright | ||||
* notice, this list of conditions and the following disclaimer. | * notice, this list of conditions and the following disclaimer. | ||||
* 2. Redistributions in binary form must reproduce the above copyright | * 2. Redistributions in binary form must reproduce the above copyright | ||||
* notice, this list of conditions and the following disclaimer in the | * notice, this list of conditions and the following disclaimer in the | ||||
▲ Show 20 Lines • Show All 3,383 Lines • ▼ Show 20 Lines | vmx_setcap(void *arg, int vcpu, int type, int val) | ||||
return (retval); | return (retval); | ||||
} | } | ||||
struct vlapic_vtx { | struct vlapic_vtx { | ||||
struct vlapic vlapic; | struct vlapic vlapic; | ||||
struct pir_desc *pir_desc; | struct pir_desc *pir_desc; | ||||
struct vmx *vmx; | struct vmx *vmx; | ||||
uint_t pending_prio; | |||||
}; | }; | ||||
#define VPR_PRIO_BIT(vpr) (1 << ((vpr) >> 4)) | |||||
#define VMX_CTR_PIR(vm, vcpuid, pir_desc, notify, vector, level, msg) \ | #define VMX_CTR_PIR(vm, vcpuid, pir_desc, notify, vector, level, msg) \ | ||||
do { \ | do { \ | ||||
VCPU_CTR2(vm, vcpuid, msg " assert %s-triggered vector %d", \ | VCPU_CTR2(vm, vcpuid, msg " assert %s-triggered vector %d", \ | ||||
level ? "level" : "edge", vector); \ | level ? "level" : "edge", vector); \ | ||||
VCPU_CTR1(vm, vcpuid, msg " pir0 0x%016lx", pir_desc->pir[0]); \ | VCPU_CTR1(vm, vcpuid, msg " pir0 0x%016lx", pir_desc->pir[0]); \ | ||||
VCPU_CTR1(vm, vcpuid, msg " pir1 0x%016lx", pir_desc->pir[1]); \ | VCPU_CTR1(vm, vcpuid, msg " pir1 0x%016lx", pir_desc->pir[1]); \ | ||||
VCPU_CTR1(vm, vcpuid, msg " pir2 0x%016lx", pir_desc->pir[2]); \ | VCPU_CTR1(vm, vcpuid, msg " pir2 0x%016lx", pir_desc->pir[2]); \ | ||||
VCPU_CTR1(vm, vcpuid, msg " pir3 0x%016lx", pir_desc->pir[3]); \ | VCPU_CTR1(vm, vcpuid, msg " pir3 0x%016lx", pir_desc->pir[3]); \ | ||||
VCPU_CTR1(vm, vcpuid, msg " notify: %s", notify ? "yes" : "no");\ | VCPU_CTR1(vm, vcpuid, msg " notify: %s", notify ? "yes" : "no");\ | ||||
} while (0) | } while (0) | ||||
/* | /* | ||||
* vlapic->ops handlers that utilize the APICv hardware assist described in | * vlapic->ops handlers that utilize the APICv hardware assist described in | ||||
* Chapter 29 of the Intel SDM. | * Chapter 29 of the Intel SDM. | ||||
*/ | */ | ||||
static int | static int | ||||
vmx_set_intr_ready(struct vlapic *vlapic, int vector, bool level) | vmx_set_intr_ready(struct vlapic *vlapic, int vector, bool level) | ||||
{ | { | ||||
struct vlapic_vtx *vlapic_vtx; | struct vlapic_vtx *vlapic_vtx; | ||||
struct pir_desc *pir_desc; | struct pir_desc *pir_desc; | ||||
uint64_t mask; | uint64_t mask; | ||||
int idx, notify; | int idx, notify = 0; | ||||
vlapic_vtx = (struct vlapic_vtx *)vlapic; | vlapic_vtx = (struct vlapic_vtx *)vlapic; | ||||
pir_desc = vlapic_vtx->pir_desc; | pir_desc = vlapic_vtx->pir_desc; | ||||
/* | /* | ||||
* Keep track of interrupt requests in the PIR descriptor. This is | * Keep track of interrupt requests in the PIR descriptor. This is | ||||
* because the virtual APIC page pointed to by the VMCS cannot be | * because the virtual APIC page pointed to by the VMCS cannot be | ||||
* modified if the vcpu is running. | * modified if the vcpu is running. | ||||
*/ | */ | ||||
idx = vector / 64; | idx = vector / 64; | ||||
mask = 1UL << (vector % 64); | mask = 1UL << (vector % 64); | ||||
atomic_set_long(&pir_desc->pir[idx], mask); | atomic_set_long(&pir_desc->pir[idx], mask); | ||||
notify = atomic_cmpset_long(&pir_desc->pending, 0, 1); | |||||
/* | |||||
* A notification is required whenever the 'pending' bit makes a | |||||
* transition from 0->1. | |||||
* | |||||
* Even if the 'pending' bit is already asserted, notification about | |||||
* the incoming interrupt may still be necessary. For example, if a | |||||
* vCPU is HLTed with a high PPR, a low priority interrupt would cause | |||||
* the 0->1 'pending' transition with a notification, but the vCPU | |||||
* would ignore the interrupt for the time being. The same vCPU would | |||||
* need to then be notified if a high-priority interrupt arrived which | |||||
* satisfied the PPR. | |||||
* | |||||
* The priorities of interrupts injected while 'pending' is asserted | |||||
* are tracked in a custom bitfield 'pending_prio'. Should the | |||||
* to-be-injected interrupt exceed the priorities already present, the | |||||
* notification is sent. The priorities recorded in 'pending_prio' are | |||||
* cleared whenever the 'pending' bit makes another 0->1 transition. | |||||
*/ | |||||
if (atomic_cmpset_long(&pir_desc->pending, 0, 1) != 0) { | |||||
notify = 1; | |||||
vlapic_vtx->pending_prio = 0; | |||||
} else { | |||||
const uint_t old_prio = vlapic_vtx->pending_prio; | |||||
jhbUnsubmitted Not Done Inline ActionsFYI, FreeBSD uses 'u_int' and doesn't have a 'uint_t'. I've fixed this during testing though and will just include it that way in the commit. jhb: FYI, FreeBSD uses 'u_int' and doesn't have a 'uint_t'. I've fixed this during testing though… | |||||
const uint_t prio_bit = VPR_PRIO_BIT(vector & APIC_TPR_INT); | |||||
Not Done Inline ActionsFreeBSD style(9) pretty much says to not declare variables in inner blocks, these should be moved and sorted into the variables at the beginning of the function. The assignments can stay here, just the declare gets moved. rgrimes: FreeBSD style(9) pretty much says to not declare variables in inner blocks, these should be… | |||||
Done Inline ActionsThat would mean discarding the 'const'. The point was to make the test and subsequent atomic assignment below more readable, without implying that the variables have any more than one state. style(9) doesn't expressly forbid it, and there are a few examples of scoped declarations elsewhere in the kernel, but I can make that change if it's an important issue. pmooney_pfmooney.com: That would mean discarding the 'const'. The point was to make the test and subsequent atomic… | |||||
Not Done Inline ActionsThat is jhb@'s call rgrimes: That is jhb@'s call | |||||
Not Done Inline Actionsstyle(9) says no such thing. It used to, but that rule has been relaxed. Here it clearly makes sense to use. imp: style(9) says no such thing. It used to, but that rule has been relaxed. Here it clearly makes… | |||||
if ((old_prio & prio_bit) == 0 && prio_bit > old_prio) { | |||||
atomic_set_int(&vlapic_vtx->pending_prio, prio_bit); | |||||
notify = 1; | |||||
} | |||||
} | |||||
VMX_CTR_PIR(vlapic->vm, vlapic->vcpuid, pir_desc, notify, vector, | VMX_CTR_PIR(vlapic->vm, vlapic->vcpuid, pir_desc, notify, vector, | ||||
level, "vmx_set_intr_ready"); | level, "vmx_set_intr_ready"); | ||||
return (notify); | return (notify); | ||||
} | } | ||||
static int | static int | ||||
vmx_pending_intr(struct vlapic *vlapic, int *vecptr) | vmx_pending_intr(struct vlapic *vlapic, int *vecptr) | ||||
{ | { | ||||
▲ Show 20 Lines • Show All 48 Lines • ▼ Show 20 Lines | vmx_pending_intr(struct vlapic *vlapic, int *vecptr) | ||||
lapic = vlapic->apic_page; | lapic = vlapic->apic_page; | ||||
ppr = lapic->ppr & APIC_TPR_INT; | ppr = lapic->ppr & APIC_TPR_INT; | ||||
if (ppr == 0) | if (ppr == 0) | ||||
return (1); | return (1); | ||||
VCPU_CTR1(vlapic->vm, vlapic->vcpuid, "HLT with non-zero PPR %d", | VCPU_CTR1(vlapic->vm, vlapic->vcpuid, "HLT with non-zero PPR %d", | ||||
lapic->ppr); | lapic->ppr); | ||||
vpr = 0; | |||||
for (i = 3; i >= 0; i--) { | for (i = 3; i >= 0; i--) { | ||||
pirval = pir_desc->pir[i]; | pirval = pir_desc->pir[i]; | ||||
if (pirval != 0) { | if (pirval != 0) { | ||||
vpr = (i * 64 + flsl(pirval) - 1) & APIC_TPR_INT; | vpr = (i * 64 + flsl(pirval) - 1) & APIC_TPR_INT; | ||||
return (vpr > ppr); | break; | ||||
} | } | ||||
} | } | ||||
/* | |||||
jhbUnsubmitted Not Done Inline ActionsI'll add a blank line before this when committing, but I can do that as part of the commit, just FYI for future reference. jhb: I'll add a blank line before this when committing, but I can do that as part of the commit… | |||||
* If the highest-priority pending interrupt falls short of the | |||||
* processor priority of this vCPU, ensure that 'pending_prio' does not | |||||
* have any stale bits which would preclude a higher-priority interrupt | |||||
* from incurring a notification later. | |||||
*/ | |||||
if (vpr <= ppr) { | |||||
const uint_t prio_bit = VPR_PRIO_BIT(vpr); | |||||
const uint_t old = vlapic_vtx->pending_prio; | |||||
if (old > prio_bit && (old & prio_bit) == 0) { | |||||
vlapic_vtx->pending_prio = prio_bit; | |||||
} | |||||
return (0); | return (0); | ||||
} | |||||
return (1); | |||||
} | } | ||||
static void | static void | ||||
vmx_intr_accepted(struct vlapic *vlapic, int vector) | vmx_intr_accepted(struct vlapic *vlapic, int vector) | ||||
{ | { | ||||
panic("vmx_intr_accepted: not expected to be called"); | panic("vmx_intr_accepted: not expected to be called"); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 232 Lines • Show Last 20 Lines |
Move this line after the all rights reserved line please, as that is part of NetApp copyright.
If Joyent wants to assert all rights, they should do so in there copyright, preferably: