Annotation of src/sys/arch/xen/x86/xen_ipi.c, Revision 1.33
1.33 ! maxv 1: /* $NetBSD: xen_ipi.c,v 1.32 2019/02/02 12:32:55 cherry Exp $ */
1.2 cherry 2:
3: /*-
4: * Copyright (c) 2011 The NetBSD Foundation, Inc.
5: * All rights reserved.
6: *
7: * This code is derived from software contributed to The NetBSD Foundation
8: * by Cherry G. Mathew <cherry@zyx.in>
9: *
10: * Redistribution and use in source and binary forms, with or without
11: * modification, are permitted provided that the following conditions
12: * are met:
13: * 1. Redistributions of source code must retain the above copyright
14: * notice, this list of conditions and the following disclaimer.
15: * 2. Redistributions in binary form must reproduce the above copyright
16: * notice, this list of conditions and the following disclaimer in the
17: * documentation and/or other materials provided with the distribution.
18: *
19: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29: * POSSIBILITY OF SUCH DAMAGE.
30: */
31:
32: #include <sys/cdefs.h> /* RCS ID macro */
33:
34: /*
35: * Based on: x86/ipi.c
1.33 ! maxv 36: * __KERNEL_RCSID(0, "$NetBSD: xen_ipi.c,v 1.32 2019/02/02 12:32:55 cherry Exp $");
1.2 cherry 37: */
38:
1.33 ! maxv 39: __KERNEL_RCSID(0, "$NetBSD: xen_ipi.c,v 1.32 2019/02/02 12:32:55 cherry Exp $");
1.24 jdolecek 40:
41: #include "opt_ddb.h"
1.2 cherry 42:
43: #include <sys/types.h>
44:
45: #include <sys/atomic.h>
1.10 bouyer 46: #include <sys/cpu.h>
1.2 cherry 47: #include <sys/mutex.h>
48: #include <sys/device.h>
49: #include <sys/xcall.h>
1.18 rmind 50: #include <sys/ipi.h>
1.2 cherry 51: #include <sys/errno.h>
52: #include <sys/systm.h>
53:
1.16 dsl 54: #include <x86/fpu.h>
1.2 cherry 55: #include <machine/frame.h>
56: #include <machine/segments.h>
57:
1.11 cherry 58: #include <xen/evtchn.h>
1.2 cherry 59: #include <xen/intr.h>
60: #include <xen/intrdefs.h>
61: #include <xen/hypervisor.h>
1.32 cherry 62: #include <xen/include/public/vcpu.h>
1.2 cherry 63:
1.24 jdolecek 64: #ifdef DDB
1.2 cherry 65: extern void ddb_ipi(struct trapframe);
1.24 jdolecek 66: static void xen_ipi_ddb(struct cpu_info *, struct intrframe *);
67: #endif
1.2 cherry 68:
69: static void xen_ipi_halt(struct cpu_info *, struct intrframe *);
1.14 christos 70: static void xen_ipi_synch_fpu(struct cpu_info *, struct intrframe *);
1.2 cherry 71: static void xen_ipi_xcall(struct cpu_info *, struct intrframe *);
1.6 cherry 72: static void xen_ipi_hvcb(struct cpu_info *, struct intrframe *);
1.18 rmind 73: static void xen_ipi_generic(struct cpu_info *, struct intrframe *);
1.2 cherry 74:
75: static void (*ipifunc[XEN_NIPIS])(struct cpu_info *, struct intrframe *) =
76: { /* In order of priority (see: xen/include/intrdefs.h */
77: xen_ipi_halt,
1.14 christos 78: xen_ipi_synch_fpu,
1.24 jdolecek 79: #ifdef DDB
1.2 cherry 80: xen_ipi_ddb,
1.24 jdolecek 81: #else
82: NULL,
83: #endif
1.6 cherry 84: xen_ipi_xcall,
1.18 rmind 85: xen_ipi_hvcb,
86: xen_ipi_generic,
1.2 cherry 87: };
88:
1.23 cherry 89: static int
90: xen_ipi_handler(void *arg)
1.2 cherry 91: {
92: uint32_t pending;
93: int bit;
1.23 cherry 94: struct cpu_info *ci;
95: struct intrframe *regs;
1.2 cherry 96:
1.23 cherry 97: ci = curcpu();
98: regs = arg;
99:
1.2 cherry 100: pending = atomic_swap_32(&ci->ci_ipis, 0);
101:
102: KDASSERT((pending >> XEN_NIPIS) == 0);
103: while ((bit = ffs(pending)) != 0) {
104: bit--;
105: pending &= ~(1 << bit);
106: ci->ci_ipi_events[bit].ev_count++;
107: if (ipifunc[bit] != NULL) {
108: (*ipifunc[bit])(ci, regs);
1.3 cherry 109: } else {
1.2 cherry 110: panic("ipifunc[%d] unsupported!\n", bit);
111: /* NOTREACHED */
112: }
113: }
1.23 cherry 114:
115: return 0;
1.2 cherry 116: }
117:
118: /* Must be called once for every cpu that expects to send/recv ipis */
119: void
120: xen_ipi_init(void)
121: {
122: cpuid_t vcpu;
123: evtchn_port_t evtchn;
124: struct cpu_info *ci;
1.25 jdolecek 125: char intr_xname[INTRDEVNAMEBUF];
1.2 cherry 126:
127: ci = curcpu();
128:
129: vcpu = ci->ci_cpuid;
1.7 cegger 130: KASSERT(vcpu < XEN_LEGACY_MAX_VCPUS);
1.2 cherry 131:
1.3 cherry 132: evtchn = bind_vcpu_to_evtch(vcpu);
133: ci->ci_ipi_evtchn = evtchn;
1.2 cherry 134:
135: KASSERT(evtchn != -1 && evtchn < NR_EVENT_CHANNELS);
136:
1.25 jdolecek 137: snprintf(intr_xname, sizeof(intr_xname), "%s ipi",
138: device_xname(ci->ci_dev));
139:
1.29 cherry 140: if (xen_intr_establish_xname(-1, &xen_pic, evtchn, IST_LEVEL, IPL_HIGH,
1.25 jdolecek 141: xen_ipi_handler, ci, true, intr_xname) == NULL) {
1.23 cherry 142: panic("%s: unable to register ipi handler\n", __func__);
1.2 cherry 143: /* NOTREACHED */
144: }
145:
1.28 cherry 146: hypervisor_unmask_event(evtchn);
1.2 cherry 147: }
148:
1.19 joerg 149: #ifdef DIAGNOSTIC
1.2 cherry 150: static inline bool /* helper */
151: valid_ipimask(uint32_t ipimask)
152: {
1.18 rmind 153: uint32_t masks = XEN_IPI_GENERIC | XEN_IPI_HVCB | XEN_IPI_XCALL |
1.6 cherry 154: XEN_IPI_DDB | XEN_IPI_SYNCH_FPU |
155: XEN_IPI_HALT | XEN_IPI_KICK;
1.2 cherry 156:
157: if (ipimask & ~masks) {
158: return false;
1.3 cherry 159: } else {
1.2 cherry 160: return true;
161: }
162:
163: }
1.19 joerg 164: #endif
1.2 cherry 165:
166: int
167: xen_send_ipi(struct cpu_info *ci, uint32_t ipimask)
168: {
169: evtchn_port_t evtchn;
170:
1.26 bouyer 171: KASSERT(ci != NULL && ci != curcpu());
1.2 cherry 172:
1.4 cherry 173: if ((ci->ci_flags & CPUF_RUNNING) == 0) {
1.2 cherry 174: return ENOENT;
175: }
176:
177: evtchn = ci->ci_ipi_evtchn;
1.3 cherry 178:
179: KASSERTMSG(valid_ipimask(ipimask) == true,
1.5 jym 180: "xen_send_ipi() called with invalid ipimask\n");
1.2 cherry 181:
182: atomic_or_32(&ci->ci_ipis, ipimask);
183: hypervisor_notify_via_evtchn(evtchn);
184:
185: return 0;
186: }
187:
188: void
189: xen_broadcast_ipi(uint32_t ipimask)
190: {
191: struct cpu_info *ci, *self = curcpu();
192: CPU_INFO_ITERATOR cii;
193:
1.3 cherry 194: KASSERTMSG(valid_ipimask(ipimask) == true,
1.5 jym 195: "xen_broadcast_ipi() called with invalid ipimask\n");
1.2 cherry 196:
197: /*
198: * XXX-cherry: there's an implicit broadcast sending order
199: * which I dislike. Randomise this ? :-)
200: */
201:
202: for (CPU_INFO_FOREACH(cii, ci)) {
203: if (ci == NULL)
204: continue;
205: if (ci == self)
206: continue;
207: if (ci->ci_data.cpu_idlelwp == NULL)
208: continue;
209: if ((ci->ci_flags & CPUF_PRESENT) == 0)
210: continue;
211: if (ci->ci_flags & (CPUF_RUNNING)) {
212: if (0 != xen_send_ipi(ci, ipimask)) {
213: panic("xen_ipi of %x from %s to %s failed\n",
214: ipimask, cpu_name(curcpu()),
215: cpu_name(ci));
216: }
217: }
218: }
219: }
220:
221: /* MD wrapper for the xcall(9) callback. */
222:
223: static void
224: xen_ipi_halt(struct cpu_info *ci, struct intrframe *intrf)
225: {
226: KASSERT(ci == curcpu());
227: KASSERT(ci != NULL);
228: if (HYPERVISOR_vcpu_op(VCPUOP_down, ci->ci_cpuid, NULL)) {
1.25 jdolecek 229: panic("%s shutdown failed.\n", device_xname(ci->ci_dev));
1.2 cherry 230: }
231:
232: }
233:
234: static void
1.14 christos 235: xen_ipi_synch_fpu(struct cpu_info *ci, struct intrframe *intrf)
236: {
237: KASSERT(ci != NULL);
238: KASSERT(intrf != NULL);
239:
1.33 ! maxv 240: panic("%s: impossible", __func__);
1.14 christos 241: }
242:
1.24 jdolecek 243: #ifdef DDB
1.14 christos 244: static void
1.2 cherry 245: xen_ipi_ddb(struct cpu_info *ci, struct intrframe *intrf)
246: {
247: KASSERT(ci != NULL);
248: KASSERT(intrf != NULL);
249:
250: #ifdef __x86_64__
251: ddb_ipi(intrf->if_tf);
252: #else
253: struct trapframe tf;
254: tf.tf_gs = intrf->if_gs;
255: tf.tf_fs = intrf->if_fs;
256: tf.tf_es = intrf->if_es;
257: tf.tf_ds = intrf->if_ds;
258: tf.tf_edi = intrf->if_edi;
259: tf.tf_esi = intrf->if_esi;
260: tf.tf_ebp = intrf->if_ebp;
261: tf.tf_ebx = intrf->if_ebx;
262: tf.tf_ecx = intrf->if_ecx;
263: tf.tf_eax = intrf->if_eax;
264: tf.tf_trapno = intrf->__if_trapno;
265: tf.tf_err = intrf->__if_err;
266: tf.tf_eip = intrf->if_eip;
267: tf.tf_cs = intrf->if_cs;
268: tf.tf_eflags = intrf->if_eflags;
269: tf.tf_esp = intrf->if_esp;
270: tf.tf_ss = intrf->if_ss;
271:
1.22 maxv 272: ddb_ipi(tf);
1.2 cherry 273: #endif
274: }
1.24 jdolecek 275: #endif /* DDB */
1.2 cherry 276:
277: static void
278: xen_ipi_xcall(struct cpu_info *ci, struct intrframe *intrf)
279: {
280: KASSERT(ci != NULL);
281: KASSERT(intrf != NULL);
282:
283: xc_ipi_handler();
284: }
285:
286: void
287: xc_send_ipi(struct cpu_info *ci)
288: {
289:
290: KASSERT(kpreempt_disabled());
291: KASSERT(curcpu() != ci);
292: if (ci) {
293: if (0 != xen_send_ipi(ci, XEN_IPI_XCALL)) {
294: panic("xen_send_ipi(XEN_IPI_XCALL) failed\n");
1.3 cherry 295: }
1.2 cherry 296: } else {
297: xen_broadcast_ipi(XEN_IPI_XCALL);
298: }
299: }
1.6 cherry 300:
301: static void
1.18 rmind 302: xen_ipi_generic(struct cpu_info *ci, struct intrframe *intrf)
303: {
304: KASSERT(ci != NULL);
305: KASSERT(intrf != NULL);
306:
307: ipi_cpu_handler();
308: }
309:
310: void
311: cpu_ipi(struct cpu_info *ci)
312: {
313: KASSERT(kpreempt_disabled());
314: KASSERT(curcpu() != ci);
315: if (ci) {
316: if (0 != xen_send_ipi(ci, XEN_IPI_GENERIC)) {
317: panic("xen_send_ipi(XEN_IPI_GENERIC) failed\n");
318: }
319: } else {
320: xen_broadcast_ipi(XEN_IPI_GENERIC);
321: }
322: }
323:
324: static void
1.6 cherry 325: xen_ipi_hvcb(struct cpu_info *ci, struct intrframe *intrf)
326: {
327: KASSERT(ci != NULL);
328: KASSERT(intrf != NULL);
1.8 cherry 329: KASSERT(ci == curcpu());
330: KASSERT(!ci->ci_vcpu->evtchn_upcall_mask);
1.6 cherry 331:
332: hypervisor_force_callback();
333: }
CVSweb <webmaster@jp.NetBSD.org>