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