]> git.ipfire.org Git - thirdparty/grub.git/commitdiff
2002-07-12 Yoshinori K. Okuji <okuji@enbug.org>
authorokuji <okuji@localhost>
Fri, 12 Jul 2002 09:55:55 +0000 (09:55 +0000)
committerokuji <okuji@localhost>
Fri, 12 Jul 2002 09:55:55 +0000 (09:55 +0000)
* stage2/boot.c (load_image): Rewrite the Linux booting support
radically. Now it should work even on a machine having, say,
only 128KB, theoretically. Of course, GRUB itself doesn't work
on such a system, though.
(load_initrd): Initialize LH based on CUR_ADDR, because the
location becomes dynamic.
* stage2/shared.h (LINUX_MAX_SETUP_SECTS): Set to 64.
(LINUX_HEAP_END_OFFSET): Set to (0x9000 - 0x200).
(LINUX_STAGING_AREA): Removed.
(LINUX_SETUP): Likewise.
(LINUX_KERNEL): Likewise.
(LINUX_KERNEL_MAXLEN): Likewise.
(LINUX_SETUP_SEG): Likewise.
(LINUX_INIT_SEG): Likewise.
(LINUX_SETUP_STACK): Set to 0x9000.
(LINUX_BZIMAGE_ADDR): New macro.
(LINUX_ZIMAGE_ADDR): Likewise.
(LINUX_OLD_REAL_MODE_ADDR): Likewise.
(CL_MY_LOCATION): Removed.
(CL_MY_END_ADDR): Likewise.
(CL_BASE_ADDR): Likewise.
(CL_MAGIC): Renamed to ...
(LINUX_CL_MAGIC): ... this.
(LINUX_CL_OFFSET): New macro.
(LINUX_CL_END_OFFSET): Likewise.
(LINUX_SETUP_MOVE_SIZE): Likewise.
(struct linux_kernel_header): Change the type of the member
"cmd_line_ptr" to char *.
(linux_data_tmp_addr): Declared.
(linux_data_real_addr): Likewise.
* stage2/asm.S [!STAGE1_5] (linux_data_tmp_addr): New variable.
[!STAGE1_5] (linux_data_real_addr): Likewise.
[!STAGE1_5] (big_linux_boot): Copy the real mode part from
LINUX_DATA_TMP_ADDR to LINUX_DATA_REAL_ADDR.
* grub/asmstub.c (linux_data_tmp_addr): New variable.
(linux_data_real_addr): Likewise.

ChangeLog
NEWS
grub/asmstub.c
stage2/asm.S
stage2/boot.c
stage2/shared.h

index 52dab648499b1a43b268403c5285e348bb90f874..f1bf0393e1c68125c0c6b23c12f0533793985865 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,42 @@
+2002-07-12  Yoshinori K. Okuji  <okuji@enbug.org>
+
+       * stage2/boot.c (load_image): Rewrite the Linux booting support
+       radically. Now it should work even on a machine having, say,
+       only 128KB, theoretically. Of course, GRUB itself doesn't work
+       on such a system, though.
+       (load_initrd): Initialize LH based on CUR_ADDR, because the
+       location becomes dynamic.
+       * stage2/shared.h (LINUX_MAX_SETUP_SECTS): Set to 64.
+       (LINUX_HEAP_END_OFFSET): Set to (0x9000 - 0x200).
+       (LINUX_STAGING_AREA): Removed.
+       (LINUX_SETUP): Likewise.
+       (LINUX_KERNEL): Likewise.
+       (LINUX_KERNEL_MAXLEN): Likewise.
+       (LINUX_SETUP_SEG): Likewise.
+       (LINUX_INIT_SEG): Likewise.
+       (LINUX_SETUP_STACK): Set to 0x9000.
+       (LINUX_BZIMAGE_ADDR): New macro.
+       (LINUX_ZIMAGE_ADDR): Likewise.
+       (LINUX_OLD_REAL_MODE_ADDR): Likewise.
+       (CL_MY_LOCATION): Removed.
+       (CL_MY_END_ADDR): Likewise.
+       (CL_BASE_ADDR): Likewise.
+       (CL_MAGIC): Renamed to ...
+       (LINUX_CL_MAGIC): ... this.
+       (LINUX_CL_OFFSET): New macro.
+       (LINUX_CL_END_OFFSET): Likewise.
+       (LINUX_SETUP_MOVE_SIZE): Likewise.
+       (struct linux_kernel_header): Change the type of the member
+       "cmd_line_ptr" to char *.
+       (linux_data_tmp_addr): Declared.
+       (linux_data_real_addr): Likewise.
+       * stage2/asm.S [!STAGE1_5] (linux_data_tmp_addr): New variable.
+       [!STAGE1_5] (linux_data_real_addr): Likewise.
+       [!STAGE1_5] (big_linux_boot): Copy the real mode part from
+       LINUX_DATA_TMP_ADDR to LINUX_DATA_REAL_ADDR.
+       * grub/asmstub.c (linux_data_tmp_addr): New variable.
+       (linux_data_real_addr): Likewise.
+
 2002-07-09  Yoshinori K. Okuji  <okuji@enbug.org>
        
        From Mark Kettenis <kettenis@chello.nl>:
