Linux内核的启动过程分析

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

一、实验目的及要求:

  • 使用gdb跟踪调试内核从start_kernel到init进程启动

  • 详细分析从start_kernel到init进程启动的过程并结合实验截图撰写一篇署名博客,并在博客文章中注明“真实姓名(与最后申请证书的姓名务必一致) + 原创作品转载请注明出处 + 《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000 ”,博客内容的具体要求如下:

    • 题目自拟,内容围绕Linux内核的启动过程,即从start_kernel到init进程启动;

    • 博客中需要使用实验截图

    • 博客内容中需要仔细分析start_kernel函数的执行过程

    • 总结部分需要阐明自己对“Linux系统启动过程”的理解,尤其是idle进程、1号进程是怎么来的。

  • 3)请提交博客文章URL到网易云课堂MOOC平台Linux内核分析MOOC课程,编辑成一个链接可以直接点击打开。  

二、实验步骤(含实验楼截图):

  1、登陆实验楼虚拟机

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

    cd LinuxKernel/

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

    

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

  2、使用gdb跟踪调试内核

  执行以下命令:

  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)file linux-3.18.6/vmlinux # 在gdb界面中targe remote之前加载符号表

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

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

  

  (不知道为什么没有找到文件目录。。)

 

三、start_kernel函数的执行过程分析:

asmlinkage void __init start_kernel(void)

