]> git.ipfire.org Git - thirdparty/grub.git/commitdiff
Move chainloader_real_boot out of the kernel
authorVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Thu, 20 Oct 2011 22:16:59 +0000 (00:16 +0200)
committerVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Thu, 20 Oct 2011 22:16:59 +0000 (00:16 +0200)
grub-core/Makefile.am
grub-core/kern/i386/pc/startup.S
grub-core/lib/i386/reboot.c
grub-core/lib/i386/relocator.c
grub-core/lib/i386/relocator16.S
grub-core/loader/i386/pc/chainloader.c
grub-core/loader/i386/pc/freedos.c
grub-core/loader/i386/pc/linux.c
grub-core/loader/i386/pc/ntldr.c
include/grub/i386/pc/loader.h [deleted file]
include/grub/i386/relocator.h

index 3bd192602a2fc92cee0020e76f74a79818ec38b7..4a46e1d9cb425c69b0b3f8e2324881deff198ab5 100644 (file)
@@ -83,7 +83,6 @@ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/libgcc.h
 KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/memory.h
 
 if COND_i386_pc
-KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/loader.h
 KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/kernel.h
 KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/pxe.h
 KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/int.h
index a0ef71f909ad904cc9de39d8ce7896bcea195612..e75f3ab90f76b86980d64b324de8ed0c0f8bd9f7 100644 (file)
@@ -463,31 +463,6 @@ FUNCTION(grub_exit)
        ljmp    $0xf000, $0xfff0
        .code32
 
-/*
- *  void grub_chainloader_real_boot (int drive, void *part_addr)
- *
- *  This starts another boot loader.
- */
-
-FUNCTION(grub_chainloader_real_boot)
-       pushl   %edx
-       pushl   %eax
-
-       /* Turn off Gate A20 */
-       xorl    %eax, %eax
-       call    grub_gate_a20
-
-       /* set up to pass boot drive */
-       popl    %edx
-
-       /* ESI must point to a partition table entry */
-       popl    %esi
-
-       call    prot_to_real
-       .code16
-       ljmp    $0, $GRUB_MEMORY_MACHINE_BOOT_LOADER_ADDR
-       .code32
-
 /*
  * void grub_console_putchar (int c)
  *
index ef28f7f65c2841b9af14c8de1f283d95e6587150..45a2259cfdb9fed1e05cf7c3716def1142bcb91a 100644 (file)
@@ -49,6 +49,7 @@ grub_reboot (void)
   state.sp = 0;
   state.cs = segment;
   state.ip = 0;
+  state.a20 = 0;
 
   grub_stop_floppy ();
   
index 2f10feb5e9344bf7a2b09722a98fe76eea4bf368..1f0aa0dd1b476382f8fcfd28285e116500bc7c09 100644 (file)
@@ -51,6 +51,9 @@ extern grub_uint16_t grub_relocator16_ss;
 extern grub_uint16_t grub_relocator16_sp;
 extern grub_uint32_t grub_relocator16_edx;
 extern grub_uint32_t grub_relocator16_ebx;
+extern grub_uint32_t grub_relocator16_esi;
+
+extern grub_uint16_t grub_relocator16_keep_a20_enabled;
 
 extern grub_uint8_t grub_relocator32_start;
 extern grub_uint8_t grub_relocator32_end;
@@ -195,7 +198,8 @@ grub_relocator16_boot (struct grub_relocator *rel,
   void *relst;
   grub_relocator_chunk_t ch;
 
-  err = grub_relocator_alloc_chunk_align (rel, &ch, 0,
+  /* Put it higher than the byte it checks for A20 check.  */
+  err = grub_relocator_alloc_chunk_align (rel, &ch, 0x8010,
                                          0xa0000 - RELOCATOR_SIZEOF (16),
                                          RELOCATOR_SIZEOF (16), 16,
                                          GRUB_RELOCATOR_PREFERENCE_NONE);