diff --git a/NEWS b/NEWS
index f1633eccd2e804cb037a0929fb10594cfc2db5af..53ed4b6a810e37ff9089c825b5c475afb2da58e1 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -20,6 +20,8 @@ New in 0.93:
   intelligent terminal (such as the comint mode in GNU Emacs).
 * The utility ``grub-md5-crypt'' prompts to retype a password and checks
   if the passwords match.
+* Support for booting Linux is rewritten, so GRUB now supports
+  large-EBDA systems.
 
 New in 0.92 - 2002-04-30:
 * The command "displaymem" uses only hex digits for consistency.
index ba6b0c4eff4adb6fc7295b9d3de8161ad9f366ad..4de3a371957a83ee6287a7c4130d78944cd7cb09 100644 (file)
@@ -73,6 +73,8 @@ int saved_entryno = 0;
 char version_string[] = VERSION;
 char config_file[128] = "/boot/grub/menu.lst"; /* FIXME: arbitrary */
 unsigned long linux_text_len = 0;
+char *linux_data_tmp_addr = 0;
+char *linux_data_real_addr = 0;
 unsigned short io_map[IO_MAP_SIZE];
 struct apm_info apm_bios_info;
 
index d2e84aa544da15fabbdd6d341dd19632abf04ae7..cc168720336f520697ee6b1998cbea5cd5789ee1 100644 (file)
@@ -1728,6 +1728,12 @@ ENTRY(patch_code_end)
 VARIABLE(linux_text_len)
        .long   0
        
+VARIABLE(linux_data_tmp_addr)
+       .long   0
+       
+VARIABLE(linux_data_real_addr)
+       .long   0
+       
 ENTRY(linux_boot)
        /* don't worry about saving anything, we're committed at this point */
        cld     /* forward copying */
@@ -1736,13 +1742,29 @@ ENTRY(linux_boot)
        movl    EXT_C(linux_text_len), %ecx
        addl    $3, %ecx
        shrl    $2, %ecx
-       movl    $LINUX_STAGING_AREA, %esi
-       movl    $LINUX_KERNEL, %edi
+       movl    $LINUX_BZIMAGE_ADDR, %esi
+       movl    $LINUX_ZIMAGE_ADDR, %edi
 
        rep
        movsl
 
 ENTRY(big_linux_boot)
+       movl    EXT_C(linux_data_real_addr), %ebx
+       
+       /* copy the real mode part */
+       movl    EXT_C(linux_data_tmp_addr), %esi
+       movl    %ebx, %edi
+       movl    $LINUX_SETUP_MOVE_SIZE, %ecx
+       cld
+       rep
+       movsb
+
+       /* change %ebx to the segment address */
+       shrl    $4, %ebx
+       movl    %ebx, %eax
+       addl    $0x20, %eax
+       movl    %eax, linux_setup_seg
+                       
        /* XXX new stack pointer in safe area for calling functions */
        movl    $0x4000, %esp
        call    EXT_C(stop_floppy)
