精华内容
下载资源
问答
  • 操作系统中有个重要的概念:引导程序 那有就有了系统引导过程,关于系统引导过程,各个百科已经给出很好的定义和流程说明,这里在给一个相对权威的链接可以参考,比较适合大部分人的理解过程:阮一峰:计算机是如何...

    操作系统中有个重要的概念:引导程序

    那有就有了系统引导过程,关于系统引导过程,各个百科已经给出很好的定义和流程说明,这里在给一个相对权威的链接可以参考,比较适合大部分人的理解过程:阮一峰:计算机是如何启动的?

    那么引导程序是装在哪里的呢?各个参考资料给出的答案是:固件

    固件(Firmware)就是写入EROM(可擦写只读存储器)或EEPROM(电可擦可编程只读存储器)中的程序。
    固件是指设备内部保存的设备“驱动程序”,通过固件,操作系统才能按照标准的设备驱动实现特定机器的运行动作,比如光驱、刻录机等都有内部固件。
    固件是担任着一个系统最基础最底层工作的软件。而在硬件设备中,固件就是硬件设备的灵魂,因为一些硬件设备除了固件以外没有其它软件组成,因此固件也就决定着硬件设备的功能及性能。–百度百科

    固件,其实就是各个硬件厂商,为了自己的硬件能够更好地被软件厂商使用,使用就给自己的硬件做了一些封装(其实就是初始的通用的软件)也就是固件(firmware)。
    而驱动,也固件的概念相似,但是它不是介于硬件和软件之间。固件是为硬件服务,而驱动是为了操作系统服务。也就是说各操作系统的驱动可能是不能兼容的。

    参考资料:


    操作系统引导过程
    驱动和固件的区别是什么
    操作系统引导程序学习笔记

    展开全文
  • 内核引导过程

    千次阅读 2016-05-23 17:00:21
    BROM引导 ARM CPU刚上电时,它的PC寄存器指针指向IC内嵌的一片ROM的起始位置处,这片ROM称之为BROM(boot rom),系统就是...BROM中会存储上电引导程序,这段程序也一般会包括以下几个内容:1. CPU上电初始化操作。 2.

    BROM引导
    ARM CPU刚上电时,它的PC寄存器指针指向IC内嵌的一片ROM的起始位置处,这片ROM称之为BROM(boot rom),系统就是通过这片BROM引导起来的。BROM的空间比较小,一般是32/64KB,IC上的ShareRAM大小也不尽相同,所以IC引导过程也是会有所不同。
    BROM中会存储上电引导程序,这段程序也一般会包括以下几个内容:

    1.  CPU上电初始化操作。
    2.  启动介质的驱动操作。
    3.  固件下载操作,用来进入刷机模式,更新时固件使用。
    4.  BROM引导程序,主要功能是用来从从启动介质中读取和加载第二阶段引导程序。
    5.  签名验证操作。
    

    BROM中的引导程序由IC厂商自己定制开发。它会根据硬件上不同,来判断要进入刷机模式还是启动模式,并且还要判断是从哪种介质中引导启动。接下来要从启动介质中读取MBREC上的引导程序到ShareRAM中,并跳转执行。BROM属于read only的,在SOC流片的时候就固定下来了,所以拿到SOC以后基本上就不会去修改了,而可定制化的东西都放在bootloader中实现。

    bootloader引导(第二阶段引导)
    ARM架构下使用的BROM引导,有点类似于X86下的BIOS引导,BROM内的引导固件一般是不会改变的,从第二阶段这里开始就进入了可定制的阶段,第二阶段的引导程序一般会单独放在启动介质的一个分区,我们叫它boot分区或者MBR分区(主引导分区)。
    我们可以把第二阶段引导分为多级引导:
    比如分为如下所示的三级引导过程:
    (1) firstMBRC
    第一级引导程序需要符合BROM引导所需要的格式,会调用BROM中的驱动函数把secondMBRC拷贝到shareRAM中校验,并跳转执行,这个都是独立代码,一般使用汇编来做。
    (2) secondMBRC(uboot-spl)
    第二级引导程序的功能是调用BROM中的驱动函数把mainMBRC拷贝到DDR 中校验,并跳转执行。第二阶段可以使用uboot中的spl来实现,也可以由自己独立代码实现。
    (3) mainMBRC(uboot)
    第三级是主要的引导程序,前面的两级引导都是为了加载mainMBRC,它的主要功能是显示启动logo,加载kernel、dtb、rootfs文件系统,并且启动kernel。一般使用uboot来做。
    所以在boot分区,我们要烧写入这三部分的引导代码,mbrc、uboot-spl、uboot。

    uboot引导
    采用uboot来启动的内核为uImage,这种内核包括两部分,一个是头部,一个是真正的内核,可以这样来表示uImage=uboot header+zImage。
    头部的定义为:

    typedef struct image_header {
    uint32_t ih_magic; /* Image Header Magic Number */
    uint32_t ih_hcrc; /* Image Header CRC Checksum */
    uint32_t ih_time; /* Image Creation Timestamp */
    uint32_t ih_size; /* Image Data Size */
    uint32_t ih_load; /* Data Load Address */
    uint32_t ih_ep; /* Entry Point Address */
    uint32_t ih_dcrc; /* Image Data CRC Checksum */
    uint8_t ih_os; /* Operating System */
    uint8_t ih_arch; /* CPU architecture */
    uint8_t ih_type; /* Image Type */
    uint8_t ih_comp; /* Compression Type */
    uint8_t ih_name[IH_NMLEN]; /* Image Name */
    } image_header_t;
    我们需要关心的是:
    uint32_t ih_load; /* Data Load Address */
    uint32_t ih_ep; /* Entry Point Address */
    ih_load是内核加载地址,即内核开始运行前应该位于的地方 ,ih_ep是内核入口地址,入口地址和加载地址可以相同。

    Uboot启动内核的过程是通过读取环境变量env中的bootcmd来决定如何启动kernel,比如uboot想从nand flash上读取kernel分区到内存地址的0x30007FC0上并且启动kernel,可以使用如下命令:bootcmd = nand read.jffs2 0x30007FC0 kernel; bootm 0x30007FC0。启动kernel的关键是bootm命令。
    bootm命令的实现在uboot中是do_bootm()函数中:
    源文件:cmd_bootm.c

    int do_bootm (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
    {
    …
     if (argc < 2) {
                addr = load_addr; 
    } else {
                addr = simple_strtoul(argv[1], NULL, 16);
    }
    /*从加载地址处读取uboot header并进行解析*/
    ……
    
       switch (hdr->ih_comp) { 
        case IH_COMP_NONE: 
                 if(ntohl(hdr->ih_load) == addr) { /
                       printf ("   XIP %s ... ", name);
                 } else {//
                       memmove ((void *) ntohl(hdr->ih_load), (uchar *)data, len);
                  }
    ……
    
    }
    

    首先判断bootm命令后面是否带了加载地址,若没有加载地址的参数,则将默认加载地址赋值给addr,否则将使用bootm命令后附带的地址作为加载地址。然后的关键是从加载地址处读取uboot header并且解析。从上面的代码逻辑我们可以看到,会判断ubootheader中的ih_load和bootm传入的加载地址是否一致,并由此区分了两种情况:
    (1)如果不同的话会把去掉头部(64Byte)的内核(zImage)复制到ih_load指定的地址中,并从ih_ep处开始启动内核。因此这种情况下,ih_load和ih_ep要相同。
    (2)如果相同的话那就让其原封不同的放在那,并从ih_ep处开始启动内核(zImage)。因此这种情况下,执行入口函数地址要和加载地址之间相差了一个uboot header。因此 ih_ep= ih_load+64Byte。

    有了上面的知识,那么我们如何去设置uboot header中的地址呢,其实这一步是在制作uImage的时候,使用mkimage工具指定的加载地址和运行地址。

    mkimage -A arm -O linux -C none -a 0x30008000 -e 0x30008000 -d zImage uImage
    -A:CPU类型
    -O:操作系统
    -C:采用的压缩方式
    -a:内核加载地址
    -e:内核入口地址

    制作镜像头以及下载地址就有两种情况:
    (1)mkimage -A arm -O linux -C none -a 0x30008000 -e 0x30008000 -d zImage uImage
    tftp 0x31000000 uImage
    bootm 0x31000000
    加载地址和入口地址相同,tftp和bootm后面的地址是任意地址(除了-a指定的地址外)。

    这种情况下uboot会对内核进行搬运的动作,搬运的是不包括uboot header的zImage,所以加载地址和入口地址要设置为相同。如果tftp和bootm后面的地址也是0x30008000,会出现什么情况呢?从上面的代码可以看出,如果相同,将不执行搬运动作,只打印除了一条信息,然后跳到入口地址进行执行,此时入口地址是一个uboot header,这里并不是可执行的zImage,所以将会报错。

    (2) mkimage -A arm -O linux -C none -a 0x30008000 -e 0x30008040 -d zImage uImage
    tftp 0x30008000 uImage
    bootm 0x30008000
    入口地址在加载地址后面64个字节,tftp和bootm后面的地址一定要在-a指定的加载地址上。

    我们一般习惯于使用第二种方法,并下载到–a所指定的地址上,这样就不用劳烦uboot进行搬运了,节省了启动时间。

    在上面的do_bootm 中,我们通过解析uboot header,已经获得了内核镜像相关的信息,其中就包括了内核入口地址,在引导的最后阶段,将跳转到内核中去执行。这一步是在do_bootm_linux()函数中实现的。通过一个函数指针 thekernel()带三个参数跳转到内核( zImage )入口点开始执行,此时, u-boot 的任务已经完成,控制权完全交给内核( zImage )。

    do_bootm_linux(),在arch\arm\lib\bootm.c定义,因为我们已经知道入口地址了,所以只需跳到入口地址就可以启动linux内核了。

    theKernel = (void (*)(int, int, uint))ntohl(hdr->ih_ep);
    theKernel (0, bd->bi_arch_number, bd->bi_boot_params);

    hdr->ih_ep—-Entry Point Address ,uImage 中指定的内核入口点,还记得ih_ep吗?其中第二个参数为机器 ID, 内核所设置的机器码和uboot所设置的机器码必须一致才能启动内核,第三参数为 u-boot 传递给内核参数存放在内存中的首地址。

    内核启动
    经过uboot引导以后,系统开始进入到zImage中执行。zImage是包括了解压缩代码和vmlinux的镜像,所以它的执行可以分为三部分,分别是zImage解压缩,vmlinux内核启动汇编阶段,vmlinux内核启动C语言阶段。

    (1) zImage解压缩
    (2) 内核启动汇编阶段
    (3) 内核启动c语言阶段(start_kernel到创建第一个进程)

    zImage解压缩
    这一阶段所涉及的文件也只有三个:
    (1)arch/arm/boot/compressed/vmlinux.lds
    (2)arch/arm/boot/compressed/head.S
    (3)arch/arm/boot/compressed/misc.c
    首先跳转到head.S中的start函数开始执行,结合lds文件可以看下具体流程,这一部分不做过多介绍。

    内核启动汇编阶段
    (这个阶段参考链接文件:arch/arm/kernel/vmlinux.lds)
    启动汇编阶段的代码是从arch/arm/kernel/head.S开始的,执行起点是stext函数。
    隔了一段时间回头来看,发现这里写的不够清楚,很容易造成歧义,需要注意的是lds文件中定义的_text/_stext仅仅是一个地址,并不和代码中的stext函数匹配,stext是函数名,它存在于.head.text段中。

    而lds文件中,_text标号存在于.head.text段中,_stext标号存在与.text段中,ENTRY入口点定义为stext,实际上是跑到了.head.text段中的stext函数里了。这里尤其需要注意区分概念。注意函数名和标号的区别,别搞混淆了。

    这部分主要完成的工作有cpu ID检查,machine ID检查,创建初始化页表,设置C代码运行环境,跳转到内核第一个真正的C函数start_kernel开始执行。
    这一阶段涉及到两个重要的结构体:
    (1) 一个是struct proc_info_list 主要描述CPU相关的信息,结构定义在文件arch/arm/include/asm/procinfo.h中,与其相关的函数及变量在文件arch/arm/mm/proc_xxx.S中被定义和赋值,比如arch/arm/mm/proc-v7.S文件是armv7使用的。
    (2) 另一个结构体是描述开发板或者说机器信息的结构体struct machine_desc,结构定义在arch/arm/include/asm/mach/arch.h文件中,其函数的定义和变量的赋值在板极相关文件arch/arm/mach-s3c2410/mach-smdk2410.c中实现,这也是内核移植非常重要的一个文件。
    该阶段一般由前面的解压缩代码调用,进入该阶段要求:
    MMU = off, D-cache = off, I-cache = dont care,r0 = 0, r1 = machine id.
    所有的机器ID列表保存在arch/arm/tools/mach-types 文件中,在编译时会生成相应的头文件在kernel/include/generated/ mach-types.h中。Kernel会根据传入的machine id查找到匹配的struct machine_desc结构,并使用其中的回调函数来启动kernel。

    在编译时,上面定义的两种结构体变量,struct proc_info_list会被链接到内核映像文件vmlinux的__proc_info_begin和__proc_info_end之间的段中。struct machine_desc会被链接到内核映像文件vmlinux的__arch_info_begin和__arch_info_end之间的段中。分别对应(.proc.info.init)和(.arch.info.init),可以参考下面的连接脚本vmlinux.lds。

    __proc_info_begin = .;
    *(.proc.info.init)
    __proc_info_end = .;
    __arch_info_begin = .;
    *(.arch.info.init)
    __arch_info_end = .;

    在汇编阶段执行的最后,会跳转到C语言阶段继续启动,在head-common.S中通过指令b start_kernel跳转到C代码中执行。

    内核启动C语言阶段
    C语言的入口函数定义在kernel/init/main.c中,通过函数start_kernel开始执行,它会调用到很多跟平台相关的函数,这部分函数的定义依然在kernel/arch/arm/mach-XXX目录中。

    比如machine的定义,在start_kernel就可以使用匹配的machine所定义的函数:

    对于平台smdk2410 来说其对应 machine_desc 结构在文件linux/arch/arm/mach-s3c2410/mach-smdk2410.c中初始化:

    MACHINE_START(SMDK2410, "SMDK2410")  
    .phys_io = S3C2410_PA_UART, 
    .io_pg_offst = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc, 
    .boot_params = S3C2410_SDRAM_PA + 0x100, 
    .map_io = smdk2410_map_io, 
    .init_irq = s3c24xx_init_irq, 
    .init_machine = smdk2410_init, 
    .timer = &s3c24xx_timer, 
    MACHINE_END 

    对于宏MACHINE_START 在文件 arch/arm/include/asm/mach/arch.h 中定义:

    #define MACHINE_START(_type,_name) / 
    static const struct machine_desc __mach_desc_##_type / 
     __used / 
     __attribute__((__section__(".arch.info.init"))) = { / 
    .nr = MACH_TYPE_##_type, / 
    .name = _name, 
    #define MACHINE_END / 
    }; 
    __attribute__((__section__(".arch.info.init")))表明该结构体在并以后存放的位置。

    还记得上面提到的vmlinux.lds中的信息吗?
    __arch_info_begin = .;
    *(.arch.info.init)
    __arch_info_end = .;
    所以上面定义的内容将被放到这个__arch_info_begin和__arch_info_end之间的段内。这样就使得在汇编文件中也可以显式查找到这个结构了。

    接下来就简单介绍一下CPU启动过程,如下所示:
    对于SMP,bootstrap CPU会在系统初始化的时候执行cpu_init函数,进行本CPU的初始化设定,具体调用序列是:

    start_kernel--->setup_arch--->setup_processor--->cpu_init--->rest_init-->cpu_startup_entry(parent thread)-->idle。
    

    对于系统中其他的CPU,bootstrap CPU会在系统初始化的最后,对每一个online的CPU进行初始化,具体的调用序列是:

    rest_init--->kernel_init(child thread)--->kernel_init_freeable-->smp_init--->cpu_up--->_cpu_up--->__cpu_up
    

    __cpu_up函数是和CPU architecture相关的。对于ARM,其调用序列是

    __cpu_up-->boot_secondary-->smp_ops.smp_boot_secondary
    -->secondary_startup-->__secondary_switched
    -->secondary_start_kernel-->cpu_init-->cpu_startup_entry

    其中涉及到的关键代码目录有:
    Kernel/init/—————————C语言启动入口
    Kernel/arch/arm/kernel/———-arm架构通用代码
    Kernel/arch/arm/mach-xxx/—–平台相关代码,移植重点

    展开全文
  • 计算机系统引导过程 主板BIOS系统进行硬件自检 硬盘主引导程序MBR 活动分区引导程序DBR 操作系统引导NTLDR 操作系统内核启动 驱动程序及服务 系统自启动程序 ...

      

    1. 主板BIOS系统进行硬件自检 
    2. 硬盘主引导程序MBR
    3. 活动分区引导程序DBR
    4. 操作系统引导NTLDR
    5. 操作系统内核启动
    6. 驱动程序及服务
    7. 系统自启动程序

    展开全文
  • Linux 引导过程内幕

    2017-12-13 15:46:22
    早期时,启动一台计算机意味着要给计算机喂一条包含引导程序的纸带,或者手工使用前端面板地址/数据/控制开关来加载引导程序。尽管目前的计算机已经装备了很多工具来简化引导过程,但是这一切并没有对整个过程进行...

    Linux 引导过程内幕

    从主引导记录到第一个用户空间应用程序的指导

    早期时,启动一台计算机意味着要给计算机喂一条包含引导程序的纸带,或者手工使用前端面板地址/数据/控制开关来加载引导程序。尽管目前的计算机已经装备了很多工具来简化引导过程,但是这一切并没有对整个过程进行必要的简化。

    让我们先从高级的视角来查看 Linux 引导过程,这样就可以看到整个过程的全貌了。然后将回顾一下在各个步骤到底发生了什么。在整个过程中,参考一下内核源代码可以帮助我们更好地了解内核源代码树,并在以后对其进行深入分析。

    概述

    图 1 是我们在 20,000 英尺的高度看到的视图。

    图 1. Linux 引导过程在 20,000 英尺处的视图


    当系统首次引导时,或系统被重置时,处理器会执行一个位于已知位置处的代码。在个人计算机(PC)中,这个位置在基本输入/输出系统(BIOS)中,它保存在主板上的闪存中。嵌入式系统中的中央处理单元(CPU)会调用这个重置向量来启动一个位于闪存/ROM 中的已知地址处的程序。在这两种情况下,结果都是相同的。因为 PC 提供了很多灵活性,BIOS 必须确定要使用哪个设备来引导系统。稍后我们将详细介绍这个过程。

    当找到一个引导设备之后,第一阶段的引导加载程序就被装入 RAM 并执行。这个引导加载程序在大小上小于 512 字节(一个扇区),其作用是加载第二阶段的引导加载程序。

    当第二阶段的引导加载程序被装入 RAM 并执行时,通常会显示一个动画屏幕,并将 Linux 和一个可选的初始 RAM 磁盘(临时根文件系统)加载到内存中。在加载映像时,第二阶段的引导加载程序就会将控制权交给内核映像,然后内核就可以进行解压和初始化了。在这个阶段中,第二阶段的引导加载程序会检测系统硬件、枚举系统链接的硬件设备、挂载根设备,然后加载必要的内核模块。完成这些操作之后启动第一个用户空间程序(init),并执行高级系统初始化工作。

    这就是 Linux 引导的整个过程。现在让我们深入挖掘一下这个过程,并深入研究一下 Linux 引导过程的一些详细信息。

    系统启动

    系统启动阶段依赖于引导 Linux 系统上的硬件。在嵌入式平台中,当系统加电或重置时,会使用一个启动环境。这方面的例子包括 U-Boot、RedBoot 和 Lucent 的 MicroMonitor。嵌入式平台通常都是与引导监视器搭配销售的。这些程序位于目标硬件上的闪存中的某一段特殊区域,它们提供了将 Linux 内核映像下载到闪存并继续执行的方法。除了可以存储并引导 Linux 映像之外,这些引导监视器还执行一定级别的系统测试和硬件初始化过程。在嵌入式平台中,这些引导监视器通常会涉及第一阶段和第二阶段的引导加载程序。

    在 PC 中,引导 Linux 是从 BIOS 中的地址 0xFFFF0 处开始的。BIOS 的第一个步骤是加电自检(POST)。POST 的工作是对硬件进行检测。BIOS 的第二个步骤是进行本地设备的枚举和初始化。

    给定 BIOS 功能的不同用法之后,BIOS 由两部分组成:POST 代码和运行时服务。当 POST 完成之后,它被从内存中清理了出来,但是 BIOS 运行时服务依然保留在内存中,目标操作系统可以使用这些服务。

    要引导一个操作系统,BIOS 运行时会按照 CMOS 的设置定义的顺序来搜索处于活动状态并且可以引导的设备。引导设备可以是软盘、CD-ROM、硬盘上的某个分区、网络上的某个设备,甚至是 USB 闪存。

    通常,Linux 都是从硬盘上引导的,其中主引导记录(MBR)中包含主引导加载程序。MBR 是一个 512 字节大小的扇区,位于磁盘上的第一个扇区中(0 道 0 柱面 1 扇区)。当 MBR 被加载到 RAM 中之后,BIOS 就会将控制权交给 MBR。

    第一阶段引导加载程序

    MBR 中的主引导加载程序是一个 512 字节大小的映像,其中包含程序代码和一个小分区表(参见图 2)。前 446 个字节是主引导加载程序,其中包含可执行代码和错误消息文本。接下来的 64 个字节是分区表,其中包含 4 个分区的记录(每个记录的大小是 16 个字节)。MBR 以两个特殊数字的字节(0xAA55)结束。这个数字会用来进行 MBR 的有效性检查。

    图 2. MBR 剖析

    主引导加载程序的工作是查找并加载次引导加载程序(第二阶段)。它是通过在分区表中查找一个活动分区来实现这种功能的。当找到一个活动分区时,它会扫描分区表中的其他分区,以确保它们都不是活动的。当这个过程验证完成之后,就将活动分区的引导记录从这个设备中读入 RAM 中并执行它。

    第二阶段引导加载程序

    次引导加载程序(第二阶段引导加载程序)可以更形象地称为内核加载程序。这个阶段的任务是加载 Linux 内核和可选的初始 RAM 磁盘。

    在 x86 PC 环境中,第一阶段和第二阶段的引导加载程序一起称为 Linux Loader(LILO)或 GRand Unified Bootloader(GRUB)。由于 LILO 有一些缺点,而 GRUB 克服了这些缺点,因此下面让我们就来看一下 GRUB。(有关 GRUB、LILO 和相关主题的更多内容,请参阅本文后面的 参考资料 部分的内容。)

    关于 GRUB,很好的一件事情是它包含了有关 Linux 文件系统的知识。GRUB 不像 LILO 一样使用裸扇区,而是可以从 ext2 或 ext3 文件系统中加载 Linux 内核。它是通过将两阶段的引导加载程序转换成三阶段的引导加载程序来实现这项功能的。阶段 1 (MBR)引导了一个阶段 1.5 的引导加载程序,它可以理解包含 Linux 内核映像的特殊文件系统。这方面的例子包括 reiserfs_stage1_5(要从 Reiser 日志文件系统上进行加载)或 e2fs_stage1_5(要从 ext2 或 ext3 文件系统上进行加载)。当阶段 1.5 的引导加载程序被加载并运行时,阶段 2 的引导加载程序就可以进行加载了。

    当阶段 2 加载之后,GRUB 就可以在请求时显示可用内核列表(在 /etc/grub.conf 中进行定义,同时还有几个软符号链接 /etc/grub/menu.lst 和 /etc/grub.conf)。我们可以选择内核甚至修改附加内核参数。另外,我们也可以使用一个命令行的 shell 对引导过程进行高级手工控制。

    将第二阶段的引导加载程序加载到内存中之后,就可以对文件系统进行查询了,并将默认的内核映像和 initrd 映像加载到内存中。当这些映像文件准备好之后,阶段 2 的引导加载程序就可以调用内核映像了。

    内核

    当内核映像被加载到内存中,并且阶段 2 的引导加载程序释放控制权之后,内核阶段就开始了。内核映像并不是一个可执行的内核,而是一个压缩过的内核映像。通常它是一个 zImage(压缩映像,小于 512KB)或一个 bzImage(较大的压缩映像,大于 512KB),它是提前使用 zlib 进行压缩过的。在这个内核映像前面是一个例程,它实现少量硬件设置,并对内核映像中包含的内核进行解压,然后将其放入高端内存中,如果有初始 RAM 磁盘映像,就会将它移动到内存中,并标明以后使用。然后该例程会调用内核,并开始启动内核引导的过程。

    当 bzImage(用于 i386 映像)被调用时,我们从 ./arch/i386/boot/head.S 的 start 汇编例程开始执行(主要流程图请参看图 3)。这个例程会执行一些基本的硬件设置,并调用 ./arch/i386/boot/compressed/head.S 中的 startup_32 例程。此例程会设置一个基本的环境(堆栈等),并清除 Block Started by Symbol(BSS)。然后调用一个叫做 decompress_kernel 的 C 函数(在 ./arch/i386/boot/compressed/misc.c 中)来解压内核。当内核被解压到内存中之后,就可以调用它了。这是另外一个 startup_32 函数,但是这个函数在 ./arch/i386/kernel/head.S 中。

    在这个新的 startup_32 函数(也称为清除程序或进程 0)中,会对页表进行初始化,并启用内存分页功能。然后会为任何可选的浮点单元(FPU)检测 CPU 的类型,并将其存储起来供以后使用。然后调用 start_kernel 函数(在 init/main.c 中),它会将您带入与体系结构无关的 Linux 内核部分。实际上,这就是 Linux 内核的 main 函数。

    图 3. Linux 内核 i386 引导的主要函数流程



    通过调用 start_kernel,会调用一系列初始化函数来设置中断,执行进一步的内存配置,并加载初始 RAM 磁盘。最后,要调用 kernel_thread(在 arch/i386/kernel/process.c 中)来启动 init 函数,这是第一个用户空间进程(user-space process)。最后,启动空任务,现在调度器就可以接管控制权了(在调用 cpu_idle 之后)。通过启用中断,抢占式的调度器就可以周期性地接管控制权,从而提供多任务处理能力。

    在内核引导过程中,初始 RAM 磁盘(initrd)是由阶段 2 引导加载程序加载到内存中的,它会被复制到 RAM 中并挂载到系统上。这个 initrd 会作为 RAM 中的临时根文件系统使用,并允许内核在没有挂载任何物理磁盘的情况下完整地实现引导。由于与外围设备进行交互所需要的模块可能是 initrd 的一部分,因此内核可以非常小,但是仍然需要支持大量可能的硬件配置。在内核引导之后,就可以正式装备根文件系统了(通过 pivot_root):此时会将 initrd 根文件系统卸载掉,并挂载真正的根文件系统。

    initrd 函数让我们可以创建一个小型的 Linux 内核,其中包括作为可加载模块编译的驱动程序。这些可加载的模块为内核提供了访问磁盘和磁盘上的文件系统的方法,并为其他硬件提供了驱动程序。由于根文件系统是磁盘上的一个文件系统,因此 initrd 函数会提供一种启动方法来获得对磁盘的访问,并挂载真正的根文件系统。在一个没有硬盘的嵌入式环境中,initrd 可以是最终的根文件系统,或者也可以通过网络文件系统(NFS)来挂载最终的根文件系统。

    Init

    当内核被引导并进行初始化之后,内核就可以启动自己的第一个用户空间应用程序了。这是第一个调用的使用标准 C 库编译的程序。在此之前,还没有执行任何标准的 C 应用程序。

    在桌面 Linux 系统上,第一个启动的程序通常是 /sbin/init。但是这不是一定的。很少有嵌入式系统会需要使用 init 所提供的丰富初始化功能(这是通过 /etc/inittab 进行配置的)。在很多情况下,我们可以调用一个简单的 shell 脚本来启动必需的嵌入式应用程序。

    结束语

    与 Linux 本身非常类似,Linux 的引导过程也非常灵活,可以支持众多的处理器和硬件平台。最初,加载引导加载程序提供了一种简单的方法,不用任何花架子就可以引导 Linux。LILO 引导加载程序对引导能力进行了扩充,但是它却缺少文件系统的感知能力。最新一代的引导加载程序,例如 GRUB,允许 Linux 从一些文件系统(从 Minix 到 Reise)上进行引导。

    tag:https://www.ibm.com/developerworks/cn/linux/l-linuxboot/


    展开全文
  • 在刚刚的启动过程中,我们已经知道启动引导程序(Boot Loader,也就是 GRUB)会在启动过程中加载内核,之后内核才能取代 BIOS 接管启动过程。如果没有启动引导程,那么内核是不能被加载的。 本节,我们就来看看启动...
  • Windows引导过程

    千次阅读 2019-04-08 11:04:47
    在cisco的学习网站学习的时候,看到的windows引导过程。特此记录以下。以便后续查阅。 Windows 引导过程 许多操作发生在按计算机电源按钮和 Windows 完全加载之间,如图所示。 有两种类型的计算机固件:基本...
  • Linux的引导过程

    2018-10-17 20:22:43
    Linux的引导过程 了解Linux的引导过程我们需要通过以下一个方面: 1.什么是引导? 打开计算机并加载操作系统的过程称为引导。...计算机引导需要执行一段程序:Bootstrap Loader。Bootstrap Loader位于引导扇...
  • 简介:引导 Linux® 系统的过程包括很多阶段。...在本文介绍的过程中,您将学习到各种与引导有关的主题,例如引导加载程序、内核解压、初始 RAM 磁盘以及 Linux 引导的其他一些元素。 早期时,启...
  • Bootloader引导过程

    2013-01-22 22:06:27
    bootloader是嵌入式系统复位启动时,操作系统内核运行前,运行的一段程序,通过bootloader初始化硬件设备,...对于片内引导,引导程序直接在Flash中运行,所以不必经历为加载stage2准备RAM空间和复制stage2到RAM这两步
  • 引导程序再认识

    2013-09-28 21:03:44
    引导程序再认识 刘建文(http://arttech.us) http://blog.csdn.net/keminlau/article/details/5690402 引导程序 在32位以上的现代计算机里,bootloader,中文叫【引导程序】,是一支将计算机从【开机重置态】...
  • Linux引导过程内幕

    2013-12-25 11:06:04
     早期时,启动一台计算机意味着要给计算机喂一条包含引导程序的纸带,或者手工使用前端面板地址/数据/控制开关来加载引导程序。尽管目前的计算机已经装备了很多工具来简化引导过程,但是这一切并没有对整个过程进行...
  • 早期时,启动一台计算机意味着要给计算机喂一条包含引导程序的纸带,或者手工使用前端面板地址/数据/控制开关来加载引导程序。尽管目前的计算机已经装备了很多工具来简化引导过程,但是这一切并没有对整个过程进行...
  • Linux系统引导过程

    2020-10-22 22:51:28
    Linux系统引导过程 理解引导过程可以帮助你解决引导系统时遇到的问题。引导过程涉及一些文件,这些文件中的错误通常造成了引导问题。引导过程和配置是不同的,这取决于你的硬件是使用UEFI固件还是传统的BIOS去处理...
  • linux开机引导过程

    2014-01-14 10:25:56
    Linux的开机引导过程抽象为以下四个模块,BIOS,MBR(第一段引导程序),,kernel,init。   *BIOS(basic input outputsystem),直译过来就是基本输入输出系统,BIOS用于计算机开机时执行系统各部分的自检,并...
  • 系统引导过程

    2017-04-21 16:31:21
    系统引导过程主要由以下几个步骤组成(以硬盘启动为例) 1、 开机; 2、 BIOS加电自检(POST---Power On Self Test),内存地址为0fff:0000; 3、 将硬盘第一个扇区(0头0道1扇区,也就是Boot Sector)读入内存地址0000:7c...
  • Linux 引导过程概述

    2020-06-18 15:11:28
    系统引导是操作系统运行的开始,在用户能够正常登录到系统之前,Linux的引导过程完成了一了一系列的舒适化任务,并加载必要的程序和命令终端,为用户登录做好准备。
  • UEFI引导过程及windows引导修复

    千次阅读 2019-03-12 17:44:00
    UEFI启动是一种新的主板引导项。传统引导方式就是Legacy模式。 CSM的选项是UEFI模拟Legacy模式启动,选中后则可使用Legacy模式启动机器。 ...UEFI引导程序直接进入64位模式,传统Legacy模式引...
  • ARM引导过程(s5pv210)

    2016-03-01 20:10:39
    ARM引导过程(s5pv210)1. 引导过程s5pv210处理器有 iROM 与 iRAM 两个存储器作为内部... 在进行安全启动的过程中,引导程序固化在 iROM 中。采用了 e-fuse (只能进行一次编程,以后便不能再进行更改)的形式。引导程序
  • 请问一般这样的引导程序 是什么汇编? 为什么没有伪指令?也不能编译?请问直接jmp那是干什么? 还有nasm 又是什么呢? 重要在U盘上面是这怎么变成引导的程序? 简单的引导程序 jmp dword 0x07c0:go ;第一种 go...
  • 启动流程 通电后,主板上BIOS或者UEFI,会加电自检(检查硬件有没错误),加载bootloader(执行程序)到内存 bootloader被写死在磁盘上第一个扇区,启动后被...因此引导程序一定要放在这个位置才能执行。 ; 下面部分和10
  • Linux内核引导过程

    2019-03-03 08:48:33
    上一篇文章解释了计算机的引导过程,正好讲到引导装载程序把系统内核镜像塞进内存,准备跳转到内核入口点去执行的时刻。作为引导启动系列文章的最后一篇,就让我们深入内核,去看看操作系统是怎么启动的吧。由于我...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 428,498
精华内容 171,399
关键字:

引导程序