一、实验过程

使用实验楼虚拟机打开shell

cd LinuxKernel/
qemu -kernel linux-3.18./arch/x86/boot/bzImage -initrd rootfs.img

内核启动进入 menu 程序。下面是用 gbd 来跟踪内核的启动过程:

gdb
(gdb)file linux-3.18./vmlinux # 在gdb界面中targe remote之前加载符号表
(gdb)target remote: # 建立gdb和gdbserver之间的连接,按c 让qemu上的Linux继续运行
(gdb)break start_kernel # 断点的设置可以在target remote之前,也可以在之后

这里的 -s和-S选项分别代表:
 -S freeze CPU at startup (use ’c’ to start execution)。

-s shorthand for -gdb tcp::1234 若不想使用1234端口,则可以使用-gdb tcp:xxxx来取代-s选项。

另开一个shell窗口,输入gdb。然后输入file linux-3.18.6/vmlinux,在gdb界面中targe remote之前加载符号表;
target remote:1234,建立gdb和gdbserver之间的连接,按c 让qemu上的Linux继续运行。

gdb
(gdb)file linux-3.18./vmlinux # 在gdb界面中targe remote之前加载符号表
(gdb)target remote: # 建立gdb和gdbserver之间的连接,按c 让qemu上的Linux继续运行
(gdb)break start_kernel # 断点的设置可以在target remote之前,也可以在之后

可以看到,内核启动在start_kernel进程处停住了,在这之前从Power On开始是很长的初始化过程。x86 CPU启动的第一个动作CS:EIP=FFFF:0000H(换算为物理地址为000FFFF0H,因为16位CPU有20根地址线),即BIOS程序的位置,在这个过程计算机只是单纯地执行二进制指令,此时并不存在真正的进程。然后是运行到第二个断点rest_init,这是start_kernel调用的最后一个函数。设置相关的断点,这里我们将断定设在函数break start_kernel以及rest_init处。继续程序并观察断点处代码。

二、start_kernel函数的执行过程

     系统进入start_kernel这个函数之前已经进行了一些最低限度的初始化,再往前研究就涉及很多硬件相关及编程语言了。内核即进入了C语言部分,它完成了内核的大部分初始化工作。实际上,可以将start_kernel函数看做内核的main函数。 这个函数在init/main.c:
asmlinkage __visible void __init start_kernel(void)
{
char *command_line;
char *after_dashes; /*
* Need to run as early as possible, to initialize the
* lockdep hash:
*/
lockdep_init();
set_task_stack_end_magic(&init_task);
smp_setup_processor_id();
debug_objects_early_init();

首先是调用 lockdep_init函数

void lockdep_init(void)
{
int i; /*
* Some architectures have their own start_kernel()
* code which calls lockdep_init(), while we also
* call lockdep_init() from the start_kernel() itself,
* and we want to initialize the hashes only once:
*/
if (lockdep_initialized)
return; for (i = ; i < CLASSHASH_SIZE; i++)
INIT_LIST_HEAD(classhash_table + i); for (i = ; i < CHAINHASH_SIZE; i++)
INIT_LIST_HEAD(chainhash_table + i); lockdep_initialized = ;
}

在start_kernel函数的最后调用了rest_init函数进行后续的初始化,生成了一号的进程。

static noinline void __init_refok rest_init(void)
{
int pid; rcu_scheduler_starting();
/*
* We need to spawn init first so that it obtains pid 1, however
* the init task will end up wanting to create kthreads, which, if
* we schedule it before we create kthreadd, will OOPS.
*/
kernel_thread(kernel_init, NULL, CLONE_FS);
numa_default_policy();
pid = kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES);

pid= kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES); 这行代码是创建一个干净内核线程,以便以后其它所有内核线程全部拷贝它,并由它来创建,这样达到更方便创建线程。

rcu_read_lock();
kthreadd_task = find_task_by_pid_ns(pid, &init_pid_ns);
rcu_read_unlock();
complete(&kthreadd_done);
/*
* The boot idle thread must execute schedule()
* at least once to get things moving:
*/
init_idle_bootup_task(current);

init_idle_bootup_task(current); 这行代码是初始化空闲进程的调度器,以便让空闲进程知道怎么样调度任务列表里的进程。current是指向当前IDLE任务的结构。

schedule_preempt_disabled();
/* Call into cpu_idle with preempt disabled */
cpu_startup_entry(CPUHP_ONLINE);

这行代码是调用进程调度函数schedule,主要初始化调度器可以切换回到空闲任务。并增加内核抢先计数。

三、总结

在本实验中,我分析了Linux系统的启动过程。最初执行的进程即是0号进程init_task,它是被静态产生的,内存栈的位置固定,执行一些初始化的工作。一直到start_kernel开始调用执行sched_init(),0号进程被init_idle(current, smp_processor_id())进程初始化成为一个idle task,变成上一次实验中的进程一样的,通过一个while循环不断执行,只要运行栈里没有别的进程它就执行,循环中不断检测运行栈里是否有其他进程并通过schedule函数进行调度。
     其中idle进程的产生为:idle是一个进程,其pid号为 0。其前身是系统创建的第一个进程,也是唯一一个没有通过fork()产生的进程。它在本实验中,具体是由init/main.c中start_kernel函数的set_task_stack_end_magic(&init_task)这一行开始实现的。其中的init_task就是手工创建的PCB,pid=0的进程,也就是最终的idle进程。
     而1号进程的产生为:而到了kernel_thread(kernel_init, NULL, CLONE_FS);则通过fork()建立了pid=1的1号进程,也叫init进程,它是第一个用户态进程,它会继续完成剩下的初始化工作,成为系统中的其他所有进程的祖先。而创建了1号进程后,随着init_idle_bootup_task(current);等函数的调用,0号进程就演变成了idle进程。而idle进程就是当系统没有进程需要执行的时候来调度用的。所以start_kernel里、rest_init里创建了0号进程,该进程在系统初始化时候建立,并在系统运行过程中一直存在;而由0号进程,生成了1号进程,以及之后的许许多多的进程。最后进入了cpu_startup_entry。这个其实就是调用了cpu_idle。其实里面就是在while循环里调用了0号进程。

