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 <palacios/vmm.h>
21 #include <palacios/vmm_dev_mgr.h>
23 #define COM1_DATA_PORT 0x3f8
24 #define COM1_IRQ_ENABLE_PORT 0x3f9
25 #define COM1_DIV_LATCH_LSB_PORT 0x3f8
26 #define COM1_DIV_LATCH_MSB_PORT 0x3f9
27 #define COM1_IIR_PORT 0x3fa
28 #define COM1_FIFO_CTRL_PORT 0x3fa
29 #define COM1_LINE_CTRL_PORT 0x3fb
30 #define COM1_MODEM_CTRL_PORT 0x3fc
31 #define COM1_LINE_STATUS_PORT 0x3fd
32 #define COM1_MODEM_STATUS_PORT 0x3fe
33 #define COM1_SCRATCH_PORT 0x3ff
35 #define COM2_DATA_PORT 0x2f8
36 #define COM2_IRQ_ENABLE_PORT 0x2f9
37 #define COM2_DIV_LATCH_LSB_PORT 0x2f8
38 #define COM2_DIV_LATCH_MSB_PORT 0x2f9
39 #define COM2_IIR_PORT 0x2fa
40 #define COM2_FIFO_CTRL_PORT 0x2fa
41 #define COM2_LINE_CTRL_PORT 0x2fb
42 #define COM2_MODEM_CTRL_PORT 0x2fc
43 #define COM2_LINE_STATUS_PORT 0x2fd
44 #define COM2_MODEM_STATUS_PORT 0x2fe
45 #define COM2_SCRATCH_PORT 0x2ff
47 #define COM3_DATA_PORT 0x3e8
48 #define COM3_IRQ_ENABLE_PORT 0x3e9
49 #define COM3_DIV_LATCH_LSB_PORT 0x3e8
50 #define COM3_DIV_LATCH_MSB_PORT 0x3e9
51 #define COM3_IIR_PORT 0x3ea
52 #define COM3_FIFO_CTRL_PORT 0x3ea
53 #define COM3_LINE_CTRL_PORT 0x3eb
54 #define COM3_MODEM_CTRL_PORT 0x3ec
55 #define COM3_LINE_STATUS_PORT 0x3ed
56 #define COM3_MODEM_STATUS_PORT 0x3ee
57 #define COM3_SCRATCH_PORT 0x3ef
59 #define COM4_DATA_PORT 0x2e8
60 #define COM4_IRQ_ENABLE_PORT 0x2e9
61 #define COM4_DIV_LATCH_LSB_PORT 0x2e8
62 #define COM4_DIV_LATCH_MSB_PORT 0x2e9
63 #define COM4_IIR_PORT 0x2ea
64 #define COM4_FIFO_CTRL_PORT 0x2ea
65 #define COM4_LINE_CTRL_PORT 0x2eb
66 #define COM4_MODEM_CTRL_PORT 0x2ec
67 #define COM4_LINE_STATUS_PORT 0x2ed
68 #define COM4_MODEM_STATUS_PORT 0x2ee
69 #define COM4_SCRATCH_PORT 0x2ef
73 struct irq_enable_reg {
74 uint_t erbfi : 1; // Enable Receiver Buffer full interrupt
75 uint_t etbei : 1; // Enable Transmit buffer empty interrupt
76 uint_t elsi : 1; // Enable Line Status Interrupt
77 uint_t edssi : 1; // Enable Delta Status signals interrupt
78 uint_t rsvd : 4; // MBZ
83 // Interrupt IDs (in priority order, highest is first)
84 #define STATUS_IRQ_LSR_OE_SET 0x3
85 #define STATUS_IRQ_LSR_PE_SET 0x3
86 #define STATUS_IRQ_LSR_FE_SET 0x3
87 #define STATUS_IRQ_LSR_BI_SET 0x3
89 #define RX_IRQ_TRIGGER_LEVEL 0x2
91 #define TX_IRQ_THRE 0x1
92 #define MODEL_IRQ_DELTA_SET 0x0
95 uint_t pending : 1; // Interrupt pending (0=interrupt pending)
96 uint_t iid : 3; // Interrupt Identification
97 uint_t rsvd : 2; // MBZ
98 uint_t fifo_en : 2; // FIFO enable
101 struct fifo_ctrl_reg {
102 uint_t enable : 1; // enable fifo
103 uint_t rfres : 1; // RX FIFO reset
104 uint_t xfres : 1; // TX FIFO reset
105 uint_t dma_sel : 1; // DMA mode select
106 uint_t rsvd : 2; // MBZ
107 uint_t rx_trigger: 2; // RX FIFO trigger level select
110 struct line_ctrl_reg {
111 uint_t word_len : 2; // word length select
112 uint_t stop_bits : 1; // Stop Bit select
113 uint_t parity_enable : 1; // Enable parity
114 uint_t even_sel : 1; // Even Parity Select
115 uint_t stick_parity : 1; // Stick Parity Select
116 uint_t sbr : 1; // Set Break
117 uint_t dlab : 1; // Divisor latch access bit
121 struct modem_ctrl_reg {
126 uint_t loop : 1; // loopback mode
127 uint_t rsvd : 3; // MBZ
131 struct line_status_reg {
132 uint_t rbf : 1; // Receiver Buffer Full
133 uint_t oe : 1; // Overrun error
134 uint_t pe : 1; // Parity Error
135 uint_t fe : 1; // Framing Error
136 uint_t brk : 1; // broken line detected
137 uint_t thre : 1; // Transmitter holding register empty
138 uint_t temt : 1; // Transmitter Empty
139 uint_t fifo_err : 1; // at least one error is pending in the RX FIFO chain
143 struct modem_status_reg {
144 uint_t dcts : 1; // Delta Clear To Send
145 uint_t ddsr : 1; // Delta Data Set Ready
146 uint_t teri : 1; // Trailing Edge Ring Indicator
147 uint_t ddcd : 1; // Delta Data Carrier Detect
148 uint_t cts : 1; // Clear to Send
149 uint_t dsr : 1; // Data Set Ready
150 uint_t ri : 1; // Ring Indicator
151 uint_t dcd : 1; // Data Carrier Detect
155 #define SERIAL_BUF_LEN 256
157 struct serial_buffer {
158 uint_t head; // most recent data
159 uint_t tail; // oldest char
160 char buffer[SERIAL_BUF_LEN];
163 static int queue_data(struct serial_buffer * buf, char data) {
164 uint_t next_loc = (buf->head + 1) % SERIAL_BUF_LEN;
166 if (next_loc == buf->tail) {
170 buf->buffer[next_loc] = data;
171 buf->head = next_loc;
176 static int dequeue_data(struct serial_buffer * buf, char * data) {
177 uint_t next_tail = (buf->tail + 1) % SERIAL_BUF_LEN;
179 if (buf->head == buf->tail) {
183 *data = buf->buffer[buf->tail];
184 buf->tail = next_tail;
199 struct serial_buffer tx_buffer;
200 struct serial_buffer rx_buffer;
204 struct serial_state {
205 struct serial_port com1;
206 struct serial_port com2;
207 struct serial_port com3;
208 struct serial_port com4;
212 static int write_data_port(ushort_t port, void * src, uint_t length, struct vm_device * dev) {
213 struct serial_state * state = (struct serial_state *)dev->private_data;
214 char * val = (char *)src;
215 PrintDebug("Write to Data Port 0x%x (val=%x)\n", port, *(char*)src);
218 PrintDebug("Invalid length(%d) in write to 0x%x\n", length, port);
224 queue_data(&(state->com1.tx_buffer), *val);
227 queue_data(&(state->com2.tx_buffer), *val);
230 queue_data(&(state->com3.tx_buffer), *val);
233 queue_data(&(state->com4.tx_buffer), *val);
245 static int read_data_port(ushort_t port, void * dst, uint_t length, struct vm_device * dev) {
246 struct serial_state * state = (struct serial_state *)dev->private_data;
247 char * val = (char *)dst;
248 PrintDebug("Read from Data Port 0x%x\n", port);
251 PrintDebug("Invalid length(%d) in write to 0x%x\n", length, port);
257 dequeue_data(&(state->com1.tx_buffer), val);
260 dequeue_data(&(state->com2.tx_buffer), val);
263 dequeue_data(&(state->com3.tx_buffer), val);
266 dequeue_data(&(state->com4.tx_buffer), val);
278 static int handle_ier_write(struct serial_port * com, struct irq_enable_reg * ier) {
285 static int write_ctrl_port(ushort_t port, void * src, uint_t length, struct vm_device * dev) {
286 struct serial_state * state = (struct serial_state *)dev->private_data;
287 char * val = (char *)src;
288 PrintDebug("Write to Control Port (val=%x)\n", *(char *)src);
291 PrintDebug("Invalid Write length to control port %d\n", port);
296 case COM1_IRQ_ENABLE_PORT:
297 if (handle_ier_write(&(state->com1), (struct irq_enable_reg *)val) == -1) {
301 case COM2_IRQ_ENABLE_PORT:
302 if (handle_ier_write(&(state->com2), (struct irq_enable_reg *)val) == -1) {
306 case COM3_IRQ_ENABLE_PORT:
307 if (handle_ier_write(&(state->com3), (struct irq_enable_reg *)val) == -1) {
311 case COM4_IRQ_ENABLE_PORT:
312 if (handle_ier_write(&(state->com4), (struct irq_enable_reg *)val) == -1) {
317 case COM1_FIFO_CTRL_PORT:
318 case COM2_FIFO_CTRL_PORT:
319 case COM3_FIFO_CTRL_PORT:
320 case COM4_FIFO_CTRL_PORT:
322 case COM1_LINE_CTRL_PORT:
323 case COM2_LINE_CTRL_PORT:
324 case COM3_LINE_CTRL_PORT:
325 case COM4_LINE_CTRL_PORT:
327 case COM1_MODEM_CTRL_PORT:
328 case COM2_MODEM_CTRL_PORT:
329 case COM3_MODEM_CTRL_PORT:
330 case COM4_MODEM_CTRL_PORT:
345 static int read_ctrl_port(ushort_t port, void * dst, uint_t length, struct vm_device * dev) {
346 struct serial_state * state = (struct serial_state *)dev->private_data;
347 char * val = (char *)dst;
348 PrintDebug("Read from Control Port\n");
351 PrintDebug("Invalid Read length to control port\n");
356 case COM1_IRQ_ENABLE_PORT:
357 *val = state->com1.ier;
359 case COM2_IRQ_ENABLE_PORT:
360 *val = state->com2.ier;
362 case COM3_IRQ_ENABLE_PORT:
363 *val = state->com3.ier;
365 case COM4_IRQ_ENABLE_PORT:
366 *val = state->com4.ier;
369 case COM1_FIFO_CTRL_PORT:
370 *val = state->com1.fcr;
372 case COM2_FIFO_CTRL_PORT:
373 *val = state->com2.fcr;
375 case COM3_FIFO_CTRL_PORT:
376 *val = state->com3.fcr;
378 case COM4_FIFO_CTRL_PORT:
379 *val = state->com4.fcr;
382 case COM1_LINE_CTRL_PORT:
383 *val = state->com1.lcr;
385 case COM2_LINE_CTRL_PORT:
386 *val = state->com2.lcr;
388 case COM3_LINE_CTRL_PORT:
389 *val = state->com3.lcr;
391 case COM4_LINE_CTRL_PORT:
392 *val = state->com4.lcr;
395 case COM1_MODEM_CTRL_PORT:
396 *val = state->com1.mcr;
398 case COM2_MODEM_CTRL_PORT:
399 *val = state->com2.mcr;
401 case COM3_MODEM_CTRL_PORT:
402 *val = state->com3.mcr;
404 case COM4_MODEM_CTRL_PORT:
405 *val = state->com4.mcr;
416 static int write_status_port(ushort_t port, void * src, uint_t length, struct vm_device * dev) {
417 PrintDebug("Write to Status Port 0x%x (val=%x)\n", port, *(char *)src);
422 static int read_status_port(ushort_t port, void * dst, uint_t length, struct vm_device * dev) {
423 struct serial_state * state = (struct serial_state *)dev->private_data;
424 char * val = (char *)dst;
425 PrintDebug("Read from Status Port 0x%x\n", port);
428 PrintDebug("Invalid Read length to control port\n");
433 case COM1_LINE_STATUS_PORT:
434 *val = state->com1.lsr;
436 case COM2_LINE_STATUS_PORT:
437 *val = state->com2.lsr;
439 case COM3_LINE_STATUS_PORT:
440 *val = state->com3.lsr;
442 case COM4_LINE_STATUS_PORT:
443 *val = state->com4.lsr;
446 case COM1_MODEM_STATUS_PORT:
447 *val = state->com1.msr;
449 case COM2_MODEM_STATUS_PORT:
450 *val = state->com2.msr;
452 case COM3_MODEM_STATUS_PORT:
453 *val = state->com3.msr;
455 case COM4_MODEM_STATUS_PORT:
456 *val = state->com4.msr;
472 static int init_serial_port(struct serial_port * com) {
473 //struct irq_enable_reg * ier = (struct irq_enable_reg *)&(com->ier);
474 //struct irq_id_reg * iir = (struct irq_id_reg *)&(com->iir);
475 //struct fifo_ctrl_reg * fcr = (struct fifo_ctrl_reg *)&(com->fcr);
476 //struct line_ctrl_reg * lcr = (struct line_ctrl_reg *)&(com->lcr);
477 //struct modem_ctrl_reg * mcr = (struct modem_ctrl_reg *)&(com->mcr);
478 //struct line_status_reg * lsr = (struct line_status_reg *)&(com->lsr);
479 //struct modem_status_reg * msr = (struct modem_status_reg *)&(com->msr);
494 static int serial_free(struct vm_device * dev) {
497 v3_dev_unhook_io(dev, COM1_DATA_PORT);
498 v3_dev_unhook_io(dev, COM1_IRQ_ENABLE_PORT);
499 v3_dev_unhook_io(dev, COM1_FIFO_CTRL_PORT);
500 v3_dev_unhook_io(dev, COM1_LINE_CTRL_PORT);
501 v3_dev_unhook_io(dev, COM1_MODEM_CTRL_PORT);
502 v3_dev_unhook_io(dev, COM1_LINE_STATUS_PORT);
503 v3_dev_unhook_io(dev, COM1_MODEM_STATUS_PORT);
504 v3_dev_unhook_io(dev, COM1_SCRATCH_PORT);
506 v3_dev_unhook_io(dev, COM2_DATA_PORT);
507 v3_dev_unhook_io(dev, COM2_IRQ_ENABLE_PORT);
508 v3_dev_unhook_io(dev, COM2_FIFO_CTRL_PORT);
509 v3_dev_unhook_io(dev, COM2_LINE_CTRL_PORT);
510 v3_dev_unhook_io(dev, COM2_MODEM_CTRL_PORT);
511 v3_dev_unhook_io(dev, COM2_LINE_STATUS_PORT);
512 v3_dev_unhook_io(dev, COM2_MODEM_STATUS_PORT);
513 v3_dev_unhook_io(dev, COM2_SCRATCH_PORT);
515 v3_dev_unhook_io(dev, COM3_DATA_PORT);
516 v3_dev_unhook_io(dev, COM3_IRQ_ENABLE_PORT);
517 v3_dev_unhook_io(dev, COM3_FIFO_CTRL_PORT);
518 v3_dev_unhook_io(dev, COM3_LINE_CTRL_PORT);
519 v3_dev_unhook_io(dev, COM3_MODEM_CTRL_PORT);
520 v3_dev_unhook_io(dev, COM3_LINE_STATUS_PORT);
521 v3_dev_unhook_io(dev, COM3_MODEM_STATUS_PORT);
522 v3_dev_unhook_io(dev, COM3_SCRATCH_PORT);
524 v3_dev_unhook_io(dev, COM4_DATA_PORT);
525 v3_dev_unhook_io(dev, COM4_IRQ_ENABLE_PORT);
526 v3_dev_unhook_io(dev, COM4_FIFO_CTRL_PORT);
527 v3_dev_unhook_io(dev, COM4_LINE_CTRL_PORT);
528 v3_dev_unhook_io(dev, COM4_MODEM_CTRL_PORT);
529 v3_dev_unhook_io(dev, COM4_LINE_STATUS_PORT);
530 v3_dev_unhook_io(dev, COM4_MODEM_STATUS_PORT);
531 v3_dev_unhook_io(dev, COM4_SCRATCH_PORT);
538 static struct v3_device_ops dev_ops = {
548 static int serial_init(struct guest_info * vm, void * cfg_data) {
549 struct serial_state * state = NULL;
551 state = (struct serial_state *)V3_Malloc(sizeof(struct serial_state));
553 V3_ASSERT(state != NULL);
555 struct vm_device * dev = v3_allocate_device("SERIAL", &dev_ops, state);
558 if (v3_attach_device(vm, dev) == -1) {
559 PrintError("Could not attach device %s\n", "SERIAL");
565 init_serial_port(&(state->com1));
566 init_serial_port(&(state->com2));
567 init_serial_port(&(state->com3));
568 init_serial_port(&(state->com4));
570 v3_dev_hook_io(dev, COM1_DATA_PORT, &read_data_port, &write_data_port);
571 v3_dev_hook_io(dev, COM1_IRQ_ENABLE_PORT, &read_ctrl_port, &write_ctrl_port);
572 v3_dev_hook_io(dev, COM1_FIFO_CTRL_PORT, &read_ctrl_port, &write_ctrl_port);
573 v3_dev_hook_io(dev, COM1_LINE_CTRL_PORT, &read_ctrl_port, &write_ctrl_port);
574 v3_dev_hook_io(dev, COM1_MODEM_CTRL_PORT, &read_ctrl_port, &write_ctrl_port);
575 v3_dev_hook_io(dev, COM1_LINE_STATUS_PORT, &read_status_port, &write_status_port);
576 v3_dev_hook_io(dev, COM1_MODEM_STATUS_PORT, &read_status_port, &write_status_port);
577 v3_dev_hook_io(dev, COM1_SCRATCH_PORT, &read_ctrl_port, &write_ctrl_port);
579 v3_dev_hook_io(dev, COM2_DATA_PORT, &read_data_port, &write_data_port);
580 v3_dev_hook_io(dev, COM2_IRQ_ENABLE_PORT, &read_ctrl_port, &write_ctrl_port);
581 v3_dev_hook_io(dev, COM2_FIFO_CTRL_PORT, &read_ctrl_port, &write_ctrl_port);
582 v3_dev_hook_io(dev, COM2_LINE_CTRL_PORT, &read_ctrl_port, &write_ctrl_port);
583 v3_dev_hook_io(dev, COM2_MODEM_CTRL_PORT, &read_ctrl_port, &write_ctrl_port);
584 v3_dev_hook_io(dev, COM2_LINE_STATUS_PORT, &read_status_port, &write_status_port);
585 v3_dev_hook_io(dev, COM2_MODEM_STATUS_PORT, &read_status_port, &write_status_port);
586 v3_dev_hook_io(dev, COM2_SCRATCH_PORT, &read_ctrl_port, &write_ctrl_port);
588 v3_dev_hook_io(dev, COM3_DATA_PORT, &read_data_port, &write_data_port);
589 v3_dev_hook_io(dev, COM3_IRQ_ENABLE_PORT, &read_ctrl_port, &write_ctrl_port);
590 v3_dev_hook_io(dev, COM3_FIFO_CTRL_PORT, &read_ctrl_port, &write_ctrl_port);
591 v3_dev_hook_io(dev, COM3_LINE_CTRL_PORT, &read_ctrl_port, &write_ctrl_port);
592 v3_dev_hook_io(dev, COM3_MODEM_CTRL_PORT, &read_ctrl_port, &write_ctrl_port);
593 v3_dev_hook_io(dev, COM3_LINE_STATUS_PORT, &read_status_port, &write_status_port);
594 v3_dev_hook_io(dev, COM3_MODEM_STATUS_PORT, &read_status_port, &write_status_port);
595 v3_dev_hook_io(dev, COM3_SCRATCH_PORT, &read_ctrl_port, &write_ctrl_port);
597 v3_dev_hook_io(dev, COM4_DATA_PORT, &read_data_port, &write_data_port);
598 v3_dev_hook_io(dev, COM4_IRQ_ENABLE_PORT, &read_ctrl_port, &write_ctrl_port);
599 v3_dev_hook_io(dev, COM4_FIFO_CTRL_PORT, &read_ctrl_port, &write_ctrl_port);
600 v3_dev_hook_io(dev, COM4_LINE_CTRL_PORT, &read_ctrl_port, &write_ctrl_port);
601 v3_dev_hook_io(dev, COM4_MODEM_CTRL_PORT, &read_ctrl_port, &write_ctrl_port);
602 v3_dev_hook_io(dev, COM4_LINE_STATUS_PORT, &read_status_port, &write_status_port);
603 v3_dev_hook_io(dev, COM4_MODEM_STATUS_PORT, &read_status_port, &write_status_port);
604 v3_dev_hook_io(dev, COM4_SCRATCH_PORT, &read_ctrl_port, &write_ctrl_port);
610 device_register("SERIAL", serial_init)