BIOS启动过程分析

1        引言

1.1    文档目的

对于电脑用户来说,打开电源启动电脑几乎是每天必做的事情,但计算机在显示这些启动画面的时候在做什么呢?大多数用户都未必清楚了。下面就向大家介绍一下从打开电源到出现Linux的登录窗口,计算机到底干了些什么工作,BIOS在其中起到什么作用。

电脑的启动过程中有一个非常完善的硬件自检机制。对于采用Award BIOS的电脑来说,它在上电自检那短暂的几秒钟里,就可以完成100多个检测步骤。

1.2    术语和缩写

术语或缩写

描述

BIOS

基本输入/输出系统

CMOS

保存系统当前的硬件配置情况和用户的设定参数

POST

Power on self test, 加电自检

2       基本概念

2.1    BIOS

BIOS即基本输入/输出系统,它是被固化在计算机ROM芯片上的一组程序。它是微机系统软、硬件之间的一个可编程接口,通过跳线开关和系统配带的驱动程序盘,可以对ROM进行重写,方便地实现BIOS升级。

2.2    CMOS

CMOS是一块可读写的RAM芯片,保存系统当前的硬件配置情况和用户的设定参数;BIOS中装有一个程序称为“系统设置程序”,设置CMOS中的参数;CMOS由电池供电,断电后数据会丢失;前16字节用于存储时间

2.3    AMI、AWARD和PHONIX三大主流厂商

开发BIOS是一件技术含量很高的工作,从业人员也少;一流主板厂商的BIOS研发人员,年薪往往是以七位数字来计算的!

3       BIOS主要功能

BIOS的主要功能概括来说包括如下几部分:

1)POST

加电自检,检测CPU各寄存器、计时芯片、中断芯片、DMA控制器等

2)Initial

枚举设备,初始化寄存器,分配中断、IO端口、DMA资源等

3)Setup

进行系统设置,存于CMOS中。一般开机时按Del或者F2进入到BIOS的设置界面。

4)常驻程序

INT 10h、INT 13h、INT 15h等,提供给操作系统或应用程序调用。

5)启动自举程序

在POST过程结束后,将调用INT 19h,启动自举程序,自举程序将读取引导记录,装载操作系统。

4       BIOS源代码结构分析

4.1    AMI BIOS代码结构分析

AMI BIOS的代码主要分成三大部分:核心代码、芯片代码和OEM代码。

核心代码目录结构如下:

4.2    AWARD BIOS代码结构分析

AWARD BIOS的源代码为进行目录分类,所有的源码、编译链接工具、生成的中间文件都在同一个目录中。没有AMI代码结构组织得好。

5       BIOS常驻程序介绍

开机自检程序运行完后,将撤出内存。BIOS提供了一组常驻程序,主要包括INT 10h,INT 13h,INT 15h等等中断服务例程,提供给操作系统或应用程序调用,下面介绍几个常用的中断服务例程。X86提供了256个中断,中断向量表在内存的起始地址1024byte上,每个中断向量地址占用4个字节。

5.1    INT 13h中断例程

INT 13h为BIOS提供的对磁盘进行操作的中断例程,包括如下几种调用方式:

1)INT 13H,AH=00H 软、硬盘控制器复位;

2)INT 13H,AH=02H 读扇区说明;

3)INT 13H,AH=03H 写扇区;

4)INT 13H,AH=04H 检测扇区;

以上调用方法详细的说明请参考相关技术文档。

举例:读取软驱0面0道1扇区的内容到0:200

mov ax,0                     /* 初始化ax寄存器为0 */

mov es,ax                    /* 将es置为0 */

mov bx,200h        /* 将bx设置为200h ,此时es:dx = 0:200,为内存地址*/

mov al,1                      /* al保存扇区数 */

mov ch,0                     /* ch保存磁道号 */

mov cl,1                  /* cl保存扇区号 */

mov dl,0               /* dl保存驱动器,0表示软驱A */

mov dh,0                     /* dh保存磁头号 */

mov ah,2                     /* ah保存int13要调用的功能号,2表示读 */

int 13h                         /* 调用int13中断 */

