debuggers.hg

view xen/drivers/char/ns16550.c @ 22855:1d1eec7e1fb4

xl: Perform minimal validation of virtual disk file while parsing config file

This patch performs some very basic validation on the virtual disk
file passed through the config file. This validation ensures that we
don't go too far with the initialization like spawn qemu and more
while there could be some potentially fundamental issues.

[ Patch fixed up to work with PHYSTYPE_EMPTY 22808:6ec61438713a -iwj ]

Signed-off-by: Kamala Narasimhan <kamala.narasimhan@citrix.com>
Acked-by: Ian Jackson <ian.jackson@eu.citrix.com>
Signed-off-by: Ian Jackson <ian.jackson@eu.citrix.com>
Committed-by: Ian Jackson <ian.jackson@eu.citrix.com>
author Kamala Narasimhan <kamala.narasimhan@gmail.com>
date Tue Jan 25 18:09:49 2011 +0000 (2011-01-25)
parents 589d075ba295
children
line source
1 /******************************************************************************
2 * ns16550.c
3 *
4 * Driver for 16550-series UARTs. This driver is to be kept within Xen as
5 * it permits debugging of seriously-toasted machines (e.g., in situations
6 * where a device driver within a guest OS would be inaccessible).
7 *
8 * Copyright (c) 2003-2005, K A Fraser
9 */
11 #include <xen/config.h>
12 #include <xen/console.h>
13 #include <xen/init.h>
14 #include <xen/irq.h>
15 #include <xen/sched.h>
16 #include <xen/serial.h>
17 #include <xen/iocap.h>
18 #include <asm/io.h>
20 /*
21 * Configure serial port with a string:
22 * <baud>[/<clock_hz>][,DPS[,<io-base>[,<irq>[,<port-bdf>[,<bridge-bdf>]]]]].
23 * The tail of the string can be omitted if platform defaults are sufficient.
24 * If the baud rate is pre-configured, perhaps by a bootloader, then 'auto'
25 * can be specified in place of a numeric baud rate. Polled mode is specified
26 * by requesting irq 0.
27 */
28 static char __initdata opt_com1[30] = "";
29 static char __initdata opt_com2[30] = "";
30 string_param("com1", opt_com1);
31 string_param("com2", opt_com2);
33 static struct ns16550 {
34 int baud, clock_hz, data_bits, parity, stop_bits, irq;
35 unsigned long io_base; /* I/O port or memory-mapped I/O address. */
36 char *remapped_io_base; /* Remapped virtual address of mmap I/O. */
37 /* UART with IRQ line: interrupt-driven I/O. */
38 struct irqaction irqaction;
39 /* UART with no IRQ line: periodically-polled I/O. */
40 struct timer timer;
41 unsigned int timeout_ms;
42 bool_t probing, intr_works;
43 /* PCI card parameters. */
44 unsigned int pb_bdf[3]; /* pci bridge BDF */
45 unsigned int ps_bdf[3]; /* pci serial port BDF */
46 bool_t pb_bdf_enable; /* if =1, pb-bdf effective, port behind bridge */
47 bool_t ps_bdf_enable; /* if =1, ps_bdf effective, port on pci card */
48 } ns16550_com[2] = { { 0 } };
50 /* Register offsets */
51 #define RBR 0x00 /* receive buffer */
52 #define THR 0x00 /* transmit holding */
53 #define IER 0x01 /* interrupt enable */
54 #define IIR 0x02 /* interrupt identity */
55 #define FCR 0x02 /* FIFO control */
56 #define LCR 0x03 /* line control */
57 #define MCR 0x04 /* Modem control */
58 #define LSR 0x05 /* line status */
59 #define MSR 0x06 /* Modem status */
60 #define DLL 0x00 /* divisor latch (ls) (DLAB=1) */
61 #define DLM 0x01 /* divisor latch (ms) (DLAB=1) */
63 /* Interrupt Enable Register */
64 #define IER_ERDAI 0x01 /* rx data recv'd */
65 #define IER_ETHREI 0x02 /* tx reg. empty */
66 #define IER_ELSI 0x04 /* rx line status */
67 #define IER_EMSI 0x08 /* MODEM status */
69 /* Interrupt Identification Register */
70 #define IIR_NOINT 0x01 /* no interrupt pending */
71 #define IIR_IMASK 0x06 /* interrupt identity: */
72 #define IIR_LSI 0x06 /* - rx line status */
73 #define IIR_RDAI 0x04 /* - rx data recv'd */
74 #define IIR_THREI 0x02 /* - tx reg. empty */
75 #define IIR_MSI 0x00 /* - MODEM status */
77 /* FIFO Control Register */
78 #define FCR_ENABLE 0x01 /* enable FIFO */
79 #define FCR_CLRX 0x02 /* clear Rx FIFO */
80 #define FCR_CLTX 0x04 /* clear Tx FIFO */
81 #define FCR_DMA 0x10 /* enter DMA mode */
82 #define FCR_TRG1 0x00 /* Rx FIFO trig lev 1 */
83 #define FCR_TRG4 0x40 /* Rx FIFO trig lev 4 */
84 #define FCR_TRG8 0x80 /* Rx FIFO trig lev 8 */
85 #define FCR_TRG14 0xc0 /* Rx FIFO trig lev 14 */
87 /* Line Control Register */
88 #define LCR_DLAB 0x80 /* Divisor Latch Access */
90 /* Modem Control Register */
91 #define MCR_DTR 0x01 /* Data Terminal Ready */
92 #define MCR_RTS 0x02 /* Request to Send */
93 #define MCR_OUT2 0x08 /* OUT2: interrupt mask */
94 #define MCR_LOOP 0x10 /* Enable loopback test mode */
96 /* Line Status Register */
97 #define LSR_DR 0x01 /* Data ready */
98 #define LSR_OE 0x02 /* Overrun */
99 #define LSR_PE 0x04 /* Parity error */
100 #define LSR_FE 0x08 /* Framing error */
101 #define LSR_BI 0x10 /* Break */
102 #define LSR_THRE 0x20 /* Xmit hold reg empty */
103 #define LSR_TEMT 0x40 /* Xmitter empty */
104 #define LSR_ERR 0x80 /* Error */
106 /* These parity settings can be ORed directly into the LCR. */
107 #define PARITY_NONE (0<<3)
108 #define PARITY_ODD (1<<3)
109 #define PARITY_EVEN (3<<3)
110 #define PARITY_MARK (5<<3)
111 #define PARITY_SPACE (7<<3)
113 /* Frequency of external clock source. This definition assumes PC platform. */
114 #define UART_CLOCK_HZ 1843200
116 static char ns_read_reg(struct ns16550 *uart, int reg)
117 {
118 if ( uart->remapped_io_base == NULL )
119 return inb(uart->io_base + reg);
120 return readb(uart->remapped_io_base + reg);
121 }
123 static void ns_write_reg(struct ns16550 *uart, int reg, char c)
124 {
125 if ( uart->remapped_io_base == NULL )
126 return outb(c, uart->io_base + reg);
127 writeb(c, uart->remapped_io_base + reg);
128 }
130 static void ns16550_interrupt(
131 int irq, void *dev_id, struct cpu_user_regs *regs)
132 {
133 struct serial_port *port = dev_id;
134 struct ns16550 *uart = port->uart;
136 if (uart->intr_works == 0)
137 {
138 uart->probing = 0;
139 uart->intr_works = 1;
140 stop_timer(&uart->timer);
141 }
143 while ( !(ns_read_reg(uart, IIR) & IIR_NOINT) )
144 {
145 char lsr = ns_read_reg(uart, LSR);
146 if ( lsr & LSR_THRE )
147 serial_tx_interrupt(port, regs);
148 if ( lsr & LSR_DR )
149 serial_rx_interrupt(port, regs);
150 }
151 }
153 /* Safe: ns16550_poll() runs in softirq context so not reentrant on a given CPU. */
154 static DEFINE_PER_CPU(struct serial_port *, poll_port);
156 static void __ns16550_poll(struct cpu_user_regs *regs)
157 {
158 struct serial_port *port = this_cpu(poll_port);
159 struct ns16550 *uart = port->uart;
161 if ( uart->intr_works )
162 return; /* Interrupts work - no more polling */
164 if ( uart->probing ) {
165 uart->probing = 0;
166 if ( (ns_read_reg(uart, LSR) & 0xff) == 0xff )
167 return; /* All bits set - probably no UART present */
168 }
170 while ( ns_read_reg(uart, LSR) & LSR_DR )
171 serial_rx_interrupt(port, regs);
173 if ( ns_read_reg(uart, LSR) & LSR_THRE )
174 serial_tx_interrupt(port, regs);
176 set_timer(&uart->timer, NOW() + MILLISECS(uart->timeout_ms));
177 }
179 static void ns16550_poll(void *data)
180 {
181 this_cpu(poll_port) = data;
182 #ifdef run_in_exception_handler
183 run_in_exception_handler(__ns16550_poll);
184 #else
185 __ns16550_poll(guest_cpu_user_regs());
186 #endif
187 }
189 static int ns16550_tx_empty(struct serial_port *port)
190 {
191 struct ns16550 *uart = port->uart;
192 return !!(ns_read_reg(uart, LSR) & LSR_THRE);
193 }
195 static void ns16550_putc(struct serial_port *port, char c)
196 {
197 struct ns16550 *uart = port->uart;
198 ns_write_reg(uart, THR, c);
199 }
201 static int ns16550_getc(struct serial_port *port, char *pc)
202 {
203 struct ns16550 *uart = port->uart;
205 if ( !(ns_read_reg(uart, LSR) & LSR_DR) )
206 return 0;
208 *pc = ns_read_reg(uart, RBR);
209 return 1;
210 }
212 static void pci_serial_early_init(struct ns16550 *uart)
213 {
214 if ( !uart->ps_bdf_enable )
215 return;
217 if ( uart->pb_bdf_enable )
218 pci_conf_write16(uart->pb_bdf[0], uart->pb_bdf[1], uart->pb_bdf[2],
219 0x1c, (uart->io_base & 0xF000) | ((uart->io_base & 0xF000) >> 8));
221 pci_conf_write32(uart->ps_bdf[0], uart->ps_bdf[1], uart->ps_bdf[2],
222 0x10, uart->io_base | 0x1);
223 pci_conf_write16(uart->ps_bdf[0], uart->ps_bdf[1], uart->ps_bdf[2],
224 0x4, 0x1);
225 }
227 static void __devinit ns16550_init_preirq(struct serial_port *port)
228 {
229 struct ns16550 *uart = port->uart;
230 unsigned char lcr;
231 unsigned int divisor;
233 pci_serial_early_init(uart);
235 /* I/O ports are distinguished by their size (16 bits). */
236 if ( uart->io_base >= 0x10000 )
237 uart->remapped_io_base = (char *)ioremap(uart->io_base, 8);
239 lcr = (uart->data_bits - 5) | ((uart->stop_bits - 1) << 2) | uart->parity;
241 /* No interrupts. */
242 ns_write_reg(uart, IER, 0);
244 /* Line control and baud-rate generator. */
245 ns_write_reg(uart, LCR, lcr | LCR_DLAB);
246 if ( uart->baud != BAUD_AUTO )
247 {
248 /* Baud rate specified: program it into the divisor latch. */
249 divisor = uart->clock_hz / (uart->baud << 4);
250 ns_write_reg(uart, DLL, (char)divisor);
251 ns_write_reg(uart, DLM, (char)(divisor >> 8));
252 }
253 else
254 {
255 /* Baud rate already set: read it out from the divisor latch. */
256 divisor = ns_read_reg(uart, DLL);
257 divisor |= ns_read_reg(uart, DLM) << 8;
258 uart->baud = uart->clock_hz / (divisor << 4);
259 }
260 ns_write_reg(uart, LCR, lcr);
262 /* No flow ctrl: DTR and RTS are both wedged high to keep remote happy. */
263 ns_write_reg(uart, MCR, MCR_DTR | MCR_RTS);
265 /* Enable and clear the FIFOs. Set a large trigger threshold. */
266 ns_write_reg(uart, FCR, FCR_ENABLE | FCR_CLRX | FCR_CLTX | FCR_TRG14);
268 /* Check this really is a 16550+. Otherwise we have no FIFOs. */
269 if ( ((ns_read_reg(uart, IIR) & 0xc0) == 0xc0) &&
270 ((ns_read_reg(uart, FCR) & FCR_TRG14) == FCR_TRG14) )
271 port->tx_fifo_size = 16;
272 }
274 static void __devinit ns16550_init_postirq(struct serial_port *port)
275 {
276 struct ns16550 *uart = port->uart;
277 int rc, bits;
279 if ( uart->irq < 0 )
280 return;
282 serial_async_transmit(port);
284 if ( !uart->timer.function )
285 init_timer(&uart->timer, ns16550_poll, port, 0);
287 /* Calculate time to fill RX FIFO and/or empty TX FIFO for polling. */
288 bits = uart->data_bits + uart->stop_bits + !!uart->parity;
289 uart->timeout_ms = max_t(
290 unsigned int, 1, (bits * port->tx_fifo_size * 1000) / uart->baud);
292 if ( uart->irq == 0 )
293 set_timer(&uart->timer, NOW() + MILLISECS(uart->timeout_ms));
294 else
295 {
296 uart->irqaction.handler = ns16550_interrupt;
297 uart->irqaction.name = "ns16550";
298 uart->irqaction.dev_id = port;
299 if ( (rc = setup_irq(uart->irq, &uart->irqaction)) != 0 )
300 printk("ERROR: Failed to allocate ns16550 IRQ %d\n", uart->irq);
302 /* Master interrupt enable; also keep DTR/RTS asserted. */
303 ns_write_reg(uart, MCR, MCR_OUT2 | MCR_DTR | MCR_RTS);
305 /* Enable receive and transmit interrupts. */
306 ns_write_reg(uart, IER, IER_ERDAI | IER_ETHREI);
308 /* Do a timed write to make sure we are getting interrupts. */
309 uart->probing = 1;
310 uart->intr_works = 0;
311 ns_write_reg(uart, THR, 0xff);
312 set_timer(&uart->timer, NOW() + MILLISECS(uart->timeout_ms));
313 }
314 }
316 #ifdef CONFIG_X86
317 static void __init ns16550_endboot(struct serial_port *port)
318 {
319 struct ns16550 *uart = port->uart;
320 if ( ioports_deny_access(dom0, uart->io_base, uart->io_base + 7) != 0 )
321 BUG();
322 }
323 #else
324 #define ns16550_endboot NULL
325 #endif
327 static int ns16550_irq(struct serial_port *port)
328 {
329 struct ns16550 *uart = port->uart;
330 return ((uart->irq > 0) ? uart->irq : -1);
331 }
333 static struct uart_driver __read_mostly ns16550_driver = {
334 .init_preirq = ns16550_init_preirq,
335 .init_postirq = ns16550_init_postirq,
336 .endboot = ns16550_endboot,
337 .tx_empty = ns16550_tx_empty,
338 .putc = ns16550_putc,
339 .getc = ns16550_getc,
340 .irq = ns16550_irq
341 };
343 static int __init parse_parity_char(int c)
344 {
345 switch ( c )
346 {
347 case 'n':
348 return PARITY_NONE;
349 case 'o':
350 return PARITY_ODD;
351 case 'e':
352 return PARITY_EVEN;
353 case 'm':
354 return PARITY_MARK;
355 case 's':
356 return PARITY_SPACE;
357 }
358 return 0;
359 }
361 static void __init parse_pci_bdf(const char **conf, unsigned int bdf[3])
362 {
363 bdf[0] = simple_strtoul(*conf, conf, 16);
364 if ( **conf != ':' )
365 return;
366 (*conf)++;
367 bdf[1] = simple_strtoul(*conf, conf, 16);
368 if ( **conf != '.' )
369 return;
370 (*conf)++;
371 bdf[2] = simple_strtoul(*conf, conf, 16);
372 }
374 static int __init check_existence(struct ns16550 *uart)
375 {
376 unsigned char status, scratch, scratch2, scratch3;
378 /*
379 * We can't poke MMIO UARTs until they get I/O remapped later. Assume that
380 * if we're getting MMIO UARTs, the arch code knows what it's doing.
381 */
382 if ( uart->io_base >= 0x10000 )
383 return 1;
385 pci_serial_early_init(uart);
387 /*
388 * Do a simple existence test first; if we fail this,
389 * there's no point trying anything else.
390 */
391 scratch = ns_read_reg(uart, IER);
392 ns_write_reg(uart, IER, 0);
394 /*
395 * Mask out IER[7:4] bits for test as some UARTs (e.g. TL
396 * 16C754B) allow only to modify them if an EFR bit is set.
397 */
398 scratch2 = ns_read_reg(uart, IER) & 0x0f;
399 ns_write_reg(uart, IER, 0x0F);
400 scratch3 = ns_read_reg(uart, IER) & 0x0f;
401 ns_write_reg(uart, IER, scratch);
402 if ( (scratch2 != 0) || (scratch3 != 0x0F) )
403 return 0;
405 /*
406 * Check to see if a UART is really there.
407 * Use loopback test mode.
408 */
409 ns_write_reg(uart, MCR, MCR_LOOP | 0x0A);
410 status = ns_read_reg(uart, MSR) & 0xF0;
411 return (status == 0x90);
412 }
414 #define PARSE_ERR(_f, _a...) \
415 do { \
416 printk( "ERROR: " _f "\n" , ## _a ); \
417 return; \
418 } while ( 0 )
420 static void __init ns16550_parse_port_config(
421 struct ns16550 *uart, const char *conf)
422 {
423 int baud;
425 /* No user-specified configuration? */
426 if ( (conf == NULL) || (*conf == '\0') )
427 {
428 /* Some platforms may automatically probe the UART configuartion. */
429 if ( uart->baud != 0 )
430 goto config_parsed;
431 return;
432 }
434 if ( strncmp(conf, "auto", 4) == 0 )
435 {
436 uart->baud = BAUD_AUTO;
437 conf += 4;
438 }
439 else if ( (baud = simple_strtoul(conf, &conf, 10)) != 0 )
440 uart->baud = baud;
442 if ( *conf == '/')
443 {
444 conf++;
445 uart->clock_hz = simple_strtoul(conf, &conf, 0) << 4;
446 }
448 if ( *conf != ',' )
449 goto config_parsed;
450 conf++;
452 uart->data_bits = simple_strtoul(conf, &conf, 10);
454 uart->parity = parse_parity_char(*conf);
455 conf++;
457 uart->stop_bits = simple_strtoul(conf, &conf, 10);
459 if ( *conf == ',' )
460 {
461 conf++;
462 uart->io_base = simple_strtoul(conf, &conf, 0);
464 if ( *conf == ',' )
465 {
466 conf++;
467 uart->irq = simple_strtoul(conf, &conf, 10);
468 if ( *conf == ',' )
469 {
470 conf++;
471 uart->ps_bdf_enable = 1;
472 parse_pci_bdf(&conf, &uart->ps_bdf[0]);
473 if ( *conf == ',' )
474 {
475 conf++;
476 uart->pb_bdf_enable = 1;
477 parse_pci_bdf(&conf, &uart->pb_bdf[0]);
478 }
479 }
480 }
481 }
483 config_parsed:
484 /* Sanity checks. */
485 if ( (uart->baud != BAUD_AUTO) &&
486 ((uart->baud < 1200) || (uart->baud > 115200)) )
487 PARSE_ERR("Baud rate %d outside supported range.", uart->baud);
488 if ( (uart->data_bits < 5) || (uart->data_bits > 8) )
489 PARSE_ERR("%d data bits are unsupported.", uart->data_bits);
490 if ( (uart->stop_bits < 1) || (uart->stop_bits > 2) )
491 PARSE_ERR("%d stop bits are unsupported.", uart->stop_bits);
492 if ( uart->io_base == 0 )
493 PARSE_ERR("I/O base address must be specified.");
494 if ( !check_existence(uart) )
495 PARSE_ERR("16550-compatible serial UART not present");
497 /* Register with generic serial driver. */
498 serial_register_uart(uart - ns16550_com, &ns16550_driver, uart);
499 }
501 void __init ns16550_init(int index, struct ns16550_defaults *defaults)
502 {
503 struct ns16550 *uart;
505 if ( (index < 0) || (index > 1) )
506 return;
508 uart = &ns16550_com[index];
510 uart->baud = (defaults->baud ? :
511 console_has((index == 0) ? "com1" : "com2")
512 ? BAUD_AUTO : 0);
513 uart->clock_hz = UART_CLOCK_HZ;
514 uart->data_bits = defaults->data_bits;
515 uart->parity = parse_parity_char(defaults->parity);
516 uart->stop_bits = defaults->stop_bits;
517 uart->irq = defaults->irq;
518 uart->io_base = defaults->io_base;
520 ns16550_parse_port_config(uart, (index == 0) ? opt_com1 : opt_com2);
521 }
523 /*
524 * Local variables:
525 * mode: C
526 * c-set-style: "BSD"
527 * c-basic-offset: 4
528 * tab-width: 4
529 * indent-tabs-mode: nil
530 * End:
531 */