xref: /illumos-gate/usr/src/grub/grub-0.97/stage2/boot.c (revision 1b8adde7ba7d5e04395c141c5400dc2cffd7d809)
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               /*
673 	       * Should not need to call RAW_ADDR; cur_addr is already
674                * adjusted to account for grub_scratch_mem.
675 	       * XXX Linux might calculate cur_addr differently.
676 	       */
677 	      if (grub_read ((char *) (cur_addr), tab_size)
678 		  == tab_size)
679 		{
680 		  mbi.syms.e.addr = cur_addr;
681 		  shdr = (Elf32_Shdr *) mbi.syms.e.addr;
682 		  cur_addr += tab_size;
683 
684 		  printf (", shtab=0x%x", cur_addr);
685 
686 		  for (i = 0; i < mbi.syms.e.num; i++)
687 		    {
688 		      /* This section is a loaded section,
689 			 so we don't care.  */
690 		      if (shdr[i].sh_addr != 0)
691 			continue;
692 
693 		      /* This section is empty, so we don't care.  */
694 		      if (shdr[i].sh_size == 0)
695 			continue;
696 
697 		      /* Align the section to a sh_addralign bits boundary.  */
698 		      cur_addr = ((cur_addr + shdr[i].sh_addralign) &
699 				  - (int) shdr[i].sh_addralign);
700 
701 		      grub_seek (shdr[i].sh_offset);
702 
703 		      sec_size = shdr[i].sh_size;
704 
705 		      /*
706 		       * Should not need to call RAW_ADDR; cur_addr is already
707 		       * adjusted to account for grub_scratch_mem.
708 		       * XXX Linux might calculate cur_addr differently.
709 		       */
710 		      if (! (memcheck (cur_addr, sec_size)
711 			     && (grub_read ((char *) (cur_addr),
712 					    sec_size)
713 				 == sec_size)))
714 			{
715 			  symtab_err = 1;
716 			  break;
717 			}
718 
719 		      shdr[i].sh_addr = cur_addr;
720 		      cur_addr += sec_size;
721 		    }
722 		}
723 	      else
724 		symtab_err = 1;
725 
726 	      if (mbi.syms.e.addr < RAW_ADDR(0x10000))
727 		symtab_err = 1;
728 
729 	      if (symtab_err)
730 		{
731 		  printf ("(bad)");
732 		  mbi.syms.e.num = 0;
733 		  mbi.syms.e.size = 0;
734 		  mbi.syms.e.addr = 0;
735 		  mbi.syms.e.shndx = 0;
736 		  cur_addr = 0;
737 		}
738 	      else
739 		mbi.flags |= MB_INFO_ELF_SHDR;
740 	    }
741 	}
742     }
743 
744   if (! errnum)
745     {
746       grub_printf (", entry=0x%x]\n", (unsigned) entry_addr);
747 
748       /* If the entry address is physically different from that of the ELF
749 	 header, correct it here.  */
750       if (real_entry_addr)
751 	entry_addr = real_entry_addr;
752     }
753   else
754     {
755       putchar ('\n');
756       type = KERNEL_TYPE_NONE;
757     }
758 
759   grub_close ();
760 
761   /* Sanity check.  */
762   if (suggested_type != KERNEL_TYPE_NONE && suggested_type != type)
763     {
764       errnum = ERR_EXEC_FORMAT;
765       return KERNEL_TYPE_NONE;
766     }
767 
768   return type;
769 }
770 
771 int
load_module(char * module,char * arg)772 load_module (char *module, char *arg)
773 {
774   int len;
775 
776   /* if we are supposed to load on 4K boundaries */
777   cur_addr = (cur_addr + 0xFFF) & 0xFFFFF000;
778 
779   if (!grub_open (module))
780     return 0;
781 
782   len = grub_read ((char *) cur_addr, -1);
783   if (! len)
784     {
785       grub_close ();
786       return 0;
787     }
788 
789   printf ("   [Multiboot-module @ 0x%x, 0x%x bytes]\n", cur_addr, len);
790 
791   /* these two simply need to be set if any modules are loaded at all */
792   mbi.flags |= MB_INFO_MODS;
793   mbi.mods_addr = (int) mll;
794 
795   mll[mbi.mods_count].cmdline = (int) arg;
796   mll[mbi.mods_count].mod_start = cur_addr;
797   cur_addr += len;
798   mll[mbi.mods_count].mod_end = cur_addr;
799   mll[mbi.mods_count].pad = 0;
800 
801   /* increment number of modules included */
802   mbi.mods_count++;
803 
804   grub_close ();
805   return 1;
806 }
807 
808 int
load_initrd(char * initrd)809 load_initrd (char *initrd)
810 {
811   int len;
812   unsigned long moveto;
813   unsigned long max_addr;
814   struct linux_kernel_header *lh
815     = (struct linux_kernel_header *) (cur_addr - LINUX_SETUP_MOVE_SIZE);
816 
817 #ifndef NO_DECOMPRESSION
818   no_decompression = 1;
819 #endif
820 
821   if (! grub_open (initrd))
822     goto fail;
823 
824   len = grub_read ((char *) cur_addr, -1);
825   if (! len)
826     {
827       grub_close ();
828       goto fail;
829     }
830 
831   if (linux_mem_size)
832     moveto = linux_mem_size;
833   else
834     moveto = (mbi.mem_upper + 0x400) << 10;
835 
836   moveto = (moveto - len) & 0xfffff000;
837   max_addr = (lh->header == LINUX_MAGIC_SIGNATURE && lh->version >= 0x0203
838 	      ? lh->initrd_addr_max : LINUX_INITRD_MAX_ADDRESS);
839   if (moveto + len >= max_addr)
840     moveto = (max_addr - len) & 0xfffff000;
841 
842   /* XXX: Linux 2.3.xx has a bug in the memory range check, so avoid
843      the last page.
844      XXX: Linux 2.2.xx has a bug in the memory range check, which is
845      worse than that of Linux 2.3.xx, so avoid the last 64kb. *sigh*  */
846   moveto -= 0x10000;
847   memmove ((void *) RAW_ADDR (moveto), (void *) cur_addr, len);
848 
849   printf ("   [Linux-initrd @ 0x%x, 0x%x bytes]\n", moveto, len);
850 
851   /* FIXME: Should check if the kernel supports INITRD.  */
852   lh->ramdisk_image = RAW_ADDR (moveto);
853   lh->ramdisk_size = len;
854 
855   grub_close ();
856 
857  fail:
858 
859 #ifndef NO_DECOMPRESSION
860   no_decompression = 0;
861 #endif
862 
863   return ! errnum;
864 }
865 
866 
867 #ifdef GRUB_UTIL
868 /* Dummy function to fake the *BSD boot.  */
869 static void
bsd_boot_entry(int flags,int bootdev,int sym_start,int sym_end,int mem_upper,int mem_lower)870 bsd_boot_entry (int flags, int bootdev, int sym_start, int sym_end,
871 		int mem_upper, int mem_lower)
872 {
873   stop ();
874 }
875 #endif
876 
877 
878 /*
879  *  All "*_boot" commands depend on the images being loaded into memory
880  *  correctly, the variables in this file being set up correctly, and
881  *  the root partition being set in the 'saved_drive' and 'saved_partition'
882  *  variables.
883  */
884 
885 
886 void
bsd_boot(kernel_t type,int bootdev,char * arg)887 bsd_boot (kernel_t type, int bootdev, char *arg)
888 {
889   char *str;
890   int clval = 0, i;
891   struct bootinfo bi;
892 
893 #ifdef GRUB_UTIL
894   entry_addr = (entry_func) bsd_boot_entry;
895 #else
896   stop_floppy ();
897 #endif
898 
899   while (*(++arg) && *arg != ' ');
900   str = arg;
901   while (*str)
902     {
903       if (*str == '-')
904 	{
905 	  while (*str && *str != ' ')
906 	    {
907 	      if (*str == 'C')
908 		clval |= RB_CDROM;
909 	      if (*str == 'a')
910 		clval |= RB_ASKNAME;
911 	      if (*str == 'b')
912 		clval |= RB_HALT;
913 	      if (*str == 'c')
914 		clval |= RB_CONFIG;
915 	      if (*str == 'd')
916 		clval |= RB_KDB;
917 	      if (*str == 'D')
918 		clval |= RB_MULTIPLE;
919 	      if (*str == 'g')
920 		clval |= RB_GDB;
921 	      if (*str == 'h')
922 		clval |= RB_SERIAL;
923 	      if (*str == 'm')
924 		clval |= RB_MUTE;
925 	      if (*str == 'r')
926 		clval |= RB_DFLTROOT;
927 	      if (*str == 's')
928 		clval |= RB_SINGLE;
929 	      if (*str == 'v')
930 		clval |= RB_VERBOSE;
931 	      str++;
932 	    }
933 	  continue;
934 	}
935       str++;
936     }
937 
938   if (type == KERNEL_TYPE_FREEBSD)
939     {
940       clval |= RB_BOOTINFO;
941 
942       bi.bi_version = BOOTINFO_VERSION;
943 
944       *arg = 0;
945       while ((--arg) > (char *) MB_CMDLINE_BUF && *arg != '/');
946       if (*arg == '/')
947 	bi.bi_kernelname = arg + 1;
948       else
949 	bi.bi_kernelname = 0;
950 
951       bi.bi_nfs_diskless = 0;
952       bi.bi_n_bios_used = 0;	/* this field is apparently unused */
953 
954       for (i = 0; i < N_BIOS_GEOM; i++)
955 	{
956 	  struct geometry geom;
957 
958 	  /* XXX Should check the return value.  */
959 	  get_diskinfo (i + 0x80, &geom);
960 	  /* FIXME: If HEADS or SECTORS is greater than 255, then this will
961 	     break the geometry information. That is a drawback of BSD
962 	     but not of GRUB.  */
963 	  bi.bi_bios_geom[i] = (((geom.cylinders - 1) << 16)
964 				+ (((geom.heads - 1) & 0xff) << 8)
965 				+ (geom.sectors & 0xff));
966 	}
967 
968       bi.bi_size = sizeof (struct bootinfo);
969       bi.bi_memsizes_valid = 1;
970       bi.bi_bios_dev = saved_drive;
971       bi.bi_basemem = mbi.mem_lower;
972       bi.bi_extmem = extended_memory;
973 
974       if (mbi.flags & MB_INFO_AOUT_SYMS)
975 	{
976 	  bi.bi_symtab = mbi.syms.a.addr;
977 	  bi.bi_esymtab = mbi.syms.a.addr + 4
978 	    + mbi.syms.a.tabsize + mbi.syms.a.strsize;
979 	}
980 #if 0
981       else if (mbi.flags & MB_INFO_ELF_SHDR)
982 	{
983 	  /* FIXME: Should check if a symbol table exists and, if exists,
984 	     pass the table to BI.  */
985 	}
986 #endif
987       else
988 	{
989 	  bi.bi_symtab = 0;
990 	  bi.bi_esymtab = 0;
991 	}
992 
993       /* call entry point */
994       (*entry_addr) (clval, bootdev, 0, 0, 0, ((int) (&bi)));
995     }
996   else
997     {
998       /*
999        *  We now pass the various bootstrap parameters to the loaded
1000        *  image via the argument list.
1001        *
1002        *  This is the official list:
1003        *
1004        *  arg0 = 8 (magic)
1005        *  arg1 = boot flags
1006        *  arg2 = boot device
1007        *  arg3 = start of symbol table (0 if not loaded)
1008        *  arg4 = end of symbol table (0 if not loaded)
1009        *  arg5 = transfer address from image
1010        *  arg6 = transfer address for next image pointer
1011        *  arg7 = conventional memory size (640)
1012        *  arg8 = extended memory size (8196)
1013        *
1014        *  ...in actuality, we just pass the parameters used by the kernel.
1015        */
1016 
1017       /* call entry point */
1018       unsigned long end_mark;
1019 
1020       if (mbi.flags & MB_INFO_AOUT_SYMS)
1021 	end_mark = (mbi.syms.a.addr + 4
1022 		    + mbi.syms.a.tabsize + mbi.syms.a.strsize);
1023       else
1024 	/* FIXME: it should be mbi.syms.e.size.  */
1025 	end_mark = 0;
1026 
1027       (*entry_addr) (clval, bootdev, 0, end_mark,
1028 		     extended_memory, mbi.mem_lower);
1029     }
1030 }
1031