zoukankan      html  css  js  c++  java
  • Linux初始化的汇编代码

    1. 内核文件布局

    首先看一下arch/x86/boot/Setup.ld文件,它定义了链接后的内核文件布局。

       1: /*
       2:  * setup.ld
       3:  *
       4:  * Linker script for the i386 setup code
       5:  */
       6: OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
       7: OUTPUT_ARCH(i386)
       8: ENTRY(_start)
       9:  
      10: SECTIONS
      11: {
      12:     . = 0;
      13:     .bstext        : { *(.bstext) }
      14:     .bsdata        : { *(.bsdata) }
      15:  
      16:     . = 497;
      17:     .header        : { *(.header) }
      18:     .entrytext    : { *(.entrytext) }
      19:     .inittext    : { *(.inittext) }
      20:     .initdata    : { *(.initdata) }
      21:     __end_init = .;
      22:  
      23:     .text        : { *(.text) }
      24:     .text32        : { *(.text32) }
      25:  
      26:     . = ALIGN(16);
      27:     .rodata        : { *(.rodata*) }
      28:  
      29:     .videocards    : {
      30:         video_cards = .;
      31:         *(.videocards)
      32:         video_cards_end = .;
      33:     }
      34:  
      35:     . = ALIGN(16);
      36:     .data        : { *(.data*) }
      37:  
      38:     .signature    : {
      39:         setup_sig = .;
      40:         LONG(0x5a5aaa55)
      41:     }
      42:  
      43:  
      44:     . = ALIGN(16);
      45:     .bss        :
      46:     {
      47:         __bss_start = .;
      48:         *(.bss)
      49:         __bss_end = .;
      50:     }
      51:     . = ALIGN(16);
      52:     _end = .;
      53:  
      54:     /DISCARD/ : { *(.note*) }
      55:  
      56:     /*
      57:      * The ASSERT() sink to . is intentional, for binutils 2.14 compatibility:
      58:      */
      59:     . = ASSERT(_end <= 0x8000, "Setup too big!");
      60:     . = ASSERT(hdr == 0x1f1, "The setup header has the wrong offset!");
      61:     /* Necessary for the very-old-loader check to work... */
      62:     . = ASSERT(__end_init <= 5*512, "init sections too big!");
      63:  
      64: }

    2. Boot Sector启动扇区

    通过该文件,可以看到,.bstext以及.bsdata段都定义在第一个sector中,实际上bs就是boot sector的简称。

    在通过Grub、Lilo等引导程序启动内核时,不会将控制权交给boot sector中的代码来执行,只有在没有安装任何引导程序,并且将内核映像写到了软盘中时,才会从boot sector引导。

    因此,boot sector的存在,只是为了兼容Linux诞生时的做法,即从软盘启动,就像PE文件头部都会有一段

    This program cannot be run in DOS mode.

    的提示一样。

    我们看一下Boot Sector里面存放了什么内容:

    .bstext section

       1: .section ".bstext", "ax"
       2:  
       3: .global bootsect_start
       4: sect_start:
       5:  
       6: # Normalize the start address
       7: ljmp    $BOOTSEG, $start2
       8:  
       9: t2:
      10: movw    %cs, %ax
      11: movw    %ax, %ds
      12: movw    %ax, %es
      13: movw    %ax, %ss
      14: xorw    %sp, %sp
      15: sti
      16: cld
      17:  
      18: movw    $bugger_off_msg, %si
      19:  
      20: loop:
      21: lodsb
      22: andb    %al, %al
      23: jz    bs_die
      24: movb    $0xe, %ah
      25: movw    $7, %bx
      26: int    $0x10
      27: jmp    msg_loop
      28:  
      29: ie:
      30: # Allow the user to press a key, then reboot
      31: xorw    %ax, %ax
      32: int    $0x16
      33: int    $0x19
      34:  
      35: # int 0x19 should never return.  In case it does anyway,
      36: # invoke the BIOS reset code...
      37: ljmp    $0xf000,$0xfff0

    .bsdata section

       1: .section ".bsdata", "a"
       2: er_off_msg:
       3: .ascii    "Direct booting from floppy is no longer supported.
    "
       4: .ascii    "Please use a boot loader program instead.
    "
       5: .ascii    "
    "
       6: .ascii    "Remove disk and press any key to reboot . . .
    "
       7: .byte    0
       8:  
       9:  
      10: # Kernel attributes; used by setup.  This is part 1 of the
      11: # header, from the old boot sector.

    .header section的一部分

       1: .section ".header", "a"
       2: .globl    hdr
       3:  
       4: p_sects:    .byte 0            /* Filled in by build.c */
       5: _flags:    .word ROOT_RDONLY
       6: ize:    .long 0            /* Filled in by build.c */
       7: size:    .word 0            /* Obsolete */
       8: mode:    .word SVGA_MODE
       9: _dev:    .word 0            /* Filled in by build.c */
      10: _flag:    .word 0xAA55
      11:  
      12: # offset 512, entry point
    基本上没有什么有价值的信息。

    在LXR上面的最新代码(http://lxr.oss.org.cn/source/arch/x86/boot/header.S)中,有

     45 #ifdef CONFIG_EFI_STUB
     46         # "MZ", MS-DOS header
     47         .byte 0x4d
     48         .byte 0x5a
     49 #endif
    这是为了支持UEFI启动,UEFI Image的头部是用PE32+格式定义的,因此有“MZ”的Signature。

    2.1.1 UEFI Images
    UEFI Images are a class of files defined by UEFI that contain executable code. The most
    distinguishing feature of UEFI Images is that the first set of bytes in the UEFI Image file contains an
    image header that defines the encoding of the executable image.

    UEFI uses a subset of the PE32+ image format with a modified header signature. The modification
    to the signature value in the PE32+ image is done to distinguish UEFI images from normal PE32
    executables. The “+” addition to PE32 provides the 64-bit relocation fix-up extensions to standard
    PE32 format.

    参考:http://www.uefi.org/sites/default/files/resources/UEFI_2.4_0.pdf

    3. Bootloader会首先将执行权利交给内核的哪段代码?

    我们看常用的Grub:

    3.4 BIOS installation
    MBR
    The partition table format traditionally used on PC BIOS platforms is called the Master
    Boot Record (MBR) format; this is the format that allows up to four primary partitions
    and additional logical partitions. With this partition table format, there are two ways to
    install GRUB: it can be embedded in the area between the MBR and the first partition
    (called by various names, such as the "boot track", "MBR gap", or "embedding area", and
    which is usually at least 31 KiB), or the core image can be installed in a file system and a
    list of the blocks that make it up can be stored in the first sector of that partition.
    Each of these has different problems. There is no way to reserve space in the embedding area with complete safety, and some proprietary software is known to use it to
    make it difficult for users to work around licensing restrictions; and systems are sometimes
    partitioned without leaving enough space before the first partition. On the other hand,
    installing to a filesystem means that GRUB is vulnerable to its blocks being moved around
    by filesystem features such as tail packing, or even by aggressive fsck implementations, so
    this approach is quite fragile; and this approach can only be used if the ‘/boot’ filesystem
    is on the same disk that the BIOS boots from, so that GRUB does not have to rely on
    guessing BIOS drive numbers.
    The GRUB development team generally recommends embedding GRUB before the
    first partition, unless you have special requirements. You must ensure that the first partition
    starts at least 31 KiB (63 sectors) from the start of the disk; on modern disks, it is often a
    performance advantage to align partitions on larger boundaries anyway, so the first partition
    might start 1 MiB from the start of the disk.

    参考:http://www.gnu.org/software/grub/manual/grub.pdf

    当计算机加电自检后,ROM BIOS加载MBR(主引导扇区,即硬盘第一扇区)中的代码到内存中,这个扇区一共512字节,前446字节内容存放grub(bootloader)的关键引导程序,接着64字节放置硬盘分区表DPT(Disk Partition Table),一共四可以有四个主分区,占64个字节,这也是为什么主分区最多只有四个的原因,最后2个字节是固定的标志0x55AA。当BIOS把引导程序加载到内存后就把控制权交给grub,而后grub的剩余代码将完成其它代码的加载和搬移以及文件系统初始化查找等工作,最终加载内核映像文件,从而把控制权交给真正的内核运行。

    参考:http://www.linuxidc.com/Linux/2013-03/81119.htm

    还有几篇关于Linux引导程序的介绍性文章:

    http://www.ibm.com/developerworks/cn/linux/l-lpic1-v3-102-2/

    http://www.ibm.com/developerworks/cn/linux/l-linuxboot/

    How to boot an OS directly with GRUB

    Multiboot (see Multiboot Specification) is the native format supported by GRUB. For the sake of convenience, there are also support for Linux, FreeBSD, NetBSD and OpenBSD. If you want to boot other operating systems, you will have to chain-load them (see Chain-loading).

    Generally, GRUB can boot any Multiboot-compliant OS in the following steps:

    1. Set GRUB's root device to the drive where the OS images are stored by the command root (see root).
    2. Load the kernel image by the command kernel (see kernel).
    3. If you need modules, load them with the command module (see module) or modulenounzip (see modulenounzip).
    4. Run the command boot (see boot).

    Linux, FreeBSD, NetBSD and OpenBSD can be booted in a similar manner. You can load a kernel image by the command kernel and then run the command boot. If the kernel requires some parameters, just append the parameters to kernel, after the file name of the kernel. Also, please refer to OS-specific notes, for the information on your OS-specific issues.

    参考:http://ftp.gnu.org/pub/pub/pub/old-gnu/Manuals/grub-0.92/html_mono/grub.html#Loading%20an%20operating%20system%20directly

    都没有直接回答这个问题。


    查看Grub的源码:grub_linux_boot函数

       1: static grub_err_t
       2: grub_linux_boot (void)
       3: {
       4:   int e820_num;
       5:   grub_err_t err = 0;
       6:   const char *modevar;
       7:   char *tmp;
       8:   struct grub_relocator32_state state;
       9:   void *real_mode_mem;
      10:   grub_addr_t real_mode_target = 0;
      11:   grub_size_t real_size, mmap_size;
      12:   grub_size_t cl_offset;
      13:  
      14: #ifdef GRUB_MACHINE_IEEE1275
      15:   {
      16:     const char *bootpath;
      17:     grub_ssize_t len;
      18:  
      19:     bootpath = grub_env_get ("root");
      20:     if (bootpath)
      21:       grub_ieee1275_set_property (grub_ieee1275_chosen,
      22:                   "bootpath", bootpath,
      23:                   grub_strlen (bootpath) + 1,
      24:                   &len);
      25:     linux_params.ofw_signature = GRUB_LINUX_OFW_SIGNATURE;
      26:     linux_params.ofw_num_items = 1;
      27:     linux_params.ofw_cif_handler = (grub_uint32_t) grub_ieee1275_entry_fn;
      28:     linux_params.ofw_idt = 0;
      29:   }
      30: #endif
      31:  
      32:   modevar = grub_env_get ("gfxpayload");
      33:  
      34:   /* Now all graphical modes are acceptable.
      35:      May change in future if we have modes without framebuffer.  */
      36:   if (modevar && *modevar != 0)
      37:     {
      38:       tmp = grub_xasprintf ("%s;" DEFAULT_VIDEO_MODE, modevar);
      39:       if (! tmp)
      40:     return grub_errno;
      41: #if ACCEPTS_PURE_TEXT
      42:       err = grub_video_set_mode (tmp, 0, 0);
      43: #else
      44:       err = grub_video_set_mode (tmp, GRUB_VIDEO_MODE_TYPE_PURE_TEXT, 0);
      45: #endif
      46:       grub_free (tmp);
      47:     }
      48:   else
      49:     {
      50: #if ACCEPTS_PURE_TEXT
      51:       err = grub_video_set_mode (DEFAULT_VIDEO_MODE, 0, 0);
      52: #else
      53:       err = grub_video_set_mode (DEFAULT_VIDEO_MODE,
      54:                  GRUB_VIDEO_MODE_TYPE_PURE_TEXT, 0);
      55: #endif
      56:     }
      57:  
      58:   if (err)
      59:     {
      60:       grub_print_error ();
      61:       grub_puts_ (N_("Booting in blind mode"));
      62:       grub_errno = GRUB_ERR_NONE;
      63:     }
      64:  
      65:   if (grub_linux_setup_video (&linux_params))
      66:     {
      67: #if defined (GRUB_MACHINE_PCBIOS) || defined (GRUB_MACHINE_COREBOOT) || defined (GRUB_MACHINE_QEMU)
      68:       linux_params.have_vga = GRUB_VIDEO_LINUX_TYPE_TEXT;
      69:       linux_params.video_mode = 0x3;
      70: #else
      71:       linux_params.have_vga = 0;
      72:       linux_params.video_mode = 0;
      73:       linux_params.video_width = 0;
      74:       linux_params.video_height = 0;
      75: #endif
      76:     }
      77:  
      78:  
      79: #ifndef GRUB_MACHINE_IEEE1275
      80:   if (linux_params.have_vga == GRUB_VIDEO_LINUX_TYPE_TEXT)
      81: #endif
      82:     {
      83:       grub_term_output_t term;
      84:       int found = 0;
      85:       FOR_ACTIVE_TERM_OUTPUTS(term)
      86:     if (grub_strcmp (term->name, "vga_text") == 0
      87:         || grub_strcmp (term->name, "console") == 0
      88:         || grub_strcmp (term->name, "ofconsole") == 0)
      89:       {
      90:         grub_uint16_t pos = grub_term_getxy (term);
      91:         linux_params.video_cursor_x = pos >> 8;
      92:         linux_params.video_cursor_y = pos & 0xff;
      93:         linux_params.video_width = grub_term_width (term);
      94:         linux_params.video_height = grub_term_height (term);
      95:         found = 1;
      96:         break;
      97:       }
      98:       if (!found)
      99:     {
     100:       linux_params.video_cursor_x = 0;
     101:       linux_params.video_cursor_y = 0;
     102:       linux_params.video_width = 80;
     103:       linux_params.video_height = 25;
     104:     }
     105:     }
     106:  
     107:   mmap_size = find_mmap_size ();
     108:   /* Make sure that each size is aligned to a page boundary.  */
     109:   cl_offset = ALIGN_UP (mmap_size + sizeof (linux_params), 4096);
     110:   if (cl_offset < ((grub_size_t) linux_params.setup_sects << GRUB_DISK_SECTOR_BITS))
     111:     cl_offset = ALIGN_UP ((grub_size_t) (linux_params.setup_sects
     112:                      << GRUB_DISK_SECTOR_BITS), 4096);
     113:   real_size = ALIGN_UP (cl_offset + maximal_cmdline_size, 4096);
     114:  
     115: #ifdef GRUB_MACHINE_EFI
     116:   efi_mmap_size = find_efi_mmap_size ();
     117:   if (efi_mmap_size == 0)
     118:     return grub_errno;
     119: #endif
     120:  
     121:   grub_dprintf ("linux", "real_size = %x, mmap_size = %x
    ",
     122:         (unsigned) real_size, (unsigned) mmap_size);
     123:  
     124:   auto int NESTED_FUNC_ATTR hook (grub_uint64_t, grub_uint64_t,
     125:                   grub_memory_type_t);
     126:   int NESTED_FUNC_ATTR hook (grub_uint64_t addr, grub_uint64_t size,
     127:                  grub_memory_type_t type)
     128:     {
     129:       /* We must put real mode code in the traditional space.  */
     130:       if (type != GRUB_MEMORY_AVAILABLE || addr > 0x90000)
     131:     return 0;
     132:  
     133:       if (addr + size < 0x10000)
     134:     return 0;
     135:  
     136:       if (addr < 0x10000)
     137:     {
     138:       size += addr - 0x10000;
     139:       addr = 0x10000;
     140:     }
     141:  
     142:       if (addr + size > 0x90000)
     143:     size = 0x90000 - addr;
     144:  
     145:       if (real_size + efi_mmap_size > size)
     146:     return 0;
     147:  
     148:       grub_dprintf ("linux", "addr = %lx, size = %x, need_size = %x
    ",
     149:             (unsigned long) addr,
     150:             (unsigned) size,
     151:             (unsigned) (real_size + efi_mmap_size));
     152:       real_mode_target = ((addr + size) - (real_size + efi_mmap_size));
     153:       return 1;
     154:     }
     155: #ifdef GRUB_MACHINE_EFI
     156:   grub_efi_mmap_iterate (hook, 1);
     157:   if (! real_mode_target)
     158:     grub_efi_mmap_iterate (hook, 0);
     159: #else
     160:   grub_mmap_iterate (hook);
     161: #endif
     162:   grub_dprintf ("linux", "real_mode_target = %lx, real_size = %x, efi_mmap_size = %x
    ",
     163:                 (unsigned long) real_mode_target,
     164:         (unsigned) real_size,
     165:         (unsigned) efi_mmap_size);
     166:  
     167:   if (! real_mode_target)
     168:     return grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate real mode pages");
     169:  
     170:   {
     171:     grub_relocator_chunk_t ch;
     172:     err = grub_relocator_alloc_chunk_addr (relocator, &ch,
     173:                        real_mode_target,
     174:                        (real_size + efi_mmap_size));
     175:     if (err)
     176:      return err;
     177:     real_mode_mem = get_virtual_current_address (ch);
     178:   }
     179:   efi_mmap_buf = (grub_uint8_t *) real_mode_mem + real_size;
     180:  
     181:   grub_dprintf ("linux", "real_mode_mem = %lx
    ",
     182:                 (unsigned long) real_mode_mem);
     183:  
     184:   struct linux_kernel_params *params;
     185:  
     186:   params = real_mode_mem;
     187:  
     188:   *params = linux_params;
     189:   params->cmd_line_ptr = real_mode_target + cl_offset;
     190:   grub_memcpy ((char *) params + cl_offset, linux_cmdline,
     191:            maximal_cmdline_size);
     192:  
     193:   grub_dprintf ("linux", "code32_start = %x
    ",
     194:         (unsigned) params->code32_start);
     195:  
     196:   auto int NESTED_FUNC_ATTR hook_fill (grub_uint64_t, grub_uint64_t,
     197:                   grub_memory_type_t);
     198:   int NESTED_FUNC_ATTR hook_fill (grub_uint64_t addr, grub_uint64_t size, 
     199:                   grub_memory_type_t type)
     200:     {
     201:       grub_uint32_t e820_type;
     202:       switch (type)
     203:         {
     204:         case GRUB_MEMORY_AVAILABLE:
     205:       e820_type = GRUB_E820_RAM;
     206:       break;
     207:  
     208:         case GRUB_MEMORY_ACPI:
     209:       e820_type = GRUB_E820_ACPI;
     210:       break;
     211:  
     212:         case GRUB_MEMORY_NVS:
     213:       e820_type = GRUB_E820_NVS;
     214:       break;
     215:  
     216:         case GRUB_MEMORY_BADRAM:
     217:       e820_type = GRUB_E820_BADRAM;
     218:       break;
     219:  
     220:         default:
     221:           e820_type = GRUB_E820_RESERVED;
     222:         }
     223:       if (grub_e820_add_region (params->e820_map, &e820_num,
     224:                 addr, size, e820_type))
     225:     return 1;
     226:  
     227:       return 0;
     228:     }
     229:  
     230:   e820_num = 0;
     231:   if (grub_mmap_iterate (hook_fill))
     232:     return grub_errno;
     233:   params->mmap_size = e820_num;
     234:  
     235: #ifdef GRUB_MACHINE_EFI
     236:   {
     237:     grub_efi_uintn_t efi_desc_size;
     238:     grub_size_t efi_mmap_target;
     239:     grub_efi_uint32_t efi_desc_version;
     240:     err = grub_efi_finish_boot_services (&efi_mmap_size, efi_mmap_buf, NULL,
     241:                      &efi_desc_size, &efi_desc_version);
     242:     if (err)
     243:       return err;
     244:     
     245:     /* Note that no boot services are available from here.  */
     246:     efi_mmap_target = real_mode_target 
     247:       + ((grub_uint8_t *) efi_mmap_buf - (grub_uint8_t *) real_mode_mem);
     248:     /* Pass EFI parameters.  */
     249:     if (grub_le_to_cpu16 (params->version) >= 0x0208)
     250:       {
     251:     params->v0208.efi_mem_desc_size = efi_desc_size;
     252:     params->v0208.efi_mem_desc_version = efi_desc_version;
     253:     params->v0208.efi_mmap = efi_mmap_target;
     254:     params->v0208.efi_mmap_size = efi_mmap_size;
     255:  
     256: #ifdef __x86_64__
     257:     params->v0208.efi_mmap_hi = (efi_mmap_target >> 32);
     258: #endif
     259:       }
     260:     else if (grub_le_to_cpu16 (params->version) >= 0x0206)
     261:       {
     262:     params->v0206.efi_mem_desc_size = efi_desc_size;
     263:     params->v0206.efi_mem_desc_version = efi_desc_version;
     264:     params->v0206.efi_mmap = efi_mmap_target;
     265:     params->v0206.efi_mmap_size = efi_mmap_size;
     266:       }
     267:     else if (grub_le_to_cpu16 (params->version) >= 0x0204)
     268:       {
     269:     params->v0204.efi_mem_desc_size = efi_desc_size;
     270:     params->v0204.efi_mem_desc_version = efi_desc_version;
     271:     params->v0204.efi_mmap = efi_mmap_target;
     272:     params->v0204.efi_mmap_size = efi_mmap_size;
     273:       }
     274:   }
     275: #endif
     276:  
     277:   /* FIXME.  */
     278:   /*  asm volatile ("lidt %0" : : "m" (idt_desc)); */
     279:   state.ebp = state.edi = state.ebx = 0;
     280:   state.esi = real_mode_target;
     281:   state.esp = real_mode_target;
     282:   state.eip = params->code32_start;
     283:   return grub_relocator32_boot (relocator, state, 0);
     284: }

    也没有明确的暗示。

    关于linux_header的定义

       1: struct linux_hdrs {
       2:     /* All HdrS versions support these fields.  */
       3:     unsigned int start_insns[2];
       4:     char magic[4]; /* "HdrS" */
       5:     unsigned int linux_kernel_version; /* LINUX_VERSION_CODE */
       6:     unsigned short hdrs_version;
       7:     unsigned short root_flags;
       8:     unsigned short root_dev;
       9:     unsigned short ram_flags;
      10:     unsigned int __deprecated_ramdisk_image;
      11:     unsigned int ramdisk_size;
      12:  
      13:     /* HdrS versions 0x0201 and higher only */
      14:     char *reboot_command;
      15:  
      16:     /* HdrS versions 0x0202 and higher only */
      17:     struct linux_bootstr_info *bootstr_info;
      18:  
      19:     /* HdrS versions 0x0301 and higher only */
      20:     unsigned long ramdisk_image;
      21: };

    可以看到这个结构与header.S中的下面部分是对应的

       1: 272         # offset 512, entry point
       2: 273 
       3: 274         .globl  _start
       4: 275 _start:
       5: 276                 # Explicitly enter this as bytes, or the assembler
       6: 277                 # tries to generate a 3-byte jump here, which causes
       7: 278                 # everything else to push off to the wrong offset.
       8: 279                 .byte   0xeb            # short (2-byte) jump
       9: 280                 .byte   start_of_setup-1f
      10: 281 1:
      11: 282 
      12: 283         # Part 2 of the header, from the old setup.S
      13: 284 
      14: 285                 .ascii  "HdrS"          # header signature
      15: 286                 .word   0x020c          # header version number (>= 0x0105)
      16: 287                                         # or else old loadlin-1.5 will fail)
      17: 288                 .globl realmode_swtch
      18: 289 realmode_swtch: .word   0, 0            # default_switch, SETUPSEG
      19: 290 start_sys_seg:  .word   SYSSEG          # obsolete and meaningless, but just
      20: 291                                         # in case something decided to "use" it
      21: 292                 .word   kernel_version-512 # pointing to kernel version string
      22: 293                                         # above section of header is compatible
      23: 294                                         # with loadlin-1.5 (header v1.5). Don't
      24: 295                                         # change it.
      25: 296 
      26: 297 type_of_loader: .byte   0               # 0 means ancient bootloader, newer
      27: 298                                         # bootloaders know to change this.
      28: 299                                         # See Documentation/x86/boot.txt for
      29: 300                                         # assigned ids
      30: 301 
      31: 302 # flags, unused bits must be zero (RFU) bit within loadflags
      32: 303 loadflags:
      33: 304                 .byte   LOADED_HIGH     # The kernel is to be loaded high
      34: 305 
      35: 306 setup_move_size: .word  0x8000          # size to move, when setup is not
      36: 307                                         # loaded at 0x90000. We will move setup
      37: 308                                         # to 0x90000 then just before jumping
      38: 309                                         # into the kernel. However, only the
      39: 310                                         # loader knows how much data behind
      40: 311                                         # us also needs to be loaded.
      41: 312 
      42: 313 code32_start:                           # here loaders can put a different
      43: 314                                         # start address for 32-bit code.
      44: 315                 .long   0x100000        # 0x100000 = default for big kernel
      45: 316 
      46: 317 ramdisk_image:  .long   0               # address of loaded ramdisk image
      47: 318                                         # Here the loader puts the 32-bit
      48: 319                                         # address where it loaded the image.
      49: 320                                         # This only will be read by the kernel.

    上面的结构是64位,我们看一下32位的情况

       1: /* For the Linux/i386 boot protocol version 2.10.  */
       2: struct linux_kernel_header
       3: {
       4:   grub_uint8_t code1[0x0020];
       5:   grub_uint16_t cl_magic;        /* Magic number 0xA33F */
       6:   grub_uint16_t cl_offset;        /* The offset of command line */
       7:   grub_uint8_t code2[0x01F1 - 0x0020 - 2 - 2];
       8:   grub_uint8_t setup_sects;        /* The size of the setup in sectors */
       9:   grub_uint16_t root_flags;        /* If the root is mounted readonly */
      10:   grub_uint16_t syssize;        /* obsolete */
      11:   grub_uint16_t swap_dev;        /* obsolete */
      12:   grub_uint16_t ram_size;        /* obsolete */
      13:   grub_uint16_t vid_mode;        /* Video mode control */
      14:   grub_uint16_t root_dev;        /* Default root device number */
      15:   grub_uint16_t boot_flag;        /* 0xAA55 magic number */
      16:   grub_uint16_t jump;            /* Jump instruction */
      17:   grub_uint32_t header;            /* Magic signature "HdrS" */
      18:   grub_uint16_t version;        /* Boot protocol version supported */
      19:   grub_uint32_t realmode_swtch;        /* Boot loader hook */
      20:   grub_uint16_t start_sys;        /* The load-low segment (obsolete) */
      21:   grub_uint16_t kernel_version;        /* Points to kernel version string */
      22:   grub_uint8_t type_of_loader;        /* Boot loader identifier */
      23: #define LINUX_LOADER_ID_LILO        0x0
      24: #define LINUX_LOADER_ID_LOADLIN        0x1
      25: #define LINUX_LOADER_ID_BOOTSECT    0x2
      26: #define LINUX_LOADER_ID_SYSLINUX    0x3
      27: #define LINUX_LOADER_ID_ETHERBOOT    0x4
      28: #define LINUX_LOADER_ID_ELILO        0x5
      29: #define LINUX_LOADER_ID_GRUB        0x7
      30: #define LINUX_LOADER_ID_UBOOT        0x8
      31: #define LINUX_LOADER_ID_XEN        0x9
      32: #define LINUX_LOADER_ID_GUJIN        0xa
      33: #define LINUX_LOADER_ID_QEMU        0xb
      34:   grub_uint8_t loadflags;        /* Boot protocol option flags */
      35:   grub_uint16_t setup_move_size;    /* Move to high memory size */
      36:   grub_uint32_t code32_start;        /* Boot loader hook */
      37:   grub_uint32_t ramdisk_image;        /* initrd load address */
      38:   grub_uint32_t ramdisk_size;        /* initrd size */
      39:   grub_uint32_t bootsect_kludge;    /* obsolete */
      40:   grub_uint16_t heap_end_ptr;        /* Free memory after setup end */
      41:   grub_uint16_t pad1;            /* Unused */
      42:   grub_uint32_t cmd_line_ptr;        /* Points to the kernel command line */
      43:   grub_uint32_t initrd_addr_max;        /* Highest address for initrd */
      44:   grub_uint32_t kernel_alignment;
      45:   grub_uint8_t relocatable;
      46:   grub_uint8_t min_alignment;
      47:   grub_uint8_t pad[2];
      48:   grub_uint32_t cmdline_size;
      49:   grub_uint32_t hardware_subarch;
      50:   grub_uint64_t hardware_subarch_data;
      51:   grub_uint32_t payload_offset;
      52:   grub_uint32_t payload_length;
      53:   grub_uint64_t setup_data;
      54:   grub_uint64_t pref_address;
      55:   grub_uint32_t init_size;
      56: } __attribute__ ((packed));
    这里面可以看到setup_sects是位于第二个扇区的位置,

    再回顾一下

       1: 255         # Kernel attributes; used by setup.  This is part 1 of the
       2: 256         # header, from the old boot sector.
       3: 257 
       4: 258         .section ".header", "a"
       5: 259         .globl  sentinel
       6: 260 sentinel:       .byte 0xff, 0xff        /* Used to detect broken loaders */
       7: 261 
       8: 262         .globl  hdr
       9: 263 hdr:
      10: 264 setup_sects:    .byte 0                 /* Filled in by build.c */
      11: 265 root_flags:     .word ROOT_RDONLY
      12: 266 syssize:        .long 0                 /* Filled in by build.c */
      13: 267 ram_size:       .word 0                 /* Obsolete */
      14: 268 vid_mode:       .word SVGA_MODE
      15: 269 root_dev:       .word 0                 /* Filled in by build.c */
      16: 270 boot_flag:      .word 0xAA55
      17: 271 
      18: 272         # offset 512, entry point

    这回明确了,jump代表的就是第二个扇区头部的跳转指令的地址。

    再看一下grub/loader/i386/pc/Linux.c中的代码

       1: static grub_command_t cmd_linux, cmd_initrd;
       2:  
       3: GRUB_MOD_INIT(linux16)
       4: {
       5:   cmd_linux =
       6:     grub_register_command ("linux16", grub_cmd_linux,
       7:                0, N_("Load Linux."));
       8:   cmd_initrd =
       9:     grub_register_command ("initrd16", grub_cmd_initrd,
      10:                0, N_("Load initrd."));
      11:   my_mod = mod;
      12: }

    定义linux16命令的实现

       1: static grub_err_t
       2: grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
       3:         int argc, char *argv[])
       4: {
       5:   grub_file_t file = 0;
       6:   struct linux_kernel_header lh;
       7:   grub_uint8_t setup_sects;
       8:   grub_size_t real_size;
       9:   grub_ssize_t len;
      10:   int i;
      11:   char *grub_linux_prot_chunk;
      12:   int grub_linux_is_bzimage;
      13:   grub_addr_t grub_linux_prot_target;
      14:   grub_err_t err;
      15:  
      16:   grub_dl_ref (my_mod);
      17:  
      18:   if (argc == 0)
      19:     {
      20:       grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
      21:       goto fail;
      22:     }
      23:  
      24:   file = grub_file_open (argv[0]);
      25:   if (! file)
      26:     goto fail;
      27:  
      28:   if (grub_file_read (file, &lh, sizeof (lh)) != sizeof (lh))
      29:     {
      30:       if (!grub_errno)
      31:     grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"),
      32:             argv[0]);
      33:       goto fail;
      34:     }
      35:  
      36:   if (lh.boot_flag != grub_cpu_to_le16 (0xaa55))
      37:     {
      38:       grub_error (GRUB_ERR_BAD_OS, "invalid magic number");
      39:       goto fail;
      40:     }
      41:  
      42:   if (lh.setup_sects > GRUB_LINUX_MAX_SETUP_SECTS)
      43:     {
      44:       grub_error (GRUB_ERR_BAD_OS, "too many setup sectors");
      45:       goto fail;
      46:     }
      47:  
      48:   grub_linux_is_bzimage = 0;
      49:   setup_sects = lh.setup_sects;
      50:   linux_mem_size = 0;
      51:  
      52:   maximal_cmdline_size = 256;
      53:  
      54:   if (lh.header == grub_cpu_to_le32 (GRUB_LINUX_MAGIC_SIGNATURE)
      55:       && grub_le_to_cpu16 (lh.version) >= 0x0200)
      56:     {
      57:       grub_linux_is_bzimage = (lh.loadflags & GRUB_LINUX_FLAG_BIG_KERNEL);
      58:       lh.type_of_loader = GRUB_LINUX_BOOT_LOADER_TYPE;
      59:  
      60:       if (grub_le_to_cpu16 (lh.version) >= 0x0206)
      61:     maximal_cmdline_size = grub_le_to_cpu32 (lh.cmdline_size) + 1;
      62:  
      63:       /* Put the real mode part at as a high location as possible.  */
      64:       grub_linux_real_target = grub_mmap_get_lower () 
      65:     - (GRUB_LINUX_CL_OFFSET + maximal_cmdline_size);
      66:       /* But it must not exceed the traditional area.  */
      67:       if (grub_linux_real_target > GRUB_LINUX_OLD_REAL_MODE_ADDR)
      68:     grub_linux_real_target = GRUB_LINUX_OLD_REAL_MODE_ADDR;
      69:  
      70:       if (grub_le_to_cpu16 (lh.version) >= 0x0201)
      71:     {
      72:       lh.heap_end_ptr = grub_cpu_to_le16 (GRUB_LINUX_HEAP_END_OFFSET);
      73:       lh.loadflags |= GRUB_LINUX_FLAG_CAN_USE_HEAP;
      74:     }
      75:  
      76:       if (grub_le_to_cpu16 (lh.version) >= 0x0202)
      77:     lh.cmd_line_ptr = grub_linux_real_target + GRUB_LINUX_CL_OFFSET;
      78:       else
      79:     {
      80:       lh.cl_magic = grub_cpu_to_le16 (GRUB_LINUX_CL_MAGIC);
      81:       lh.cl_offset = grub_cpu_to_le16 (GRUB_LINUX_CL_OFFSET);
      82:       lh.setup_move_size = grub_cpu_to_le16 (GRUB_LINUX_CL_OFFSET
      83:                          + maximal_cmdline_size);
      84:     }
      85:     }
      86:   else
      87:     {
      88:       /* Your kernel is quite old...  */
      89:       lh.cl_magic = grub_cpu_to_le16 (GRUB_LINUX_CL_MAGIC);
      90:       lh.cl_offset = grub_cpu_to_le16 (GRUB_LINUX_CL_OFFSET);
      91:  
      92:       setup_sects = GRUB_LINUX_DEFAULT_SETUP_SECTS;
      93:  
      94:       grub_linux_real_target = GRUB_LINUX_OLD_REAL_MODE_ADDR;
      95:     }
      96:  
      97:   /* If SETUP_SECTS is not set, set it to the default (4).  */
      98:   if (! setup_sects)
      99:     setup_sects = GRUB_LINUX_DEFAULT_SETUP_SECTS;
     100:  
     101:   real_size = setup_sects << GRUB_DISK_SECTOR_BITS;
     102:   grub_linux16_prot_size = grub_file_size (file)
     103:     - real_size - GRUB_DISK_SECTOR_SIZE;
     104:  
     105:   if (! grub_linux_is_bzimage
     106:       && GRUB_LINUX_ZIMAGE_ADDR + grub_linux16_prot_size
     107:       > grub_linux_real_target)
     108:     {
     109:       grub_error (GRUB_ERR_BAD_OS, "too big zImage (0x%x > 0x%x), use bzImage instead",
     110:           (char *) GRUB_LINUX_ZIMAGE_ADDR + grub_linux16_prot_size,
     111:           (grub_size_t) grub_linux_real_target);
     112:       goto fail;
     113:     }
     114:  
     115:   if (grub_linux_real_target + GRUB_LINUX_CL_OFFSET + maximal_cmdline_size
     116:       > grub_mmap_get_lower ())
     117:     {
     118:       grub_error (GRUB_ERR_OUT_OF_RANGE,
     119:          "too small lower memory (0x%x > 0x%x)",
     120:           grub_linux_real_target + GRUB_LINUX_CL_OFFSET
     121:           + maximal_cmdline_size,
     122:           (int) grub_mmap_get_lower ());
     123:       goto fail;
     124:     }
     125:  
     126:   grub_dprintf ("linux", "[Linux-%s, setup=0x%x, size=0x%x]
    ",
     127:         grub_linux_is_bzimage ? "bzImage" : "zImage", real_size,
     128:         grub_linux16_prot_size);
     129:  
     130:   relocator = grub_relocator_new ();
     131:   if (!relocator)
     132:     goto fail;
     133:  
     134:   for (i = 1; i < argc; i++)
     135:     if (grub_memcmp (argv[i], "vga=", 4) == 0)
     136:       {
     137:     /* Video mode selection support.  */
     138:     grub_uint16_t vid_mode;
     139:     char *val = argv[i] + 4;
     140:  
     141:     if (grub_strcmp (val, "normal") == 0)
     142:       vid_mode = GRUB_LINUX_VID_MODE_NORMAL;
     143:     else if (grub_strcmp (val, "ext") == 0)
     144:       vid_mode = GRUB_LINUX_VID_MODE_EXTENDED;
     145:     else if (grub_strcmp (val, "ask") == 0)
     146:       vid_mode = GRUB_LINUX_VID_MODE_ASK;
     147:     else
     148:       vid_mode = (grub_uint16_t) grub_strtoul (val, 0, 0);
     149:  
     150:     if (grub_errno)
     151:       goto fail;
     152:  
     153:     lh.vid_mode = grub_cpu_to_le16 (vid_mode);
     154:       }
     155:     else if (grub_memcmp (argv[i], "mem=", 4) == 0)
     156:       {
     157:     char *val = argv[i] + 4;
     158:  
     159:     linux_mem_size = grub_strtoul (val, &val, 0);
     160:  
     161:     if (grub_errno)
     162:       {
     163:         grub_errno = GRUB_ERR_NONE;
     164:         linux_mem_size = 0;
     165:       }
     166:     else
     167:       {
     168:         int shift = 0;
     169:  
     170:         switch (grub_tolower (val[0]))
     171:           {
     172:           case 'g':
     173:         shift += 10;
     174:           case 'm':
     175:         shift += 10;
     176:           case 'k':
     177:         shift += 10;
     178:           default:
     179:         break;
     180:           }
     181:  
     182:         /* Check an overflow.  */
     183:         if (linux_mem_size > (~0UL >> shift))
     184:           linux_mem_size = 0;
     185:         else
     186:           linux_mem_size <<= shift;
     187:       }
     188:       }
     189:  
     190:   {
     191:     grub_relocator_chunk_t ch;
     192:     err = grub_relocator_alloc_chunk_addr (relocator, &ch,
     193:                        grub_linux_real_target,
     194:                        GRUB_LINUX_CL_OFFSET
     195:                        + maximal_cmdline_size);
     196:     if (err)
     197:       return err;
     198:     grub_linux_real_chunk = get_virtual_current_address (ch);
     199:   }
     200:  
     201:   /* Put the real mode code at the temporary address.  */
     202:   grub_memmove (grub_linux_real_chunk, &lh, sizeof (lh));
     203:  
     204:   len = real_size + GRUB_DISK_SECTOR_SIZE - sizeof (lh);
     205:   if (grub_file_read (file, grub_linux_real_chunk + sizeof (lh), len) != len)
     206:     {
     207:       if (!grub_errno)
     208:     grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"),
     209:             argv[0]);
     210:       goto fail;
     211:     }
     212:  
     213:   if (lh.header != grub_cpu_to_le32 (GRUB_LINUX_MAGIC_SIGNATURE)
     214:       || grub_le_to_cpu16 (lh.version) < 0x0200)
     215:     /* Clear the heap space.  */
     216:     grub_memset (grub_linux_real_chunk
     217:          + ((setup_sects + 1) << GRUB_DISK_SECTOR_BITS),
     218:          0,
     219:          ((GRUB_LINUX_MAX_SETUP_SECTS - setup_sects - 1)
     220:           << GRUB_DISK_SECTOR_BITS));
     221:  
     222:   /* Create kernel command line.  */
     223:   grub_memcpy ((char *)grub_linux_real_chunk + GRUB_LINUX_CL_OFFSET,
     224:         LINUX_IMAGE, sizeof (LINUX_IMAGE));
     225:   grub_create_loader_cmdline (argc, argv,
     226:                   (char *)grub_linux_real_chunk
     227:                   + GRUB_LINUX_CL_OFFSET + sizeof (LINUX_IMAGE) - 1,
     228:                   maximal_cmdline_size
     229:                   - (sizeof (LINUX_IMAGE) - 1));
     230:  
     231:   if (grub_linux_is_bzimage)
     232:     grub_linux_prot_target = GRUB_LINUX_BZIMAGE_ADDR;
     233:   else
     234:     grub_linux_prot_target = GRUB_LINUX_ZIMAGE_ADDR;
     235:   {
     236:     grub_relocator_chunk_t ch;
     237:     err = grub_relocator_alloc_chunk_addr (relocator, &ch,
     238:                        grub_linux_prot_target,
     239:                        grub_linux16_prot_size);
     240:     if (err)
     241:       return err;
     242:     grub_linux_prot_chunk = get_virtual_current_address (ch);
     243:   }
     244:  
     245:   len = grub_linux16_prot_size;
     246:   if (grub_file_read (file, grub_linux_prot_chunk, grub_linux16_prot_size)
     247:       != (grub_ssize_t) grub_linux16_prot_size && !grub_errno)
     248:     grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"),
     249:         argv[0]);
     250:  
     251:   if (grub_errno == GRUB_ERR_NONE)
     252:     {
     253:       grub_loader_set (grub_linux16_boot, grub_linux_unload, 0);
     254:       loaded = 1;
     255:     }
     256:  
     257:  fail:
     258:  
     259:   if (file)
     260:     grub_file_close (file);
     261:  
     262:   if (grub_errno != GRUB_ERR_NONE)
     263:     {
     264:       grub_dl_unref (my_mod);
     265:       loaded = 0;
     266:       grub_relocator_unload (relocator);
     267:     }
     268:  
     269:   return grub_errno;
     270: }

    关键的语句:

    struct linux_kernel_header lh;

    ……

    if (grub_file_read (file, &lh, sizeof (lh)) != sizeof (lh))

    ……

    还有解压以及代码搬移操作。

    setup部分可以认为并不是Linux内核的一部分,而是为了启动内核的。setup部分大小不能超64个sector,

       1: #define GRUB_LINUX_MAX_SETUP_SECTS    64
       2:  
       3: if (lh.setup_sects > GRUB_LINUX_MAX_SETUP_SECTS)
       4:   {
       5:     grub_error (GRUB_ERR_BAD_OS, "too many setup sectors");
       6:     goto fail;
       7:   }

    如果是zImage,需要使用linux16命令引导

       1: if (! (lh.loadflags & GRUB_LINUX_FLAG_BIG_KERNEL))
       2:   {
       3:     grub_error (GRUB_ERR_BAD_OS, "zImage doesn't support 32-bit boot"
       4: fdef GRUB_MACHINE_PCBIOS
       5:         " (try with `linux16')"
       6: ndif
       7:         );
       8:     goto fail;
       9:   }

    setup部分默认为4个sector大小。

       1: /* If SETUP_SECTS is not set, set it to the default (4).  */
       2:   if (! setup_sects)
       3:     setup_sects = GRUB_LINUX_DEFAULT_SETUP_SECTS;

    real_size是setup部分的大小,prot_file_size是内核除去setup部分以及boot sector部分的大小。

       1:  
       2:   real_size = setup_sects << GRUB_DISK_SECTOR_BITS;
       3:   prot_file_size = grub_file_size (file) - real_size - GRUB_DISK_SECTOR_SIZE;

    Linux的bzImage的目标地址为0x100000(1MB)物理内存处。

       1: if (grub_le_to_cpu16 (lh.version) >= 0x020a)
       2:   {
       3:     min_align = lh.min_alignment;
       4:     prot_size = grub_le_to_cpu32 (lh.init_size);
       5:     prot_init_space = page_align (prot_size);
       6:     if (relocatable)
       7:   preffered_address = grub_le_to_cpu64 (lh.pref_address);
       8:     else
       9:   preffered_address = GRUB_LINUX_BZIMAGE_ADDR;
      10:   }
      11: else
      12:   {
      13:     min_align = align;
      14:     prot_size = prot_file_size;
      15:     preffered_address = GRUB_LINUX_BZIMAGE_ADDR;
      16:     /* Usually, the compression ratio is about 50%.  */
      17:     prot_init_space = page_align (prot_size) * 3;
      18:   }

    调用allocate_pages函数,这是一个很重要的函数

       1: if (allocate_pages (prot_size, &align,
       2:             min_align, relocatable,
       3:             preffered_address))
       4:   goto fail;
       1: /* Allocate pages for the real mode code and the protected mode code
       2:    for linux as well as a memory map buffer.  */
       3: static grub_err_t
       4: allocate_pages (grub_size_t prot_size, grub_size_t *align,
       5:         grub_size_t min_align, int relocatable,
       6:         grub_uint64_t prefered_address)
       7: {
       8:   grub_err_t err;
       9:  
      10:   prot_size = page_align (prot_size);
      11:  
      12:   /* Initialize the memory pointers with NULL for convenience.  */
      13:   free_pages ();
      14:  
      15:   relocator = grub_relocator_new ();
      16:   if (!relocator)
      17:     {
      18:       err = grub_errno;
      19:       goto fail;
      20:     }
      21:  
      22:   /* FIXME: Should request low memory from the heap when this feature is
      23:      implemented.  */
      24:  
      25:   {
      26:     grub_relocator_chunk_t ch;
      27:     if (relocatable)
      28:       {
      29:     err = grub_relocator_alloc_chunk_align (relocator, &ch,
      30:                         prefered_address,
      31:                         prefered_address,
      32:                         prot_size, 1,
      33:                         GRUB_RELOCATOR_PREFERENCE_LOW,
      34:                         1);
      35:     for (; err && *align + 1 > min_align; (*align)--)
      36:       {
      37:         grub_errno = GRUB_ERR_NONE;
      38:         err = grub_relocator_alloc_chunk_align (relocator, &ch,
      39:                             0x1000000,
      40:                             0xffffffff & ~prot_size,
      41:                             prot_size, 1 << *align,
      42:                             GRUB_RELOCATOR_PREFERENCE_LOW,
      43:                             1);
      44:       }
      45:     if (err)
      46:       goto fail;
      47:       }
      48:     else
      49:       err = grub_relocator_alloc_chunk_addr (relocator, &ch,
      50:                          prefered_address,
      51:                          prot_size);
      52:     if (err)
      53:       goto fail;
      54:     prot_mode_mem = get_virtual_current_address (ch);
      55:     prot_mode_target = get_physical_target_address (ch);
      56:   }
      57:  
      58:   grub_dprintf ("linux", "prot_mode_mem = %lx, prot_mode_target = %lx, prot_size = %x
    ",
      59:                 (unsigned long) prot_mode_mem, (unsigned long) prot_mode_target,
      60:         (unsigned) prot_size);
      61:   return GRUB_ERR_NONE;
      62:  
      63:  fail:
      64:   free_pages ();
      65:   return err;
      66: }

        if (err)
          goto fail;
          }
        else
          err = grub_relocator_alloc_chunk_addr (relocator, &ch,
                             prefered_address,
                             prot_size);
        if (err)
          goto fail;
        prot_mode_mem = get_virtual_current_address (ch);
        prot_mode_target = get_physical_target_address (ch);

    进行重定位操作,并且分配物理内存页。

    (Grub部分还需要更多的Research.)

     

    当内核映像被加载到内存中,并且阶段 2 的引导加载程序释放控制权之后,内核阶段就开始了。内核映像并不是一个可执行的内核,而是一个压缩过的内核映像。通常它是一个 zImage(压缩映像,小于 512KB)或一个 bzImage(较大的压缩映像,大于 512KB),它是提前使用 zlib 进行压缩过的。在这个内核映像前面是一个例程,它实现少量硬件设置,并对内核映像中包含的内核进行解压,然后将其放入高端内存中,如果有初始 RAM 磁盘映像,就会将它移动到内存中,并标明以后使用。然后该例程会调用内核,并开始启动内核引导的过程。

    当 bzImage(用于 i386 映像)被调用时,我们从 ./arch/i386/boot/head.Sstart 汇编例程开始执行(主要流程图请参看图 3)。这个例程会执行一些基本的硬件设置,并调用./arch/i386/boot/compressed/head.S 中的 startup_32 例程。此例程会设置一个基本的环境(堆栈等),并清除 Block Started by Symbol(BSS)。然后调用一个叫做 decompress_kernel 的 C 函数(在 ./arch/i386/boot/compressed/misc.c 中)来解压内核。当内核被解压到内存中之后,就可以调用它了。这是另外一个 startup_32 函数,但是这个函数在 ./arch/i386/kernel/head.S 中。

    在这个新的 startup_32 函数(也称为清除程序或进程 0)中,会对页表进行初始化,并启用内存分页功能。然后会为任何可选的浮点单元(FPU)检测 CPU 的类型,并将其存储起来供以后使用。然后调用 start_kernel 函数(在 init/main.c 中),它会将您带入与体系结构无关的 Linux 内核部分。实际上,这就是 Linux 内核的 main 函数。

    http://www.ibm.com/developerworks/cn/linux/l-linuxboot/

    所有这些尝试都失败后我们先假设

    因此Grub会将控制权交给Setup Sector的起始位置,即内核映像中的第二个扇区。

    即跳转到_start标号处执行:

       1: .globl    _start
       2: rt:
       3:     # Explicitly enter this as bytes, or the assembler
       4:     # tries to generate a 3-byte jump here, which causes
       5:     # everything else to push off to the wrong offset.
       6:     .byte    0xeb        # short (2-byte) jump
       7:     .byte    start_of_setup-1f
       8: 1:
       9:  
      10: # Part 2 of the header, from the old setup.S

    4. setup程序

       1: .section ".entrytext", "ax"
       2: start_of_setup:
       3: #ifdef SAFE_RESET_DISK_CONTROLLER
       4: # Reset the disk controller.
       5:     movw    $0x0000, %ax        # Reset disk controller
       6:     movb    $0x80, %dl        # All disks
       7:     int    $0x13
       8: #endif
       9:  
      10: # Force %es = %ds
      11:     movw    %ds, %ax
      12:     movw    %ax, %es
      13:     cld
      14:  
      15: # Apparently some ancient versions of LILO invoked the kernel with %ss != %ds,
      16: # which happened to work by accident for the old code.  Recalculate the stack
      17: # pointer if %ss is invalid.  Otherwise leave it alone, LOADLIN sets up the
      18: # stack behind its own code, so we cant blindly put it directly past the heap.
      19:  
      20:     movw    %ss, %dx
      21:     cmpw    %ax, %dx    # %ds == %ss?
      22:     movw    %sp, %dx
      23:     je    2f        # -> assume %sp is reasonably set
      24:  
      25:     # Invalid %ss, make up a new stack
      26:     movw    $_end, %dx
      27:     testb    $CAN_USE_HEAP, loadflags
      28:     jz    1f
      29:     movw    heap_end_ptr, %dx
      30: 1:    addw    $STACK_SIZE, %dx
      31:     jnc    2f
      32:     xorw    %dx, %dx    # Prevent wraparound
      33:  
      34: 2:    # Now %dx should point to the end of our stack space
      35:     andw    $~3, %dx    # dword align (might as well...)
      36:     jnz    3f
      37:     movw    $0xfffc, %dx    # Make sure we are not zero
      38: 3:    movw    %ax, %ss
      39:     movzwl    %dx, %esp    # Clear upper half of %esp
      40:     sti            # Now we should have a working stack
      41:  
      42: # We will have entered with %cs = %ds+0x20, normalize %cs so
      43: # it is on par with the other segments.
      44:     pushw    %ds
      45:     pushw    $6f
      46:     lretw
      47: 6:
      48:  
      49: # Check signature at end of setup
      50:     cmpl    $0x5a5aaa55, setup_sig
      51:     jne    setup_bad
      52:  
      53: # Zero the bss
      54:     movw    $__bss_start, %di
      55:     movw    $_end+3, %cx
      56:     xorl    %eax, %eax
      57:     subw    %di, %cx
      58:     shrw    $2, %cx
      59:     rep; stosl
      60:  
      61: # Jump to C code (should not return)
      62:     calll    main
      63:  
      64: # Setup corrupt somehow...
      65: setup_bad:
      66:     movl    $setup_corrupt, %eax
      67:     calll    puts
      68:     # Fall through...
      69:  
      70:     .globl    die
      71:     .type    die, @function
      72: die:
      73:     hlt
      74:     jmp    die
      75:  
      76:     .size    die, .-die
      77:  
      78:     .section ".initdata", "a"
      79: setup_corrupt:
      80:     .byte    7
      81:     .string    "No setup signature found...
    "

    最重要的语句:

    # Jump to C code (should not return)
        calll    main

    下面就跳到了C语言部分了。

  • 相关阅读:
    android常见错误-
    android常见错误-Unexpected namespace prefix "xmlns" found for tag LinearLayout
    从零学习IOS-VirtualBox-4.3.20-96997-Win
    android常见错误--INSTALL_FAILED_DEXOPT
    android常见错误-The container 'Android Dependencies' references non existing library
    从零开始学android开发-开发环境的选择
    传微软欲收购Xamarin:未来有望通过VS开发iOS和Android应用?
    SQLSERVER2008 18456错误
    windows 2003 远程登录时如何修改管理员密码
    python的web压力测试工具-pylot安装使用
  • 原文地址:https://www.cnblogs.com/long123king/p/3543872.html
Copyright © 2011-2022 走看看