@@ -215,6 +219,9 @@ grub_relocator16_boot (struct grub_relocator *rel,
 
   grub_relocator16_ebx = state.ebx;
   grub_relocator16_edx = state.edx;
+  grub_relocator16_esi = state.esi;
+
+  grub_relocator16_keep_a20_enabled = state.a20;
 
   grub_memmove (get_virtual_current_address (ch), &grub_relocator16_start,
                RELOCATOR_SIZEOF (16));
index d6673fade12473a9fcabcc1dcdaefde88d49d2fe..babe69e1d2f7d31868bb110a88b9f5050ebb7cec 100644 (file)
@@ -93,6 +93,85 @@ LOCAL(segment):
        .word   0
 
 LOCAL(cont3):
+
+       /* movw imm16, %ax.  */
+       .byte   0xb8
+VARIABLE(grub_relocator16_keep_a20_enabled)
+       .word   0
+       test    %ax, %ax
+       jnz     LOCAL(gate_a20_done)
+
+       /* first of all, test if already in a good state */
+       call    LOCAL(gate_a20_check_state)
+       testb   %al, %al
+       jz      LOCAL(gate_a20_done)
+
+       /* second, try a BIOS call */
+       movw    $0x2400, %ax
+       int     $0x15
+
+       call    LOCAL(gate_a20_check_state)
+       testb   %al, %al
+       jz      LOCAL(gate_a20_done)
+
+       /*
+        * In macbook, the keyboard test would hang the machine, so we move
+        * this forward.
+        */
+       /* fourth, try the system control port A */
+       inb     $0x92
+       andb    $(~0x03), %al
+       outb    $0x92
+
+       /* When turning off Gate A20, do not check the state strictly,
+          because a failure is not fatal usually, and Gate A20 is always
+          on some modern machines.  */
+       jmp     LOCAL(gate_a20_done)
+
+LOCAL(gate_a20_check_state):
+       /* iterate the checking for a while */
+       movw    $100, %cx
+1:
+       call    3f
+       testb   %al, %al
+       jz      2f
+       loop    1b
+2:
+       ret
+
+3:
+       xorw    %ax, %ax
+       movw    %ax, %ds
+       decw    %ax
+       movw    %ax, %es
+       xorw    %ax, %ax
+
+       movw    $0x8000, %ax
+       /* compare the byte at ADDR with that at 0x100000 + ADDR */
+       movw    %ax, %si
+       addw    $0x10, %ax
+       movw    %ax, %di
+
+       /* save the original byte in DL */
+       movb    %ds:(%si), %dl
+       movb    %es:(%di), %al
+       /* try to set one less value at ADDR */
+       movb    %al, %dh
+       decb    %dh
+       movb    %dh, %ds:(%si)
+       /* serialize */
+       outb    %al, $0x80
+       outb    %al, $0x80
+       /* obtain the value at 0x100000 + ADDR in CH */
+       movb    %es:(%di), %dh
+       /* this result is 1 if A20 is on or 0 if it is off */
+       subb    %dh, %al
+       xorb    $1, %al
+       /* restore the original */
+       movb    %dl, %es:(%di)
+       ret
+
+LOCAL(gate_a20_done):
        /* we are in real mode now
         * set up the real mode segment registers : DS, SS, ES
         */
@@ -132,6 +211,12 @@ VARIABLE(grub_relocator16_sp)
        .word   0
        movzwl  %ax, %esp
 
+       /* movw imm32, %eax.  */
+       .byte   0x66, 0xb8
+VARIABLE(grub_relocator16_esi)
+       .long   0
+       movl    %eax, %esi
+
        /* movw imm32, %edx.  */
        .byte   0x66, 0xba
 VARIABLE(grub_relocator16_edx)
index 8d6ec8f2012e3b3aaddc7208b0e4aa2299637f3d..929569921639701ba77e7dab573be89974a51c2b 100644 (file)
@@ -18,7 +18,6 @@
  */
 
 #include <grub/loader.h>
-#include <grub/machine/loader.h>
 #include <grub/machine/chainloader.h>
 #include <grub/machine/memory.h>
 #include <grub/file.h>
 #include <grub/mm.h>
 #include <grub/fat.h>
 #include <grub/ntfs.h>
+#include <grub/i386/relocator.h>
 
 GRUB_MOD_LICENSE ("GPLv3+");
 
 static grub_dl_t my_mod;
 static int boot_drive;
-static void *boot_part_addr;
+static grub_addr_t boot_part_addr;
+static struct grub_relocator *rel;
 
 typedef enum
   {
@@ -55,16 +56,29 @@ typedef enum
 static grub_err_t
 grub_chainloader_boot (void)
 {
+  struct grub_relocator16_state state = { 
+    .edx = boot_drive,
+    .esi = boot_part_addr,
+    .ds = 0,
+    .es = 0,
+    .fs = 0,
+    .gs = 0,
+    .ss = 0,
+    .cs = 0,
+    .sp = GRUB_MEMORY_MACHINE_BOOT_LOADER_ADDR,
+    .ip = GRUB_MEMORY_MACHINE_BOOT_LOADER_ADDR,
+    .a20 = 0
+  };
   grub_video_set_mode ("text", 0, 0);
-  grub_chainloader_real_boot (boot_drive, boot_part_addr);
 
-  /* Never reach here.  */
-  return GRUB_ERR_NONE;
+  return grub_relocator16_boot (rel, state);
 }
 
 static grub_err_t
 grub_chainloader_unload (void)
 {
+  grub_relocator_unload (rel);
+  rel = NULL;
   grub_dl_unref (my_mod);
   return GRUB_ERR_NONE;
 }
@@ -133,7 +147,12 @@ grub_chainloader_cmd (const char *filename, grub_chainloader_flags_t flags)
   grub_uint16_t signature;
   grub_device_t dev;
   int drive = -1;
-  void *part_addr = 0;
+  grub_addr_t part_addr = 0;
+  grub_uint8_t *bs, *ptable;
+
+  rel = grub_relocator_new ();
+  if (!rel)
+    goto fail;
 
   grub_dl_ref (my_mod);
 
@@ -142,8 +161,25 @@ grub_chainloader_cmd (const char *filename, grub_chainloader_flags_t flags)
   if (! file)
     goto fail;
 
+  {
+    grub_relocator_chunk_t ch;
+    grub_err_t err;
+
+    err = grub_relocator_alloc_chunk_addr (rel, &ch, 0x7C00,
+                                          GRUB_DISK_SECTOR_SIZE);
+    if (err)
+      goto fail;
+    bs = get_virtual_current_address (ch);
+    err = grub_relocator_alloc_chunk_addr (rel, &ch,
+                                          GRUB_MEMORY_MACHINE_PART_TABLE_ADDR,
+                                          64);
+    if (err)
+      goto fail;
+    ptable = get_virtual_current_address (ch);
+  }
+
   /* Read the first block.  */
-  if (grub_file_read (file, (void *) 0x7C00, GRUB_DISK_SECTOR_SIZE)
+  if (grub_file_read (file, bs, GRUB_DISK_SECTOR_SIZE)
       != GRUB_DISK_SECTOR_SIZE)
     {
       if (grub_errno == GRUB_ERR_NONE)
@@ -153,7 +189,7 @@ grub_chainloader_cmd (const char *filename, grub_chainloader_flags_t flags)
     }
 
   /* Check the signature.  */
-  signature = *((grub_uint16_t *) (0x7C00 + GRUB_DISK_SECTOR_SIZE - 2));
+  signature = *((grub_uint16_t *) (bs + GRUB_DISK_SECTOR_SIZE - 2));
   if (signature != grub_le_to_cpu16 (0xaa55)
       && ! (flags & GRUB_CHAINLOADER_FORCE))
     {
@@ -177,10 +213,9 @@ grub_chainloader_cmd (const char *filename, grub_chainloader_flags_t flags)
          if (p && grub_strcmp (p->partmap->name, "msdos") == 0)
            {
              disk->partition = p->parent;
-             grub_disk_read (disk, p->offset, 446, 64,
-                             (void *) GRUB_MEMORY_MACHINE_PART_TABLE_ADDR);
-             part_addr = (void *) (GRUB_MEMORY_MACHINE_PART_TABLE_ADDR
-                                   + (p->index << 4));
+             grub_disk_read (disk, p->offset, 446, 64, ptable);
+             part_addr = (GRUB_MEMORY_MACHINE_PART_TABLE_ADDR
+                          + (p->index << 4));
              disk->partition = p;
            }
        }
index f796e08f4b128e1f8b67ccb1692fbdf24d50feaa..1f088e2b58103d2faa984066a49f5446846069e8 100644 (file)
@@ -56,7 +56,8 @@ grub_freedos_boot (void)
     .ss = GRUB_FREEDOS_STACK_SEGMENT,
     .sp = GRUB_FREEDOS_STACK_POINTER,
     .ebx = ebx,
-    .edx = 0
+    .edx = 0,
+    .a20 = 1
   };
   grub_video_set_mode ("text", 0, 0);
 
index adc6e8b995be3265e5df3ee3d6963998447b3bd9..c7c0991748a349be526adb72596161b9c7979f17 100644 (file)
@@ -18,7 +18,6 @@
  */
 
 #include <grub/loader.h>
-#include <grub/machine/loader.h>
 #include <grub/file.h>
 #include <grub/err.h>
 #include <grub/device.h>
@@ -61,6 +60,7 @@ grub_linux16_boot (void)
   state.sp = GRUB_LINUX_SETUP_STACK;
   state.cs = segment + 0x20;
   state.ip = 0;
+  state.a20 = 1;
 
   grub_video_set_mode ("text", 0, 0);
 
index b2909c191834cffe267e435a744dae1cd06834e2..153b605edc7d303b34627e0169603a6b0c2e60ec 100644 (file)
@@ -54,7 +54,8 @@ grub_ntldr_boot (void)
     .gs = 0,
     .ss = 0,
     .sp = 0x7c00,
-    .edx = edx
+    .edx = edx,
+    .a20 = 1
   };
   grub_video_set_mode ("text", 0, 0);
 
diff --git a/include/grub/i386/pc/loader.h b/include/grub/i386/pc/loader.h
deleted file mode 100644 (file)
index bfbcaac..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- *  GRUB  --  GRand Unified Bootloader
- *  Copyright (C) 2002,2003,2004,2007  Free Software Foundation, Inc.
- *
- *  GRUB is free software: you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation, either version 3 of the License, or
- *  (at your option) any later version.
- *
- *  GRUB is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef GRUB_LOADER_MACHINE_HEADER
-#define GRUB_LOADER_MACHINE_HEADER     1
-
-#include <grub/symbol.h>
-
-/* This is an asm part of the chainloader.  */
-void EXPORT_FUNC(grub_chainloader_real_boot) (int drive, void *part_addr) __attribute__ ((noreturn));
-
-#endif /* ! GRUB_LOADER_MACHINE_HEADER */
index 778049eefc402f6f40e591d085c3f30634aecb7e..b2fe900b6d0bc3e1c0b22a7be6cf10e163d4ea02 100644 (file)
@@ -48,6 +48,8 @@ struct grub_relocator16_state
   grub_uint16_t ip;
   grub_uint32_t ebx;
   grub_uint32_t edx;
+  grub_uint32_t esi;
+  int a20;
 };
 
 struct grub_relocator64_state