header.S文件的初步解读

来源:互联网 发布:易语言手机版编程软件 编辑:程序博客网 时间:2024/05/06 15:25
/*
 * 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 <generated/utsrelease.h>
#include <asm/boot.h>
#include <asm/e820.h>
#include <asm/page_types.h>
#include <asm/setup.h>
#include <asm/bootparam.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 ROOT_RDONLY
#define ROOT_RDONLY 1
#endif


.code16
.section ".bstext", "ax"                //第一个section的名字


.global bootsect_start               /*当 PC启动后,x86结构的CPU将自动进入实模式,并从地址0xFFFF0开始自动执行程序代码,这个地址通常是ROM-BIOS中的地址。PC 机的BIOS将执行某些系统的检测,在物理地址0处开始初始化中断向量。然后,将硬盘 MBR 中的 Boot Loader 读到系统的 RAM 中,然后将控制权交给操作系统Boot Loader。Boot Loader将内核映象从硬盘上读到 RAM 中,也即将setup.elf读到0x90000处,还有vmlinux读到x0100000处,将然后跳转到内核的入口点去运行,也即开始启动操作系 统,这个入口点是0x90200处,刚好略过512B启动扇区。如果从软盘启动的话就会直接将启动扇区读到RAM中,然后开始执行的代码就是上面的,于是 会打印出: Direct booting from floppy is no longer supported.,也就是bugger_off_msg的第一条信息。现在的内核启动不支持从软盘启动。也就是说真正的开始处在0x90200处。*/

//表明如果不是软盘启动的话会跳到0x90200处,如果是软盘启动就会在0x90000处也就是下面的bootsect_start开始执行当然,bootsect_start主要功能就是显示屏显示一个不再支持软盘启动了,并且帮你重启电脑。如果不是软盘启动的话boot loader会跳转到下面的_start处开始启动。


bootsect_start:
#ifdef CONFIG_EFI_STUB
# "MZ", MS-DOS header
.byte 0x4d
.byte 0x5a
#endif


# Normalize the start address
ljmp $BOOTSEG, $start2     //跳转到start2处执行


start2:
movw %cs, %ax             //cs=Ox7C00 并用它给ax ds es ss 赋初值
movw %ax, %ds
movw %ax, %es
movw %ax, %ss
xorw %sp, %sp           //xorw 异或操作,因为两个操作数是一样的,所以异或结果为0,所以sp为0,其实等价于 mov $0 %sp
sti                                         //开中断
cld                                        //清标志寄存器方向位DF


movw $bugger_off_msg, %si             //把bugger_off_msg的地址赋给si源地址寄存器中。


msg_loop:
lodsb                                    //将ds:si出的字节读入al中
andb %al, %al              //对al执行与操作
jz bs_die                         //当AL为0时跳转到bs_die,即此时重启电脑
movb $0xe, %ah           //将$0xe 放到ax中的高地址ah中。           
movw $7, %bx               //将$7放到bx中
int $0x10                          //调用显示器中断  al中的内容将会显示在屏幕上,其实就是si中的内容 也就是bugger_off_msg处定义的内容
jmp msg_loop                  //循环


bs_die:
# Allow the user to press a key, then reboot
xorw %ax, %ax              //清空ax
int $0x16                          //调用键盘中断,等待用户输入
int $0x19


# int 0x19 should never return.  In case it does anyway,
# invoke the BIOS reset code...
ljmp $0xf000,$0xfff0        //跳转到0xfffo,该地址是bios读取的地址,等于是重启电脑。


#ifdef CONFIG_EFI_STUB
.org 0x3c
#
# Offset to the PE header.
#
.long pe_header
#endif /* CONFIG_EFI_STUB */


.section ".bsdata", "a"                                                            //第二段开始
bugger_off_msg:                                                                           //设置数据值,这段话,会经过上面的si显示到屏幕上
.ascii "Direct floppy boot is not supported. "               //这段话表示不在支持软盘启动了
.ascii "Use a boot loader program instead.\r\n"
.ascii "\n"
.ascii "Remove disk and press any key to reboot ...\r\n"
.byte 0


#ifdef CONFIG_EFI_STUB
pe_header:
.ascii "PE"
.word 0


