source: trunk/packages/xen-3.1/xen-3.1/tools/ioemu/hw/serial.c @ 34

Last change on this file since 34 was 34, checked in by hartmans, 18 years ago

Add xen and xen-common

File size: 16.1 KB
Line 
1/*
2 * QEMU 16450 UART emulation
3 *
4 * Copyright (c) 2003-2004 Fabrice Bellard
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 */
24#include "vl.h"
25#include <sys/time.h>
26#include <time.h>
27#include <assert.h>
28
29//#define DEBUG_SERIAL
30
31#define UART_LCR_DLAB   0x80    /* Divisor latch access bit */
32
33#define UART_IER_MSI    0x08    /* Enable Modem status interrupt */
34#define UART_IER_RLSI   0x04    /* Enable receiver line status interrupt */
35#define UART_IER_THRI   0x02    /* Enable Transmitter holding register int. */
36#define UART_IER_RDI    0x01    /* Enable receiver data interrupt */
37
38#define UART_IIR_NO_INT 0x01    /* No interrupts pending */
39#define UART_IIR_ID     0x06    /* Mask for the interrupt ID */
40
41#define UART_IIR_MSI    0x00    /* Modem status interrupt */
42#define UART_IIR_THRI   0x02    /* Transmitter holding register empty */
43#define UART_IIR_RDI    0x04    /* Receiver data interrupt */
44#define UART_IIR_RLSI   0x06    /* Receiver line status interrupt */
45
46/*
47 * These are the definitions for the Modem Control Register
48 */
49#define UART_MCR_LOOP   0x10    /* Enable loopback test mode */
50#define UART_MCR_OUT2   0x08    /* Out2 complement */
51#define UART_MCR_OUT1   0x04    /* Out1 complement */
52#define UART_MCR_RTS    0x02    /* RTS complement */
53#define UART_MCR_DTR    0x01    /* DTR complement */
54
55/*
56 * These are the definitions for the Modem Status Register
57 */
58#define UART_MSR_DCD    0x80    /* Data Carrier Detect */
59#define UART_MSR_RI     0x40    /* Ring Indicator */
60#define UART_MSR_DSR    0x20    /* Data Set Ready */
61#define UART_MSR_CTS    0x10    /* Clear to Send */
62#define UART_MSR_DDCD   0x08    /* Delta DCD */
63#define UART_MSR_TERI   0x04    /* Trailing edge ring indicator */
64#define UART_MSR_DDSR   0x02    /* Delta DSR */
65#define UART_MSR_DCTS   0x01    /* Delta CTS */
66#define UART_MSR_ANY_DELTA 0x0F /* Any of the delta bits! */
67
68#define UART_LSR_TEMT   0x40    /* Transmitter empty */
69#define UART_LSR_THRE   0x20    /* Transmit-hold-register empty */
70#define UART_LSR_BI     0x10    /* Break interrupt indicator */
71#define UART_LSR_FE     0x08    /* Frame error indicator */
72#define UART_LSR_PE     0x04    /* Parity error indicator */
73#define UART_LSR_OE     0x02    /* Overrun error indicator */
74#define UART_LSR_DR     0x01    /* Receiver data ready */
75
76/* Maximum retries for a single byte transmit. */
77#define WRITE_MAX_SINGLE_RETRIES 3
78/* Maximum retries for a sequence of back-to-back unsuccessful transmits. */
79#define WRITE_MAX_TOTAL_RETRIES 10
80
81struct SerialState {
82    uint8_t divider;
83    uint8_t rbr; /* receive register */
84    uint8_t ier;
85    uint8_t iir; /* read only */
86    uint8_t lcr;
87    uint8_t mcr;
88    uint8_t lsr; /* read only */
89    uint8_t msr; /* read only */
90    uint8_t scr;
91    /* NOTE: this hidden state is necessary for tx irq generation as
92       it can be reset while reading iir */
93    int thr_ipending;
94    SetIRQFunc *set_irq;
95    void *irq_opaque;
96    int irq;
97    CharDriverState *chr;
98    int last_break_enable;
99    target_ulong base;
100    int it_shift;
101
102    /*
103     * If a character transmitted via UART cannot be written to its
104     * destination immediately we remember it here and retry a few times via
105     * a polling timer.
106     *  - write_single_retries: Number of write retries for current byte.
107     *  - write_total_retries:  Number of write retries for back-to-back
108     *                          unsuccessful transmits.
109     */
110    int write_single_retries;
111    int write_total_retries;
112    char write_chr;
113    QEMUTimer *write_retry_timer;
114};
115
116static void serial_update_irq(SerialState *s)
117{
118    if ((s->lsr & UART_LSR_DR) && (s->ier & UART_IER_RDI)) {
119        s->iir = UART_IIR_RDI;
120    } else if (s->thr_ipending && (s->ier & UART_IER_THRI)) {
121        s->iir = UART_IIR_THRI;
122    } else {
123        s->iir = UART_IIR_NO_INT;
124    }
125    if (s->iir != UART_IIR_NO_INT) {
126        s->set_irq(s->irq_opaque, s->irq, 1);
127    } else {
128        s->set_irq(s->irq_opaque, s->irq, 0);
129    }
130}
131
132static void serial_update_parameters(SerialState *s)
133{
134    int speed, parity, data_bits, stop_bits;
135    QEMUSerialSetParams ssp;
136
137    if (s->lcr & 0x08) {
138        if (s->lcr & 0x10)
139            parity = 'E';
140        else
141            parity = 'O';
142    } else {
143            parity = 'N';
144    }
145    if (s->lcr & 0x04) 
146        stop_bits = 2;
147    else
148        stop_bits = 1;
149    data_bits = (s->lcr & 0x03) + 5;
150    if (s->divider == 0)
151        return;
152    speed = 115200 / s->divider;
153    ssp.speed = speed;
154    ssp.parity = parity;
155    ssp.data_bits = data_bits;
156    ssp.stop_bits = stop_bits;
157    qemu_chr_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
158#if 0
159    printf("speed=%d parity=%c data=%d stop=%d\n",
160           speed, parity, data_bits, stop_bits);
161#endif
162}
163
164/* Rate limit serial requests so that e.g. grub on a serial console
165   doesn't kill dom0.  Simple token bucket.  If we get some actual
166   data from the user, instantly refil the bucket. */
167
168/* How long it takes to generate a token, in microseconds. */
169#define TOKEN_PERIOD 1000
170/* Maximum and initial size of token bucket */
171#define TOKENS_MAX 100000
172
173static int tokens_avail;
174
175static void serial_get_token(void)
176{
177    static struct timeval last_refil_time;
178    static int started;
179
180    assert(tokens_avail >= 0);
181    if (!tokens_avail) {
182        struct timeval delta, now;
183        int generated;
184
185        if (!started) {
186            gettimeofday(&last_refil_time, NULL);
187            tokens_avail = TOKENS_MAX;
188            started = 1;
189            return;
190        }
191    retry:
192        gettimeofday(&now, NULL);
193        delta.tv_sec = now.tv_sec - last_refil_time.tv_sec;
194        delta.tv_usec = now.tv_usec - last_refil_time.tv_usec;
195        if (delta.tv_usec < 0) {
196            delta.tv_usec += 1000000;
197            delta.tv_sec--;
198        }
199        assert(delta.tv_usec >= 0 && delta.tv_sec >= 0);
200        if (delta.tv_usec < TOKEN_PERIOD) {
201            struct timespec ts;
202            /* Wait until at least one token is available. */
203            ts.tv_sec = TOKEN_PERIOD / 1000000;
204            ts.tv_nsec = (TOKEN_PERIOD % 1000000) * 1000;
205            while (nanosleep(&ts, &ts) < 0 && errno == EINTR)
206                ;
207            goto retry;
208        }
209        generated = (delta.tv_sec * 1000000) / TOKEN_PERIOD;
210        generated +=
211            ((delta.tv_sec * 1000000) % TOKEN_PERIOD + delta.tv_usec) / TOKEN_PERIOD;
212        assert(generated > 0);
213
214        last_refil_time.tv_usec += (generated * TOKEN_PERIOD) % 1000000;
215        last_refil_time.tv_sec  += last_refil_time.tv_usec / 1000000;
216        last_refil_time.tv_usec %= 1000000;
217        last_refil_time.tv_sec  += (generated * TOKEN_PERIOD) / 1000000;
218        if (generated > TOKENS_MAX)
219            generated = TOKENS_MAX;
220        tokens_avail = generated;
221    }
222    tokens_avail--;
223}
224
225static void serial_chr_write(void *opaque)
226{
227    SerialState *s = opaque;
228
229    /* Cancel any outstanding retry if this is a new byte. */
230    qemu_del_timer(s->write_retry_timer);
231
232    /* Retry every 100ms for 300ms total. */
233    if (qemu_chr_write(s->chr, &s->write_chr, 1) == -1) {
234        s->write_total_retries++; 
235        if (s->write_single_retries++ >= WRITE_MAX_SINGLE_RETRIES)
236            fprintf(stderr, "serial: write error\n");
237        else if (s->write_total_retries <= WRITE_MAX_TOTAL_RETRIES) {
238            qemu_mod_timer(s->write_retry_timer,
239                           qemu_get_clock(vm_clock) + ticks_per_sec / 10);
240            return;
241        }
242    } else {
243        s->write_total_retries = 0;  /* if successful then reset counter */
244    }
245
246    /* Success: Notify guest that THR is empty. */
247    s->thr_ipending = 1;
248    s->lsr |= UART_LSR_THRE;
249    s->lsr |= UART_LSR_TEMT;
250    serial_update_irq(s);
251}
252
253static void serial_ioport_write(void *opaque, uint32_t addr, uint32_t val)
254{
255    SerialState *s = opaque;
256   
257    addr &= 7;
258#ifdef DEBUG_SERIAL
259    printf("serial: write addr=0x%02x val=0x%02x\n", addr, val);
260#endif
261    switch(addr) {
262    default:
263    case 0:
264        if (s->lcr & UART_LCR_DLAB) {
265            s->divider = (s->divider & 0xff00) | val;
266            serial_update_parameters(s);
267        } else {
268            s->thr_ipending = 0;
269            s->lsr &= ~UART_LSR_THRE;
270            serial_update_irq(s);
271            s->write_chr = val;
272            s->write_single_retries = 0;
273            serial_chr_write(s);
274        }
275        break;
276    case 1:
277        if (s->lcr & UART_LCR_DLAB) {
278            s->divider = (s->divider & 0x00ff) | (val << 8);
279            serial_update_parameters(s);
280        } else {
281            s->ier = val & 0x0f;
282            if (s->lsr & UART_LSR_THRE) {
283                s->thr_ipending = 1;
284            }
285            serial_update_irq(s);
286        }
287        break;
288    case 2:
289        break;
290    case 3:
291        {
292            int break_enable;
293            s->lcr = val;
294            serial_update_parameters(s);
295            break_enable = (val >> 6) & 1;
296            if (break_enable != s->last_break_enable) {
297                s->last_break_enable = break_enable;
298                qemu_chr_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_BREAK, 
299                               &break_enable);
300            }
301        }
302        break;
303    case 4:
304        s->mcr = val & 0x1f;
305        break;
306    case 5:
307        break;
308    case 6:
309        break;
310    case 7:
311        s->scr = val;
312        break;
313    }
314}
315
316static uint32_t serial_ioport_read(void *opaque, uint32_t addr)
317{
318    SerialState *s = opaque;
319    uint32_t ret;
320
321    addr &= 7;
322    switch(addr) {
323    default:
324    case 0:
325        if (s->lcr & UART_LCR_DLAB) {
326            ret = s->divider & 0xff; 
327        } else {
328            ret = s->rbr;
329            s->lsr &= ~(UART_LSR_DR | UART_LSR_BI);
330            serial_update_irq(s);
331        }
332        break;
333    case 1:
334        if (s->lcr & UART_LCR_DLAB) {
335            ret = (s->divider >> 8) & 0xff;
336        } else {
337            ret = s->ier;
338        }
339        break;
340    case 2:
341        ret = s->iir;
342        /* reset THR pending bit */
343        if ((ret & 0x7) == UART_IIR_THRI)
344            s->thr_ipending = 0;
345        serial_update_irq(s);
346        break;
347    case 3:
348        ret = s->lcr;
349        break;
350    case 4:
351        ret = s->mcr;
352        break;
353    case 5:
354        serial_get_token();
355        ret = s->lsr;
356        break;
357    case 6:
358        serial_get_token();
359        if (s->mcr & UART_MCR_LOOP) {
360            /* in loopback, the modem output pins are connected to the
361               inputs */
362            ret = (s->mcr & 0x0c) << 4;
363            ret |= (s->mcr & 0x02) << 3;
364            ret |= (s->mcr & 0x01) << 5;
365        } else {
366            ret = s->msr;
367        }
368        break;
369    case 7:
370        ret = s->scr;
371        break;
372    }
373#ifdef DEBUG_SERIAL
374    printf("serial: read addr=0x%02x val=0x%02x\n", addr, ret);
375#endif
376    return ret;
377}
378
379static int serial_can_receive(SerialState *s)
380{
381    return !(s->lsr & UART_LSR_DR);
382}
383
384static void serial_receive_byte(SerialState *s, int ch)
385{
386    s->rbr = ch;
387    s->lsr |= UART_LSR_DR;
388    serial_update_irq(s);
389}
390
391static void serial_receive_break(SerialState *s)
392{
393    s->rbr = 0;
394    s->lsr |= UART_LSR_BI | UART_LSR_DR;
395    serial_update_irq(s);
396}
397
398static int serial_can_receive1(void *opaque)
399{
400    SerialState *s = opaque;
401    return serial_can_receive(s);
402}
403
404static void serial_receive1(void *opaque, const uint8_t *buf, int size)
405{
406    SerialState *s = opaque;
407    tokens_avail = TOKENS_MAX;
408    serial_receive_byte(s, buf[0]);
409}
410
411static void serial_event(void *opaque, int event)
412{
413    SerialState *s = opaque;
414    tokens_avail = TOKENS_MAX;
415    if (event == CHR_EVENT_BREAK)
416        serial_receive_break(s);
417}
418
419static void serial_save(QEMUFile *f, void *opaque)
420{
421    SerialState *s = opaque;
422
423    qemu_put_8s(f,&s->divider);
424    qemu_put_8s(f,&s->rbr);
425    qemu_put_8s(f,&s->ier);
426    qemu_put_8s(f,&s->iir);
427    qemu_put_8s(f,&s->lcr);
428    qemu_put_8s(f,&s->mcr);
429    qemu_put_8s(f,&s->lsr);
430    qemu_put_8s(f,&s->msr);
431    qemu_put_8s(f,&s->scr);
432}
433
434static int serial_load(QEMUFile *f, void *opaque, int version_id)
435{
436    SerialState *s = opaque;
437
438    if(version_id != 1)
439        return -EINVAL;
440
441    qemu_get_8s(f,&s->divider);
442    qemu_get_8s(f,&s->rbr);
443    qemu_get_8s(f,&s->ier);
444    qemu_get_8s(f,&s->iir);
445    qemu_get_8s(f,&s->lcr);
446    qemu_get_8s(f,&s->mcr);
447    qemu_get_8s(f,&s->lsr);
448    qemu_get_8s(f,&s->msr);
449    qemu_get_8s(f,&s->scr);
450
451    return 0;
452}
453
454/* If fd is zero, it means that the serial device uses the console */
455SerialState *serial_init(SetIRQFunc *set_irq, void *opaque,
456                         int base, int irq, CharDriverState *chr)
457{
458    SerialState *s;
459
460    s = qemu_mallocz(sizeof(SerialState));
461    if (!s)
462        return NULL;
463    s->set_irq = set_irq;
464    s->irq_opaque = opaque;
465    s->irq = irq;
466    s->lsr = UART_LSR_TEMT | UART_LSR_THRE;
467    s->iir = UART_IIR_NO_INT;
468    s->msr = UART_MSR_DCD | UART_MSR_DSR | UART_MSR_CTS;
469    s->write_retry_timer = qemu_new_timer(vm_clock, serial_chr_write, s);
470
471    register_savevm("serial", base, 1, serial_save, serial_load, s);
472
473    register_ioport_write(base, 8, 1, serial_ioport_write, s);
474    register_ioport_read(base, 8, 1, serial_ioport_read, s);
475    s->chr = chr;
476    qemu_chr_add_read_handler(chr, serial_can_receive1, serial_receive1, s);
477    qemu_chr_add_event_handler(chr, serial_event);
478    return s;
479}
480
481/* Memory mapped interface */
482static uint32_t serial_mm_readb (void *opaque, target_phys_addr_t addr)
483{
484    SerialState *s = opaque;
485
486    return serial_ioport_read(s, (addr - s->base) >> s->it_shift) & 0xFF;
487}
488
489static void serial_mm_writeb (void *opaque,
490                              target_phys_addr_t addr, uint32_t value)
491{
492    SerialState *s = opaque;
493
494    serial_ioport_write(s, (addr - s->base) >> s->it_shift, value & 0xFF);
495}
496
497static uint32_t serial_mm_readw (void *opaque, target_phys_addr_t addr)
498{
499    SerialState *s = opaque;
500
501    return serial_ioport_read(s, (addr - s->base) >> s->it_shift) & 0xFFFF;
502}
503
504static void serial_mm_writew (void *opaque,
505                              target_phys_addr_t addr, uint32_t value)
506{
507    SerialState *s = opaque;
508
509    serial_ioport_write(s, (addr - s->base) >> s->it_shift, value & 0xFFFF);
510}
511
512static uint32_t serial_mm_readl (void *opaque, target_phys_addr_t addr)
513{
514    SerialState *s = opaque;
515
516    return serial_ioport_read(s, (addr - s->base) >> s->it_shift);
517}
518
519static void serial_mm_writel (void *opaque,
520                              target_phys_addr_t addr, uint32_t value)
521{
522    SerialState *s = opaque;
523
524    serial_ioport_write(s, (addr - s->base) >> s->it_shift, value);
525}
526
527static CPUReadMemoryFunc *serial_mm_read[] = {
528    &serial_mm_readb,
529    &serial_mm_readw,
530    &serial_mm_readl,
531};
532
533static CPUWriteMemoryFunc *serial_mm_write[] = {
534    &serial_mm_writeb,
535    &serial_mm_writew,
536    &serial_mm_writel,
537};
538
539SerialState *serial_mm_init (SetIRQFunc *set_irq, void *opaque,
540                             target_ulong base, int it_shift,
541                             int irq, CharDriverState *chr)
542{
543    SerialState *s;
544    int s_io_memory;
545
546    s = qemu_mallocz(sizeof(SerialState));
547    if (!s)
548        return NULL;
549    s->set_irq = set_irq;
550    s->irq_opaque = opaque;
551    s->irq = irq;
552    s->lsr = UART_LSR_TEMT | UART_LSR_THRE;
553    s->iir = UART_IIR_NO_INT;
554    s->msr = UART_MSR_DCD | UART_MSR_DSR | UART_MSR_CTS;
555    s->base = base;
556    s->it_shift = it_shift;
557    s->write_retry_timer = qemu_new_timer(vm_clock, serial_chr_write, s);
558
559    register_savevm("serial", base, 1, serial_save, serial_load, s);
560
561    s_io_memory = cpu_register_io_memory(0, serial_mm_read,
562                                         serial_mm_write, s);
563    cpu_register_physical_memory(base, 8 << it_shift, s_io_memory);
564    s->chr = chr;
565    qemu_chr_add_read_handler(chr, serial_can_receive1, serial_receive1, s);
566    qemu_chr_add_event_handler(chr, serial_event);
567    return s;
568}
Note: See TracBrowser for help on using the repository browser.