入口参数:

ah=int 13h的功能号

al=读取的扇区数

ch=磁道号

cl=扇区号

dh=磁头号(对于软盘即面号,因为一个面用一个磁头来读写)

dl=驱动器号 软驱从0开始,0:软驱A,1:软驱B;硬盘从80h开始,

80h:硬盘C,81h:硬盘D。

es:bx指向接收从扇区读入数据的内存区

返回参数:

操作成功:ah=0,al=读入的扇区数

操作失败:ah=出错代码

5.2    INT 10h中断例程

屏幕I/O接口,切换各文字/图形模式,提供显示/绘图卷页服务。详细的调用方法可以参考相关的文档。例如00号功能:

功能号:00H

功能:设置显示模式
入口参数:AH=00H
   AL=显示模式
显示模式列表:

显示模式  显示模式属性
  00H       40×25    16色 文本
  01H       40×25    16色 文本
  02H       80×25    16色 文本
  04H       320×200   4色
  05H       320×200   4色
  06H       640×200   2色
  07H       80×25     2色 文本
  08H       160×200  16色
  09H       320×200  16色
  0AH       640×200   4色
  0BH       保留
  0CH       保留
  0DH       320×200  16色
  0EH       640×200  16色
  0FH       640×350   2色(单色)
  10H       640×350   4色
  11H       640×480   2色
  12H       640×480  16色
  13H       320×200 256色

5.3    INT 16h中断例程

BIOS提供的键盘读取中断服务,功能如下表:

AH

功能

返回参数

0

从键盘读一字符

AL=字符码

AH=扫描码

1

读键盘缓冲区的字符

如ZF=0

AL=字符码

AH=扫描码

如ZF=1,缓冲区空

2

取键盘状态字节

AL=键盘状态字节

调用方法:

MOV  AH,0         ; 读字符功能
INT   16H          ; 键盘BIOS调用

5.4    用debug工具获取中断例程的内存地址

在DOS模式下,进入DEBUG,输入

a100

int 10

t=100

得 0210:08A9

int 10h的中断服务程序入口地址存放在中断向量表中的物理地址是0000:0040H~0043H,指向CS:IP(0210:08A9),如下图执行结果:

6       启动过程分析

6.1    Linux系统开机启动的总体流程

6.2    BIOS启动过程概述

BIOS启动的过程主要包括POST过程和自举过程,其流程和执行指令地址的变化如下:

6.3    POST过程分析

POST过程在AWARD BIOS的源码中在BOOTROM.ASM文件中BootBlock_POST函数过程中实现,主要步骤如下:

1)初始化各种主板芯片组

2)初始化键盘控制器8042

3)初始化中断向量 ,中断服务例程.

4)初始化 VGA BIOS 控制器

5)显示BIOS的版本和公司名称

6)扫描软驱和各种介质容量

7)读取CMOS的启动顺序配置,并检测启动装置是否正常

8)调用INT 19h启动自举程序

以上每个过程都有大量的代码,在这不一一做仔细分析,请参考源代码。下面对第三步源码做一些分析。

6.4    中断向量表初始化过程源码分析

中断向量表存储在内存的第一个1k空间里,本节主要分析AWARD BIOS中中断向量服务例程的初始化过程。

;[]==============================================================[]

;

;      Initialize int. vectors (0-77h) to the spurious interrupt

;      handler. Then initialize 00h-1fh to their proper places.

;

;[]==============================================================[]        

POST_CODE 12

              mov ax,cs

              mov ds,ax

;

;      Initialize vectors 00-77h to SPURIOUS_INT_HDLR

;   。。。。。。

       。。。。。。

       。。。。。。

;

;      Initialize vectors 00-1fh to the real handlers

;

              lea   si,DGROUP:Int_Tbl

p10_21:

              lodsb                           ;load next offset

              cmp al,0ffh                   ;over?

              je    short Init_Vect_Over   ;Yes,skip

              movzx    di,al               ;get vector number

              shl   di,2                      ;set to coresspond offset

              movsw                        ;load offset from DS:[SI]

              mov ax,cs             ;get segment

              stosw                          ;load segment

              jmp short p10_21 ;next cycle

