Linux学习笔记 - Linux系统启动

计算机在刚加电的时刻,RAM芯片中所包含的随机数据,此时并没有操作系统在运行。在启动的时候,硬件会产生一个RESET信号,此时处理器就会将一些寄存器例如CS和EIP设置成固定值,从而执行物理地址0xFFFFFFF0处的代码,此处通常被映射在ROM中,包含一条跳转指令,跳转到真正的初始化程序的起始点(通常为BIOS)。

BIOS

BIOS使用实地址,由 seg * 16 + offsef 构成,因此不需要将逻辑地址转换为物理地址。而且,对GDT、LDT和页表的初始化代码必须在实模式下完成。

  • 对硬件进行一系列测试(POST)
  • 初始化硬件设备,保证不引起IRQ与I/O冲突
  • 搜索一个可以启动的操作系统
  • 将启动设备第一个扇区的内容拷贝到0x00007c00,跳转到此处开始运行

Bootloader

被BIOS装入内存后,bootloader把包含内核映像的其他扇区拷贝到RAM中。Linux的bootloader一般有Linux Loader(LILO)和Grand Unified Bootloader(GRUB)。对于硬盘,它被放在MBR或者每个磁盘的引导扇区上。允许用户选择启动多个操作系统中的哪一个。

Bootloader一般分为两个阶段,第一阶段的代码被BIOS搬到0x00007c00,它又将自己移动到0x00096a00,建立实模式堆栈,并将第二阶段的代码装入0x00096c00启动的内存中。第二部分依次读取操作系统映射表,提示用户选择一个操作系统以便启动。在用户选择或等待一阵后,开始载入内核映像:

  • 通过一个BIOS调用显示启动信息
  • 通过一个BIOS调用从磁盘载入映像的前512字节到0x00090000起始的内存中,将setup()的代码载入到0x00090200起始的内存中
  • 通过一个BIOS调用从磁盘载入映像的剩余部分,并将内核映像放入低地址0x00010000(对于zImage)或0x00100000(对于bzImage)
  • 跳转到setup()的代码

setup()

setup()的汇编代码由链接程序放在内核映像偏移量0x200处,因此bootloader很容易确定setup()的位置,并将其拷贝到0x00090200。

虽然BIOS初始化了大部分硬件设备,但Linux运行时不依赖于BIOS,而是以自己的方式重新初始化设备,增强了可移植性和健壮性,这些工作正是由此函数来完成:

  • 在RAM中建立系统物理内存布局表
  • 设置键盘延时与速率
  • 初始化显卡
  • 重新初始化磁盘控制器并检测硬盘参数
  • 检查鼠标
  • 若内核映像不在0x00001000,则移动它到此处
  • 建立临时的IDT和GDT
  • 重新编写中断控制器,屏蔽除IRQ2(两中断控制器级联用)以外的所有中断
  • 设置cr0寄存器的PE位,切换CPU到保护模式;清除PG位,还不启用分页
  • 跳转到startup_32()函数

startup_32()

1. arch/i386/boot/compressed/head.S中的startup_32():

在setup()结束后,startup_32()被搬移到固定的物理地址0x00100000或0x00001000处,并开始执行:

  • 初始化段寄存器和临时堆栈
  • 清除eflags寄存器
  • 用0填充_edata和_end标示的内核未初始化数据区
  • 调用decompress_kernel()解压内核映像,并将解压后的映像再次搬移到0x00100000
  • 跳转到0x00100000处

2. arch/i386/kernel/head.S中的startup_32():

解压的映像以同名的startup_32()开始,为Linux进程0建立环境:

  • 设置段寄存器为最终值
  • 用0填充bss段
  • 初始化临时内核页表,初始化pg0
  • 将页全局目录的地址放到cr3寄存器中,设置cr0的PG位,启用分页
  • 为进程0建立内核态堆栈
  • 再次清零eflags寄存器
  • 使用setup_idt()填充IDT为空中断处理程序
  • 获取BIOS中的传递的参数,并放入第一个页框中
  • 识别处理器型号
  • 用GDT和IDT的地址填充gdtr和idtr寄存器
  • 跳转到start_kernel()

start_kernel()

完成内核部件的初始化:

  • sched_init() 初始化调度程序
  • build_all_zonelist() 初始化内存管理区
  • page_alloc_init() 初始化Buddy分配程序
  • trap_init() & init_IRQ() 初始化IDT
  • softirq_init() 初始化软中断
  • time_init() 初始化日期时间
  • kmem_cache_init() 初始化slab分配器
  • calibrate_delay() 获取时钟速度
  • kernel_thread() 创建内核线程1,进而创建其他内核线程
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值