{
 char * command_line;
 extern struct kernel_param __start___param[], __stop___param[];
/*
 * Interrupts are still disabled. Do necessary setups, then
 * enable them
 */
 lock_kernel();
如果内核配置成支持抢占,那么在这里禁止抢占,将0号进程的init_thread_info.preempt_count加1;
如果配置成不支持抢占,那么内核全局自选锁kernel_flag上锁。
 page_address_init();
10版本的ARM部分,没有支持高端内存相关代码,空函数。
 printk(linux_banner);
将linux_banner的内容打印到log_buf缓冲区中。
 setup_arch(&command_line);
函数原型在arch/arm/kernel/setup.c中
根据处理器、硬件平台具体型号设置系统。解析Linux系统命令行,设置0号进程(swapper进程)的内存描述结构init_mm,系统内存管理初始化,统计并注册系统各种资源,其他项目的初始化。
 setup_per_cpu_areas();
为系统中每个处理器的per_cpu变量申请空间。
/*
  * Mark the boot cpu "online" so that it can call console drivers in
  * printk() and can access its per-cpu storage.
  */
 smp_prepare_boot_cpu();
/*
  * 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();
初始化每个处理器的可运行进程队列,设置系统初始化进程即0号进程。
 build_all_zonelists();
建立系统内存页区(zone)链表。
 page_alloc_init();
 printk("Kernel command line: %s\n", saved_command_line);
 parse_early_param();
解析早期格式内核参数。
 parse_args("Booting kernel", command_line, __start___param,
     __stop___param - __start___param,
     &unknown_bootoption);
解析新格式内核参数。
 sort_main_extable();
将放在__start__ex_table到__stop__ex_table之间的*(__ex_table)区中的struct exception_table_entry型全局结构变量按insn成员变量值从小到大排序,即将可能导致缺页异常的指令按其指令二进制代码值从小到大排序。
 trap_init();
把放在.Lcvectors处的系统8个意外的入口跳转指令搬到高端中断向量0xffff0000处,再将从__stubs_start到__stubs_end之间的各种意外初始处理代码搬到0xffff0200处。刷新0xffff0000处1页范围的指令cache,将DOMAIN_USER的访问权限由DOMAIN_MANAGER权限改设置成DOMAIN_CLIENT权限。
 rcu_init();
初始化当前CPU的读、复制、更新数据结构(struct rcu_data)全局变量per_cpu_rcu_data和per_cpu_rcu_bh_data。
 init_IRQ();
初始化系统中支持的最大可能中断数的中断描述结构struct irqdesc变量数组irq_desc[NR_IRQS],把每个结构变量irq_desc[n]都初始化为预先定义好的坏中断描述结构变量bad_irq_desc,并初始化该中断的连表表头成员结构变量pend.
 pidhash_init();
设置系统中每种pid hash表中的hash链表数的移位值全局变量pidhash_shift,将pidhash_shift设置为min(12);分别为每种hash表的连续hash链表表头结构空间申请内存,把申请到的内存虚拟基址分别传给pid_hash[n](n=0~3),并将每种hash表中的每个hash链表表头结构struct hlist_head中的first成员指针设置成NULL
 init_timers();
初始化当前出处理器的时间向量基本结构struct tvec_t_base_s全局变量per_cpu_tvec_bases,初始化per_cpu_tvec_bases的自旋锁成员变量lock。
 softirq_init();
设置系统小任务软件中断行为函数描述结构变量softirq_vec[TASKLET_SOFTIRQ(=6)],将softirq_vec[6]的行动函数指针action指向tasklet_action()函数,参数指针设置为NULL.
 time_init();
检查系统定时器描述结构struct sys_timer全局变量system_timer是否为空,如果是将其指向dummy_gettimeoffset()函数。
/*
  * HACK ALERT! This is early. We're enabling the console before
  * we've done PCI setups etc, and console_init() must be aware of
  * this. But we do want output early, in case something goes wrong.
  */
 console_init();
初始化系统的控制台结构,该函数执行后调用printk()函数将log_buf中符合打印级别要求的系统信息打印到控制台上。
 if (panic_later)
  panic(panic_later, panic_param);
 profile_init();
对系统剖析作相关初始化,系统剖析用于系统调用。
 local_irq_enable();
将处理器的当前系统状态寄存器CPSR的第7位清0,使能IRQ中断。
#ifdef CONFIG_BLK_DEV_INITRD
 if (initrd_start && !initrd_below_start_ok &&
   initrd_start < min_low_pfn << PAGE_SHIFT) {
  printk(KERN_CRIT "initrd overwritten (0x%08lx < 0x%08lx) - "
      "disabling it.\n",initrd_start,min_low_pfn << PAGE_SHIFT);
  initrd_start = 0;
 }
#endif
 vfs_caches_init_early();
 mem_init();
该函数执行完后不能再用像alloc_bootmem()、alloc_bootmem_low()、alloc_bootmem_pages()等申请低端内存的函数来申请内存,也就不能申请大块的连续物理内存了。
 kmem_cache_init();
执行高速缓存内存管理即slab分配器相关初始化。
 numa_policy_init();
 if (late_time_init)
  late_time_init();
 calibrate_delay();
计算机系统的BogMIPS数值,即处理器每秒钟执行的指令数。
 pidmap_init();
 pgtable_cache_init();
 prio_tree_init();
初始化无符号长整型全局数组index_bits_to_maxindex[BITS_PER_LONG]的每个组员,将每个组员index_bits_to_maxindex[n]设置成-1,将最后的index_bits_to_maxindex[BITS_PER_LONG-1]设置成~0UL。
 anon_vma_init();
该函数调用kmem_cache_create()函数,为匿名虚拟内存区域链表结构struct anon_vma创建高速缓存内存描述结构kmem_cache_t变量,为该变量命名为“anon_vma",其对象的构造函数指针指向void anon_vma_ctor(void *data,kmem_cache_t *cachep,unsigned long flags)函数,析构函数指针空,将创建的kmem_cache_t结构变量地址传给全局指针anon_vma_chachep。
#ifdef CONFIG_X86
 if (efi_enabled)
  efi_enter_virtual_mode();
#endif
 fork_init(num_physpages);
执行进程创建相关初始化。
 proc_caches_init();
 buffer_init();
调用 kmem_cache_create("buffer_head", sizeof(struct buffer_head), 0, SLAB_PANIC, init_buffer_head, NULL)函数为缓冲区描述结构struct buffer_head创建高速缓存内存描述结构kmem_cache_t变量。
 unnamed_dev_init();
调用并返回idr_init(&unnamed_dev_idr)函数。
 security_init();
打印”安全架构v1.0.0被初始化“。如果没有定义系统哑元安全操作函数组结构全局变量dummy_security_ops,打印错误信息,返回I/O错误。
 vfs_caches_init(num_physpages);
 radix_tree_init();
 signals_init();
调用kmem_cache_create("sigqueue", sizeof(struct sigqueue), __alignof__(struct sigqueue), SLAB_PANIC, NULL, NULL)函数为信号队列结构struct sigqueue创建高速缓存内存描述结构kmem_cache_t变量,名字叫”sigqueue“,不要求其对象按处理器硬件cache line大小对齐,没有定义其对象的构造和析构函数,将创建号的kmem_cache_t结构变量的地址传给全局指针sigqueue_cachep。
 /* rootfs populating might need page-writeback */
 page_writeback_init();
统计系统中所有内存节点的通用(NORMAL)内存页区中高页数水印值页数之外的额外内存总页数之和传给buffer_pages。
#ifdef CONFIG_PROC_FS
 proc_root_init();
只有在系统支持proc文件系统即配置了CONFIG_PROC_FS选项时才被调用。
#endif
 check_bugs();
acpi_early_init(); /* before LAPIC and SMP init */
/* Do the rest non-__init'ed, we're now alive */
 rest_init();
该函数创建init()内核进程即1号进程,然后是系统启动进程即0号进程空闲。
}

 

