Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


change to device configuration syntax
[palacios.git] / palacios / src / devices / serial.c
1 /*
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.
5  *
6  * The V3VEE Project is a joint project between Northwestern University
7  * and the University of New Mexico.  You can find out more at
8  * http://www.v3vee.org
9  *
10  * Copyright (c) 2010, Rumou Duan <duanrumou@gmail.com>
11  * Copyright (c) 2010, The V3VEE Project <http://www.v3vee.org>
12  * All rights reserved.
13  *
14  * Author: Rumou Duan <duanrumou@gmail.com>
15  *
16  * This is free software.  You are permitted to use,
17  * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
18  */
19
20
21 #include <palacios/vmm.h>
22 #include <palacios/vmm_dev_mgr.h>
23 #include <palacios/vmm_types.h>
24
25 #include <palacios/vmm_ringbuffer.h>
26 #include <palacios/vmm_lock.h>
27 #include <palacios/vmm_intr.h>
28 #include <palacios/vmm_host_events.h>
29 #include <palacios/vm_guest.h>
30
31
32 #define COM1_DATA_PORT           0x3f8
33 #define COM1_IRQ_ENABLE_PORT     0x3f9
34 #define COM1_DIV_LATCH_LSB_PORT  0x3f8
35 #define COM1_DIV_LATCH_MSB_PORT  0x3f9
36 #define COM1_IIR_PORT            0x3fa
37 #define COM1_FIFO_CTRL_PORT      0x3fa
38 #define COM1_LINE_CTRL_PORT      0x3fb
39 #define COM1_MODEM_CTRL_PORT     0x3fc
40 #define COM1_LINE_STATUS_PORT    0x3fd
41 #define COM1_MODEM_STATUS_PORT   0x3fe
42 #define COM1_SCRATCH_PORT        0x3ff
43
44 #define COM2_DATA_PORT           0x2f8
45 #define COM2_IRQ_ENABLE_PORT     0x2f9
46 #define COM2_DIV_LATCH_LSB_PORT  0x2f8
47 #define COM2_DIV_LATCH_MSB_PORT  0x2f9
48 #define COM2_IIR_PORT            0x2fa
49 #define COM2_FIFO_CTRL_PORT      0x2fa
50 #define COM2_LINE_CTRL_PORT      0x2fb
51 #define COM2_MODEM_CTRL_PORT     0x2fc
52 #define COM2_LINE_STATUS_PORT    0x2fd
53 #define COM2_MODEM_STATUS_PORT   0x2fe
54 #define COM2_SCRATCH_PORT        0x2ff
55
56 #define COM3_DATA_PORT           0x3e8
57 #define COM3_IRQ_ENABLE_PORT     0x3e9
58 #define COM3_DIV_LATCH_LSB_PORT  0x3e8
59 #define COM3_DIV_LATCH_MSB_PORT  0x3e9
60 #define COM3_IIR_PORT            0x3ea
61 #define COM3_FIFO_CTRL_PORT      0x3ea
62 #define COM3_LINE_CTRL_PORT      0x3eb
63 #define COM3_MODEM_CTRL_PORT     0x3ec
64 #define COM3_LINE_STATUS_PORT    0x3ed
65 #define COM3_MODEM_STATUS_PORT   0x3ee
66 #define COM3_SCRATCH_PORT        0x3ef
67
68 #define COM4_DATA_PORT           0x2e8
69 #define COM4_IRQ_ENABLE_PORT     0x2e9
70 #define COM4_DIV_LATCH_LSB_PORT  0x2e8
71 #define COM4_DIV_LATCH_MSB_PORT  0x2e9
72 #define COM4_IIR_PORT            0x2ea
73 #define COM4_FIFO_CTRL_PORT      0x2ea
74 #define COM4_LINE_CTRL_PORT      0x2eb
75 #define COM4_MODEM_CTRL_PORT     0x2ec
76 #define COM4_LINE_STATUS_PORT    0x2ed
77 #define COM4_MODEM_STATUS_PORT   0x2ee
78 #define COM4_SCRATCH_PORT        0x2ef
79
80
81 // Interrupt IDs (in priority order, highest is first)
82 #define STATUS_IRQ_LSR_OE_SET   0x3
83 #define STATUS_IRQ_LSR_PE_SET   0x3
84 #define STATUS_IRQ_LSR_FE_SET   0x3
85 #define STATUS_IRQ_LSR_BI_SET   0x3
86 #define RX_IRQ_DR               0x2
87 #define RX_IRQ_TRIGGER_LEVEL    0x2
88 #define FIFO_IRQ                0x6
89 #define TX_IRQ_THRE             0x1
90 #define MODEL_IRQ_DELTA_SET     0x0
91
92 //COMs IRQ ID
93 #define COM1_IRQ  0x4
94 #define COM2_IRQ  0x3
95 #define COM3_IRQ  0x4
96 #define COM4_IRQ  0x3
97
98 #define RX_BUFFER 0x1
99 #define TX_BUFFER 0x2
100
101 //initial value for registers
102
103 #define  IER_INIT_VAL 0x3
104 //receive data available interrupt and THRE interrupt are enabled
105 #define  IIR_INIT_VAL 0x1
106 //No Pending Interrupt bit is set.
107 #define  FCR_INIT_VAL 0xc0
108 //fifo control register is set to 0
109 #define  LCR_INIT_VAL 0x3
110 #define  MCR_INIT_VAL 0x0
111 #define  LSR_INIT_VAL 0x60
112 #define  MSR_INIT_VAL 0x0
113 #define  DLL_INIT_VAL 0x1
114 #define  DLM_INIT_VAL 0x0
115
116
117
118 //receiver buffer register
119 struct rbr_register {
120     uint8_t data;
121 };
122
123 // transmitter holding register
124 struct thr_register {
125     uint8_t data;
126 };
127
128 //interrupt enable register
129 struct ier_register {
130     union {
131         uint8_t val;
132         struct {
133             uint8_t erbfi   : 1;   // Enable Receiver Buffer full interrupt
134             uint8_t etbei   : 1;  // Enable Transmit buffer empty interrupt
135             uint8_t elsi    : 1;  // Enable Line Status Interrupt
136             uint8_t edssi   : 1;  // Enable Delta Status signals interrupt
137             uint8_t rsvd    : 4;   // MBZ
138         } __attribute__((packed));
139     } __attribute__((packed));
140 } __attribute__((packed));
141
142
143 //interrupt identification register
144 struct iir_register {
145     union {
146         uint8_t val;
147         struct {
148             uint8_t pending : 1; // Interrupt pending (0=interrupt pending)
149             uint8_t iid     : 3; // Interrupt Identification
150             uint8_t rsvd    : 2; // MBZ
151             uint8_t fifo_en : 2; // FIFO enable
152         } __attribute__((packed));
153     } __attribute__((packed));
154 } __attribute__((packed));
155
156 //FIFO control register
157 struct fcr_register {
158     union {
159         uint8_t val;
160         struct {
161             uint8_t enable  : 1; // enable fifo
162             uint8_t rfres   : 1; // RX FIFO reset
163             uint8_t xfres   : 1; // TX FIFO reset
164             uint8_t dma_sel : 1; // DMA mode select
165             uint8_t rsvd    : 2; // MBZ
166             uint8_t rx_trigger: 2; // RX FIFO trigger level select
167         } __attribute__((packed));
168     } __attribute__((packed));
169 } __attribute__((packed));
170
171
172 //line control register
173 struct lcr_register {
174     union {
175         uint8_t val;
176         struct {
177             uint8_t word_len       : 2;  // word length select
178             uint8_t stop_bits      : 1;  // Stop Bit select
179             uint8_t parity_enable  : 1;  // Enable parity
180             uint8_t even_sel       : 1;  // Even Parity Select
181             uint8_t stick_parity   : 1;  // Stick Parity Select
182             uint8_t sbr            : 1;  // Set Break
183             uint8_t dlab           : 1;  // Divisor latch access bit
184         } __attribute__((packed));
185     } __attribute__((packed));
186 } __attribute__((packed));
187
188
189 //modem control register
190 struct mcr_register {
191     union {
192         uint8_t val;
193         struct {
194             uint8_t dtr      : 1;
195             uint8_t rts      : 1;
196             uint8_t out1     : 1;
197             uint8_t out2     : 1;
198             uint8_t loop     : 1;  // loopback mode
199             uint8_t rsvd     : 3;  // MBZ
200         } __attribute__((packed));
201     } __attribute__((packed));
202 } __attribute__((packed));
203
204
205 //line status register
206 struct lsr_register {
207     union {
208         uint8_t val;
209         struct {
210             uint8_t dr      : 1;  // data ready
211             uint8_t oe       : 1;  // Overrun error
212             uint8_t pe       : 1;  // Parity Error
213             uint8_t fe       : 1;  // Framing Error
214             uint8_t brk      : 1;  // broken line detected
215             uint8_t thre     : 1;  // Transmitter holding register empty
216             uint8_t temt     : 1;  // Transmitter Empty
217             uint8_t fifo_err : 1;  // at least one error is pending in the RX FIFO chain
218         } __attribute__((packed));
219     } __attribute__((packed));
220 } __attribute__((packed));
221
222
223 struct msr_register {
224     union {
225         uint8_t val;
226         struct {
227             uint8_t dcts     : 1;  // Delta Clear To Send
228             uint8_t ddsr     : 1;  // Delta Data Set Ready
229             uint8_t teri     : 1;  // Trailing Edge Ring Indicator
230             uint8_t ddcd     : 1;  // Delta Data Carrier Detect
231             uint8_t cts      : 1;  // Clear to Send
232             uint8_t dsr      : 1;  // Data Set Ready
233             uint8_t ri       : 1;  // Ring Indicator
234             uint8_t dcd      : 1;  // Data Carrier Detect
235         } __attribute__((packed));
236     } __attribute__((packed));
237 } __attribute__((packed));
238
239 //scratch register
240 struct scr_register {
241     uint8_t data;
242 };
243
244 //divisor latch LSB
245 struct dll_register {
246     uint8_t data;
247 };
248
249 //divisor latch MSB
250 struct dlm_register {
251     uint8_t data;
252 };
253 #define SERIAL_BUF_LEN 16
254
255 struct serial_buffer {
256     int head; // most recent data
257     int tail; // oldest char
258     int full;
259     uint8_t buffer[SERIAL_BUF_LEN];
260 };
261
262 struct serial_port {
263     struct rbr_register     rbr;
264     struct thr_register     thr;
265     struct ier_register     ier;
266     struct iir_register     iir;
267     struct fcr_register     fcr;
268     struct lcr_register     lcr;
269     struct mcr_register     mcr;
270     struct lsr_register     lsr;
271     struct msr_register     msr;
272     struct scr_register     scr;
273     struct dll_register     dll;
274     struct dlm_register     dlm;
275     
276     
277     struct serial_buffer tx_buffer;
278     struct serial_buffer rx_buffer;
279     uint_t irq_number;
280 };
281
282
283 struct serial_state {
284     struct serial_port com1;
285     struct serial_port com2;
286     struct serial_port com3;
287     struct serial_port com4;
288 };
289
290
291
292 static struct serial_port * get_com_from_port(struct serial_state * serial, uint16_t port) {
293     if ((port >= COM1_DATA_PORT) && (port <= COM1_SCRATCH_PORT)) {
294         return &(serial->com1);
295     } else if ((port >= COM2_DATA_PORT) && (port <= COM2_SCRATCH_PORT)) {
296         return &(serial->com2);
297     } else if ((port >= COM3_DATA_PORT) && (port <= COM3_SCRATCH_PORT)) {
298         return &(serial->com3);
299     } else if ((port >= COM4_DATA_PORT) && (port <= COM4_SCRATCH_PORT)) {
300         return &(serial->com4);
301     } else {
302         PrintError("Error: Could not find serial port associated with IO port %d\n", port);
303         return NULL;
304     }
305 }
306
307 static inline bool receive_buffer_trigger(int number, int trigger_number) {
308
309     switch (trigger_number) {
310         case 0:
311             return (number >= 1);
312         case 1:
313             return (number >= 4);
314         case 2:
315             return (number >= 8);
316         case 3:
317             return (number >= 14);
318     }
319
320     return false;
321 }
322
323 static int getNumber(struct serial_buffer * buf) {
324     int number = buf->head - buf->tail;
325   
326     if (buf->full == 1) {
327         return SERIAL_BUF_LEN;
328     } else if (number >= 0) {
329         return number;
330     } else {
331         return SERIAL_BUF_LEN + number;
332     }
333 }
334
335 static int updateIRQ(struct serial_port * com, struct vm_device * dev) {
336     
337     if ( (com->ier.erbfi == 0x1) && 
338          (receive_buffer_trigger( getNumber(&(com->rx_buffer)), com->fcr.rx_trigger)) ) {
339
340         PrintDebug("UART: receive buffer interrupt(trigger level reached)");
341
342         com->iir.iid = RX_IRQ_TRIGGER_LEVEL;
343         v3_raise_irq(dev->vm, com->irq_number);
344     }
345     
346     if ( (com->iir.iid == RX_IRQ_TRIGGER_LEVEL) && 
347          (!(receive_buffer_trigger( getNumber(&(com->rx_buffer)), com->fcr.rx_trigger))) ) {
348
349         com->iir.iid = 0x0;   //reset interrupt identification register
350         com->iir.pending = 0x1;
351     }
352     
353     if ( (com->iir.iid == TX_IRQ_THRE) && 
354          (getNumber(&(com->tx_buffer)) == SERIAL_BUF_LEN)) {
355
356         com->iir.iid = 0x0; //reset interrupt identification register
357         com->iir.pending = 0x1;
358
359     } else if ( (com->ier.etbei == 0x1) && 
360                 (getNumber(&(com->tx_buffer)) != SERIAL_BUF_LEN )) {
361         
362         PrintDebug("UART: transmit buffer interrupt(buffer not full)");
363
364         com->iir.iid = TX_IRQ_THRE;
365         com->iir.pending = 0;
366
367         v3_raise_irq(dev->vm, com->irq_number);
368     }
369
370     return 1;
371 }
372
373
374 static int queue_data(struct serial_buffer * buf, uint8_t  data, 
375                       struct serial_port * com, struct vm_device * dev) {
376
377     int next_loc = (buf->head + 1) % SERIAL_BUF_LEN;    
378
379     if (buf->full == 1) {
380         PrintDebug("Buffer is full!\n");
381
382         if (buf == &(com->rx_buffer)) {
383             com->lsr.oe = 1; //overrun error bit set
384         }
385
386         return 0;
387     }
388     
389     buf->buffer[next_loc] = data;
390     buf->head = next_loc;
391     
392     if (buf->head == buf->tail) {
393         buf->full = 1;
394     }
395     
396     if (buf == &(com->rx_buffer)) {
397         com->lsr.dr = 1; //as soon as new data arrives at receive buffer, set data ready bit in lsr.
398     }
399     
400     if (buf == &(com->tx_buffer)) {
401         com->lsr.thre = 0; //reset thre and temt bits.
402         com->lsr.temt = 0;
403     }
404     
405     updateIRQ(com, dev);
406     
407     return 0;
408 }
409
410 static int dequeue_data(struct serial_buffer * buf, uint8_t * data, 
411                         struct serial_port * com, struct vm_device * dev) {
412
413     int next_tail = (buf->tail + 1) % SERIAL_BUF_LEN;
414
415
416     if ( (buf->head == buf->tail) && (buf->full != 1) ) {
417         PrintDebug("no data to delete!\n");
418         return -1;
419     }
420     
421     if (buf->full == 1) {
422         buf->full = 0;
423     }
424     
425         
426     *data = buf->buffer[next_tail];
427     buf->buffer[next_tail] = 0;
428     buf->tail = next_tail;
429     
430     if ( (buf == &(com->rx_buffer)) && (getNumber(&(com->rx_buffer)) == 0) ) {
431         com->lsr.dr = 0;
432     }
433     
434     if ((buf == &(com->tx_buffer)) && (getNumber(&(com->tx_buffer)) == 0)) {
435         com->lsr.thre = 1;
436         com->lsr.temt = 1;
437     }
438     
439     updateIRQ(com, dev);
440     
441     return 0;
442 }
443
444 /*
445 static void printBuffer(struct serial_buffer * buf) {
446     int i = 0;
447
448     for (i = 0; i < SERIAL_BUF_LEN; i++) {
449         PrintDebug(" %d ", buf->buffer[i]);
450     }
451
452     PrintDebug("\n the number of elements is %d \n", getNumber(buf));
453 }
454 */
455
456 //note: write to data port is NOT implemented and corresponding codes are commented out
457 static int write_data_port(struct guest_info * core, uint16_t port, 
458                            void * src, uint_t length, struct vm_device * dev) {
459     struct serial_state * state = (struct serial_state *)dev->private_data;
460     uint8_t * val = (uint8_t *)src;
461     struct serial_port * com_port = NULL;
462
463     PrintDebug("Write to Data Port 0x%x (val=%x)\n", port, *val);
464     
465     if (length != 1) {
466         PrintDebug("Invalid length(%d) in write to 0x%x\n", length, port);
467         return -1;
468     }
469
470     if ((port != COM1_DATA_PORT) && (port != COM2_DATA_PORT) && 
471         (port != COM3_DATA_PORT) && (port != COM4_DATA_PORT)) {
472         PrintError("Serial Read data port for illegal port Number (%d)\n", port);
473         return -1;
474     }
475
476     com_port = get_com_from_port(state, port);
477
478     if (com_port == NULL) {
479         PrintDebug("UART:read from NOBODY");
480         return -1;
481     }
482     
483
484     // dlab is always checked first
485     if (com_port->lcr.dlab == 1) {
486         com_port->dll.data = *val;
487     }  else {
488         queue_data(&(com_port->tx_buffer), *val, com_port, dev);
489     }
490     
491     
492     return length;
493 }
494
495
496
497 static int read_data_port(struct guest_info * core, uint16_t port, 
498                           void * dst, uint_t length, struct vm_device * dev) {
499     struct serial_state * state = (struct serial_state *)dev->private_data;
500     uint8_t * val = (uint8_t *)dst;
501     struct serial_port * com_port = NULL;
502
503     PrintDebug("Read from Data Port 0x%x\n", port);
504     
505     if (length != 1) {
506         PrintDebug("Invalid length(%d) in write to 0x%x\n", length, port);
507         return -1;
508     }
509     
510     if ((port != COM1_DATA_PORT) && (port != COM2_DATA_PORT) && 
511         (port != COM3_DATA_PORT) && (port != COM4_DATA_PORT)) {
512         PrintError("Serial Read data port for illegal port Number (%d)\n", port);
513         return -1;
514     }
515
516     com_port = get_com_from_port(state, port);
517
518     if (com_port == NULL) {
519         PrintDebug("UART:read from NOBODY");
520         return -1;
521     }
522     
523     if (com_port->lcr.dlab == 1) {
524         *val = com_port->dll.data;
525     } else {
526         dequeue_data(&(com_port->rx_buffer), val, com_port, dev);
527     }
528     
529     return length;
530 }
531
532
533
534 static int handle_fcr_write(struct serial_port * com, uint8_t value) {
535
536     com->fcr.enable = value & 0x1;
537     
538     if (com->fcr.enable == 0x1) {
539         com->fcr.val = value;
540
541         com->fcr.enable = 1; // Do we need to set this??
542
543         //if rfres set, clear receive buffer.
544         if (com->fcr.rfres == 0x1) {
545             com->rx_buffer.head = 0;
546             com->rx_buffer.tail = 0;
547             com->rx_buffer.full = 0;
548             memset(com->rx_buffer.buffer, 0, SERIAL_BUF_LEN);
549             com->fcr.rfres = 0;
550         }
551
552         //if xfres set, clear transmit buffer.
553         if (com->fcr.xfres == 0x1) {
554             com->tx_buffer.head = 0;
555             com->tx_buffer.tail = 0;
556             com->tx_buffer.full = 0;
557             memset(com->tx_buffer.buffer, 0, SERIAL_BUF_LEN);
558             com->fcr.xfres = 0;
559         }
560     } else {
561         //clear both buffers.
562         com->tx_buffer.head = 0;
563         com->tx_buffer.tail = 0;
564         com->tx_buffer.full = 0;
565         com->rx_buffer.head = 0;
566         com->rx_buffer.tail = 0;
567         com->rx_buffer.full = 0;
568         
569         memset(com->rx_buffer.buffer, 0, SERIAL_BUF_LEN);
570         memset(com->tx_buffer.buffer, 0, SERIAL_BUF_LEN);
571     }
572     
573     return 1;
574 }
575
576
577
578
579
580 static int write_ctrl_port(struct guest_info * core, uint16_t port, void * src, 
581                            uint_t length, struct vm_device * dev) {
582     struct serial_state * state = (struct serial_state *)dev->private_data;
583     uint8_t val = *(uint8_t *)src;
584     struct serial_port * com_port = NULL;
585
586     PrintDebug("UART:Write to Control Port (val=%x)\n", val);
587     
588     if (length != 1) {
589         PrintDebug("UART:Invalid Write length to control port%d\n", port);
590         return -1;
591     }
592
593     com_port = get_com_from_port(state, port);
594
595     if (com_port == NULL) {
596         PrintError("Could not find serial port corresponding to IO port %d\n", port);
597         return -1;
598     }
599     
600     //always check dlab first
601     switch (port) {
602         case COM1_IRQ_ENABLE_PORT:
603         case COM2_IRQ_ENABLE_PORT:
604         case COM3_IRQ_ENABLE_PORT:
605         case COM4_IRQ_ENABLE_PORT: {
606             PrintDebug("UART:Write to IER/LATCH port: dlab is %x\n", com_port->lcr.dlab);
607
608             if (com_port->lcr.dlab == 1) {
609                 com_port->dlm.data = val;
610             } else {
611                 com_port->ier.val = val;
612             }
613
614             break;
615         }           
616         case COM1_FIFO_CTRL_PORT:
617         case COM2_FIFO_CTRL_PORT:
618         case COM3_FIFO_CTRL_PORT:
619         case COM4_FIFO_CTRL_PORT: {
620             PrintDebug("UART:Write to FCR");
621
622             if (handle_fcr_write(com_port, val) == -1) {
623                 return -1;
624             }
625
626             break;
627         }
628         case COM1_LINE_CTRL_PORT:
629         case COM2_LINE_CTRL_PORT:
630         case COM3_LINE_CTRL_PORT:
631         case COM4_LINE_CTRL_PORT: {
632             PrintDebug("UART:Write to LCR");
633             com_port->lcr.val = val;
634             break;
635         }
636         case COM1_MODEM_CTRL_PORT:
637         case COM2_MODEM_CTRL_PORT:
638         case COM3_MODEM_CTRL_PORT:
639         case COM4_MODEM_CTRL_PORT: {
640             PrintDebug("UART:Write to MCR");
641             com_port->mcr.val = val;
642             break;
643         }
644         case COM1_SCRATCH_PORT:
645         case COM2_SCRATCH_PORT:
646         case COM3_SCRATCH_PORT:
647         case COM4_SCRATCH_PORT: {
648             PrintDebug("UART:Write to SCRATCH");
649             com_port->scr.data = val;
650             break;
651         }
652         default:
653             PrintDebug("UART:Write to NOBODY, ERROR");
654             return -1;
655     }
656     
657
658     return length;
659 }
660
661
662
663
664 static int read_ctrl_port(struct guest_info * core, uint16_t port, void * dst, 
665                           uint_t length, struct vm_device * dev) {
666     struct serial_state * state = (struct serial_state *)dev->private_data;
667     uint8_t * val = (uint8_t *)dst;
668     struct serial_port * com_port = NULL;
669
670     PrintDebug("Read from Control Port\n");
671     
672     if (length != 1) {
673         PrintDebug("Invalid Read length to control port\n");
674         return -1;
675     }
676
677     com_port = get_com_from_port(state, port);
678
679     if (com_port == NULL) {
680         PrintError("Could not find serial port corresponding to IO port %d\n", port);
681         return -1;
682     }
683     
684     //always check dlab first
685     switch (port) {
686         case COM1_IRQ_ENABLE_PORT:
687         case COM2_IRQ_ENABLE_PORT:
688         case COM3_IRQ_ENABLE_PORT:
689         case COM4_IRQ_ENABLE_PORT: {
690             PrintDebug("UART:read from IER");
691
692             if (com_port->lcr.dlab == 1) {
693                 *val = com_port->dlm.data;
694             } else {
695                 *val = com_port->ier.val;
696             }
697             break;
698         }
699
700         case COM1_FIFO_CTRL_PORT:
701         case COM2_FIFO_CTRL_PORT:
702         case COM3_FIFO_CTRL_PORT:
703         case COM4_FIFO_CTRL_PORT:
704             PrintDebug("UART:read from FCR");
705             *val = com_port->fcr.val;
706             break;
707
708         case COM1_LINE_CTRL_PORT:
709         case COM2_LINE_CTRL_PORT:
710         case COM3_LINE_CTRL_PORT:
711         case COM4_LINE_CTRL_PORT:
712             PrintDebug("UART:read from LCR");
713             *val = com_port->lcr.val;
714             break;
715
716         case COM1_MODEM_CTRL_PORT:
717         case COM2_MODEM_CTRL_PORT:
718         case COM3_MODEM_CTRL_PORT:
719         case COM4_MODEM_CTRL_PORT:
720             PrintDebug("UART:read from MCR");
721             *val = com_port->mcr.val;
722             break;
723
724         case COM1_SCRATCH_PORT:
725         case COM2_SCRATCH_PORT:
726         case COM3_SCRATCH_PORT:
727         case COM4_SCRATCH_PORT:
728             PrintDebug("UART:read from SCRATCH");
729             *val = com_port->scr.data;
730             break;
731
732         default:
733             PrintDebug("UART:read from NOBODY");
734             return -1;
735     }
736
737     return length;
738 }
739
740
741 static int write_status_port(struct guest_info * core, uint16_t port, void * src, 
742                              uint_t length, struct vm_device * dev) {
743     struct serial_state * state = (struct serial_state *)dev->private_data;
744     uint8_t val = *(uint8_t *)src;
745     struct serial_port * com_port = NULL;
746
747     PrintDebug("Write to Status Port (val=%x)\n", val);
748
749     if (length != 1) {
750         PrintDebug("Invalid Write length to status port %d\n", port);
751         return -1;
752     }
753
754     com_port = get_com_from_port(state, port);
755
756     if (com_port == NULL) {
757         PrintError("Could not find serial port corresponding to IO port %d\n", port);
758         return -1;
759     }
760
761     switch (port) {
762         case COM1_LINE_STATUS_PORT:
763         case COM2_LINE_STATUS_PORT:
764         case COM3_LINE_STATUS_PORT:
765         case COM4_LINE_STATUS_PORT:
766             PrintDebug("UART:write to LSR");
767             com_port->lsr.val = val;
768             break;
769
770         case COM1_MODEM_STATUS_PORT:
771         case COM2_MODEM_STATUS_PORT:
772         case COM3_MODEM_STATUS_PORT:
773         case COM4_MODEM_STATUS_PORT:
774             PrintDebug("UART:write to MSR");
775             com_port->msr.val = val;
776             break;
777
778         default:
779             PrintDebug("UART:write to NOBODY");
780             return -1;
781     }
782
783     return length;
784 }
785
786 static int read_status_port(struct guest_info * core, uint16_t port, void * dst, 
787                             uint_t length, struct vm_device * dev) {
788     struct serial_state * state = (struct serial_state *)dev->private_data;
789     uint8_t * val = (uint8_t *)dst;
790     struct serial_port * com_port = NULL;
791
792     PrintDebug("Read from Status Port 0x%x\n", port);
793
794     if (length != 1) {
795         PrintDebug("Invalid Read length to control port\n");
796         return -1;
797     }
798
799     com_port = get_com_from_port(state, port);
800
801     if (com_port == NULL) {
802         PrintError("Could not find serial port corresponding to IO port %d\n", port);
803         return -1;
804     }
805
806     switch (port) {
807         case COM1_LINE_STATUS_PORT:
808         case COM2_LINE_STATUS_PORT:
809         case COM3_LINE_STATUS_PORT:
810         case COM4_LINE_STATUS_PORT:
811             PrintDebug("UART:read from LSR");
812
813             *val = com_port->lsr.val;
814             com_port->lsr.oe = 0;     // Why do we clear this??
815
816             break;
817
818         case COM1_MODEM_STATUS_PORT:
819         case COM2_MODEM_STATUS_PORT:
820         case COM3_MODEM_STATUS_PORT:
821         case COM4_MODEM_STATUS_PORT:
822             PrintDebug("UART:read from COM4 MSR");
823             *val = com_port->msr.val;
824             break;
825
826         default:
827             PrintDebug("UART:read from NOBODY");
828             return -1;
829     }
830
831     return length;
832 }
833
834 static int serial_deinit(struct vm_device * dev) {
835
836
837     v3_dev_unhook_io(dev, COM1_DATA_PORT);
838     v3_dev_unhook_io(dev, COM1_IRQ_ENABLE_PORT);
839     v3_dev_unhook_io(dev, COM1_FIFO_CTRL_PORT);
840     v3_dev_unhook_io(dev, COM1_LINE_CTRL_PORT);
841     v3_dev_unhook_io(dev, COM1_MODEM_CTRL_PORT);
842     v3_dev_unhook_io(dev, COM1_LINE_STATUS_PORT);
843     v3_dev_unhook_io(dev, COM1_MODEM_STATUS_PORT);
844     v3_dev_unhook_io(dev, COM1_SCRATCH_PORT);
845
846     v3_dev_unhook_io(dev, COM2_DATA_PORT);
847     v3_dev_unhook_io(dev, COM2_IRQ_ENABLE_PORT);
848     v3_dev_unhook_io(dev, COM2_FIFO_CTRL_PORT);
849     v3_dev_unhook_io(dev, COM2_LINE_CTRL_PORT);
850     v3_dev_unhook_io(dev, COM2_MODEM_CTRL_PORT);
851     v3_dev_unhook_io(dev, COM2_LINE_STATUS_PORT);
852     v3_dev_unhook_io(dev, COM2_MODEM_STATUS_PORT);
853     v3_dev_unhook_io(dev, COM2_SCRATCH_PORT);
854
855     v3_dev_unhook_io(dev, COM3_DATA_PORT);
856     v3_dev_unhook_io(dev, COM3_IRQ_ENABLE_PORT);
857     v3_dev_unhook_io(dev, COM3_FIFO_CTRL_PORT);
858     v3_dev_unhook_io(dev, COM3_LINE_CTRL_PORT);
859     v3_dev_unhook_io(dev, COM3_MODEM_CTRL_PORT);
860     v3_dev_unhook_io(dev, COM3_LINE_STATUS_PORT);
861     v3_dev_unhook_io(dev, COM3_MODEM_STATUS_PORT);
862     v3_dev_unhook_io(dev, COM3_SCRATCH_PORT);
863
864     v3_dev_unhook_io(dev, COM4_DATA_PORT);
865     v3_dev_unhook_io(dev, COM4_IRQ_ENABLE_PORT);
866     v3_dev_unhook_io(dev, COM4_FIFO_CTRL_PORT);
867     v3_dev_unhook_io(dev, COM4_LINE_CTRL_PORT);
868     v3_dev_unhook_io(dev, COM4_MODEM_CTRL_PORT);
869     v3_dev_unhook_io(dev, COM4_LINE_STATUS_PORT);
870     v3_dev_unhook_io(dev, COM4_MODEM_STATUS_PORT);
871     v3_dev_unhook_io(dev, COM4_SCRATCH_PORT);
872
873     return 0;
874 }
875
876
877
878
879 static struct v3_device_ops dev_ops = {
880     //.init = serial_init,
881     .free = serial_deinit,
882     .reset = NULL,
883     .start = NULL,
884     .stop = NULL,
885 };
886
887
888
889 static int init_serial_port(struct serial_port * com) {
890
891     com->ier.val = IER_INIT_VAL;
892     com->iir.val = IIR_INIT_VAL;
893     com->fcr.val = FCR_INIT_VAL;
894     com->lcr.val = LCR_INIT_VAL;
895     com->mcr.val = MCR_INIT_VAL;
896     com->lsr.val = LSR_INIT_VAL;
897     com->msr.val = MSR_INIT_VAL;
898
899     com->dll.data =  DLL_INIT_VAL;
900     com->dlm.data =  DLM_INIT_VAL;
901     
902     com->tx_buffer.head = 0;
903     com->tx_buffer.tail = 0;
904     com->tx_buffer.full = 0;
905     memset(com->tx_buffer.buffer, 0, SERIAL_BUF_LEN);
906
907     com->rx_buffer.head = 0;
908     com->rx_buffer.tail = 0;
909     com->rx_buffer.full = 0;
910     memset(com->rx_buffer.buffer, 0, SERIAL_BUF_LEN);
911     
912     return 0;
913 }
914
915 static int serial_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
916     struct serial_state * state = (struct serial_state *)V3_Malloc(sizeof(struct serial_state));
917     char * dev_id = v3_cfg_val(cfg, "ID");
918
919     PrintDebug("UART: init_device\n");
920     init_serial_port(&(state->com1));
921     init_serial_port(&(state->com2));
922     init_serial_port(&(state->com3));
923     init_serial_port(&(state->com4));
924
925     state->com1.irq_number = COM1_IRQ;
926     state->com2.irq_number = COM2_IRQ;
927     state->com3.irq_number = COM3_IRQ;
928     state->com4.irq_number = COM4_IRQ;
929
930
931     struct vm_device * dev = v3_allocate_device(dev_id, &dev_ops, state);
932
933     if (v3_attach_device(vm, dev) == -1) {
934         PrintError("Could not attach device %s\n", dev_id);
935         return -1;
936     }
937
938     v3_dev_hook_io(dev, COM1_DATA_PORT, &read_data_port, &write_data_port);
939     v3_dev_hook_io(dev, COM1_IRQ_ENABLE_PORT, &read_ctrl_port, &write_ctrl_port);
940     v3_dev_hook_io(dev, COM1_FIFO_CTRL_PORT, &read_ctrl_port, &write_ctrl_port);
941     v3_dev_hook_io(dev, COM1_LINE_CTRL_PORT, &read_ctrl_port, &write_ctrl_port);
942     v3_dev_hook_io(dev, COM1_MODEM_CTRL_PORT, &read_ctrl_port, &write_ctrl_port);
943     v3_dev_hook_io(dev, COM1_LINE_STATUS_PORT, &read_status_port, &write_status_port);
944     v3_dev_hook_io(dev, COM1_MODEM_STATUS_PORT, &read_status_port, &write_status_port);
945     v3_dev_hook_io(dev, COM1_SCRATCH_PORT, &read_ctrl_port, &write_ctrl_port);
946
947     v3_dev_hook_io(dev, COM2_DATA_PORT, &read_data_port, &write_data_port);
948     v3_dev_hook_io(dev, COM2_IRQ_ENABLE_PORT, &read_ctrl_port, &write_ctrl_port);
949     v3_dev_hook_io(dev, COM2_FIFO_CTRL_PORT, &read_ctrl_port, &write_ctrl_port);
950     v3_dev_hook_io(dev, COM2_LINE_CTRL_PORT, &read_ctrl_port, &write_ctrl_port);
951     v3_dev_hook_io(dev, COM2_MODEM_CTRL_PORT, &read_ctrl_port, &write_ctrl_port);
952     v3_dev_hook_io(dev, COM2_LINE_STATUS_PORT, &read_status_port, &write_status_port);
953     v3_dev_hook_io(dev, COM2_MODEM_STATUS_PORT, &read_status_port, &write_status_port);
954     v3_dev_hook_io(dev, COM2_SCRATCH_PORT, &read_ctrl_port, &write_ctrl_port);
955
956     v3_dev_hook_io(dev, COM3_DATA_PORT, &read_data_port, &write_data_port);
957     v3_dev_hook_io(dev, COM3_IRQ_ENABLE_PORT, &read_ctrl_port, &write_ctrl_port);
958     v3_dev_hook_io(dev, COM3_FIFO_CTRL_PORT, &read_ctrl_port, &write_ctrl_port);
959     v3_dev_hook_io(dev, COM3_LINE_CTRL_PORT, &read_ctrl_port, &write_ctrl_port);
960     v3_dev_hook_io(dev, COM3_MODEM_CTRL_PORT, &read_ctrl_port, &write_ctrl_port);
961     v3_dev_hook_io(dev, COM3_LINE_STATUS_PORT, &read_status_port, &write_status_port);
962     v3_dev_hook_io(dev, COM3_MODEM_STATUS_PORT, &read_status_port, &write_status_port);
963     v3_dev_hook_io(dev, COM3_SCRATCH_PORT, &read_ctrl_port, &write_ctrl_port);
964
965     v3_dev_hook_io(dev, COM4_DATA_PORT, &read_data_port, &write_data_port);
966     v3_dev_hook_io(dev, COM4_IRQ_ENABLE_PORT, &read_ctrl_port, &write_ctrl_port);
967     v3_dev_hook_io(dev, COM4_FIFO_CTRL_PORT, &read_ctrl_port, &write_ctrl_port);
968     v3_dev_hook_io(dev, COM4_LINE_CTRL_PORT, &read_ctrl_port, &write_ctrl_port);
969     v3_dev_hook_io(dev, COM4_MODEM_CTRL_PORT, &read_ctrl_port, &write_ctrl_port);
970     v3_dev_hook_io(dev, COM4_LINE_STATUS_PORT, &read_status_port, &write_status_port);
971     v3_dev_hook_io(dev, COM4_MODEM_STATUS_PORT, &read_status_port, &write_status_port);
972     v3_dev_hook_io(dev, COM4_SCRATCH_PORT, &read_ctrl_port, &write_ctrl_port);
973
974     return 0;
975 }
976
977
978 device_register("SERIAL", serial_init)