2382778f40
Minor fixes to make the Xen Dom0 console work. This includes always returning there's pending input in xencons_has_input, because on Dom0 there's no shared ring and we cannot test the indexes. The second fix is to use the CONSOLEIO_read hypercall in order to read input data from the Xen console. Sponsored by: Citrix Systems R&D dev/xen/console/xencons_ring.c: - Always return true in xencons_has_input for Dom0. - Implement Dom0 console support for xencons_handle_input.
202 lines
3.6 KiB
C
202 lines
3.6 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;
|
|
#define DOM0_BUFFER_SIZE 16
|
|
|
|
static inline struct xencons_interface *
|
|
xencons_interface(void)
|
|
{
|
|
return (struct xencons_interface *)console_page;
|
|
}
|
|
|
|
|
|
int
|
|
xencons_has_input(void)
|
|
{
|
|
struct xencons_interface *intf;
|
|
|
|
if (xen_initial_domain()) {
|
|
/*
|
|
* Since the Dom0 console works with hypercalls
|
|
* there's no way to know if there's input unless
|
|
* we actually try to retrieve it, so always return
|
|
* like there's pending data. Then if the hypercall
|
|
* returns no input, we can handle it without problems
|
|
* in xencons_handle_input().
|
|
*/
|
|
return 1;
|
|
}
|
|
|
|
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);
|
|
|
|
if (xen_initial_domain()) {
|
|
static char rbuf[DOM0_BUFFER_SIZE];
|
|
int l;
|
|
|
|
while ((l = HYPERVISOR_console_io(CONSOLEIO_read,
|
|
DOM0_BUFFER_SIZE, rbuf)) > 0)
|
|
xencons_rx(rbuf, l);
|
|
|
|
CN_UNLOCK(cn_mtx);
|
|
return;
|
|
}
|
|
|
|
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:
|
|
*/
|