版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、计算机科学与技术学院操作系统课程设计报告学号: 姓名: 指导老师: 指导老师评语: 签字: 课程设计成绩:设计过程表现设计报告质量总分目录: TOC o 1-3 h z u HYPERLINK l _Toc312310922 1课程设计内容: PAGEREF _Toc312310922 h 3 HYPERLINK l _Toc312310923 1.1安装Linux操作系统 PAGEREF _Toc312310923 h 3 HYPERLINK l _Toc312310924 1.2下载另一版本的内核进行内核编译 PAGEREF _Toc312310924 h 3 HYPERLINK l _T
2、oc312310925 1.3把新编译好的内核和原来的内核用boot loader设置成可选的新旧内核启动开机 PAGEREF _Toc312310925 h 3 HYPERLINK l _Toc312310926 1.4分析内核代码中文件init/main.c,在对代码进行充分阅读的根底上,得到相应的框图 PAGEREF _Toc312310926 h 3 HYPERLINK l _Toc312310927 2安装Linux操作系统 PAGEREF _Toc312310927 h 3 HYPERLINK l _Toc312310928 2.1从内网ftp:/s23上下载所需资料: PAGER
3、EF _Toc312310928 h 3 HYPERLINK l _Toc312310929 3升级内核从linux-2.4.20-8到linux-2.6.18 PAGEREF _Toc312310929 h 4 HYPERLINK l _Toc312310930 3.1在因特网上下载内核以及其他5个工具。 PAGEREF _Toc312310930 h 4 HYPERLINK l _Toc312310931 3.2把下载好的6个文件装入同一个文件夹如:linux-tools,复制到u盘。如图3.2: PAGEREF _Toc312310931 h 4 HYPERLINK l _Toc3123
4、10932 3.3把鼠标移动到linux下,插入U盘。新建终端,输入以下命令: PAGEREF _Toc312310932 h 4 HYPERLINK l _Toc312310933 3.4查看自己内核版本。 PAGEREF _Toc312310933 h 4 HYPERLINK l _Toc312310934 3.5在linux安装6个文件 PAGEREF _Toc312310934 h 5 HYPERLINK l _Toc312310935 3.6安装binutils-2.17.tar.gz工具包,依次执行如下命令: PAGEREF _Toc312310935 h 5 HYPERLINK
5、l _Toc312310936 3.7配置内核选项。 PAGEREF _Toc312310936 h 6 HYPERLINK l _Toc312310937 3.8编译内核 PAGEREF _Toc312310937 h 8 HYPERLINK l _Toc312310938 3.9把新编译好的内核和原来的内核用boot loader设置成可选的新旧内核启动开机 PAGEREF _Toc312310938 h 8 HYPERLINK l _Toc312310939 3.10重新启动linux,此时你会看到内核进入选项。 PAGEREF _Toc312310939 h 9 HYPERLINK l
6、 _Toc312310940 4分析内核代码中文件init/main.c,并建立相应框图 PAGEREF _Toc312310940 h 10 HYPERLINK l _Toc312310941 4.1找到init/main.c代码并阅读 PAGEREF _Toc312310941 h 10 HYPERLINK l _Toc312310942 4.2系统初始化过程流程 PAGEREF _Toc312310942 h 11 HYPERLINK l _Toc312310943 4.3常量和出错信息的意义 PAGEREF _Toc312310943 h 14 HYPERLINK l _Toc3123
7、10944 4.4调用关系图 PAGEREF _Toc312310944 h 15 HYPERLINK l _Toc312310945 4.5各模块/函数的功能及详细框图 PAGEREF _Toc312310945 h 15 HYPERLINK l _Toc312310946 4.6static void time_init(void)分析 PAGEREF _Toc312310946 h 16 HYPERLINK l _Toc312310947 4.7void main(void)分析 PAGEREF _Toc312310947 h 17 HYPERLINK l _Toc312310948 4
8、.8pause()分析 PAGEREF _Toc312310948 h 19 HYPERLINK l _Toc312310949 4.9static int printf(const char *fmt, .)分析 PAGEREF _Toc312310949 h 19 HYPERLINK l _Toc312310950 4.10void init(void)分析 PAGEREF _Toc312310950 h 20 HYPERLINK l _Toc312310951 5总结与体会 PAGEREF _Toc312310951 h 24 HYPERLINK l _Toc312310952 5.1升
9、级内核的总结体会 PAGEREF _Toc312310952 h 24 HYPERLINK l _Toc312310953 5.2阅读main.c代码的总结体会 PAGEREF _Toc312310953 h 25课程设计内容:安装Linux操作系统下载另一版本的内核进行内核编译把新编译好的内核和原来的内核用boot loader设置成可选的新旧内核启动开机分析内核代码中文件init/main.c,在对代码进行充分阅读的根底上,得到相应的框图安装Linux操作系统从内网 HYPERLINK ftp:/s23 ftp:/s23上下载所需资料:VMware-workstation-6.5.1-12
10、6130.exe、vmware的序列号.txt、redhat 9 虚拟机原始文件.rar。安装“VMware-workstation,并启动。如图2.2解压“redhat 9虚拟机原始文件.rar,翻开解压文件,双击“redhat.vmx。此时linux安装完成,且启动。用户名:root密码:123456.升级内核从linux-2.4.20-8到linux-2.6.18在因特网上下载内核以及其他5个工具。下载linux-2.6.18.tar.bz2下载mkinitrd-4.1.18-2.i386.rpm下载lvm2-2.00.25-1.01.i386.rpm下载device-mapper-1.
11、00.19-2.i386.rpm下载module-init-tools-3.2.tar.bz2下载binutils-2.17.tar.gz把下载好的6个文件装入同一个文件夹如:linux-tools,复制到u盘。如图3.2:把鼠标移动到linux下,插入U盘。新建终端,输入以下命令:#fidisk f 查看所有硬盘和u盘,找到u盘的挂载名,如/dev/sdb1 #mount /dev/sdb1 /mnt#cd /mnt#ls 查看mnt目录下的文件,并把需要的6个文件拷贝到/usr/src中#cp binutils-2.17.tar.gz /usr/src#cp device-mapper-1
12、.00.19-2.i386.rpm / usr/src#cp linux-2.6.18.tar.bz2 /usr/src#cp lvm2-2.00.25-1.01.i386.rpm /usr/src#cp mkinitrd-4.1.18-2.i386.rpm /usr/src#cp module-init-tools-3.2.tar.bz2 /usr/src查看自己内核版本。#uname a 我的是linux-2.4.20-8在linux安装6个文件解压内核,具体操作请依次执行以下命令:# cd /usr/src (进入到/usr/src目录) # tar jvxf linux-2.6.18.
13、tar.bz2 (解压新内核)# ln -s linux-2.6.18 linux (重新生成linux文件夹)安装module-init-tools工具包在/usr/src目录下,依次执行以下命令:# tar jvxf module-init-tools-3.2.tar.bz2 (解压module-init-tools)# cd module-init-tools-3.2 (由/usr/src目录进入module-init-tools目录下)#./configure -prefix=/# make moveold将原来的工具程序改名,这样还可继续使用原来的2.4.x内核# make all
14、install#./generate-modprobe.conf /etc/modprobe.conf安装另外三个升级工具回到/usr/src目录下,依次执行以下3个命令来安装另外三个升级工具:# rpm -ivh -nodeps mkinitrd-4.1.18-2.i386.rpm (注意,这里一定要参加-nodeps参数,下同)# rpm -ivh -nodeps lvm2-2.00.25-1.01.i386.rpm# rpm -ivh -nodeps device-mapper-1.00.19-2.i386.rpm如果不更新以上几个升级包,在后面编译内核时会提示以下错误:mkinitrd
15、 failedmake1: * install Error 1make: * install Error 2安装binutils-2.17.tar.gz工具包,依次执行如下命令:# tar zxf binutils-2.17.tar.gz# cd binutils-2.17# ./configure# make# make install最开始的时候我没有装Binutils 开发包因此都会出现错误,如下类似:Loading BusLogic.o moduleNo module found in objectinsmod:error inserting /lib/BusLogic.o:-1 In
16、valid module formatERROR:/bin/insomd exited abnormally!Mounting /proc filesystemCreating block devicesVFS:Cannot open root device LABEL=/dev/sda2 or unknown-block(0,0)Please append a correct root= boot optionKernel panic - not syncing:VFS:Unable to mount root fs on unknown-block(0,0)配置内核选项。# cd linu
17、x-2.6.18 (进入到/usr/src/linux-2.6.18目录下)# make mrproper (该命令可确保源代码目录下没有不正确的.o文件)# make menuconfig 配置内核各选项此时会出现一个图形界面,列出了所有的内核配置选项,有的选项下还有子选项,你可以用方向键来选择,用Y键来确定。大多数选项默认就行,以下几个选项必须选择请认真核对下面每一个选项,否那么编译很有可能前功尽弃:注意:前面的符号可能不用有M等等,这里提及的要全部选成*,除非无法转化成*,那么保存原来的格式,但是一定要选中Loadable Module support选项中,选“Module unloa
18、ding和“Automatic kernel module loading这两项;Device Drivers-Block Devices中选“Loopback device support;Device Drivers-Multi-device support(RAID and LVM)处选“device mapper support;Device Drivers-Graphics support, 选“ Support for frame buffer devices;Device Drivers -;USB support -选上USB Mass Storage supportDevic
19、e Drivers -; Network device support -;Ethernet (10 or 100Mbit) -; ; AMD PCnet32 PCI support由于在VMware虚拟机下编译内核,SCSI硬盘,因此以下三个选项必选:“Device Drivers“SCSI device support “SCSI device support;“Device Drivers“SCSI device support“SCSI disk support;“Device Drivers“SCSI device support“SCSI low-level drivers“Bus
20、Logic SCSI support; File system-以下9个选项是关于ext2和ext3文件系统配置,全部选上Second extended fs supportExt2 extended attributesExt2 POSIX Access Control ListsExt2 Security LabelsExt3 journalling file system supportExt3 extended attributesExt3 POSIX Access Control ListsExt3 Security LabelsJBD (ext3) debugging suppor
21、tFile system-DOS/FAT/NT Filesystems -选上“ NTFS file system support;File Systems - Miscellaneous filesystems - Compressed ROM file system support (cramfs)注意:由于Red Hat 9.0使用ext3作为文件系统,ext2和ext3文件系统配置很重要,也是必需的,如果对Ext3、Ext2文件的支持直接编译进内核,在你 reboot时机器就会当掉,出现如下错误信息:kernel panic : no init found ,try passing i
22、nit = option to kernel.或者是:VFS:Cannot open root device hdxy or unknow-block(0,0)Please append a correct root= boot optionkernel panic:VFS:Unable to mount root fs on unknown-block(0,0)或者是:mount: error 19 mounting ext3pivotroot: pivot_root(/sysroot,/sysroot/initrd) failed: 2umount /initrd/proc fail: 2
23、Freeing unused kernel memory: 244k freedKernel panic not syncing: No init found. Try passing init = option to kernel 编译内核设置完成!开始进行真正的内核编译工作。依次执行如下命令: 在/usr/src/linux-2.6.18目录下,执行以下命令即可编译。编译需要一段时间。# make dep 建立编译时所需的附属文件。注意:如果内核从未编译过,此步可跳过# make clean 去除内核编译的目标文件# make bzImage 注意大小写。这一步才真正编译内核比拟费时间内核
24、编译成功后,会在/usr/src/linux/arch/i386/boot目录中生成一个新内核的映像文件bzImage。如果用make zImage编译,内核很大的话,系统会提示你使用make bzImage命令来编译,所以我直接用make bzImage来编译。在root目录下输入:/usr/src/linux/arch/i386/boot命令查看有没有bzImage文件,有说明你安装正确。#cd /usr/src/linux 将目录切换到/usr/src/linux下执行以下命令# make modules 编译可加载模块比拟花时间# make modules_install 安装可加载模
25、块安装成功后,系统会在/lib/modules目录下生成一个2.6.18子目录,里面存放着新内核的所有可加载模块。#cp /usr/src/linux-2.6.18/drivers/scsi/BusLogic.o /lib/modules/2.6.18/kernel/drivers/scsi如果不执行上一步复制操作,在make install时会出现如下错误信息:No module BusLogic found for kernel 2.4.12mkinitrd failed此问题一般只出现在SCSI硬盘VMWARE+REDHAT架构中,因为BusLogic被编译进了内核而不是一个module
26、的形式2.4内核的Buslogic模块即使静态编译进内核也不行。其解决方式就是直接将BusLogic.o文件复制过去。# make install 安装新内核把新编译好的内核和原来的内核用boot loader设置成可选的新旧内核启动开机将新内核和System.map文件拷贝到/boot目录下,依次执行以下命令:在root下可执行下面这些命令# cp /usr/src/linux-2.6.18/arch/i386/boot/bzImage /boot/vmlinuz-2.6.18# cp /usr/src/linux-2.6.18/System.map /boot/System.map-2.6
27、.18# cd /boot 进入boot目录# rm rf System.map (删除原来的连接)# ln -s System.map-2.6.18 System.map (重新建立连接) 修改Grub启动管理器把新编译好的内核和原来的内核用boot loader设置成可选的新旧内核启动开机如果没有错误的话, 下面开始修改grub配置文件在/boot目录下cd /boot,执行以下命令:# new-kernel-pkg -mkinitrd -depmod -install 2.6.18 这时候你的/boot下生成一个initrd-2.6.18.img,并且你的grub.conf也作了相应更改
28、# df 查看根目录在那个分区,下一步要用到。注意,这里根分区不是boot的那个50M的分区,而一般是你最大的那个分区,也就是/,千万不要搞错。我的为 /dev/sda2如果你是在root目录下:# vi /boot/grub/grub.conf如果不在root目录下,要进入到root目录下执行此命令进入grub.conf文件,做两处修改:将default=1改为default=0不改的话,重启之后默认进入2.4内核将kernel行的“LABEL=/dev/sda2换成根目录所在的分区上一步查看的就是此步很重要,修改错误将会可能导致进不去系统,我把我修改后的grub.conf文件列出来,不明之
29、处,可以对照修改:default=0timeout=10splashimage=(hd0,0)/grub/splash.xpm.gztitle Red Hat Linux (2.6.18)root (hd0,0)kernel /vmlinuz-2.6.18 ro root=/dev/sda2initrd /initrd-2.6.18.imgtitle Red Hat Linux (2.4.20-8)root (hd0,0)kernel /vmlinuz-2.4.20-8 ro root=LABEL=/initrd /initrd-2.4.20-8.img按“Esc之后再按“: wq退出编辑并保
30、存。重新启动linux,此时你会看到内核进入选项。选择自己更新的内核版本进入系统,并查看内核版本。#uname a分析内核代码中文件init/main.c,并建立相应框图找到init/main.c代码并阅读#vi /usr/src/linux/init/main.c系统初始化过程流程系统整个初始化过程见图4.2所示:进程n进程1开始系统初始化对物理内存各局部进行功能划分和分配系统各个局部初始化,包括对任务0初始化移到任务0中执行创立进程1(init)空闲时执行pause()加载根文件系统设置终端标准IO创立进程2循环等待进程2退出创立子进程循环等待进程结束任务进程0终端输入定向到rc执行she
31、ll退 出设置终端标准IO执行shell退 出进程2图4.2 内核初始化程序流程示意图数据结构时间结构:#define CLOCKS_PER_SEC 100/* 系统时钟滴答频率,100HZ */typedef long clock_t;/* 从进程开始系统经过的时钟滴答数 */struct tm int tm_sec;/* 秒数 0,59 */ int tm_min;/* 分钟数 0,59 */ int tm_hour;/* 小时数 0,59 */ int tm_mday;/* 1 个月的天数 0,31 */ int tm_mon;/* 1 年中月份 0,11 */ int tm_year;
32、/* 从1900 年开始的年数 */ int tm_wday;/* 1 星期中的某天 0,6星期天=0 */ int tm_yday;/* 1 年中的某天 0,365 */ int tm_isdst;/* 夏令时标志 */;存放硬盘参数表信息:struct drive_info char dummy32;drive_info;/* 用于存放硬盘参数表信息 */tty 等待队列数据结构和tty 数据结构:struct tty_queue unsigned long data;/* 等待队列缓冲区中当前数据指针字符数 */ unsigned long head;/* 缓冲区中数据头指针 */ un
33、signed long tail;/* 缓冲区中数据尾指针 */ struct task_struct *proc_list; /* 等待进程列表 */ char bufTTY_BUF_SIZE;/* 队列的缓冲区 */;struct tty_struct /* tty 数据结构 */ struct termios termios;/* 终端io 属性和控制字符数据结构 */ int pgrp;/* 所属进程组 */ int stopped;/* 停止标志 */ void (*write) (struct tty_struct * tty); /* tty 写函数指针 */ struct tt
34、y_queue read_q;/* tty 读队列 */ struct tty_queue write_q; /* tty 写队列 */ struct tty_queue secondary; /* tty 辅助队列(存放标准模式字符序列) */;/* 可称为标准(熟)模式队列 */请求队列中项的结构和块设备结构:struct request/* 请求队列中项的结构。其中如果dev=-1,那么表示该项没有被使用 */ int dev;/* 使用的设备号 */ int cmd;/* 命令(READ或 WRITE) */ int errors;/* 操作时产生的错误次数 */ unsigned l
35、ong sector;/* 起始扇区(1块=2扇区) */ unsigned long nr_sectors; /* 读/写扇区数 */ char *buffer;/* 数据缓冲区 */ struct task_struct *waiting; /* 任务等待操作执行完成的地方 */ struct buffer_head *bh;/* 缓冲区头指针(include/Linux/fs.h,68) */ struct request *next;/* 指向下一请求项 */;struct blk_dev_struct/* 块设备结构 */ void (*request_fn) (void); /*
36、请求操作的函数指针 */ struct request *current_request; /* 请求信息结构 */;常量和出错信息的意义定义系统调用嵌入式汇编宏函数。不带参数的系统调用宏函数。type name(void)。%0 - eax(_res),%1 - eax(_NR_#name)。其中name 是系统调用的名称,与 _NR_ 组合形成上面的系统调用符号常数,从而用来对系统调用表中函数指针寻址。返回:如果返回值大于等于0,那么返回该值,否那么置出错号errno,并返回-1。#define _syscall0(type,name) type name(void) long _res;
37、 _asm_ volatile ( int $0 x80 /* 调用系统中断0 x80 */:=a (_res) /* 返回值eax(_res) */: (_NR_#name); /* 输入为系统中断调用号_NR_name */ if (_res = 0) /* 如果返回值=0,那么直接返回该值 */ return (type) _res; errno = -_res; /* 否那么置出错号,并返回-1 */ return -1;/* 有1 个参数的系统调用宏函数。type name(atype a) */* %0 - eax(_res),%1 - eax(_NR_name),%2 - ebx
38、(a) */#define _syscall1(type,name,atype,a) type name(atype a) long _res; _asm_ volatile ( int $0 x80 : =a (_res) : (_NR_#name), b (long)(a); if (_res = 0) return (type) _res; errno = -_res; return -1; extern int errno;/* 出错号,全局变量 */static inline _syscall0(int,fork)/*这是unistd.h 中的内嵌宏代码。以嵌入汇编的形式调用Linu
39、x 的系统调用中断0 x80。该中断是所有系统调用的入口。该条语句实际上是int fork()创立进程系统调用。syscall0 名称中最后的0 表示无参数,1 表示1 个参数 */static inline _syscall0(int,pause) /* int pause()系统调用:暂停进程的执行,直到收到一个信号 */static inline _syscall1(int,setup,void *,BIOS)/* int setup(void * BIOS)系统调用,仅用于Linux 初始化仅在这个程序中被调用*/static inline _syscall0(int,sync) /*
40、 int sync()系统调用更新文件系统 */调用关系图在内核源代码的init/目录中只有一个main.c 文件。系统在执行完boot/目录中的head.s 程序后就会将执行权交给main.c。该程序虽然不长,但却包括了内核初始化的所有工作。main.c 程序首先利用前面setup.s 程序取得的系统参数设置系统的根文件设备号以及一些内存全局变量。这些内存变量指明了主内存的开始地址、系统所拥有的内存容量和作为高速缓冲区内存的末端地址。如果还定义了虚拟盘RAMDISK,那么主内存将适当减少。整个内存的映像示意图见图4.4 所示。内核程序高速缓存主内存区虚拟盘图4.4 系统中内存功能划分示意图图
41、中,高速缓冲局部还要扣除被显存和ROM BIOS 占用的局部。高速缓冲区是用于磁盘等块设备临时存放数据的地方,以1K1024字节为一个数据块单位。主内存区域的内存是由内存管理模块mm通过分页机制进行管理分配,以4K 字节为一个内存页单位。内核程序可以自由访问高速缓冲中的数据,但需要通过mm 才能使用分配到的内存页面。然后,内核进行所有方面的硬件初始化工作。包括陷阱门、块设备、字符设备和tty,包括人工设置第一个任务task 0。待所有初始化工作完成后就设置中断允许标志以开启中断,main()也切换到了任务0 中运行。在整个内核完成初始化后,内核将执行权切换到了用户模式任务0,也即CPU 从0
42、特权级切换到了第3 特权级。此时main.c 的主程序就工作在任务0 中。然后系统第一次调用进程创立函数fork(),创立出一个用于运行init()的子进程。各模块/函数的功能及详细框图该程序首先确定如何分配使用系统物理内存,然后调用内核各局部的初始化函数分别对内存管理、中断处理、块设备和字符设备、进程管理以及硬盘和软盘硬件进行初始化处理。在完成了这些操作之后,系统各局部已处于可运行状态。此后程序把自己“手工移动到任务0进程0中运行,并使用fork()调用首次创立出进程1init 进程。在init进程中程序将继续进行应用环境的初始化并执行shell 登录程序。而原进程0那么会在系统空闲时被调度
43、执行,此时任务0仅执行pause()系统调用,并又会调用调度函数。在init 进程中,如果终端环境建立成功,那么会再生成一个子进程进程2,用于运行shell 程序/bin/sh。假设该子进程退出,那么父进程进入一个死循环内,继续生成子进程,并在此子进程中再次执行shell 程序/bin/sh,而父进程那么继续等待。由于创立新进程的过程是通过完全复制父进程代码段和数据段的方式实现的,因此在首次使用fork()创立新进程init 时,为了确保新进程用户态堆栈没有进程0 的多余信息,要求进程0 在创立首个新进程之前不要使用用户态堆栈,也即要求任务0 不要调用函数。因此在main.c 主程序移动到任务
44、0 执行后,任务0 中的代码fork()不能以函数形式进行调用。程序中实现的方法是采用gcc 函数内嵌的形式来执行这个系统调用。通过申明一个内嵌inline函数,可以让gcc 把函数的代码集成到调用它的代码中。这会提高代码执行的速度,因为省去了函数调用的开销。另外,如果任何一个实际参数是一个常量,那么在编译时这些值就可能使得无需把内嵌函数的所有代码都包括进来而让代码也得到简化。另外,任务0 中的pause()也需要使用函数内嵌形式来定义。如果调度程序首先执行新创立的子进程init,那么pause()采用函数调用形式不会有什么问题。但是内核调度程序执行父进程进程0和子进程init 的次序是随机的
45、,在创立了init 后有可能首先会调度进程0 执行。因此pause()也必须采用宏定义来实现。对于Linux 来说,所有任务都是在用户模式运行的,包括很多系统应用程序,如shell 程序、网络子系统程序等。内核源代码lib/目录下的库文件就是专门为这里新创立的进程提供支持函数的。static void time_init(void)分析该子程用于读取取CMOS 时钟,并设置开机时间startup_time(秒)。struct tm time; /* 时间结构tm 定义在include/time.h 中 */ do time.tm_sec = CMOS_READ(0); /* 当前时间秒值均是B
46、CD 码值*/ time.tm_min = CMOS_READ(2); /* 当前分钟值 */ time.tm_hour = CMOS_READ(4); /* 当前小时值 */ time.tm_mday = CMOS_READ(7); /* 一月中的当天日期 */ time.tm_mon = CMOS_READ(8); /* 当前月份112*/ time.tm_year = CMOS_READ(9); /* 当前年份 */ while (time.tm_sec != CMOS_READ(0);CMOS 的访问速度很慢。为了减小时间误差,在读取了下面循环中所有数值后,假设此时CMOS 中秒值发生
47、了变化,那么就重新读取所有值。 BCD_TO_BIN(time.tm_sec); /* 转换成二进制数值 */ BCD_TO_BIN(time.tm_min); BCD_TO_BIN(time.tm_hour); BCD_TO_BIN(time.tm_mday); BCD_TO_BIN(time.tm_mon); BCD_TO_BIN(time.tm_year); time.tm_mon-; /* tm_mon 中月份范围是011 */startup_time = kernel_mktime(&time); /* 调用kernel/mktime.c 中函数,计算从1970年1月1日0时起到开机
48、当日经过的秒数,作为开机时间 */void main(void)分析main()函数中完成启动时对设备内核初始化,以及创立进程。此时中断仍被禁止着,做完必要的设置后就将其开启。下面这段代码用于保存:根设备号:ROOT_DEV; 高速缓存末端地址:buffer_memory_end;机器内存:memory_end;主内存开始地址 :main_memory_start; ROOT_DEV = ORIG_ROOT_DEV; /* ROOT_DEV 定义在fs/super.c */ drive_info = DRIVE_INFO; /* 复制0 x90080 处的硬盘参数表 */ memory_end
49、 = (120) + (EXT_MEM_K 16*1024*1024) /* 如果内存超过16Mb,那么按16Mb 计 */ memory_end = 16*1024*1024; if (memory_end 12*1024*1024) /* 如果内存12Mb,那么设置缓冲区末端=4Mb */ buffer_memory_end = 4*1024*1024; else if (memory_end 6*1024*1024) /* 否那么如果内存6Mb,那么设置缓冲区末端=2Mb */ buffer_memory_end = 2*1024*1024; else buffer_memory_end
50、 = 1*1024*1024; /* 否那么那么设置缓冲区末端=1Mb */ main_memory_start = buffer_memory_end; /* 主内存起始位置=缓冲区末端 */* 如果定义了内存虚拟盘,那么初始化虚拟盘。此时主内存将减少。参见kernel/blk_drv/ramdisk.c。*/#ifdef RAMDISKmain_memory_start += rd_init(main_memory_start, RAMDISK*1024);#endifmem_init(main_memory_start,memory_end); /* 内核进行所有方面的初始化工作 */t
51、rap_init(); /* 陷阱门硬件中断向量初始化。kernel/traps.c */blk_dev_init(); /* 块设备初始化。 kernel/blk_drv/ll_rw_blk.c*/chr_dev_init(); /* 字符设备初始化。 kernel/chr_drv/tty_io.c*/tty_init(); /* tty 初始化。 kernel/chr_drv/tty_io.c*/time_init(); /* 设置开机启动时间:startup_time */sched_init(); /* 调度程序初始化(加载了任务0 的tr,ldtr)kernel/sched.c*/b
52、uffer_init(buffer_memory_end); /* 缓冲管理初始化,建内存链表等。fs/buffer.c*/hd_init(); /* 硬盘初始化。 kernel/blk_drv/hd.c*/floppy_init(); /* 软驱初始化。 kernel/blk_drv/floppy.c*/sti(); /* 所有初始化工作都做完了,开启中断 */* 下面过程通过在堆栈中设置的参数,利用中断返回指令启动任务0 执行 */move_to_user_mode(); /* 移到用户模式下执行。include/asm/system.h*/if (!fork() init(); /* 在
53、新建的子进程任务1中执行 */main()流程图如图4.7: YN开始内存起始分配启动设备和程序初始化开启中断切换到用户模式fork()!=0调用init()初始化调用pause ()运行任务0结 束图4.7 main()流程图pause()分析代码开始以任务0 的身份运行。对于任何其它的任务,pause()将意味着我们必须等待收到一个信号才会返回就绪运行态,但任务0task0是唯一的例外情况,因为任务0 在任何空闲时间里都会被激活当没有其它任务在运行时,因此对于任务0 pause()仅意味着我们返回来查看是否有其它任务可以运行,如果没有的话我们就回到这里,一直循环执行pause()。paus
54、e()系统调用kernel/sched.c,144会把任务0 转换成可中断等待状态,再执行调度函数。但是调度函数只要发现系统中没有其它任务可以运行时就会切换到任务0,而不依赖于任务0 的状态。static int printf(const char *fmt, .)分析产生格式化信息并输出到标准输出设备stdout(1),这里是指屏幕上显示。参数*fmt指定输出将采用的格式。该子程序正好是vsprintf 如何使用的一个例子。该程序使用vsprintf()将格式化的字符串放入printbuf 缓冲区,然后用write()将缓冲区的内容输出到标准设备1-stdout。static int pri
55、ntf(const char *fmt, .)va_list args;int i;va_start(args, fmt);write(1,printbuf,i=vsprintf(printbuf, fmt, args);va_end(args);return i;void init(void)分析 argv0中的字符“-是传递给shell 程序sh 的一个标志。通过识别该标志,sh程序会作为登录shell 执行。其执行过程与在shell 提示符下执行sh 不太一样。static char * argv_rc = /bin/sh, NULL ; /* 调用执行程序时参数的字符串数组 */sta
56、tic char * envp_rc = HOME=/, NULL ; /* 调用执行程序时的环境字符串数组 */static char * argv = -/bin/sh,NULL ; /* 同上 */static char * envp = HOME=/usr/root, NULL ; 在main()中已经进行了系统初始化,包括内存管理、各种硬件设备和驱动程序。init()函数运行在任务0 第1 次创立的子进程任务1中。它首先对第一个将要执行的程序shell的环境进行初始化,然后加载该程序并执行之。setup(void *) &drive_info);/* 这是一个系统调用。用于读取硬盘参
57、数包括分区表信息并加载虚拟盘假设存在的话和安装根文件系统设备。该函数对应函数是sys_setup() */然后以读写访问方式翻开设备“/dev/tty0,它对应终端控制台。由于这是第一次翻开文件操作,因此产生的文件句柄号文件描述符肯定是0。该句柄是UNIX 类操作系统默认的控制台标准输入句柄stdin。这里把它以读和写的方式翻开是为了复制产生标准 输出写句柄stdout 和标准出错输出句柄stderr。(void) open(/dev/tty0,O_RDWR,0);(void) dup(0); /* 复制句柄,产生句柄1 号 - stdout 标准输出设备 */(void) dup(0); /
58、* 复制句柄,产生句柄2 号 - stderr 标准出错输出设备 */ 打印缓冲区块数和总字节数,每块1024 字节,以及主内存区空闲内存字节数。printf(%d buffers = %d bytes buffer spacenr,NR_BUFFERS,NR_BUFFERS*BLOCK_SIZE);printf(Free mem: %d bytesnr,memory_end-main_memory_start); fork()用于创立一个子进程(任务2)。对于被创立的子进程,fork()将返回0 值,对于原进程(父进程)那么返回子进程的进程号pid。该子进程关闭了句柄0(stdin) 、以只
59、读方式翻开/etc/rc 文件,并使用execve()函数将进程自身替换成/bin/sh 程序(即shell 程序),然后执行/bin/sh 程序。所带参数和环境变量分别由argv_rc 和envp_rc 数组给出。函数_exit()退出时的出错码1 操作未许可;2 - 文件或目录不存在。 if (!(pid=fork() close(0); if (open(/etc/rc,O_RDONLY,0) _exit(1); /* 如果翻开文件失败,那么退出(lib/_exit.c,10) */ execve(/bin/sh,argv_rc,envp_rc); /* 替换成/bin/sh 程序并执行 */ _exit(2); /* 假设execve()执行失败那么退出 */ 下面还是父进程1执行的语句。wait()等待子进程停止或终止,返回值应是子进程的进程号(pid)。这三句的作用是父进程等待子进程的结束。&i 是存放返回状态信息的位置。如果wait()返回值不等于子进程号,那么继续等待。if (pid0)while (pid != wait(&i) /* 空循环 */如果执行到这里,说明刚创立的子进程的执行已停止或终止了。下面
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 施肥机械操作工诚信品质知识考核试卷含答案
- 船舶特大型起重机驾驶工岗前安全素养考核试卷含答案
- 涡轮发动机修理工安全宣传强化考核试卷含答案
- 交通安全设施工岗前设备性能考核试卷含答案
- 石材开采工安全文明能力考核试卷含答案
- 石脑油加工工7S执行考核试卷含答案
- 液晶显示器件彩膜制造工安全操作强化考核试卷含答案
- 绝缘防爆工具制作工改进竞赛考核试卷含答案
- 大型物流项目的实施过程及应聘注册建设岗位注意事项解读
- 2026年大学大四(智能制造工程)数控智能制造基础测试题及答案
- 2026云南昆明巫家坝商业运营管理有限公司校园招聘8人考试参考题库及答案解析
- 紫菜养殖常见病虫害防治方法
- 药品市场营销技术
- (正式版)YST 1682-2024 镁冶炼行业绿色工厂评价要求
- 西门子变频器技术入门及实践- 课件 第5、6章 G120变频器的基本调试、G120变频器的操作与设置
- 部编人教版3三年级《道德与法治》下册电子课本课件
- 小学数学竞赛指导
- 通用电子嘉宾礼薄
- 机器人控制技术与实践 课程标准-教学大纲
- 室内无机防火涂料施工方案
- 安全意识培训课件 38、安全意识培训
评论
0/150
提交评论