cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

kdb_keyboard.c (5642B)


      1/*
      2 * Kernel Debugger Architecture Dependent Console I/O handler
      3 *
      4 * This file is subject to the terms and conditions of the GNU General Public
      5 * License.
      6 *
      7 * Copyright (c) 1999-2006 Silicon Graphics, Inc.  All Rights Reserved.
      8 * Copyright (c) 2009 Wind River Systems, Inc.  All Rights Reserved.
      9 */
     10
     11#include <linux/kdb.h>
     12#include <linux/keyboard.h>
     13#include <linux/ctype.h>
     14#include <linux/io.h>
     15
     16/* Keyboard Controller Registers on normal PCs. */
     17
     18#define KBD_STATUS_REG		0x64	/* Status register (R) */
     19#define KBD_DATA_REG		0x60	/* Keyboard data register (R/W) */
     20
     21/* Status Register Bits */
     22
     23#define KBD_STAT_OBF 		0x01	/* Keyboard output buffer full */
     24#define KBD_STAT_MOUSE_OBF	0x20	/* Mouse output buffer full */
     25
     26static int kbd_exists;
     27static int kbd_last_ret;
     28
     29/*
     30 * Check if the keyboard controller has a keypress for us.
     31 * Some parts (Enter Release, LED change) are still blocking polled here,
     32 * but hopefully they are all short.
     33 */
     34int kdb_get_kbd_char(void)
     35{
     36	int scancode, scanstatus;
     37	static int shift_lock;	/* CAPS LOCK state (0-off, 1-on) */
     38	static int shift_key;	/* Shift next keypress */
     39	static int ctrl_key;
     40	u_short keychar;
     41
     42	if (KDB_FLAG(NO_I8042) || KDB_FLAG(NO_VT_CONSOLE) ||
     43	    (inb(KBD_STATUS_REG) == 0xff && inb(KBD_DATA_REG) == 0xff)) {
     44		kbd_exists = 0;
     45		return -1;
     46	}
     47	kbd_exists = 1;
     48
     49	if ((inb(KBD_STATUS_REG) & KBD_STAT_OBF) == 0)
     50		return -1;
     51
     52	/*
     53	 * Fetch the scancode
     54	 */
     55	scancode = inb(KBD_DATA_REG);
     56	scanstatus = inb(KBD_STATUS_REG);
     57
     58	/*
     59	 * Ignore mouse events.
     60	 */
     61	if (scanstatus & KBD_STAT_MOUSE_OBF)
     62		return -1;
     63
     64	/*
     65	 * Ignore release, trigger on make
     66	 * (except for shift keys, where we want to
     67	 *  keep the shift state so long as the key is
     68	 *  held down).
     69	 */
     70
     71	if (((scancode&0x7f) == 0x2a) || ((scancode&0x7f) == 0x36)) {
     72		/*
     73		 * Next key may use shift table
     74		 */
     75		if ((scancode & 0x80) == 0)
     76			shift_key = 1;
     77		else
     78			shift_key = 0;
     79		return -1;
     80	}
     81
     82	if ((scancode&0x7f) == 0x1d) {
     83		/*
     84		 * Left ctrl key
     85		 */
     86		if ((scancode & 0x80) == 0)
     87			ctrl_key = 1;
     88		else
     89			ctrl_key = 0;
     90		return -1;
     91	}
     92
     93	if ((scancode & 0x80) != 0) {
     94		if (scancode == 0x9c)
     95			kbd_last_ret = 0;
     96		return -1;
     97	}
     98
     99	scancode &= 0x7f;
    100
    101	/*
    102	 * Translate scancode
    103	 */
    104
    105	if (scancode == 0x3a) {
    106		/*
    107		 * Toggle caps lock
    108		 */
    109		shift_lock ^= 1;
    110
    111#ifdef	KDB_BLINK_LED
    112		kdb_toggleled(0x4);
    113#endif
    114		return -1;
    115	}
    116
    117	if (scancode == 0x0e) {
    118		/*
    119		 * Backspace
    120		 */
    121		return 8;
    122	}
    123
    124	/* Special Key */
    125	switch (scancode) {
    126	case 0xF: /* Tab */
    127		return 9;
    128	case 0x53: /* Del */
    129		return 4;
    130	case 0x47: /* Home */
    131		return 1;
    132	case 0x4F: /* End */
    133		return 5;
    134	case 0x4B: /* Left */
    135		return 2;
    136	case 0x48: /* Up */
    137		return 16;
    138	case 0x50: /* Down */
    139		return 14;
    140	case 0x4D: /* Right */
    141		return 6;
    142	}
    143
    144	if (scancode == 0xe0)
    145		return -1;
    146
    147	/*
    148	 * For Japanese 86/106 keyboards
    149	 * 	See comment in drivers/char/pc_keyb.c.
    150	 * 	- Masahiro Adegawa
    151	 */
    152	if (scancode == 0x73)
    153		scancode = 0x59;
    154	else if (scancode == 0x7d)
    155		scancode = 0x7c;
    156
    157	if (!shift_lock && !shift_key && !ctrl_key) {
    158		keychar = plain_map[scancode];
    159	} else if ((shift_lock || shift_key) && key_maps[1]) {
    160		keychar = key_maps[1][scancode];
    161	} else if (ctrl_key && key_maps[4]) {
    162		keychar = key_maps[4][scancode];
    163	} else {
    164		keychar = 0x0020;
    165		kdb_printf("Unknown state/scancode (%d)\n", scancode);
    166	}
    167	keychar &= 0x0fff;
    168	if (keychar == '\t')
    169		keychar = ' ';
    170	switch (KTYP(keychar)) {
    171	case KT_LETTER:
    172	case KT_LATIN:
    173		if (isprint(keychar))
    174			break;		/* printable characters */
    175		fallthrough;
    176	case KT_SPEC:
    177		if (keychar == K_ENTER)
    178			break;
    179		fallthrough;
    180	default:
    181		return -1;	/* ignore unprintables */
    182	}
    183
    184	if (scancode == 0x1c) {
    185		kbd_last_ret = 1;
    186		return 13;
    187	}
    188
    189	return keychar & 0xff;
    190}
    191EXPORT_SYMBOL_GPL(kdb_get_kbd_char);
    192
    193/*
    194 * Best effort cleanup of ENTER break codes on leaving KDB. Called on
    195 * exiting KDB, when we know we processed an ENTER or KP ENTER scan
    196 * code.
    197 */
    198void kdb_kbd_cleanup_state(void)
    199{
    200	int scancode, scanstatus;
    201
    202	/*
    203	 * Nothing to clean up, since either
    204	 * ENTER was never pressed, or has already
    205	 * gotten cleaned up.
    206	 */
    207	if (!kbd_last_ret)
    208		return;
    209
    210	kbd_last_ret = 0;
    211	/*
    212	 * Enter key. Need to absorb the break code here, lest it gets
    213	 * leaked out if we exit KDB as the result of processing 'g'.
    214	 *
    215	 * This has several interesting implications:
    216	 * + Need to handle KP ENTER, which has break code 0xe0 0x9c.
    217	 * + Need to handle repeat ENTER and repeat KP ENTER. Repeats
    218	 *   only get a break code at the end of the repeated
    219	 *   sequence. This means we can't propagate the repeated key
    220	 *   press, and must swallow it away.
    221	 * + Need to handle possible PS/2 mouse input.
    222	 * + Need to handle mashed keys.
    223	 */
    224
    225	while (1) {
    226		while ((inb(KBD_STATUS_REG) & KBD_STAT_OBF) == 0)
    227			cpu_relax();
    228
    229		/*
    230		 * Fetch the scancode.
    231		 */
    232		scancode = inb(KBD_DATA_REG);
    233		scanstatus = inb(KBD_STATUS_REG);
    234
    235		/*
    236		 * Skip mouse input.
    237		 */
    238		if (scanstatus & KBD_STAT_MOUSE_OBF)
    239			continue;
    240
    241		/*
    242		 * If we see 0xe0, this is either a break code for KP
    243		 * ENTER, or a repeat make for KP ENTER. Either way,
    244		 * since the second byte is equivalent to an ENTER,
    245		 * skip the 0xe0 and try again.
    246		 *
    247		 * If we see 0x1c, this must be a repeat ENTER or KP
    248		 * ENTER (and we swallowed 0xe0 before). Try again.
    249		 *
    250		 * We can also see make and break codes for other keys
    251		 * mashed before or after pressing ENTER. Thus, if we
    252		 * see anything other than 0x9c, we have to try again.
    253		 *
    254		 * Note, if you held some key as ENTER was depressed,
    255		 * that break code would get leaked out.
    256		 */
    257		if (scancode != 0x9c)
    258			continue;
    259
    260		return;
    261	}
    262}