Init_Vect_Over:

              mov al,10111100b              ;Enable IRQ 0,1,6

              out  a8259+1,al

              sti

看以上蓝色部分代码,为初始化中断服务例程,红色部分Int_Tb1为BIOS定义的中断服务例程列表,用于替换相应的中断服务。Int_Tb1的定义如下:

INT_TBL:     db   2                          ; INT02

              DW OFFSET DGROUP:NMI_VECT           ; INT02 offset

              db   6                          ; INT06

              DW OFFSET DGROUP:LOADALL             ; INVALID OP-CODE

              db   8                          ; INT08

              DW OFFSET DGROUP:TIMER_VECT       ; INT08 offset

              db   9                          ; INT09

              DW OFFSET DGROUP:KBDINT_VECT    ; INT09 offset

              db   0eh                       ; INT0E

              DW OFFSET DGROUP:DSKINT_VECT     ; INT0E offset

              db   11h                       ; INT11

              DW OFFSET DGROUP:EQ_VECT              ; INT11 offset

              db   12h                      ; INT12

              DW OFFSET DGROUP:MEM_SZ_VECT   ; INT12 offset

              db   13h                      ; INT13

              DW OFFSET DGROUP:DSK_VECT           ; INT13 offset

              db   15h                      ; INT15

              DW OFFSET DGROUP:Multi_Service   ; INT15 offset

              db   16h                      ; INT16

              DW OFFSET DGROUP:KBD_VECT           ; INT16 offset

              db   19h                      ; INT19

              DW OFFSET DGROUP:INT19_VECT  ; INT19 offset

              db   1Ah                      ; INT1A

              DW OFFSET DGROUP:INT1A_VECT       ; INT1A offset

              db   1Eh                      ; INT1E

              DW OFFSET DGROUP:FD_BIOS_PARMS       ; INT1E offset

              db   0ffh                      ; over

中断服务例程对应的函数也在Bootrom.asm文件中有实现。替换的中断服务例程总结如下。

中断号

BIOS中断例程

属性

备注

INT02

NMI_VECT

硬中断

None Maskable Interrupt,不可屏蔽中断

INT06

LOADALL

错误中断

非法,不支持的指令

INT08

TIMER_VECT

硬中断

IRQ0,系统定时器中断

INT09

KBDINT_VECT

硬中断

IRQ1,键盘中断

INT0E

DSKINT_VECT

硬中断

IRQ6,软盘驱动器读写中断

INT11

EQ_VECT

软中断

PC外围设备检查

INT12

MEM_SZ_VECT

软中断

PC主存储器大小检查

INT13

DSK_VECT

软中断

磁盘I/O接口(读写、复位等)

INT15

Multi_Service

软中断

卡带接口服务程序,AT扩展中断服务调用,程序多任务

INT16

KBD_VECT

软中断

键盘读取服务程序

INT19

INT19_VECT

软中断

激活操作系统的入口点

INT1A

INT1A_VECT

软中断

BIOS时间接口

INT1E

FD_BIOS_PARMS

软中断

软盘驱动器参数地址表

AWARD的其他中断服务调用未在BIOS中指定服务例程。

6.5    自举过程源码分析

自举过程即为执行中断INT19的中断服务例程INT19_VECT的过程,该过程在AWARD的Bootrom.asm文件中实现,其主要功能为读取操作系统启动块,将其读入到内存0000:7C00h,并跳转至此处执行。下面分析一下操作系统启动块MBR是如何从磁盘中读取到内存0000:7C00h处的。

new_dsk:

              xor  dx,dx

              mov es,dx                    ; set to load at 0:offset Boot

              mov bx,offset Boot       ; location to load boot sector

              mov cx,1                      ; set to read one sector

[U1]

              xor  ax,ax

              int    13h                             ; reset disk

[U2]

              mov ax,0201h              ; read boot record

              int    13h                             ; read disk

              jc    short Boot_fail

[U3]

              call  Check_Boot_Record  ; check boot sector valid ?

              jc    short Boot_fail             ; invalid boot sector.

              jmp far ptr Boot               ; go to boot code