虽然在实验中我出不体会了Linux系统的启动过程,但是对Linux系统的理解还不深入,需要进一步加强。

刘帅

原创作品转载请注明出处

《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000

Linux内核分析之跟踪分析Linux内核的启动过程的更多相关文章

  1. linux内核学习之三 跟踪分析内核的启动过程

    一   前期准备工作       1 搭建环境 1.1下载内核源代码并编译内核 创建目录,并进入该目录: 下载源码: 解压缩,并进入该目录:xz -d linux-3.18.6.tar.xz tar ...

  2. Linux第三周——跟踪分析内核的启动过程

    跟踪分析内核的启动过程实验 张潇月<Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 这周主要学习的是对内核 ...

  3. 走进Linux之systemd启动过程

    Linux系统的启动方式有点复杂,而且总是有需要优化的地方.传统的Linux系统启动过程主要由著名的init进程(也被称为SysV init启动系统)处理,而基于init的启动系统被认为有效率不足的问 ...

  4. Hive源码分析(1)——HiveServer2启动过程

    1.想了解HiveServer2的启动过程,则需要找到启动HiveServer2的入口,hive服务的启动命令为hive --service HiveServer2,通过分析$HIVE_HOME/bi ...

  5. Linux内核分析--理解进程调度时机、跟踪分析进程调度和进程切换的过程

    ID:fuchen1994 姓名:江军 作业要求: 理解Linux系统中进程调度的时机,可以在内核代码中搜索schedule()函数,看都是哪里调用了schedule(),判断我们课程内容中的总结是否 ...

  6. 跟踪分析Linux内核的启动过程--实验报告 分析 及知识重点

    跟踪分析Linux内核的启动过程 攥写人:杨光  学号:20135233 ( *原创作品转载请注明出处*) ( 学习课程:<Linux内核分析>MOOC课程http://mooc.stud ...

  7. 20135202闫佳歆--week3 跟踪分析Linux内核的启动过程--实验及总结

    实验三:跟踪分析Linux内核的启动过程 一.调试步骤如下: 使用gdb跟踪调试内核 qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd r ...

  8. Linux内核分析 实验三:跟踪分析Linux内核的启动过程

    贺邦 + 原创作品转载请注明出处 + <Linux内核分析>MOOC课程 http://mooc.study.163.com/course/USTC-1000029000 一. 实验过程 ...

  9. 跟踪分析Linux内核的启动过程小解

    跟踪分析Linux内核的启动过程 “20135224陈实  + <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029 ...

随机推荐

  1. linux——ssh服务

    SSH服务(TCP端口号22):安全的命令解释器 为客户机提供安全的Shell 环境,用于远程管理 SSH基于公钥加密(非对称加密)技术: 数据加密传输: 客户端和服务器的身份验证: 公钥 和 私钥 ...

  2. AngularJs 简单实现全选,多选操作

    很多时候我们在处理CURD(增删改查)的时候需要实现批量操作数据,这时候就必须使用多选操作. Angular 中实现如下(当然还有很多种比笔者写的更好的方法,这里只是简单的实现.) demo 演示地址 ...

  3. 2,SFDC 管理员篇 - 组织架构

    1,组织架构 Setup | Administrator | Manage User| Role 组织层级有三种模式,基于区域划分,基于产品划分,基于公司规模划分层级(目标客户群体划分层级或渠道划分) ...

  4. maven仓库介绍《本地仓库、远程仓库》

    在Maven中,任何一个依赖.插件或者项目构建的输出,都可以称之为构件.Maven在某个统一的位置存储所有项目的共享的构件,这个统一的位置,我们就称之为仓库.(仓库就是存放依赖和插件的地方)任何的构件 ...

  5. Windows上x86程序正常但x64程序崩溃问题

    先看下面代码: #include <stdio.h> #include <windows.h> #include <memory> class Test { pub ...

  6. 窗口 超类化 子类化 HOOK

    body { font-family: Bitstream Vera Sans Mono; font-size: 11pt; line-height: 1.5; } html, body { colo ...

  7. SQL Server开启READ_COMMITTED_SNAPSHOT

    --查询数据库状态 select name,user_access,user_access_desc,     snapshot_isolation_state,snapshot_isolation_ ...

  8. 【转】awk、nawk、mawk、gawk的简答介绍

    来自http://blog.sina.com.cn/s/blog_3d2d79aa0100h47h.html awk 是一种编程语言,用于在linux/unix下对文本和数据进行处理.数据可以来自标准 ...

  9. mybaits中xml文件大于号和小于号的处理方法

    1.转义字符 原符号 < <= > >= & ' " 替换符号 < <= > >= & &apos; " 2 ...

  10. Unity协程(Coroutine)管理类——TaskManager工具分享

    博客分类: Unity3D插件学习,工具分享 源码分析   Unity协程(Coroutine)管理类——TaskManager工具分享 By D.S.Qiu 尊重他人的劳动,支持原创,转载请注明出处 ...