1 /* (c) 2008, Jack Lange <jarusl@cs.northwestern.edu> */
2 /* (c) 2008, The V3VEE Project <http://www.v3vee.org> */
4 #include <devices/serial.h>
5 #include <palacios/vmm.h>
8 #define COM1_DATA_PORT 0x3f8
9 #define COM1_IRQ_ENABLE_PORT 0x3f9
10 #define COM1_DIV_LATCH_LSB_PORT 0x3f8
11 #define COM1_DIV_LATCH_MSB_PORT 0x3f9
12 #define COM1_IIR_PORT 0x3fa
13 #define COM1_FIFO_CTRL_PORT 0x3fa
14 #define COM1_LINE_CTRL_PORT 0x3fb
15 #define COM1_MODEM_CTRL_PORT 0x3fc
16 #define COM1_LINE_STATUS_PORT 0x3fd
17 #define COM1_MODEM_STATUS_PORT 0x3fe
18 #define COM1_SCRATCH_PORT 0x3ff
20 #define COM2_DATA_PORT 0x2f8
21 #define COM2_IRQ_ENABLE_PORT 0x2f9
22 #define COM2_DIV_LATCH_LSB_PORT 0x2f8
23 #define COM2_DIV_LATCH_MSB_PORT 0x2f9
24 #define COM2_IIR_PORT 0x2fa
25 #define COM2_FIFO_CTRL_PORT 0x2fa
26 #define COM2_LINE_CTRL_PORT 0x2fb
27 #define COM2_MODEM_CTRL_PORT 0x2fc
28 #define COM2_LINE_STATUS_PORT 0x2fd
29 #define COM2_MODEM_STATUS_PORT 0x2fe
30 #define COM2_SCRATCH_PORT 0x2ff
32 #define COM3_DATA_PORT 0x3e8
33 #define COM3_IRQ_ENABLE_PORT 0x3e9
34 #define COM3_DIV_LATCH_LSB_PORT 0x3e8
35 #define COM3_DIV_LATCH_MSB_PORT 0x3e9
36 #define COM3_IIR_PORT 0x3ea
37 #define COM3_FIFO_CTRL_PORT 0x3ea
38 #define COM3_LINE_CTRL_PORT 0x3eb
39 #define COM3_MODEM_CTRL_PORT 0x3ec
40 #define COM3_LINE_STATUS_PORT 0x3ed
41 #define COM3_MODEM_STATUS_PORT 0x3ee
42 #define COM3_SCRATCH_PORT 0x3ef
44 #define COM4_DATA_PORT 0x2e8
45 #define COM4_IRQ_ENABLE_PORT 0x2e9
46 #define COM4_DIV_LATCH_LSB_PORT 0x2e8
47 #define COM4_DIV_LATCH_MSB_PORT 0x2e9
48 #define COM4_IIR_PORT 0x2ea
49 #define COM4_FIFO_CTRL_PORT 0x2ea
50 #define COM4_LINE_CTRL_PORT 0x2eb
51 #define COM4_MODEM_CTRL_PORT 0x2ec
52 #define COM4_LINE_STATUS_PORT 0x2ed
53 #define COM4_MODEM_STATUS_PORT 0x2ee
54 #define COM4_SCRATCH_PORT 0x2ef
58 struct irq_enable_reg {
59 uint_t erbfi : 1; // Enable Receiver Buffer full interrupt
60 uint_t etbei : 1; // Enable Transmit buffer empty interrupt
61 uint_t elsi : 1; // Enable Line Status Interrupt
62 uint_t edssi : 1; // Enable Delta Status signals interrupt
63 uint_t rsvd : 4; // MBZ
68 // Interrupt IDs (in priority order, highest is first)
69 #define STATUS_IRQ_LSR_OE_SET 0x3
70 #define STATUS_IRQ_LSR_PE_SET 0x3
71 #define STATUS_IRQ_LSR_FE_SET 0x3
72 #define STATUS_IRQ_LSR_BI_SET 0x3
74 #define RX_IRQ_TRIGGER_LEVEL 0x2
76 #define TX_IRQ_THRE 0x1
77 #define MODEL_IRQ_DELTA_SET 0x0
80 uint_t pending : 1; // Interrupt pending (0=interrupt pending)
81 uint_t iid : 3; // Interrupt Identification
82 uint_t rsvd : 2; // MBZ
83 uint_t fifo_en : 2; // FIFO enable
86 struct fifo_ctrl_reg {
87 uint_t enable : 1; // enable fifo
88 uint_t rfres : 1; // RX FIFO reset
89 uint_t xfres : 1; // TX FIFO reset
90 uint_t dma_sel : 1; // DMA mode select
91 uint_t rsvd : 2; // MBZ
92 uint_t rx_trigger: 2; // RX FIFO trigger level select
95 struct line_ctrl_reg {
96 uint_t word_len : 2; // word length select
97 uint_t stop_bits : 1; // Stop Bit select
98 uint_t parity_enable : 1; // Enable parity
99 uint_t even_sel : 1; // Even Parity Select
100 uint_t stick_parity : 1; // Stick Parity Select
101 uint_t sbr : 1; // Set Break
102 uint_t dlab : 1; // Divisor latch access bit
106 struct modem_ctrl_reg {
111 uint_t loop : 1; // loopback mode
112 uint_t rsvd : 3; // MBZ
116 struct line_status_reg {
117 uint_t rbf : 1; // Receiver Buffer Full
118 uint_t oe : 1; // Overrun error
119 uint_t pe : 1; // Parity Error
120 uint_t fe : 1; // Framing Error
121 uint_t brk : 1; // broken line detected
122 uint_t thre : 1; // Transmitter holding register empty
123 uint_t temt : 1; // Transmitter Empty
124 uint_t fifo_err : 1; // at least one error is pending in the RX FIFO chain
128 struct modem_status_reg {
129 uint_t dcts : 1; // Delta Clear To Send
130 uint_t ddsr : 1; // Delta Data Set Ready
131 uint_t teri : 1; // Trailing Edge Ring Indicator
132 uint_t ddcd : 1; // Delta Data Carrier Detect
133 uint_t cts : 1; // Clear to Send
134 uint_t dsr : 1; // Data Set Ready
135 uint_t ri : 1; // Ring Indicator
136 uint_t dcd : 1; // Data Carrier Detect
140 #define SERIAL_BUF_LEN 256
142 struct serial_buffer {
143 uint_t head; // most recent data
144 uint_t tail; // oldest char
145 char buffer[SERIAL_BUF_LEN];
148 int queue_data(struct serial_buffer * buf, char data) {
149 int next_loc = (buf->head + 1) % SERIAL_BUF_LEN;
151 if (next_loc == buf->tail) {
155 buf->buffer[next_loc] = data;
156 buf->head = next_loc;
161 int dequeue_data(struct serial_buffer * buf, char * data) {
162 int next_tail = (buf->tail + 1) % SERIAL_BUF_LEN;
164 if (buf->head == buf->tail) {
168 *data = buf->buffer[buf->tail];
169 buf->tail = next_tail;
184 struct serial_buffer tx_buffer;
185 struct serial_buffer rx_buffer;
189 struct serial_state {
190 struct serial_port com1;
191 struct serial_port com2;
192 struct serial_port com3;
193 struct serial_port com4;
197 int write_data_port(ushort_t port, void * src, uint_t length, struct vm_device * dev) {
198 struct serial_state * state = (struct serial_state *)dev->private_data;
199 char * val = (char *)src;
200 PrintDebug("Write to Data Port 0x%x (val=%x)\n", port, *(char*)src);
203 PrintDebug("Invalid length(%d) in write to 0x%x\n", length, port);
209 queue_data(&(state->com1.tx_buffer), *val);
212 queue_data(&(state->com2.tx_buffer), *val);
215 queue_data(&(state->com3.tx_buffer), *val);
218 queue_data(&(state->com4.tx_buffer), *val);
230 int read_data_port(ushort_t port, void * dst, uint_t length, struct vm_device * dev) {
231 struct serial_state * state = (struct serial_state *)dev->private_data;
232 char * val = (char *)dst;
233 PrintDebug("Read from Data Port 0x%x\n", port);
236 PrintDebug("Invalid length(%d) in write to 0x%x\n", length, port);
242 dequeue_data(&(state->com1.tx_buffer), val);
245 dequeue_data(&(state->com2.tx_buffer), val);
248 dequeue_data(&(state->com3.tx_buffer), val);
251 dequeue_data(&(state->com4.tx_buffer), val);
263 int handle_ier_write(struct serial_port * com, struct irq_enable_reg * ier) {
270 int write_ctrl_port(ushort_t port, void * src, uint_t length, struct vm_device * dev) {
271 struct serial_state * state = (struct serial_state *)dev->private_data;
272 char * val = (char *)src;
273 PrintDebug("Write to Control Port (val=%x)\n", *(char *)src);
276 PrintDebug("Invalid Write length to control port\n", port, port);
281 case COM1_IRQ_ENABLE_PORT:
282 if (handle_ier_write(&(state->com1), (struct irq_enable_reg *)val) == -1) {
286 case COM2_IRQ_ENABLE_PORT:
287 if (handle_ier_write(&(state->com2), (struct irq_enable_reg *)val) == -1) {
291 case COM3_IRQ_ENABLE_PORT:
292 if (handle_ier_write(&(state->com3), (struct irq_enable_reg *)val) == -1) {
296 case COM4_IRQ_ENABLE_PORT:
297 if (handle_ier_write(&(state->com4), (struct irq_enable_reg *)val) == -1) {
302 case COM1_FIFO_CTRL_PORT:
303 case COM2_FIFO_CTRL_PORT:
304 case COM3_FIFO_CTRL_PORT:
305 case COM4_FIFO_CTRL_PORT:
307 case COM1_LINE_CTRL_PORT:
308 case COM2_LINE_CTRL_PORT:
309 case COM3_LINE_CTRL_PORT:
310 case COM4_LINE_CTRL_PORT:
312 case COM1_MODEM_CTRL_PORT:
313 case COM2_MODEM_CTRL_PORT:
314 case COM3_MODEM_CTRL_PORT:
315 case COM4_MODEM_CTRL_PORT:
330 int read_ctrl_port(ushort_t port, void * dst, uint_t length, struct vm_device * dev) {
331 struct serial_state * state = (struct serial_state *)dev->private_data;
332 char * val = (char *)dst;
333 PrintDebug("Read from Control Port\n");
336 PrintDebug("Invalid Read length to control port\n");
341 case COM1_IRQ_ENABLE_PORT:
342 *val = state->com1.ier;
344 case COM2_IRQ_ENABLE_PORT:
345 *val = state->com2.ier;
347 case COM3_IRQ_ENABLE_PORT:
348 *val = state->com3.ier;
350 case COM4_IRQ_ENABLE_PORT:
351 *val = state->com4.ier;
354 case COM1_FIFO_CTRL_PORT:
355 *val = state->com1.fcr;
357 case COM2_FIFO_CTRL_PORT:
358 *val = state->com2.fcr;
360 case COM3_FIFO_CTRL_PORT:
361 *val = state->com3.fcr;
363 case COM4_FIFO_CTRL_PORT:
364 *val = state->com4.fcr;
367 case COM1_LINE_CTRL_PORT:
368 *val = state->com1.lcr;
370 case COM2_LINE_CTRL_PORT:
371 *val = state->com2.lcr;
373 case COM3_LINE_CTRL_PORT:
374 *val = state->com3.lcr;
376 case COM4_LINE_CTRL_PORT:
377 *val = state->com4.lcr;
380 case COM1_MODEM_CTRL_PORT:
381 *val = state->com1.mcr;
383 case COM2_MODEM_CTRL_PORT:
384 *val = state->com2.mcr;
386 case COM3_MODEM_CTRL_PORT:
387 *val = state->com3.mcr;
389 case COM4_MODEM_CTRL_PORT:
390 *val = state->com4.mcr;
401 int write_status_port(ushort_t port, void * src, uint_t length, struct vm_device * dev) {
402 PrintDebug("Write to Status Port 0x%x (val=%x)\n", port, *(char *)src);
407 int read_status_port(ushort_t port, void * dst, uint_t length, struct vm_device * dev) {
408 struct serial_state * state = (struct serial_state *)dev->private_data;
409 char * val = (char *)dst;
410 PrintDebug("Read from Status Port 0x%x\n", port);
413 PrintDebug("Invalid Read length to control port\n");
418 case COM1_LINE_STATUS_PORT:
419 *val = state->com1.lsr;
421 case COM2_LINE_STATUS_PORT:
422 *val = state->com2.lsr;
424 case COM3_LINE_STATUS_PORT:
425 *val = state->com3.lsr;
427 case COM4_LINE_STATUS_PORT:
428 *val = state->com4.lsr;
431 case COM1_MODEM_STATUS_PORT:
432 *val = state->com1.msr;
434 case COM2_MODEM_STATUS_PORT:
435 *val = state->com2.msr;
437 case COM3_MODEM_STATUS_PORT:
438 *val = state->com3.msr;
440 case COM4_MODEM_STATUS_PORT:
441 *val = state->com4.msr;
457 static int init_serial_port(struct serial_port * com) {
458 //struct irq_enable_reg * ier = (struct irq_enable_reg *)&(com->ier);
459 //struct irq_id_reg * iir = (struct irq_id_reg *)&(com->iir);
460 //struct fifo_ctrl_reg * fcr = (struct fifo_ctrl_reg *)&(com->fcr);
461 //struct line_ctrl_reg * lcr = (struct line_ctrl_reg *)&(com->lcr);
462 //struct modem_ctrl_reg * mcr = (struct modem_ctrl_reg *)&(com->mcr);
463 //struct line_status_reg * lsr = (struct line_status_reg *)&(com->lsr);
464 //struct modem_status_reg * msr = (struct modem_status_reg *)&(com->msr);
477 int serial_init(struct vm_device * dev) {
478 struct serial_state * state = (struct serial_state *)dev->private_data;
481 init_serial_port(&(state->com1));
482 init_serial_port(&(state->com2));
483 init_serial_port(&(state->com3));
484 init_serial_port(&(state->com4));
486 dev_hook_io(dev, COM1_DATA_PORT, &read_data_port, &write_data_port);
487 dev_hook_io(dev, COM1_IRQ_ENABLE_PORT, &read_ctrl_port, &write_ctrl_port);
488 dev_hook_io(dev, COM1_FIFO_CTRL_PORT, &read_ctrl_port, &write_ctrl_port);
489 dev_hook_io(dev, COM1_LINE_CTRL_PORT, &read_ctrl_port, &write_ctrl_port);
490 dev_hook_io(dev, COM1_MODEM_CTRL_PORT, &read_ctrl_port, &write_ctrl_port);
491 dev_hook_io(dev, COM1_LINE_STATUS_PORT, &read_status_port, &write_status_port);
492 dev_hook_io(dev, COM1_MODEM_STATUS_PORT, &read_status_port, &write_status_port);
493 dev_hook_io(dev, COM1_SCRATCH_PORT, &read_ctrl_port, &write_ctrl_port);
495 dev_hook_io(dev, COM2_DATA_PORT, &read_data_port, &write_data_port);
496 dev_hook_io(dev, COM2_IRQ_ENABLE_PORT, &read_ctrl_port, &write_ctrl_port);
497 dev_hook_io(dev, COM2_FIFO_CTRL_PORT, &read_ctrl_port, &write_ctrl_port);
498 dev_hook_io(dev, COM2_LINE_CTRL_PORT, &read_ctrl_port, &write_ctrl_port);
499 dev_hook_io(dev, COM2_MODEM_CTRL_PORT, &read_ctrl_port, &write_ctrl_port);
500 dev_hook_io(dev, COM2_LINE_STATUS_PORT, &read_status_port, &write_status_port);
501 dev_hook_io(dev, COM2_MODEM_STATUS_PORT, &read_status_port, &write_status_port);
502 dev_hook_io(dev, COM2_SCRATCH_PORT, &read_ctrl_port, &write_ctrl_port);
504 dev_hook_io(dev, COM3_DATA_PORT, &read_data_port, &write_data_port);
505 dev_hook_io(dev, COM3_IRQ_ENABLE_PORT, &read_ctrl_port, &write_ctrl_port);
506 dev_hook_io(dev, COM3_FIFO_CTRL_PORT, &read_ctrl_port, &write_ctrl_port);
507 dev_hook_io(dev, COM3_LINE_CTRL_PORT, &read_ctrl_port, &write_ctrl_port);
508 dev_hook_io(dev, COM3_MODEM_CTRL_PORT, &read_ctrl_port, &write_ctrl_port);
509 dev_hook_io(dev, COM3_LINE_STATUS_PORT, &read_status_port, &write_status_port);
510 dev_hook_io(dev, COM3_MODEM_STATUS_PORT, &read_status_port, &write_status_port);
511 dev_hook_io(dev, COM3_SCRATCH_PORT, &read_ctrl_port, &write_ctrl_port);
513 dev_hook_io(dev, COM4_DATA_PORT, &read_data_port, &write_data_port);
514 dev_hook_io(dev, COM4_IRQ_ENABLE_PORT, &read_ctrl_port, &write_ctrl_port);
515 dev_hook_io(dev, COM4_FIFO_CTRL_PORT, &read_ctrl_port, &write_ctrl_port);
516 dev_hook_io(dev, COM4_LINE_CTRL_PORT, &read_ctrl_port, &write_ctrl_port);
517 dev_hook_io(dev, COM4_MODEM_CTRL_PORT, &read_ctrl_port, &write_ctrl_port);
518 dev_hook_io(dev, COM4_LINE_STATUS_PORT, &read_status_port, &write_status_port);
519 dev_hook_io(dev, COM4_MODEM_STATUS_PORT, &read_status_port, &write_status_port);
520 dev_hook_io(dev, COM4_SCRATCH_PORT, &read_ctrl_port, &write_ctrl_port);
526 int serial_deinit(struct vm_device * dev) {
529 dev_unhook_io(dev, COM1_DATA_PORT);
530 dev_unhook_io(dev, COM1_IRQ_ENABLE_PORT);
531 dev_unhook_io(dev, COM1_FIFO_CTRL_PORT);
532 dev_unhook_io(dev, COM1_LINE_CTRL_PORT);
533 dev_unhook_io(dev, COM1_MODEM_CTRL_PORT);
534 dev_unhook_io(dev, COM1_LINE_STATUS_PORT);
535 dev_unhook_io(dev, COM1_MODEM_STATUS_PORT);
536 dev_unhook_io(dev, COM1_SCRATCH_PORT);
538 dev_unhook_io(dev, COM2_DATA_PORT);
539 dev_unhook_io(dev, COM2_IRQ_ENABLE_PORT);
540 dev_unhook_io(dev, COM2_FIFO_CTRL_PORT);
541 dev_unhook_io(dev, COM2_LINE_CTRL_PORT);
542 dev_unhook_io(dev, COM2_MODEM_CTRL_PORT);
543 dev_unhook_io(dev, COM2_LINE_STATUS_PORT);
544 dev_unhook_io(dev, COM2_MODEM_STATUS_PORT);
545 dev_unhook_io(dev, COM2_SCRATCH_PORT);
547 dev_unhook_io(dev, COM3_DATA_PORT);
548 dev_unhook_io(dev, COM3_IRQ_ENABLE_PORT);
549 dev_unhook_io(dev, COM3_FIFO_CTRL_PORT);
550 dev_unhook_io(dev, COM3_LINE_CTRL_PORT);
551 dev_unhook_io(dev, COM3_MODEM_CTRL_PORT);
552 dev_unhook_io(dev, COM3_LINE_STATUS_PORT);
553 dev_unhook_io(dev, COM3_MODEM_STATUS_PORT);
554 dev_unhook_io(dev, COM3_SCRATCH_PORT);
556 dev_unhook_io(dev, COM4_DATA_PORT);
557 dev_unhook_io(dev, COM4_IRQ_ENABLE_PORT);
558 dev_unhook_io(dev, COM4_FIFO_CTRL_PORT);
559 dev_unhook_io(dev, COM4_LINE_CTRL_PORT);
560 dev_unhook_io(dev, COM4_MODEM_CTRL_PORT);
561 dev_unhook_io(dev, COM4_LINE_STATUS_PORT);
562 dev_unhook_io(dev, COM4_MODEM_STATUS_PORT);
563 dev_unhook_io(dev, COM4_SCRATCH_PORT);
570 static struct vm_device_ops dev_ops = {
572 .deinit = serial_deinit,
579 struct vm_device * create_serial(int num_ports) {
580 struct serial_state * state = NULL;
581 state = (struct serial_state *)V3_Malloc(sizeof(struct serial_state));
582 V3_ASSERT(state != NULL);
584 struct vm_device * device = create_device("Serial UART", &dev_ops, state);