[U4] Boot_Fail:

              lea   ax,Bad_Disk_Msg       ; boot failed

              mov cx,Bad_Disk_Msg_Len

              call  Disk_Fail_Routine

[U5]         xor  ax,ax                           ; g_ram

              jmp short new_dsk

[U6]

Disk_Fail_Routine:

              mov dx,0ff01h

              call  Display_Str

       ;Beep out if no bootable media

              mov bl,2                      ; beep on override

              mov cx,1700h

              call  SND_SPKR_TONE

              xor  cx,cx

              loop       short $

              mov bl,5                      ; beep on override

              mov cx,3000h

              call  SND_SPKR_TONE

[U7]

       ;wait for "Enter" key to continue

endless:

              xor  ah,ah                           ;wait ENTER key

              int    16h

              cmp ah,1ch

              jne   short endless

              ret

[U8]

流程图如下:

7       参考资料

1)AMI和AWARD的BIOS源码

2)grub-0.97.tar.gz源码

3)AMI BIOS98 User Guide

4)AMI BIOS98 Technical Reference

5)《BIOS研发技术剖析》

6)网站搜索内容:

BIOS之家:www.bios.net.cn

Google


[U1]初始化es:dx = 0000:7C00

[U2]复位磁盘

[U3]读取引导记录,失败则跳转至Boot_Fail

[U4]检查启动扇区内容是否有效,无效则跳转至Boot_Fail,有效则直接跳转至启动代码

