栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 系统运维 > 运维 > Linux

Linux内核引导过程学习

Linux 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Linux内核引导过程学习

Linux 内核引导过程 学习
开机加电整体过程
BIOS

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

加载bootsect

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

  • header.S 源码解读
BOOTSEG		= 0x07C0		
SYSSEG		= 0x1000		

#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 

	.section ".bsdata", "a"
bugger_off_msg:                 # 打印的信息
	.ascii	"Use a boot loader.rn"
	.ascii	"n"
	.ascii	"Remove disk and press any key to reboot...rn"
	.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        

	.globl	hdr
hdr:
setup_sects:	.byte 0			
root_flags:	.word ROOT_RDonLY
syssize:	.long 0			
ram_size:	.word 0			
vid_mode:	.word SVGA_MODE
root_dev:	.word 0			
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
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/694451.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号