现在的位置: 首页 > 综合 > 正文

内核文件分析—I—Header.S的分析

2013年02月07日 ⁄ 综合 ⁄ 共 8773字 ⁄ 字号 评论关闭

 从开始到 # offset 512, entry point 功能和以前的bootsect.

  后面的功能和setup.S的一部分

类似:

    1:设置setup header参数部分

    2:start_of_setup

       1):设置堆栈

       2):检查setup中的标签

      
3):清除BSS段

       4):调用C入口main

/*

 * header.S

 *

 * Copyright (C) 1991, 1992
Linus Torvalds

 *

 * Based on bootsect.S and setup.S

 * modified
by more people than can be counted

 *

 * Rewritten as a common
file by H. Peter Anvin (Apr 2007)

 *

 * BIG FAT NOTE: We're in
real mode using 64k segments.  Therefore segment

 * addresses must be
multiplied by 16 to obtain their respective linear

 * addresses. To
avoid confusion, linear addresses are written using leading

 * hex
while segment addresses are written as segment:offset.

 *

 */

#include <asm/segment.h>

#include
<linux/utsrelease.h>

#include <asm/boot.h>

#include
<asm/e820.h>

#include <asm/page_types.h>

#include
<asm/setup.h>

#include "boot.h"

#include "voffset.h"

#include
"zoffset.h"

BOOTSEG  = 0x07C0  /* original
address of boot-sector */

SYSSEG  = 0x1000  /* historical load
address >> 4 */

#ifndef SVGA_MODE

#define SVGA_MODE ASK_VGA

#endif

#ifndef RAMDISK

#define RAMDISK 0

#endif

#ifndef ROOT_RDONLY

#define ROOT_RDONLY 1

#endif

 .code16              //以下为16位模式
代码

 .section ".bstext", "ax"  //定义一个
。bstext段,这个段是可写'a'和可执行'x'的

 .global bootsect_start  
//AT&T汇编语法中, .global 修饰使得 符号bootsect_start   对ld可见

bootsect_start:              
//符号定义

 # Normalize the start address

 ljmp $BOOTSEG,
$start2   //跳转到 07C0的偏移 start2处

start2:

 movw %cs, %ax

 movw %ax, %ds

 movw %ax,
%es

 movw %ax, %ss  //将ds,es,ss全设置为cs

 xorw %sp,
%sp   //将sp置0

 sti                //开中断

      

 cld              //清方向标志

 movw $bugger_off_msg, %si  //把下
面bugger_off_msg 符号的偏移地址放在 si寄存器中

msg_loop:

 lodsb   
//把si指向的源串的内容逐步装入al 中     PS:stosb 指的是将al中数据装入di指向的地址中.

 andb %al, %al   //当取完的时候,al=0
,此时操作andb后方向为0,执行下句跳转

 jz bs_die  

 movb $0xe, %ah

 movw $7,
%bx

 int $0x10     // 视频服务中断指令, AH = 0Eh, AL = Character, BL = Color
(only in graphic mode)

 jmp msg_loop

bs_die:

 # Allow the user to press a key, then
reboot

 xorw %ax, %ax

 int $0x16

 int $0x19

 # int 0x19 should never return.  In case it does
anyway,

 # invoke the BIOS reset code...

 ljmp $0xf000,$0xfff0   //跳转到bios入口 fff0

 .section ".bsdata", "a"

bugger_off_msg:

 .ascii "Direct
booting from floppy is no longer supported./r/n"

 .ascii "Please use
a boot loader program instead./r/n"

 .ascii "/n"

 .ascii "Remove
disk and press any key to reboot . . ./r/n"

 .byte 0

#可以看出以上的bootsect无任何实际意义,其实2.6以后的
内核需要另外的bootloader才可以 ,例如grub等.

在grub的boot_func中的big_linux_boot
里,描述了实际上grub的stage2将内核的
bootsect和setup实模式代码载入到地址0x90000后,是skip了头0x200个字节的,直接跳转到地址0x90200处执行的。 


 # Kernel attributes; used by
setup.  This is part 1 of the header, from the old boot sector.

 .section ".header", "a"   
//header段

 .globl hdr                   
//定义一个全局的符号

hdr:
setup_sects: .byte
0   /* Filled in by build.c */   //.byte是类型定义 
,这行及以下是一个首部的设置  01F1

root_flags: .word
ROOT_RDONLY                         //01F2

