【Linux内核-02】引导(boot)与初始化(init)
引导启动程序(boot)
概述
boot/目录文件列表
bootsect.s
setup.s
head.s
注释:
实模式+Intel:bootsect.s, setup.s
保护模式+ATT:head.s
原理

步骤1:启动电源,CPU进入实模式,执行ROM-BIOS(位于内存0xFFFF0
处),其功能为:(1)硬件检测;(2)在物理地址0处设置中断向量;(3)将引导扇区(第一个扇区,512字节)加载到0x07c00
处。
步骤2:执行bootsect.s(位于内存0x7c00
处),其功能为:(1)将自身移动到0x90000
~0x90200
,共512B。(2)将setup模块(共四个扇区)加载到0x90200
处。(3)将内核system模块加载到0x10000
处。
步骤3:执行setup.s(位于内存0x90200
处),其功能为:(1)将system模块移动到物理内存起始地址。(2)进入保护模式并跳转到head.s
步骤4:执行head.s(位于内存0x00000
处),其功能为:(1)加载GDT、IDT、LDT;设置分页工作;完成保护模式的相关设置。(2)执行init/main.c
源码分析
bootsect.S
SETUPLEN = 4 ! setup程序代码占用扇区数
BOOTSEG = 0x07c0 ! bootsect程序代码所在内存原始地址
INITSEG = 0x9000 ! 将bootsect移动到0x9000处
SETUPSEG = 0x9020 ! setup程序开始的地址
! entry指定程序入口
entry _start
_start:
! 将自身复制到0x9000处
mov ax,#BOOTSEG
mov ds,ax !基址ds=0x7c00
mov ax,#INITSEG
mov es,ax ! 基址es=0x9000
mov cx,#256
sub si,si ! 偏移si=0
sub di,di ! 偏移di=0
! ds:si = 0x7c000
! es:di = 0x90000
rep movw ! 重复移动256字节(0x7c00→0x9000)
jmpi go,INITSEG ! CS=INITSEG, ip=go.(顺序执行)
go: mov ax,cs
mov ds,ax
mov es,ax
! 设置ds=es=cs=0x9000
! 加载setup.s程序
load_setup:
mov dx,#0x0000 ! dh:磁头号0, dl:驱动器号0
mov cx,#0x0002 ! ch:柱面号0, cl:开始扇区2
mov bx,#0x0200 ! es:bx = address = 0x9000 + 512
mov ax,#0x0200+SETUPLEN ! ah:读磁盘功能号2, al:扇区数量4
int 0x13 ! 读磁盘中断
jnc ok_load_setup ! ok,读setup.S到0x90200
!加载错误
mov dx,#0x0000
mov ax,#0x0000 ! 复位
int 0x13
j load_setup ! 重读
! 输出一些信息
ok_load_setup:
mov ah,#0x03 ! 当前位置
xor bh,bh
int 0x10 ! 中断:读当前光标
mov cx,#26 ! 读26个字符
mov bx,#0x000c ! page 0, attribute c
mov bp,#msg1 ! es:bp = 指向待显示字符串
mov ax,#0x1301 ! write string, move cursor
int 0x10 ! 显示中断
!开始执行setup代码
jmpi 0,SETUPSEG
msg1:
.byte 13,10 ! 回车:13 换行:10
.ascii "Duanos is loading..."
.byte 13,10,13,10
setup.S
entry _start
_start:
!设置cs=ds=es=0x9020
mov ax,cs
mov ds,ax
mov es,ax
mov ah,#0x03 ! 当前位置
xor bh,bh
int 0x10 ! 中断:读当前光标
mov cx,#28 ! 读28个字符
mov bx,#0x000c ! page 0, attribute c
mov bp,#msg1
mov ax,#0x1301 ! write string, move cursor
int 0x10
...
! 获取拓展内存大小 => 0x9000:2;不同机器不同的内存(1m扩展)
mov ah,#0x88
int 0x15
mov [2],ax
...
! 移动system(0x10000→0x00000)
do_move:
mov es,ax ! destination segment: ex=0x0000
add ax,#0x1000
cmp ax,#0x9000
jz end_move ! system内容覆盖boot
mov ds,ax ! source segment: ds=0x1000
sub di,di
sub si,si
! ds:si = 0x10000
! es:di = 0x00000
mov cx,#0x8000
rep movsw ! 重复移动8000字节
jmp do_move
...
! 进入保护模式
mov ax,#0x0001 ! 进入保护模式
lmsw ax ! mov cr0 ax (cr0 = 0 or 1 : 实模式 or 保护模式)
! 此时寻址方式已经由实模式(16位)切换为保护模式(32位)
jmpi 0,8 ! 跳转地址0x0000
head.s
... # startup_32
... # set gdt, idt, ldt, page_table
after_page_tables:
pushl $0
pushl $0
pushl $0 # main参数argv[3]
pushl $L6 # 返回地址,跳转到main()
pushl $main
jmp setup_paging
L6:
jmp L6 # 执行主函数
初始化程序(init)
概述
init/目录文件列表
main.c
内核初始化的相关工作
相关功能:各种初始化
- 初始化:陷阱门、块设备、字符设备和 tty。
- 开启中断,切换到任务0运行
原理

源码分析
void main(void)
{
//初始化工作
mem_init(main_memory_start,memory_end);
trap_init();
blk_dev_init();
chr_dev_init();
tty_init();
time_init();
sched_init();
buffer_init(buffer_memory_end);
hd_init();
floppy_init();
sti();
move_to_user_mode();
if (!fork()) { /* we count on this going ok */
init();
}
for(;;) pause();
}