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	      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
761int
762load_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
798int
799load_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.  */
859static void
860bsd_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
876void
877bsd_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