syssize: .long
0   /* Filled in by build.c */   //01F4

ram_size: .word
0   /* Obsolete */  

vid_mode: .word SVGA_MODE

root_dev: .word
0   /* Filled in by build.c */

boot_flag: .word 0xAA55   

//01FE

 # offset 512, entry point    

 

以上生成的程序偏
移地址从 0000~~~01ff  就是512Bytes的bootsect.

------------------------------------------------------------------------------------------------------------------------------------------------------------------

下面的就是真正的setup代码了,从偏移0x0200开始.0200
位置处有一个Jump指令

 .globl _start   

_start:

  # Explicitly enter
this as bytes, or the assembler

  # tries to generate a 3-byte jump
here, which causes

  # everything else to push off to the wrong
offset.
  .byte 0xeb  # short (2-byte) jump  
//0200的第一个字节是跳转指令.  

  .byte start_of_setup-1f                
//0201是跳转距离,(start_of_setup-1f)其实就是 setup中的头部长度.

1:

 
# Part 2 of the header, from
the old setup.S  

  .ascii "HdrS"  # header
signature      //0202

  .word 0x020a  # header version number (>=
0x0105)

     # or else old loadlin-1.5 will fail)
  .globl realmode_swtch

realmode_swtch: .word 0, 0  # default_switch, SETUPSEG

start_sys_seg: .word SYSSEG

  #
obsolete and meaningless, but just

     # in case something decided
to "use" it
  .word kernel_version-512 #
pointing to kernel version string

     # above section of
header is compatible

     # with loadlin-1.5 (header v1.5). Don't

     #
change it.

type_of_loader: .byte 0

  #
0 means ancient bootloader, newer

     # bootloaders know to change
this.

     # See Documentation/i386/boot.txt for

     # assigned
ids

# flags, unused bits must be zero (RFU) bit within
loadflags
loadflags:

LOADED_HIGH = 1   # If set, the kernel is loaded high

    //大内核

CAN_USE_HEAP =
0x80  

 # If set, the loader also has set 

     #
heap_end_ptr to tell how much

     # space behind setup.S can be used
for

     # heap purposes.

     # Only the loader knows what is
free
  .byte LOADED_HIGH    //添加符号

setup_move_size: .word 
0x8000  # size to move, when setup is not

     # loaded at
0x90000. We will move setup

     # to 0x90000 then just before
jumping

     # into the kernel. However, only the

     # loader
knows how much data behind

     # us also needs to be loaded.

code32_start:    # here loaders can put a different

     #
start address for 32-bit code.

  .long 0x100000 # 0x100000 = default
for big kernel

ramdisk_image: .long 0  # address of loaded ramdisk
image

     # Here the loader puts the 32-bit

     # address where
it loaded the image.

     # This only will be read by the kernel.

ramdisk_size: .long 0  # its size in bytes

bootsect_kludge:

  .long 0  # obsolete

heap_end_ptr: .word _end+STACK_SIZE-512

     #
(Header version 0x0201 or later)

     # space from here (exclusive)
down to

     # end of setup code can be used by setup

     # for
local heap purposes.

ext_loader_ver:

  .byte 0  # Extended boot loader
version

ext_loader_type:

  .byte 0  # Extended boot loader type

cmd_line_ptr: .long 0  # (Header version 0x0202 or
later)

     # If nonzero, a 32-bit pointer

     # to the kernel
command line.

     # The command line should be

     # located
between the start of

     # setup and the end of low

     # memory
(0xa0000), or it may

     # get overwritten before it

     # gets
read.  If this field is

     # used, there is no longer

     #
anything magical about the

     # 0x90000 segment; the setup

     #
can be located anywhere in

     # low memory 0x10000 or higher.

ramdisk_max: .long 0x7fffffff

     # (Header
version 0x0203 or later)

     # The highest safe address for

     #
the contents of an initrd

     # The current kernel allows up to 4
GB,

     # but leave it at 2 GB to avoid

     # possible
bootloader bugs.

kernel_alignment:  .long
CONFIG_PHYSICAL_ALIGN #physical addr alignment

      #required for
protected mode

      #kernel

#ifdef CONFIG_RELOCATABLE

relocatable_kernel:   
.byte 1

#else

relocatable_kernel:    .byte 0

#endif

min_alignment:  .byte
MIN_KERNEL_ALIGN_LG2 # minimum alignment

pad3:   .word 0