四、实验总结:

   当计算机电源启动,BIOS代码被调用执行,然后开始调用执行Linux内核初始化代码,在平台相关的汇编代码

执行完毕后会跳转到start_kernel()函数,开始真正的内核初始化,其中init_task创建了0号进程,即最终的idle进程,

随后rest_init()函数创建了init进程,即1号进程,以及kthreadd进程,即2号进程,系统开始正式对外工作了。

 

转载于:https://www.cnblogs.com/qindingtao/p/5268143.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/375004.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

四则运算2+psp0

程序要求&#xff1a; 1.题目避免重复 2.可定制&#xff08;数量\打印方式&#xff09; 3.可以一下控制参数 ① 是否有乘除法 ② 是否有括号&#xff08;最多支持十个数参与运算&#xff09; ③ 数值范围 ④加减有无负数 ⑤除法有无余数 分析&#xff1a;① 如果是两个数…

浅析Kerberos原理,及其应用和管理

文章作者&#xff1a;luxianghao 文章来源&#xff1a;http://www.cnblogs.com/luxianghao/p/5269739.html 转载请注明&#xff0c;谢谢合作。 免责声明&#xff1a;文章内容仅代表个人观点&#xff0c;如有不当&#xff0c;欢迎指正。 --- 一&#xff0c;引言 Kerberos简单来…

asp.net 导出Excel

asp.net 导出Excel 分享一个asp.net 导出假Excel代码。优点&#xff0c;不用借助于任何插件比如&#xff08;NPOI&#xff09;,复制代码&#xff0c;修改grid.DataSource直接导出。 先看导出后的效果图 1 System.Web.UI.WebControls.DataGrid grid new DataGrid();2 …

bzoj 2300 动态维护上凸壳(不支持删除)

新技能GET。 用set保存点&#xff0c;然后只需要找前趋和后继就可以动态维护了。 1 /**************************************************************2 Problem: 23003 User: idy0024 Language: C5 Result: Accepted6 Time:556 ms7 Memory:4824 kb8 …

《Linux内核分析》 第四节 扒开系统调用的三层皮(上)

黄胤凯 原创作品转载请注明出处 《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000 一、视频学习 1.系统调用的三层皮&#xff1a;xyz system_call sys_xyz 对应的是API&#xff0c;中断向量对应的中断服务程序&#xff0c;系统调用服务程…

OllyDBG反汇编快速找到程序入口一点分析

出处&#xff1a;http://hi.baidu.com/0soul/blog/item/b62f8f08c2c3c42c6b60fbbe.html 先声明下&#xff1a;这个和脱壳没关系&#xff0c;不是找壳里面的程序入口哦&#xff0c;只是程序本身的入口&#xff0c;个别朋友不要误会哈。其实这个应该是基础&#xff0c;但我经常找…

PHP计划任务之关闭浏览器后仍然继续执行的函数

函数名称&#xff1a;ignore_user_abort 本函数配置或取得使用端连接中断后&#xff0c;PHP 程序是否仍继续执行。默认值为中断连接后就停止执行。在 PHP 配置文件中 (php3.ini/php.ini) 的 ignore_user_abort 选项就是配置处。本功能在 PHP 3.0.7 版之后才开始提供。 官方说明…

记对一个key file crackme的破解

crackme下载地址: http://kssd.pediy.com/tutorial/exercise/section04/chap6-1-4-03.zip ------------------------------------------------------------------------------------------------------------------------------- ----------------------------------------…

