ia64/xen-unstable

view freebsd-5.3-xen-sparse/i386-xen/xen/char/console.c @ 6515:ac8cae1f2c47

Don't attempt to create paravirtualized devices for VMX domains for now.

Signed-off-by: Arun Sharma <arun.sharma@intel.com>
author adsharma@los-vmm.sc.intel.com
date Tue Aug 09 11:06:45 2005 -0800 (2005-08-09)
parents a01199a95070
children
line source
1 #include <sys/cdefs.h>
4 #include <sys/param.h>
5 #include <sys/module.h>
6 #include <sys/systm.h>
7 #include <sys/consio.h>
8 #include <sys/proc.h>
9 #include <sys/uio.h>
10 #include <sys/tty.h>
11 #include <sys/systm.h>
12 #include <sys/taskqueue.h>
13 #include <sys/conf.h>
14 #include <sys/kernel.h>
15 #include <sys/bus.h>
16 #include <machine/stdarg.h>
17 #include <machine/xen-os.h>
18 #include <machine/hypervisor.h>
19 #include <machine/ctrl_if.h>
20 #include <sys/cons.h>
22 #include "opt_ddb.h"
23 #ifdef DDB
24 #include <ddb/ddb.h>
25 #endif
27 static char driver_name[] = "xc";
28 devclass_t xc_devclass;
29 static void xcstart (struct tty *);
30 static int xcparam (struct tty *, struct termios *);
31 static void xcstop (struct tty *, int);
32 static void xc_timeout(void *);
33 static void xencons_tx_flush_task_routine(void *,int );
34 static void __xencons_tx_flush(void);
35 static void xencons_rx(ctrl_msg_t *msg,unsigned long id);
36 static boolean_t xcons_putc(int c);
38 /* switch console so that shutdown can occur gracefully */
39 static void xc_shutdown(void *arg, int howto);
40 static int xc_mute;
42 void xcons_force_flush(void);
44 static cn_probe_t xccnprobe;
45 static cn_init_t xccninit;
46 static cn_getc_t xccngetc;
47 static cn_putc_t xccnputc;
48 static cn_checkc_t xccncheckc;
50 #define XC_POLLTIME (hz/10)
52 CONS_DRIVER(xc, xccnprobe, xccninit, NULL, xccngetc,
53 xccncheckc, xccnputc, NULL);
55 static int xen_console_up;
56 static boolean_t xc_tx_task_queued;
57 static boolean_t xc_start_needed;
58 static struct callout xc_callout;
59 struct mtx cn_mtx;
61 #define RBUF_SIZE 1024
62 #define RBUF_MASK(_i) ((_i)&(RBUF_SIZE-1))
63 #define WBUF_SIZE 4096
64 #define WBUF_MASK(_i) ((_i)&(WBUF_SIZE-1))
65 static char wbuf[WBUF_SIZE];
66 static char rbuf[RBUF_SIZE];
67 static int rc, rp;
68 static int cnsl_evt_reg;
69 static unsigned int wc, wp; /* write_cons, write_prod */
70 static struct task xencons_tx_flush_task = { {NULL},0,0,&xencons_tx_flush_task_routine,NULL };
73 #define CDEV_MAJOR 12
74 #define XCUNIT(x) (minor(x))
75 #define ISTTYOPEN(tp) ((tp) && ((tp)->t_state & TS_ISOPEN))
76 #define CN_LOCK_INIT(x, _name) \
77 mtx_init(&x, _name, _name, MTX_SPIN)
78 #define CN_LOCK(l, f) mtx_lock_irqsave(&(l), (f))
79 #define CN_UNLOCK(l, f) mtx_unlock_irqrestore(&(l), (f))
80 #define CN_LOCK_ASSERT(x) mtx_assert(&x, MA_OWNED)
81 #define CN_LOCK_DESTROY(x) mtx_destroy(&x)
84 static struct tty *xccons;
86 struct xc_softc {
87 int xc_unit;
88 struct cdev *xc_dev;
89 };
92 static d_open_t xcopen;
93 static d_close_t xcclose;
94 static d_ioctl_t xcioctl;
96 static struct cdevsw xc_cdevsw = {
97 /* version */ D_VERSION_00,
98 /* maj */ CDEV_MAJOR,
99 /* flags */ D_TTY | D_NEEDGIANT,
100 /* name */ driver_name,
102 /* open */ xcopen,
103 /* fdopen */ 0,
104 /* close */ xcclose,
105 /* read */ ttyread,
106 /* write */ ttywrite,
107 /* ioctl */ xcioctl,
108 /* poll */ ttypoll,
109 /* mmap */ 0,
110 /* strategy */ 0,
111 /* dump */ 0,
112 /* kqfilter */ ttykqfilter
113 };
115 static void
116 xccnprobe(struct consdev *cp)
117 {
118 cp->cn_pri = CN_REMOTE;
119 cp->cn_tp = xccons;
120 sprintf(cp->cn_name, "%s0", driver_name);
121 }
124 static void
125 xccninit(struct consdev *cp)
126 {
127 CN_LOCK_INIT(cn_mtx,"XCONS LOCK");
129 }
130 int
131 xccngetc(struct consdev *dev)
132 {
133 int c;
134 if (xc_mute)
135 return 0;
136 do {
137 if ((c = xccncheckc(dev)) == -1) {
138 /* polling without sleeping in Xen doesn't work well.
139 * Sleeping gives other things like clock a chance to
140 * run
141 */
142 tsleep(&cn_mtx, PWAIT | PCATCH, "console sleep",
143 XC_POLLTIME);
144 }
145 } while( c == -1 );
146 return c;
147 }
149 int
150 xccncheckc(struct consdev *dev)
151 {
152 int ret = (xc_mute ? 0 : -1);
153 int flags;
154 CN_LOCK(cn_mtx, flags);
155 if ( (rp - rc) ){
156 /* we need to return only one char */
157 ret = (int)rbuf[RBUF_MASK(rc)];
158 rc++;
159 }
160 CN_UNLOCK(cn_mtx, flags);
161 return(ret);
162 }
164 static void
165 xccnputc(struct consdev *dev, int c)
166 {
167 int flags;
168 CN_LOCK(cn_mtx, flags);
169 xcons_putc(c);
170 CN_UNLOCK(cn_mtx, flags);
171 }
173 static boolean_t
174 xcons_putc(int c)
175 {
176 int force_flush = xc_mute ||
177 #ifdef DDB
178 db_active ||
179 #endif
180 panicstr; /* we're not gonna recover, so force
181 * flush
182 */
184 if ( (wp-wc) < (WBUF_SIZE-1) ){
185 if ( (wbuf[WBUF_MASK(wp++)] = c) == '\n' ) {
186 wbuf[WBUF_MASK(wp++)] = '\r';
187 if (force_flush)
188 xcons_force_flush();
189 }
190 } else if (force_flush) {
191 xcons_force_flush();
193 }
194 if (cnsl_evt_reg)
195 __xencons_tx_flush();
197 /* inform start path that we're pretty full */
198 return ((wp - wc) >= WBUF_SIZE - 100) ? TRUE : FALSE;
199 }
201 static void
202 xc_identify(driver_t *driver, device_t parent)
203 {
204 device_t child;
205 child = BUS_ADD_CHILD(parent, 0, driver_name, 0);
206 device_set_driver(child, driver);
207 device_set_desc(child, "Xen Console");
208 }
210 static int
211 xc_probe(device_t dev)
212 {
213 struct xc_softc *sc = (struct xc_softc *)device_get_softc(dev);
215 sc->xc_unit = device_get_unit(dev);
216 return (0);
217 }
219 static int
220 xc_attach(device_t dev)
221 {
222 struct xc_softc *sc = (struct xc_softc *)device_get_softc(dev);
224 sc->xc_dev = make_dev(&xc_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, "xc%r", 0);
225 xccons = ttymalloc(NULL);
227 sc->xc_dev->si_drv1 = (void *)sc;
228 sc->xc_dev->si_tty = xccons;
230 xccons->t_oproc = xcstart;
231 xccons->t_param = xcparam;
232 xccons->t_stop = xcstop;
233 xccons->t_dev = sc->xc_dev;
235 callout_init(&xc_callout, 0);
237 /* Ensure that we don't attach before the event channel is able to receive
238 * a registration. The XenBus code delays the probe/attach order until
239 * this has occurred.
240 */
241 (void)ctrl_if_register_receiver(CMSG_CONSOLE, xencons_rx, 0);
242 cnsl_evt_reg = 1;
244 callout_reset(&xc_callout, XC_POLLTIME, xc_timeout, xccons);
246 /* register handler to flush console on shutdown */
247 if ((EVENTHANDLER_REGISTER(shutdown_post_sync, xc_shutdown,
248 NULL, SHUTDOWN_PRI_DEFAULT)) == NULL)
249 printf("xencons: shutdown event registration failed!\n");
251 return (0);
252 }
254 /*
255 * return 0 for all console input, force flush all output.
256 */
257 static void
258 xc_shutdown(void *arg, int howto)
259 {
260 xc_mute = 1;
261 xcons_force_flush();
263 }
265 static void
266 xencons_rx(ctrl_msg_t *msg,unsigned long id)
267 {
268 int i, flags;
269 struct tty *tp = xccons;
271 CN_LOCK(cn_mtx, flags);
272 for ( i = 0; i < msg->length; i++ ) {
273 if ( xen_console_up )
274 (*linesw[tp->t_line]->l_rint)(msg->msg[i], tp);
275 else
276 rbuf[RBUF_MASK(rp++)] = msg->msg[i];
277 }
278 CN_UNLOCK(cn_mtx, flags);
279 msg->length = 0;
280 ctrl_if_send_response(msg);
281 }
283 static void
284 __xencons_tx_flush(void)
285 {
286 int sz, work_done = 0;
287 ctrl_msg_t msg;
289 while ( wc != wp )
290 {
291 sz = wp - wc;
292 if ( sz > sizeof(msg.msg) )
293 sz = sizeof(msg.msg);
294 if ( sz > (WBUF_SIZE - WBUF_MASK(wc)) )
295 sz = WBUF_SIZE - WBUF_MASK(wc);
297 msg.type = CMSG_CONSOLE;
298 msg.subtype = CMSG_CONSOLE_DATA;
299 msg.length = sz;
300 memcpy(msg.msg, &wbuf[WBUF_MASK(wc)], sz);
302 if ( ctrl_if_send_message_noblock(&msg, NULL, 0) == 0 ){
303 wc += sz;
304 }
305 else if (xc_tx_task_queued) {
306 /* avoid the extra enqueue check if we know we're already queued */
307 break;
308 } else if (ctrl_if_enqueue_space_callback(&xencons_tx_flush_task)) {
309 xc_tx_task_queued = TRUE;
310 break;
311 }
313 work_done = 1;
314 }
316 if ( work_done && xen_console_up )
317 ttwakeup(xccons);
318 }
319 static void
320 xencons_tx_flush_task_routine(void * data, int arg)
321 {
322 int flags;
323 CN_LOCK(cn_mtx, flags);
324 xc_tx_task_queued = FALSE;
325 __xencons_tx_flush();
326 CN_UNLOCK(cn_mtx, flags);
327 }
329 int
330 xcopen(struct cdev *dev, int flag, int mode, struct thread *td)
331 {
332 struct xc_softc *sc;
333 int unit = XCUNIT(dev);
334 struct tty *tp;
335 int s, error;
337 sc = (struct xc_softc *)device_get_softc(
338 devclass_get_device(xc_devclass, unit));
339 if (sc == NULL)
340 return (ENXIO);
342 tp = dev->si_tty;
343 s = spltty();
344 if (!ISTTYOPEN(tp)) {
345 tp->t_state |= TS_CARR_ON;
346 ttychars(tp);
347 tp->t_iflag = TTYDEF_IFLAG;
348 tp->t_oflag = TTYDEF_OFLAG;
349 tp->t_cflag = TTYDEF_CFLAG|CLOCAL;
350 tp->t_lflag = TTYDEF_LFLAG;
351 tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
352 xcparam(tp, &tp->t_termios);
353 ttsetwater(tp);
354 } else if (tp->t_state & TS_XCLUDE && suser(td)) {
355 splx(s);
356 return (EBUSY);
357 }
358 splx(s);
360 xen_console_up = 1;
362 error = (*linesw[tp->t_line]->l_open)(dev, tp);
364 return error;
365 }
367 int
368 xcclose(struct cdev *dev, int flag, int mode, struct thread *td)
369 {
370 struct tty *tp = dev->si_tty;
372 if (tp == NULL)
373 return (0);
374 xen_console_up = 0;
376 spltty();
377 (*linesw[tp->t_line]->l_close)(tp, flag);
378 tty_close(tp);
379 spl0();
380 return (0);
381 }
384 int
385 xcioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td)
386 {
387 struct tty *tp = dev->si_tty;
388 int error;
390 error = (*linesw[tp->t_line]->l_ioctl)(tp, cmd, data, flag, td);
391 if (error != ENOIOCTL)
392 return (error);
393 error = ttioctl(tp, cmd, data, flag);
394 if (error != ENOIOCTL)
395 return (error);
396 return (ENOTTY);
397 }
399 static inline int
400 __xencons_put_char(int ch)
401 {
402 char _ch = (char)ch;
403 if ( (wp - wc) == WBUF_SIZE )
404 return 0;
405 wbuf[WBUF_MASK(wp++)] = _ch;
406 return 1;
407 }
410 static void
411 xcstart(struct tty *tp)
412 {
413 int flags;
414 int s;
415 boolean_t cons_full = FALSE;
417 s = spltty();
418 CN_LOCK(cn_mtx, flags);
419 if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP)) {
420 ttwwakeup(tp);
421 CN_UNLOCK(cn_mtx, flags);
422 return;
423 }
425 tp->t_state |= TS_BUSY;
426 while (tp->t_outq.c_cc != 0 && !cons_full)
427 cons_full = xcons_putc(getc(&tp->t_outq));
429 /* if the console is close to full leave our state as busy */
430 if (!cons_full) {
431 tp->t_state &= ~TS_BUSY;
432 ttwwakeup(tp);
433 } else {
434 /* let the timeout kick us in a bit */
435 xc_start_needed = TRUE;
436 }
437 CN_UNLOCK(cn_mtx, flags);
438 splx(s);
439 }
441 static void
442 xcstop(struct tty *tp, int flag)
443 {
445 if (tp->t_state & TS_BUSY) {
446 if ((tp->t_state & TS_TTSTOP) == 0) {
447 tp->t_state |= TS_FLUSH;
448 }
449 }
450 }
452 static void
453 xc_timeout(void *v)
454 {
455 struct tty *tp;
456 int c;
458 tp = (struct tty *)v;
460 while ((c = xccncheckc(NULL)) != -1) {
461 if (tp->t_state & TS_ISOPEN) {
462 (*linesw[tp->t_line]->l_rint)(c, tp);
463 }
464 }
466 if (xc_start_needed) {
467 xc_start_needed = FALSE;
468 xcstart(tp);
469 }
471 callout_reset(&xc_callout, XC_POLLTIME, xc_timeout, tp);
472 }
474 /*
475 * Set line parameters.
476 */
477 int
478 xcparam(struct tty *tp, struct termios *t)
479 {
480 tp->t_ispeed = t->c_ispeed;
481 tp->t_ospeed = t->c_ospeed;
482 tp->t_cflag = t->c_cflag;
483 return (0);
484 }
487 static device_method_t xc_methods[] = {
488 DEVMETHOD(device_identify, xc_identify),
489 DEVMETHOD(device_probe, xc_probe),
490 DEVMETHOD(device_attach, xc_attach),
491 {0, 0}
492 };
494 static driver_t xc_driver = {
495 driver_name,
496 xc_methods,
497 sizeof(struct xc_softc),
498 };
500 /*** Forcibly flush console data before dying. ***/
501 void
502 xcons_force_flush(void)
503 {
504 ctrl_msg_t msg;
505 int sz;
507 /*
508 * We use dangerous control-interface functions that require a quiescent
509 * system and no interrupts. Try to ensure this with a global cli().
510 */
511 cli();
513 /* Spin until console data is flushed through to the domain controller. */
514 while ( (wc != wp) && !ctrl_if_transmitter_empty() )
515 {
516 /* Interrupts are disabled -- we must manually reap responses. */
517 ctrl_if_discard_responses();
519 if ( (sz = wp - wc) == 0 )
520 continue;
521 if ( sz > sizeof(msg.msg) )
522 sz = sizeof(msg.msg);
523 if ( sz > (WBUF_SIZE - WBUF_MASK(wc)) )
524 sz = WBUF_SIZE - WBUF_MASK(wc);
526 msg.type = CMSG_CONSOLE;
527 msg.subtype = CMSG_CONSOLE_DATA;
528 msg.length = sz;
529 memcpy(msg.msg, &wbuf[WBUF_MASK(wc)], sz);
531 if ( ctrl_if_send_message_noblock(&msg, NULL, 0) == 0 )
532 wc += sz;
533 }
534 }
536 DRIVER_MODULE(xc, xenbus, xc_driver, xc_devclass, 0, 0);