[U5]Boot_Fail过程,初始化启动失败信息,并调用磁盘失败例程

  • 0
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
内容: 一. Bootloader 二.Kernel引导入口 三.核心数据结构初始化--内核引导第一部分 四.外设初始化--内核引导第二部分 五.init进程和inittab引导指令 六.rc启动脚本 七.getty和login 八.bash 附:XDM方式登录 本文以Redhat 6.0 Linux 2.2.19 for Alpha/AXP为平台,描述了从开机到登录的 Linux 启动全过程。该文对i386平台同样适用。 一. Bootloader 在Alpha/AXP 平台上引导Linux通常有两种方法,一种是由MILO及其他类似的引导程序引导,另一种是由Firmware直接引导。MILO功能与i386平台的LILO相近,但内置有基本的磁盘驱动程序(如IDE、SCSI等),以及常见的文件系统驱动程序(如ext2,iso9660等), firmware有ARC、SRM两种形式,ARC具有类BIOS界面,甚至还有多重引导的设置;而SRM则具有功能强大的命令行界面,用户可以在控制台上使用boot等命令引导系统。ARC有分区(Partition)的概念,因此可以访问到分区的首扇区;而SRM只能将控制转给磁盘的首扇区。两种firmware都可以通过引导MILO来引导Linux,也可以直接引导Linux的引导代码。 “arch/alpha/boot” 下就是制作Linux Bootloader的文件。“head.S”文件提供了对 OSF PAL/1的调用入口,它将被编译后置于引导扇区(ARC的分区首扇区或SRM的磁盘0扇区),得到控制后初始化一些数据结构,再将控制转给“main.c”中的start_kernel(), start_kernel()向控制台输出一些提示,调用pal_init()初始化PAL代码,调用openboot() 打开引导设备(通过读取Firmware环境),调用load()将核心代码加载到START_ADDR(见 “include/asm-alpha/system.h”),再将Firmware中的核心引导参数加载到ZERO_PAGE(0) 中,最后调用runkernel()将控制转给0x100000的kernel,bootloader部分结束。 “arch/alpha/boot/bootp.c”以“main.c”为基础,可代替“main.c”与“head.S” 生成用于BOOTP协议网络引导的Bootloader。 Bootloader中使用的所有“srm_”函数在“arch/alpha/lib/”中定义。 以上这种Boot方式是一种最简单的方式,即不需其他工具就能引导Kernel,前提是按照 Makefile的指导,生成bootimage文件,内含以上提到的bootloader以及vmlinux,然后将 bootimage写入自磁盘引导扇区始的位置中。 当采用MILO这样的引导程序来引导Linux时,不需要上面所说的Bootloader,而只需要 vmlinux或vmlinux.gz,引导程序会主动解压加载内核到0x1000(小内核)或0x100000(大内核),并直接进入内核引导部分,即本文的第二节。 对于I386平台 i386系统中一般都有BIOS做最初的引导工作,那就是将四个主分区表中的第一个可引导 分区的第一个扇区加载到实模式地址0x7c00上,然后将控制转交给它。 在“arch/i386/boot” 目录下,bootsect.S是生成引导扇区的汇编源码,它首先将自己拷贝到0x90000上,然后将紧接其后的setup部分(第二扇区)拷贝到0x90200,将真正的内核代码拷贝到0x100000。以上这些拷贝动作都是以bootsect.S、setup.S以及vmlinux在磁盘上连续存放为前提的,也就是说,我们的bzImage文件或者zImage文件是按照bootsect,setup, vmlinux这样的顺序组织,并存放于始于引导分区的首扇区的连续磁盘扇区之中。 bootsect.S完成加载动作后,就直接跳转到0x90200,这里正是setup.S的程序入口。 setup.S的主要功能就是将系统参数(包括内存、磁盘等,由BIOS返回)拷贝到 0x90000-0x901FF内存中,这个地方正是bootsect.S存放的地方,这时它将被系统参数覆盖。以后这些参数将由保护模式下的代码来读取。 除此之外,setup.S还将video.S中的代码包含进来,检测和设置显示器和显示模式。最 后,setup.S将系统转换到保护模式,并跳转到0x100000(对于bzImage格式的大内核是 0x100000,对于zImage格式的是0x1000)的内核引导代码,Bootloader过程结束。 对于2.4.x版内核 没有什么变化。 二.Kernel引导入口 在arch/alpha/vmlinux.lds 的链接脚本控制下,链接程序将vmlinux的入口置于 "arch/alpha/kernel/head.S"中的__start上,因此当Bootloader跳转到0x100000时, __start处的代码开始执行。__start的代码很简单,只需要设置一下全局变量,然后就跳转到start_kernel去了。start_kernel()是"init/main.c"中的asmlinkage函数,至此,启动过程转入体系结构无关的通用C代码中。 对于I386平台 在i386体系结构中,因为i386本身的问题,在 "arch/alpha/kernel/head.S"中需要更多的设置,但最终也是通过call SYMBOL_NAME(start_kernel)转到start_kernel()这个体系结构无关的函数中去执行了。 所不同的是,在i386系统中,当内核以bzImage的形式压缩,即大内核方式(__BIG_KERNEL__)压缩时就需要预先处理bootsect.S和setup.S,按照大核模式使用$(CPP) 处理生成bbootsect.S和bsetup.S,然后再编译生成相应的.o文件,并使用 "arch/i386/boot/compressed/build.c"生成的build工具,将实际的内核(未压缩的,含 kernel中的head.S代码)与"arch/i386/boot/compressed"下的head.S和misc.c合成到一起,其中的 head.S代替了"arch/i386/kernel/head.S"的位置,由Bootloader引导执行(startup_32入口),然后它调用misc.c中定义的decompress_kernel()函数,使用 "lib/inflate.c"中定义的gunzip()将内核解压到0x100000,再转到其上执行 "arch/i386/kernel/head.S"中的startup_32代码。 对于2.4.x版内核 没有变化。 三.核心数据结构初始化--内核引导第一部分 start_kernel()中调用了一系列初始化函数,以完成kernel本身的设置。 这些动作有的是公共的,有的则是需要配置的才会执行的。 在start_kernel()函数中, 输出Linux版本信息(printk(linux_banner)) 设置与体系结构相关的环境(setup_arch()) 页表结构初始化(paging_init()) 使用"arch/alpha/kernel/entry.S"中的入口点设置系统自陷入口(trap_init()) 使用alpha_mv结构和entry.S入口初始化系统IRQ(init_IRQ()) 核心进程调度器初始化(包括初始化几个缺省的Bottom-half,sched_init()) 时间、定时器初始化(包括读取CMOS时钟、估测主频、初始化定时器中断等,time_init()) 提取并分析核心启动参数(从环境变量中读取参数,设置相应标志位等待处理,(parse_options()) 控制台初始化(为输出信息而先于PCI初始化,console_init()) 剖析器数据结构初始化(prof_buffer和prof_len变量) 核心Cache初始化(描述Cache信息的Cache,kmem_cache_init()) 延迟校准(获得时钟jiffies与CPU主频ticks的延迟,calibrate_delay()) 内存初始化(设置内存上下界和页表项初始值,mem_init()) 创建和设置内部及通用cache("slab_cache",kmem_cache_sizes_init()) 创建uid taskcount SLAB cache("uid_cache",uidcache_init()) 创建文件cache("files_cache",filescache_init()) 创建目录cache("dentry_cache",dcache_init()) 创建与虚存相关的cache("vm_area_struct","mm_struct",vma_init()) 块设备读写缓冲区初始化(同时创建"buffer_head"cache用户加速访问,buffer_init()) 创建页cache(内存页hash表初始化,page_cache_init()) 创建信号队列cache("signal_queue",signals_init()) 初始化内存inode表(inode_init()) 创建内存文件描述符表("filp_cache",file_table_init()) 检查体系结构漏洞(对于alpha,此函数为空,check_bugs()) SMP机器其余CPU(除当前引导CPU)初始化(对于没有配置SMP的内核,此函数为空,smp_init()) 启动init过程(创建第一个核心线程,调用init()函数,原执行序列调用cpu_idle() 等待调度,init()) 至此start_kernel()结束,基本的核心环境已经建立起来了。 对于I386平台 i386平台上的内核启动过程与此基本相同,所不同的主要是实现方式。 对于2.4.x版内核 2.4.x中变化比较大,但基本过程没变,变动的是各个数据结构的具体实现,比如Cache。 四.外设初始化--内核引导第二部分 init()函数作为核心线程,首先锁定内核(仅对SMP机器有效),然后调用 do_basic_setup()完成外设及其驱动程序的加载和初始化。过程如下: 总线初始化(比如pci_init()) 网络初始化(初始化网络数据结构,包括sk_init()、skb_init()和proto_init()三部分,在proto_init()中,将调用protocols结构中包含的所有协议的初始化过程,sock_init()) 创建bdflush核心线程(bdflush()过程常驻核心空间,由核心唤醒来清理被写过的内存缓冲区,当bdflush()由kernel_thread()启动后,它将自己命名为kflushd) 创建kupdate核心线程(kupdate()过程常驻核心空间,由核心按时调度执行,将内存缓冲区中的信息更新到磁盘中,更新的内容包括超级块和inode表) 设置并启动核心调页线程kswapd(为了防止kswapd启动时将版本信息输出到其他信息中间,核心线调用kswapd_setup()设置kswapd运行所要求的环境,然后再创建 kswapd核心线程) 创建事件管理核心线程(start_context_thread()函数启动context_thread()过程,并重命名为keventd) 设备初始化(包括并口parport_init()、字符设备chr_dev_init()、块设备 blk_dev_init()、SCSI设备scsi_dev_init()、网络设备net_dev_init()、磁盘初始化及分区检查等等, device_setup()) 执行文件格式设置(binfmt_setup()) 启动任何使用__initcall标识的函数(方便核心开发者添加启动函数,do_initcalls()) 文件系统初始化(filesystem_setup()) 安装root文件系统(mount_root()) 至此do_basic_setup()函数返回init(),在释放启动内存段(free_initmem())并给内核解锁以后,init()打开 /dev/console设备,重定向stdin、stdout和stderr到控制台,最后,搜索文件系统中的init程序(或者由init=命令行参数指定的程序),并使用 execve()系统调用加载执行init程序。 init()函数到此结束,内核的引导部分也到此结束了,这个由start_kernel()创建的第一个线程已经成为一个用户模式下的进程了。此时系统中存在着六个运行实体: start_kernel()本身所在的执行体,这其实是一个"手工"创建的线程,它在创建了init()线程以后就进入cpu_idle()循环了,它不会在进程(线程)列表中出现 init线程,由start_kernel()创建,当前处于用户态,加载了init程序 kflushd核心线程,由init线程创建,在核心态运行bdflush()函数 kupdate核心线程,由init线程创建,在核心态运行kupdate()函数 kswapd核心线程,由init线程创建,在核心态运行kswapd()函数 keventd核心线程,由init线程创建,在核心态运行context_thread()函数 对于I386平台 基本相同。 对于2.4.x版内核 这一部分的启动过程在2.4.x内核中简化了不少,缺省的独立初始化过程只剩下网络 (sock_init())和创建事件管理核心线程,而其他所需要的初始化都使用__initcall()宏 包含在do_initcalls()函数中启动执行。 五.init进程和inittab引导指令 init进程是系统所有进程的起点,内核在完成核内引导以后,即在本线程(进程)空 间内加载init程序,它的进程号是1。 init程序需要读取/etc/inittab文件作为其行为指针,inittab是以行为单位的描述性(非执行性)文本,每一个指令行都具有以下格式: id:runlevel:action:process其中id为入口标识符,runlevel为运行级别,action为动作代号,process为具体的执行程序。 id一般要求4个字符以内,对于getty或其他login程序项,要求id与tty的编号相同,否则getty程序将不能正常工作。 runlevel 是init所处于的运行级别的标识,一般使用0-6以及S或s。0、1、6运行级别被系统保留,0作为shutdown动作,1作为重启至单用户模式,6 为重启;S和s意义相同,表示单用户模式,且无需inittab文件,因此也不在inittab中出现,实际上,进入单用户模式时,init直接在控制台(/dev/console)上运行/sbin/sulogin。 在一般的系统实现中,都使用了2、3、4、5几个级别,在 Redhat系统中,2表示无NFS支持的多用户模式,3表示完全多用户模式(也是最常用的级别),4保留给用户自定义,5表示XDM图形登录方式。7- 9级别也是可以使用的,传统的Unix系统没有定义这几个级别。runlevel可以是并列的多个值,以匹配多个运行级别,对大多数action来说,仅当runlevel与当前运行级别匹配成功才会执行。 initdefault是一个特殊的action值,用于标识缺省的启动级别;当init由核心激活 以后,它将读取inittab中的initdefault项,取得其中的runlevel,并作为当前的运行级别。如果没有inittab文件,或者其中没有initdefault项,init将在控制台上请求输入 runlevel。 sysinit、 boot、bootwait等action将在系统启动时无条件运行,而忽略其中的runlevel,其余的action(不含initdefault)都与某个runlevel相关。各个action的定义在inittab的man手册中有详细的描述。 在Redhat系统中,一般情况下inittab都会有如下几项: id:3:initdefault: #表示当前缺省运行级别为3--完全多任务模式; si::sysinit:/etc/rc.d/rc.sysinit #启动时自动执行/etc/rc.d/rc.sysinit脚本 l3:3:wait:/etc/rc.d/rc 3 #当运行级别为3时,以3为参数运行/etc/rc.d/rc脚本,init将等待其返回 0:12345:respawn:/sbin/mingetty tty0 #在1-5各个级别上以tty0为参数执行/sbin/mingetty程序,打开tty0终端用于 #用户登录,如果进程退出则再次运行mingetty程序 x:5:respawn:/usr/bin/X11/xdm -nodaemon #在5级别上运行xdm程序,提供xdm图形方式登录界面,并在退出时重新执行. 六.rc启动脚本 上一节已经提到init进程将启动运行rc脚本,这一节将介绍rc脚本具体的工作。 一般情况下,rc启动脚本都位于/etc/rc.d目录下,rc.sysinit中最常见的动作就是激活交换分区,检查磁盘,加载硬件模块,这些动作无论哪个运行级别都是需要优先执行的。仅当rc.sysinit执行完以后init才会执行其他的boot或bootwait动作。 如果没有其他boot、bootwait动作,在运行级别3下,/etc/rc.d/rc将会得到执行,命令行参数为3,即执行 /etc/rc.d/rc3.d/目录下的所有文件。rc3.d下的文件都是指向/etc/rc.d/init.d/目录下各个Shell脚本的符号连接,而这些脚本一般能接受start、stop、restart、status等参数。rc脚本以start参数启动所有以S开头的脚本,在此之前,如果相应的脚本也存在K打头的链接,而且已经处于运行态了(以/var/lock/subsys/下的文件作为标志),则将首先启动K开头的脚本,以stop 作为参数停止这些已经启动了的服务,然后再重新运行。显然,这样做的直接目的就是当init改变运行级别时,所有相关的服务都将重启,即使是同一个级别。 rc程序执行完毕后,系统环境已经设置好了,下面就该用户登录系统了。 七.getty和login 在rc返回后,init将得到控制,并启动mingetty(见第五节)。mingetty是getty的简化,不能处理串口操作。getty的功能一般包括: 打开终端线,并设置模式 输出登录界面及提示,接受用户名的输入 以该用户名作为login的参数,加载login程序 缺省的登录提示记录在/etc/issue文件中,但每次启动,一般都会由rc.local脚本根据系统环境重新生成。 注:用于远程登录的提示信息位于/etc/issue.net中。 login程序在getty的同一个进程空间中运行,接受getty传来的用户名参数作为登录的用户名。 如果用户名不是root,且存在/etc/nologin文件,login将输出nologin文件的内容,然后退出。这通常用来系统维护时防止非root用户登录。 只有/etc/securetty中登记了的终端才允许root用户登录,如果不存在这个文件,则root可以在任何终端上登录。/etc/usertty文件用于对用户作出附加访问限制,如果不存在这个文件,则没有其他限制。 当用户登录通过了这些检查后,login将搜索/etc/passwd文件(必要时搜索 /etc/shadow文件)用于匹配密码、设置主目录和加载shell。如果没有指定主目录,将默认为根目录;如果没有指定shell,将默认为 /bin/sh。在将控制转交给shell以前, getty将输出/var/log/lastlog中记录的上次登录系统的信息,然后检查用户是否有新邮件(/usr/spool/mail/ {username})。在设置好shell的uid、gid,以及TERM,PATH 等环境变量以后,进程加载shell,login的任务也就完成了。 八.bash 运行级别3下的用户login以后,将启动一个用户指定的shell,以下以/bin/bash为例继续我们的启动过程。 bash 是Bourne Shell的GNU扩展,除了继承了sh的所有特点以外,还增加了很多特性和功能。由login启动的bash是作为一个登录shell启动的,它继承了 getty设置的TERM、PATH等环境变量,其中PATH对于普通用户为"/bin:/usr/bin:/usr/local/bin",对于 root 为"/sbin:/bin:/usr/sbin:/usr/bin"。作为登录shell,它将首先寻找/etc/profile 脚本文件,并执行它;然后如果存在~/.bash_profile,则执行它,否则执行 ~/.bash_login,如果该文件也不存在,则执行~/.profile文件。然后bash将作为一个交互式shell执行~/.bashrc文件(如果存在的话),很多系统中,~/.bashrc都将启动 /etc/bashrc作为系统范围内的配置文件。 当显示出命令行提示符的时候,整个启动过程就结束了。此时的系统,运行着内核,运行着几个核心线程,运行着init进程,运行着一批由rc启动脚本激活的守护进程(如 inetd等),运行着一个bash作为用户的命令解释器。 附:XDM方式登录 如果缺省运行级别设为5,则系统中不光有1-6个getty监听着文本终端,还有启动了一个XDM的图形登录窗口。登录过程和文本方式差不多,也需要提供用户名和口令,XDM 的配置文件缺省为/usr/X11R6/lib/X11/xdm/xdm-config文件,其中指定了 /usr/X11R6/lib/X11/xdm/xsession作为XDM的会话描述脚本。登录成功后,XDM将执行这个脚本以运行一个会话管理器,比如gnome-session等。 除了XDM以外,不同的窗口管理系统(如KDE和GNOME)都提供了一个XDM的替代品,如gdm和kdm,这些程序的功能和XDM都差不多。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值