2 * This file is part of the Palacios Virtual Machine Monitor developed
3 * by the V3VEE Project with funding from the United States National
4 * Science Foundation and the Department of Energy.
6 * The V3VEE Project is a joint project between Northwestern University
7 * and the University of New Mexico. You can find out more at
10 * Copyright (c) 2008, Jack Lange <jarusl@cs.northwestern.edu>
11 * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org>
12 * All rights reserved.
14 * Author: Jack Lange <jarusl@cs.northwestern.edu>
16 * This is free software. You are permitted to use,
17 * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
20 #include <devices/serial.h>
21 #include <palacios/vmm.h>
24 #define COM1_DATA_PORT 0x3f8
25 #define COM1_IRQ_ENABLE_PORT 0x3f9
26 #define COM1_DIV_LATCH_LSB_PORT 0x3f8
27 #define COM1_DIV_LATCH_MSB_PORT 0x3f9
28 #define COM1_IIR_PORT 0x3fa
29 #define COM1_FIFO_CTRL_PORT 0x3fa
30 #define COM1_LINE_CTRL_PORT 0x3fb
31 #define COM1_MODEM_CTRL_PORT 0x3fc
32 #define COM1_LINE_STATUS_PORT 0x3fd
33 #define COM1_MODEM_STATUS_PORT 0x3fe
34 #define COM1_SCRATCH_PORT 0x3ff
36 #define COM2_DATA_PORT 0x2f8
37 #define COM2_IRQ_ENABLE_PORT 0x2f9
38 #define COM2_DIV_LATCH_LSB_PORT 0x2f8
39 #define COM2_DIV_LATCH_MSB_PORT 0x2f9
40 #define COM2_IIR_PORT 0x2fa
41 #define COM2_FIFO_CTRL_PORT 0x2fa
42 #define COM2_LINE_CTRL_PORT 0x2fb
43 #define COM2_MODEM_CTRL_PORT 0x2fc
44 #define COM2_LINE_STATUS_PORT 0x2fd
45 #define COM2_MODEM_STATUS_PORT 0x2fe
46 #define COM2_SCRATCH_PORT 0x2ff
48 #define COM3_DATA_PORT 0x3e8
49 #define COM3_IRQ_ENABLE_PORT 0x3e9
50 #define COM3_DIV_LATCH_LSB_PORT 0x3e8
51 #define COM3_DIV_LATCH_MSB_PORT 0x3e9
52 #define COM3_IIR_PORT 0x3ea
53 #define COM3_FIFO_CTRL_PORT 0x3ea
54 #define COM3_LINE_CTRL_PORT 0x3eb
55 #define COM3_MODEM_CTRL_PORT 0x3ec
56 #define COM3_LINE_STATUS_PORT 0x3ed
57 #define COM3_MODEM_STATUS_PORT 0x3ee
58 #define COM3_SCRATCH_PORT 0x3ef
60 #define COM4_DATA_PORT 0x2e8
61 #define COM4_IRQ_ENABLE_PORT 0x2e9
62 #define COM4_DIV_LATCH_LSB_PORT 0x2e8
63 #define COM4_DIV_LATCH_MSB_PORT 0x2e9
64 #define COM4_IIR_PORT 0x2ea
65 #define COM4_FIFO_CTRL_PORT 0x2ea
66 #define COM4_LINE_CTRL_PORT 0x2eb
67 #define COM4_MODEM_CTRL_PORT 0x2ec
68 #define COM4_LINE_STATUS_PORT 0x2ed
69 #define COM4_MODEM_STATUS_PORT 0x2ee
70 #define COM4_SCRATCH_PORT 0x2ef
74 struct irq_enable_reg {
75 uint_t erbfi : 1; // Enable Receiver Buffer full interrupt
76 uint_t etbei : 1; // Enable Transmit buffer empty interrupt
77 uint_t elsi : 1; // Enable Line Status Interrupt
78 uint_t edssi : 1; // Enable Delta Status signals interrupt
79 uint_t rsvd : 4; // MBZ
84 // Interrupt IDs (in priority order, highest is first)
85 #define STATUS_IRQ_LSR_OE_SET 0x3
86 #define STATUS_IRQ_LSR_PE_SET 0x3
87 #define STATUS_IRQ_LSR_FE_SET 0x3
88 #define STATUS_IRQ_LSR_BI_SET 0x3
90 #define RX_IRQ_TRIGGER_LEVEL 0x2
92 #define TX_IRQ_THRE 0x1
93 #define MODEL_IRQ_DELTA_SET 0x0
96 uint_t pending : 1; // Interrupt pending (0=interrupt pending)
97 uint_t iid : 3; // Interrupt Identification
98 uint_t rsvd : 2; // MBZ
99 uint_t fifo_en : 2; // FIFO enable
102 struct fifo_ctrl_reg {
103 uint_t enable : 1; // enable fifo
104 uint_t rfres : 1; // RX FIFO reset
105 uint_t xfres : 1; // TX FIFO reset
106 uint_t dma_sel : 1; // DMA mode select
107 uint_t rsvd : 2; // MBZ
108 uint_t rx_trigger: 2; // RX FIFO trigger level select
111 struct line_ctrl_reg {
112 uint_t word_len : 2; // word length select
113 uint_t stop_bits : 1; // Stop Bit select
114 uint_t parity_enable : 1; // Enable parity
115 uint_t even_sel : 1; // Even Parity Select
116 uint_t stick_parity : 1; // Stick Parity Select
117 uint_t sbr : 1; // Set Break
118 uint_t dlab : 1; // Divisor latch access bit
122 struct modem_ctrl_reg {
127 uint_t loop : 1; // loopback mode
128 uint_t rsvd : 3; // MBZ
132 struct line_status_reg {
133 uint_t rbf : 1; // Receiver Buffer Full
134 uint_t oe : 1; // Overrun error
135 uint_t pe : 1; // Parity Error
136 uint_t fe : 1; // Framing Error
137 uint_t brk : 1; // broken line detected
138 uint_t thre : 1; // Transmitter holding register empty
139 uint_t temt : 1; // Transmitter Empty
140 uint_t fifo_err : 1; // at least one error is pending in the RX FIFO chain
144 struct modem_status_reg {
145 uint_t dcts : 1; // Delta Clear To Send
146 uint_t ddsr : 1; // Delta Data Set Ready
147 uint_t teri : 1; // Trailing Edge Ring Indicator
148 uint_t ddcd : 1; // Delta Data Carrier Detect
149 uint_t cts : 1; // Clear to Send
150 uint_t dsr : 1; // Data Set Ready
151 uint_t ri : 1; // Ring Indicator
152 uint_t dcd : 1; // Data Carrier Detect
156 #define SERIAL_BUF_LEN 256
158 struct serial_buffer {
159 uint_t head; // most recent data
160 uint_t tail; // oldest char
161 char buffer[SERIAL_BUF_LEN];
164 static int queue_data(struct serial_buffer * buf, char data) {
165 uint_t next_loc = (buf->head + 1) % SERIAL_BUF_LEN;
167 if (next_loc == buf->tail) {
171 buf->buffer[next_loc] = data;
172 buf->head = next_loc;
177 static int dequeue_data(struct serial_buffer * buf, char * data) {
178 uint_t next_tail = (buf->tail + 1) % SERIAL_BUF_LEN;
180 if (buf->head == buf->tail) {
184 *data = buf->buffer[buf->tail];
185 buf->tail = next_tail;
200 struct serial_buffer tx_buffer;
201 struct serial_buffer rx_buffer;
205 struct serial_state {
206 struct serial_port com1;
207 struct serial_port com2;
208 struct serial_port com3;
209 struct serial_port com4;
213 static int write_data_port(ushort_t port, void * src, uint_t length, struct vm_device * dev) {
214 struct serial_state * state = (struct serial_state *)dev->private_data;
215 char * val = (char *)src;
216 PrintDebug("Write to Data Port 0x%x (val=%x)\n", port, *(char*)src);
219 PrintDebug("Invalid length(%d) in write to 0x%x\n", length, port);
225 queue_data(&(state->com1.tx_buffer), *val);
228 queue_data(&(state->com2.tx_buffer), *val);
231 queue_data(&(state->com3.tx_buffer), *val);
234 queue_data(&(state->com4.tx_buffer), *val);
246 static int read_data_port(ushort_t port, void * dst, uint_t length, struct vm_device * dev) {
247 struct serial_state * state = (struct serial_state *)dev->private_data;
248 char * val = (char *)dst;
249 PrintDebug("Read from Data Port 0x%x\n", port);
252 PrintDebug("Invalid length(%d) in write to 0x%x\n", length, port);
258 dequeue_data(&(state->com1.tx_buffer), val);
261 dequeue_data(&(state->com2.tx_buffer), val);
264 dequeue_data(&(state->com3.tx_buffer), val);
267 dequeue_data(&(state->com4.tx_buffer), val);
279 static int handle_ier_write(struct serial_port * com, struct irq_enable_reg * ier) {
286 static int write_ctrl_port(ushort_t port, void * src, uint_t length, struct vm_device * dev) {
287 struct serial_state * state = (struct serial_state *)dev->private_data;
288 char * val = (char *)src;
289 PrintDebug("Write to Control Port (val=%x)\n", *(char *)src);
292 PrintDebug("Invalid Write length to control port %d\n", port);
297 case COM1_IRQ_ENABLE_PORT:
298 if (handle_ier_write(&(state->com1), (struct irq_enable_reg *)val) == -1) {
302 case COM2_IRQ_ENABLE_PORT:
303 if (handle_ier_write(&(state->com2), (struct irq_enable_reg *)val) == -1) {
307 case COM3_IRQ_ENABLE_PORT:
308 if (handle_ier_write(&(state->com3), (struct irq_enable_reg *)val) == -1) {
312 case COM4_IRQ_ENABLE_PORT:
313 if (handle_ier_write(&(state->com4), (struct irq_enable_reg *)val) == -1) {
318 case COM1_FIFO_CTRL_PORT:
319 case COM2_FIFO_CTRL_PORT:
320 case COM3_FIFO_CTRL_PORT:
321 case COM4_FIFO_CTRL_PORT:
323 case COM1_LINE_CTRL_PORT:
324 case COM2_LINE_CTRL_PORT:
325 case COM3_LINE_CTRL_PORT:
326 case COM4_LINE_CTRL_PORT:
328 case COM1_MODEM_CTRL_PORT:
329 case COM2_MODEM_CTRL_PORT:
330 case COM3_MODEM_CTRL_PORT:
331 case COM4_MODEM_CTRL_PORT:
346 static int read_ctrl_port(ushort_t port, void * dst, uint_t length, struct vm_device * dev) {
347 struct serial_state * state = (struct serial_state *)dev->private_data;
348 char * val = (char *)dst;
349 PrintDebug("Read from Control Port\n");
352 PrintDebug("Invalid Read length to control port\n");
357 case COM1_IRQ_ENABLE_PORT:
358 *val = state->com1.ier;
360 case COM2_IRQ_ENABLE_PORT:
361 *val = state->com2.ier;
363 case COM3_IRQ_ENABLE_PORT:
364 *val = state->com3.ier;
366 case COM4_IRQ_ENABLE_PORT:
367 *val = state->com4.ier;
370 case COM1_FIFO_CTRL_PORT:
371 *val = state->com1.fcr;
373 case COM2_FIFO_CTRL_PORT:
374 *val = state->com2.fcr;
376 case COM3_FIFO_CTRL_PORT:
377 *val = state->com3.fcr;
379 case COM4_FIFO_CTRL_PORT:
380 *val = state->com4.fcr;
383 case COM1_LINE_CTRL_PORT:
384 *val = state->com1.lcr;
386 case COM2_LINE_CTRL_PORT:
387 *val = state->com2.lcr;
389 case COM3_LINE_CTRL_PORT:
390 *val = state->com3.lcr;
392 case COM4_LINE_CTRL_PORT:
393 *val = state->com4.lcr;
396 case COM1_MODEM_CTRL_PORT:
397 *val = state->com1.mcr;
399 case COM2_MODEM_CTRL_PORT:
400 *val = state->com2.mcr;
402 case COM3_MODEM_CTRL_PORT:
403 *val = state->com3.mcr;
405 case COM4_MODEM_CTRL_PORT:
406 *val = state->com4.mcr;
417 static int write_status_port(ushort_t port, void * src, uint_t length, struct vm_device * dev) {
418 PrintDebug("Write to Status Port 0x%x (val=%x)\n", port, *(char *)src);
423 static int read_status_port(ushort_t port, void * dst, uint_t length, struct vm_device * dev) {
424 struct serial_state * state = (struct serial_state *)dev->private_data;
425 char * val = (char *)dst;
426 PrintDebug("Read from Status Port 0x%x\n", port);
429 PrintDebug("Invalid Read length to control port\n");
434 case COM1_LINE_STATUS_PORT:
435 *val = state->com1.lsr;
437 case COM2_LINE_STATUS_PORT:
438 *val = state->com2.lsr;
440 case COM3_LINE_STATUS_PORT:
441 *val = state->com3.lsr;
443 case COM4_LINE_STATUS_PORT:
444 *val = state->com4.lsr;
447 case COM1_MODEM_STATUS_PORT:
448 *val = state->com1.msr;
450 case COM2_MODEM_STATUS_PORT:
451 *val = state->com2.msr;
453 case COM3_MODEM_STATUS_PORT:
454 *val = state->com3.msr;
456 case COM4_MODEM_STATUS_PORT:
457 *val = state->com4.msr;
473 static int init_serial_port(struct serial_port * com) {
474 //struct irq_enable_reg * ier = (struct irq_enable_reg *)&(com->ier);
475 //struct irq_id_reg * iir = (struct irq_id_reg *)&(com->iir);
476 //struct fifo_ctrl_reg * fcr = (struct fifo_ctrl_reg *)&(com->fcr);
477 //struct line_ctrl_reg * lcr = (struct line_ctrl_reg *)&(com->lcr);
478 //struct modem_ctrl_reg * mcr = (struct modem_ctrl_reg *)&(com->mcr);
479 //struct line_status_reg * lsr = (struct line_status_reg *)&(com->lsr);
480 //struct modem_status_reg * msr = (struct modem_status_reg *)&(com->msr);
493 static int serial_init(struct vm_device * dev) {
494 struct serial_state * state = (struct serial_state *)dev->private_data;
497 init_serial_port(&(state->com1));
498 init_serial_port(&(state->com2));
499 init_serial_port(&(state->com3));
500 init_serial_port(&(state->com4));
502 v3_dev_hook_io(dev, COM1_DATA_PORT, &read_data_port, &write_data_port);
503 v3_dev_hook_io(dev, COM1_IRQ_ENABLE_PORT, &read_ctrl_port, &write_ctrl_port);
504 v3_dev_hook_io(dev, COM1_FIFO_CTRL_PORT, &read_ctrl_port, &write_ctrl_port);
505 v3_dev_hook_io(dev, COM1_LINE_CTRL_PORT, &read_ctrl_port, &write_ctrl_port);
506 v3_dev_hook_io(dev, COM1_MODEM_CTRL_PORT, &read_ctrl_port, &write_ctrl_port);
507 v3_dev_hook_io(dev, COM1_LINE_STATUS_PORT, &read_status_port, &write_status_port);
508 v3_dev_hook_io(dev, COM1_MODEM_STATUS_PORT, &read_status_port, &write_status_port);
509 v3_dev_hook_io(dev, COM1_SCRATCH_PORT, &read_ctrl_port, &write_ctrl_port);
511 v3_dev_hook_io(dev, COM2_DATA_PORT, &read_data_port, &write_data_port);
512 v3_dev_hook_io(dev, COM2_IRQ_ENABLE_PORT, &read_ctrl_port, &write_ctrl_port);
513 v3_dev_hook_io(dev, COM2_FIFO_CTRL_PORT, &read_ctrl_port, &write_ctrl_port);
514 v3_dev_hook_io(dev, COM2_LINE_CTRL_PORT, &read_ctrl_port, &write_ctrl_port);
515 v3_dev_hook_io(dev, COM2_MODEM_CTRL_PORT, &read_ctrl_port, &write_ctrl_port);
516 v3_dev_hook_io(dev, COM2_LINE_STATUS_PORT, &read_status_port, &write_status_port);
517 v3_dev_hook_io(dev, COM2_MODEM_STATUS_PORT, &read_status_port, &write_status_port);
518 v3_dev_hook_io(dev, COM2_SCRATCH_PORT, &read_ctrl_port, &write_ctrl_port);
520 v3_dev_hook_io(dev, COM3_DATA_PORT, &read_data_port, &write_data_port);
521 v3_dev_hook_io(dev, COM3_IRQ_ENABLE_PORT, &read_ctrl_port, &write_ctrl_port);
522 v3_dev_hook_io(dev, COM3_FIFO_CTRL_PORT, &read_ctrl_port, &write_ctrl_port);
523 v3_dev_hook_io(dev, COM3_LINE_CTRL_PORT, &read_ctrl_port, &write_ctrl_port);
524 v3_dev_hook_io(dev, COM3_MODEM_CTRL_PORT, &read_ctrl_port, &write_ctrl_port);
525 v3_dev_hook_io(dev, COM3_LINE_STATUS_PORT, &read_status_port, &write_status_port);
526 v3_dev_hook_io(dev, COM3_MODEM_STATUS_PORT, &read_status_port, &write_status_port);
527 v3_dev_hook_io(dev, COM3_SCRATCH_PORT, &read_ctrl_port, &write_ctrl_port);
529 v3_dev_hook_io(dev, COM4_DATA_PORT, &read_data_port, &write_data_port);
530 v3_dev_hook_io(dev, COM4_IRQ_ENABLE_PORT, &read_ctrl_port, &write_ctrl_port);
531 v3_dev_hook_io(dev, COM4_FIFO_CTRL_PORT, &read_ctrl_port, &write_ctrl_port);
532 v3_dev_hook_io(dev, COM4_LINE_CTRL_PORT, &read_ctrl_port, &write_ctrl_port);
533 v3_dev_hook_io(dev, COM4_MODEM_CTRL_PORT, &read_ctrl_port, &write_ctrl_port);
534 v3_dev_hook_io(dev, COM4_LINE_STATUS_PORT, &read_status_port, &write_status_port);
535 v3_dev_hook_io(dev, COM4_MODEM_STATUS_PORT, &read_status_port, &write_status_port);
536 v3_dev_hook_io(dev, COM4_SCRATCH_PORT, &read_ctrl_port, &write_ctrl_port);
542 static int serial_deinit(struct vm_device * dev) {
545 v3_dev_unhook_io(dev, COM1_DATA_PORT);
546 v3_dev_unhook_io(dev, COM1_IRQ_ENABLE_PORT);
547 v3_dev_unhook_io(dev, COM1_FIFO_CTRL_PORT);
548 v3_dev_unhook_io(dev, COM1_LINE_CTRL_PORT);
549 v3_dev_unhook_io(dev, COM1_MODEM_CTRL_PORT);
550 v3_dev_unhook_io(dev, COM1_LINE_STATUS_PORT);
551 v3_dev_unhook_io(dev, COM1_MODEM_STATUS_PORT);
552 v3_dev_unhook_io(dev, COM1_SCRATCH_PORT);
554 v3_dev_unhook_io(dev, COM2_DATA_PORT);
555 v3_dev_unhook_io(dev, COM2_IRQ_ENABLE_PORT);
556 v3_dev_unhook_io(dev, COM2_FIFO_CTRL_PORT);
557 v3_dev_unhook_io(dev, COM2_LINE_CTRL_PORT);
558 v3_dev_unhook_io(dev, COM2_MODEM_CTRL_PORT);
559 v3_dev_unhook_io(dev, COM2_LINE_STATUS_PORT);
560 v3_dev_unhook_io(dev, COM2_MODEM_STATUS_PORT);
561 v3_dev_unhook_io(dev, COM2_SCRATCH_PORT);
563 v3_dev_unhook_io(dev, COM3_DATA_PORT);
564 v3_dev_unhook_io(dev, COM3_IRQ_ENABLE_PORT);
565 v3_dev_unhook_io(dev, COM3_FIFO_CTRL_PORT);
566 v3_dev_unhook_io(dev, COM3_LINE_CTRL_PORT);
567 v3_dev_unhook_io(dev, COM3_MODEM_CTRL_PORT);
568 v3_dev_unhook_io(dev, COM3_LINE_STATUS_PORT);
569 v3_dev_unhook_io(dev, COM3_MODEM_STATUS_PORT);
570 v3_dev_unhook_io(dev, COM3_SCRATCH_PORT);
572 v3_dev_unhook_io(dev, COM4_DATA_PORT);
573 v3_dev_unhook_io(dev, COM4_IRQ_ENABLE_PORT);
574 v3_dev_unhook_io(dev, COM4_FIFO_CTRL_PORT);
575 v3_dev_unhook_io(dev, COM4_LINE_CTRL_PORT);
576 v3_dev_unhook_io(dev, COM4_MODEM_CTRL_PORT);
577 v3_dev_unhook_io(dev, COM4_LINE_STATUS_PORT);
578 v3_dev_unhook_io(dev, COM4_MODEM_STATUS_PORT);
579 v3_dev_unhook_io(dev, COM4_SCRATCH_PORT);
586 static struct vm_device_ops dev_ops = {
588 .deinit = serial_deinit,
595 struct vm_device * v3_create_serial(int num_ports) {
596 struct serial_state * state = NULL;
597 state = (struct serial_state *)V3_Malloc(sizeof(struct serial_state));
598 V3_ASSERT(state != NULL);
600 struct vm_device * device = v3_create_device("Serial UART", &dev_ops, state);