@@ -1754,20 +1776,20 @@ ENTRY(big_linux_boot)
 
        /* final setup for linux boot */
        cli
-       movw    $LINUX_INIT_SEG, %ax
-       movw    %ax, %ss
+       movw    %bx, %ss
        movw    $LINUX_SETUP_STACK, %sp
        
-       movw    %ax, %ds
-       movw    %ax, %es
-       movw    %ax, %fs
-       movw    %ax, %gs
+       movw    %bx, %ds
+       movw    %bx, %es
+       movw    %bx, %fs
+       movw    %bx, %gs
 
        /* jump to start */
        /* ljmp */
        .byte   0xea
        .word   0
-       .word   LINUX_SETUP_SEG
+linux_setup_seg:       
+       .word   0
        .code32
 
 
index 3e39099e8e425f6c77abf0f6af7aa9a134f655ac..f490d159395499ebc94c27a60d1f419cf1b0b460 100644 (file)
@@ -227,6 +227,13 @@ load_image (char *kernel, char *arg, kernel_t suggested_type,
          big_linux = (lh->loadflags & LINUX_FLAG_BIG_KERNEL);
          lh->type_of_loader = LINUX_BOOT_LOADER_TYPE;
 
+         /* Put the real mode part at as a high location as possible.  */
+         linux_data_real_addr
+           = (char *) ((mbi.mem_lower << 10) - LINUX_SETUP_MOVE_SIZE);
+         /* But it must not exceed the traditional area.  */
+         if (linux_data_real_addr > (char *) LINUX_OLD_REAL_MODE_ADDR)
+           linux_data_real_addr = (char *) LINUX_OLD_REAL_MODE_ADDR;
+
          if (lh->version >= 0x0201)
            {
              lh->heap_end_ptr = LINUX_HEAP_END_OFFSET;
@@ -234,22 +241,23 @@ load_image (char *kernel, char *arg, kernel_t suggested_type,
            }
 
          if (lh->version >= 0x0202)
-           lh->cmd_line_ptr = CL_MY_LOCATION;
+           lh->cmd_line_ptr = linux_data_real_addr + LINUX_CL_OFFSET;
          else
            {
-             lh->cl_magic = CL_MAGIC;
-             lh->cl_offset = CL_MY_LOCATION - CL_BASE_ADDR;
-             lh->setup_move_size
-               = (unsigned short) (CL_MY_END_ADDR - CL_BASE_ADDR + 1);
+             lh->cl_magic = LINUX_CL_MAGIC;
+             lh->cl_offset = LINUX_CL_OFFSET;
+             lh->setup_move_size = LINUX_SETUP_MOVE_SIZE;
            }
        }
       else
        {
          /* Your kernel is quite old...  */
-         lh->cl_magic = CL_MAGIC;
-         lh->cl_offset = CL_MY_LOCATION - CL_BASE_ADDR;
+         lh->cl_magic = LINUX_CL_MAGIC;
+         lh->cl_offset = LINUX_CL_OFFSET;
          
          setup_sects = LINUX_DEFAULT_SETUP_SECTS;
+
+         linux_data_real_addr = (char *) LINUX_OLD_REAL_MODE_ADDR;
        }
       
       /* If SETUP_SECTS is not set, set it to the default (4).  */
@@ -258,22 +266,23 @@ load_image (char *kernel, char *arg, kernel_t suggested_type,
 
       data_len = setup_sects << 9;
       text_len = filemax - data_len - SECTOR_SIZE;
+
+      linux_data_tmp_addr = (char *) LINUX_BZIMAGE_ADDR + text_len;
       
-      if (! big_linux && text_len > LINUX_KERNEL_MAXLEN)
+      if (! big_linux
+         && text_len > linux_data_real_addr - (char *) LINUX_ZIMAGE_ADDR)
        {
          grub_printf (" linux 'zImage' kernel too big, try 'make bzImage'\n");
-         grub_close ();
          errnum = ERR_WONT_FIT;
-         return KERNEL_TYPE_NONE;
        }
-
-      grub_printf ("   [Linux-%s, setup=0x%x, size=0x%x]\n",
-                  (big_linux ? "bzImage" : "zImage"), data_len, text_len);
-
-      /* FIXME: SETUP_SECTS should be supported up to 63.
-        But do you know there are >640KB conventional memory machines?  */
-      if (mbi.mem_lower >= 608 && setup_sects < 60)
+      else if (linux_data_real_addr + LINUX_SETUP_MOVE_SIZE
+              > RAW_ADDR ((char *) (mbi.mem_lower << 10)))
+       errnum = ERR_WONT_FIT;
+      else
        {
+         grub_printf ("   [Linux-%s, setup=0x%x, size=0x%x]\n",
+                      (big_linux ? "bzImage" : "zImage"), data_len, text_len);
+
          /* Video mode selection support. What a mess!  */
          /* NOTE: Even the word "mess" is not still enough to
             represent how wrong and bad the Linux video support is,
@@ -281,14 +290,14 @@ load_image (char *kernel, char *arg, kernel_t suggested_type,
             any more. -okuji  */
          {
            char *vga;
-
+       
            /* Find the substring "vga=".  */
            vga = grub_strstr (arg, "vga=");
            if (vga)
              {
                char *value = vga + 4;
                int vid_mode;
-
+           
                /* Handle special strings.  */
                if (substring ("normal", value) < 1)
                  vid_mode = LINUX_VID_MODE_NORMAL;
@@ -305,7 +314,7 @@ load_image (char *kernel, char *arg, kernel_t suggested_type,
                    grub_close ();
                    return KERNEL_TYPE_NONE;
                  }
-
+           
                lh->vid_mode = vid_mode;
              }
          }
@@ -313,12 +322,12 @@ load_image (char *kernel, char *arg, kernel_t suggested_type,
          /* Check the mem= option to limit memory used for initrd.  */
          {
            char *mem;
-           
+       
            mem = grub_strstr (arg, "mem=");
            if (mem)
              {
                char *value = mem + 4;
-
+           
                safe_parse_maxint (&value, &linux_mem_size);
                switch (errnum)
                  {
@@ -329,11 +338,11 @@ load_image (char *kernel, char *arg, kernel_t suggested_type,
                    linux_mem_size = LINUX_INITRD_MAX_ADDRESS;
                    errnum = ERR_NONE;
                    break;
-                   
+               
                  case ERR_NONE:
                    {
                      int shift = 0;
-                     
+                 
                      switch (grub_tolower (*value))
                        {
                        case 'g':
@@ -345,7 +354,7 @@ load_image (char *kernel, char *arg, kernel_t suggested_type,
                        default:
                          break;
                        }
-
+                 
                      /* Check an overflow.  */
                      if (linux_mem_size > (MAXINT >> shift))
                        linux_mem_size = LINUX_INITRD_MAX_ADDRESS;
@@ -353,7 +362,7 @@ load_image (char *kernel, char *arg, kernel_t suggested_type,
                        linux_mem_size <<= shift;
                    }
                    break;
-                   
+               
                  default:
                    linux_mem_size = 0;
                    errnum = ERR_NONE;
@@ -363,26 +372,26 @@ load_image (char *kernel, char *arg, kernel_t suggested_type,
            else
              linux_mem_size = 0;
          }
-
+      
          /* It is possible that DATA_LEN is greater than MULTIBOOT_SEARCH,
             so the data may have been read partially.  */
          if (data_len <= MULTIBOOT_SEARCH)
-           grub_memmove ((char *) LINUX_SETUP, buffer,
+           grub_memmove (linux_data_tmp_addr, buffer,
                          data_len + SECTOR_SIZE);
          else
            {
-             grub_memmove ((char *) LINUX_SETUP, buffer, MULTIBOOT_SEARCH);
-             grub_read ((char *) LINUX_SETUP + MULTIBOOT_SEARCH,
+             grub_memmove (linux_data_tmp_addr, buffer, MULTIBOOT_SEARCH);
+             grub_read (linux_data_tmp_addr + MULTIBOOT_SEARCH,
                         data_len + SECTOR_SIZE - MULTIBOOT_SEARCH);
            }
-
+         
          if (lh->header != LINUX_MAGIC_SIGNATURE ||
              lh->version < 0x0200)
            /* Clear the heap space.  */
-           grub_memset ((char *) LINUX_SETUP + ((setup_sects - 1) << 9),
+           grub_memset (linux_data_tmp_addr + ((setup_sects + 1) << 9),
                         0,
                         (64 - setup_sects - 1) << 9);
-
+      
          /* Copy command-line plus memory hack to staging area.
             NOTE: Linux has a bug that it doesn't handle multiple spaces
             between two options and a space after a "mem=" option isn't
@@ -393,39 +402,40 @@ load_image (char *kernel, char *arg, kernel_t suggested_type,
             avoid to copy spaces unnecessarily. Hell.  */
          {
            char *src = skip_to (0, arg);
-           char *dest = (char *) CL_MY_LOCATION;
-
-           while (((int) dest) < CL_MY_END_ADDR && *src)
+           char *dest = linux_data_tmp_addr + LINUX_CL_OFFSET;
+       
+           while (dest < linux_data_tmp_addr + LINUX_CL_END_OFFSET && *src)
              *(dest++) = *(src++);
-           
+       
            /* Add a mem option automatically only if the user doesn't
               specify it explicitly.  */
            if (! grub_strstr (arg, "mem=")
-               && ! (load_flags & KERNEL_LOAD_NO_MEM_OPTION))
+               && ! (load_flags & KERNEL_LOAD_NO_MEM_OPTION)
+               && dest + 15 < linux_data_tmp_addr + LINUX_CL_END_OFFSET)
              {
-               if (dest != (char *) CL_MY_LOCATION)
-                 *(dest++) = ' ';
-               
-               grub_memmove (dest, "mem=", 4);
-               dest += 4;
-               
+               *dest++ = ' ';
+               *dest++ = 'm';
+               *dest++ = 'e';
+               *dest++ = 'm';
+               *dest++ = '=';
+           
                dest = convert_to_ascii (dest, 'u', (extended_memory + 0x400));
-               *(dest++) = 'K';
+               *dest++ = 'K';
              }
-
+       
            *dest = 0;
          }
-
+      
          /* offset into file */
          grub_seek (data_len + SECTOR_SIZE);
-
-         cur_addr = LINUX_STAGING_AREA + text_len;
-         grub_read ((char *) LINUX_STAGING_AREA, text_len);
-         
+      
+         cur_addr = (int) linux_data_tmp_addr + LINUX_SETUP_MOVE_SIZE;
+         grub_read ((char *) LINUX_BZIMAGE_ADDR, text_len);
+      
          if (errnum == ERR_NONE)
            {
              grub_close ();
-
+         
              /* Sanity check.  */
              if (suggested_type != KERNEL_TYPE_NONE
                  && ((big_linux && suggested_type != KERNEL_TYPE_BIG_LINUX)
@@ -434,17 +444,13 @@ load_image (char *kernel, char *arg, kernel_t suggested_type,
                  errnum = ERR_EXEC_FORMAT;
                  return KERNEL_TYPE_NONE;
                }
-
+         
              /* Ugly hack.  */
              linux_text_len = text_len;
-             
+         
              return big_linux ? KERNEL_TYPE_BIG_LINUX : KERNEL_TYPE_LINUX;
            }
-         
-         grub_close ();
        }
-      else
-       errnum = ERR_WONT_FIT;
     }
   else                         /* no recognizable format */
     errnum = ERR_EXEC_FORMAT;
@@ -780,7 +786,8 @@ load_initrd (char *initrd)
 {
   int len;
   unsigned long moveto;
-  struct linux_kernel_header *lh;
+  struct linux_kernel_header *lh
+    = (struct linux_kernel_header *) (cur_addr - LINUX_SETUP_MOVE_SIZE);
   
 #ifndef NO_DECOMPRESSION
   no_decompression = 1;
@@ -815,7 +822,6 @@ load_initrd (char *initrd)
   printf ("   [Linux-initrd @ 0x%x, 0x%x bytes]\n", moveto, len);
 
   /* FIXME: Should check if the kernel supports INITRD.  */
-  lh = (struct linux_kernel_header *) LINUX_SETUP;
   lh->ramdisk_image = RAW_ADDR (moveto);
   lh->ramdisk_size = len;
 
index cf51549e2de7d8e0fff44b556c83d77773c215dd..97e6a9abe50b1168faaf792052cedd025decf50d 100644 (file)
@@ -138,29 +138,26 @@ extern char *grub_scratch_mem;
 #define LINUX_DEFAULT_SETUP_SECTS      4
 #define LINUX_FLAG_CAN_USE_HEAP                0x80
 #define LINUX_INITRD_MAX_ADDRESS       0x38000000
-#define LINUX_MAX_SETUP_SECTS          63
+#define LINUX_MAX_SETUP_SECTS          64
 #define LINUX_BOOT_LOADER_TYPE         0x71
-#define LINUX_HEAP_END_OFFSET          (0x7F00 - 0x200)
+#define LINUX_HEAP_END_OFFSET          (0x9000 - 0x200)
 
-#define LINUX_STAGING_AREA        RAW_ADDR (0x100000)
-#define LINUX_SETUP               RAW_ADDR (0x90000)
-#define LINUX_KERNEL              RAW_ADDR (0x10000)
-#define LINUX_KERNEL_MAXLEN       0x7F000
-#define LINUX_SETUP_SEG           0x9020
-#define LINUX_INIT_SEG            0x9000
-#define LINUX_SETUP_STACK         0x7F00
+#define LINUX_BZIMAGE_ADDR             RAW_ADDR (0x100000)
+#define LINUX_ZIMAGE_ADDR              RAW_ADDR (0x10000)
+#define LINUX_OLD_REAL_MODE_ADDR       RAW_ADDR (0x90000)
+#define LINUX_SETUP_STACK              0x9000
 
-#define LINUX_FLAG_BIG_KERNEL     0x1
+#define LINUX_FLAG_BIG_KERNEL          0x1
 
 /* Linux's video mode selection support. Actually I hate it!  */
-#define LINUX_VID_MODE_NORMAL  0xFFFF
-#define LINUX_VID_MODE_EXTENDED        0xFFFE
-#define LINUX_VID_MODE_ASK     0xFFFD
+#define LINUX_VID_MODE_NORMAL          0xFFFF
+#define LINUX_VID_MODE_EXTENDED                0xFFFE
+#define LINUX_VID_MODE_ASK             0xFFFD
 
-#define CL_MY_LOCATION  RAW_ADDR (0x97F00)
-#define CL_MY_END_ADDR  RAW_ADDR (0x97FFF)
-#define CL_MAGIC        0xA33F
-#define CL_BASE_ADDR    RAW_ADDR (0x90000)
+#define LINUX_CL_OFFSET                        0x9000
+#define LINUX_CL_END_OFFSET            0x90FF
+#define LINUX_SETUP_MOVE_SIZE          0x9100
+#define LINUX_CL_MAGIC                 0xA33F
 
 /*
  *  General disk stuff
@@ -376,7 +373,7 @@ extern char *grub_scratch_mem;
 #include "mb_header.h"
 #include "mb_info.h"
 
-/* For the Linux/i386 boot protocol version 2.02.  */
+/* For the Linux/i386 boot protocol version 2.03.  */
 struct linux_kernel_header
 {
   char code1[0x0020];
@@ -405,7 +402,7 @@ struct linux_kernel_header
   unsigned long bootsect_kludge;       /* obsolete */
   unsigned short heap_end_ptr;         /* Free memory after setup end */
   unsigned short pad1;                 /* Unused */
-  unsigned long cmd_line_ptr;          /* Points to the kernel command line */
+  char *cmd_line_ptr;                  /* Points to the kernel command line */
 } __attribute__ ((packed));
 
 /* Memory map address range descriptor used by GET_MMAP_ENTRY. */
@@ -550,6 +547,8 @@ extern unsigned char force_lba;
 extern char version_string[];
 extern char config_file[];
 extern unsigned long linux_text_len;
+extern char *linux_data_tmp_addr;
+extern char *linux_data_real_addr;
 
 #ifdef GRUB_UTIL
 /* If not using config file, this variable is set to zero,