Linux内核引导过程学习

Linux 内核引导过程 学习


开机加电整体过程

上电
BIOS
bootsect
setup
main

BIOS

BIOS的启动由硬件完成,CPU的硬件逻辑设计为加电瞬间强行将CS的值射中为0xF000,IP设置为0xFFF0。这样CS:IP就指向0XFFFF0,作为BIOS的程序入口地址。

BIOS
BIOS自检
加载中断向量表和服务程序

加载bootsect

完成BIOS启动后,CPU会接收到 int 0x19 的中断向量,会加载相应的服务程序,将0号磁头对应软盘的0磁道1扇区MBR(Master Boot Record)内容复制到内存 0X7C00处

0X19中断
中断向量表
启动中断服务程序
拷贝程序
  • header.S 源码解读
BOOTSEG		= 0x07C0		/* original address of boot-sector */
SYSSEG		= 0x1000		/* historical load address >> 4 */

#ifndef SVGA_MODE                       #  VGA 视频模式
#define SVGA_MODE ASK_VGA
#endif

#ifndef ROOT_RDONLY
#define ROOT_RDONLY 1
#endif

	.code16
	.section ".bstext", "ax"

	.global bootsect_start
bootsect_start:                         # boostsect 启动
#ifdef CONFIG_EFI_STUB                  # 适配的pecoff格式,UEFI启动模式(区别于BOOT)
	# "MZ", MS-DOS header
	.byte 0x4d
	.byte 0x5a
#endif

	# Normalize the start address
	ljmp	$BOOTSEG, $start2   # 控制台跳转到 0x07C0 + S(offset) 处 也就是start2

start2:
	movw	%cs, %ax            # cs目前是0x07C0
	movw	%ax, %ds            # 初始化 指令(CS)、数据(DS)、堆栈(SS)、其他(ES)寄存器
	movw	%ax, %es
	movw	%ax, %ss
	xorw	%sp, %sp
	sti                         # 使能中断
	cld                         # 清方向标志位

	movw	$bugger_off_msg, %si   # 将 si 指向 打印信息(bugger_off_msg)

msg_loop:                       # 打印信息
	lodsb                       # 将Si指向的内存读入累加器
	andb	%al, %al
	jz	bs_die                  # 如果al 为0 则跳转 bs_die
	movb	$0xe, %ah
	movw	$7, %bx
	int	$0x10                   # 0x10是BIOS视频中断,用于打印字符
	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
#ifdef CONFIG_EFI_STUB
	.org	0x3c
	#
	# Offset to the PE header.
	#
	.long	pe_header
#endif /* CONFIG_EFI_STUB */

	.section ".bsdata", "a"
bugger_off_msg:                 # 打印的信息
	.ascii	"Use a boot loader.\r\n"
	.ascii	"\n"
	.ascii	"Remove disk and press any key to reboot...\r\n"
	.byte	0

...     #  这里省略了针对UFI模式的启动适配

	# 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 加载多少16字节作为保护模式的代码*/
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           # 第一扇区的字节数正好是512字节

上述字节数没有达到512B, 再看一下 setup.ld的源码:

	. = 0;
	.bstext		: { *(.bstext) }
	.bsdata		: { *(.bsdata) }

	. = 495;                       # 495 + 17 = 512
	.header		: { *(.header) }
	.entrytext	: { *(.entrytext) }
	.inittext	: { *(.inittext) }
	.initdata	: { *(.initdata) }
	__end_init = .;

PS: 上述过程是软盘时代的引导过程,Linux为了兼容软盘加载所存在的代码,正好是512字节,放到第一个扇区内,最新的Linux 内核已经基本放弃了软盘启动, 已经有GRUB来管理系统的引导启动

  • LILO 和 GRUB

LILO: LInux LOader
GRUB: GRandUnified Bootloader
//to do

SETUP

上面说到.header偏移了495, 而512处正好是_start, 也就是入口,但是这里是存放 hdr的数据结构信息,那么需要保证不破坏数据结构.

_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

可以看见 这里其实是一个Jump
.hdr中会设置默认的大内核地址,

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

当 with boot protocol version >= 2.02 ,内存布局如下:

	~                        ~
	|  Protected-mode kernel |
100000  +------------------------+
	|  I/O memory hole	 |
0A0000	+------------------------+
	|  Reserved for BIOS	 |	Leave as much as possible unused
	~                        ~
	|  Command line		 |	(Can also be below the X+10000 mark)
X+10000	+------------------------+
	|  Stack/heap		 |	For use by the kernel real-mode code.
X+08000	+------------------------+
	|  Kernel setup		 |	The kernel real-mode code.
	|  Kernel boot sector	 |	The kernel legacy boot sector.
X       +------------------------+
	|  Boot loader		 |	<- Boot sector entry point 0000:7C00
001000	+------------------------+
	|  Reserved for MBR/BIOS |
000800	+------------------------+
	|  Typically used by MBR |
000600	+------------------------+
	|  BIOS use only	 |
000000	+------------------------+

接下来就是需要为调用mian做准备,设置堆栈等:

	.section ".entrytext", "ax"
start_of_setup:
# Force %es = %ds
	movw	%ds, %ax
	movw	%ax, %es
	cld

...  # 设置堆栈

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

setup.ld 内会把 setup_sig 设置:

	.signature	: {
		setup_sig = .;
		LONG(0x5a5aaa55)
	}

然后清空 bss,跳转main

# 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
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值