⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 1.html

📁 介绍linux下文件和设备编程
💻 HTML
📖 第 1 页 / 共 5 页
字号:
&nbsp;&nbsp;&nbsp; &middot;创建目录cache(&quot;dentry_cache&quot;,dcache_init())<br>&nbsp;&nbsp;&nbsp; &middot;创建与虚存相关的cache(&quot;vm_area_struct&quot;,&quot;mm_struct&quot;,vma_init())<br>&nbsp;&nbsp;&nbsp; &middot;块设备读写缓冲区初始化(同时创建&quot;buffer_head&quot;cache用户加速访问,buffer_init())<br>&nbsp;&nbsp;&nbsp; &middot;创建页cache(内存页hash表初始化,page_cache_init())<br>&nbsp;&nbsp;&nbsp; &middot;创建信号队列cache(&quot;signal_queue&quot;,signals_init())<br>&nbsp;&nbsp;&nbsp; &middot;初始化内存inode表(inode_init())<br>&nbsp;&nbsp;&nbsp; &middot;创建内存文件描述符表(&quot;filp_cache&quot;,file_table_init())<br>&nbsp;&nbsp;&nbsp; &middot;检查体系结构漏洞(对于alpha,此函数为空,check_bugs())<br>&nbsp;&nbsp;&nbsp; &middot;SMP机器其余CPU(除当前引导CPU)初始化(对于没有配置SMP的内核,此函数为空,smp_init())<br>&nbsp;&nbsp;&nbsp; &middot;启动init过程(创建第一个核心线程,调用init()函数,原执行序列调用cpu_idle() 等待调度,init())<p>至此start_kernel()结束,基本的核心环境已经建立起来了。<p>对于I386平台<br>&nbsp;&nbsp;&nbsp; i386平台上的内核启动过程与此基本相同,所不同的主要是实现方式。<p>对于2.4.x版内核<br>&nbsp;&nbsp;&nbsp; 2.4.x中变化比较大,但基本过程没变,变动的是各个数据结构的具体实现,比如Cache。<p>四.外设初始化--内核引导第二部分<br>&nbsp;&nbsp;&nbsp; init()函数作为核心线程,首先锁定内核(仅对SMP机器有效),然后调用 do_basic_setup()完成外设及其驱动程序的加载和初始化。过程如下:<p>&nbsp;&nbsp;&nbsp; &middot;总线初始化(比如pci_init())<br>&nbsp;&nbsp;&nbsp; &middot;网络初始化(初始化网络数据结构,包括sk_init()、skb_init()和proto_init()三部分,在proto_init()中,将调用protocols结构中包含的所有协议的初始化过程,sock_init())<br>&nbsp;&nbsp;&nbsp; &middot;创建bdflush核心线程(bdflush()过程常驻核心空间,由核心唤醒来清理被写过的内存缓冲区,当bdflush()由kernel_thread()启动后,它将自己命名为kflushd)<br>&nbsp;&nbsp;&nbsp; &middot;创建kupdate核心线程(kupdate()过程常驻核心空间,由核心按时调度执行,将内存缓冲区中的信息更新到磁盘中,更新的内容包括超级块和inode表)<br>&nbsp;&nbsp;&nbsp; &middot;设置并启动核心调页线程kswapd(为了防止kswapd启动时将版本信息输出到其他信息中间,核心线调用kswapd_setup()设置kswapd运行所要求的环境,然后再创建 kswapd核心线程)<br>&nbsp;&nbsp;&nbsp; &middot;创建事件管理核心线程(start_context_thread()函数启动context_thread()过程,并重命名为keventd)<br>&nbsp;&nbsp;&nbsp; &middot;设备初始化(包括并口parport_init()、字符设备chr_dev_init()、块设备 blk_dev_init()、SCSI设备scsi_dev_init()、网络设备net_dev_init()、磁盘初始化及分区检查等等,device_setup())<br>&nbsp;&nbsp;&nbsp; &middot;执行文件格式设置(binfmt_setup())<br>&nbsp;&nbsp;&nbsp; &middot;启动任何使用__initcall标识的函数(方便核心开发者添加启动函数,do_initcalls())<br>&nbsp;&nbsp;&nbsp; &middot;文件系统初始化(filesystem_setup())<br>&nbsp;&nbsp;&nbsp; &middot;安装root文件系统(mount_root())<p>&nbsp;&nbsp;&nbsp; 至此do_basic_setup()函数返回init(),在释放启动内存段(free_initmem())并给内核解锁以后,init()打开/dev/console设备,重定向stdin、stdout和stderr到控制台,最后,搜索文件系统中的init程序(或者由init=命令行参数指定的程序),并使用 execve()系统调用加载执行init程序。<p><br>&nbsp;&nbsp;&nbsp; init()函数到此结束,内核的引导部分也到此结束了,这个由start_kernel()创建的第一个线程已经成为一个用户模式下的进程了。此时系统中存在着六个运行实体:<p>&nbsp;&nbsp;&nbsp; &middot;start_kernel()本身所在的执行体,这其实是一个&quot;手工&quot;创建的线程,它在创建了init()线程以后就进入cpu_idle()循环了,它不会在进程(线程)列表中出现<br>&nbsp;&nbsp;&nbsp; &middot;init线程,由start_kernel()创建,当前处于用户态,加载了init程序<br>&nbsp;&nbsp;&nbsp; &middot;kflushd核心线程,由init线程创建,在核心态运行bdflush()函数<br>&nbsp;&nbsp;&nbsp; &middot;kupdate核心线程,由init线程创建,在核心态运行kupdate()函数<br>&nbsp;&nbsp;&nbsp; &middot;kswapd核心线程,由init线程创建,在核心态运行kswapd()函数<br>&nbsp;&nbsp;&nbsp; &middot;keventd核心线程,由init线程创建,在核心态运行context_thread()函数<p>对于I386平台<br>&nbsp;&nbsp;&nbsp; 基本相同。<p>对于2.4.x版内核<br>&nbsp;&nbsp;&nbsp; 这一部分的启动过程在2.4.x内核中简化了不少,缺省的独立初始化过程只剩下网络(sock_init())和创建事件管理核心线程,而其他所需要的初始化都使用__initcall()宏包含在do_initcalls()函数中启动执行。<p>五.init进程和inittab引导指令<br>&nbsp;&nbsp;&nbsp; init进程是系统所有进程的起点,内核在完成核内引导以后,即在本线程(进程)空间内加载init程序,它的进程号是1。<p>&nbsp;&nbsp;&nbsp; init程序需要读取/etc/inittab文件作为其行为指针,inittab是以行为单位的描述性(非执行性)文本,每一个指令行都具有以下格式:<p>&nbsp;&nbsp;&nbsp; id:runlevel:action:process其中id为入口标识符,runlevel为运行级别,action为动作代号,process为具体的执行程序。<p>&nbsp;&nbsp;&nbsp; id一般要求4个字符以内,对于getty或其他login程序项,要求id与tty的编号相同,否则getty程序将不能正常工作。<p>&nbsp;&nbsp;&nbsp; runlevel是init所处于的运行级别的标识,一般使用0-6以及S或s。0、1、6运行级别被系统保留,0作为shutdown动作,1作为重启至单用户模式,6为重启;S和s意义相同,表示单用户模式,且无需inittab文件,因此也不在inittab中出现,实际上,进入单用户模式时,init直接在控制台(/dev/console)上运行/sbin/sulogin。<p>&nbsp;&nbsp;&nbsp; 在一般的系统实现中,都使用了2、3、4、5几个级别,在Redhat系统中,2表示无NFS支持的多用户模式,3表示完全多用户模式(也是最常用的级别),4保留给用户自定义,5表示XDM图形登录方式。7-9级别也是可以使用的,传统的Unix系统没有定义这几个级别。runlevel可以是并列的多个值,以匹配多个运行级别,对大多数action来说,仅当runlevel与当前运行级别匹配成功才会执行。<p>&nbsp;&nbsp;&nbsp; initdefault是一个特殊的action值,用于标识缺省的启动级别;当init由核心激活以后,它将读取inittab中的initdefault项,取得其中的runlevel,并作为当前的运行级别。如果没有inittab文件,或者其中没有initdefault项,init将在控制台上请求输入 runlevel。<p>&nbsp;&nbsp;&nbsp; sysinit、boot、bootwait等action将在系统启动时无条件运行,而忽略其中的runlevel,其余的action(不含initdefault)都与某个runlevel相关。各个action的定义在inittab的man手册中有详细的描述。<p>&nbsp;&nbsp;&nbsp; 在Redhat系统中,一般情况下inittab都会有如下几项:<p>&nbsp;&nbsp;&nbsp; id:3:initdefault:<br>&nbsp;&nbsp;&nbsp; #表示当前缺省运行级别为3--完全多任务模式;<br>&nbsp;&nbsp;&nbsp; si::sysinit:/etc/rc.d/rc.sysinit<br>&nbsp;&nbsp;&nbsp; #启动时自动执行/etc/rc.d/rc.sysinit脚本<br>&nbsp;&nbsp;&nbsp; l3:3:wait:/etc/rc.d/rc 3<br>&nbsp;&nbsp;&nbsp; #当运行级别为3时,以3为参数运行/etc/rc.d/rc脚本,init将等待其返回<br>&nbsp;&nbsp;&nbsp; 0:12345:respawn:/sbin/mingetty tty0<br>&nbsp;&nbsp;&nbsp; #在1-5各个级别上以tty0为参数执行/sbin/mingetty程序,打开tty0终端用于<br>&nbsp;&nbsp;&nbsp; #用户登录,如果进程退出则再次运行mingetty程序<br>&nbsp;&nbsp;&nbsp; x:5:respawn:/usr/bin/X11/xdm -nodaemon<br>&nbsp;&nbsp;&nbsp; #在5级别上运行xdm程序,提供xdm图形方式登录界面,并在退出时重新执行<p><br>六.rc启动脚本<br>&nbsp;&nbsp;&nbsp; 上一节已经提到init进程将启动运行rc脚本,这一节将介绍rc脚本具体的工作。<p>&nbsp;&nbsp;&nbsp; 一般情况下,rc启动脚本都位于/etc/rc.d目录下,rc.sysinit中最常见的动作就是激活交换分区,检查磁盘,加载硬件模块,这些动作无论哪个运行级别都是需要优先执行的。仅当rc.sysinit执行完以后init才会执行其他的boot或bootwait动作。<p>&nbsp;&nbsp;&nbsp; 如果没有其他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改变运行级别时,所有相关的服务都将重启,即使是同一个级别。<p>&nbsp;&nbsp;&nbsp; rc程序执行完毕后,系统环境已经设置好了,下面就该用户登录系统了。<p>七.getty和login<br>&nbsp;&nbsp;&nbsp; 在rc返回后,init将得到控制,并启动mingetty(见第五节)。mingetty是getty的简化,不能处理串口操作。getty的功能一般包括:<p>&nbsp;&nbsp;&nbsp; 打开终端线,并设置模式<br>&nbsp;&nbsp;&nbsp; 输出登录界面及提示,接受用户名的输入<br>&nbsp;&nbsp;&nbsp; 以该用户名作为login的参数,加载login程序<br>&nbsp;&nbsp;&nbsp; 缺省的登录提示记录在/etc/issue文件中,但每次启动,一般都会由rc.local脚本根据系统环境重新生成。<p>注:用于远程登录的提示信息位于/etc/issue.net中。<p>&nbsp;&nbsp;&nbsp; login程序在getty的同一个进程空间中运行,接受getty传来的用户名参数作为登录的用户名。<p>&nbsp;&nbsp;&nbsp; 如果用户名不是root,且存在/etc/nologin文件,login将输出nologin文件的内容,然后退出。这通常用来系统维护时防止非root用户登录。<p>&nbsp;&nbsp;&nbsp; 只有/etc/securetty中登记了的终端才允许root用户登录,如果不存在这个文件,则root可以在任何终端上登录。/etc/usertty文件用于对用户作出附加访问限制,如果不存在这个文件,则没有其他限制。<p>&nbsp;&nbsp;&nbsp; 当用户登录通过了这些检查后,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的任务也就完成了。<p>八.bash<br>&nbsp;&nbsp;&nbsp; 运行级别3下的用户login以后,将启动一个用户指定的shell,以下以/bin/bash为例继续我们的启动过程。<p>&nbsp;&nbsp;&nbsp; bash是Bourne Shell的GNU扩展,除了继承了sh的所有特点以外,还增加了很多特性和功能。由login启动的bash是作为一个登录shell启动的,它继承了getty设置的TERM、PATH等环境变量,其中PATH对于普通用户为&quot;/bin:/usr/bin:/usr/local/bin&quot;,对于root 为&quot;/sbin:/bin:/usr/sbin:/usr/bin&quot;。作为登录shell,它将首先寻找/etc/profile 脚本文件,并执行它;然后如果存在~/.bash_profile,则执行它,否则执行 ~/.bash_login,如果该文件也不存在,则执行~/.profile文件。然后bash将作为一个交互式shell执行~/.bashrc文件(如果存在的话),很多系统中,~/.bashrc都将启动 /etc/bashrc作为系统范围内的配置文件。<p>&nbsp;&nbsp;&nbsp; 当显示出命令行提示符的时候,整个启动过程就结束了。此时的系统,运行着内核,运行着几个核心线程,运行着init进程,运行着一批由rc启动脚本激活的守护进程(如 inetd等),运行着一个bash作为用户的命令解释器。<p><p><center><A HREF="#Content">[目录]</A></center><hr><br><A NAME="I27" ID="I27"></A><center><b><font size=+2>lilo</font></b></center><br><center><A HREF="#Content">[目录]</A></center><hr><br><A NAME="I28" ID="I28"></A><center><b><font size=+2>lilo原理</font></b></center><br> 1一般的开机引导过程。<br>&nbsp;&nbsp;&nbsp; 在PC机上,最初的启动由BIOS完成。当开机自检结束时(Power-On Self Test,POST),BIOS尝试读入软盘的第一个扇区,把它看作引导扇区。若没有软盘,则尝试读入硬盘的第一个扇区。新的BIOS可以改变这种次序,先从硬盘启动。甚至从光盘启动。由于大多数BIOS不提供SCSI支持,若要从SCSI磁盘启动,SCSI适配器要提供他自己的BIOS.如果什么都找不到,老的BIOS会启动内置的ROM BASIC,或直接打印&quot;NO<br>ROM-BASIC&quot;.<br>&nbsp;&nbsp;&nbsp; 操作系统的启动分几步完成。由于引导扇区比较小,通常它主要任务是读入第二个loader,第二个loader再读入第三个loader,直到整个操作系统被完全读入。<p>&nbsp;&nbsp;&nbsp; DOS 引导区:<br>OFFSET<br>0x000&nbsp;&nbsp; JMP xx&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Near jump into the program code<br>0x003&nbsp;&nbsp; Disk parameters<br>0x03E&nbsp;&nbsp; Program code loading the DOS kernel<br>0x1FE&nbsp;&nbsp; 0xAA55&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Magic number for BIOS<br>&nbsp;&nbsp;&nbsp;&nbsp; 可见,引导区的结构相对比较简单。它的长度总是512字节。以上,磁盘参数只对DOS有意义。重要的是引导区从0开始,以BIOS的magic number 结束。<br>&nbsp;&nbsp;&nbsp;&nbsp; 从软盘启动比较简单,因为只有一个引导扇区:第一个扇区。硬盘则困难一些,它被分成很多分区。但是,BIOS根本不管分区信息,它象对待软盘一样对待硬盘,仍读入第一个分区,叫作:master boot record.(MBR).<br>&nbsp;&nbsp;&nbsp; 所以MBR也应该和上面介绍的结构一样:从0开始,以BIOS的magic number 结束<br>在MBR的最后部分,有分区表。如下图:<p>OFFSET&nbsp; Length<br>0x000&nbsp;&nbsp; 0x1BE code loading and starting the boot sector of the active<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; partitian<br>0x1BE&nbsp;&nbsp; 0x010&nbsp;&nbsp; partition1<br>0x1CE&nbsp;&nbsp; 0x010&nbsp;&nbsp; partition2<br>0x1DE&nbsp;&nbsp; 0x010&nbsp;&nbsp; partition3<br>0x1EE&nbsp;&nbsp; 0x010&nbsp;&nbsp; partition4<br>0x1FE&nbsp;&nbsp; 0x0012&nbsp; 0xAA55&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Disk parameters<p>每个分区信息占16字节,结构如下:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1 BOOT&nbsp; Boot flag: 0=not active ,0x80 active<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1 HD&nbsp;&nbsp;&nbsp; Begin:head number<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2 SEC&nbsp; CYL&nbsp; Begin:sector and cylinder number of boot sector<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1 SYS System Code:0x83 linux , 0x82 linux swap etc.<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1 HD&nbsp;&nbsp;&nbsp; End:head number<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2 SEC&nbsp; CYL&nbsp; End: sector and cylinder number of boot sector<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 4 low byte&nbsp; high byte&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Relative sector number of start sector<br>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -