Home | History | Annotate | Download | only in stage2
      1 /* boot.c - load and bootstrap a kernel */
      2 /*
      3  *  GRUB  --  GRand Unified Bootloader
      4  *  Copyright (C) 1999,2000,2001,2002,2003,2004  Free Software Foundation, Inc.
      5  *
      6  *  This program is free software; you can redistribute it and/or modify
      7  *  it under the terms of the GNU General Public License as published by
      8  *  the Free Software Foundation; either version 2 of the License, or
      9  *  (at your option) any later version.
     10  *
     11  *  This program is distributed in the hope that it will be useful,
     12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
     13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     14  *  GNU General Public License for more details.
     15  *
     16  *  You should have received a copy of the GNU General Public License
     17  *  along with this program; if not, write to the Free Software
     18  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
     19  */
     20 
     21 
     22 #include "shared.h"
     23 
     24 #include "freebsd.h"
     25 #include "imgact_aout.h"
     26 #include "i386-elf.h"
     27 
     28 static int cur_addr;
     29 entry_func entry_addr;
     30 static struct mod_list mll[99];
     31 static int linux_mem_size;
     32 
     33 /*
     34  *  The next two functions, 'load_image' and 'load_module', are the building
     35  *  blocks of the multiboot loader component.  They handle essentially all
     36  *  of the gory details of loading in a bootable image and the modules.
     37  */
     38 
     39 kernel_t
     40 load_image (char *kernel, char *arg, kernel_t suggested_type,
     41 	    unsigned long load_flags)
     42 {
     43   int len, i, exec_type = 0, align_4k = 1;
     44   entry_func real_entry_addr = 0;
     45   kernel_t type = KERNEL_TYPE_NONE;
     46   unsigned long flags = 0, text_len = 0, data_len = 0, bss_len = 0;
     47   char *str = 0, *str2 = 0;
     48   struct linux_kernel_header *lh;
     49   union
     50     {
     51       struct multiboot_header *mb;
     52       struct exec *aout;
     53       Elf32_Ehdr *elf;
     54     }
     55   pu;
     56   /* presuming that MULTIBOOT_SEARCH is large enough to encompass an
     57      executable header */
     58   unsigned char buffer[MULTIBOOT_SEARCH];
     59 
     60   /* sets the header pointer to point to the beginning of the
     61      buffer by default */
     62   pu.aout = (struct exec *) buffer;
     63 
     64   if (!grub_open (kernel))
     65     return KERNEL_TYPE_NONE;
     66 
     67   if (!(len = grub_read (buffer, MULTIBOOT_SEARCH)) || len < 32)
     68     {
     69       grub_close ();
     70 
     71       if (!errnum)
     72 	errnum = ERR_EXEC_FORMAT;
     73 
     74       return KERNEL_TYPE_NONE;
     75     }
     76 
     77   for (i = 0; i < len; i++)
     78     {
     79       if (MULTIBOOT_FOUND ((int) (buffer + i), len - i))
     80 	{
     81 	  flags = ((struct multiboot_header *) (buffer + i))->flags;
     82 	  if (flags & MULTIBOOT_UNSUPPORTED)
     83 	    {
     84 	      grub_close ();
     85 	      errnum = ERR_BOOT_FEATURES;
     86 	      return KERNEL_TYPE_NONE;
     87 	    }
     88 	  type = KERNEL_TYPE_MULTIBOOT;
     89 	  str2 = "Multiboot";
     90 	  break;
     91 	}
     92     }
     93 
     94   /* Use BUFFER as a linux kernel header, if the image is Linux zImage
     95      or bzImage.  */
     96   lh = (struct linux_kernel_header *) buffer;
     97 
     98   /* ELF loading supported if multiboot, FreeBSD and NetBSD.  */
     99   if ((type == KERNEL_TYPE_MULTIBOOT
    100        || pu.elf->e_ident[EI_OSABI] == ELFOSABI_FREEBSD
    101        || grub_strcmp (pu.elf->e_ident + EI_BRAND, "FreeBSD") == 0
    102        || suggested_type == KERNEL_TYPE_NETBSD)
    103       && len > sizeof (Elf32_Ehdr)
    104       && BOOTABLE_I386_ELF ((*((Elf32_Ehdr *) buffer))))
    105     {
    106       if (type == KERNEL_TYPE_MULTIBOOT)
    107 	entry_addr = (entry_func) pu.elf->e_entry;
    108       else
    109 	entry_addr = (entry_func) (pu.elf->e_entry & 0xFFFFFF);
    110 
    111       if (entry_addr < (entry_func) 0x100000)
    112 	errnum = ERR_BELOW_1MB;
    113 
    114       /* don't want to deal with ELF program header at some random
    115          place in the file -- this generally won't happen */
    116       if (pu.elf->e_phoff == 0 || pu.elf->e_phnum == 0
    117 	  || ((pu.elf->e_phoff + (pu.elf->e_phentsize * pu.elf->e_phnum))
    118 	      >= len))
    119 	errnum = ERR_EXEC_FORMAT;
    120       str = "elf";
    121 
    122       if (type == KERNEL_TYPE_NONE)
    123 	{
    124 	  /* At the moment, there is no way to identify a NetBSD ELF
    125 	     kernel, so rely on the suggested type by the user.  */
    126 	  if (suggested_type == KERNEL_TYPE_NETBSD)
    127 	    {
    128 	      str2 = "NetBSD";
    129 	      type = suggested_type;
    130 	    }
    131 	  else
    132 	    {
    133 	      str2 = "FreeBSD";
    134 	      type = KERNEL_TYPE_FREEBSD;
    135 	    }
    136 	}
    137     }
    138   else if (flags & MULTIBOOT_AOUT_KLUDGE)
    139     {
    140       pu.mb = (struct multiboot_header *) (buffer + i);
    141       entry_addr = (entry_func) pu.mb->entry_addr;
    142       cur_addr = pu.mb->load_addr;
    143       /* first offset into file */
    144       grub_seek (i - (pu.mb->header_addr - cur_addr));
    145 
    146       /* If the load end address is zero, load the whole contents.  */
    147       if (! pu.mb->load_end_addr)
    148 	pu.mb->load_end_addr = cur_addr + filemax;
    149 
    150       text_len = pu.mb->load_end_addr - cur_addr;
    151       data_len = 0;
    152 
    153       /* If the bss end address is zero, assume that there is no bss area.  */
    154       if (! pu.mb->bss_end_addr)
    155 	pu.mb->bss_end_addr = pu.mb->load_end_addr;
    156 
    157       bss_len = pu.mb->bss_end_addr - pu.mb->load_end_addr;
    158 
    159       if (pu.mb->header_addr < pu.mb->load_addr
    160 	  || pu.mb->load_end_addr <= pu.mb->load_addr
    161 	  || pu.mb->bss_end_addr < pu.mb->load_end_addr
    162 	  || (pu.mb->header_addr - pu.mb->load_addr) > i)
    163 	errnum = ERR_EXEC_FORMAT;
    164 
    165       if (cur_addr < 0x100000)
    166 	errnum = ERR_BELOW_1MB;
    167 
    168       pu.aout = (struct exec *) buffer;
    169       exec_type = 2;
    170       str = "kludge";
    171     }
    172   else if (len > sizeof (struct exec) && !N_BADMAG ((*(pu.aout))))
    173     {
    174       entry_addr = (entry_func) pu.aout->a_entry;
    175 
    176       if (type == KERNEL_TYPE_NONE)
    177 	{
    178 	  /*
    179 	   *  If it doesn't have a Multiboot header, then presume
    180 	   *  it is either a FreeBSD or NetBSD executable.  If so,
    181 	   *  then use a magic number of normal ordering, ZMAGIC to
    182 	   *  determine if it is FreeBSD.
    183 	   *
    184 	   *  This is all because freebsd and netbsd seem to require
    185 	   *  masking out some address bits...  differently for each
    186 	   *  one...  plus of course we need to know which booting
    187 	   *  method to use.
    188 	   */
    189 	  entry_addr = (entry_func) ((int) entry_addr & 0xFFFFFF);
    190 
    191 	  if (buffer[0] == 0xb && buffer[1] == 1)
    192 	    {
    193 	      type = KERNEL_TYPE_FREEBSD;
    194 	      cur_addr = (int) entry_addr;
    195 	      str2 = "FreeBSD";
    196 	    }
    197 	  else
    198 	    {
    199 	      type = KERNEL_TYPE_NETBSD;
    200 	      cur_addr = (int) entry_addr & 0xF00000;
    201 	      if (N_GETMAGIC ((*(pu.aout))) != NMAGIC)
    202 		align_4k = 0;
    203 	      str2 = "NetBSD";
    204 	    }
    205 	}
    206 
    207       /* first offset into file */
    208       grub_seek (N_TXTOFF (*(pu.aout)));
    209       text_len = pu.aout->a_text;
    210       data_len = pu.aout->a_data;
    211       bss_len = pu.aout->a_bss;
    212 
    213       if (cur_addr < 0x100000)
    214 	errnum = ERR_BELOW_1MB;
    215 
    216       exec_type = 1;
    217       str = "a.out";
    218     }
    219   else if (lh->boot_flag == BOOTSEC_SIGNATURE
    220 	   && lh->setup_sects <= LINUX_MAX_SETUP_SECTS)
    221     {
    222       int big_linux = 0;
    223       int setup_sects = lh->setup_sects;
    224 
    225       if (lh->header == LINUX_MAGIC_SIGNATURE && lh->version >= 0x0200)
    226 	{
    227 	  big_linux = (lh->loadflags & LINUX_FLAG_BIG_KERNEL);
    228 	  lh->type_of_loader = LINUX_BOOT_LOADER_TYPE;
    229 
    230 	  /* Put the real mode part at as a high location as possible.  */
    231 	  linux_data_real_addr
    232 	    = (char *) ((mbi.mem_lower << 10) - LINUX_SETUP_MOVE_SIZE);
    233 	  /* But it must not exceed the traditional area.  */
    234 	  if (linux_data_real_addr > (char *) LINUX_OLD_REAL_MODE_ADDR)
    235 	    linux_data_real_addr = (char *) LINUX_OLD_REAL_MODE_ADDR;
    236 
    237 	  if (lh->version >= 0x0201)
    238 	    {
    239 	      lh->heap_end_ptr = LINUX_HEAP_END_OFFSET;
    240 	      lh->loadflags |= LINUX_FLAG_CAN_USE_HEAP;
    241 	    }
    242 
    243 	  if (lh->version >= 0x0202)
    244 	    lh->cmd_line_ptr = linux_data_real_addr + LINUX_CL_OFFSET;
    245 	  else
    246 	    {
    247 	      lh->cl_magic = LINUX_CL_MAGIC;
    248 	      lh->cl_offset = LINUX_CL_OFFSET;
    249 	      lh->setup_move_size = LINUX_SETUP_MOVE_SIZE;
    250 	    }
    251 	}
    252       else
    253 	{
    254 	  /* Your kernel is quite old...  */
    255 	  lh->cl_magic = LINUX_CL_MAGIC;
    256 	  lh->cl_offset = LINUX_CL_OFFSET;
    257 
    258 	  setup_sects = LINUX_DEFAULT_SETUP_SECTS;
    259 
    260 	  linux_data_real_addr = (char *) LINUX_OLD_REAL_MODE_ADDR;
    261 	}
    262 
    263       /* If SETUP_SECTS is not set, set it to the default (4).  */
    264       if (! setup_sects)
    265 	setup_sects = LINUX_DEFAULT_SETUP_SECTS;
    266 
    267       data_len = setup_sects << 9;
    268       text_len = filemax - data_len - SECTOR_SIZE;
    269 
    270       linux_data_tmp_addr = (char *) LINUX_BZIMAGE_ADDR + text_len;
    271 
    272       if (! big_linux
    273 	  && text_len > linux_data_real_addr - (char *) LINUX_ZIMAGE_ADDR)
    274 	{
    275 	  grub_printf (" linux 'zImage' kernel too big, try 'make bzImage'\n");
    276 	  errnum = ERR_WONT_FIT;
    277 	}
    278       else if (linux_data_real_addr + LINUX_SETUP_MOVE_SIZE
    279 	       > RAW_ADDR ((char *) (mbi.mem_lower << 10)))
    280 	errnum = ERR_WONT_FIT;
    281       else
    282 	{
    283 	  grub_printf ("   [Linux-%s, setup=0x%x, size=0x%x]\n",
    284 		       (big_linux ? "bzImage" : "zImage"), data_len, text_len);
    285 
    286 	  /* Video mode selection support. What a mess!  */
    287 	  /* NOTE: Even the word "mess" is not still enough to
    288 	     represent how wrong and bad the Linux video support is,
    289 	     but I don't want to hear complaints from Linux fanatics
    290 	     any more. -okuji  */
    291 	  {
    292 	    char *vga;
    293 
    294 	    /* Find the substring "vga=".  */
    295 	    vga = grub_strstr (arg, "vga=");
    296 	    if (vga)
    297 	      {
    298 		char *value = vga + 4;
    299 		int vid_mode;
    300 
    301 		/* Handle special strings.  */
    302 		if (substring ("normal", value) < 1)
    303 		  vid_mode = LINUX_VID_MODE_NORMAL;
    304 		else if (substring ("ext", value) < 1)
    305 		  vid_mode = LINUX_VID_MODE_EXTENDED;
    306 		else if (substring ("ask", value) < 1)
    307 		  vid_mode = LINUX_VID_MODE_ASK;
    308 		else if (safe_parse_maxint (&value, &vid_mode))
    309 		  ;
    310 		else
    311 		  {
    312 		    /* ERRNUM is already set inside the function
    313 		       safe_parse_maxint.  */
    314 		    grub_close ();
    315 		    return KERNEL_TYPE_NONE;
    316 		  }
    317 
    318 		lh->vid_mode = vid_mode;
    319 	      }
    320 	  }
    321 
    322 	  /* Check the mem= option to limit memory used for initrd.  */
    323 	  {
    324 	    char *mem;
    325 
    326 	    mem = grub_strstr (arg, "mem=");
    327 	    if (mem)
    328 	      {
    329 		char *value = mem + 4;
    330 
    331 		safe_parse_maxint (&value, &linux_mem_size);
    332 		switch (errnum)
    333 		  {
    334 		  case ERR_NUMBER_OVERFLOW:
    335 		    /* If an overflow occurs, use the maximum address for
    336 		       initrd instead. This is good, because MAXINT is
    337 		       greater than LINUX_INITRD_MAX_ADDRESS.  */
    338 		    linux_mem_size = LINUX_INITRD_MAX_ADDRESS;
    339 		    errnum = ERR_NONE;
    340 		    break;
    341 
    342 		  case ERR_NONE:
    343 		    {
    344 		      int shift = 0;
    345 
    346 		      switch (grub_tolower (*value))
    347 			{
    348 			case 'g':
    349 			  shift += 10;
    350 			case 'm':
    351 			  shift += 10;
    352 			case 'k':
    353 			  shift += 10;
    354 			default:
    355 			  break;
    356 			}
    357 
    358 		      /* Check an overflow.  */
    359 		      if (linux_mem_size > (MAXINT >> shift))
    360 			linux_mem_size = LINUX_INITRD_MAX_ADDRESS;
    361 		      else
    362 			linux_mem_size <<= shift;
    363 		    }
    364 		    break;
    365 
    366 		  default:
    367 		    linux_mem_size = 0;
    368 		    errnum = ERR_NONE;
    369 		    break;
    370 		  }
    371 	      }
    372 	    else
    373 	      linux_mem_size = 0;
    374 	  }
    375 
    376 	  /* It is possible that DATA_LEN + SECTOR_SIZE is greater than
    377 	     MULTIBOOT_SEARCH, so the data may have been read partially.  */
    378 	  if (data_len + SECTOR_SIZE <= MULTIBOOT_SEARCH)
    379 	    grub_memmove (linux_data_tmp_addr, buffer,
    380 			  data_len + SECTOR_SIZE);
    381 	  else
    382 	    {
    383 	      grub_memmove (linux_data_tmp_addr, buffer, MULTIBOOT_SEARCH);
    384 	      grub_read (linux_data_tmp_addr + MULTIBOOT_SEARCH,
    385 			 data_len + SECTOR_SIZE - MULTIBOOT_SEARCH);
    386 	    }
    387 
    388 	  if (lh->header != LINUX_MAGIC_SIGNATURE ||
    389 	      lh->version < 0x0200)
    390 	    /* Clear the heap space.  */
    391 	    grub_memset (linux_data_tmp_addr + ((setup_sects + 1) << 9),
    392 			 0,
    393 			 (64 - setup_sects - 1) << 9);
    394 
    395 	  /* Copy command-line plus memory hack to staging area.
    396 	     NOTE: Linux has a bug that it doesn't handle multiple spaces
    397 	     between two options and a space after a "mem=" option isn't
    398 	     removed correctly so the arguments to init could be like
    399 	     {"init", "", "", NULL}. This affects some not-very-clever
    400 	     shells. Thus, the code below does a trick to avoid the bug.
    401 	     That is, copy "mem=XXX" to the end of the command-line, and
    402 	     avoid to copy spaces unnecessarily. Hell.  */
    403 	  {
    404 	    char *src = skip_to (0, arg);
    405 	    char *dest = linux_data_tmp_addr + LINUX_CL_OFFSET;
    406 
    407 	    while (dest < linux_data_tmp_addr + LINUX_CL_END_OFFSET && *src)
    408 	      *(dest++) = *(src++);
    409 
    410 	    /* Old Linux kernels have problems determining the amount of
    411 	       the available memory.  To work around this problem, we add
    412 	       the "mem" option to the kernel command line.  This has its
    413 	       own drawbacks because newer kernels can determine the
    414 	       memory map more accurately.  Boot protocol 2.03, which
    415 	       appeared in Linux 2.4.18, provides a pointer to the kernel
    416 	       version string, so we could check it.  But since kernel
    417 	       2.4.18 and newer are known to detect memory reliably, boot
    418 	       protocol 2.03 already implies that the kernel is new
    419 	       enough.  The "mem" option is added if neither of the
    420 	       following conditions is met:
    421 	       1) The "mem" option is already present.
    422 	       2) The "kernel" command is used with "--no-mem-option".
    423 	       3) GNU GRUB is configured not to pass the "mem" option.
    424 	       4) The kernel supports boot protocol 2.03 or newer.  */
    425 	    if (! grub_strstr (arg, "mem=")
    426 		&& ! (load_flags & KERNEL_LOAD_NO_MEM_OPTION)
    427 		&& lh->version < 0x0203		/* kernel version < 2.4.18 */
    428 		&& dest + 15 < linux_data_tmp_addr + LINUX_CL_END_OFFSET)
    429 	      {
    430 		*dest++ = ' ';
    431 		*dest++ = 'm';
    432 		*dest++ = 'e';
    433 		*dest++ = 'm';
    434 		*dest++ = '=';
    435 
    436 		dest = convert_to_ascii (dest, 'u', (extended_memory + 0x400));
    437 		*dest++ = 'K';
    438 	      }
    439 
    440 	    *dest = 0;
    441 	  }
    442 
    443 	  /* offset into file */
    444 	  grub_seek (data_len + SECTOR_SIZE);
    445 
    446 	  cur_addr = (int) linux_data_tmp_addr + LINUX_SETUP_MOVE_SIZE;
    447 	  grub_read ((char *) LINUX_BZIMAGE_ADDR, text_len);
    448 
    449 	  if (errnum == ERR_NONE)
    450 	    {
    451 	      grub_close ();
    452 
    453 	      /* Sanity check.  */
    454 	      if (suggested_type != KERNEL_TYPE_NONE
    455 		  && ((big_linux && suggested_type != KERNEL_TYPE_BIG_LINUX)
    456 		      || (! big_linux && suggested_type != KERNEL_TYPE_LINUX)))
    457 		{
    458 		  errnum = ERR_EXEC_FORMAT;
    459 		  return KERNEL_TYPE_NONE;
    460 		}
    461 
    462 	      /* Ugly hack.  */
    463 	      linux_text_len = text_len;
    464 
    465 	      return big_linux ? KERNEL_TYPE_BIG_LINUX : KERNEL_TYPE_LINUX;
    466 	    }
    467 	}
    468     }
    469   else				/* no recognizable format */
    470     errnum = ERR_EXEC_FORMAT;
    471 
    472   /* return if error */
    473   if (errnum)
    474     {
    475       grub_close ();
    476       return KERNEL_TYPE_NONE;
    477     }
    478 
    479   /* fill the multiboot info structure */
    480   mbi.cmdline = (int) arg;
    481   mbi.mods_count = 0;
    482   mbi.mods_addr = 0;
    483   mbi.boot_device = (current_drive << 24) | current_partition;
    484   mbi.flags &= ~(MB_INFO_MODS | MB_INFO_AOUT_SYMS | MB_INFO_ELF_SHDR);
    485   mbi.syms.a.tabsize = 0;
    486   mbi.syms.a.strsize = 0;
    487   mbi.syms.a.addr = 0;
    488   mbi.syms.a.pad = 0;
    489 
    490   printf ("   [%s-%s", str2, str);
    491 
    492   str = "";
    493 
    494   if (exec_type)		/* can be loaded like a.out */
    495     {
    496       if (flags & MULTIBOOT_AOUT_KLUDGE)
    497 	str = "-and-data";
    498 
    499       printf (", loadaddr=0x%x, text%s=0x%x", cur_addr, str, text_len);
    500 
    501       /* read text, then read data */
    502       if (grub_read ((char *) RAW_ADDR (cur_addr), text_len) == text_len)
    503 	{
    504 	  cur_addr += text_len;
    505 
    506 	  if (!(flags & MULTIBOOT_AOUT_KLUDGE))
    507 	    {
    508 	      /* we have to align to a 4K boundary */
    509 	      if (align_4k)
    510 		cur_addr = (cur_addr + 0xFFF) & 0xFFFFF000;
    511 	      else
    512 		printf (", C");
    513 
    514 	      printf (", data=0x%x", data_len);
    515 
    516 	      if ((grub_read ((char *) RAW_ADDR (cur_addr), data_len)
    517 		   != data_len)
    518 		  && !errnum)
    519 		errnum = ERR_EXEC_FORMAT;
    520 	      cur_addr += data_len;
    521 	    }
    522 
    523 	  if (!errnum)
    524 	    {
    525 	      memset ((char *) RAW_ADDR (cur_addr), 0, bss_len);
    526 	      cur_addr += bss_len;
    527 
    528 	      printf (", bss=0x%x", bss_len);
    529 	    }
    530 	}
    531       else if (!errnum)
    532 	errnum = ERR_EXEC_FORMAT;
    533 
    534       if (!errnum && pu.aout->a_syms
    535 	  && pu.aout->a_syms < (filemax - filepos))
    536 	{
    537 	  int symtab_err, orig_addr = cur_addr;
    538 
    539 	  /* we should align to a 4K boundary here for good measure */
    540 	  if (align_4k)
    541 	    cur_addr = (cur_addr + 0xFFF) & 0xFFFFF000;
    542 
    543 	  mbi.syms.a.addr = cur_addr;
    544 
    545 	  *((int *) RAW_ADDR (cur_addr)) = pu.aout->a_syms;
    546 	  cur_addr += sizeof (int);
    547 
    548 	  printf (", symtab=0x%x", pu.aout->a_syms);
    549 
    550 	  if (grub_read ((char *) RAW_ADDR (cur_addr), pu.aout->a_syms)
    551 	      == pu.aout->a_syms)
    552 	    {
    553 	      cur_addr += pu.aout->a_syms;
    554 	      mbi.syms.a.tabsize = pu.aout->a_syms;
    555 
    556 	      if (grub_read ((char *) &i, sizeof (int)) == sizeof (int))
    557 		{
    558 		  *((int *) RAW_ADDR (cur_addr)) = i;
    559 		  cur_addr += sizeof (int);
    560 
    561 		  mbi.syms.a.strsize = i;
    562 
    563 		  i -= sizeof (int);
    564 
    565 		  printf (", strtab=0x%x", i);
    566 
    567 		  symtab_err = (grub_read ((char *) RAW_ADDR (cur_addr), i)
    568 				!= i);
    569 		  cur_addr += i;
    570 		}
    571 	      else
    572 		symtab_err = 1;
    573 	    }
    574 	  else
    575 	    symtab_err = 1;
    576 
    577 	  if (symtab_err)
    578 	    {
    579 	      printf ("(bad)");
    580 	      cur_addr = orig_addr;
    581 	      mbi.syms.a.tabsize = 0;
    582 	      mbi.syms.a.strsize = 0;
    583 	      mbi.syms.a.addr = 0;
    584 	    }
    585 	  else
    586 	    mbi.flags |= MB_INFO_AOUT_SYMS;
    587 	}
    588     }
    589   else
    590     /* ELF executable */
    591     {
    592       unsigned loaded = 0, memaddr, memsiz, filesiz;
    593       Elf32_Phdr *phdr;
    594 
    595       /* reset this to zero for now */
    596       cur_addr = 0;
    597 
    598       /* scan for program segments */
    599       for (i = 0; i < pu.elf->e_phnum; i++)
    600 	{
    601 	  phdr = (Elf32_Phdr *)
    602 	    (pu.elf->e_phoff + ((int) buffer)
    603 	     + (pu.elf->e_phentsize * i));
    604 	  if (phdr->p_type == PT_LOAD)
    605 	    {
    606 	      /* offset into file */
    607 	      grub_seek (phdr->p_offset);
    608 	      filesiz = phdr->p_filesz;
    609 
    610 	      if (type == KERNEL_TYPE_FREEBSD || type == KERNEL_TYPE_NETBSD)
    611 		memaddr = RAW_ADDR (phdr->p_paddr & 0xFFFFFF);
    612 	      else
    613 		memaddr = RAW_ADDR (phdr->p_paddr);
    614 
    615 	      memsiz = phdr->p_memsz;
    616 	      if (memaddr < RAW_ADDR (0x100000))
    617 		errnum = ERR_BELOW_1MB;
    618 
    619 	      /* If the memory range contains the entry address, get the
    620 		 physical address here.  */
    621 	      if (type == KERNEL_TYPE_MULTIBOOT
    622 		  && (unsigned) entry_addr >= phdr->p_vaddr
    623 		  && (unsigned) entry_addr < phdr->p_vaddr + memsiz)
    624 		real_entry_addr = (entry_func) ((unsigned) entry_addr
    625 						+ memaddr - phdr->p_vaddr);
    626 
    627 	      /* make sure we only load what we're supposed to! */
    628 	      if (filesiz > memsiz)
    629 		filesiz = memsiz;
    630 	      /* mark memory as used */
    631 	      if (cur_addr < memaddr + memsiz)
    632 		cur_addr = memaddr + memsiz;
    633 	      printf (", <0x%x:0x%x:0x%x>", memaddr, filesiz,
    634 		      memsiz - filesiz);
    635 	      /* increment number of segments */
    636 	      loaded++;
    637 
    638 	      /* load the segment */
    639 	      if (memcheck (memaddr, memsiz)
    640 		  && grub_read ((char *) memaddr, filesiz) == filesiz)
    641 		{
    642 		  if (memsiz > filesiz)
    643 		    memset ((char *) (memaddr + filesiz), 0, memsiz - filesiz);
    644 		}
    645 	      else
    646 		break;
    647 	    }
    648 	}
    649 
    650       if (! errnum)
    651 	{
    652 	  if (! loaded)
    653 	    errnum = ERR_EXEC_FORMAT;
    654 	  else
    655 	    {
    656 	      /* Load ELF symbols.  */
    657 	      Elf32_Shdr *shdr = NULL;
    658 	      int tab_size, sec_size;
    659 	      int symtab_err = 0;
    660 
    661 	      mbi.syms.e.num = pu.elf->e_shnum;
    662 	      mbi.syms.e.size = pu.elf->e_shentsize;
    663 	      mbi.syms.e.shndx = pu.elf->e_shstrndx;
    664 
    665 	      /* We should align to a 4K boundary here for good measure.  */
    666 	      if (align_4k)
    667 		cur_addr = (cur_addr + 0xFFF) & 0xFFFFF000;
    668 
    669 	      tab_size = pu.elf->e_shentsize * pu.elf->e_shnum;
    670 
    671 	      grub_seek (pu.elf->e_shoff);
    672 	      if (grub_read ((char *) RAW_ADDR (cur_addr), tab_size)
    673 		  == tab_size)
    674 		{
    675 		  mbi.syms.e.addr = cur_addr;
    676 		  shdr = (Elf32_Shdr *) mbi.syms.e.addr;
    677 		  cur_addr += tab_size;
    678 
    679 		  printf (", shtab=0x%x", cur_addr);
    680 
    681 		  for (i = 0; i < mbi.syms.e.num; i++)
    682 		    {
    683 		      /* This section is a loaded section,
    684 			 so we don't care.  */
    685 		      if (shdr[i].sh_addr != 0)
    686 			continue;
    687 
    688 		      /* This section is empty, so we don't care.  */
    689 		      if (shdr[i].sh_size == 0)
    690 			continue;
    691 
    692 		      /* Align the section to a sh_addralign bits boundary.  */
    693 		      cur_addr = ((cur_addr + shdr[i].sh_addralign) &
    694 				  - (int) shdr[i].sh_addralign);
    695 
    696 		      grub_seek (shdr[i].sh_offset);
    697 
    698 		      sec_size = shdr[i].sh_size;
    699 
    700 		      if (! (memcheck (cur_addr, sec_size)
    701 			     && (grub_read ((char *) RAW_ADDR (cur_addr),
    702 					    sec_size)
    703 				 == sec_size)))
    704 			{
    705 			  symtab_err = 1;
    706 			  break;
    707 			}
    708 
    709 		      shdr[i].sh_addr = cur_addr;
    710 		      cur_addr += sec_size;
    711 		    }
    712 		}
    713 	      else
    714 		symtab_err = 1;
    715 
    716 	      if (mbi.syms.e.addr < RAW_ADDR(0x10000))
    717 		symtab_err = 1;
    718 
    719 	      if (symtab_err)
    720 		{
    721 		  printf ("(bad)");
    722 		  mbi.syms.e.num = 0;
    723 		  mbi.syms.e.size = 0;
    724 		  mbi.syms.e.addr = 0;
    725 		  mbi.syms.e.shndx = 0;
    726 		  cur_addr = 0;
    727 		}
    728 	      else
    729 		mbi.flags |= MB_INFO_ELF_SHDR;
    730 	    }
    731 	}
    732     }
    733 
    734   if (! errnum)
    735     {
    736       grub_printf (", entry=0x%x]\n", (unsigned) entry_addr);
    737 
    738       /* If the entry address is physically different from that of the ELF
    739 	 header, correct it here.  */
    740       if (real_entry_addr)
    741 	entry_addr = real_entry_addr;
    742     }
    743   else
    744     {
    745       putchar ('\n');
    746       type = KERNEL_TYPE_NONE;
    747     }
    748 
    749   grub_close ();
    750 
    751   /* Sanity check.  */
    752   if (suggested_type != KERNEL_TYPE_NONE && suggested_type != type)
    753     {
    754       errnum = ERR_EXEC_FORMAT;
    755       return KERNEL_TYPE_NONE;
    756     }
    757 
    758   return type;
    759 }
    760 
    761 int
    762 load_module (char *module, char *arg)
    763 {
    764   int len;
    765 
    766   /* if we are supposed to load on 4K boundaries */
    767   cur_addr = (cur_addr + 0xFFF) & 0xFFFFF000;
    768 
    769   if (!grub_open (module))
    770     return 0;
    771 
    772   len = grub_read ((char *) cur_addr, -1);
    773   if (! len)
    774     {
    775       grub_close ();
    776       return 0;
    777     }
    778 
    779   printf ("   [Multiboot-module @ 0x%x, 0x%x bytes]\n", cur_addr, len);
    780 
    781   /* these two simply need to be set if any modules are loaded at all */
    782   mbi.flags |= MB_INFO_MODS;
    783   mbi.mods_addr = (int) mll;
    784 
    785   mll[mbi.mods_count].cmdline = (int) arg;
    786   mll[mbi.mods_count].mod_start = cur_addr;
    787   cur_addr += len;
    788   mll[mbi.mods_count].mod_end = cur_addr;
    789   mll[mbi.mods_count].pad = 0;
    790 
    791   /* increment number of modules included */
    792   mbi.mods_count++;
    793 
    794   grub_close ();
    795   return 1;
    796 }
    797 
    798 int
    799 load_initrd (char *initrd)
    800 {
    801   int len;
    802   unsigned long moveto;
    803   unsigned long max_addr;
    804   struct linux_kernel_header *lh
    805     = (struct linux_kernel_header *) (cur_addr - LINUX_SETUP_MOVE_SIZE);
    806 
    807 #ifndef NO_DECOMPRESSION
    808   no_decompression = 1;
    809 #endif
    810 
    811   if (! grub_open (initrd))
    812     goto fail;
    813 
    814   len = grub_read ((char *) cur_addr, -1);
    815   if (! len)
    816     {
    817       grub_close ();
    818       goto fail;
    819     }
    820 
    821   if (linux_mem_size)
    822     moveto = linux_mem_size;
    823   else
    824     moveto = (mbi.mem_upper + 0x400) << 10;
    825 
    826   moveto = (moveto - len) & 0xfffff000;
    827   max_addr = (lh->header == LINUX_MAGIC_SIGNATURE && lh->version >= 0x0203
    828 	      ? lh->initrd_addr_max : LINUX_INITRD_MAX_ADDRESS);
    829   if (moveto + len >= max_addr)
    830     moveto = (max_addr - len) & 0xfffff000;
    831 
    832   /* XXX: Linux 2.3.xx has a bug in the memory range check, so avoid
    833      the last page.
    834      XXX: Linux 2.2.xx has a bug in the memory range check, which is
    835      worse than that of Linux 2.3.xx, so avoid the last 64kb. *sigh*  */
    836   moveto -= 0x10000;
    837   memmove ((void *) RAW_ADDR (moveto), (void *) cur_addr, len);
    838 
    839   printf ("   [Linux-initrd @ 0x%x, 0x%x bytes]\n", moveto, len);
    840 
    841   /* FIXME: Should check if the kernel supports INITRD.  */
    842   lh->ramdisk_image = RAW_ADDR (moveto);
    843   lh->ramdisk_size = len;
    844 
    845   grub_close ();
    846 
    847  fail:
    848 
    849 #ifndef NO_DECOMPRESSION
    850   no_decompression = 0;
    851 #endif
    852 
    853   return ! errnum;
    854 }
    855 
    856 
    857 #ifdef GRUB_UTIL
    858 /* Dummy function to fake the *BSD boot.  */
    859 static void
    860 bsd_boot_entry (int flags, int bootdev, int sym_start, int sym_end,
    861 		int mem_upper, int mem_lower)
    862 {
    863   stop ();
    864 }
    865 #endif
    866 
    867 
    868 /*
    869  *  All "*_boot" commands depend on the images being loaded into memory
    870  *  correctly, the variables in this file being set up correctly, and
    871  *  the root partition being set in the 'saved_drive' and 'saved_partition'
    872  *  variables.
    873  */
    874 
    875 
    876 void
    877 bsd_boot (kernel_t type, int bootdev, char *arg)
    878 {
    879   char *str;
    880   int clval = 0, i;
    881   struct bootinfo bi;
    882 
    883 #ifdef GRUB_UTIL
    884   entry_addr = (entry_func) bsd_boot_entry;
    885 #else
    886   stop_floppy ();
    887 #endif
    888 
    889   while (*(++arg) && *arg != ' ');
    890   str = arg;
    891   while (*str)
    892     {
    893       if (*str == '-')
    894 	{
    895 	  while (*str && *str != ' ')
    896 	    {
    897 	      if (*str == 'C')
    898 		clval |= RB_CDROM;
    899 	      if (*str == 'a')
    900 		clval |= RB_ASKNAME;
    901 	      if (*str == 'b')
    902 		clval |= RB_HALT;
    903 	      if (*str == 'c')
    904 		clval |= RB_CONFIG;
    905 	      if (*str == 'd')
    906 		clval |= RB_KDB;
    907 	      if (*str == 'D')
    908 		clval |= RB_MULTIPLE;
    909 	      if (*str == 'g')
    910 		clval |= RB_GDB;
    911 	      if (*str == 'h')
    912 		clval |= RB_SERIAL;
    913 	      if (*str == 'm')
    914 		clval |= RB_MUTE;
    915 	      if (*str == 'r')
    916 		clval |= RB_DFLTROOT;
    917 	      if (*str == 's')
    918 		clval |= RB_SINGLE;
    919 	      if (*str == 'v')
    920 		clval |= RB_VERBOSE;
    921 	      str++;
    922 	    }
    923 	  continue;
    924 	}
    925       str++;
    926     }
    927 
    928   if (type == KERNEL_TYPE_FREEBSD)
    929     {
    930       clval |= RB_BOOTINFO;
    931 
    932       bi.bi_version = BOOTINFO_VERSION;
    933 
    934       *arg = 0;
    935       while ((--arg) > (char *) MB_CMDLINE_BUF && *arg != '/');
    936       if (*arg == '/')
    937 	bi.bi_kernelname = arg + 1;
    938       else
    939 	bi.bi_kernelname = 0;
    940 
    941       bi.bi_nfs_diskless = 0;
    942       bi.bi_n_bios_used = 0;	/* this field is apparently unused */
    943 
    944       for (i = 0; i < N_BIOS_GEOM; i++)
    945 	{
    946 	  struct geometry geom;
    947 
    948 	  /* XXX Should check the return value.  */
    949 	  get_diskinfo (i + 0x80, &geom);
    950 	  /* FIXME: If HEADS or SECTORS is greater than 255, then this will
    951 	     break the geometry information. That is a drawback of BSD
    952 	     but not of GRUB.  */
    953 	  bi.bi_bios_geom[i] = (((geom.cylinders - 1) << 16)
    954 				+ (((geom.heads - 1) & 0xff) << 8)
    955 				+ (geom.sectors & 0xff));
    956 	}
    957 
    958       bi.bi_size = sizeof (struct bootinfo);
    959       bi.bi_memsizes_valid = 1;
    960       bi.bi_bios_dev = saved_drive;
    961       bi.bi_basemem = mbi.mem_lower;
    962       bi.bi_extmem = extended_memory;
    963 
    964       if (mbi.flags & MB_INFO_AOUT_SYMS)
    965 	{
    966 	  bi.bi_symtab = mbi.syms.a.addr;
    967 	  bi.bi_esymtab = mbi.syms.a.addr + 4
    968 	    + mbi.syms.a.tabsize + mbi.syms.a.strsize;
    969 	}
    970 #if 0
    971       else if (mbi.flags & MB_INFO_ELF_SHDR)
    972 	{
    973 	  /* FIXME: Should check if a symbol table exists and, if exists,
    974 	     pass the table to BI.  */
    975 	}
    976 #endif
    977       else
    978 	{
    979 	  bi.bi_symtab = 0;
    980 	  bi.bi_esymtab = 0;
    981 	}
    982 
    983       /* call entry point */
    984       (*entry_addr) (clval, bootdev, 0, 0, 0, ((int) (&bi)));
    985     }
    986   else
    987     {
    988       /*
    989        *  We now pass the various bootstrap parameters to the loaded
    990        *  image via the argument list.
    991        *
    992        *  This is the official list:
    993        *
    994        *  arg0 = 8 (magic)
    995        *  arg1 = boot flags
    996        *  arg2 = boot device
    997        *  arg3 = start of symbol table (0 if not loaded)
    998        *  arg4 = end of symbol table (0 if not loaded)
    999        *  arg5 = transfer address from image
   1000        *  arg6 = transfer address for next image pointer
   1001        *  arg7 = conventional memory size (640)
   1002        *  arg8 = extended memory size (8196)
   1003        *
   1004        *  ...in actuality, we just pass the parameters used by the kernel.
   1005        */
   1006 
   1007       /* call entry point */
   1008       unsigned long end_mark;
   1009 
   1010       if (mbi.flags & MB_INFO_AOUT_SYMS)
   1011 	end_mark = (mbi.syms.a.addr + 4
   1012 		    + mbi.syms.a.tabsize + mbi.syms.a.strsize);
   1013       else
   1014 	/* FIXME: it should be mbi.syms.e.size.  */
   1015 	end_mark = 0;
   1016 
   1017       (*entry_addr) (clval, bootdev, 0, end_mark,
   1018 		     extended_memory, mbi.mem_lower);
   1019     }
   1020 }
   1021