diff --git a/include/grub/i386/pc/chainloader.h b/include/grub/i386/pc/chainloader.h index c28a42d..b9b65ad 100644 --- a/include/grub/i386/pc/chainloader.h +++ b/include/grub/i386/pc/chainloader.h @@ -22,12 +22,10 @@ #include /* Common function for normal and rescue mode commands. */ -typedef enum - { - GRUB_CHAINLOADER_FORCE = 0x1 - } grub_chainloader_flags_t; +#define GRUB_CHAINLOADER_FORCE 0x1 +#define GRUB_CHAINLOADER_KEEP_A20 0x2 void EXPORT_FUNC(grub_chainloader_cmd) (const char * file, - grub_chainloader_flags_t flags); + int flags); #endif /* GRUB_CHAINLOADER_MACHINE_HEADER */ diff --git a/include/grub/i386/pc/loader.h b/include/grub/i386/pc/loader.h index 3e03141..2405dbb 100644 --- a/include/grub/i386/pc/loader.h +++ b/include/grub/i386/pc/loader.h @@ -23,6 +23,6 @@ #include /* This is an asm part of the chainloader. */ -void EXPORT_FUNC(grub_chainloader_real_boot) (int drive, void *part_addr) __attribute__ ((noreturn)); +void EXPORT_FUNC(grub_chainloader_real_boot) (int drive, void *part_addr, int keep_a20) __attribute__ ((noreturn)); #endif /* ! GRUB_LOADER_MACHINE_HEADER */ diff --git a/kern/i386/pc/startup.S b/kern/i386/pc/startup.S index 9542978..e0edacc 100644 --- a/kern/i386/pc/startup.S +++ b/kern/i386/pc/startup.S @@ -594,7 +594,7 @@ FUNCTION(grub_halt) /* - * void grub_chainloader_real_boot (int drive, void *part_addr) + * void grub_chainloader_real_boot (int drive, void *part_addr, int keep_a20) * * This starts another boot loader. */ @@ -602,13 +602,19 @@ FUNCTION(grub_halt) FUNCTION(grub_chainloader_real_boot) pushl %edx pushl %eax + pushl %ecx call EXT_C(grub_dl_unload_all) + popl %ecx + orl %ecx, %ecx + jnz 1f + /* Turn off Gate A20 */ xorl %eax, %eax call EXT_C(grub_gate_a20) +1: /* set up to pass boot drive */ popl %edx diff --git a/loader/i386/pc/chainloader.c b/loader/i386/pc/chainloader.c index 825dbb3..fe2a932 100644 --- a/loader/i386/pc/chainloader.c +++ b/loader/i386/pc/chainloader.c @@ -35,11 +35,12 @@ static grub_dl_t my_mod; static int boot_drive; static void *boot_part_addr; +static int keep_a20; static grub_err_t grub_chainloader_boot (void) { - grub_chainloader_real_boot (boot_drive, boot_part_addr); + grub_chainloader_real_boot (boot_drive, boot_part_addr, keep_a20); /* Never reach here. */ return GRUB_ERR_NONE; @@ -53,7 +54,7 @@ grub_chainloader_unload (void) } void -grub_chainloader_cmd (const char *filename, grub_chainloader_flags_t flags) +grub_chainloader_cmd (const char *filename, int flags) { grub_file_t file = 0; grub_uint16_t signature; @@ -118,6 +119,7 @@ grub_chainloader_cmd (const char *filename, grub_chainloader_flags_t flags) boot_drive = drive; boot_part_addr = part_addr; + keep_a20 = ((flags & GRUB_CHAINLOADER_KEEP_A20) != 0); grub_loader_set (grub_chainloader_boot, grub_chainloader_unload, 1); return; @@ -133,7 +135,7 @@ grub_chainloader_cmd (const char *filename, grub_chainloader_flags_t flags) static void grub_rescue_cmd_chainloader (int argc, char *argv[]) { - grub_chainloader_flags_t flags = 0; + int flags = 0; if (argc > 0 && grub_strcmp (argv[0], "--force") == 0) { @@ -142,6 +144,13 @@ grub_rescue_cmd_chainloader (int argc, char *argv[]) argv++; } + if (argc > 0 && grub_strcmp (argv[0], "--keep-a20") == 0) + { + flags |= GRUB_CHAINLOADER_KEEP_A20; + argc--; + argv++; + } + if (argc == 0) grub_error (GRUB_ERR_BAD_ARGUMENT, "no file specified"); else diff --git a/loader/i386/pc/chainloader_normal.c b/loader/i386/pc/chainloader_normal.c index 106cd56..8bae1a3 100644 --- a/loader/i386/pc/chainloader_normal.c +++ b/loader/i386/pc/chainloader_normal.c @@ -25,6 +25,7 @@ static const struct grub_arg_option options[] = { {"force", 'f', 0, "skip bootsector magic number test", 0, 0}, + {"keep-a20", 'k', 0, "keep a20 gate enabled", 0, 0}, {0, 0, 0, 0, 0, 0} }; @@ -32,7 +33,13 @@ static grub_err_t chainloader_command (struct grub_arg_list *state, int argc, char **args) { - grub_chainloader_flags_t flags = state[0].set ? GRUB_CHAINLOADER_FORCE : 0; + int flags = 0; + + if (state[0].set) + flags |= GRUB_CHAINLOADER_FORCE; + + if (state[1].set) + flags |= GRUB_CHAINLOADER_KEEP_A20; if (argc == 0) grub_error (GRUB_ERR_BAD_ARGUMENT, "no file specified"); diff --git a/util/i386/pc/grub-setup.c b/util/i386/pc/grub-setup.c index 043484e..ecf1682 100644 --- a/util/i386/pc/grub-setup.c +++ b/util/i386/pc/grub-setup.c @@ -393,7 +393,7 @@ setup (const char *dir, != (grub_ssize_t) core_size) grub_util_info ("succeeded in opening the core image but cannot read %d bytes", (int) core_size); - else if (memcmp (core_img, tmp_img, core_size) != 0) + else if (memcmp (core_img + 1024, tmp_img + 1024, core_size - 1024) != 0) { #if 0 FILE *dump;