《Linux内核分析》第三周 构建一个简单的Linux系统MenuOS

【刘蔚然 原创作品转载请注明出处 《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000

WEEK THREE(2.29——3.6)构造一个简单的Linux系统MenuOS

SECTION 1 Linux内核源代码简介

1.操作系统的两把宝剑(回顾上一讲)

  1. 中断上下文的切换——保存现场&恢复现场
  2. 进程上下文的切换

2.Linux内核源代码简介

  1. 打开内核源代码页面

    • arch/目录:支持不同CPU的源代码;其中的X86是重点
    • init/目录:内核启动相关的代码基本都在该目录中(比如main.c等)
      • start_kernel函数就相当于普通C程序的main函数
    • kernel/目录:Linux内核核心代码在kernel目录中
  2. README
    • 介绍了什么是Linux,Linux能够在哪些硬件上运行,如何安装内核源代码等

SECTION 2 构造一个简单的Linux系统MenuOS

1.init是第一个用户态进程

2.实验楼环境下的实验步骤

  1. 进入实验楼,输入$ cd LinuxKernel
  2. 其中,Linux-3.18.6是最新版本的Linux系统。rootfs是含有init函数的文件,生成的是rootfs.img
  3. 直接启动kernel。其中 -initrd(指明一个根文件系统) rootfs。我们尝试着输入命令help,可以看到这个系统也会给出有关help命令的参数及说明(虽然比较少哈)
  4. 启动gdb调试
    • 关于参数 - s,- S:
      • - S是指在CPU初始化之前(刚启动的时候)将其冻结
      • - s是指在1234这个端口上创建的gdb server
  5. 用水平分割另外打开一个shell窗口之后,进行调试
    • 输入gdb之后,gdb即被打开;
    • 加载Linux符号表;
    • 连接到刚刚被冻结的Linux系统;
    • 可以设置断点(break),格式为:break [函数名](此时系统还是被冻结而并没有启动的);
    • 设置完断点之后,输入c命令continue(继续执行),函数会停在断点处(如图);
    • 输入list指令之后,可以详细地查看函数停留的位置(比如断点在startkernel处的话停留在501行,而断点设置为restinit之后就停留在394行);

3. 简单分析一下start_kernel

分析一下Linux系统是如何启动的:

  1. 参考

  2. 代码节选(分析见注释) 不管分析内核的那一部分都会涉及到start_kernel;因为几乎所有的模块在启动的时候都是通过调用init函数来启动的
    500asmlinkage __visible void __init start_kernel(void)
    501{
    502 char *command_line;
    503 char *after_dashes;
    504
    505 /*
    506  * Need to run as early as possible, to initialize the
    507  * lockdep hash:
    508  */
    509 lockdep_init();
    510 set_task_stack_end_magic(&init_task);//init_task即手工创建的PCB,0号进程及最终的idle进程
    511 smp_setup_processor_id();
    512 debug_objects_early_init();
    513
    514 /*
    515  * Set up the the initial canary ASAP:
    516  */
    517 boot_init_stack_canary();
    518
    519 cgroup_init_early();
    520
    521 local_irq_disable();
    522 early_boot_irqs_disabled = true;
    523
    524/*
    525 * Interrupts are still disabled. Do necessary setups, then
    526 * enable them
    527 */
    528 boot_cpu_init();
    529 page_address_init();
    ……
    setup_log_buf(0);
    558 pidhash_init();
    559 vfs_caches_init_early();
    560 sort_main_extable();
    561 trap_init();//初始化中断向量。跟踪此函数,见下方解释
    562 mm_init();
    ……
    677 ftrace_init();
    678
    679 /* Do the rest non-__init‘ed, we‘re now alive */
    680 rest_init();//跟踪此函数,见下方解释
    681}
    
    • 点击追踪561行的trapinit函数,找到x86对应的trapinit函数,可以看到其中设置了很多断点。
    • setintrgate就是set interrupt(设置断点)的意思;从图中也可以看到,程序中设置了很多不同的硬件中断。其中,第839行的系统陷阱门就是我们重点关注的系统调用。
    • restinit中有kernelthread函数:
    • 此函数中有一个函数参数kernel_init:
    • run_init函数是系统的1号进程,用户态的第一个进程;
    • 创建了一号进程后,kernel_thread函数通过405行的kthreadd管理线程;
    • 由cpustartupentry(CPUHPONLINE);——>cpuidleloop();——>static void cpuidle_loop(void):
      • cpuidleloop中有一个while循环,当start_kernel启动之后,她就一直存在。当系统没有进场需要执行的时候就调度到idle进程。
  3. 总结
    • kernelthread是0号进程,它创建了1号进程kernelinit,以及它的一些服务的内核线程,这样整个系统及启动起来了;
    • 然后init进程会再启动一些进程。
    • 道生一,一生二,二生三,三生万物。系统就这样运行起来了
    • 根据CSDN中博客的系统阐述,来龙去脉更加深邃
      • inittask进程在Linux中属于一个比较特殊的进程,它是内核开发者人为制造出来的,而不是其他进程通过dofork来完成【这是系统在通电之后就会加载的数据结构struct】
      • Linux在无进程概念的情况下将一直从初始化部分的代码执行到startkernel,然后再到其最后一个函数调用restinit【这一点也是和视频中推的是一致的】
      • 从restinit开始,Linux开始产生进程,因为inittask是静态制造出来的,pid=0,它试图将从最早的汇编代码一直到startkernel的执行都纳入到inittask进程上下文中。在restinit函数中,内核将通过下面的代码产生第一个真正的进程(pid=1),也就是 kernelthread(kernelinit, NULL, CLONEFS | CLONE_SIGHAND);【0号进程创建1号进程】
      • 此时init_task的任务基本上已经完全结束了,它将沦落为一个idle task【很符合操作系统精简一切不必要支出的特征】
      • 事实上在更早前的schedinit()函数中,通过initidle(current, smpprocessorid())函数的调用就已经把inittask初始化成了一个idle task,initidle函数的第一个参数current就是&inittask,在initidle中将会把inittask加入到cpu的运行队列中,这样当运行队列中没有别的就绪进程时,inittask(也就是idle task)将会被调用,它的核心是一个while(1)循环,在循环中它将会调用schedule函数以便在运行队列中有新进程加入时切换到该新进程上。【这样就保证了系统可以随时迎接新进程而不至于卡壳】
