1a231723cSRoger Pau Monné /*
2a231723cSRoger Pau Monné * Copyright (c) 2015 Julien Grall <julien.grall@citrix.com>
3a231723cSRoger Pau Monné * All rights reserved.
4a231723cSRoger Pau Monné *
5a231723cSRoger Pau Monné * Redistribution and use in source and binary forms, with or without
6a231723cSRoger Pau Monné * modification, are permitted provided that the following conditions
7a231723cSRoger Pau Monné * are met:
8a231723cSRoger Pau Monné * 1. Redistributions of source code must retain the above copyright
9a231723cSRoger Pau Monné * notice, this list of conditions and the following disclaimer.
10a231723cSRoger Pau Monné * 2. Redistributions in binary form must reproduce the above copyright
11a231723cSRoger Pau Monné * notice, this list of conditions and the following disclaimer in the
12a231723cSRoger Pau Monné * documentation and/or other materials provided with the distribution.
13a231723cSRoger Pau Monné *
14a231723cSRoger Pau Monné * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS AS IS'' AND
15a231723cSRoger Pau Monné * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16a231723cSRoger Pau Monné * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17a231723cSRoger Pau Monné * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18a231723cSRoger Pau Monné * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19a231723cSRoger Pau Monné * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20a231723cSRoger Pau Monné * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21a231723cSRoger Pau Monné * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22a231723cSRoger Pau Monné * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23a231723cSRoger Pau Monné * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24a231723cSRoger Pau Monné * SUCH DAMAGE.
25a231723cSRoger Pau Monné */
26a231723cSRoger Pau Monné
27a231723cSRoger Pau Monné #include <sys/param.h>
28a231723cSRoger Pau Monné #include <sys/module.h>
29a231723cSRoger Pau Monné #include <sys/systm.h>
30e2e050c8SConrad Meyer #include <sys/eventhandler.h>
31a231723cSRoger Pau Monné #include <sys/consio.h>
32a231723cSRoger Pau Monné #include <sys/priv.h>
33a231723cSRoger Pau Monné #include <sys/proc.h>
34a231723cSRoger Pau Monné #include <sys/uio.h>
35a231723cSRoger Pau Monné #include <sys/tty.h>
36a231723cSRoger Pau Monné #include <sys/systm.h>
37a231723cSRoger Pau Monné #include <sys/taskqueue.h>
38a231723cSRoger Pau Monné #include <sys/conf.h>
39a231723cSRoger Pau Monné #include <sys/kernel.h>
40a231723cSRoger Pau Monné #include <sys/bus.h>
41a231723cSRoger Pau Monné #include <sys/cons.h>
42a231723cSRoger Pau Monné #include <sys/kdb.h>
43a231723cSRoger Pau Monné #include <sys/proc.h>
44d16bd541SRoger Pau Monné #include <sys/reboot.h>
45a231723cSRoger Pau Monné
46a231723cSRoger Pau Monné #include <machine/stdarg.h>
47a231723cSRoger Pau Monné
48cfa0b7b8SRoger Pau Monné #include <vm/vm.h>
49cfa0b7b8SRoger Pau Monné #include <vm/pmap.h>
50cfa0b7b8SRoger Pau Monné
51a231723cSRoger Pau Monné #include <xen/xen-os.h>
52a231723cSRoger Pau Monné #include <xen/hypervisor.h>
53a231723cSRoger Pau Monné #include <xen/xen_intr.h>
54ad7dd514SElliott Mitchell #include <contrib/xen/io/console.h>
55a231723cSRoger Pau Monné
56a231723cSRoger Pau Monné #include "opt_ddb.h"
57a231723cSRoger Pau Monné #include "opt_printf.h"
58a231723cSRoger Pau Monné
59a231723cSRoger Pau Monné #ifdef DDB
60a231723cSRoger Pau Monné #include <ddb/ddb.h>
61a231723cSRoger Pau Monné #endif
62a231723cSRoger Pau Monné
63a231723cSRoger Pau Monné static char driver_name[] = "xc";
64a231723cSRoger Pau Monné
65a231723cSRoger Pau Monné struct xencons_priv;
66a231723cSRoger Pau Monné
67a231723cSRoger Pau Monné typedef void xencons_early_init_t(struct xencons_priv *cons);
68a231723cSRoger Pau Monné typedef int xencons_init_t(device_t dev, struct tty *tp,
69a231723cSRoger Pau Monné driver_intr_t intr_handler);
70a231723cSRoger Pau Monné typedef int xencons_read_t(struct xencons_priv *cons, char *buffer,
71a231723cSRoger Pau Monné unsigned int size);
72a231723cSRoger Pau Monné typedef int xencons_write_t(struct xencons_priv *cons, const char *buffer,
73a231723cSRoger Pau Monné unsigned int size);
74a231723cSRoger Pau Monné
75a231723cSRoger Pau Monné struct xencons_ops {
76a231723cSRoger Pau Monné /*
77a231723cSRoger Pau Monné * Called by the low-level driver during early boot.
78a231723cSRoger Pau Monné * Only the minimal set up to get a console should be done here.
79a231723cSRoger Pau Monné */
80a231723cSRoger Pau Monné xencons_early_init_t *early_init;
81a231723cSRoger Pau Monné /* Prepare the console to be fully use */
82a231723cSRoger Pau Monné xencons_init_t *init;
83a231723cSRoger Pau Monné /* Read/write helpers */
84a231723cSRoger Pau Monné xencons_read_t *read;
85a231723cSRoger Pau Monné xencons_write_t *write;
86a231723cSRoger Pau Monné };
87a231723cSRoger Pau Monné
88a231723cSRoger Pau Monné struct xencons_priv {
89a231723cSRoger Pau Monné /* Mutex to protect the shared ring and the internal buffers */
90a231723cSRoger Pau Monné struct mtx mtx;
91a231723cSRoger Pau Monné /* Interrupt handler used for notify the backend */
92a231723cSRoger Pau Monné xen_intr_handle_t intr_handle;
93a231723cSRoger Pau Monné /* KDB internal state */
94a231723cSRoger Pau Monné #ifdef KDB
95a231723cSRoger Pau Monné int altbrk;
96a231723cSRoger Pau Monné #endif
97a231723cSRoger Pau Monné /* Status of the tty */
98a231723cSRoger Pau Monné bool opened;
99a231723cSRoger Pau Monné /* Callout used when the write buffer is full */
100a231723cSRoger Pau Monné struct callout callout;
101a231723cSRoger Pau Monné
102a231723cSRoger Pau Monné /* Internal buffers must be used with mtx locked */
103a231723cSRoger Pau Monné #define WBUF_SIZE 4096
104a231723cSRoger Pau Monné #define WBUF_MASK(_i) ((_i)&(WBUF_SIZE-1))
105a231723cSRoger Pau Monné char wbuf[WBUF_SIZE];
106a231723cSRoger Pau Monné unsigned int wc, wp; /* Consumer/producer wbuf */
107a231723cSRoger Pau Monné
108a231723cSRoger Pau Monné #define RBUF_SIZE 1024
109a231723cSRoger Pau Monné #define RBUF_MASK(_i) ((_i)&(RBUF_SIZE-1))
110a231723cSRoger Pau Monné char rbuf[RBUF_SIZE];
111a231723cSRoger Pau Monné unsigned int rc, rp; /* Consumer/producer rbuf */
112a231723cSRoger Pau Monné
113a231723cSRoger Pau Monné /* Pointer to the console operations */
114a231723cSRoger Pau Monné const struct xencons_ops *ops;
115a231723cSRoger Pau Monné
116a231723cSRoger Pau Monné /*
117a231723cSRoger Pau Monné * Ring specific fields
118a231723cSRoger Pau Monné * XXX: make an union?
119a231723cSRoger Pau Monné */
120a231723cSRoger Pau Monné /* Event channel number for early notification (PV only) */
121a231723cSRoger Pau Monné uint32_t evtchn;
122a231723cSRoger Pau Monné /* Console shared page */
123a231723cSRoger Pau Monné struct xencons_interface *intf;
124a231723cSRoger Pau Monné };
125a231723cSRoger Pau Monné
126a231723cSRoger Pau Monné /*
127a231723cSRoger Pau Monné * Data for the main console
128a231723cSRoger Pau Monné * Necessary to support low-level console driver
129a231723cSRoger Pau Monné */
130a231723cSRoger Pau Monné static struct xencons_priv main_cons;
131a231723cSRoger Pau Monné
132a231723cSRoger Pau Monné #define XC_POLLTIME (hz/10)
133a231723cSRoger Pau Monné
134a231723cSRoger Pau Monné /*----------------------------- Debug function ------------------------------*/
135a231723cSRoger Pau Monné struct putchar_arg {
136a231723cSRoger Pau Monné char *buf;
137a231723cSRoger Pau Monné size_t size;
138a231723cSRoger Pau Monné size_t n_next;
139a231723cSRoger Pau Monné };
140a231723cSRoger Pau Monné
141*399386f1SRoger Pau Monné void __weak_symbol
xen_emergency_print(const char * str,size_t size)142*399386f1SRoger Pau Monné xen_emergency_print(const char *str, size_t size)
143*399386f1SRoger Pau Monné {
144*399386f1SRoger Pau Monné KASSERT((xen_domain()), ("call to xc_printf from non Xen guest"));
145*399386f1SRoger Pau Monné HYPERVISOR_console_write(str, size);
146*399386f1SRoger Pau Monné }
147*399386f1SRoger Pau Monné
148a231723cSRoger Pau Monné static void
putchar(int c,void * arg)149a231723cSRoger Pau Monné putchar(int c, void *arg)
150a231723cSRoger Pau Monné {
151a231723cSRoger Pau Monné struct putchar_arg *pca;
152a231723cSRoger Pau Monné
153a231723cSRoger Pau Monné pca = (struct putchar_arg *)arg;
154a231723cSRoger Pau Monné
155a231723cSRoger Pau Monné if (pca->buf == NULL) {
156a231723cSRoger Pau Monné /*
157a231723cSRoger Pau Monné * We have no buffer, output directly to the
158a231723cSRoger Pau Monné * console char by char.
159a231723cSRoger Pau Monné */
160*399386f1SRoger Pau Monné xen_emergency_print((char *)&c, 1);
161a231723cSRoger Pau Monné } else {
162a231723cSRoger Pau Monné pca->buf[pca->n_next++] = c;
163a231723cSRoger Pau Monné if ((pca->size == pca->n_next) || (c = '\0')) {
164a231723cSRoger Pau Monné /* Flush the buffer */
165*399386f1SRoger Pau Monné xen_emergency_print(pca->buf, pca->n_next);
166a231723cSRoger Pau Monné pca->n_next = 0;
167a231723cSRoger Pau Monné }
168a231723cSRoger Pau Monné }
169a231723cSRoger Pau Monné }
170a231723cSRoger Pau Monné
171a231723cSRoger Pau Monné void
xc_printf(const char * fmt,...)172a231723cSRoger Pau Monné xc_printf(const char *fmt, ...)
173a231723cSRoger Pau Monné {
174a231723cSRoger Pau Monné va_list ap;
175a231723cSRoger Pau Monné struct putchar_arg pca;
176a231723cSRoger Pau Monné #ifdef PRINTF_BUFR_SIZE
177a231723cSRoger Pau Monné char buf[PRINTF_BUFR_SIZE];
178a231723cSRoger Pau Monné
179a231723cSRoger Pau Monné pca.buf = buf;
180a231723cSRoger Pau Monné pca.size = sizeof(buf);
181a231723cSRoger Pau Monné pca.n_next = 0;
182a231723cSRoger Pau Monné #else
183a231723cSRoger Pau Monné pca.buf = NULL;
184a231723cSRoger Pau Monné pca.size = 0;
185a231723cSRoger Pau Monné #endif
186a231723cSRoger Pau Monné
187a231723cSRoger Pau Monné va_start(ap, fmt);
188a231723cSRoger Pau Monné kvprintf(fmt, putchar, &pca, 10, ap);
189a231723cSRoger Pau Monné va_end(ap);
190a231723cSRoger Pau Monné
191a231723cSRoger Pau Monné #ifdef PRINTF_BUFR_SIZE
192a231723cSRoger Pau Monné if (pca.n_next != 0)
193*399386f1SRoger Pau Monné xen_emergency_print(buf, pca.n_next);
194a231723cSRoger Pau Monné #endif
195a231723cSRoger Pau Monné }
196a231723cSRoger Pau Monné
197a231723cSRoger Pau Monné /*---------------------- Helpers for the console lock -----------------------*/
198a231723cSRoger Pau Monné /*
199a231723cSRoger Pau Monné * The lock is not used when the kernel is panicing as it will never recover
200a231723cSRoger Pau Monné * and we want to output no matter what it costs.
201a231723cSRoger Pau Monné */
xencons_lock(struct xencons_priv * cons)202a231723cSRoger Pau Monné static inline void xencons_lock(struct xencons_priv *cons)
203a231723cSRoger Pau Monné {
204a231723cSRoger Pau Monné
205879e0604SMateusz Guzik if (!KERNEL_PANICKED())
206a231723cSRoger Pau Monné mtx_lock_spin(&cons->mtx);
207a231723cSRoger Pau Monné
208a231723cSRoger Pau Monné }
209a231723cSRoger Pau Monné
xencons_unlock(struct xencons_priv * cons)210a231723cSRoger Pau Monné static inline void xencons_unlock(struct xencons_priv *cons)
211a231723cSRoger Pau Monné {
212a231723cSRoger Pau Monné
213879e0604SMateusz Guzik if (!KERNEL_PANICKED())
214a231723cSRoger Pau Monné mtx_unlock_spin(&cons->mtx);
215a231723cSRoger Pau Monné }
216a231723cSRoger Pau Monné
217a231723cSRoger Pau Monné #define xencons_lock_assert(cons) mtx_assert(&(cons)->mtx, MA_OWNED)
218a231723cSRoger Pau Monné
219a231723cSRoger Pau Monné /*------------------ Helpers for the hypervisor console ---------------------*/
220a231723cSRoger Pau Monné static void
xencons_early_init_hypervisor(struct xencons_priv * cons)221a231723cSRoger Pau Monné xencons_early_init_hypervisor(struct xencons_priv *cons)
222a231723cSRoger Pau Monné {
223a231723cSRoger Pau Monné /*
224a231723cSRoger Pau Monné * Nothing to setup for the low-level console when using
225a231723cSRoger Pau Monné * the hypervisor console.
226a231723cSRoger Pau Monné */
227a231723cSRoger Pau Monné }
228a231723cSRoger Pau Monné
229a231723cSRoger Pau Monné static int
xencons_init_hypervisor(device_t dev,struct tty * tp,driver_intr_t intr_handler)230a231723cSRoger Pau Monné xencons_init_hypervisor(device_t dev, struct tty *tp,
231a231723cSRoger Pau Monné driver_intr_t intr_handler)
232a231723cSRoger Pau Monné {
233a231723cSRoger Pau Monné struct xencons_priv *cons;
234a231723cSRoger Pau Monné int err;
235a231723cSRoger Pau Monné
236a231723cSRoger Pau Monné cons = tty_softc(tp);
237a231723cSRoger Pau Monné
238a231723cSRoger Pau Monné err = xen_intr_bind_virq(dev, VIRQ_CONSOLE, 0, NULL,
239a231723cSRoger Pau Monné intr_handler, tp, INTR_TYPE_TTY | INTR_MPSAFE, &cons->intr_handle);
240a231723cSRoger Pau Monné if (err != 0)
241a231723cSRoger Pau Monné device_printf(dev, "Can't register console interrupt\n");
242a231723cSRoger Pau Monné
243a231723cSRoger Pau Monné return (err);
244a231723cSRoger Pau Monné }
245a231723cSRoger Pau Monné
246a231723cSRoger Pau Monné static int
xencons_write_hypervisor(struct xencons_priv * cons,const char * buffer,unsigned int size)247a231723cSRoger Pau Monné xencons_write_hypervisor(struct xencons_priv *cons, const char *buffer,
248a231723cSRoger Pau Monné unsigned int size)
249a231723cSRoger Pau Monné {
250a231723cSRoger Pau Monné
251a231723cSRoger Pau Monné HYPERVISOR_console_io(CONSOLEIO_write, size, buffer);
252a231723cSRoger Pau Monné
253a231723cSRoger Pau Monné return (size);
254a231723cSRoger Pau Monné }
255a231723cSRoger Pau Monné
256a231723cSRoger Pau Monné static int
xencons_read_hypervisor(struct xencons_priv * cons,char * buffer,unsigned int size)257a231723cSRoger Pau Monné xencons_read_hypervisor(struct xencons_priv *cons, char *buffer,
258a231723cSRoger Pau Monné unsigned int size)
259a231723cSRoger Pau Monné {
260a231723cSRoger Pau Monné
261a231723cSRoger Pau Monné xencons_lock_assert(cons);
262a231723cSRoger Pau Monné
263a231723cSRoger Pau Monné return (HYPERVISOR_console_io(CONSOLEIO_read, size, buffer));
264a231723cSRoger Pau Monné }
265a231723cSRoger Pau Monné
266a231723cSRoger Pau Monné static const struct xencons_ops xencons_hypervisor_ops = {
267a231723cSRoger Pau Monné .early_init = xencons_early_init_hypervisor,
268a231723cSRoger Pau Monné .init = xencons_init_hypervisor,
269a231723cSRoger Pau Monné .read = xencons_read_hypervisor,
270a231723cSRoger Pau Monné .write = xencons_write_hypervisor,
271a231723cSRoger Pau Monné };
272a231723cSRoger Pau Monné
273a231723cSRoger Pau Monné /*------------------ Helpers for the ring console ---------------------------*/
274a231723cSRoger Pau Monné static void
xencons_early_init_ring(struct xencons_priv * cons)275a231723cSRoger Pau Monné xencons_early_init_ring(struct xencons_priv *cons)
276a231723cSRoger Pau Monné {
277cfa0b7b8SRoger Pau Monné cons->intf = pmap_mapdev_attr(ptoa(xen_get_console_mfn()), PAGE_SIZE,
278b6ff9345SElliott Mitchell VM_MEMATTR_XEN);
279cfa0b7b8SRoger Pau Monné cons->evtchn = xen_get_console_evtchn();
280a231723cSRoger Pau Monné }
281a231723cSRoger Pau Monné
282a231723cSRoger Pau Monné static int
xencons_init_ring(device_t dev,struct tty * tp,driver_intr_t intr_handler)283a231723cSRoger Pau Monné xencons_init_ring(device_t dev, struct tty *tp, driver_intr_t intr_handler)
284a231723cSRoger Pau Monné {
285a231723cSRoger Pau Monné struct xencons_priv *cons;
286a231723cSRoger Pau Monné int err;
287a231723cSRoger Pau Monné
288a231723cSRoger Pau Monné cons = tty_softc(tp);
289a231723cSRoger Pau Monné
290a231723cSRoger Pau Monné if (cons->evtchn == 0)
291a231723cSRoger Pau Monné return (ENODEV);
292a231723cSRoger Pau Monné
293a231723cSRoger Pau Monné err = xen_intr_bind_local_port(dev, cons->evtchn, NULL,
294a231723cSRoger Pau Monné intr_handler, tp, INTR_TYPE_TTY | INTR_MPSAFE, &cons->intr_handle);
295a231723cSRoger Pau Monné if (err != 0)
296a231723cSRoger Pau Monné return (err);
297a231723cSRoger Pau Monné
298a231723cSRoger Pau Monné return (0);
299a231723cSRoger Pau Monné }
300a231723cSRoger Pau Monné
301a231723cSRoger Pau Monné static void
xencons_notify_ring(struct xencons_priv * cons)302a231723cSRoger Pau Monné xencons_notify_ring(struct xencons_priv *cons)
303a231723cSRoger Pau Monné {
304a231723cSRoger Pau Monné /*
305a231723cSRoger Pau Monné * The console may be used before the ring interrupt is properly
306a231723cSRoger Pau Monné * initialized.
307a231723cSRoger Pau Monné * If so, fallback to directly use the event channel hypercall.
308a231723cSRoger Pau Monné */
309a231723cSRoger Pau Monné if (__predict_true(cons->intr_handle != NULL))
310a231723cSRoger Pau Monné xen_intr_signal(cons->intr_handle);
311a231723cSRoger Pau Monné else {
312a231723cSRoger Pau Monné struct evtchn_send send = {
313a231723cSRoger Pau Monné .port = cons->evtchn
314a231723cSRoger Pau Monné };
315a231723cSRoger Pau Monné
316a231723cSRoger Pau Monné HYPERVISOR_event_channel_op(EVTCHNOP_send, &send);
317a231723cSRoger Pau Monné }
318a231723cSRoger Pau Monné }
319a231723cSRoger Pau Monné
320a231723cSRoger Pau Monné static int
xencons_write_ring(struct xencons_priv * cons,const char * buffer,unsigned int size)321a231723cSRoger Pau Monné xencons_write_ring(struct xencons_priv *cons, const char *buffer,
322a231723cSRoger Pau Monné unsigned int size)
323a231723cSRoger Pau Monné {
324a231723cSRoger Pau Monné struct xencons_interface *intf;
325a231723cSRoger Pau Monné XENCONS_RING_IDX wcons, wprod;
326a231723cSRoger Pau Monné int sent;
327a231723cSRoger Pau Monné
328a231723cSRoger Pau Monné intf = cons->intf;
329a231723cSRoger Pau Monné
330a231723cSRoger Pau Monné xencons_lock_assert(cons);
331a231723cSRoger Pau Monné
332a231723cSRoger Pau Monné wcons = intf->out_cons;
333a231723cSRoger Pau Monné wprod = intf->out_prod;
334a231723cSRoger Pau Monné
335a231723cSRoger Pau Monné mb();
336a231723cSRoger Pau Monné KASSERT((wprod - wcons) <= sizeof(intf->out),
337a231723cSRoger Pau Monné ("console send ring inconsistent"));
338a231723cSRoger Pau Monné
339a231723cSRoger Pau Monné for (sent = 0; sent < size; sent++, wprod++) {
340a231723cSRoger Pau Monné if ((wprod - wcons) >= sizeof(intf->out))
341a231723cSRoger Pau Monné break;
342a231723cSRoger Pau Monné intf->out[MASK_XENCONS_IDX(wprod, intf->out)] = buffer[sent];
343a231723cSRoger Pau Monné }
344a231723cSRoger Pau Monné
345a231723cSRoger Pau Monné wmb();
346a231723cSRoger Pau Monné intf->out_prod = wprod;
347a231723cSRoger Pau Monné
348a231723cSRoger Pau Monné xencons_notify_ring(cons);
349a231723cSRoger Pau Monné
350a231723cSRoger Pau Monné return (sent);
351a231723cSRoger Pau Monné }
352a231723cSRoger Pau Monné
353a231723cSRoger Pau Monné static int
xencons_read_ring(struct xencons_priv * cons,char * buffer,unsigned int size)354a231723cSRoger Pau Monné xencons_read_ring(struct xencons_priv *cons, char *buffer, unsigned int size)
355a231723cSRoger Pau Monné {
356a231723cSRoger Pau Monné struct xencons_interface *intf;
357a231723cSRoger Pau Monné XENCONS_RING_IDX rcons, rprod;
358a231723cSRoger Pau Monné unsigned int rsz;
359a231723cSRoger Pau Monné
360a231723cSRoger Pau Monné intf = cons->intf;
361a231723cSRoger Pau Monné
362a231723cSRoger Pau Monné xencons_lock_assert(cons);
363a231723cSRoger Pau Monné
364a231723cSRoger Pau Monné rcons = intf->in_cons;
365a231723cSRoger Pau Monné rprod = intf->in_prod;
366a231723cSRoger Pau Monné rmb();
367a231723cSRoger Pau Monné
368a231723cSRoger Pau Monné for (rsz = 0; rsz < size; rsz++, rcons++) {
369a231723cSRoger Pau Monné if (rprod == rcons)
370a231723cSRoger Pau Monné break;
371a231723cSRoger Pau Monné buffer[rsz] = intf->in[MASK_XENCONS_IDX(rcons, intf->in)];
372a231723cSRoger Pau Monné }
373a231723cSRoger Pau Monné
374a231723cSRoger Pau Monné wmb();
375a231723cSRoger Pau Monné intf->in_cons = rcons;
376a231723cSRoger Pau Monné
377a231723cSRoger Pau Monné /* No need to notify the backend if nothing has been read */
378a231723cSRoger Pau Monné if (rsz != 0)
379a231723cSRoger Pau Monné xencons_notify_ring(cons);
380a231723cSRoger Pau Monné
381a231723cSRoger Pau Monné return (rsz);
382a231723cSRoger Pau Monné }
383a231723cSRoger Pau Monné
384a231723cSRoger Pau Monné static const struct xencons_ops xencons_ring_ops = {
385a231723cSRoger Pau Monné .early_init = xencons_early_init_ring,
386a231723cSRoger Pau Monné .init = xencons_init_ring,
387a231723cSRoger Pau Monné .read = xencons_read_ring,
388a231723cSRoger Pau Monné .write = xencons_write_ring,
389a231723cSRoger Pau Monné };
390a231723cSRoger Pau Monné
391a231723cSRoger Pau Monné /*------------------ Common implementation of the console -------------------*/
392a231723cSRoger Pau Monné
393a231723cSRoger Pau Monné /*
394a231723cSRoger Pau Monné * Called by the low-level driver during early boot to initialize the
395a231723cSRoger Pau Monné * main console driver.
396a231723cSRoger Pau Monné * Only the minimal set up to get a console should be done here.
397a231723cSRoger Pau Monné */
398a231723cSRoger Pau Monné static void
xencons_early_init(void)399a231723cSRoger Pau Monné xencons_early_init(void)
400a231723cSRoger Pau Monné {
401a231723cSRoger Pau Monné
402a231723cSRoger Pau Monné mtx_init(&main_cons.mtx, "XCONS LOCK", NULL, MTX_SPIN);
403a231723cSRoger Pau Monné
404fa609042SRoger Pau Monné if (xen_get_console_evtchn() == 0)
405a231723cSRoger Pau Monné main_cons.ops = &xencons_hypervisor_ops;
406a231723cSRoger Pau Monné else
407a231723cSRoger Pau Monné main_cons.ops = &xencons_ring_ops;
408a231723cSRoger Pau Monné
409a231723cSRoger Pau Monné main_cons.ops->early_init(&main_cons);
410a231723cSRoger Pau Monné }
411a231723cSRoger Pau Monné
412a231723cSRoger Pau Monné /*
413a231723cSRoger Pau Monné * Receive character from the console and put them in the internal buffer
414a231723cSRoger Pau Monné * XXX: Handle overflow of the internal buffer
415a231723cSRoger Pau Monné */
416a231723cSRoger Pau Monné static void
xencons_rx(struct xencons_priv * cons)417a231723cSRoger Pau Monné xencons_rx(struct xencons_priv *cons)
418a231723cSRoger Pau Monné {
419a231723cSRoger Pau Monné char buf[16];
420a231723cSRoger Pau Monné int sz;
421a231723cSRoger Pau Monné
422a231723cSRoger Pau Monné xencons_lock(cons);
423a231723cSRoger Pau Monné while ((sz = cons->ops->read(cons, buf, sizeof(buf))) > 0) {
424a231723cSRoger Pau Monné int i;
425a231723cSRoger Pau Monné
426a231723cSRoger Pau Monné for (i = 0; i < sz; i++)
427a231723cSRoger Pau Monné cons->rbuf[RBUF_MASK(cons->rp++)] = buf[i];
428a231723cSRoger Pau Monné }
429a231723cSRoger Pau Monné xencons_unlock(cons);
430a231723cSRoger Pau Monné }
431a231723cSRoger Pau Monné
432a231723cSRoger Pau Monné /* Return true if the write buffer is full */
433a231723cSRoger Pau Monné static bool
xencons_tx_full(struct xencons_priv * cons)434a231723cSRoger Pau Monné xencons_tx_full(struct xencons_priv *cons)
435a231723cSRoger Pau Monné {
436a231723cSRoger Pau Monné unsigned int used;
437a231723cSRoger Pau Monné
438a231723cSRoger Pau Monné xencons_lock(cons);
439a231723cSRoger Pau Monné used = cons->wp - cons->wc;
440a231723cSRoger Pau Monné xencons_unlock(cons);
441a231723cSRoger Pau Monné
442a231723cSRoger Pau Monné return (used >= WBUF_SIZE);
443a231723cSRoger Pau Monné }
444a231723cSRoger Pau Monné
445a231723cSRoger Pau Monné static void
xencons_tx_flush(struct xencons_priv * cons,int force)446a231723cSRoger Pau Monné xencons_tx_flush(struct xencons_priv *cons, int force)
447a231723cSRoger Pau Monné {
448a231723cSRoger Pau Monné int sz;
449a231723cSRoger Pau Monné
450a231723cSRoger Pau Monné xencons_lock(cons);
451a231723cSRoger Pau Monné while (cons->wc != cons->wp) {
452a231723cSRoger Pau Monné int sent;
453a231723cSRoger Pau Monné sz = cons->wp - cons->wc;
454a231723cSRoger Pau Monné if (sz > (WBUF_SIZE - WBUF_MASK(cons->wc)))
455a231723cSRoger Pau Monné sz = WBUF_SIZE - WBUF_MASK(cons->wc);
456a231723cSRoger Pau Monné sent = cons->ops->write(cons, &cons->wbuf[WBUF_MASK(cons->wc)],
457a231723cSRoger Pau Monné sz);
458a231723cSRoger Pau Monné
459a231723cSRoger Pau Monné /*
460a231723cSRoger Pau Monné * The other end may not have been initialized. Ignore
461a231723cSRoger Pau Monné * the force.
462a231723cSRoger Pau Monné */
463a231723cSRoger Pau Monné if (__predict_false(sent < 0))
464a231723cSRoger Pau Monné break;
465a231723cSRoger Pau Monné
466a231723cSRoger Pau Monné /*
467a231723cSRoger Pau Monné * If force is set, spin until the console data is
468a231723cSRoger Pau Monné * flushed through the domain controller.
469a231723cSRoger Pau Monné */
470a231723cSRoger Pau Monné if (sent == 0 && __predict_true(!force))
471a231723cSRoger Pau Monné break;
472a231723cSRoger Pau Monné
473a231723cSRoger Pau Monné cons->wc += sent;
474a231723cSRoger Pau Monné }
475a231723cSRoger Pau Monné xencons_unlock(cons);
476a231723cSRoger Pau Monné }
477a231723cSRoger Pau Monné
478a231723cSRoger Pau Monné static bool
xencons_putc(struct xencons_priv * cons,int c,bool force_flush)479a231723cSRoger Pau Monné xencons_putc(struct xencons_priv *cons, int c, bool force_flush)
480a231723cSRoger Pau Monné {
481a231723cSRoger Pau Monné
482a231723cSRoger Pau Monné xencons_lock(cons);
483a231723cSRoger Pau Monné if ((cons->wp - cons->wc) < WBUF_SIZE)
484a231723cSRoger Pau Monné cons->wbuf[WBUF_MASK(cons->wp++)] = c;
485a231723cSRoger Pau Monné xencons_unlock(cons);
486a231723cSRoger Pau Monné
487a231723cSRoger Pau Monné xencons_tx_flush(cons, force_flush);
488a231723cSRoger Pau Monné
489a231723cSRoger Pau Monné return (xencons_tx_full(cons));
490a231723cSRoger Pau Monné }
491a231723cSRoger Pau Monné
492a231723cSRoger Pau Monné static int
xencons_getc(struct xencons_priv * cons)493a231723cSRoger Pau Monné xencons_getc(struct xencons_priv *cons)
494a231723cSRoger Pau Monné {
495a231723cSRoger Pau Monné int ret;
496a231723cSRoger Pau Monné
497a231723cSRoger Pau Monné xencons_lock(cons);
498a231723cSRoger Pau Monné if (cons->rp != cons->rc) {
499a231723cSRoger Pau Monné /* We need to return only one char */
500a231723cSRoger Pau Monné ret = (int)cons->rbuf[RBUF_MASK(cons->rc)];
501a231723cSRoger Pau Monné cons->rc++;
502a231723cSRoger Pau Monné } else {
503a231723cSRoger Pau Monné ret = -1;
504a231723cSRoger Pau Monné }
505a231723cSRoger Pau Monné
506a231723cSRoger Pau Monné xencons_unlock(cons);
507a231723cSRoger Pau Monné
508a231723cSRoger Pau Monné return (ret);
509a231723cSRoger Pau Monné }
510a231723cSRoger Pau Monné
511a231723cSRoger Pau Monné static bool
xencons_tx(struct tty * tp)512a231723cSRoger Pau Monné xencons_tx(struct tty *tp)
513a231723cSRoger Pau Monné {
514a231723cSRoger Pau Monné bool cons_full;
515a231723cSRoger Pau Monné char c;
516a231723cSRoger Pau Monné struct xencons_priv *cons;
517a231723cSRoger Pau Monné
518a231723cSRoger Pau Monné cons = tty_softc(tp);
519a231723cSRoger Pau Monné
52023d53268SKyle Evans tty_assert_locked(tp);
521a231723cSRoger Pau Monné
522a231723cSRoger Pau Monné /*
523a231723cSRoger Pau Monné * Don't transmit any character if the buffer is full. Otherwise,
524a231723cSRoger Pau Monné * characters may be lost
525a231723cSRoger Pau Monné */
526a231723cSRoger Pau Monné if (xencons_tx_full(cons))
527a231723cSRoger Pau Monné return (false);
528a231723cSRoger Pau Monné
529a231723cSRoger Pau Monné cons_full = false;
530a231723cSRoger Pau Monné while (!cons_full && ttydisc_getc(tp, &c, 1) == 1)
531a231723cSRoger Pau Monné cons_full = xencons_putc(cons, c, false);
532a231723cSRoger Pau Monné
533a231723cSRoger Pau Monné return (!cons_full);
534a231723cSRoger Pau Monné }
535a231723cSRoger Pau Monné
536a231723cSRoger Pau Monné static void
xencons_intr(void * arg)537a231723cSRoger Pau Monné xencons_intr(void *arg)
538a231723cSRoger Pau Monné {
539a231723cSRoger Pau Monné struct tty *tp;
540a231723cSRoger Pau Monné struct xencons_priv *cons;
541a231723cSRoger Pau Monné int ret;
542a231723cSRoger Pau Monné
543a231723cSRoger Pau Monné tp = arg;
544a231723cSRoger Pau Monné cons = tty_softc(tp);
545a231723cSRoger Pau Monné
546a231723cSRoger Pau Monné /*
547a231723cSRoger Pau Monné * The input will be used by the low-level console when KDB is active
548a231723cSRoger Pau Monné */
549a231723cSRoger Pau Monné if (kdb_active)
550a231723cSRoger Pau Monné return;
551a231723cSRoger Pau Monné
552a231723cSRoger Pau Monné /*
553a231723cSRoger Pau Monné * It's not necessary to retrieve input when the tty is not opened
554a231723cSRoger Pau Monné */
555a231723cSRoger Pau Monné if (!cons->opened)
556a231723cSRoger Pau Monné return;
557a231723cSRoger Pau Monné
558a231723cSRoger Pau Monné xencons_rx(cons);
559a231723cSRoger Pau Monné
560a231723cSRoger Pau Monné tty_lock(tp);
561a231723cSRoger Pau Monné while ((ret = xencons_getc(cons)) != -1) {
562a231723cSRoger Pau Monné #ifdef KDB
563a231723cSRoger Pau Monné kdb_alt_break(ret, &cons->altbrk);
564a231723cSRoger Pau Monné #endif
565a231723cSRoger Pau Monné ttydisc_rint(tp, ret, 0);
566a231723cSRoger Pau Monné }
567a231723cSRoger Pau Monné ttydisc_rint_done(tp);
568a231723cSRoger Pau Monné tty_unlock(tp);
569a231723cSRoger Pau Monné
570a231723cSRoger Pau Monné /* Try to flush remaining characters if necessary */
571a231723cSRoger Pau Monné xencons_tx_flush(cons, 0);
572a231723cSRoger Pau Monné }
573a231723cSRoger Pau Monné
574a231723cSRoger Pau Monné /*
575a231723cSRoger Pau Monné * Helpers to call while shutting down:
576a231723cSRoger Pau Monné * - Force flush all output
577a231723cSRoger Pau Monné */
578a231723cSRoger Pau Monné static void
xencons_shutdown(void * arg,int howto)579a231723cSRoger Pau Monné xencons_shutdown(void *arg, int howto)
580a231723cSRoger Pau Monné {
581a231723cSRoger Pau Monné struct tty *tp;
582a231723cSRoger Pau Monné
583a231723cSRoger Pau Monné tp = arg;
584a231723cSRoger Pau Monné
585a231723cSRoger Pau Monné xencons_tx_flush(tty_softc(tp), 1);
586a231723cSRoger Pau Monné }
587a231723cSRoger Pau Monné
588a231723cSRoger Pau Monné /*---------------------- Low-level console driver ---------------------------*/
589a231723cSRoger Pau Monné static void
xencons_cnprobe(struct consdev * cp)590a231723cSRoger Pau Monné xencons_cnprobe(struct consdev *cp)
591a231723cSRoger Pau Monné {
592a231723cSRoger Pau Monné
593fa609042SRoger Pau Monné if (!xen_domain())
594a231723cSRoger Pau Monné return;
595a231723cSRoger Pau Monné
596d16bd541SRoger Pau Monné cp->cn_pri = (boothowto & RB_SERIAL) ? CN_REMOTE : CN_NORMAL;
597a231723cSRoger Pau Monné sprintf(cp->cn_name, "%s0", driver_name);
598a231723cSRoger Pau Monné }
599a231723cSRoger Pau Monné
600a231723cSRoger Pau Monné static void
xencons_cninit(struct consdev * cp)601a231723cSRoger Pau Monné xencons_cninit(struct consdev *cp)
602a231723cSRoger Pau Monné {
603a231723cSRoger Pau Monné
604a231723cSRoger Pau Monné xencons_early_init();
605a231723cSRoger Pau Monné }
606a231723cSRoger Pau Monné
607a231723cSRoger Pau Monné static void
xencons_cnterm(struct consdev * cp)608a231723cSRoger Pau Monné xencons_cnterm(struct consdev *cp)
609a231723cSRoger Pau Monné {
610a231723cSRoger Pau Monné }
611a231723cSRoger Pau Monné
612a231723cSRoger Pau Monné static void
xencons_cngrab(struct consdev * cp)613a231723cSRoger Pau Monné xencons_cngrab(struct consdev *cp)
614a231723cSRoger Pau Monné {
615a231723cSRoger Pau Monné }
616a231723cSRoger Pau Monné
617a231723cSRoger Pau Monné static void
xencons_cnungrab(struct consdev * cp)618a231723cSRoger Pau Monné xencons_cnungrab(struct consdev *cp)
619a231723cSRoger Pau Monné {
620a231723cSRoger Pau Monné }
621a231723cSRoger Pau Monné
622a231723cSRoger Pau Monné static int
xencons_cngetc(struct consdev * dev)623a231723cSRoger Pau Monné xencons_cngetc(struct consdev *dev)
624a231723cSRoger Pau Monné {
625a231723cSRoger Pau Monné
626a231723cSRoger Pau Monné xencons_rx(&main_cons);
627a231723cSRoger Pau Monné
628a231723cSRoger Pau Monné return (xencons_getc(&main_cons));
629a231723cSRoger Pau Monné }
630a231723cSRoger Pau Monné
631a231723cSRoger Pau Monné static void
xencons_cnputc(struct consdev * dev,int c)632a231723cSRoger Pau Monné xencons_cnputc(struct consdev *dev, int c)
633a231723cSRoger Pau Monné {
634a231723cSRoger Pau Monné /*
635a231723cSRoger Pau Monné * The low-level console is used by KDB and panic. We have to ensure
636a231723cSRoger Pau Monné * that any character sent will be seen by the backend.
637a231723cSRoger Pau Monné */
638a231723cSRoger Pau Monné xencons_putc(&main_cons, c, true);
639a231723cSRoger Pau Monné }
640a231723cSRoger Pau Monné
641a231723cSRoger Pau Monné CONSOLE_DRIVER(xencons);
642a231723cSRoger Pau Monné
643a231723cSRoger Pau Monné /*----------------------------- TTY driver ---------------------------------*/
644a231723cSRoger Pau Monné
645a231723cSRoger Pau Monné static int
xencons_tty_open(struct tty * tp)646a231723cSRoger Pau Monné xencons_tty_open(struct tty *tp)
647a231723cSRoger Pau Monné {
648a231723cSRoger Pau Monné struct xencons_priv *cons;
649a231723cSRoger Pau Monné
650a231723cSRoger Pau Monné cons = tty_softc(tp);
651a231723cSRoger Pau Monné
652a231723cSRoger Pau Monné cons->opened = true;
653a231723cSRoger Pau Monné
654a231723cSRoger Pau Monné return (0);
655a231723cSRoger Pau Monné }
656a231723cSRoger Pau Monné
657a231723cSRoger Pau Monné static void
xencons_tty_close(struct tty * tp)658a231723cSRoger Pau Monné xencons_tty_close(struct tty *tp)
659a231723cSRoger Pau Monné {
660a231723cSRoger Pau Monné struct xencons_priv *cons;
661a231723cSRoger Pau Monné
662a231723cSRoger Pau Monné cons = tty_softc(tp);
663a231723cSRoger Pau Monné
664a231723cSRoger Pau Monné cons->opened = false;
665a231723cSRoger Pau Monné }
666a231723cSRoger Pau Monné
667a231723cSRoger Pau Monné static void
xencons_timeout(void * v)668a231723cSRoger Pau Monné xencons_timeout(void *v)
669a231723cSRoger Pau Monné {
670a231723cSRoger Pau Monné struct tty *tp;
671a231723cSRoger Pau Monné struct xencons_priv *cons;
672a231723cSRoger Pau Monné
673a231723cSRoger Pau Monné tp = v;
674a231723cSRoger Pau Monné cons = tty_softc(tp);
675a231723cSRoger Pau Monné
676a231723cSRoger Pau Monné if (!xencons_tx(tp))
677a231723cSRoger Pau Monné callout_reset(&cons->callout, XC_POLLTIME,
678a231723cSRoger Pau Monné xencons_timeout, tp);
679a231723cSRoger Pau Monné }
680a231723cSRoger Pau Monné
681a231723cSRoger Pau Monné static void
xencons_tty_outwakeup(struct tty * tp)682a231723cSRoger Pau Monné xencons_tty_outwakeup(struct tty *tp)
683a231723cSRoger Pau Monné {
684a231723cSRoger Pau Monné struct xencons_priv *cons;
685a231723cSRoger Pau Monné
686a231723cSRoger Pau Monné cons = tty_softc(tp);
687a231723cSRoger Pau Monné
688a231723cSRoger Pau Monné callout_stop(&cons->callout);
689a231723cSRoger Pau Monné
690a231723cSRoger Pau Monné if (!xencons_tx(tp))
691a231723cSRoger Pau Monné callout_reset(&cons->callout, XC_POLLTIME,
692a231723cSRoger Pau Monné xencons_timeout, tp);
693a231723cSRoger Pau Monné }
694a231723cSRoger Pau Monné
695a231723cSRoger Pau Monné static struct ttydevsw xencons_ttydevsw = {
696a231723cSRoger Pau Monné .tsw_flags = TF_NOPREFIX,
697a231723cSRoger Pau Monné .tsw_open = xencons_tty_open,
698a231723cSRoger Pau Monné .tsw_close = xencons_tty_close,
699a231723cSRoger Pau Monné .tsw_outwakeup = xencons_tty_outwakeup,
700a231723cSRoger Pau Monné };
701a231723cSRoger Pau Monné
702a231723cSRoger Pau Monné /*------------------------ Main console driver ------------------------------*/
703a231723cSRoger Pau Monné static void
xencons_identify(driver_t * driver,device_t parent)704a231723cSRoger Pau Monné xencons_identify(driver_t *driver, device_t parent)
705a231723cSRoger Pau Monné {
706e7236a7dSMateusz Guzik device_t child __unused;
707a231723cSRoger Pau Monné
708fa609042SRoger Pau Monné if (main_cons.ops == NULL)
709a231723cSRoger Pau Monné return;
710a231723cSRoger Pau Monné
711a231723cSRoger Pau Monné child = BUS_ADD_CHILD(parent, 0, driver_name, 0);
712a231723cSRoger Pau Monné }
713a231723cSRoger Pau Monné
714a231723cSRoger Pau Monné static int
xencons_probe(device_t dev)715a231723cSRoger Pau Monné xencons_probe(device_t dev)
716a231723cSRoger Pau Monné {
717a231723cSRoger Pau Monné
718a231723cSRoger Pau Monné device_set_desc(dev, "Xen Console");
719a231723cSRoger Pau Monné return (BUS_PROBE_NOWILDCARD);
720a231723cSRoger Pau Monné }
721a231723cSRoger Pau Monné
722a231723cSRoger Pau Monné static int
xencons_attach(device_t dev)723a231723cSRoger Pau Monné xencons_attach(device_t dev)
724a231723cSRoger Pau Monné {
725a231723cSRoger Pau Monné struct tty *tp;
726a231723cSRoger Pau Monné /*
727a231723cSRoger Pau Monné * The main console is already allocated statically in order to
728a231723cSRoger Pau Monné * support low-level console
729a231723cSRoger Pau Monné */
730a231723cSRoger Pau Monné struct xencons_priv *cons;
731a231723cSRoger Pau Monné int err;
732a231723cSRoger Pau Monné
733a231723cSRoger Pau Monné cons = &main_cons;
734a231723cSRoger Pau Monné
735a231723cSRoger Pau Monné tp = tty_alloc(&xencons_ttydevsw, cons);
736a231723cSRoger Pau Monné tty_makedev(tp, NULL, "%s%r", driver_name, 0);
737a231723cSRoger Pau Monné device_set_softc(dev, tp);
738a231723cSRoger Pau Monné
739a231723cSRoger Pau Monné callout_init_mtx(&cons->callout, tty_getlock(tp), 0);
740a231723cSRoger Pau Monné
741a231723cSRoger Pau Monné err = cons->ops->init(dev, tp, xencons_intr);
742a231723cSRoger Pau Monné if (err != 0) {
743a231723cSRoger Pau Monné device_printf(dev, "Unable to initialize the console (%d)\n",
744a231723cSRoger Pau Monné err);
745a231723cSRoger Pau Monné return (err);
746a231723cSRoger Pau Monné }
747a231723cSRoger Pau Monné
748a231723cSRoger Pau Monné /* register handler to flush console on shutdown */
749a231723cSRoger Pau Monné if ((EVENTHANDLER_REGISTER(shutdown_post_sync, xencons_shutdown,
750a231723cSRoger Pau Monné tp, SHUTDOWN_PRI_DEFAULT)) == NULL)
751a231723cSRoger Pau Monné device_printf(dev, "shutdown event registration failed!\n");
752a231723cSRoger Pau Monné
753a231723cSRoger Pau Monné return (0);
754a231723cSRoger Pau Monné }
755a231723cSRoger Pau Monné
756a231723cSRoger Pau Monné static int
xencons_resume(device_t dev)757a231723cSRoger Pau Monné xencons_resume(device_t dev)
758a231723cSRoger Pau Monné {
759a231723cSRoger Pau Monné struct xencons_priv *cons;
760a231723cSRoger Pau Monné struct tty *tp;
761a231723cSRoger Pau Monné int err;
762a231723cSRoger Pau Monné
763a231723cSRoger Pau Monné tp = device_get_softc(dev);
764a231723cSRoger Pau Monné cons = tty_softc(tp);
765a231723cSRoger Pau Monné xen_intr_unbind(&cons->intr_handle);
766a231723cSRoger Pau Monné
767a231723cSRoger Pau Monné err = cons->ops->init(dev, tp, xencons_intr);
768a231723cSRoger Pau Monné if (err != 0) {
769a231723cSRoger Pau Monné device_printf(dev, "Unable to resume the console (%d)\n", err);
770a231723cSRoger Pau Monné return (err);
771a231723cSRoger Pau Monné }
772a231723cSRoger Pau Monné
773a231723cSRoger Pau Monné return (0);
774a231723cSRoger Pau Monné }
775a231723cSRoger Pau Monné
776a231723cSRoger Pau Monné static device_method_t xencons_methods[] = {
777a231723cSRoger Pau Monné DEVMETHOD(device_identify, xencons_identify),
778a231723cSRoger Pau Monné DEVMETHOD(device_probe, xencons_probe),
779a231723cSRoger Pau Monné DEVMETHOD(device_attach, xencons_attach),
780a231723cSRoger Pau Monné DEVMETHOD(device_resume, xencons_resume),
781a231723cSRoger Pau Monné
782a231723cSRoger Pau Monné DEVMETHOD_END
783a231723cSRoger Pau Monné };
784a231723cSRoger Pau Monné
785a231723cSRoger Pau Monné static driver_t xencons_driver = {
786a231723cSRoger Pau Monné driver_name,
787a231723cSRoger Pau Monné xencons_methods,
788a231723cSRoger Pau Monné 0,
789a231723cSRoger Pau Monné };
790a231723cSRoger Pau Monné
791f929eb1eSJohn Baldwin DRIVER_MODULE(xc, xenpv, xencons_driver, 0, 0);
792