陈巧然 原创作品 转载请注明出处

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

实验步骤

登陆实验楼虚拟机http://www.shiyanlou.com/courses/195

打开shell终端,执行以下命令:

cd LinuxKernel/

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

执行完毕后会弹出QEMU窗口,输出Linux内核启动信息

 

启动成功后界面显示MenuOS命令提示符

 
系统支持三个命令:help、version、quit

 
 
使用gdb跟踪调试内核

打开shell终端,执行以下命令:

cd LinuxKernel/

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

关于-s和-S选项的说明:

-S freeze CPU at startup (use ’c’ to start execution) 在系统启动的时候冻结CPU,使用c键继续执行后续操作

-s shorthand for -gdb tcp::1234 打开远程调试端口,默认使用tcp协议1234端口,若不想使用1234端口,则可以使用-gdb tcp:xxxx来取代-s选项

 
 
打开另外一个shell终端,执行以下命令

gdb

(gdb)filelinux-3.18.6/vmlinux # 在gdb界面中targe remote之前加载符号表

 
 
(gdb)target remote:1234 # 建立gdb和gdbserver之间的连接,按c 让qemu上的Linux继续运行

 
 
(gdb)breakstart_kernel # 断点的设置可以在target remote之前,也可以在之后

 
 
按c键继续执行到start_kernel()函数

 
 
输入list命令查看start_kernel()函数代码

 
 
再设置一个断点rest_init

 
 
查看rest_init()函数代码

 
 
利用break设置断点,c继续执行,list查看函数代码可以方便调试Linux启动过程中用到的任何函数。

实验分析

本文以Linux3.19.1源代码为例分析。

分析./init/main.c源码文件start_kernel()函数

Linux内核启动代码大致分2部分:

一部分是硬件平台相关的,存放在./arch/目录下,以平台区分不同目录,比如x86平台就在./arch/x86/目录下,由汇编语言编写而成。

另一部分是硬件平台无关的,由C语言编写而成。

./init/main.c中的start_kernel()函数即是Linux内核启动过程由平台相关转为平台无关代码后第一个执行的函数,在这个函数中,Linux内核开始真正进入初始化阶段。

下面简单介绍其中的几个函数。(斜体字为源码,粗体字为解释)

/*

* Need to run as early as possible, to initialize the

* lockdep hash:

*/

lockdep_init();

lockdep是一个内核调试模块,用来检查内核互斥机制(尤其是自旋锁)潜在的死锁问题。

set_task_stack_end_magic(&init_task);

手工创建的PCB,0号进程即最终的idle进程。

/*

* Set up the the initial canary ASAP:

*/

boot_init_stack_canary();

canary值的是用于防止栈溢出攻击的堆栈的保护字。

trap_init();

对内核陷阱异常进行初始化。

mm_init();

初始化内核内存分配器。

/*

* Set up the scheduler prior starting any interrupts (such as the

* timer interrupt). Full topology setup happens at smp_init()

* time - but meanwhile we still have a functioning scheduler.

*/

sched_init();

初始化调度器数据结构,并创建运行队列。(一道作业题的答案:Linux源码start_kernel函数中调用进程调度初始化的是哪个函数?)

/* Do the rest non-__init'ed, we're now alive */

rest_init();

start_kernel()函数中调用的最后一个函数。

分析./init/main.c源码文件rest_init()函数

rest_init()函数的主要功能是创建并启动内核进程init,即第一个用户态进程。

int pid;

定义pid变量存放进程号

rcu_scheduler_starting();

RCU(Read-Copy Update)锁机制启动。

参考:Linux 2.6内核中新的锁机制--RCU

