• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
load_image(char * kernel,char * arg,kernel_t suggested_type,unsigned long load_flags)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
load_module(char * module,char * arg)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
load_initrd(char * initrd)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
bsd_boot_entry(int flags,int bootdev,int sym_start,int sym_end,int mem_upper,int mem_lower)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
bsd_boot(kernel_t type,int bootdev,char * arg)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