staticinlinevoid notify_daemon(struct xencons_info *cons)
{ /* Use evtchn: this is called early, before irq is set up. */
notify_remote_via_evtchn(cons->evtchn);
}
/* * Make sure the whole buffer is emitted, polling if * necessary. We don't ever want to rely on the hvc daemon * because the most interesting console output is when the * kernel is crippled.
*/ while (len) {
ssize_t sent = __write_console(cons, data, len);
if (sent < 0) return sent;
data += sent;
len -= sent;
if (unlikely(len))
HYPERVISOR_sched_op(SCHEDOP_yield, NULL);
}
mb(); /* read ring before consuming */
intf->in_cons = cons;
/* * When to mark interrupt having been spurious: * - there was no new data to be read, and * - the backend did not consume some output bytes, and * - the previous round with no read data didn't see consumed bytes * (we might have a race with an interrupt being in flight while * updating xencons->out_cons, so account for that by allowing one * round without any visible reason)
*/ if (intf->out_cons != xencons->out_cons) {
xencons->out_cons = intf->out_cons;
xencons->out_cons_same = 0;
} if (!recv && xencons->out_cons_same++ > 1) {
eoiflag = XEN_EOI_FLAG_SPURIOUS;
}
spin_unlock_irqrestore(&xencons->ring_lock, flags);
/* * Either for a dom0 to write to the system console, or a domU with a * debug version of Xen
*/ static ssize_t dom0_write_console(uint32_t vtermno, const u8 *str, size_t len)
{ int rc = HYPERVISOR_console_io(CONSOLEIO_write, len, (u8 *)str); if (rc < 0) return rc;
staticint xen_hvm_console_init(void)
{ int r;
uint64_t v = 0; unsignedlong gfn, flags; struct xencons_info *info;
if (!xen_hvm_domain()) return -ENODEV;
info = vtermno_to_xencons(HVC_COOKIE); if (!info) {
info = kzalloc(sizeof(struct xencons_info), GFP_KERNEL); if (!info) return -ENOMEM;
spin_lock_init(&info->ring_lock);
} elseif (info->intf != NULL) { /* already configured */ return 0;
} /* * If the toolstack (or the hypervisor) hasn't set these values, the * default value is 0. Even though gfn = 0 and evtchn = 0 are * theoretically correct values, in practice they never are and they * mean that a legacy toolstack hasn't initialized the pv console correctly.
*/
r = hvm_get_parameter(HVM_PARAM_CONSOLE_EVTCHN, &v); if (r < 0 || v == 0) goto err;
info->evtchn = v;
v = 0;
r = hvm_get_parameter(HVM_PARAM_CONSOLE_PFN, &v); if (r < 0 || v == 0) goto err;
gfn = v;
info->intf = memremap(gfn << XEN_PAGE_SHIFT, XEN_PAGE_SIZE, MEMREMAP_WB); if (info->intf == NULL) goto err;
info->vtermno = HVC_COOKIE;
info = vtermno_to_xencons(HVC_COOKIE); if (!info) {
info = kzalloc(sizeof(struct xencons_info), GFP_KERNEL); if (!info) return -ENOMEM;
spin_lock_init(&info->ring_lock);
}
#ifdef CONFIG_HVC_XEN_FRONTEND staticvoid xencons_disconnect_backend(struct xencons_info *info)
{ if (info->hvc != NULL)
hvc_remove(info->hvc);
info->hvc = NULL; if (info->irq > 0) {
evtchn_put(info->evtchn);
info->irq = 0;
info->evtchn = 0;
} /* evtchn_put() will also close it so this is only an error path */ if (info->evtchn > 0)
xenbus_free_evtchn(info->xbdev, info->evtchn);
info->evtchn = 0; if (info->gntref > 0)
gnttab_free_grant_references(info->gntref);
info->gntref = 0;
}
staticvoid xencons_backend_changed(struct xenbus_device *dev, enum xenbus_state backend_state)
{ switch (backend_state) { case XenbusStateReconfiguring: case XenbusStateReconfigured: case XenbusStateInitialising: case XenbusStateInitialised: case XenbusStateUnknown: break;
case XenbusStateInitWait: break;
case XenbusStateConnected:
xenbus_switch_state(dev, XenbusStateConnected); break;
case XenbusStateClosed: if (dev->state == XenbusStateClosed) break;
fallthrough; /* Missed the backend's CLOSING state */ case XenbusStateClosing: { struct xencons_info *info = dev_get_drvdata(&dev->dev);
/* * Don't tear down the evtchn and grant ref before the other * end has disconnected, but do stop userspace from trying * to use the device before we allow the backend to close.
*/ if (info->hvc) {
hvc_remove(info->hvc);
info->hvc = NULL;
}
if (xen_initial_domain()) {
ops = &dom0_hvc_ops;
r = xen_initial_domain_console_init(); if (r < 0) goto register_fe;
info = vtermno_to_xencons(HVC_COOKIE);
} else {
ops = &domU_hvc_ops; if (xen_hvm_domain())
r = xen_hvm_console_init(); else
r = xen_pv_console_init(); if (r < 0) goto register_fe;
info = vtermno_to_xencons(HVC_COOKIE);
info->irq = bind_evtchn_to_irq_lateeoi(info->evtchn);
} if (info->irq < 0)
info->irq = 0; /* NO_IRQ */ else
irq_set_noprobe(info->irq);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.