⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 boot.c

📁 GRUB 0.93的源代码。有人说可以当一个很小的操作系统了
💻 C
📖 第 1 页 / 共 2 页
字号:
/* boot.c - load and bootstrap a kernel *//* *  GRUB  --  GRand Unified Bootloader *  Copyright (C) 1999,2000,2001,2002  Free Software Foundation, Inc. * *  This program is free software; you can redistribute it and/or modify *  it under the terms of the GNU General Public License as published by *  the Free Software Foundation; either version 2 of the License, or *  (at your option) any later version. * *  This program is distributed in the hope that it will be useful, *  but WITHOUT ANY WARRANTY; without even the implied warranty of *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the *  GNU General Public License for more details. * *  You should have received a copy of the GNU General Public License *  along with this program; if not, write to the Free Software *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */#include "shared.h"#include "freebsd.h"#include "imgact_aout.h"#include "i386-elf.h"static int cur_addr;entry_func entry_addr;static struct mod_list mll[99];static int linux_mem_size;/* *  The next two functions, 'load_image' and 'load_module', are the building *  blocks of the multiboot loader component.  They handle essentially all *  of the gory details of loading in a bootable image and the modules. */kernel_tload_image (char *kernel, char *arg, kernel_t suggested_type,	    unsigned long load_flags){  int len, i, exec_type = 0, align_4k = 1;  entry_func real_entry_addr = 0;  kernel_t type = KERNEL_TYPE_NONE;  unsigned long flags = 0, text_len = 0, data_len = 0, bss_len = 0;  char *str = 0, *str2 = 0;  struct linux_kernel_header *lh;  union    {      struct multiboot_header *mb;      struct exec *aout;      Elf32_Ehdr *elf;    }  pu;  /* presuming that MULTIBOOT_SEARCH is large enough to encompass an     executable header */  unsigned char buffer[MULTIBOOT_SEARCH];  /* sets the header pointer to point to the beginning of the     buffer by default */  pu.aout = (struct exec *) buffer;  if (!grub_open (kernel))    return KERNEL_TYPE_NONE;  if (!(len = grub_read (buffer, MULTIBOOT_SEARCH)) || len < 32)    {      grub_close ();            if (!errnum)	errnum = ERR_EXEC_FORMAT;      return KERNEL_TYPE_NONE;    }  for (i = 0; i < len; i++)    {      if (MULTIBOOT_FOUND ((int) (buffer + i), len - i))	{	  flags = ((struct multiboot_header *) (buffer + i))->flags;	  if (flags & MULTIBOOT_UNSUPPORTED)	    {	      grub_close ();	      errnum = ERR_BOOT_FEATURES;	      return KERNEL_TYPE_NONE;	    }	  type = KERNEL_TYPE_MULTIBOOT;	  str2 = "Multiboot";	  break;	}    }  /* Use BUFFER as a linux kernel header, if the image is Linux zImage     or bzImage.  */  lh = (struct linux_kernel_header *) buffer;    /* ELF loading supported if multiboot, FreeBSD and NetBSD.  */  if ((type == KERNEL_TYPE_MULTIBOOT       || pu.elf->e_ident[EI_OSABI] == ELFOSABI_FREEBSD       || grub_strcmp (pu.elf->e_ident + EI_BRAND, "FreeBSD") == 0       || suggested_type == KERNEL_TYPE_NETBSD)      && len > sizeof (Elf32_Ehdr)      && BOOTABLE_I386_ELF ((*((Elf32_Ehdr *) buffer))))    {      if (type == KERNEL_TYPE_MULTIBOOT)	entry_addr = (entry_func) pu.elf->e_entry;      else	entry_addr = (entry_func) (pu.elf->e_entry & 0xFFFFFF);      if (entry_addr < (entry_func) 0x100000)	errnum = ERR_BELOW_1MB;      /* don't want to deal with ELF program header at some random         place in the file -- this generally won't happen */      if (pu.elf->e_phoff == 0 || pu.elf->e_phnum == 0	  || ((pu.elf->e_phoff + (pu.elf->e_phentsize * pu.elf->e_phnum))	      >= len))	errnum = ERR_EXEC_FORMAT;      str = "elf";      if (type == KERNEL_TYPE_NONE)	{	  /* At the moment, there is no way to identify a NetBSD ELF	     kernel, so rely on the suggested type by the user.  */	  if (suggested_type == KERNEL_TYPE_NETBSD)	    {	      str2 = "NetBSD";	      type = suggested_type;	    }	  else	    {	      str2 = "FreeBSD";	      type = KERNEL_TYPE_FREEBSD;	    }	}    }  else if (flags & MULTIBOOT_AOUT_KLUDGE)    {      pu.mb = (struct multiboot_header *) (buffer + i);      entry_addr = (entry_func) pu.mb->entry_addr;      cur_addr = pu.mb->load_addr;      /* first offset into file */      grub_seek (i - (pu.mb->header_addr - cur_addr));      /* If the load end address is zero, load the whole contents.  */      if (! pu.mb->load_end_addr)	pu.mb->load_end_addr = cur_addr + filemax;            text_len = pu.mb->load_end_addr - cur_addr;      data_len = 0;      /* If the bss end address is zero, assume that there is no bss area.  */      if (! pu.mb->bss_end_addr)	pu.mb->bss_end_addr = pu.mb->load_end_addr;            bss_len = pu.mb->bss_end_addr - pu.mb->load_end_addr;      if (pu.mb->header_addr < pu.mb->load_addr	  || pu.mb->load_end_addr <= pu.mb->load_addr	  || pu.mb->bss_end_addr < pu.mb->load_end_addr	  || (pu.mb->header_addr - pu.mb->load_addr) > i)	errnum = ERR_EXEC_FORMAT;      if (cur_addr < 0x100000)	errnum = ERR_BELOW_1MB;      pu.aout = (struct exec *) buffer;      exec_type = 2;      str = "kludge";    }  else if (len > sizeof (struct exec) && !N_BADMAG ((*(pu.aout))))    {      entry_addr = (entry_func) pu.aout->a_entry;      if (type == KERNEL_TYPE_NONE)	{	  /*	   *  If it doesn't have a Multiboot header, then presume	   *  it is either a FreeBSD or NetBSD executable.  If so,	   *  then use a magic number of normal ordering, ZMAGIC to	   *  determine if it is FreeBSD.	   *	   *  This is all because freebsd and netbsd seem to require	   *  masking out some address bits...  differently for each	   *  one...  plus of course we need to know which booting	   *  method to use.	   */	  entry_addr = (entry_func) ((int) entry_addr & 0xFFFFFF);	  	  if (buffer[0] == 0xb && buffer[1] == 1)	    {	      type = KERNEL_TYPE_FREEBSD;	      cur_addr = (int) entry_addr;	      str2 = "FreeBSD";	    }	  else	    {	      type = KERNEL_TYPE_NETBSD;	      cur_addr = (int) entry_addr & 0xF00000;	      if (N_GETMAGIC ((*(pu.aout))) != NMAGIC)		align_4k = 0;	      str2 = "NetBSD";	    }	}      /* first offset into file */      grub_seek (N_TXTOFF (*(pu.aout)));      text_len = pu.aout->a_text;      data_len = pu.aout->a_data;      bss_len = pu.aout->a_bss;      if (cur_addr < 0x100000)	errnum = ERR_BELOW_1MB;      exec_type = 1;      str = "a.out";    }  else if (lh->boot_flag == BOOTSEC_SIGNATURE	   && lh->setup_sects <= LINUX_MAX_SETUP_SECTS)    {      int big_linux = 0;      int setup_sects = lh->setup_sects;      if (lh->header == LINUX_MAGIC_SIGNATURE && lh->version >= 0x0200)	{	  big_linux = (lh->loadflags & LINUX_FLAG_BIG_KERNEL);	  lh->type_of_loader = LINUX_BOOT_LOADER_TYPE;	  /* Put the real mode part at as a high location as possible.  */	  linux_data_real_addr	    = (char *) ((mbi.mem_lower << 10) - LINUX_SETUP_MOVE_SIZE);	  /* But it must not exceed the traditional area.  */	  if (linux_data_real_addr > (char *) LINUX_OLD_REAL_MODE_ADDR)	    linux_data_real_addr = (char *) LINUX_OLD_REAL_MODE_ADDR;	  if (lh->version >= 0x0201)	    {	      lh->heap_end_ptr = LINUX_HEAP_END_OFFSET;	      lh->loadflags |= LINUX_FLAG_CAN_USE_HEAP;	    }	  if (lh->version >= 0x0202)	    lh->cmd_line_ptr = linux_data_real_addr + LINUX_CL_OFFSET;	  else	    {	      lh->cl_magic = LINUX_CL_MAGIC;	      lh->cl_offset = LINUX_CL_OFFSET;	      lh->setup_move_size = LINUX_SETUP_MOVE_SIZE;	    }	}      else	{	  /* Your kernel is quite old...  */	  lh->cl_magic = LINUX_CL_MAGIC;	  lh->cl_offset = LINUX_CL_OFFSET;	  	  setup_sects = LINUX_DEFAULT_SETUP_SECTS;	  linux_data_real_addr = (char *) LINUX_OLD_REAL_MODE_ADDR;	}            /* If SETUP_SECTS is not set, set it to the default (4).  */      if (! setup_sects)	setup_sects = LINUX_DEFAULT_SETUP_SECTS;      data_len = setup_sects << 9;      text_len = filemax - data_len - SECTOR_SIZE;      linux_data_tmp_addr = (char *) LINUX_BZIMAGE_ADDR + text_len;            if (! big_linux	  && text_len > linux_data_real_addr - (char *) LINUX_ZIMAGE_ADDR)	{	  grub_printf (" linux 'zImage' kernel too big, try 'make bzImage'\n");	  errnum = ERR_WONT_FIT;	}      else if (linux_data_real_addr + LINUX_SETUP_MOVE_SIZE	       > RAW_ADDR ((char *) (mbi.mem_lower << 10)))	errnum = ERR_WONT_FIT;      else	{	  grub_printf ("   [Linux-%s, setup=0x%x, size=0x%x]\n",		       (big_linux ? "bzImage" : "zImage"), data_len, text_len);	  /* Video mode selection support. What a mess!  */	  /* NOTE: Even the word "mess" is not still enough to	     represent how wrong and bad the Linux video support is,	     but I don't want to hear complaints from Linux fanatics	     any more. -okuji  */	  {	    char *vga;		    /* Find the substring "vga=".  */	    vga = grub_strstr (arg, "vga=");	    if (vga)	      {		char *value = vga + 4;		int vid_mode;	    		/* Handle special strings.  */		if (substring ("normal", value) < 1)		  vid_mode = LINUX_VID_MODE_NORMAL;		else if (substring ("ext", value) < 1)		  vid_mode = LINUX_VID_MODE_EXTENDED;		else if (substring ("ask", value) < 1)		  vid_mode = LINUX_VID_MODE_ASK;		else if (safe_parse_maxint (&value, &vid_mode))		  ;		else		  {		    /* ERRNUM is already set inside the function		       safe_parse_maxint.  */		    grub_close ();		    return KERNEL_TYPE_NONE;		  }	    		lh->vid_mode = vid_mode;	      }	  }	  /* Check the mem= option to limit memory used for initrd.  */	  {	    char *mem;		    mem = grub_strstr (arg, "mem=");	    if (mem)	      {		char *value = mem + 4;	    		safe_parse_maxint (&value, &linux_mem_size);		switch (errnum)		  {		  case ERR_NUMBER_OVERFLOW:		    /* If an overflow occurs, use the maximum address for		       initrd instead. This is good, because MAXINT is		       greater than LINUX_INITRD_MAX_ADDRESS.  */		    linux_mem_size = LINUX_INITRD_MAX_ADDRESS;		    errnum = ERR_NONE;		    break;				  case ERR_NONE:		    {		      int shift = 0;		  		      switch (grub_tolower (*value))			{			case 'g':			  shift += 10;			case 'm':			  shift += 10;			case 'k':			  shift += 10;			default:			  break;			}		  		      /* Check an overflow.  */		      if (linux_mem_size > (MAXINT >> shift))			linux_mem_size = LINUX_INITRD_MAX_ADDRESS;		      else			linux_mem_size <<= shift;		    }		    break;				  default:		    linux_mem_size = 0;		    errnum = ERR_NONE;		    break;		  }	      }	    else	      linux_mem_size = 0;	  }      	  /* It is possible that DATA_LEN is greater than MULTIBOOT_SEARCH,	     so the data may have been read partially.  */	  if (data_len <= MULTIBOOT_SEARCH)	    grub_memmove (linux_data_tmp_addr, buffer,			  data_len + SECTOR_SIZE);	  else	    {	      grub_memmove (linux_data_tmp_addr, buffer, MULTIBOOT_SEARCH);	      grub_read (linux_data_tmp_addr + MULTIBOOT_SEARCH,			 data_len + SECTOR_SIZE - MULTIBOOT_SEARCH);	    }	  	  if (lh->header != LINUX_MAGIC_SIGNATURE ||	      lh->version < 0x0200)	    /* Clear the heap space.  */	    grub_memset (linux_data_tmp_addr + ((setup_sects + 1) << 9),			 0,			 (64 - setup_sects - 1) << 9);      	  /* Copy command-line plus memory hack to staging area.	     NOTE: Linux has a bug that it doesn't handle multiple spaces	     between two options and a space after a "mem=" option isn't	     removed correctly so the arguments to init could be like	     {"init", "", "", NULL}. This affects some not-very-clever	     shells. Thus, the code below does a trick to avoid the bug.	     That is, copy "mem=XXX" to the end of the command-line, and	     avoid to copy spaces unnecessarily. Hell.  */	  {	    char *src = skip_to (0, arg);	    char *dest = linux_data_tmp_addr + LINUX_CL_OFFSET;		    while (dest < linux_data_tmp_addr + LINUX_CL_END_OFFSET && *src)	      *(dest++) = *(src++);		    /* Add a mem option automatically only if the user doesn't	       specify it explicitly.  */	    if (! grub_strstr (arg, "mem=")		&& ! (load_flags & KERNEL_LOAD_NO_MEM_OPTION)		&& dest + 15 < linux_data_tmp_addr + LINUX_CL_END_OFFSET)	      {		*dest++ = ' ';		*dest++ = 'm';		*dest++ = 'e';		*dest++ = 'm';		*dest++ = '=';	    		dest = convert_to_ascii (dest, 'u', (extended_memory + 0x400));		*dest++ = 'K';	      }		    *dest = 0;	  }      	  /* offset into file */	  grub_seek (data_len + SECTOR_SIZE);      	  cur_addr = (int) linux_data_tmp_addr + LINUX_SETUP_MOVE_SIZE;	  grub_read ((char *) LINUX_BZIMAGE_ADDR, text_len);      	  if (errnum == ERR_NONE)	    {	      grub_close ();	  	      /* Sanity check.  */	      if (suggested_type != KERNEL_TYPE_NONE		  && ((big_linux && suggested_type != KERNEL_TYPE_BIG_LINUX)		      || (! big_linux && suggested_type != KERNEL_TYPE_LINUX)))		{		  errnum = ERR_EXEC_FORMAT;		  return KERNEL_TYPE_NONE;		}	  	      /* Ugly hack.  */	      linux_text_len = text_len;	  	      return big_linux ? KERNEL_TYPE_BIG_LINUX : KERNEL_TYPE_LINUX;	    }	}    }  else				/* no recognizable format */    errnum = ERR_EXEC_FORMAT;  /* return if error */  if (errnum)    {      grub_close ();      return KERNEL_TYPE_NONE;    }  /* fill the multiboot info structure */  mbi.cmdline = (int) arg;  mbi.mods_count = 0;  mbi.mods_addr = 0;  mbi.boot_device = (current_drive << 24) | current_partition;  mbi.flags &= ~(MB_INFO_MODS | MB_INFO_AOUT_SYMS | MB_INFO_ELF_SHDR);  mbi.syms.a.tabsize = 0;  mbi.syms.a.strsize = 0;  mbi.syms.a.addr = 0;  mbi.syms.a.pad = 0;  printf ("   [%s-%s", str2, str);  str = "";  if (exec_type)		/* can be loaded like a.out */    {      if (flags & MULTIBOOT_AOUT_KLUDGE)	str = "-and-data";      printf (", loadaddr=0x%x, text%s=0x%x", cur_addr, str, text_len);      /* read text, then read data */      if (grub_read ((char *) RAW_ADDR (cur_addr), text_len) == text_len)	{	  cur_addr += text_len;	  if (!(flags & MULTIBOOT_AOUT_KLUDGE))	    {	      /* we have to align to a 4K boundary */	      if (align_4k)		cur_addr = (cur_addr + 0xFFF) & 0xFFFFF000;	      else		printf (", C");	      printf (", data=0x%x", data_len);	      if ((grub_read ((char *) RAW_ADDR (cur_addr), data_len)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -