]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/bhyve/ps2kbd.c
bhyve: Don't leak uninitialized bits in NVMe completion statuses.
[FreeBSD/FreeBSD.git] / usr.sbin / bhyve / ps2kbd.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2015 Tycho Nightingale <tycho.nightingale@pluribusnetworks.com>
5  * Copyright (c) 2015 Nahanni Systems Inc.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
32
33 #include <sys/types.h>
34 #include <sys/stat.h>
35
36 #include <machine/vmm_snapshot.h>
37
38 #include <assert.h>
39 #include <stdbool.h>
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include <strings.h>
44 #include <pthread.h>
45 #include <pthread_np.h>
46 #include <unistd.h>
47 #include <fcntl.h>
48
49 #include "atkbdc.h"
50 #include "bhyverun.h"
51 #include "config.h"
52 #include "console.h"
53 #include "debug.h"
54 #include "ps2kbd.h"
55
56 /* keyboard device commands */
57 #define PS2KC_RESET_DEV         0xff
58 #define PS2KC_DISABLE           0xf5
59 #define PS2KC_ENABLE            0xf4
60 #define PS2KC_SET_TYPEMATIC     0xf3
61 #define PS2KC_SEND_DEV_ID       0xf2
62 #define PS2KC_SET_SCANCODE_SET  0xf0
63 #define PS2KC_ECHO              0xee
64 #define PS2KC_SET_LEDS          0xed
65
66 #define PS2KC_BAT_SUCCESS       0xaa
67 #define PS2KC_ACK               0xfa
68
69 #define PS2KBD_FIFOSZ           16
70
71 #define PS2KBD_LAYOUT_BASEDIR   "/usr/share/bhyve/kbdlayout/"
72
73 #define MAX_PATHNAME            256
74
75 struct fifo {
76         uint8_t buf[PS2KBD_FIFOSZ];
77         int     rindex;         /* index to read from */
78         int     windex;         /* index to write to */
79         int     num;            /* number of bytes in the fifo */
80         int     size;           /* size of the fifo */
81 };
82
83 struct ps2kbd_softc {
84         struct atkbdc_softc     *atkbdc_sc;
85         pthread_mutex_t         mtx;
86
87         bool                    enabled;
88         struct fifo             fifo;
89
90         uint8_t                 curcmd; /* current command for next byte */
91 };
92
93 #define SCANCODE_E0_PREFIX 1
94 struct extended_translation {
95         uint32_t keysym;
96         uint8_t scancode;
97         int flags;
98 };
99
100 /*
101  * FIXME: Pause/break and Print Screen/SysRq require special handling.
102  */
103 static struct extended_translation extended_translations[128] = {
104                 {0xff08, 0x66, 0},              /* Back space */
105                 {0xff09, 0x0d, 0},              /* Tab */
106                 {0xff0d, 0x5a, 0},              /* Return */
107                 {0xff1b, 0x76, 0},              /* Escape */
108                 {0xff50, 0x6c, SCANCODE_E0_PREFIX},     /* Home */
109                 {0xff51, 0x6b, SCANCODE_E0_PREFIX},     /* Left arrow */
110                 {0xff52, 0x75, SCANCODE_E0_PREFIX},     /* Up arrow */
111                 {0xff53, 0x74, SCANCODE_E0_PREFIX},     /* Right arrow */
112                 {0xff54, 0x72, SCANCODE_E0_PREFIX},     /* Down arrow */
113                 {0xff55, 0x7d, SCANCODE_E0_PREFIX},     /* PgUp */
114                 {0xff56, 0x7a, SCANCODE_E0_PREFIX},     /* PgDown */
115                 {0xff57, 0x69, SCANCODE_E0_PREFIX},     /* End */
116                 {0xff63, 0x70, SCANCODE_E0_PREFIX},     /* Ins */
117                 {0xff8d, 0x5a, SCANCODE_E0_PREFIX},     /* Keypad Enter */
118                 {0xffe1, 0x12, 0},              /* Left shift */
119                 {0xffe2, 0x59, 0},              /* Right shift */
120                 {0xffe3, 0x14, 0},              /* Left control */
121                 {0xffe4, 0x14, SCANCODE_E0_PREFIX},     /* Right control */
122                 /* {0xffe7, XXX}, Left meta */
123                 /* {0xffe8, XXX}, Right meta */
124                 {0xffe9, 0x11, 0},              /* Left alt */
125                 {0xfe03, 0x11, SCANCODE_E0_PREFIX},     /* AltGr */
126                 {0xffea, 0x11, SCANCODE_E0_PREFIX},     /* Right alt */
127                 {0xffeb, 0x1f, SCANCODE_E0_PREFIX},     /* Left Windows */
128                 {0xffec, 0x27, SCANCODE_E0_PREFIX},     /* Right Windows */
129                 {0xffbe, 0x05, 0},              /* F1 */
130                 {0xffbf, 0x06, 0},              /* F2 */
131                 {0xffc0, 0x04, 0},              /* F3 */
132                 {0xffc1, 0x0c, 0},              /* F4 */
133                 {0xffc2, 0x03, 0},              /* F5 */
134                 {0xffc3, 0x0b, 0},              /* F6 */
135                 {0xffc4, 0x83, 0},              /* F7 */
136                 {0xffc5, 0x0a, 0},              /* F8 */
137                 {0xffc6, 0x01, 0},              /* F9 */
138                 {0xffc7, 0x09, 0},              /* F10 */
139                 {0xffc8, 0x78, 0},              /* F11 */
140                 {0xffc9, 0x07, 0},              /* F12 */
141                 {0xffff, 0x71, SCANCODE_E0_PREFIX},     /* Del */
142                 {0xff14, 0x7e, 0},              /* ScrollLock */
143                 /* NumLock and Keypads*/
144                 {0xff7f, 0x77, 0},      /* NumLock */
145                 {0xffaf, 0x4a, SCANCODE_E0_PREFIX},     /* Keypad slash */
146                 {0xffaa, 0x7c, 0},      /* Keypad asterisk */
147                 {0xffad, 0x7b, 0},      /* Keypad minus */
148                 {0xffab, 0x79, 0},      /* Keypad plus */
149                 {0xffb7, 0x6c, 0},      /* Keypad 7 */
150                 {0xff95, 0x6c, 0},      /* Keypad home */
151                 {0xffb8, 0x75, 0},      /* Keypad 8 */
152                 {0xff97, 0x75, 0},      /* Keypad up arrow */
153                 {0xffb9, 0x7d, 0},      /* Keypad 9 */
154                 {0xff9a, 0x7d, 0},      /* Keypad PgUp */
155                 {0xffb4, 0x6b, 0},      /* Keypad 4 */
156                 {0xff96, 0x6b, 0},      /* Keypad left arrow */
157                 {0xffb5, 0x73, 0},      /* Keypad 5 */
158                 {0xff9d, 0x73, 0},      /* Keypad empty */
159                 {0xffb6, 0x74, 0},      /* Keypad 6 */
160                 {0xff98, 0x74, 0},      /* Keypad right arrow */
161                 {0xffb1, 0x69, 0},      /* Keypad 1 */
162                 {0xff9c, 0x69, 0},      /* Keypad end */
163                 {0xffb2, 0x72, 0},      /* Keypad 2 */
164                 {0xff99, 0x72, 0},      /* Keypad down arrow */
165                 {0xffb3, 0x7a, 0},      /* Keypad 3 */
166                 {0xff9b, 0x7a, 0},      /* Keypad PgDown */
167                 {0xffb0, 0x70, 0},      /* Keypad 0 */
168                 {0xff9e, 0x70, 0},      /* Keypad ins */
169                 {0xffae, 0x71, 0},      /* Keypad . */
170                 {0xff9f, 0x71, 0},      /* Keypad del */
171                 {0, 0, 0}               /* Terminator */
172 };
173
174 /* ASCII to type 2 scancode lookup table */
175 static uint8_t ascii_translations[128] = {
176                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
177                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
178                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
179                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
180                 0x29, 0x16, 0x52, 0x26, 0x25, 0x2e, 0x3d, 0x52,
181                 0x46, 0x45, 0x3e, 0x55, 0x41, 0x4e, 0x49, 0x4a,
182                 0x45, 0x16, 0x1e, 0x26, 0x25, 0x2e, 0x36, 0x3d,
183                 0x3e, 0x46, 0x4c, 0x4c, 0x41, 0x55, 0x49, 0x4a,
184                 0x1e, 0x1c, 0x32, 0x21, 0x23, 0x24, 0x2b, 0x34,
185                 0x33, 0x43, 0x3b, 0x42, 0x4b, 0x3a, 0x31, 0x44,
186                 0x4d, 0x15, 0x2d, 0x1b, 0x2c, 0x3c, 0x2a, 0x1d,
187                 0x22, 0x35, 0x1a, 0x54, 0x5d, 0x5b, 0x36, 0x4e,
188                 0x0e, 0x1c, 0x32, 0x21, 0x23, 0x24, 0x2b, 0x34,
189                 0x33, 0x43, 0x3b, 0x42, 0x4b, 0x3a, 0x31, 0x44,
190                 0x4d, 0x15, 0x2d, 0x1b, 0x2c, 0x3c, 0x2a, 0x1d,
191                 0x22, 0x35, 0x1a, 0x54, 0x5d, 0x5b, 0x0e, 0x00,
192 };
193
194 /* ScanCode set1 to set2 lookup table */
195 static const uint8_t keyset1to2_translations[128] = {
196                    0, 0x76, 0x16, 0x1E, 0x26, 0x25, 0x2e, 0x36,
197                 0x3d, 0x3e, 0x46, 0x45, 0x4e, 0x55, 0x66, 0x0d,
198                 0x15, 0x1d, 0x24, 0x2d, 0x2c, 0x35, 0x3c, 0x43,
199                 0x44, 0x4d, 0x54, 0x5b, 0x5a, 0x14, 0x1c, 0x1b,
200                 0x23, 0x2b, 0x34, 0x33, 0x3b, 0x42, 0x4b, 0x4c,
201                 0x52, 0x0e, 0x12, 0x5d, 0x1a, 0x22, 0x21, 0x2a,
202                 0x32, 0x31, 0x3a, 0x41, 0x49, 0x4a, 0x59, 0x7c,
203                 0x11, 0x29, 0x58, 0x05, 0x06, 0x04, 0x0c, 0x03,
204                 0x0b, 0x83, 0x0a, 0x01, 0x09, 0x77, 0x7e, 0x6c,
205                 0x75, 0x7d, 0x7b, 0x6b, 0x73, 0x74, 0x79, 0x69,
206                 0x72, 0x7a, 0x70, 0x71, 0x84, 0x60, 0x61, 0x78,
207                 0x07, 0x0f, 0x17, 0x1f, 0x27, 0x2f, 0x37, 0x3f,
208                 0x47, 0x4f, 0x56, 0x5e, 0x08, 0x10, 0x18, 0x20,
209                 0x28, 0x30, 0x38, 0x40, 0x48, 0x50, 0x57, 0x6f,
210                 0x13, 0x19, 0x39, 0x51, 0x53, 0x5c, 0x5f, 0x62,
211                 0x63, 0x64, 0x65, 0x67, 0x68, 0x6a, 0x6d, 0x6e,
212 };
213
214 static void
215 fifo_init(struct ps2kbd_softc *sc)
216 {
217         struct fifo *fifo;
218
219         fifo = &sc->fifo;
220         fifo->size = sizeof(((struct fifo *)0)->buf);
221 }
222
223 static void
224 fifo_reset(struct ps2kbd_softc *sc)
225 {
226         struct fifo *fifo;
227
228         fifo = &sc->fifo;
229         bzero(fifo, sizeof(struct fifo));
230         fifo->size = sizeof(((struct fifo *)0)->buf);
231 }
232
233 static void
234 fifo_put(struct ps2kbd_softc *sc, uint8_t val)
235 {
236         struct fifo *fifo;
237
238         fifo = &sc->fifo;
239         if (fifo->num < fifo->size) {
240                 fifo->buf[fifo->windex] = val;
241                 fifo->windex = (fifo->windex + 1) % fifo->size;
242                 fifo->num++;
243         }
244 }
245
246 static int
247 fifo_get(struct ps2kbd_softc *sc, uint8_t *val)
248 {
249         struct fifo *fifo;
250
251         fifo = &sc->fifo;
252         if (fifo->num > 0) {
253                 *val = fifo->buf[fifo->rindex];
254                 fifo->rindex = (fifo->rindex + 1) % fifo->size;
255                 fifo->num--;
256                 return (0);
257         }
258
259         return (-1);
260 }
261
262 int
263 ps2kbd_read(struct ps2kbd_softc *sc, uint8_t *val)
264 {
265         int retval;
266
267         pthread_mutex_lock(&sc->mtx);
268         retval = fifo_get(sc, val);
269         pthread_mutex_unlock(&sc->mtx);
270
271         return (retval);
272 }
273
274 void
275 ps2kbd_write(struct ps2kbd_softc *sc, uint8_t val)
276 {
277         pthread_mutex_lock(&sc->mtx);
278         if (sc->curcmd) {
279                 switch (sc->curcmd) {
280                 case PS2KC_SET_TYPEMATIC:
281                         fifo_put(sc, PS2KC_ACK);
282                         break;
283                 case PS2KC_SET_SCANCODE_SET:
284                         fifo_put(sc, PS2KC_ACK);
285                         break;
286                 case PS2KC_SET_LEDS:
287                         fifo_put(sc, PS2KC_ACK);
288                         break;
289                 default:
290                         EPRINTLN("Unhandled ps2 keyboard current "
291                             "command byte 0x%02x", val);
292                         break;
293                 }
294                 sc->curcmd = 0;
295         } else {
296                 switch (val) {
297                 case 0x00:
298                         fifo_put(sc, PS2KC_ACK);
299                         break;
300                 case PS2KC_RESET_DEV:
301                         fifo_reset(sc);
302                         fifo_put(sc, PS2KC_ACK);
303                         fifo_put(sc, PS2KC_BAT_SUCCESS);
304                         break;
305                 case PS2KC_DISABLE:
306                         sc->enabled = false;
307                         fifo_put(sc, PS2KC_ACK);
308                         break;
309                 case PS2KC_ENABLE:
310                         sc->enabled = true;
311                         fifo_reset(sc);
312                         fifo_put(sc, PS2KC_ACK);
313                         break;
314                 case PS2KC_SET_TYPEMATIC:
315                         sc->curcmd = val;
316                         fifo_put(sc, PS2KC_ACK);
317                         break;
318                 case PS2KC_SEND_DEV_ID:
319                         fifo_put(sc, PS2KC_ACK);
320                         fifo_put(sc, 0xab);
321                         fifo_put(sc, 0x83);
322                         break;
323                 case PS2KC_SET_SCANCODE_SET:
324                         sc->curcmd = val;
325                         fifo_put(sc, PS2KC_ACK);
326                         break;
327                 case PS2KC_ECHO:
328                         fifo_put(sc, PS2KC_ECHO);
329                         break;
330                 case PS2KC_SET_LEDS:
331                         sc->curcmd = val;
332                         fifo_put(sc, PS2KC_ACK);
333                         break;
334                 default:
335                         EPRINTLN("Unhandled ps2 keyboard command "
336                             "0x%02x", val);
337                         break;
338                 }
339         }
340         pthread_mutex_unlock(&sc->mtx);
341 }
342
343 /*
344  * Translate keysym to type 2 scancode and insert into keyboard buffer.
345  */
346 static void
347 ps2kbd_keysym_queue(struct ps2kbd_softc *sc,
348     int down, uint32_t keysym, uint32_t keycode)
349 {
350         const struct extended_translation *trans;
351         int e0_prefix, found;
352         uint8_t code;
353
354         assert(pthread_mutex_isowned_np(&sc->mtx));
355
356         if (keycode) {
357                 code =  keyset1to2_translations[(uint8_t)(keycode & 0x7f)];
358                 e0_prefix = ((keycode & 0x80) ?  SCANCODE_E0_PREFIX : 0);
359                 found = 1;
360         } else {
361                 found = 0;
362                 if (keysym < 0x80) {
363                         code = ascii_translations[keysym];
364                         e0_prefix = 0;
365                         found = 1;
366                 } else {
367                         for (trans = &extended_translations[0];
368                             trans->keysym != 0; trans++) {
369                                 if (keysym == trans->keysym) {
370                                         code = trans->scancode;
371                                         e0_prefix = trans->flags & SCANCODE_E0_PREFIX;
372                                         found = 1;
373                                         break;
374                                 }
375                         }
376                 }
377         }
378
379         if (!found) {
380                 EPRINTLN("Unhandled ps2 keyboard keysym 0x%x", keysym);
381                 return;
382         }
383
384         if (e0_prefix)
385                 fifo_put(sc, 0xe0);
386         if (!down)
387                 fifo_put(sc, 0xf0);
388         fifo_put(sc, code);
389 }
390
391 static void
392 ps2kbd_event(int down, uint32_t keysym, uint32_t keycode, void *arg)
393 {
394         struct ps2kbd_softc *sc = arg;
395         int fifo_full;
396
397         pthread_mutex_lock(&sc->mtx);
398         if (!sc->enabled) {
399                 pthread_mutex_unlock(&sc->mtx);
400                 return;
401         }
402         fifo_full = sc->fifo.num == PS2KBD_FIFOSZ;
403         ps2kbd_keysym_queue(sc, down, keysym, keycode);
404         pthread_mutex_unlock(&sc->mtx);
405
406         if (!fifo_full)
407                 atkbdc_event(sc->atkbdc_sc, 1);
408 }
409
410 static void
411 ps2kbd_update_extended_translation(uint32_t keycode, uint32_t scancode, uint32_t prefix)
412 {
413         int i = 0;
414
415         do {
416                 if (extended_translations[i].keysym == keycode)
417                         break;
418         } while (extended_translations[++i].keysym);
419
420         if (i == (sizeof(extended_translations) / sizeof(struct extended_translation) - 1))
421                 return;
422
423         if (!extended_translations[i].keysym)   {
424                 extended_translations[i].keysym = keycode;
425
426                 extended_translations[i+1].keysym = 0;
427                 extended_translations[i+1].scancode = 0;
428                 extended_translations[i+1].flags = 0;
429         }
430
431         extended_translations[i].scancode = (uint8_t)(scancode & 0xff);
432         extended_translations[i].flags = (prefix ? SCANCODE_E0_PREFIX : 0);
433 }
434
435 static void
436 ps2kbd_setkbdlayout(void)
437 {
438         int err;
439         int fd;
440         char path[MAX_PATHNAME];
441         char *buf, *next, *line;
442         struct stat sb;
443         ssize_t sz;
444         uint8_t ascii;
445         uint32_t keycode, scancode, prefix;
446
447         snprintf(path, MAX_PATHNAME, PS2KBD_LAYOUT_BASEDIR"%s", get_config_value("keyboard.layout") );
448
449         err = stat(path, &sb);
450         if (err)
451                 return;
452
453         buf = (char *)malloc(sizeof(char) * sb.st_size);
454         if (buf == NULL)
455                 return;
456
457         fd = open(path, O_RDONLY);
458         if (fd == -1)
459                 goto out;
460
461         sz = read(fd, buf, sb.st_size);
462
463         close(fd);
464
465         if (sz < 0 || sz != sb.st_size)
466                 goto out;
467
468         next = buf;
469         while ((line = strsep(&next, "\n")) != NULL)    {
470                 if (sscanf(line, "'%c',%x;", &ascii, &scancode) == 2)   {
471                         if (ascii < 0x80)
472                                 ascii_translations[ascii] = (uint8_t)(scancode & 0xff);
473                 } else if (sscanf(line, "%x,%x,%x;", &keycode, &scancode, &prefix) == 3 )       {
474                         ps2kbd_update_extended_translation(keycode, scancode, prefix);
475                 } else if (sscanf(line, "%x,%x;", &keycode, &scancode) == 2)    {
476                         if (keycode < 0x80)
477                                 ascii_translations[(uint8_t)(keycode & 0xff)] = (uint8_t)(scancode & 0xff);
478                         else
479                                 ps2kbd_update_extended_translation(keycode, scancode, 0);
480                 }
481         }
482
483 out:
484         free(buf);
485 }
486
487 struct ps2kbd_softc *
488 ps2kbd_init(struct atkbdc_softc *atkbdc_sc)
489 {
490         struct ps2kbd_softc *sc;
491
492         if (get_config_value("keyboard.layout") != NULL)
493                 ps2kbd_setkbdlayout();
494
495         sc = calloc(1, sizeof (struct ps2kbd_softc));
496         pthread_mutex_init(&sc->mtx, NULL);
497         fifo_init(sc);
498         sc->atkbdc_sc = atkbdc_sc;
499
500         console_kbd_register(ps2kbd_event, sc, 1);
501
502         return (sc);
503 }
504
505 #ifdef BHYVE_SNAPSHOT
506 int
507 ps2kbd_snapshot(struct ps2kbd_softc *sc, struct vm_snapshot_meta *meta)
508 {
509         int ret;
510
511         SNAPSHOT_VAR_OR_LEAVE(sc->enabled, meta, ret, done);
512         SNAPSHOT_VAR_OR_LEAVE(sc->curcmd, meta, ret, done);
513
514 done:
515         return (ret);
516 }
517 #endif
518