操作系统启动[LINUX]

所需积分/C币:23 2007-03-14 12:32:21 253KB PDF
收藏 收藏
举报

因为没专业限制,开始学ARM的时候,觉得很难受。操作系统启动虽然是针对LINUX,但我想对这有一些认识,对于学ARM的编程结构有很好的帮助
Linux内核源代码漫游 创建时间:2001101121时13分 过在 kernel/ sched.c中的调度程序来改变。然而,由于所有的进程都必须方问它,所以使 用了宏 for each task。当系统负荷很轻时,它要比数组的顺序扫描快得多 进程总是运行于“用户模式”或“内核模式”。用户程序的主体是运行」用户模式而其 中的系统调用则运行于内核模式中。在这两种执行模式中进程所用的堆栈是不一样的-常 规的堆栈段用于用广模式,而个固定大小的堆栈(页,由该进程所有)则用于内核模式。 内核堆栈贝是从不交换出去的,因为每当一个系统调用进入时它就必须存在着 内核中的系统调用( system calls)是作为C语言函数存在的,它们的‘正规’名称是 以‘sys’廾头的。例如一个名为 burnout的系统调用将调用内核函数 sys burnout( MoR系统调用机制在本手册的第三章中进行了讨论。观看在 includc/ linux/ sched.h 中的 for each task和 SET LINKS能够帮助理解进程表中的列表和树结构。 创建和结束进程 unix系统是通过fork()系统调用创建一个进程的,而进程的终止是通过exit()或收到 个信号来完成的。它们的 Linux实现位于 kernel/fork.c和 kerne/ exit c中。派生出 个进程是很容易的,所以fork.c程序很短并易于珄解。它的主要任务是为新的进程填写 数据结构。除了填写各个字段以外,相关的步骤有: ●取得一个空闲内存页面米保存 task struct 找到一个空闲的进程槽( find empty process() ●为内存堆栈页 kernel stack page取得另一个空闲的内存页面 将父辈的LD拷贝到了进程 ●复制父进稈的mmap信息 svs fork(同样也管理文件描述符和 inode。 γ1.0的内核也对线程提供某些不够完善的支持,所以fork(系统调用对此也给出了 某些示意。内核的线程是主流内核以外的过程产品。 从个进程中退出是比较有窍门的,因为父进程必须被通告有关任何了进程的退出。而 且,一个进程可以由另外一个进程使用kil0而退出(这些是Unix的特性),所以除了 sys exit(之外, sys ki10以及 sys wait的各种特性也存在于exit.c之中了 这里不对exit.c的代码加以讨论—因为它一点也不令人感兴趣。为了以一致的状态退 出系统,它涉及到许多细节。而 POSIX标准对于信号则是要求相当严格的,所以这里必须对 其加以叙述 执行程序 在调用了fork○之后,就有同一个稈序的两个拷贝在运行了,通常一个程序使用 cacc( 执行另一个程序。exec(系统调用必须定位该执行文件的进制映像,加载并执行它。词语 ‘加载’并不一定意味着“将二进制映像拷贝进内存”,因为Linuⅹ支持按需加载。 exec 的 Linux实现支持不同的二进制格式。这是通过 linux binfmt结构来达到的,其中内嵌了 两个指向函数的指针—个是用于加载可执行文件的,另个用于加载库函数,每种二进制 格式都实现有这两个函数。共享库的加载是在 ccc(同一个源程序中实现的,但我们只讨 论eXec()本身。Unix系统提供了六种exec函数。除了一个以外,所有都是以库函数的 形式实现的,并且, Linux内核是单独实现 sys execve(调用的。它执行一个非常简单的任 务:加载可执行文件的头部,并试着去执行它。如果头两个字节是“#!”,那么就会解析该 可执行文件的第行并调用个解释器来执行它,否则的话,就会顺序地试用各个注册过的 二进制格式。 Linux本身的格式是由fs/exec.C接支持的,并且相关的函数是 第页共页 Linux内核源代码漫游 创建时间:2001101121时13分 oad_ aout binary和load_ aout library。对于二进制,函数将加载一个“a.out”可执行 文件并以使用map⑨加载磁盘文件或调用 read exec(而结束。前一种方法使用了 Linux 的按需加载札理,在程序被访问时使用出铓加载方式( fault-in)加载程序页面,而后一种 方式是在主机文件系统不支持内存映像时(例如“ msdos”文件系统)使用的。 新近的1.1内核内嵌了个修订的 msdos文件系统,它支持mmap0。而且 linux binfmt结构已是一个链表而不是一个数组了,以允许以一个内核模块的方式加载 个新的二进制格式。最后,结构的本身也已经被扩展成能够访问与格式相关的核心转储程序 访问文件系统 众所周知,文件系统是Unix系统中最为基本的资溟了,它如比的基本和普遍存在以至 于它需要个更为便利的名字一我将忠于标准的称呼简单地称之为“fs 我将假设读者早已知道基本的Unix文件系统的原理一访问(权限)许可、i节点( inode)、 超级块、加载( mount)和卸载( umount)文件系统。这些概念在标准的Lnix文献中由比我聪明 的作者给出了很好的解释,所以我就不重复他们的工作并且我将只专注于有关 Linux方面的 问题 早期的Unix通常只支持一个文件系统(fs)类型,它的代码散布于整个内核中,现今 的实现是在内核和fs之间使用一个标准的接口,以便于在不同的体系结构中进行数据的交 换ε Linux本身提供了一个标准层以在内核和每和fs模块之间传递数据。这个接口层称为 VFS,即“虚拟文件系统”(" virtual filesystem")。 因而文件系统的代码被分割成了两层:上层是关于内核表格的管理和数据结构的,而低 层是由与各文件系统相关的函数集构成的,并且是由ⅥS数据结构进行调用的。 所有与文件系统独立的资料都位于fs/*.C文件中。它们涉及如下的问题: 管理缓冲寄存器( buffer.c); 对 fcntl(和 ioctl(系统调用作出响应(fnt.c和 ioctl.c); 在 inode和缓冲区上映射管道和fifo(fifo.c,pipe.c) 管理文件和 inode表( file table.C, inode.c); 锁定和解锁文件和记求(lock.c) 将名称映射到 i node( name 1.c,open.c); 实现错综复杂的 select()函数( select.c); 提供信息(stat.c); 加载和卸载文件系统( super.c) 使用exec执行可执行程序以及转储核心程序(exec.c); 加载各和二进制格式( bin fmt半.c,如上面所述)。 而VTS接凵则由一组相对比较高层次的操作组成,并从与文件系统独立的代码中调用而 实际上是由每种文件系统类型执行的。最为相关的数据结构是 inode operations和 file operations,尽管它们不是独自存在的:同样存在着其它一些数据结构。它们都定义 在 include/liux/fs.h文件中。 到实际文件系统的内核入口点是数据结构file_ system typea file system types的 个数组包含在fs/ filesystems.c中,并且每当发出了一个加载( moun t)命令时都会引用它 然后,相应fs类型的函数 read super就负责填写结构 super block的一个项,而该项又内 揿了结构 super_ struc t和结构 type sb info。前者为当前的fs类型提供了指向一般fs操 作的指针,而后者对相应fs类型内嵌了特定的信息。 第页共页 Linux内核源代码漫游 创建时间:2001101121时13分 擿γ文件系统类型数组已经转换成了一个链表,以允许用内核模块的形式加载新的fs 类型。函数(un-) register filesystem代码包含在fs/ super.c中。 个文件系统类型的快速剖析 一个文件系统类型的任务是执行用于映射相应高层ⅦFS操作到物理介质(磁盘、內络等 等)的低层任务。VFS接口有足够的灵活性来支持传统的Unix文件系统和外来的象mdos 和 umsdos文件系统类型。 每一个fs类型除了它自己的源代码日录以外,是由下列各项组成的: file systems[]数组中的一个条目(项)(fs/ filesystems.c): 超级块( superblock)的 include文件( include/ linux/ type fs sb.h); i节点( inode)的 includc文件( includc/ linux/ typc fs_i.h) 普通自己专用的 inc lude文件( include/ linux/ type fs.h); include/ linux.fs.h中的两行# include,以及在结构 super b1ock和 inode中的 条目。 对」特定fs类型自凵的目录,包含有所有的实际代码、 inode和数据的管理程序。 MORE木手册中有关 procfs的章节,揭示了所有有关那种fs类型的低层代码和FS接 。在阅读过那个章节之后,fs/ procfs中的源代码就显得非常容易理解了。 现在我们来观察VFS机制的内部工作情況,并以 mInIX文件系统的代码作为一个实际例 子。我选择 minix类型是因为它比较短小但却是完整的;而且, Linux中的所有其它的fs 类型都衍生于它。在最近 Linux安装中的事实上的标准文件系统类型ext2,要比它复朱得 多,对cxt2这个文件系统的探索就留给聪明的读者作为一个练习了。 当一个 minix fs被加载后, minix read super就会把从被加载的设备中读取的数据添 入 super_ block数据结构中。此时,该结构中的s_op域将休留有一个指向 minIX sops的指 针,该指针将被一般文件系统代码用于分派超级块的操作 在全局系统树结构中链接新加载的fs依赖于下列各数据项(假设sb是超级块数据结构, 而diri是指向加载点的 inode的指针) b> s mounted指向被加载文件系统的根目录i节点( MINIX ROOT INO); diri-> 1 mount休存有sb→> s mounted sb-> s covered保存有diri 卸载操作将最终通过 do umount来执行,而它会依次调用 minix put super。 每当访问一个文件时, minix read inode就会开始执行:它会使用 minix inode各字 段中的数据填写系统范围的 inode数据结构。 inode→)iop字段是依照 inode-) i mode来填 写的,它将负责该文件的任何其它操作。上述 minIX函数的代码可以从fs/ mInIx/ inode 中找到 inode operations数据结构是用于把 inode操作分派给特定fs类型的内核函数;该数 据结构的第一项是一个指向file_ operations项的指针,它等同于数据管理的 1 opo miniX 文件系统类型允诈有 inode操作集中的三种方式(用于目录、文件和符号链接〕和文件操作 集中的两种(符号链接不需要文件操作) 位于fs/ 'minIx/file.c中而符号操作(读取并跟随着链)位于 fs/minix/ symlink. c write) 目录操作(仅 minix readdir)位于fs/ mInIX/dir.c中;文什操作(读read和写 minIX源代码目录中的其余部分用于实现以下任务 bitmap.c用于管理i节点与块的分配和释放(而ext2文件系统却有两个不同的代 吗文件); 第页共页 Linux内核源代码漫游 创建时间:2001101121时13分 fsnk.c用于 Sync(系统调用—它管理直接、间接和双重间接块(我假定你是知 道这些术语的,因为这是Inix的普通知识) naei.¢内嵌有所有与名字有关的i节点的操作,比如象节点的创建和消除、重命 名和链接; truncate.c执行文件的截断操作。 控制台驱动程序( 作为大多数 Linux系统上的主要I/0设备,控制台驱动程序是应该受到某些关注的。有 关控制台和其它字符驱动程序的源代码可以在 drivers/char中找到,当我们指称文件时, 我们将使用这个特定的目录。 控制台的初始化是由 tty 1o.c中的 tty init函数来执行的。这个函数仅仅涉及取得 每个设备集的主设备号并调用每个设备集的init函数。而 con init(则是与控制台相关的 函数,并存在于 console.c中。 w在内核1.1的开发中,控制台的初始化已经有了很大的变化。 console init(已 经从 tty init(中脱离出来了,并且是由..../main.c直接调用的。现在虚拟控制台是动 态分配的,其代码也已有了很大的变化。所以我将跳过初始化、分配等等的详细讨论 文件操作是如何分派给控制台的 这一节是相当底层的讨论,你可以放心地跳过本节。 毫无疑问,Unix设备是通过文件系统来访问的。本节将详细描述从设备文件到实际控 制台函数的所有步骤,而且,以下的信息是从内核的1.1.73源代码中抽取来的,它与1.0 的代码可能少许有点不同。 当打开一个设备i节点时,在../../fs/ devices.c中的 chrdev open(函数(或者是 blkdev open○,但我只专注于字符设备)将被执行。这个函数是通过数据结构 def chr_fops 取得的,而它又是被 chrdev inode operations引用的,是被所有文件系统类型使用的(见 前面有关文件系统的部分) chrdev open通过在当前操作中替换具体设备的 file operations表并且调用特定的 open(函数来管理指定的设备操作的。具体设备的表结构是保存在数组 chrdevs[中的,并 由主设备号作为索引,位于同一个.../ devices.c中。 如果该改备是一个tty类型的(我们不是只关注控制台吗?),我们就来讨论tty的改 备驱动程序,它们的函数在 tty 10.c之中,由 tty fops作为索引。这样, tty open(就会 调用 init dev(,血 init dev○就会棖据次设备号为设备分配任何所需的数据结构。 次设备号也用于检索已终使用 tty register driver注册登记过的设备的实际驱动 程序。而且,该驱动程序仍是另一个用于分派计算的数据结构,正如file_ops一样;它是 与改备的与操作和控制有关的。最后一个用于管理tty的数据结构是线路规程,这将在后面 叙述。控制台(以及任何其它的tty设备)的线路规程是由 initialize_ tty struct()设置 的,并由 init dev调用的。 在这一节中我们所涉及的所有事情都是与设备无关的,仅有与特定控制台相关的是 console.c,在 con init(操作期间已经注册了自己的驱动程序。相反,线路规程是与设备 无关的。 MOREThe tty driver数据结构在〈 linux/ tty driver.h>中有着完整的描述 腰上述信息是从1.1.73源代码中取得的。它是有可能与你的内核有所不同的(“如 信息有所变动将不另行通知”)。 第页共页 Linux内核源代码漫游 创建时间:2001101121时13分 控制台写操作 当往一个控制台设备进行写操作时,就会调用 con write函数。这个函数管理所有控制 宇符和换码字符序列,这些字符给应用程序提供全部的屏幕管理操作。所实现的换码序列是 vt102终端的;这意味着当你使用 telnet连接到一台非 Linux主机时,你的环境变量应该 有 TERM=Vt102;然而,对于本地操作最佳的选择是设置TERM= console,因为 Linux控制台 提供了一个vt102功能的超集 因而, con write(主要是由转换语句组成的,用于处理每一次一个字符的有限长状态 自动换码序列的解释。在止常方式下,所打印的字符是使用当前属性直接写到显示内存中的。 在 console.c中,数据结构vc的所有域使用宏都是可访问的,所以(例如)任何对attr 的引用,只要 currens是所指的控制台的号码,确实是引证了数据结构 vc cons[ currens 中的域。 腰w实际上,新内核中的 vc cons已不再是一个数据结构数组了,现在它是指针的数 组,其内容是用 kmalloc(操作的。宏的使用大大地简化了代码修改的工作,因为许多代码 都不需要被重写。 控制台内存到屏幕内存的实际映射和非映射是由函数 set scrmem0(它把控制台缓冲 区中的数据拷贝到显示内存中)和 get srcmem((它把数据拷贝回控制台缓冲区中)执行 的。为了减少数据传输的次数,当前控制台的私有缓冲区是物理地映射到实际显示RAM上的。 这意味着 console.c中的get和 set scrmem o是静态的,并且仅在一个控制台转换期间才 被调用。 控制台读操作 控制台读操作是由线路规程来完成的。Linx中默认的(也是唯一的)线路规程被称为 tty lisc N tty。线峰规程也就是“通过一线路约束输入”。它是另一个函数表(我们u 习惯了这种方法,不是吗?),它是有关于设备读操作的。在 termas标志的帮助下,线路 规程也即是从tty上控制输入的规程:未处理过的数据、 creak和计划的方式; select(; ioct1(等等。 线路规程中的读(read)函数称为 read chan o,它读取tty的缓沖区而不管数据是从 哪里来的。原因是通过一个tty来到的字符是由异步硬件中断管理的。 MOR线路规程NTTY也同样在 tty 10.c中,尽管以后出的内核都使用一个不同的 ntty.c源程序。 控制台输入的最底层是键盘管理的一部分,因此它是在 keyboard.c的 keyboard interrupt()中处理的。 键盘管理 键盘管理简直是一场噩梦。它限」文件 keyboard.c中,里面充满了表示不同厂家键盘 的各个键码的十六进制数 我将不对 key board.c进行深入讨论,因为其中没有与内核研究者有关的相关信息 Moπ对于那些对 Linux的键盘编程确实感兴趣的人,最好的方法是从 keyboard.c的最 后一行往回看起。最底层的细节是在该文件的上半部分。 转换当前控制台 第页共页 Linux内核源代码漫游 创建时间:2001101121时13分 当前控制台是通过使用函数 change console()来转换的,它位于 tty 10.c中由 keyboard.c和vt.c调用(前者响应按键的控制台转换,后者是当一个程序通过引用一个 ioctl调用时转换控制台)。 实际的转换过程是分两步来执行的,函数 complcte changc console(处理其中的第二 部分。转换的分裂意味着在个与控制着我们止在离开的tty的进程的可能的握手以后完成 任务。如果控制台不在进程控制之下, change console(就会自己调用 complete change console()。进程需要足够的能力来成功地完成从图形到文本控制台或从 文木到图形控制台的转换,并且ⅹ服务器(例如)是其图形控制台的控制进程 选择机制 选择( sclcction)”是 Linux文本控制台的剪切(cut)与粘贴( paste)功能。这 个技巧主要是由用广级的进程来处理的,它可以用 selection或gpm的具体例了说明。用户 级的程序在控制台上使用 ioctl(通知内核来加亮显示屏幕的一个区域。然后,被选择的文 本被拷贝到一个选择缓冲区。该缓冲区是 console.c中的一个静态实体。粘贴文本操作是通 过“手工地”将宇符放入ty输入队列中完成的。整个选择机制是通过#ifde'受到保护的, 所以用户在内核配置期间可以禁用它以节省几千字节的内存。 选择是一个非常低级的功能,因而它工作是任何其它内核活动所看不见的。这意味着许 多的 ifdef只是屏幕在以任何方式作修改之前简单地移动加亮部分 γ新内核特性改善了选择的代码,鼠标指针的加亮可以与被选择的文本独立(内核 1.1.23或更高)。而且,从1.1.73版起,被选择的文本使用了动态的缓冲区而不是静态的 了,使得内核小了4KB。 使用 ioctL O操作设备 ioctl(系统调用是用户进程控制设备文件行为的入凵点。Ioct1管理是 从.../fs/ioct1.c中产生的,实际上 sys ioct1(就是在这个ioct1.c中的。标准的 ioctl 请求就是在那里执行的,其它与文件相关的请求是由 file iact10处理的(在同一个源文 件中),而其它任何请求都分派给特定设备的 ioctl(函数 搾制台设备的 ioctl资料是位于vt.c中的,因为搾制台驱动稈序要将 ioctl请求分派 给 vt ioctl0 腰w上述信息是关于内核1.1.7x的。1.0内核是没有“驱动程序”表的,而且 vt ioctl 是直接由 file operations(表指向的。 Ioctl的资料确实是相当让人混淆的。有些请求是与设备相关的,而有些却是与线路规 稈相关的。我将试图对1.0和1.1.7x内核之间发牛的仟何事概要总结一下 1.1.7x系列内核有如下的特性:tty_ioct1.c只实现了线路规程请求(也就是 n tty ioctl(,这是唯一在ntty.c外血的ntty函数),而 file operations字段指向 tty 10.c中的tty_iotl(。如果请求号没有被tty_ioct1O解析出来,它就会被传到 tty- driver.ioct或者,如果它失败吋,就到tty- disc. ioct l。控制台的与驱动程序相 关的资料可以从vt.c中找到,而线路规稈方面的资料则在 tty ioctl.c中 在1.0内核中, tty loct10是在 tty 1oct1.c中的并有一般tty的 file operations 所指向。未皴解析出的请求将用与1.1.7x相似的方法被传送到特定的ioct1函数或到线路 规程代码去 注意,在这两种情况中, TIOCLINUX请求是在与设备无关的代码中的,这暗示着控制台 选择操作可以通过 ioctl对任何tty进行操作来设置( set selection()总是在控制台前台 第页共页 Linux内核源代码漫游 创建时间:2001101121时13分 上操作的),而这是一个安全上的漏洞。这也是转移到一个更新的内核的很好理由,在新内 核中,通过仅允诈超级用户来处理选择弥补了这个漏洞。 有很多请求可以被发给控制台设备,而知道它们的最好方法是浏览源程序文件vt.C。 版权所有(c)1994 Alessandro rubini, rubini@pop. systemy.it 第页共页

...展开详情
试读 9P 操作系统启动[LINUX]
立即下载 低至0.43元/次 身份认证VIP会员低至7折
一个资源只可评论一次,评论内容不能少于5个字
jellyhd 还好,就是内容太少
2014-12-22
回复
南国生红豆 不错,给我一个积分~
2014-06-09
回复
  • GitHub

    绑定GitHub第三方账户获取
关注 私信 TA的资源
上传资源赚积分,得勋章
最新推荐
操作系统启动[LINUX] 23积分/C币 立即下载
1/9
操作系统启动[LINUX]第1页
操作系统启动[LINUX]第2页

试读结束, 可继续读1页

23积分/C币 立即下载 >