cmdline_size:   .long   COMMAND_LINE_SIZE-1    
#length of the command line,

                                               
#added with boot protocol

                                               
#version 2.06

hardware_subarch: .long 0   # subarchitecture, added
with 2.07

      # default to 0 for normal x86 PC

hardware_subarch_data: .quad 0

payload_offset:  .long ZO_input_data

payload_length:  .long
ZO_z_input_len

setup_data:  .quad 0   # 64-bit physical pointer to

      #
single linked list of

      # struct setup_data

pref_address:  .quad LOAD_PHYSICAL_ADDR # preferred
load addr

#define ZO_INIT_SIZE (ZO__end - ZO_startup_32 +
ZO_z_extract_offset)

#define VO_INIT_SIZE (VO__end - VO__text)

#if
ZO_INIT_SIZE > VO_INIT_SIZE

#define INIT_SIZE ZO_INIT_SIZE

#else

#define
INIT_SIZE VO_INIT_SIZE

#endif

init_size:  .long INIT_SIZE  #
kernel initialization size

# End of setup
header ,首部设置完毕,现在开始start_of_setup:

   .section ".entrytext", "ax"    //声明一个段

start_of_setup:

#ifdef SAFE_RESET_DISK_CONTROLLER

#
Reset the disk controller.

 movw $0x0000, %ax  # Reset disk
controller

 movb $0x80, %dl  # All disks

 int $0x13  
#用13号中断重设磁盘控制器 ax=0x0 ,dl=0x80

#endif

 

# Force %es = %ds   #ds:数据段 es:附加数据段

 movw %ds,
%ax

 movw %ax, %es

 cld    #清方向标志位DF=0

 

# Apparently some ancient versions of LILO invoked the
kernel with %ss != %ds,

# which happened to work by accident for the
old code.  Recalculate the stack

# pointer if %ss is invalid. 
Otherwise leave it alone, LOADLIN sets up the

# stack behind its own
code, so we can't blindly put it directly past the heap.

 movw %ss, %dx

 cmpw %ax, %dx    #
%ds == %ss? #ax里的还是ds的值,现在就是比较 ds和ss的值

 movw %sp, %dx   #再把dx设置位栈顶指针值

 je 2f  #
-> assume %sp is reasonably set   #如果比较相等,则跳转到 前面(f表前,b表后)的 标号2处
,不相等就新建一个栈

 

 # Invalid %ss, make up a new stack  #ds和ss不相等的情况下

 
movw $_end, %dx      #把栈底设置给dx

 testb $CAN_USE_HEAP,
loadflags  #testb:两操作数(byte)做与运算,只修改标志位. 看内核头参数中有没有设置 CAN_USE_HEAP位.

 jz 1f                       
#如果与运算结果等于0,即设置了这一位则跳到下面标号1处

 movw heap_end_ptr, %dx 
#否则用heap_end_ptr变量作为栈底


1: addw $STACK_SIZE, %dx  
#将栈的大小加上设置的

 jnc 2f    //无进位时转移到标号2处

 xorw %dx,
%dx # Prevent wraparound   //,若有进位则将dx设置为0

 

2: 
# Now
%dx should point to the end of our stack space

 andw $~3,
%dx    # dword align (might as well...)

 jnz 3f 

 movw $0xfffc,
%dx # Make sure we're not zero


3: movw %ax, %ss        
//ss=ds了

 movzwl %dx, %esp # Clear upper half of %esp  //只用低16位的sp

 sti   # Now we should have a
working stack  #sti:置中断允许位

 

# We will have entered with %cs = %ds+0x20, normalize
%cs so

# it is on par with the other segments.

 pushw %ds

 pushw $6f

 lretw

6:

# Check signature at end of setup
 cmpl $0x5a5aaa55, setup_sig

 jne setup_bad

# Zero the bss

 movw $__bss_start,
%di

 movw $_end+3, %cx

 xorl %eax, %eax

 subw %di, %cx

 shrw $2,
%cx

 rep; stosl

# Jump to C code (should not return)

 calll main

# Setup corrupt somehow...

setup_bad:

 movl $setup_corrupt,
%eax

 calll puts

 # Fall through...

 .globl die

 .type die, @function

die:

 hlt

 jmp die

 .size die, .-die

 .section ".initdata", "a"

setup_corrupt:

 .byte 7

 .string "No
setup signature found.../n"

抱歉!评论已关闭.