|  | @@ -26,9 +26,12 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 | 
		
	
		
			
			| 26 | 26 |  #include <assert.h>
 | 
		
	
		
			
			| 27 | 27 |  #include <realmode.h>
 | 
		
	
		
			
			| 28 | 28 |  #include <bios.h>
 | 
		
	
		
			
			|  | 29 | +#include <biosint.h>
 | 
		
	
		
			
			| 29 | 30 |  #include <ipxe/console.h>
 | 
		
	
		
			
			| 30 | 31 |  #include <ipxe/ansiesc.h>
 | 
		
	
		
			
			|  | 32 | +#include <ipxe/keys.h>
 | 
		
	
		
			
			| 31 | 33 |  #include <ipxe/keymap.h>
 | 
		
	
		
			
			|  | 34 | +#include <ipxe/init.h>
 | 
		
	
		
			
			| 32 | 35 |  #include <config/console.h>
 | 
		
	
		
			
			| 33 | 36 |  
 | 
		
	
		
			
			| 34 | 37 |  #define ATTR_BOLD		0x08
 | 
		
	
	
		
			
			|  | @@ -66,6 +69,17 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 | 
		
	
		
			
			| 66 | 69 |  /** Current character attribute */
 | 
		
	
		
			
			| 67 | 70 |  static unsigned int bios_attr = ATTR_DEFAULT;
 | 
		
	
		
			
			| 68 | 71 |  
 | 
		
	
		
			
			|  | 72 | +/** Keypress injection lock */
 | 
		
	
		
			
			|  | 73 | +static uint8_t __text16 ( bios_inject_lock );
 | 
		
	
		
			
			|  | 74 | +#define bios_inject_lock __use_text16 ( bios_inject_lock )
 | 
		
	
		
			
			|  | 75 | +
 | 
		
	
		
			
			|  | 76 | +/** Vector for chaining to other INT 16 handlers */
 | 
		
	
		
			
			|  | 77 | +static struct segoff __text16 ( int16_vector );
 | 
		
	
		
			
			|  | 78 | +#define int16_vector __use_text16 ( int16_vector )
 | 
		
	
		
			
			|  | 79 | +
 | 
		
	
		
			
			|  | 80 | +/** Assembly wrapper */
 | 
		
	
		
			
			|  | 81 | +extern void int16_wrapper ( void );
 | 
		
	
		
			
			|  | 82 | +
 | 
		
	
		
			
			| 69 | 83 |  /**
 | 
		
	
		
			
			| 70 | 84 |   * Handle ANSI CUP (cursor position)
 | 
		
	
		
			
			| 71 | 85 |   *
 | 
		
	
	
		
			
			|  | @@ -265,30 +279,35 @@ static void bios_putchar ( int character ) {
 | 
		
	
		
			
			| 265 | 279 |   * not in the middle of such a sequence, this will point to a NUL
 | 
		
	
		
			
			| 266 | 280 |   * (note: not "will be NULL").
 | 
		
	
		
			
			| 267 | 281 |   */
 | 
		
	
		
			
			| 268 |  | -static const char *ansi_input = "";
 | 
		
	
		
			
			| 269 |  | -
 | 
		
	
		
			
			| 270 |  | -/** A mapping from a BIOS scan code to an ANSI escape sequence */
 | 
		
	
		
			
			| 271 |  | -#define BIOS_KEY( key, ansi ) key ansi "\0"
 | 
		
	
		
			
			| 272 |  | -
 | 
		
	
		
			
			| 273 |  | -/** Mapping from BIOS scan codes to ANSI escape sequences */
 | 
		
	
		
			
			| 274 |  | -static const char ansi_sequences[] = {
 | 
		
	
		
			
			| 275 |  | -	BIOS_KEY ( "\x53", "[3~" )	/* Delete */
 | 
		
	
		
			
			| 276 |  | -	BIOS_KEY ( "\x48", "[A" )	/* Up arrow */
 | 
		
	
		
			
			| 277 |  | -	BIOS_KEY ( "\x50", "[B" )	/* Down arrow */
 | 
		
	
		
			
			| 278 |  | -	BIOS_KEY ( "\x4b", "[D" )	/* Left arrow */
 | 
		
	
		
			
			| 279 |  | -	BIOS_KEY ( "\x4d", "[C" )	/* Right arrow */
 | 
		
	
		
			
			| 280 |  | -	BIOS_KEY ( "\x47", "[H" )	/* Home */
 | 
		
	
		
			
			| 281 |  | -	BIOS_KEY ( "\x4f", "[F" )	/* End */
 | 
		
	
		
			
			| 282 |  | -	BIOS_KEY ( "\x49", "[5~" )	/* Page up */
 | 
		
	
		
			
			| 283 |  | -	BIOS_KEY ( "\x51", "[6~" )	/* Page down */
 | 
		
	
		
			
			| 284 |  | -	BIOS_KEY ( "\x3f", "[15~" )	/* F5 */
 | 
		
	
		
			
			| 285 |  | -	BIOS_KEY ( "\x40", "[17~" )	/* F6 */
 | 
		
	
		
			
			| 286 |  | -	BIOS_KEY ( "\x41", "[18~" )	/* F7 */
 | 
		
	
		
			
			| 287 |  | -	BIOS_KEY ( "\x42", "[19~" )	/* F8 (required for PXE) */
 | 
		
	
		
			
			| 288 |  | -	BIOS_KEY ( "\x43", "[20~" )	/* F9 */
 | 
		
	
		
			
			| 289 |  | -	BIOS_KEY ( "\x44", "[21~" )	/* F10 */
 | 
		
	
		
			
			| 290 |  | -	BIOS_KEY ( "\x85", "[23~" )	/* F11 */
 | 
		
	
		
			
			| 291 |  | -	BIOS_KEY ( "\x86", "[24~" )	/* F12 */
 | 
		
	
		
			
			|  | 282 | +static const char *bios_ansi_input = "";
 | 
		
	
		
			
			|  | 283 | +
 | 
		
	
		
			
			|  | 284 | +/** A BIOS key */
 | 
		
	
		
			
			|  | 285 | +struct bios_key {
 | 
		
	
		
			
			|  | 286 | +	/** Scancode */
 | 
		
	
		
			
			|  | 287 | +	uint8_t scancode;
 | 
		
	
		
			
			|  | 288 | +	/** Key code */
 | 
		
	
		
			
			|  | 289 | +	uint16_t key;
 | 
		
	
		
			
			|  | 290 | +} __attribute__ (( packed ));
 | 
		
	
		
			
			|  | 291 | +
 | 
		
	
		
			
			|  | 292 | +/** Mapping from BIOS scan codes to iPXE key codes */
 | 
		
	
		
			
			|  | 293 | +static const struct bios_key bios_keys[] = {
 | 
		
	
		
			
			|  | 294 | +	{ 0x53, KEY_DC },
 | 
		
	
		
			
			|  | 295 | +	{ 0x48, KEY_UP },
 | 
		
	
		
			
			|  | 296 | +	{ 0x50, KEY_DOWN },
 | 
		
	
		
			
			|  | 297 | +	{ 0x4b, KEY_LEFT },
 | 
		
	
		
			
			|  | 298 | +	{ 0x4d, KEY_RIGHT },
 | 
		
	
		
			
			|  | 299 | +	{ 0x47, KEY_HOME },
 | 
		
	
		
			
			|  | 300 | +	{ 0x4f, KEY_END },
 | 
		
	
		
			
			|  | 301 | +	{ 0x49, KEY_PPAGE },
 | 
		
	
		
			
			|  | 302 | +	{ 0x51, KEY_NPAGE },
 | 
		
	
		
			
			|  | 303 | +	{ 0x3f, KEY_F5 },
 | 
		
	
		
			
			|  | 304 | +	{ 0x40, KEY_F6 },
 | 
		
	
		
			
			|  | 305 | +	{ 0x41, KEY_F7 },
 | 
		
	
		
			
			|  | 306 | +	{ 0x42, KEY_F8 },
 | 
		
	
		
			
			|  | 307 | +	{ 0x43, KEY_F9 },
 | 
		
	
		
			
			|  | 308 | +	{ 0x44, KEY_F10 },
 | 
		
	
		
			
			|  | 309 | +	{ 0x85, KEY_F11 },
 | 
		
	
		
			
			|  | 310 | +	{ 0x86, KEY_F12 },
 | 
		
	
		
			
			| 292 | 311 |  };
 | 
		
	
		
			
			| 293 | 312 |  
 | 
		
	
		
			
			| 294 | 313 |  /**
 | 
		
	
	
		
			
			|  | @@ -297,14 +316,35 @@ static const char ansi_sequences[] = {
 | 
		
	
		
			
			| 297 | 316 |   * @v scancode		BIOS scancode
 | 
		
	
		
			
			| 298 | 317 |   * @ret ansi_seq	ANSI escape sequence, if any, otherwise NULL
 | 
		
	
		
			
			| 299 | 318 |   */
 | 
		
	
		
			
			| 300 |  | -static const char * scancode_to_ansi_seq ( unsigned int scancode ) {
 | 
		
	
		
			
			| 301 |  | -	const char *seq = ansi_sequences;
 | 
		
	
		
			
			| 302 |  | -
 | 
		
	
		
			
			| 303 |  | -	while ( *seq ) {
 | 
		
	
		
			
			| 304 |  | -		if ( *(seq++) == ( ( char ) scancode ) )
 | 
		
	
		
			
			| 305 |  | -			return seq;
 | 
		
	
		
			
			| 306 |  | -		seq += ( strlen ( seq ) + 1 );
 | 
		
	
		
			
			|  | 319 | +static const char * bios_ansi_seq ( unsigned int scancode ) {
 | 
		
	
		
			
			|  | 320 | +	static char buf[ 5 /* "[" + two digits + terminator + NUL */ ];
 | 
		
	
		
			
			|  | 321 | +	unsigned int key;
 | 
		
	
		
			
			|  | 322 | +	unsigned int terminator;
 | 
		
	
		
			
			|  | 323 | +	unsigned int n;
 | 
		
	
		
			
			|  | 324 | +	unsigned int i;
 | 
		
	
		
			
			|  | 325 | +	char *tmp = buf;
 | 
		
	
		
			
			|  | 326 | +
 | 
		
	
		
			
			|  | 327 | +	/* Construct ANSI escape sequence for scancode, if known */
 | 
		
	
		
			
			|  | 328 | +	for ( i = 0 ; i < ( sizeof ( bios_keys ) /
 | 
		
	
		
			
			|  | 329 | +			    sizeof ( bios_keys[0] ) ) ; i++ ) {
 | 
		
	
		
			
			|  | 330 | +
 | 
		
	
		
			
			|  | 331 | +		/* Look for matching scancode */
 | 
		
	
		
			
			|  | 332 | +		if ( bios_keys[i].scancode != scancode )
 | 
		
	
		
			
			|  | 333 | +			continue;
 | 
		
	
		
			
			|  | 334 | +
 | 
		
	
		
			
			|  | 335 | +		/* Construct escape sequence */
 | 
		
	
		
			
			|  | 336 | +		key = bios_keys[i].key;
 | 
		
	
		
			
			|  | 337 | +		n = KEY_ANSI_N ( key );
 | 
		
	
		
			
			|  | 338 | +		terminator = KEY_ANSI_TERMINATOR ( key );
 | 
		
	
		
			
			|  | 339 | +		*(tmp++) = '[';
 | 
		
	
		
			
			|  | 340 | +		if ( n )
 | 
		
	
		
			
			|  | 341 | +			tmp += sprintf ( tmp, "%d", n );
 | 
		
	
		
			
			|  | 342 | +		*(tmp++) = terminator;
 | 
		
	
		
			
			|  | 343 | +		*(tmp++) = '\0';
 | 
		
	
		
			
			|  | 344 | +		assert ( tmp <= &buf[ sizeof ( buf ) ] );
 | 
		
	
		
			
			|  | 345 | +		return buf;
 | 
		
	
		
			
			| 307 | 346 |  	}
 | 
		
	
		
			
			|  | 347 | +
 | 
		
	
		
			
			| 308 | 348 |  	DBG ( "Unrecognised BIOS scancode %02x\n", scancode );
 | 
		
	
		
			
			| 309 | 349 |  	return NULL;
 | 
		
	
		
			
			| 310 | 350 |  }
 | 
		
	
	
		
			
			|  | @@ -336,16 +376,23 @@ static int bios_getchar ( void ) {
 | 
		
	
		
			
			| 336 | 376 |  	const char *ansi_seq;
 | 
		
	
		
			
			| 337 | 377 |  
 | 
		
	
		
			
			| 338 | 378 |  	/* If we are mid-sequence, pass out the next byte */
 | 
		
	
		
			
			| 339 |  | -	if ( ( character = *ansi_input ) ) {
 | 
		
	
		
			
			| 340 |  | -		ansi_input++;
 | 
		
	
		
			
			|  | 379 | +	if ( ( character = *bios_ansi_input ) ) {
 | 
		
	
		
			
			|  | 380 | +		bios_ansi_input++;
 | 
		
	
		
			
			| 341 | 381 |  		return character;
 | 
		
	
		
			
			| 342 | 382 |  	}
 | 
		
	
		
			
			| 343 | 383 |  
 | 
		
	
		
			
			|  | 384 | +	/* Do nothing if injection is in progress */
 | 
		
	
		
			
			|  | 385 | +	if ( bios_inject_lock )
 | 
		
	
		
			
			|  | 386 | +		return 0;
 | 
		
	
		
			
			|  | 387 | +
 | 
		
	
		
			
			| 344 | 388 |  	/* Read character from real BIOS console */
 | 
		
	
		
			
			|  | 389 | +	bios_inject_lock++;
 | 
		
	
		
			
			| 345 | 390 |  	__asm__ __volatile__ ( REAL_CODE ( "sti\n\t"
 | 
		
	
		
			
			| 346 | 391 |  					   "int $0x16\n\t"
 | 
		
	
		
			
			| 347 | 392 |  					   "cli\n\t" )
 | 
		
	
		
			
			| 348 |  | -			       : "=a" ( keypress ) : "a" ( 0x1000 ) );
 | 
		
	
		
			
			|  | 393 | +			       : "=a" ( keypress )
 | 
		
	
		
			
			|  | 394 | +			       : "a" ( 0x1000 ), "m" ( bios_inject_lock ) );
 | 
		
	
		
			
			|  | 395 | +	bios_inject_lock--;
 | 
		
	
		
			
			| 349 | 396 |  	character = ( keypress & 0xff );
 | 
		
	
		
			
			| 350 | 397 |  
 | 
		
	
		
			
			| 351 | 398 |  	/* If it's a normal character, just map and return it */
 | 
		
	
	
		
			
			|  | @@ -353,9 +400,9 @@ static int bios_getchar ( void ) {
 | 
		
	
		
			
			| 353 | 400 |  		return bios_keymap ( character );
 | 
		
	
		
			
			| 354 | 401 |  
 | 
		
	
		
			
			| 355 | 402 |  	/* Otherwise, check for a special key that we know about */
 | 
		
	
		
			
			| 356 |  | -	if ( ( ansi_seq = scancode_to_ansi_seq ( keypress >> 8 ) ) ) {
 | 
		
	
		
			
			|  | 403 | +	if ( ( ansi_seq = bios_ansi_seq ( keypress >> 8 ) ) ) {
 | 
		
	
		
			
			| 357 | 404 |  		/* Start of escape sequence: return ESC (0x1b) */
 | 
		
	
		
			
			| 358 |  | -		ansi_input = ansi_seq;
 | 
		
	
		
			
			|  | 405 | +		bios_ansi_input = ansi_seq;
 | 
		
	
		
			
			| 359 | 406 |  		return 0x1b;
 | 
		
	
		
			
			| 360 | 407 |  	}
 | 
		
	
		
			
			| 361 | 408 |  
 | 
		
	
	
		
			
			|  | @@ -373,23 +420,147 @@ static int bios_iskey ( void ) {
 | 
		
	
		
			
			| 373 | 420 |  	unsigned int flags;
 | 
		
	
		
			
			| 374 | 421 |  
 | 
		
	
		
			
			| 375 | 422 |  	/* If we are mid-sequence, we are always ready */
 | 
		
	
		
			
			| 376 |  | -	if ( *ansi_input )
 | 
		
	
		
			
			|  | 423 | +	if ( *bios_ansi_input )
 | 
		
	
		
			
			| 377 | 424 |  		return 1;
 | 
		
	
		
			
			| 378 | 425 |  
 | 
		
	
		
			
			|  | 426 | +	/* Do nothing if injection is in progress */
 | 
		
	
		
			
			|  | 427 | +	if ( bios_inject_lock )
 | 
		
	
		
			
			|  | 428 | +		return 0;
 | 
		
	
		
			
			|  | 429 | +
 | 
		
	
		
			
			| 379 | 430 |  	/* Otherwise check the real BIOS console */
 | 
		
	
		
			
			|  | 431 | +	bios_inject_lock++;
 | 
		
	
		
			
			| 380 | 432 |  	__asm__ __volatile__ ( REAL_CODE ( "sti\n\t"
 | 
		
	
		
			
			| 381 | 433 |  					   "int $0x16\n\t"
 | 
		
	
		
			
			| 382 | 434 |  					   "pushfw\n\t"
 | 
		
	
		
			
			| 383 | 435 |  					   "popw %w0\n\t"
 | 
		
	
		
			
			| 384 | 436 |  					   "cli\n\t" )
 | 
		
	
		
			
			| 385 | 437 |  			       : "=r" ( flags ), "=a" ( discard_a )
 | 
		
	
		
			
			| 386 |  | -			       : "a" ( 0x1100 ) );
 | 
		
	
		
			
			|  | 438 | +			       : "a" ( 0x1100 ), "m" ( bios_inject_lock ) );
 | 
		
	
		
			
			|  | 439 | +	bios_inject_lock--;
 | 
		
	
		
			
			| 387 | 440 |  	return ( ! ( flags & ZF ) );
 | 
		
	
		
			
			| 388 | 441 |  }
 | 
		
	
		
			
			| 389 | 442 |  
 | 
		
	
		
			
			|  | 443 | +/** BIOS console */
 | 
		
	
		
			
			| 390 | 444 |  struct console_driver bios_console __console_driver = {
 | 
		
	
		
			
			| 391 | 445 |  	.putchar = bios_putchar,
 | 
		
	
		
			
			| 392 | 446 |  	.getchar = bios_getchar,
 | 
		
	
		
			
			| 393 | 447 |  	.iskey = bios_iskey,
 | 
		
	
		
			
			| 394 | 448 |  	.usage = CONSOLE_PCBIOS,
 | 
		
	
		
			
			| 395 | 449 |  };
 | 
		
	
		
			
			|  | 450 | +
 | 
		
	
		
			
			|  | 451 | +/**
 | 
		
	
		
			
			|  | 452 | + * Inject keypresses
 | 
		
	
		
			
			|  | 453 | + *
 | 
		
	
		
			
			|  | 454 | + * @v ix86		Registers as passed to INT 16
 | 
		
	
		
			
			|  | 455 | + */
 | 
		
	
		
			
			|  | 456 | +static __asmcall void bios_inject ( struct i386_all_regs *ix86 ) {
 | 
		
	
		
			
			|  | 457 | +	unsigned int discard_a;
 | 
		
	
		
			
			|  | 458 | +	unsigned int scancode;
 | 
		
	
		
			
			|  | 459 | +	unsigned int i;
 | 
		
	
		
			
			|  | 460 | +	uint16_t keypress;
 | 
		
	
		
			
			|  | 461 | +	int key;
 | 
		
	
		
			
			|  | 462 | +
 | 
		
	
		
			
			|  | 463 | +	/* If this is a blocking call, then loop until the
 | 
		
	
		
			
			|  | 464 | +	 * non-blocking variant of the call indicates that a keypress
 | 
		
	
		
			
			|  | 465 | +	 * is available.  Do this without acquiring the injection
 | 
		
	
		
			
			|  | 466 | +	 * lock, so that injection may take place.
 | 
		
	
		
			
			|  | 467 | +	 */
 | 
		
	
		
			
			|  | 468 | +	if ( ( ix86->regs.ah & ~0x10 ) == 0x00 ) {
 | 
		
	
		
			
			|  | 469 | +		__asm__ __volatile__ ( REAL_CODE ( "sti\n\t"
 | 
		
	
		
			
			|  | 470 | +						   "\n1:\n\t"
 | 
		
	
		
			
			|  | 471 | +						   "pushw %%ax\n\t"
 | 
		
	
		
			
			|  | 472 | +						   "int $0x16\n\t"
 | 
		
	
		
			
			|  | 473 | +						   "popw %%ax\n\t"
 | 
		
	
		
			
			|  | 474 | +						   "jc 2f\n\t"
 | 
		
	
		
			
			|  | 475 | +						   "jz 1b\n\t"
 | 
		
	
		
			
			|  | 476 | +						   "\n2:\n\t"
 | 
		
	
		
			
			|  | 477 | +						   "cli\n\t" )
 | 
		
	
		
			
			|  | 478 | +				       : "=a" ( discard_a )
 | 
		
	
		
			
			|  | 479 | +				       : "a" ( ix86->regs.eax | 0x0100 ),
 | 
		
	
		
			
			|  | 480 | +					 "m" ( bios_inject_lock ) );
 | 
		
	
		
			
			|  | 481 | +	}
 | 
		
	
		
			
			|  | 482 | +
 | 
		
	
		
			
			|  | 483 | +	/* Acquire injection lock */
 | 
		
	
		
			
			|  | 484 | +	bios_inject_lock++;
 | 
		
	
		
			
			|  | 485 | +
 | 
		
	
		
			
			|  | 486 | +	/* Check for keypresses */
 | 
		
	
		
			
			|  | 487 | +	if ( iskey() ) {
 | 
		
	
		
			
			|  | 488 | +
 | 
		
	
		
			
			|  | 489 | +		/* Get key */
 | 
		
	
		
			
			|  | 490 | +		key = getkey ( 0 );
 | 
		
	
		
			
			|  | 491 | +
 | 
		
	
		
			
			|  | 492 | +		/* Reverse internal CR->LF mapping */
 | 
		
	
		
			
			|  | 493 | +		if ( key == '\n' )
 | 
		
	
		
			
			|  | 494 | +			key = '\r';
 | 
		
	
		
			
			|  | 495 | +
 | 
		
	
		
			
			|  | 496 | +		/* Convert to keypress */
 | 
		
	
		
			
			|  | 497 | +		keypress = ( ( key << 8 ) | key );
 | 
		
	
		
			
			|  | 498 | +
 | 
		
	
		
			
			|  | 499 | +		/* Handle special keys */
 | 
		
	
		
			
			|  | 500 | +		if ( key >= KEY_MIN ) {
 | 
		
	
		
			
			|  | 501 | +			for ( i = 0 ; i < ( sizeof ( bios_keys ) /
 | 
		
	
		
			
			|  | 502 | +					    sizeof ( bios_keys[0] ) ) ; i++ ) {
 | 
		
	
		
			
			|  | 503 | +				if ( bios_keys[i].key == key ) {
 | 
		
	
		
			
			|  | 504 | +					scancode = bios_keys[i].scancode;
 | 
		
	
		
			
			|  | 505 | +					keypress = ( scancode << 8 );
 | 
		
	
		
			
			|  | 506 | +					break;
 | 
		
	
		
			
			|  | 507 | +				}
 | 
		
	
		
			
			|  | 508 | +			}
 | 
		
	
		
			
			|  | 509 | +		}
 | 
		
	
		
			
			|  | 510 | +
 | 
		
	
		
			
			|  | 511 | +		/* Inject keypress */
 | 
		
	
		
			
			|  | 512 | +		DBGC ( &bios_console, "BIOS injecting keypress %04x\n",
 | 
		
	
		
			
			|  | 513 | +		       keypress );
 | 
		
	
		
			
			|  | 514 | +		__asm__ __volatile__ ( REAL_CODE ( "int $0x16\n\t" )
 | 
		
	
		
			
			|  | 515 | +				       : "=a" ( discard_a )
 | 
		
	
		
			
			|  | 516 | +				       : "a" ( 0x0500 ), "c" ( keypress ),
 | 
		
	
		
			
			|  | 517 | +					 "m" ( bios_inject_lock ) );
 | 
		
	
		
			
			|  | 518 | +	}
 | 
		
	
		
			
			|  | 519 | +
 | 
		
	
		
			
			|  | 520 | +	/* Release injection lock */
 | 
		
	
		
			
			|  | 521 | +	bios_inject_lock--;
 | 
		
	
		
			
			|  | 522 | +}
 | 
		
	
		
			
			|  | 523 | +
 | 
		
	
		
			
			|  | 524 | +/**
 | 
		
	
		
			
			|  | 525 | + * Start up keypress injection
 | 
		
	
		
			
			|  | 526 | + *
 | 
		
	
		
			
			|  | 527 | + */
 | 
		
	
		
			
			|  | 528 | +static void bios_inject_startup ( void ) {
 | 
		
	
		
			
			|  | 529 | +
 | 
		
	
		
			
			|  | 530 | +	/* Assembly wrapper to call bios_inject() */
 | 
		
	
		
			
			|  | 531 | +	__asm__ __volatile__ (
 | 
		
	
		
			
			|  | 532 | +		TEXT16_CODE ( "\nint16_wrapper:\n\t"
 | 
		
	
		
			
			|  | 533 | +			      "pushfw\n\t"
 | 
		
	
		
			
			|  | 534 | +			      "cmpb $0, %%cs:bios_inject_lock\n\t"
 | 
		
	
		
			
			|  | 535 | +			      "jnz 1f\n\t"
 | 
		
	
		
			
			|  | 536 | +			      "pushl %0\n\t"
 | 
		
	
		
			
			|  | 537 | +			      "pushw %%cs\n\t"
 | 
		
	
		
			
			|  | 538 | +			      "call prot_call\n\t"
 | 
		
	
		
			
			|  | 539 | +			      "addw $4, %%sp\n\t"
 | 
		
	
		
			
			|  | 540 | +			      "\n1:\n\t"
 | 
		
	
		
			
			|  | 541 | +			      "popfw\n\t"
 | 
		
	
		
			
			|  | 542 | +			      "ljmp *%%cs:int16_vector\n\t" )
 | 
		
	
		
			
			|  | 543 | +		: : "i" ( bios_inject ) );
 | 
		
	
		
			
			|  | 544 | +
 | 
		
	
		
			
			|  | 545 | +	/* Hook INT 16 */
 | 
		
	
		
			
			|  | 546 | +	hook_bios_interrupt ( 0x16, ( ( unsigned int ) int16_wrapper ),
 | 
		
	
		
			
			|  | 547 | +			      &int16_vector );
 | 
		
	
		
			
			|  | 548 | +}
 | 
		
	
		
			
			|  | 549 | +
 | 
		
	
		
			
			|  | 550 | +/**
 | 
		
	
		
			
			|  | 551 | + * Shut down keypress injection
 | 
		
	
		
			
			|  | 552 | + *
 | 
		
	
		
			
			|  | 553 | + * @v booting		System is shutting down for OS boot
 | 
		
	
		
			
			|  | 554 | + */
 | 
		
	
		
			
			|  | 555 | +static void bios_inject_shutdown ( int booting __unused ) {
 | 
		
	
		
			
			|  | 556 | +
 | 
		
	
		
			
			|  | 557 | +	/* Unhook INT 16 */
 | 
		
	
		
			
			|  | 558 | +	unhook_bios_interrupt ( 0x16, ( ( unsigned int ) int16_wrapper ),
 | 
		
	
		
			
			|  | 559 | +				&int16_vector );
 | 
		
	
		
			
			|  | 560 | +}
 | 
		
	
		
			
			|  | 561 | +
 | 
		
	
		
			
			|  | 562 | +/** Keypress injection startup function */
 | 
		
	
		
			
			|  | 563 | +struct startup_fn bios_inject_startup_fn __startup_fn ( STARTUP_NORMAL ) = {
 | 
		
	
		
			
			|  | 564 | +	.startup = bios_inject_startup,
 | 
		
	
		
			
			|  | 565 | +	.shutdown = bios_inject_shutdown,
 | 
		
	
		
			
			|  | 566 | +};
 |