freebsd-dev/sys/dev/xen/console/xencons_ring.c
Roger Pau Monné c203fa6940 xen: add and enable Xen console for PVH guests
This adds and enables the PV console used on XEN kernels to
GENERIC/XENHVM kernels in order for it to be used on PVH.

Approved by: gibbs
Sponsored by: Citrix Systems R&D

dev/xen/console/console.c:
 - Define console_page.
 - Move xc_printf debug function from i386 XEN code to generic console
   code.
 - Rework xc_printf.
 - Use xen_initial_domain instead of open-coded checks for Dom0.
 - Gate the attach of the PV console to PV(H) guests.

dev/xen/console/xencons_ring.c:
 - Allow the PV Xen console to output earlier by directly signaling
   the event channel in start_info if the event channel is not yet
   initialized.
 - Use HYPERVISOR_start_info instead of xen_start_info.

i386/include/xen/xen-os.h:
 - Remove prototype for xc_printf since it's now declared in global
   xen-os.h

i386/xen/xen_machdep.c:
 - Remove previous version of xc_printf.
 - Remove definition of console_page (now it's defined in the console
   itself).
 - Fix some printf formatting errors.

x86/xen/pv.c:
 - Add some early boot debug messages using xc_printf.
 - Set console_page based on the value passed in start_info.

xen/xen-os.h:
 - Declare console_page and add prototype for xc_printf.
2014-03-11 10:09:23 +00:00

176 lines
3.0 KiB
C

#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/module.h>
#include <sys/systm.h>
#include <sys/consio.h>
#include <sys/proc.h>
#include <sys/uio.h>
#include <sys/tty.h>
#include <sys/systm.h>
#include <sys/taskqueue.h>
#include <sys/conf.h>
#include <sys/kernel.h>
#include <sys/bus.h>
#include <sys/cons.h>
#include <machine/stdarg.h>
#include <xen/xen-os.h>
#include <xen/hypervisor.h>
#include <xen/xen_intr.h>
#include <sys/cons.h>
#include <xen/xen_intr.h>
#include <xen/evtchn.h>
#include <xen/interface/io/console.h>
#include <dev/xen/console/xencons_ring.h>
#include <xen/evtchn.h>
#include <xen/interface/io/console.h>
#define console_evtchn console.domU.evtchn
xen_intr_handle_t console_handle;
extern struct mtx cn_mtx;
extern device_t xencons_dev;
extern bool cnsl_evt_reg;
static inline struct xencons_interface *
xencons_interface(void)
{
return (struct xencons_interface *)console_page;
}
int
xencons_has_input(void)
{
struct xencons_interface *intf;
intf = xencons_interface();
return (intf->in_cons != intf->in_prod);
}
int
xencons_ring_send(const char *data, unsigned len)
{
struct xencons_interface *intf;
XENCONS_RING_IDX cons, prod;
int sent;
struct evtchn_send send = {
.port = HYPERVISOR_start_info->console_evtchn
};
intf = xencons_interface();
cons = intf->out_cons;
prod = intf->out_prod;
sent = 0;
mb();
KASSERT((prod - cons) <= sizeof(intf->out),
("console send ring inconsistent"));
while ((sent < len) && ((prod - cons) < sizeof(intf->out)))
intf->out[MASK_XENCONS_IDX(prod++, intf->out)] = data[sent++];
wmb();
intf->out_prod = prod;
if (cnsl_evt_reg)
xen_intr_signal(console_handle);
else
HYPERVISOR_event_channel_op(EVTCHNOP_send, &send);
return sent;
}
static xencons_receiver_func *xencons_receiver;
void
xencons_handle_input(void *unused)
{
struct xencons_interface *intf;
XENCONS_RING_IDX cons, prod;
CN_LOCK(cn_mtx);
intf = xencons_interface();
cons = intf->in_cons;
prod = intf->in_prod;
CN_UNLOCK(cn_mtx);
/* XXX needs locking */
while (cons != prod) {
xencons_rx(intf->in + MASK_XENCONS_IDX(cons, intf->in), 1);
cons++;
}
mb();
intf->in_cons = cons;
CN_LOCK(cn_mtx);
xen_intr_signal(console_handle);
xencons_tx();
CN_UNLOCK(cn_mtx);
}
void
xencons_ring_register_receiver(xencons_receiver_func *f)
{
xencons_receiver = f;
}
int
xencons_ring_init(void)
{
int err;
if (HYPERVISOR_start_info->console_evtchn == 0)
return 0;
err = xen_intr_bind_local_port(xencons_dev,
HYPERVISOR_start_info->console_evtchn, NULL, xencons_handle_input, NULL,
INTR_TYPE_MISC | INTR_MPSAFE, &console_handle);
if (err) {
return err;
}
return 0;
}
extern void xencons_suspend(void);
extern void xencons_resume(void);
void
xencons_suspend(void)
{
if (HYPERVISOR_start_info->console_evtchn == 0)
return;
xen_intr_unbind(&console_handle);
}
void
xencons_resume(void)
{
(void)xencons_ring_init();
}
/*
* Local variables:
* mode: C
* c-set-style: "BSD"
* c-basic-offset: 8
* tab-width: 4
* indent-tabs-mode: t
* End:
*/