[BACK]Return to xen_ipi.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / arch / xen / x86

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>