/*

* 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);

init进程在此时创建好了,但是现在还不能调度它。

numa_default_policy();

设定NUMA(Non-Uniform Memory Access Architecture)系统的内存访问策略为默认。

参考:Linux 的 NUMA 技术

pid = kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES);

创建kthreadd内核线程,它的作用是管理和调度其它内核线程。

rcu_read_lock();

kthreadd_task = find_task_by_pid_ns(pid, &init_pid_ns);

获取kthreadd的线程信息,获取完成说明kthreadd已经创建成功。

rcu_read_unlock();

complete(&kthreadd_done);

通过一个complete变量(kthreadd_done)来通知kernel_init线程。

实验总结:

当计算机系统加电(Power on PC)后,BIOS代码被调用执行,然后开始调用执行Linux内核初始化代码,在平台相关的汇编代码执行完毕后会跳转到start_kernel()函数,开始真正的内核初始化,其中init_task创建了0号进程,即最终的idle进程,随后rest_init()函数创建了init进程,即1号进程,以及kthreadd进程,即2号进程,系统开始正常工作了。

Linux内核设计第三周学习总结 跟踪分析Linux内核的启动过程的更多相关文章

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

    Linux内核设计第三周 ——构造一个简单的Linux系统 一.知识点总结 计算机三个法宝: 存储程序计算机 函数调用堆栈 中断 操作系统两把宝剑: 中断上下文的切换 进程上下文的切换 linux内核 ...

  2. Linux内核设计第八周 ——进程的切换和系统的一般执行过程

    Linux内核设计第八周 ——进程的切换和系统的一般执行过程 第一部分 知识点总结 第二部分 实验部分 1.配置实验环境,确保menu内核可以正常启动 2.进入gdb调试,在shedule和conte ...

  3. Linux内核设计第八周学习总结 理解进程调度时机跟踪分析进程调度与进程切换的过程

    陈巧然 原创作品转载请注明出处 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 一.视频内容 Linux ...

  4. Linux内核设计第五周学习总结 分析system_call中断处理过程

    陈巧然原创作品 转载请注明出处   <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 使用gdb跟踪分析一 ...

  5. Linux内核设计第七周学习总结 Linux内核如何装载和启动一个可执行程序

    陈巧然原创作品 转载请注明出处 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-100002900 实验目的 使用gdb跟踪s ...

  6. Linux内核设计第六周学习总结 分析Linux内核创建一个新进程的过程

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

  7. 《Linux内核分析》第三周学习报告

    <Linux内核分析>第三周学习报告                                    ——构造一个简单的Linux系统MenuOS 姓名:王玮怡  学号:201351 ...

  8. 《Linux内核分析》第三周学习笔记

    <Linux内核分析>第三周学习笔记 构造一个简单的Linux系统MenuOS 郭垚 原创作品转载请注明出处 <Linux内核分析>MOOC课程http://mooc.stud ...

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

    LINUX内核分析第三周学习总结——构造一个简单的Linux系统MenuOS 张忻(原创作品转载请注明出处) <Linux内核分析>MOOC课程http://mooc.study.163. ...

随机推荐

  1. PLSQL变量和类型,流程控制语句,集合

    ---PLSQL 调试授权 GRANT debug any procedure, debug connect session TO scott; --定义变量 declare part_number ...

  2. Java Monitoring&Troubleshooting Tools

    JDK Tools and Utilities Monitoring Tools You can use the following tools to monitor JVM performance ...

  3. openstack-r版(rocky)搭建基于centos7.4 的openstack swift对象存储服务 四

    openstack-r版(rocky)搭建基于centos7.4 的openstack swift对象存储服务 一 openstack-r版(rocky)搭建基于centos7.4 的openstac ...

  4. vs2017搭建linux c++开发环境

    最近一直在阅读ovs的源码,看到用户态代码的时候,需要对用户态的代码进行调试,一开始想直接使用linux中的GDB进行调试,但是ovs的工程太过于复杂,从网上找了些文章,发现vs2017能够支持lin ...

  5. 在GPT格式的硬盘上,使用EFI启动的方式,安装Win7 64位系统

    Win7 sp1 原装系统,用UltraISO(软碟通) 把U 盘制成Win7 安装的启动U盘 将bootmgfw.efi和shell.efi 加到已制好启动U盘的根目录,并在efi/boot/路径下 ...

  6. leetcode个人题解——#36 valid Sudoku

    思路题目里已经给出来了,判断是否是一个有效数独,只需满足以下三个条件: 1.同行元素不重复且1-9都有: 2.同列元素不重复且1-9都有: 3.每个粗线分隔的3*3的小九宫格元素不重复且1-9都有. ...

  7. ASP.NET Web API - 使用 Castle Windsor 依赖注入

    示例代码 项目启动时,创建依赖注入容器 定义一静态容器 IWindsorContainer private static IWindsorContainer _container; 在 Applica ...

  8. 20181120-8 Beta阶段第2周/共2周 Scrum立会报告+燃尽图 06

    此作业要求参见:https://edu.cnblogs.com/campus/nenu/2018fall/homework/2414 版本控制地址    [https://git.coding.net ...

  9. PSP1130

    PSP时间图: 类型 任务 开始时间 结束时间 净时间 中断时间 日期 开会 开会 16:17 16:50 33 0 20171027 开会 开会 17:00 17:22 22 0 20171028 ...

  10. 20172305 2018-2019-1 《Java软件结构与数据结构》第九周学习总结

    20172305 2018-2019-1 <Java软件结构与数据结构>第九周学习总结 教材学习内容总结 本周内容主要为书第十五章内容: 图(结点和结点之间的连接构成) 顶点:结点 边:结 ...