1 #include "kvm/early_printk.h" 2 3 #include "kvm/ioport.h" 4 #include "kvm/util.h" 5 6 #include <stdbool.h> 7 8 /* Transmitter holding register */ 9 #define THR 0 10 11 /* Receive buffer register */ 12 #define RBR 0 13 14 /* Divisor latch low byte */ 15 #define DLL 0 16 17 /* Divisor latch high byte */ 18 #define DLM 1 19 20 /* Interrupt enable register */ 21 #define IER 1 22 23 /* Interrupt identification register */ 24 #define IIR 2 25 26 #define UART_IIR_NO_INT 0x01 27 28 /* 16550 FIFO Control Register */ 29 #define FCR 2 30 31 /* Line control register */ 32 #define LCR 3 33 34 #define UART_LCR_DLAB 0x80 35 36 /* Modem control register */ 37 #define MCR 4 38 39 /* Line status register */ 40 #define LSR 5 41 42 #define UART_LSR_THRE 0x20 43 44 /* Modem status register */ 45 #define MSR 6 46 47 #define UART_MSR_CTS 0x10 48 49 /* Scratch register */ 50 #define SCR 7 51 52 struct serial8250_device { 53 uint16_t iobase; 54 uint8_t dll; 55 uint8_t dlm; 56 uint8_t ier; 57 uint8_t fcr; 58 uint8_t lcr; 59 uint8_t mcr; 60 uint8_t scr; 61 }; 62 63 static struct serial8250_device device = { 64 .iobase = 0x3f8, /* ttyS0 */ 65 }; 66 67 static bool serial8250_out(struct kvm *self, uint16_t port, void *data, int size, uint32_t count) 68 { 69 uint16_t offset = port - device.iobase; 70 71 if (device.lcr & UART_LCR_DLAB) { 72 switch (offset) { 73 case DLL: 74 device.dll = ioport__read8(data); 75 break; 76 case DLM: 77 device.dlm = ioport__read8(data); 78 break; 79 case FCR: 80 device.fcr = ioport__read8(data); 81 break; 82 case LCR: 83 device.lcr = ioport__read8(data); 84 break; 85 default: 86 return false; 87 } 88 } else { 89 switch (offset) { 90 case THR: { 91 char *p = data; 92 int i; 93 94 while (count--) { 95 for (i = 0; i < size; i++) 96 fprintf(stdout, "%c", *p++); 97 } 98 fflush(stdout); 99 break; 100 } 101 case IER: 102 device.ier = ioport__read8(data); 103 break; 104 case FCR: 105 device.fcr = ioport__read8(data); 106 break; 107 case LCR: 108 device.lcr = ioport__read8(data); 109 break; 110 case MCR: 111 device.mcr = ioport__read8(data); 112 break; 113 case SCR: 114 device.scr = ioport__read8(data); 115 break; 116 default: 117 return false; 118 } 119 } 120 121 return true; 122 } 123 124 static bool serial8250_in(struct kvm *self, uint16_t port, void *data, int size, uint32_t count) 125 { 126 uint16_t offset = port - device.iobase; 127 128 if (device.lcr & UART_LCR_DLAB) 129 return false; 130 131 switch (offset) { 132 case THR: 133 ioport__write8(data, 0x00); 134 break; 135 case IER: 136 ioport__write8(data, device.ier); 137 break; 138 case IIR: 139 ioport__write8(data, UART_IIR_NO_INT); 140 break; 141 case LCR: 142 ioport__write8(data, device.lcr); 143 break; 144 case MCR: 145 ioport__write8(data, device.mcr); 146 break; 147 case LSR: 148 ioport__write8(data, UART_LSR_THRE); 149 break; 150 case MSR: 151 ioport__write8(data, UART_MSR_CTS); 152 break; 153 case SCR: 154 ioport__write8(data, device.scr); 155 break; 156 default: 157 return false; 158 } 159 160 return true; 161 } 162 163 static struct ioport_operations serial8250_ops = { 164 .io_in = serial8250_in, 165 .io_out = serial8250_out, 166 }; 167 168 void early_printk__init(void) 169 { 170 ioport__register(device.iobase, &serial8250_ops, 8); 171 } 172