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
28static int cur_addr;
29entry_func entry_addr;
30static struct mod_list mll[99];
31static 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
39kernel_t
40load_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
771int
772load_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
808int
809load_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.  */
869static void
870bsd_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
886void
887bsd_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