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

📄 linux.c

📁 grub 1.95 linux 的bootloader 源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *  GRUB  --  GRand Unified Bootloader *  Copyright (C) 2006  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 <grub/loader.h>#include <grub/machine/loader.h>#include <grub/file.h>#include <grub/disk.h>#include <grub/err.h>#include <grub/misc.h>#include <grub/types.h>#include <grub/rescue.h>#include <grub/dl.h>#include <grub/mm.h>#include <grub/term.h>#include <grub/cpu/linux.h>#include <grub/efi/api.h>#include <grub/efi/efi.h>#define NEXT_MEMORY_DESCRIPTOR(desc, size)      \  ((grub_efi_memory_descriptor_t *) ((char *) (desc) + (size)))static grub_dl_t my_mod;static grub_size_t linux_mem_size;static int loaded;static void *real_mode_mem;static void *prot_mode_mem;static void *initrd_mem;static grub_efi_uintn_t real_mode_pages;static grub_efi_uintn_t prot_mode_pages;static grub_efi_uintn_t initrd_pages;static void *mmap_buf;static grub_uint8_t gdt[] __attribute__ ((aligned(16))) =  {    /* NULL.  */    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,    /* Reserved.  */    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,    /* Code segment.  */    0xFF, 0xFF, 0x00, 0x00, 0x00, 0x9A, 0xCF, 0x00,    /* Data segment.  */    0xFF, 0xFF, 0x00, 0x00, 0x00, 0x92, 0xCF, 0x00  };struct gdt_descriptor{  grub_uint16_t dummy;  grub_uint16_t limit;  grub_uint32_t base;} __attribute__ ((aligned(4), packed));static struct gdt_descriptor gdt_desc =  {    0,    sizeof (gdt) - 1,    (grub_addr_t) gdt  };struct idt_descriptor{  grub_uint16_t dummy;  grub_uint16_t limit;  grub_uint32_t base;} __attribute__ ((aligned(4)));static struct idt_descriptor idt_desc =  {    0,    0,    0  };static inline grub_size_tpage_align (grub_size_t size){  return (size + (1 << 12) - 1) & (~((1 << 12) - 1));}/* Find the optimal number of pages for the memory map. Is it better to   move this code to efi/mm.c?  */static grub_efi_uintn_tfind_mmap_size (void){  static grub_efi_uintn_t mmap_size = 0;  if (mmap_size != 0)    return mmap_size;    mmap_size = (1 << 12);  while (1)    {      int ret;      grub_efi_memory_descriptor_t *mmap;      grub_efi_uintn_t desc_size;            mmap = grub_malloc (mmap_size);      if (! mmap)	return 0;      ret = grub_efi_get_memory_map (&mmap_size, mmap, 0, &desc_size, 0);      grub_free (mmap);            if (ret < 0)	grub_fatal ("cannot get memory map");      else if (ret > 0)	break;      mmap_size += (1 << 12);    }  /* Increase the size a bit for safety, because GRUB allocates more on     later, and EFI itself may allocate more.  */  mmap_size += (1 << 12);  return page_align (mmap_size);}static voidfree_pages (void){  if (real_mode_mem)    {      grub_efi_free_pages ((grub_addr_t) real_mode_mem, real_mode_pages);      real_mode_mem = 0;    }  if (prot_mode_mem)    {      grub_efi_free_pages ((grub_addr_t) prot_mode_mem, prot_mode_pages);      prot_mode_mem = 0;    }    if (initrd_mem)    {      grub_efi_free_pages ((grub_addr_t) initrd_mem, initrd_pages);      initrd_mem = 0;    }}/* Allocate pages for the real mode code and the protected mode code   for linux as well as a memory map buffer.  */static intallocate_pages (grub_size_t real_size, grub_size_t prot_size){  grub_efi_uintn_t desc_size;  grub_efi_memory_descriptor_t *mmap, *mmap_end;  grub_efi_uintn_t mmap_size, tmp_mmap_size;  grub_efi_memory_descriptor_t *desc;    /* Make sure that each size is aligned to a page boundary.  */  real_size = page_align (real_size + GRUB_DISK_SECTOR_SIZE);  prot_size = page_align (prot_size);  mmap_size = find_mmap_size ();  grub_dprintf ("linux", "real_size = %x, prot_size = %x, mmap_size = %x\n",		real_size, prot_size, mmap_size);    /* Calculate the number of pages; Combine the real mode code with     the memory map buffer for simplicity.  */  real_mode_pages = ((real_size + mmap_size) >> 12);  prot_mode_pages = (prot_size >> 12);    /* Initialize the memory pointers with NULL for convenience.  */  real_mode_mem = 0;  prot_mode_mem = 0;    /* Read the memory map temporarily, to find free space.  */  mmap = grub_malloc (mmap_size);  if (! mmap)    return 0;  tmp_mmap_size = mmap_size;  if (grub_efi_get_memory_map (&tmp_mmap_size, mmap, 0, &desc_size, 0) <= 0)    grub_fatal ("cannot get memory map");  mmap_end = NEXT_MEMORY_DESCRIPTOR (mmap, tmp_mmap_size);    /* First, find free pages for the real mode code     and the memory map buffer.  */  for (desc = mmap;       desc < mmap_end;       desc = NEXT_MEMORY_DESCRIPTOR (desc, desc_size))    {      /* Probably it is better to put the real mode code in the traditional	 space for safety.  */      if (desc->type == GRUB_EFI_CONVENTIONAL_MEMORY	  && desc->physical_start <= 0x90000	  && desc->num_pages >= real_mode_pages)	{	  grub_efi_physical_address_t physical_end;	  grub_efi_physical_address_t addr;	  	  physical_end = desc->physical_start + (desc->num_pages << 12);	  if (physical_end > 0x90000)	    physical_end = 0x90000;	  grub_dprintf ("linux", "physical_start = %x, physical_end = %x\n",			(unsigned) desc->physical_start,			(unsigned) physical_end);	  addr = physical_end - real_size - mmap_size;	  if (addr < 0x10000)	    continue;	  grub_dprintf ("linux", "trying to allocate %u pages at %x\n",			real_mode_pages, (unsigned) addr);	  real_mode_mem = grub_efi_allocate_pages (addr, real_mode_pages);	  if (! real_mode_mem)	    grub_fatal ("cannot allocate pages");	  	  desc->num_pages -= real_mode_pages;	  break;	}    }  if (! real_mode_mem)    {      grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate real mode pages");      goto fail;    }  mmap_buf = (void *) ((char *) real_mode_mem + real_size);	        /* Next, find free pages for the protected mode code.  */  /* XXX what happens if anything is using this address?  */  prot_mode_mem = grub_efi_allocate_pages (0x100000, prot_mode_pages);  if (! prot_mode_mem)    {      grub_error (GRUB_ERR_OUT_OF_MEMORY,		  "cannot allocate protected mode pages");      goto fail;    }  grub_free (mmap);  return 1; fail:  grub_free (mmap);  free_pages ();  return 0;}static grub_err_tgrub_linux_boot (void){  struct linux_kernel_header *lh;  struct linux_kernel_params *params;  grub_efi_uintn_t mmap_size;  grub_efi_uintn_t map_key;  grub_efi_uintn_t desc_size;  grub_efi_uint32_t desc_version;    lh = real_mode_mem;  params = real_mode_mem;  grub_dprintf ("linux", "code32_start = %x, idt_desc = %x, gdt_desc = %x\n",		(unsigned) lh->code32_start, (grub_addr_t) &(idt_desc.limit),		(grub_addr_t) &(gdt_desc.limit));  grub_dprintf ("linux", "idt = %x:%x, gdt = %x:%x\n",		(unsigned) idt_desc.limit, (unsigned) idt_desc.base,		(unsigned) gdt_desc.limit, (unsigned) gdt_desc.base);  mmap_size = find_mmap_size ();  if (grub_efi_get_memory_map (&mmap_size, mmap_buf, &map_key,			       &desc_size, &desc_version) <= 0)    grub_fatal ("cannot get memory map");  if (! grub_efi_exit_boot_services (map_key))    grub_fatal ("cannot exit boot services");  /* Note that no boot services are available from here.  */  /* Hardware interrupts are not safe any longer.  */  asm volatile ("cli" : : );    /* Pass EFI parameters.  */  params->efi_mem_desc_size = desc_size;  params->efi_mem_desc_version = desc_version;  params->efi_mmap = (grub_addr_t) mmap_buf;  params->efi_mmap_size = mmap_size;  /* Pass parameters.  */  asm volatile ("movl %0, %%esi" : : "m" (real_mode_mem));  asm volatile ("movl %0, %%ecx" : : "m" (lh->code32_start));  asm volatile ("xorl %%ebx, %%ebx" : : );  /* Load the IDT and the GDT for the bootstrap.  */  asm volatile ("lidt %0" : : "m" (idt_desc.limit));  asm volatile ("lgdt %0" : : "m" (gdt_desc.limit));  /* Enter Linux.  */  asm volatile ("jmp *%%ecx" : : );    /* Never reach here.  */  return GRUB_ERR_NONE;}static grub_err_tgrub_linux_unload (void){  free_pages ();  grub_dl_unref (my_mod);  loaded = 0;  return GRUB_ERR_NONE;}voidgrub_rescue_cmd_linux (int argc, char *argv[]){  grub_file_t file = 0;  struct linux_kernel_header lh;  struct linux_kernel_params *params;  grub_uint8_t setup_sects;  grub_size_t real_size, prot_size;  grub_ssize_t len;  int i;  char *dest;  grub_dl_ref (my_mod);    if (argc == 0)    {      grub_error (GRUB_ERR_BAD_ARGUMENT, "no kernel specified");      goto fail;    }  file = grub_file_open (argv[0]);  if (! file)    goto fail;

⌨️ 快捷键说明

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