Chrome/Chromium HTML5 video 视频播放硬件加速

Chromium站点上有个大致的框图。描写叙述了Chromium的video在各个平台 - 包含Android - 上是怎样使用硬件资源来做视频编解码加速的&#xff1a; 而依据Android Kitkat上的Chromium代码分析&#xff0c;HTML5 video播放硬件加速&#xff0c;终于是使用MediaCodec.java来利用本地…

.net mvc结合微软提供的FormsAuthenticationTicket登陆

一、Web.config <system.web><compilation debug"true" targetFramework"4.5" /><httpRuntime targetFramework"4.5" /><authentication mode"Forms"><forms loginUrl"/Sign/SignIn" defaultUrl…

JS 操作 radio input(cc问卷管理)

1、选中特定的单选按钮 function showDetail(content){$("input[name^radio]").removeAttr("checked");for(var i0;i<content.length;i){$("#radio"(i1)content.substr(i,1)).attr("checked","checked");} }2、手动添加问…

Apache Lucene拼写检查器的“您是不是要”功能

Google的“您是不是要”功能 在上一篇文章中对Lucene进行了介绍之后 &#xff0c;现在是时候提高它&#xff0c;创建一个更复杂的应用程序了。 您肯定最熟悉Google的“您是不是要”功能&#xff08;其他搜索引擎也支持此功能&#xff09;。 这是一个例子&#xff1a; Lucene …

Android-做个性化的进度条

1.案例效果图 2.准备素材 progress1.png(78*78) progress2.png(78*78) 3.原理 采用一张图片作为ProgressBar的背景图片(一般采用颜色比较浅的)。另一张是进度条的图片(一般采用颜色比较深的图片)。进度在滚动时&#xff1a;进度图片逐步显示&#xff0c;背景图片逐…

(笔试题)二进制1的个数相同的距离最小数

题目&#xff1a; 输入&#xff1a;整数A输出&#xff1a;整数B条件&#xff1a;A和B的二进制1的个数相同&#xff0c;且A和B之间的距离|A-B|最小。思路&#xff1a; 题目没有说明整数类型&#xff0c;这里认为是带符号的整数&#xff0c;即区分正负数。 根据题意&#xff0c;A…

hadoop5--mapreduce设计模式

运行结果附图 本节课程主要内容为学习MapReduc设计模式&#xff0c;并编写java程序对日志文件进行处理。 课本上介绍的MapReduce的设计模式主要包含:计数(Counting),分类(Classification),过滤处理(Filtering),排序(Sorting),去重计数(Distinct Counting),相关计数(Cross-Corre…

jqGrid,REST,AJAX和Spring MVC集成

两年多以前&#xff0c;我写了一篇关于两个如何在Struts2中实现优雅的CRUD的文章。 实际上&#xff0c;我必须就该主题写两篇文章&#xff0c;因为该主题如此广泛。 今天&#xff0c;我采用了一套更为流行的&#xff0c;完善的框架和库&#xff0c;采用了更为轻量级的现代方法。…

Java-马士兵设计模式学习笔记-代理模式--动态代理 修改成可以代理任意接口

一、概述 1.目标&#xff1a;把Proxy修改成可以代理任意接口及其任意方法 2.思路&#xff1a; (1)代理任意接口&#xff1a;把接口类型作为参数传给Proxy的newProxyInstance(Class interfze) (2)代理任意方法&#xff1a;用interfze.getMethods()取出所有方法&#xff0c;拼接实…

C语言5-7习题

本题要求实现一个函数&#xff0c;用下列公式求cos(x)的近似值&#xff0c;精确到最后一项的绝对值小于e&#xff1a; #include <stdio.h> #include <math.h>double funcos( double e, double x );int main() { double e, x;scanf("%lf %lf", &…

BC div2补题以及 复习模除 逆元__BestCoder Round #78 (div.2)

第一题没话说 智商欠费 加老柴辅导终于过了 需要在意的是数据范围为2的63次方-1 三个数相加肯定爆了 四边形的定义  任意边小于其余三边之和 换句话说就是  最长边小于其余三边之和 这样的话问题转化为 最长边依次减其余三边的结果是否小于等于0 还有一点是题目出现0边 即最…