1 #include "kvm/read-write.h"
2 #include "kvm/ioport.h"
3 #include "kvm/mutex.h"
4 #include "kvm/util.h"
5 #include "kvm/term.h"
6 #include "kvm/kvm.h"
7 #include "kvm/i8042.h"
8 #include "kvm/kvm-cpu.h"
9
10 #include <stdint.h>
11
12 /*
13 * IRQs
14 */
15 #define KBD_IRQ 1
16 #define AUX_IRQ 12
17
18 /*
19 * Registers
20 */
21 #define I8042_DATA_REG 0x60
22 #define I8042_PORT_B_REG 0x61
23 #define I8042_COMMAND_REG 0x64
24
25 /*
26 * Commands
27 */
28 #define I8042_CMD_CTL_RCTR 0x20
29 #define I8042_CMD_CTL_WCTR 0x60
30 #define I8042_CMD_AUX_LOOP 0xD3
31 #define I8042_CMD_AUX_SEND 0xD4
32 #define I8042_CMD_AUX_TEST 0xA9
33 #define I8042_CMD_AUX_DISABLE 0xA7
34 #define I8042_CMD_AUX_ENABLE 0xA8
35 #define I8042_CMD_SYSTEM_RESET 0xFE
36
37 #define RESPONSE_ACK 0xFA
38
39 #define MODE_DISABLE_AUX 0x20
40
41 #define AUX_ENABLE_REPORTING 0x20
42 #define AUX_SCALING_FLAG 0x10
43 #define AUX_DEFAULT_RESOLUTION 0x2
44 #define AUX_DEFAULT_SAMPLE 100
45
46 /*
47 * Status register bits
48 */
49 #define I8042_STR_AUXDATA 0x20
50 #define I8042_STR_KEYLOCK 0x10
51 #define I8042_STR_CMDDAT 0x08
52 #define I8042_STR_MUXERR 0x04
53 #define I8042_STR_OBF 0x01
54
55 #define KBD_MODE_KBD_INT 0x01
56 #define KBD_MODE_SYS 0x02
57
58 #define QUEUE_SIZE 128
59
60 /*
61 * This represents the current state of the PS/2 keyboard system,
62 * including the AUX device (the mouse)
63 */
64 struct kbd_state {
65 struct kvm *kvm;
66
67 u8 kq[QUEUE_SIZE]; /* Keyboard queue */
68 int kread, kwrite; /* Indexes into the queue */
69 int kcount; /* number of elements in queue */
70
71 u8 mq[QUEUE_SIZE];
72 int mread, mwrite;
73 int mcount;
74
75 u8 mstatus; /* Mouse status byte */
76 u8 mres; /* Current mouse resolution */
77 u8 msample; /* Current mouse samples/second */
78
79 u8 mode; /* i8042 mode register */
80 u8 status; /* i8042 status register */
81 /*
82 * Some commands (on port 0x64) have arguments;
83 * we store the command here while we wait for the argument
84 */
85 u8 write_cmd;
86 };
87
88 static struct kbd_state state;
89
90 /*
91 * If there are packets to be read, set the appropriate IRQs high
92 */
kbd_update_irq(void)93 static void kbd_update_irq(void)
94 {
95 u8 klevel = 0;
96 u8 mlevel = 0;
97
98 /* First, clear the kbd and aux output buffer full bits */
99 state.status &= ~(I8042_STR_OBF | I8042_STR_AUXDATA);
100
101 if (state.kcount > 0) {
102 state.status |= I8042_STR_OBF;
103 klevel = 1;
104 }
105
106 /* Keyboard has higher priority than mouse */
107 if (klevel == 0 && state.mcount != 0) {
108 state.status |= I8042_STR_OBF | I8042_STR_AUXDATA;
109 mlevel = 1;
110 }
111
112 kvm__irq_line(state.kvm, KBD_IRQ, klevel);
113 kvm__irq_line(state.kvm, AUX_IRQ, mlevel);
114 }
115
116 /*
117 * Add a byte to the mouse queue, then set IRQs
118 */
mouse_queue(u8 c)119 void mouse_queue(u8 c)
120 {
121 if (state.mcount >= QUEUE_SIZE)
122 return;
123
124 state.mq[state.mwrite++ % QUEUE_SIZE] = c;
125
126 state.mcount++;
127 kbd_update_irq();
128 }
129
130 /*
131 * Add a byte to the keyboard queue, then set IRQs
132 */
kbd_queue(u8 c)133 void kbd_queue(u8 c)
134 {
135 if (state.kcount >= QUEUE_SIZE)
136 return;
137
138 state.kq[state.kwrite++ % QUEUE_SIZE] = c;
139
140 state.kcount++;
141 kbd_update_irq();
142 }
143
kbd_write_command(struct kvm * kvm,u8 val)144 static void kbd_write_command(struct kvm *kvm, u8 val)
145 {
146 switch (val) {
147 case I8042_CMD_CTL_RCTR:
148 kbd_queue(state.mode);
149 break;
150 case I8042_CMD_CTL_WCTR:
151 case I8042_CMD_AUX_SEND:
152 case I8042_CMD_AUX_LOOP:
153 state.write_cmd = val;
154 break;
155 case I8042_CMD_AUX_TEST:
156 /* 0 means we're a normal PS/2 mouse */
157 mouse_queue(0);
158 break;
159 case I8042_CMD_AUX_DISABLE:
160 state.mode |= MODE_DISABLE_AUX;
161 break;
162 case I8042_CMD_AUX_ENABLE:
163 state.mode &= ~MODE_DISABLE_AUX;
164 break;
165 case I8042_CMD_SYSTEM_RESET:
166 kvm__reboot(kvm);
167 break;
168 default:
169 break;
170 }
171 }
172
173 /*
174 * Called when the OS reads from port 0x60 (PS/2 data)
175 */
kbd_read_data(void)176 static u8 kbd_read_data(void)
177 {
178 u8 ret;
179 int i;
180
181 if (state.kcount != 0) {
182 /* Keyboard data gets read first */
183 ret = state.kq[state.kread++ % QUEUE_SIZE];
184 state.kcount--;
185 kvm__irq_line(state.kvm, KBD_IRQ, 0);
186 kbd_update_irq();
187 } else if (state.mcount > 0) {
188 /* Followed by the mouse */
189 ret = state.mq[state.mread++ % QUEUE_SIZE];
190 state.mcount--;
191 kvm__irq_line(state.kvm, AUX_IRQ, 0);
192 kbd_update_irq();
193 } else {
194 i = state.kread - 1;
195 if (i < 0)
196 i = QUEUE_SIZE;
197 ret = state.kq[i];
198 }
199 return ret;
200 }
201
202 /*
203 * Called when the OS read from port 0x64, the command port
204 */
kbd_read_status(void)205 static u8 kbd_read_status(void)
206 {
207 return state.status;
208 }
209
210 /*
211 * Called when the OS writes to port 0x60 (data port)
212 * Things written here are generally arguments to commands previously
213 * written to port 0x64 and stored in state.write_cmd
214 */
kbd_write_data(u8 val)215 static void kbd_write_data(u8 val)
216 {
217 switch (state.write_cmd) {
218 case I8042_CMD_CTL_WCTR:
219 state.mode = val;
220 kbd_update_irq();
221 break;
222 case I8042_CMD_AUX_LOOP:
223 mouse_queue(val);
224 mouse_queue(RESPONSE_ACK);
225 break;
226 case I8042_CMD_AUX_SEND:
227 /* The OS wants to send a command to the mouse */
228 mouse_queue(RESPONSE_ACK);
229 switch (val) {
230 case 0xe6:
231 /* set scaling = 1:1 */
232 state.mstatus &= ~AUX_SCALING_FLAG;
233 break;
234 case 0xe8:
235 /* set resolution */
236 state.mres = val;
237 break;
238 case 0xe9:
239 /* Report mouse status/config */
240 mouse_queue(state.mstatus);
241 mouse_queue(state.mres);
242 mouse_queue(state.msample);
243 break;
244 case 0xf2:
245 /* send ID */
246 mouse_queue(0); /* normal mouse */
247 break;
248 case 0xf3:
249 /* set sample rate */
250 state.msample = val;
251 break;
252 case 0xf4:
253 /* enable reporting */
254 state.mstatus |= AUX_ENABLE_REPORTING;
255 break;
256 case 0xf5:
257 state.mstatus &= ~AUX_ENABLE_REPORTING;
258 break;
259 case 0xf6:
260 /* set defaults, just fall through to reset */
261 case 0xff:
262 /* reset */
263 state.mstatus = 0x0;
264 state.mres = AUX_DEFAULT_RESOLUTION;
265 state.msample = AUX_DEFAULT_SAMPLE;
266 break;
267 default:
268 break;
269 }
270 break;
271 case 0:
272 /* Just send the ID */
273 kbd_queue(RESPONSE_ACK);
274 kbd_queue(0xab);
275 kbd_queue(0x41);
276 kbd_update_irq();
277 break;
278 default:
279 /* Yeah whatever */
280 break;
281 }
282 state.write_cmd = 0;
283 }
284
kbd_reset(void)285 static void kbd_reset(void)
286 {
287 state = (struct kbd_state) {
288 .status = I8042_STR_MUXERR | I8042_STR_CMDDAT | I8042_STR_KEYLOCK, /* 0x1c */
289 .mode = KBD_MODE_KBD_INT | KBD_MODE_SYS, /* 0x3 */
290 .mres = AUX_DEFAULT_RESOLUTION,
291 .msample = AUX_DEFAULT_SAMPLE,
292 };
293 }
294
kbd_io(struct kvm_cpu * vcpu,u64 addr,u8 * data,u32 len,u8 is_write,void * ptr)295 static void kbd_io(struct kvm_cpu *vcpu, u64 addr, u8 *data, u32 len,
296 u8 is_write, void *ptr)
297 {
298 u8 value = 0;
299
300 if (is_write)
301 value = ioport__read8(data);
302
303 switch (addr) {
304 case I8042_COMMAND_REG:
305 if (is_write)
306 kbd_write_command(vcpu->kvm, value);
307 else
308 value = kbd_read_status();
309 break;
310 case I8042_DATA_REG:
311 if (is_write)
312 kbd_write_data(value);
313 else
314 value = kbd_read_data();
315 break;
316 case I8042_PORT_B_REG:
317 if (!is_write)
318 value = 0x20;
319 break;
320 default:
321 return;
322 }
323
324 if (!is_write)
325 ioport__write8(data, value);
326 }
327
kbd__init(struct kvm * kvm)328 static int kbd__init(struct kvm *kvm)
329 {
330 int r;
331
332 kbd_reset();
333 state.kvm = kvm;
334 r = kvm__register_pio(kvm, I8042_DATA_REG, 2, kbd_io, NULL);
335 if (r < 0)
336 return r;
337 r = kvm__register_pio(kvm, I8042_COMMAND_REG, 2, kbd_io, NULL);
338 if (r < 0) {
339 kvm__deregister_pio(kvm, I8042_DATA_REG);
340 return r;
341 }
342
343 return 0;
344 }
345 dev_init(kbd__init);
346