coff_header:
#ifdef CONFIG_X86_32
.word 0x14c# i386
#else
.word 0x8664# x86-64
#endif
.word 3# nr_sections
.long 0# TimeDateStamp
.long 0# PointerToSymbolTable
.long 1# NumberOfSymbols
.word section_table - optional_header# SizeOfOptionalHeader
#ifdef CONFIG_X86_32
.word 0x306# Characteristics.
# IMAGE_FILE_32BIT_MACHINE |
# IMAGE_FILE_DEBUG_STRIPPED |
# IMAGE_FILE_EXECUTABLE_IMAGE |
# IMAGE_FILE_LINE_NUMS_STRIPPED
#else
.word 0x206# Characteristics
# IMAGE_FILE_DEBUG_STRIPPED |
# IMAGE_FILE_EXECUTABLE_IMAGE |
# IMAGE_FILE_LINE_NUMS_STRIPPED
#endif


optional_header:
#ifdef CONFIG_X86_32
.word 0x10b# PE32 format
#else
.word 0x20b# PE32+ format
#endif
.byte 0x02# MajorLinkerVersion
.byte 0x14# MinorLinkerVersion


# Filled in by build.c
.long 0# SizeOfCode


.long 0# SizeOfInitializedData
.long 0# SizeOfUninitializedData


# Filled in by build.c
.long 0x0000# AddressOfEntryPoint


.long 0x0200# BaseOfCode
#ifdef CONFIG_X86_32
.long 0# data
#endif


extra_header_fields:
#ifdef CONFIG_X86_32
.long 0# ImageBase
#else
.quad 0# ImageBase
#endif
.long 0x20# SectionAlignment
.long 0x20# FileAlignment
.word 0# MajorOperatingSystemVersion
.word 0# MinorOperatingSystemVersion
.word 0# MajorImageVersion
.word 0# MinorImageVersion
.word 0# MajorSubsystemVersion
.word 0# MinorSubsystemVersion
.long 0# Win32VersionValue


#
# The size of the bzImage is written in tools/build.c
#
.long 0# SizeOfImage


.long 0x200# SizeOfHeaders
.long 0# CheckSum
.word 0xa# Subsystem (EFI application)
.word 0# DllCharacteristics
#ifdef CONFIG_X86_32
.long 0# SizeOfStackReserve
.long 0# SizeOfStackCommit
.long 0# SizeOfHeapReserve
.long 0# SizeOfHeapCommit
#else
.quad 0# SizeOfStackReserve
.quad 0# SizeOfStackCommit
.quad 0# SizeOfHeapReserve
.quad 0# SizeOfHeapCommit
#endif
.long 0# LoaderFlags
.long 0x6# NumberOfRvaAndSizes


.quad 0# ExportTable
.quad 0# ImportTable
.quad 0# ResourceTable
.quad 0# ExceptionTable
.quad 0# CertificationTable
.quad 0# BaseRelocationTable


# Section table
section_table:
#
# The offset & size fields are filled in by build.c.
#
.ascii ".setup"
.byte 0
.byte 0
.long 0
.long 0x0# startup_{32,64}
.long 0# Size of initialized data
# on disk
.long 0x0# startup_{32,64}
.long 0# PointerToRelocations
.long 0# PointerToLineNumbers
.word 0# NumberOfRelocations
.word 0# NumberOfLineNumbers
.long 0x60500020# Characteristics (section flags)


#
# The EFI application loader requires a relocation section
# because EFI applications must be relocatable. The .reloc
# offset & size fields are filled in by build.c.
#
.ascii ".reloc"
.byte 0
.byte 0
.long 0
.long 0
.long 0# SizeOfRawData
.long 0# PointerToRawData
.long 0# PointerToRelocations
.long 0# PointerToLineNumbers
.word 0# NumberOfRelocations
.word 0# NumberOfLineNumbers
.long 0x42100040# Characteristics (section flags)


#
# The offset & size fields are filled in by build.c.
#
.ascii ".text"
.byte 0
.byte 0
.byte 0
.long 0
.long 0x0# startup_{32,64}
.long 0# Size of initialized data
# on disk
.long 0x0# startup_{32,64}
.long 0# PointerToRelocations
.long 0# PointerToLineNumbers
.word 0# NumberOfRelocations
.word 0# NumberOfLineNumbers
.long 0x60500020# Characteristics (section flags)


