From 42afef19ebde9f8e69296dc9de718db8483e43e9 Mon Sep 17 00:00:00 2001 From: okuji Date: Wed, 20 Oct 1999 20:13:15 +0000 Subject: [PATCH] add the command map. --- ChangeLog | 24 ++++++++ NEWS | 3 + grub/asmstub.c | 6 ++ stage2/asm.S | 141 ++++++++++++++++++++++++++++++++++++++++++++-- stage2/builtins.c | 82 +++++++++++++++++++++++++++ stage2/shared.h | 6 ++ 6 files changed, 257 insertions(+), 5 deletions(-) diff --git a/ChangeLog b/ChangeLog index 8d88a789b..a0b62214c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,27 @@ +1999-10-21 OKUJI Yoshinori + + Add BIOS drive remapping support for chain-loading some foolish + operating systems. + + * stage2/builtins.c (bios_drive_map): New variable. + (boot_func): If KERNEL_TYPE is KERNEL_TYPE_CHAINLOADER, check + if BIOS_DRIVE_MAP contains meaningful values. If so, search for + SAVED_DRIVE in BIOS_DRIVE_MAP and exchange SAVED_DRIVE with the + mapped drive if found. And then call set_int13_handler. + (map_func): New function. + (builtin_map): New variable. + (builtin_table): Added a pointer to BUILTIN_MAP. + * stage2/asm.S (ABS): New macro. + [!STAGE1_5] (set_int13_handler): New function. + [!STAGE1_5] (int13_handler): New interrupt handler for the real + mode. + [!STAGE1_5] (drive_map): New variable. + [!STAGE1_5] (int13_handler_end): New label used for just + computing the end address of int13_handler. + * stage2/shared.h (DRIVE_MAP_SIZE): New macro. + (set_int13_handler): Declared. + * grub/asmstub.c (set_int13_handler): New function. Do nothing. + 1999-10-20 OKUJI Yoshinori * stage2/builtins.c (find_func): Print only the device names. diff --git a/NEWS b/NEWS index e98f61132..973bb54bb 100644 --- a/NEWS +++ b/NEWS @@ -15,6 +15,9 @@ New in 0.5.94: added. * The command "find" searches for a filename in all devices and print the list of the device which contain the file. +* 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. New in 0.5.93: * ELF format of FreeBSD kernel is supported. diff --git a/grub/asmstub.c b/grub/asmstub.c index 62cd8bf8f..f884214a4 100644 --- a/grub/asmstub.c +++ b/grub/asmstub.c @@ -597,6 +597,12 @@ gateA20 (int linear) /* Nothing to do in the simulator. */ } +/* Copy MAP to the drive map and set up the int13 handler. */ +void +set_int13_handler (unsigned short *map) +{ + /* Nothing to do in the simulator. */ +} int get_code_end (void) diff --git a/stage2/asm.S b/stage2/asm.S index 7b0fbb613..26d6c8c15 100644 --- a/stage2/asm.S +++ b/stage2/asm.S @@ -22,6 +22,12 @@ #include "shared.h" +#ifdef STAGE1_5 +#define ABS(x) ((x) - EXT_C(main) + 0x2200) +#else +#define ABS(x) ((x) - EXT_C(main) + 0x8200) +#endif + .file "asm.S" .text @@ -46,11 +52,7 @@ ENTRY(main) * Guarantee that "main" is loaded at 0x0:0x8200 in stage2 and * at 0x0:0x2200 in stage1.5. */ -#ifndef STAGE1_5 - ljmp $0, $(codestart - EXT_C(main) + 0x8200) -#else - ljmp $0, $(codestart - EXT_C(main) + 0x2200) -#endif + ljmp $0, $ABS(codestart) /* * Compatibility version number @@ -153,6 +155,135 @@ ENTRY(stop_floppy) outb %al, %dx ret +/* + * set_int13_handler(map) + * + * Copy MAP to the drive map and set up int13_handler. + */ +ENTRY(set_int13_handler) + pushl %ebp + movl %esp, %ebp + + pushl %ecx + pushl %edi + pushl %esi + + /* copy MAP to the drive map */ + movl $DRIVE_MAP_SIZE, %ecx + movl $ABS(drive_map), %edi + movl 4(%ebp), %esi + cld + rep + movsb + + /* save the original int13 handler */ + movw 0x13 * 4, %ax + movw %ax, int13_offset + movw 0x13 * 4 + 2, %ax + movw %ax, int13_segment + + /* get the lower memory size */ + movl $EXT_C(mbi), %edi + movl 4(%edi), %eax + /* decrease the lower memory size and set it to the BIOS memory */ + decl %eax + movw %ax, 0x413 + /* compute the segment */ + shll $6, %eax + + /* save the new int13 handler */ + movw %ax, 0x13 * 4 + 2 + xorw %ax, %ax + movw %ax, 0x13 * 4 + + /* copy int13_handler to the reserved area */ + shll $4, %eax + movl %eax, %edi + movl $ABS(int13_handler), %esi + movl $(int13_handler_end - int13_handler), %ecx + rep + movsb + + popl %esi + popl %edi + popl %ecx + popl %ebp + ret + + +/* + * Map a drive to another drive. + */ + + .code16 + +int13_handler: + pushw %ax + pushw %bp + movw %sp, %bp + + pushw %ds + pushw %si + + /* set %ds to %cs */ + movw %cs, %ax + movw %ax, %ds + /* set %si to the drive map */ + movw $(drive_map - int13_handler), %si + /* find the drive number from the drive map */ +1: + lodsw + /* check if this is the end */ + testw %ax, %ax + jz 2f + /* check if this matches the drive number */ + cmpb %al, %dl + jne 1b + /* if so, perform the mapping */ + movb %ah, %dl +2: + /* restore %si and %ds */ + popw %si + popw %ds + /* save %ax in the stack */ + pushw %ax + /* set %ax and %bp to the original values */ + movw 2(%bp), %ax + movw (%bp), %bp + /* simulate the interrupt call */ + pushf + /* ljmp */ + .byte 0x9a +int13_offset: .word 0 +int13_segment: .word 0 + /* restore %bp */ + movw %sp, %bp + /* save %ax */ + pushw %ax + /* check if should map the drive number */ + movw 4(%bp), %ax + cmpw $0x8, %ax + jne 3f + cmpw $0x15, %ax + jne 3f + /* check if the mapping was performed */ + movw (%bp), %ax + testw %ax, %ax + jz 3f + /* perform the mapping */ + movb %al, %dl +3: + popw %ax + movw 2(%bp), %bp + addw $6, %sp + iret + +drive_map: .space (DRIVE_MAP_SIZE + 1) * 2 +int13_handler_end: + + .code32 + + /* * chain_stage1(segment, offset, part_table_addr) * diff --git a/stage2/builtins.c b/stage2/builtins.c index c2aa74608..4bafc6cbc 100644 --- a/stage2/builtins.c +++ b/stage2/builtins.c @@ -46,6 +46,8 @@ int normal_color; int highlight_color; /* The timeout. */ int grub_timeout = -1; +/* The BIOS drive map. */ +static unsigned short bios_drive_map[DRIVE_MAP_SIZE + 1]; /* Initialize the data for builtins. */ void @@ -101,6 +103,29 @@ boot_func (char *arg, int flags) case KERNEL_TYPE_CHAINLOADER: /* Chainloader */ + + /* Check if we should set the int13 handler. */ + if (bios_drive_map[0] != 0) + { + int i; + + /* Search for SAVED_DRIVE. */ + for (i = 0; i <= DRIVE_MAP_SIZE; i++) + { + if (! bios_drive_map[i]) + break; + else if ((bios_drive_map[i] & 0xFF) == saved_drive) + { + /* Exchage SAVED_DRIVE with the mapped drive. */ + saved_drive = (bios_drive_map[i] >> 8) & 0xFF; + break; + } + } + + /* Set the handler. This is somewhat dangerous. */ + set_int13_handler (bios_drive_map); + } + gateA20 (0); boot_drive = saved_drive; chain_stage1 (0, BOOTSEC_LOCATION, BOOTSEC_LOCATION - 16); @@ -1432,6 +1457,62 @@ static struct builtin builtin_makeactive = " This command is limited to _primary_ PC partitions on a hard disk." }; + +/* map */ +/* Map FROM_DRIVE to TO_DRIVE. */ +static int +map_func (char *arg, int flags) +{ + char *to_drive; + char *from_drive; + unsigned long to, from; + int i; + + to_drive = arg; + from_drive = skip_to (0, arg); + + /* Get the drive number for TO_DRIVE. */ + set_device (to_drive); + if (errnum) + return 1; + to = current_drive; + + /* Get the drive number for FROM_DRIVE. */ + set_device (from_drive); + if (errnum) + return 1; + from = current_drive; + + /* If TO and FROM is the same, do nothing. */ + if (to == from) + return 0; + + /* Search for an empty slot in BIOS_DRIVE_MAP. */ + for (i = 0; i <= DRIVE_MAP_SIZE; i++) + if (! bios_drive_map[i]) + break; + + if (i > DRIVE_MAP_SIZE) + { + errnum = ERR_WONT_FIT; + return 1; + } + + bios_drive_map[i] = from | (to << 8); + return 0; +} + +static struct builtin builtin_map = +{ + "map", + map_func, + BUILTIN_CMDLINE, + "map TO_DRIVE FROM_DRIVE", + "Map the drive FROM_DRIVE to the drive TO_DRIVE. This is necessary" + " when you chain-load some operating systems, such as DOS, if such a" + " OS resides at a non-first drive." +}; + /* module */ static int @@ -2101,6 +2182,7 @@ struct builtin *builtin_table[] = &builtin_install, &builtin_kernel, &builtin_makeactive, + &builtin_map, &builtin_module, &builtin_modulenounzip, &builtin_password, diff --git a/stage2/shared.h b/stage2/shared.h index f3652e320..cc6f432cd 100644 --- a/stage2/shared.h +++ b/stage2/shared.h @@ -117,6 +117,9 @@ extern char *grub_scratch_mem; #define MENU_BUF (UNIQUE_BUF + UNIQUE_BUFLEN) #define MENU_BUFLEN (0x8000 + PASSWORD_BUF - UNIQUE_BUF) +/* The size of the drive map. */ +#define DRIVE_MAP_SIZE 8 + /* * Linux setup parameters */ @@ -494,6 +497,9 @@ void cmain (void); /* Halt the processor (called after an unrecoverable error). */ void stop (void) __attribute__ ((noreturn)); +/* Copy MAP to the drive map and set up int13_handler. */ +void set_int13_handler (unsigned short *map); + /* calls for direct boot-loader chaining */ void chain_stage1 (int segment, int offset, int part_table_addr) __attribute__ ((noreturn));