Linux内核总结
Linux内核分析总结
一、博客地址
计算机是如何工作的:http://www.cnblogs.com/disturbia/p/5212724.html
操作系统是如何工作的:http://www.cnblogs.com/disturbia/p/5245004.html
构造一个简单的Linux系统MenuOS:http://www.cnblogs.com/disturbia/p/5268904.html
扒开系统调用的三层皮(上):http://www.cnblogs.com/disturbia/p/5283285.html
扒开系统调用的三层皮(下): http://www.cnblogs.com/disturbia/p/5311720.html
进程的描述和进程的创建: http://www.cnblogs.com/disturbia/p/5332980.html
可执行程序的装载 : http://www.cnblogs.com/disturbia/p/5360841.html
进程的切换和系统的一般执行过程 : http://www.cnblogs.com/disturbia/p/5388823.html
二、对Linux的理解
1.Linux学习中的一定要了解的知识
(1) Linux是大小些敏感的系统,用户的登录名和密码也是大小写敏感的; (2) 文件名最多可有256个字符,可以包含数字,点号“.”,下划线等;
(3) 文件名前面带“.”的在输入“ls”命令时一般不显示,这些文件是隐含文
件,可以使用命令“ls -a”来显示;
(4) 在配置文件里,以#打头的行是注释行,在修改配置文件的时候尽量不要删
除旧的设置,可以在原来的设置加上#变成注释行,总是在修改的地方对应的加入一些关于修改的注释,在以后的管理中获益很多的;
(5) 整个系统范围的设定一般放在目录/etc下;
2. 我的一些看法
八周的学习使我对Linux系统和网络管理有了进一步的认识。 上大学之前只接触过Windows操作系统,小时候最早接触的是Windows98操作系统,之后是Windows XP,上大学时开始接触Windows7.大概是受先入为主思想和自己知识欠缺状况的影响,一直以来,我都认为Windows操作系统是最完美的操作系统,但现在我开始明白,除了Windows系统之外还有Linux这个很完美的操作系统。
Linux是一种自由和开放操作系统。目前存在着许多不同的Linux,但它们都使用了Linux内核。Linux可安装在各种计算机硬件设备中,从手机、平板电脑、路由器和视频游戏控制台,到台式计算机、大型机和超级计算机。Linux是一个领先的操作系统,世界上运算最快的10台超级计算机运行的都是Linux操作系统。严格来讲,Linux这个词本身只表示Linux内核,但实际上人们已经习惯了用Linux来形容整个基于Linux内核,并且使用GNU 工程各种工具和数据库的操作系统。
Linux是芬兰大学生Linus Torvalds按照UNIX内核制作的一款有别于UNIX的系统。它的标志是一个名叫“Tux”的企鹅,之所以选择这个标志,是因为企鹅能在高寒酷冷的南极生存,具有顽强奋斗的精神,而这正是Linux的精神之一。
三、总结
(一)计算机是如何工作的
三个法宝:
- 存储程序计算机:所有计算机基础性的逻辑框架
- 堆栈:高级语言的起点,函数调用需要堆栈机制
- 中断机制:多道系统的基础,是计算机效率提升的关键
(二)操作系统是如何工作的
1.操作系统的两把剑:中断上下文和进程上下文的切换
2.C代码中嵌入汇编代码的写法:
__asm__(
汇编语句模板:
输入部分:
输出部分:
破坏描述部分:);
(三)构造一个简单的Linux系统MenuOS
1.Linux内核源代码简介
•arch:支持不同的CPU的源代码,其中的关键目录包括:Documentation、drivers、firewall、fs、include等
•documentation:文档目录
•fs:文件系统
•init:内核启动相关的代码main.c、Makefile等基本都在该目录中。(main.c中的start_ kernel函数是Linux内核启动的起点,即初始化内核的起点)
•kernel:Linux内核核心代码在kernel目录中。
•lib:公用的库文件
•mm:内存管理的代码
•scripts:与脚本相关的代码
•security:与安全相关的代码
•sound目录:与声音相关的代码
•tools目录:与工具相关的代码
•net:与网络相关的代码
•readme:介绍了什么是Linux,Linux能够在哪些硬件上运行,如何安装内核源代码等
•……
2.构造一个简单的Linux系统
-
启动MenuOS系统
cd LinuxKernel/ qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img
-
使用gdb跟踪调试内核
qemu -kernel linux-3.18.6
扒开系统调用的三层皮(上)
1.内核态:在高的执行级别下,代码可以执行特权指令,访问任意的物理地址,这时的CPU就对应内核态
2.用户态:在低级别的指令状态下,代码 只能在级别允许的特定范围内活动。在日常操作下,执行系统调用的方式是通过库函数,库函数封装系统调用,为用户提供接口以便直接使用。
3.在Linux下0级表示内核态,3级表示用户态。
4.内核态cs:eip的值是任意的,即可以访问所有的地址空间。用户态只能访问其中的一部分内存地址。
5.中断处理是从用户态进入内核态的主要方式,系统调用是一种特殊的中断。
6.系统调用的三层皮:xyz(API)、system_call(中断向量)、sys_xyz(中断服务程序)
7.操作系统为用户态进程与硬件设备进行交互提供的一组接口——系统调用
(五)扒开应用系统的三层皮(下)
1.给MenuOS增加time和time-asm命令
rm menu -rf //强制删除当前menu git clone http://github.com/mengning/menu.git //重新克隆新版本的menu cd menu ls make rootfs //rootfs是事先写好的一个脚本,自动编译自动生成根文件系统,同时自动启动MenuOS vi test.c //进入test.c文件 MenuConfig("getpid","Show Pid",Getpid); MenuConfig("getpid_asm","Show Pid(asm)",GetpidAsm); //在main函数中增加MenuConfig() int Getpid(int argc,char *argv[]); int GetpidAsm(int argc,char *argv[]); //增加对应的Getpid和GetpidAsm两个函数 make rootfs //编译
2.使用gdb跟踪系统调用内核函数sys_time
qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img -s -S gdb (gdb)file linux-3.18.6/vmlinux (gdb)target remote:1234 //连接到需要调试的MenuOS (gdb)b start_kernel //设置断点 (gdb)c //执行,可见程序在start_kernel处停下 list //可查看start_kernel的代码 (gdb)b sys_time //sys_time是13号系统调用对应的内核处理函数,在该函数处设置断点 (gdb)c //如果这里一直按n单步执行,会进入schedule函数。sys_time返回后进入汇编代码处理,gdb无法继续进行追踪 执行int 0x80后执行system call对应的代码(system call不是函数,是一段特殊的汇编代码,gdb还不能进行跟踪)。
(六)进程的描述和进程的创建
1.进程描述符task_struct数据结构
2.操作系统内核里有三大功能:
- 进程管理
- 内存管理
- 文件系统
3.进程的创建
- 1.进程的状态以及fork一个进程的用户态代码
- 2.fork系统调用在父进程和子进程各返回一次
- 3.TASK_RUNNING具体是就绪还是执行,要看系统当前的资源分配情况
- 4. TASK_ZOMBIE也叫僵尸进程
4.使用gdb跟踪创建新进程的过程
- 更新menu内核,然后删除test_fork.c以及test.c
- 编译内核,可以看到fork命令
- 启动gdb调试,并对主要的函数设置断点
(七)可执行程序的装载
1.可执行文件的创建——预处理、编译和链接
- shiyanlou:~/ $ cd Code [9:27:05]
- shiyanlou:Code/ $ vi hello.c [9:27:14]
- shiyanlou:Code/ $ gcc -E -o hello.cpp hello.c -m32 [9:34:55] //预处理,负责把include的文件包含进来及宏替换等工作
- shiyanlou:Code/ $ vi hello.cpp [9:35:04]
- shiyanlou:Code/ $ gcc -x cpp-output -S -o hello.s hello.cpp -m32 [9:35:21] //把预处理之后的程序编译成汇编代码
- shiyanlou:Code/ $ vi hello.s [9:35:28]
- shiyanlou:Code/ $ gcc -x assembler -c hello.s -o hello.o -m32 [9:35:58] //把汇编代码编译成目标代码
- shiyanlou:Code/ $ vi hello.o [9:38:44] //得到一个二进制的文件,不是一个可执行文件
- shiyanlou:Code/ $ gcc -o hello hello.o -m32 [9:39:37] //把hello.o链接成一个可执行文件
- shiyanlou:Code/ $ vi hello [9:39:44] //可执行文件,与hello.o一样是ELF格式的文件,使用共享库
- shiyanlou:Code/ $ gcc -o hello.static hello.o -m32 -static [9:40:21] //静态编译
- shiyanlou:Code/ $ ls -l [9:41:13]
- -rwxrwxr-x 1 shiyanlou shiyanlou 7292 3\u6708 23 09:39 hello
- -rw-rw-r-- 1 shiyanlou shiyanlou 64 3\u6708 23 09:30 hello.c
- -rw-rw-r-- 1 shiyanlou shiyanlou 17302 3\u6708 23 09:35 hello.cpp
- -rw-rw-r-- 1 shiyanlou shiyanlou 1020 3\u6708 23 09:38 hello.o
- -rw-rw-r-- 1 shiyanlou shiyanlou 470 3\u6708 23 09:35 hello.s
- -rwxrwxr-x 1 shiyanlou shiyanlou 733254 3\u6708 23 09:41 hello.static
2.ELF格式主要有三种文件
- 一个可重定位(reloacatable)文件保存着代码和适当的数据,用来和其他的object文件一起来创建一个可执行文件或者是一个共享文件。主要是.o文件
- 一个可执行(executable)文件保存着一个用来执行的程序;该文件指出了exec(BA_OS)如何来创建程序进程印象。
- 一个共享object文件保存着代码和合适的数据,用来被下面两个链接器链接:一个是连接编辑器,另一个是动态链接器。主要是.so文件
(八)进程的切换和系统的一般执行过程
1.不同类型的进程有不同的调度需求
- 第一种分类:
- I/O-bound:频繁地进行I/O,花费很多的时间等待I/O操作的完成
- CPU-bound:计算密集型,需要大量的CPU时间进行计算
- 第二种分类:
- 批处理进程
- 实时进程
- 交互式进程(shell)
2.进程调度的时机
-
中断处理过程(包括时钟中断、I/O中断、系统调用和异常)中,直接调用schedule(),或者返回用户态时根据need_resched标记调用schedule();
-
内核线程可以直接调用schedule()进行进程切换,也可以在中断处理过程中进行调度,也就是说内核线程作为一类的特殊的进程可以主动调度,也可以被动调度;
-
用户态进程无法实现主动调度,仅能通过陷入内核态后的某个时机点进行调度,即在中断处理过程中进行调度。
3.进程的切换
-
为了控制进程的执行,内核必须有能力挂起正在CPU上执行的进程,并恢复以前挂起的某个进程的执行,这叫做进程切换、任务切换、上下文切换;
-
挂起正在CPU上执行的进程,与中断时保存现场是不同的,中断前后是在同一个进程上下文中,只是由用户态转向内核态执行;
-
进程上下文包含了进程执行需要的所有信息
-
用户地址空间:包括程序代码,数据,用户堆栈等
-
控制信息:进程描述符,内核堆栈等
-
硬件上下文(注意中断也要保存硬件上下文只是保存的方法不同)
-
schedule()函数选择一个新的进程来运行,并调用context_switch进行上下文的切换,这个宏调用switch_to来进行关键上下文切换
4.Linux系统的一般执行过程分析
- 最一般的情况:正在运行的用户态进程X切换到运行用户态进程Y的过程
5.几种特殊情况
-
通过中断处理过程中的调度时机,用户态进程与内核线程之间互相切换,与最一般的情况非常类似,只是内核线程运行过程中发生中断没有进程用户态和内核态的转换;
-
内核线程主动调用schedule(),只有进程上下文的切换,没有发生中断上下文的切换,与最一般的情况略简略;
-
创建子进程的系统调用在子进程中的执行起点及返回用户态,如fork;next_ip=ret_from_fork
-
加载一个新的可执行程序后返回到用户态的情况,如execve;
6.内核与舞女
- 进程的地址空间一共有4G,其中0——3G是用户态可以访问,3G以上只有内核态可以访问
- 内核就是各种中断处理过程和内核线程的集合;
- 内核相当于出租车,可以为每一个“招手”的进程提供内核态到用户态的转换;
- 没有进程需要“承载”的时候,内核进入idle0号进程进行“空转”;
- 3G以上的部分就是这样的“出租车”,是所有进程共享的,在内核态部分切换的时候就比较容易