时间: 2024-12-14 05:26:44

《Linux内核分析》第三周 构建一个简单的Linux系统MenuOS的相关文章

20135327郭皓--Linux内核分析第三周 构造一个简单的Linux系统MenuOS

Linux内核分析第三周  构造一个简单的Linux系统MenuOS 前提回顾 1.计算机是如何工作的三个法宝 1.存储程序计算机 2.函数调用堆栈 3.中断 2.操作系统的两把宝剑 中断上下文的切换 进程上下文的切换 第一讲  Linux内核源代码介绍 arch目录包括了所有和体系结构相关的核心代码.它下面的每一个子目录都代表一种Linux支持的体系结构,例如i386就是Intel CPU及与之相兼容体系结构的子目录.PC机一般都基于此目录. init目录包含核心的初始化代码(不是系统的引导代

linux内核分析 第三周 构造一个简单的Linux系统MenuOS

一.计算机的三个法宝 存储程序计算机,函数调用堆栈,中断二.操作系统的两把剑:1.中断上下文的切换,保存现场和恢复现场2.进程上下文的切换. 三.linux内核源代码的分析: ·arch/目录保存支持多种CPU类型的源代码,重点是x86·init目录:含有main.c,内核启动相关的代码基本都在init目录下·ipc目录:进程间的通信·kernel目录:有Linux内核的核心代码.四.构造一个简单的Linux系统 使用实验楼的虚拟机打开shell 1.cd LinuxKernel/2.qemu

Linux内核设计第三周——构造一个简单的Linux系统

Linux内核设计第三周 ——构造一个简单的Linux系统 一.知识点总结 计算机三个法宝: 存储程序计算机 函数调用堆栈 中断 操作系统两把宝剑: 中断上下文的切换 进程上下文的切换 linux内核源代码分析 arch/目录保存支持多种CPU类型的源代码 其中的关键目录包括:Documentation.drivers.firewall.fs(文件系统).include init目录:含有main.c,内核启动相关的代码基本都在init目录下 start_kernal()函数为启动函数,初始化内

第三周——构建一个简单的Linux系统MenuOS

[洪韶武 原创作品转载请注明出处 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 ] 第三周  构建一个简单的Linux系统MenuOS

《Linux内核分析》 第三节 构造一个简单的Linux系统

黄胤凯   原创作品转载请注明出处   <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000

LINUX内核分析第三周学习总结——构造一个简单的Linux系统MenuOS

LINUX内核分析第三周学习总结——构造一个简单的Linux系统MenuOS 黄韧(原创作品转载请注明出处) <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 回顾: [计算机三个法宝] 1)存储程序计算机 2)函数调用堆栈 3)中断 [操作系统两把宝剑] 1)中断上下文的切换:保存现场和恢复现场 2)进程上下文的切换 一.使用gdb跟踪调试内核从start_kernel到init进程启动 使用实验楼的虚拟机打开

Linux内核分析——第三周学习笔记20135308

第三周 构造一个简单的Linux系统MenuOS 计算机三个法宝: 1.存储程序计算机 2.函数调用堆栈 3.中断 操作系统两把宝剑: 1.中断上下文的切换:保存现场和恢复现场 2.进程上下文的切换 一.阅读Linux内核代码 本周我们要学习如何阅读Linux内核源代码,首先打开Lstest Stable Kernel:linux-3.18.6 arch/目录在Linux内核中占有相当庞大的代码量,因为Linux支持很多CPU,这个arch/x86目录下的代码是我们重要关注的代码 根目录中比较关

《Linux内核分析》MOOC课程 反汇编一个简单的C程序,分析汇编代码

一个简单c程序 分析一个简单的c程序 main.c 如下图: 用命令 gcc –S –o main.s main.c -m32编译成汇编文件.在汇编文件中有许多的虚指令并不会形成机器指令,为了使分析简单我们把大部分去掉: 得到如下图所示: 栈的介绍 APUE中指出每一个c程序,都有一个独立的地址空间,在内存中的典型布局如下: 对栈的操作和我们在数据结构中的栈的操作是类似的,ebp,esp(具体名称与cpu体系结构相关) 这两个寄存器直接与栈的操作相关. 栈地址是从高到低的方向分配的. 开始一个新

《Linux内核分析》MOOC课程 完成一个简单的时间片轮转多道程序内核代码

上一篇文章中介绍了一个进程执行的过程,分析了在调用子程序时栈的变化过程.本文介绍一下多进程的执行过程,当一个进程需要停下来等待某个条件或者cpu给它分配的时间片用完时需要切换给别的进程,在切换时首先会产生一个中断,然后cpu会执行相应的中断处理操作,比如一个重要的操作就是保护当前进程的栈和cpu寄存器的值,当cpu再次调度时可以恢复上一次状态继续执行下去. 按照mykernel上的步骤安装好程序,执行qemu -kernel arch/x86/boot/bzImage看到如下图: 执行的程序如下