#endif /* CONFIG_EFI_STUB */


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


.section ".header", "a"
.globl sentinel
sentinel: .byte 0xff, 0xff        /* Used to detect broken loaders */


.globl hdr
hdr:
setup_sects: .byte 0/* Filled in by build.c */
root_flags: .word ROOT_RDONLY
syssize: .long 0/* Filled in by build.c */
ram_size: .word 0/* Obsolete */
vid_mode: .word SVGA_MODE
root_dev: .word 0/* Filled in by build.c */
boot_flag: .word 0xAA55


# offset 512, entry point


.globl _start                         /*这里是0x90200处  刚刚好过了512b,这里是现在真正操作系统的入口  之前的是软盘启动的时候会调用的 之前的一段在原始的linux中是一单独的文件bootsect.S,现在已经被合并到header.S中来了*/。


_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
.byte start_of_setup-1f
1:


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



.ascii "HdrS" # header signature
.word 0x020c# header version number (>= 0x0105)
# or else old loadlin-1.5 will fail)
.globl realmode_swtch
realmode_swtch: .word0, 0# default_switch, SETUPSEG
start_sys_seg: .wordSYSSEG# 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: .byte0# 0 means ancient bootloader, newer
# bootloaders know to change this.
# See Documentation/x86/boot.txt for
# assigned ids


# flags, unused bits must be zero (RFU) bit within loadflags
loadflags:
.byte LOADED_HIGH# The kernel is to be 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: .long0# 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: .long0# 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: .long0# (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


xloadflags:
#ifdef CONFIG_X86_64
# define XLF0 XLF_KERNEL_64 /* 64-bit kernel */
#else
# define XLF0 0
#endif


#if defined(CONFIG_RELOCATABLE) && defined(CONFIG_X86_64)
   /* kernel/boot_param/ramdisk could be loaded above 4g */
# define XLF1 XLF_CAN_BE_LOADED_ABOVE_4G
#else
# define XLF1 0
#endif


#ifdef CONFIG_EFI_STUB
# ifdef CONFIG_X86_64
#  define XLF23 XLF_EFI_HANDOVER_64 /* 64-bit EFI handover ok */
# else
#  define XLF23 XLF_EFI_HANDOVER_32 /* 32-bit EFI handover ok */
# endif
#else
# define XLF23 0
#endif


#if defined(CONFIG_X86_64) && defined(CONFIG_EFI) && defined(CONFIG_KEXEC)
# define XLF4 XLF_EFI_KEXEC
#else
# define XLF4 0
#endif


.word XLF0 | XLF1 | XLF23 | XLF4


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
handover_offset:
#ifdef CONFIG_EFI_STUB
  .long 0x30 # offset to the handover
# protocol entry point
#else
.long 0
#endif


# End of setup header #################################################### 

/*上面这些其实就是和那个hdr下标一块的,组成了一个结构,在x86/include/asm/bootparam.h中,struct setup_header。你可以按照结构体顺序对对,非常符合。当然了,它们都有含义的。具体见表*/



.section ".entrytext", "ax"
start_of_setup:
# Force %es = %ds                             //此处强制让es=ds
movw %ds, %ax
movw %ax, %es
cld


# 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?   
movw %sp, %dx
je 2f# -> assume %sp is reasonably set


# Invalid %ss, make up a new stack
movw $_end, %dx
testb $CAN_USE_HEAP, loadflags
jz 1f
movw heap_end_ptr, %dx               //设置堆大小
1: addw $STACK_SIZE, %dx               //把栈大小和堆相加,其实就是一起设置堆栈的大小
jnc 2f
xorw %dx, %dx# Prevent wraparound


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
movzwl %dx, %esp # Clear upper half of %esp
sti # Now we should have a working stack


# 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)                 //跳转到main函数,这header.S只是引导启动作用,真正做的很多复杂工作在main

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"



 /*

总结一下,做了哪些事情:

1、硬盘复位

2、检查并设置堆栈

3、检查setup.elf是否装入完全

4、将.bss段清0

5、跳入main函数(boot/main.c)

*/
0 0
原创粉丝点击