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