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系统

cd LinuxKernel/ 
qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img
  • 使用gdb跟踪调试内核

qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img -s -S

 

(四)扒开系统调用的三层皮(上)

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跟踪创建新进程的过程

  1. 更新menu内核,然后删除test_fork.c以及test.c
  2. 编译内核,可以看到fork命令
  3. 启动gdb调试,并对主要的函数设置断点

 

(七)可执行程序的装载

1.可执行文件的创建——预处理、编译和链接

 

  1. shiyanlou:~/ $ cd Code                                                [9:27:05]
  2. shiyanlou:Code/ $ vi hello.c                                          [9:27:14]
  3. shiyanlou:Code/ $ gcc -E -o hello.cpp hello.c -m32                    [9:34:55]    //预处理,负责把include的文件包含进来及宏替换等工作
  4. shiyanlou:Code/ $ vi hello.cpp                                        [9:35:04]
  5. shiyanlou:Code/ $ gcc -x cpp-output -S -o hello.s hello.cpp -m32      [9:35:21] //把预处理之后的程序编译成汇编代码
  6. shiyanlou:Code/ $ vi hello.s                                          [9:35:28]
  7. shiyanlou:Code/ $ gcc -x assembler -c hello.s -o hello.o -m32         [9:35:58]  //把汇编代码编译成目标代码
  8. shiyanlou:Code/ $ vi hello.o                                          [9:38:44]  //得到一个二进制的文件,不是一个可执行文件
  9. shiyanlou:Code/ $ gcc -o hello hello.o -m32                           [9:39:37]  //把hello.o链接成一个可执行文件
  10. shiyanlou:Code/ $ vi hello                                            [9:39:44]  //可执行文件,与hello.o一样是ELF格式的文件,使用共享库
  11. shiyanlou:Code/ $ gcc -o hello.static hello.o -m32 -static            [9:40:21]  //静态编译
  12. shiyanlou:Code/ $ ls -l                                               [9:41:13]
  13. -rwxrwxr-x 1 shiyanlou shiyanlou   7292  3\u6708 23 09:39 hello
  14. -rw-rw-r-- 1 shiyanlou shiyanlou     64  3\u6708 23 09:30 hello.c
  15. -rw-rw-r-- 1 shiyanlou shiyanlou  17302  3\u6708 23 09:35 hello.cpp
  16. -rw-rw-r-- 1 shiyanlou shiyanlou   1020  3\u6708 23 09:38 hello.o
  17. -rw-rw-r-- 1 shiyanlou shiyanlou    470  3\u6708 23 09:35 hello.s
  18. -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时间进行计算
  1. 第二种分类:
    • 批处理进程
    • 实时进程
    • 交互式进程(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.内核与舞女

  1. 进程的地址空间一共有4G,其中0——3G是用户态可以访问,3G以上只有内核态可以访问
  2. 内核就是各种中断处理过程和内核线程的集合;
  3. 内核相当于出租车,可以为每一个“招手”的进程提供内核态到用户态的转换;
  4. 没有进程需要“承载”的时候,内核进入idle0号进程进行“空转”;
  5. 3G以上的部分就是这样的“出租车”,是所有进程共享的,在内核态部分切换的时候就比较容易

 

posted on 2016-04-20 20:03  20135232  阅读(295)  评论(0编辑  收藏  举报