diff --git a/ChangeLog b/ChangeLog index d4ce90df7..967602147 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,31 @@ +1999-10-23 OKUJI Yoshinori + + * stage2/asm.S [!STAGE1_5] (set_int15_handler): New function. + [!STAGE1_5] (unset_int15_handler): Likewise. + [!STAGE1_5] (int15_handler): New interrupt handler for the real + mode. + [!STAGE1_5] (int15_offset): New variable. + [!STAGE1_5] (int15_segment): Likewise. + [!STAGE1_5] (key_map): Likewise. + [!STAGE1_5] (set_int13_handler): Use the macro ABS for + INT13_OFFSET and INT13_SEGMENT. + * stage2/shared.h (KEY_MAP_SIZE): New macro. + (set_int15_handler): Declared. + (unset_int15_handler): Likewise. + * stage2/builtins.c (boot_func): Do not allow I to be equal to + DRIVE_MAP_SIZE. + Call unset_int15_handler unless KERNEL_TYPE is KERNEL_TYPE_NONE. + (map_func): Search for an empty slot till I is less than + DRIVE_MAP_SIZE. + Check if I is equal to DRIVE_MAP_SIZE instead of if I is greater + than DRIVE_MAP_SIZE. + (keycode_func): New function. + (builtin_keycode): New variable. + (builtin_table): Added a pointer to BUILTIN_KEYCODE. + * grub/asmstub.c (set_int15_handler): New function. + (unset_int15_handler): Likewise. + (key_map): New variable. + 1999-10-23 OKUJI Yoshinori From Michael Hohmuth : diff --git a/NEWS b/NEWS index 973bb54bb..8b296262a 100644 --- a/NEWS +++ b/NEWS @@ -18,6 +18,7 @@ New in 0.5.94: * The command "map" maps a drive to another drive so that we can chain-load some foolish operating systems (such as DOS) even if such an operating system resides at a non-first drive. +* The command "keycode" maps a key code to another. New in 0.5.93: * ELF format of FreeBSD kernel is supported. diff --git a/grub/asmstub.c b/grub/asmstub.c index f884214a4..3d09b9ae3 100644 --- a/grub/asmstub.c +++ b/grub/asmstub.c @@ -597,6 +597,23 @@ gateA20 (int linear) /* Nothing to do in the simulator. */ } +/* Set up the int15 handler. */ +void +set_int15_handler (void) +{ + /* Nothing to do in the simulator. */ +} + +/* Restore the original int15 handler. */ +void +unset_int15_handler (void) +{ + /* Nothing to do in the simulator. */ +} + +/* The key map. */ +unsigned short key_map[KEY_MAP_SIZE + 1]; + /* Copy MAP to the drive map and set up the int13 handler. */ void set_int13_handler (unsigned short *map) diff --git a/stage2/asm.S b/stage2/asm.S index ba9eabee1..36354b805 100644 --- a/stage2/asm.S +++ b/stage2/asm.S @@ -186,6 +186,107 @@ ENTRY(stop_floppy) outb %al, %dx ret +/* + * set_int15_handler(void) + * + * Set up int15_handler. + */ +ENTRY(set_int15_handler) + /* save the original int15 handler */ + movw 0x15 * 4, %ax + movw %ax, ABS(int15_offset) + movw 0x15 * 4 + 2, %ax + movw %ax, ABS(int15_segment) + + /* save the new int15 handler */ + movl $ABS(int15_handler), %eax + rorl $4, %eax + movw %ax, 0x15 * 4 + 2 + shrl $28, %eax + movw %ax, 0x15 * 4 + + ret + + +/* + * unset_int15_handler(void) + * + * Restore the original int15 handler + */ +ENTRY(unset_int15_handler) + /* check if int15_handler is set */ + movl $ABS(int15_handler), %eax + rorl $4, %eax + cmpw %ax, 0x15 * 4 + 2 + jne 1f + shrl $28, %eax + cmpw %ax, 0x15 * 4 + jne 1f + + /* restore the original */ + movw ABS(int15_offset), %ax + movw %ax, 0x15 * 4 + movw ABS(int15_segment), %ax + movw %ax, 0x15 * 4 + 2 + +1: + ret + + +/* + * Translate a key code to another. + */ + .code16 +int15_handler: + /* check if AH=4F */ + cmpb $0x4F, %ah + jmp 1f + + pushw %dx + pushw %ds + pushw %si + + /* save %ax in %dx */ + movw %ax, %dx + /* set %ds to 0 */ + xorw %ax, %ax + movw %ax, %ds + /* set %si to the key map */ + movw $ABS(key_map), %si + /* find the key code from the key map */ +2: + lodsw + /* check if this the end */ + testw %ax, %ax + jz 3f + /* check if this matches the key code */ + cmpb %al, %dl + jne 2b + /* if so, perform the mapping */ + movb %ah, %dl +3: + /* restore %ax */ + movw %dx, %ax + /* restore other registers */ + popw %si + popw %ds + popw %dx + iret +1: + /* simulate the interrupt call */ + pushf + /* ljmp */ + .byte 0x9a +int15_offset: .word 0 +int15_segment: .word 0 + iret + + .code32 + +ENTRY(key_map) + .space (KEY_MAP_SIZE + 1) * 2 + + /* * set_int13_handler(map) * @@ -209,9 +310,9 @@ ENTRY(set_int13_handler) /* save the original int13 handler */ movw 0x13 * 4, %ax - movw %ax, int13_offset + movw %ax, ABS(int13_offset) movw 0x13 * 4 + 2, %ax - movw %ax, int13_segment + movw %ax, ABS(int13_segment) /* get the lower memory size */ movl $EXT_C(mbi), %edi diff --git a/stage2/builtins.c b/stage2/builtins.c index 39ae9ab2e..bf38e54a4 100644 --- a/stage2/builtins.c +++ b/stage2/builtins.c @@ -83,6 +83,12 @@ disk_read_print_func (int sector) static int boot_func (char *arg, int flags) { + /* Clear the int15 handler if we can boot the kernel successfully. + This assumes that the boot code never fails only if KERNEL_TYPE is + not KERNEL_TYPE_NONE. Is this assumption is bad? */ + if (kernel_type != KERNEL_TYPE_NONE) + unset_int15_handler (); + switch (kernel_type) { case KERNEL_TYPE_FREEBSD: @@ -110,7 +116,7 @@ boot_func (char *arg, int flags) int i; /* Search for SAVED_DRIVE. */ - for (i = 0; i <= DRIVE_MAP_SIZE; i++) + for (i = 0; i < DRIVE_MAP_SIZE; i++) { if (! bios_drive_map[i]) break; @@ -1465,6 +1471,80 @@ static struct builtin builtin_kernel = " using this command." }; + +/* keycode */ +static int +keycode_func (char *arg, int flags) +{ + char *to_code, *from_code; + int to, from; + int i; + + to_code = arg; + from_code = skip_to (0, to_code); + + safe_parse_maxint (&to_code, &to); + if (errnum) + return 1; + if (to < 0 || to > 0xff) + { + /* FIXME: more appropriate error code! */ + errnum = ERR_NUMBER_PARSING; + return 1; + } + + safe_parse_maxint (&from_code, &from); + if (errnum) + return 1; + if (from < 0 || to > 0xff) + { + /* FIXME: more appropriate error code! */ + errnum = ERR_NUMBER_PARSING; + return 1; + } + + /* If TO is identical with FROM, do nothing. */ + if (to == from) + return 0; + + /* Find an empty slot. */ + for (i = 0; i < KEY_MAP_SIZE; i++) + { + if ((key_map[i] & 0xff) == from) + { + /* Perhaps the user wants to overwrite the map. */ + break; + } + + if (! key_map[i]) + break; + } + + if (i == KEY_MAP_SIZE) + { + errnum = ERR_WONT_FIT; + return 1; + } + + key_map[i] = (to << 8) | from; + + /* Ugly but should work. */ + unset_int15_handler (); + set_int15_handler (); + + return 0; +} + +static struct builtin builtin_keycode = +{ + "keycode", + keycode_func, + BUILTIN_CMDLINE | BUILTIN_MENU, + "keycode TO_CODE FROM_CODE", + "Change the keyboard map. The keycode FROM_CODE is mapped to the keycode" + " TO_CODE. They must be decimal or hexadecimal." +}; + /* makeactive */ static int @@ -1517,11 +1597,11 @@ map_func (char *arg, int flags) return 0; /* Search for an empty slot in BIOS_DRIVE_MAP. */ - for (i = 0; i <= DRIVE_MAP_SIZE; i++) + for (i = 0; i < DRIVE_MAP_SIZE; i++) if (! bios_drive_map[i]) break; - if (i > DRIVE_MAP_SIZE) + if (i == DRIVE_MAP_SIZE) { errnum = ERR_WONT_FIT; return 1; @@ -2217,6 +2297,7 @@ struct builtin *builtin_table[] = &builtin_initrd, &builtin_install, &builtin_kernel, + &builtin_keycode, &builtin_makeactive, &builtin_map, &builtin_module, diff --git a/stage2/shared.h b/stage2/shared.h index 3367f7699..c5efa9db8 100644 --- a/stage2/shared.h +++ b/stage2/shared.h @@ -120,6 +120,10 @@ extern char *grub_scratch_mem; /* The size of the drive map. */ #define DRIVE_MAP_SIZE 8 +/* The size of the key map. */ +#define KEY_MAP_SIZE 8 + + /* * Linux setup parameters */ @@ -500,6 +504,15 @@ void stop (void) __attribute__ ((noreturn)); /* Copy MAP to the drive map and set up int13_handler. */ void set_int13_handler (unsigned short *map); +/* Set up int15_handler. */ +void set_int15_handler (void); + +/* Restore the original int15 handler. */ +void unset_int15_handler (void); + +/* The key map. */ +extern unsigned short key_map[]; + /* calls for direct boot-loader chaining */ void chain_stage1 (int segment, int offset, int part_table_addr) __attribute__ ((noreturn));