1221828Sgrehan/*-
2221828Sgrehan * Copyright (c) 2011 NetApp, Inc.
3221828Sgrehan * All rights reserved.
4221828Sgrehan *
5221828Sgrehan * Redistribution and use in source and binary forms, with or without
6221828Sgrehan * modification, are permitted provided that the following conditions
7221828Sgrehan * are met:
8221828Sgrehan * 1. Redistributions of source code must retain the above copyright
9221828Sgrehan *    notice, this list of conditions and the following disclaimer.
10221828Sgrehan * 2. Redistributions in binary form must reproduce the above copyright
11221828Sgrehan *    notice, this list of conditions and the following disclaimer in the
12221828Sgrehan *    documentation and/or other materials provided with the distribution.
13221828Sgrehan *
14221828Sgrehan * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND
15221828Sgrehan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16221828Sgrehan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17221828Sgrehan * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE
18221828Sgrehan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19221828Sgrehan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20221828Sgrehan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21221828Sgrehan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22221828Sgrehan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23221828Sgrehan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24221828Sgrehan * SUCH DAMAGE.
25221828Sgrehan *
26221828Sgrehan * $FreeBSD$
27221828Sgrehan */
28221828Sgrehan
29221828Sgrehan#include <sys/cdefs.h>
30221828Sgrehan__FBSDID("$FreeBSD$");
31221828Sgrehan
32221828Sgrehan#include <sys/param.h>
33221828Sgrehan#include <sys/systm.h>
34221828Sgrehan#include <sys/proc.h>
35221828Sgrehan#include <sys/bus.h>
36221828Sgrehan
37221828Sgrehan#include <machine/intr_machdep.h>
38221828Sgrehan#include <machine/apicvar.h>
39221828Sgrehan#include <machine/segments.h>
40221828Sgrehan#include <machine/md_var.h>
41221828Sgrehan
42221828Sgrehan#include <machine/vmm.h>
43221828Sgrehan#include "vmm_ipi.h"
44221828Sgrehan
45221828Sgrehanextern inthand_t IDTVEC(rsvd), IDTVEC(justreturn);
46221828Sgrehan
47221828SgrehanCTASSERT(APIC_SPURIOUS_INT == 255);
48221828Sgrehan
49266339Sjhbint
50266339Sjhbvmm_ipi_alloc(void)
51221828Sgrehan{
52221828Sgrehan	int idx;
53221828Sgrehan	uintptr_t func;
54221828Sgrehan	struct gate_descriptor *ip;
55221828Sgrehan
56221828Sgrehan	/*
57221828Sgrehan	 * Search backwards from the highest IDT vector available for use
58221828Sgrehan	 * as our IPI vector. We install the 'justreturn' handler at that
59221828Sgrehan	 * vector and use it to interrupt the vcpus.
60221828Sgrehan	 *
61221828Sgrehan	 * We do this because the IPI_AST is heavyweight and saves all
62221828Sgrehan	 * registers in the trapframe. This is overkill for our use case
63221828Sgrehan	 * which is simply to EOI the interrupt and return.
64221828Sgrehan	 */
65221828Sgrehan	idx = APIC_SPURIOUS_INT;
66221828Sgrehan	while (--idx >= APIC_IPI_INTS) {
67221828Sgrehan		ip = &idt[idx];
68221828Sgrehan		func = ((long)ip->gd_hioffset << 16 | ip->gd_looffset);
69221828Sgrehan		if (func == (uintptr_t)&IDTVEC(rsvd)) {
70266339Sjhb			setidt(idx , IDTVEC(justreturn), SDT_SYSIGT,
71221828Sgrehan			       SEL_KPL, 0);
72266339Sjhb			return (idx);
73221828Sgrehan		}
74221828Sgrehan	}
75266339Sjhb	return (0);
76221828Sgrehan}
77221828Sgrehan
78221828Sgrehanvoid
79266339Sjhbvmm_ipi_free(int ipinum)
80221828Sgrehan{
81266339Sjhb	uintptr_t func;
82266339Sjhb	struct gate_descriptor *ip;
83266339Sjhb
84266339Sjhb	KASSERT(ipinum >= APIC_IPI_INTS && ipinum < APIC_SPURIOUS_INT,
85266339Sjhb	    ("invalid ipi %d", ipinum));
86266339Sjhb
87266339Sjhb	ip = &idt[ipinum];
88266339Sjhb	func = ((long)ip->gd_hioffset << 16 | ip->gd_looffset);
89266339Sjhb	KASSERT(func == (uintptr_t)&IDTVEC(justreturn),
90266339Sjhb	    ("invalid ipi %d", ipinum));
91266339Sjhb
92266339Sjhb	setidt(ipinum, IDTVEC(rsvd), SDT_SYSIGT, SEL_KPL, 0);
93221828Sgrehan}
94