《Linux内核分析》第三周学习笔记
《Linux内核分析》第三周学习笔记 构造一个简单的Linux系统MenuOS
郭垚 原创作品转载请注明出处 《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000
一、Linux内核源代码简介
1.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能够在哪些硬件上运行,如何安装内核源代码等
- ……
二、构造一个简单的Linux系统
2.1 构造一个简单的Linux系统MenuOS
cd LinuxKernel/
qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img
- qemu命令是模拟内核启动虚拟机,启动Linux内核需要三个参数(kernel、initrd、root所在的分区和目录),执行的第一个文件是init。
- -kernel指明内核文件名
- -initrd指明根文件系统,启动其中的init文件。(menuOS源代码编译->init->rootfs.img)其中rootfs.img 为根文件系统,目前只支持help、version、quit功能。
- 启动过程为:启动内核->启动init->启动进程

三、跟踪调试Linux内核的启动过程
3.1 使用gdb跟踪调试Linux内核的方法
使用带参数命令启动MenuOS,使得系统在刚启动时,暂停等待调试器跟踪执行。
qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img -s -S
# -S 在CPU初始化之前冻结CPU
# -s 1234端口上创建一个tcp接口。若不想使用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
# 在start_kernel函数入口处设置断点
(gdb)c
# 使得系统运行到start_kernel处停住
(gdb)list
# 显示当前行所在位置上下的代码
注:编译的目的就是生成自带内核中没有的符号表。符号是全局变量、函数名,符号表即名字与地址一一对应。
使用gdb进行调试:

在start_kernal设置断点

3.2 简单分析start_kernel
在init目录下的main.c包含start_ kernel函数。基本上所有模块启动时都需要调用init中的start_kernel函数来进行初始化。
- 全局变量init_ task:手工创建的PCB,0号进程
start_ kernel函数分析
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);
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();
530 pr_notice("%s", linux_banner);
531 setup_arch(&command_line);
532 mm_init_cpumask(&init_mm);
533 setup_command_line(command_line);
534 setup_nr_cpu_ids();
535 setup_per_cpu_areas();
536 smp_prepare_boot_cpu(); /* arch-specific boot-cpu hooks */
537
538 build_all_zonelists(NULL, NULL);
539 page_alloc_init();
540
541 pr_notice("Kernel command line: %s\n", boot_command_line);
542 parse_early_param();
543 after_dashes = parse_args("Booting kernel",
544 static_command_line, __start___param,
545 __stop___param - __start___param,
546 -1, -1, &unknown_bootoption);
547 if (!IS_ERR_OR_NULL(after_dashes))
548 parse_args("Setting init args", after_dashes, NULL, 0, -1, -1,
549 set_init_arg);
550
551 jump_label_init();
552
553 /*
554 * These use large bootmem allocations and must precede
555 * kmem_cache_init()
556 */
557 setup_log_buf(0);
558 pidhash_init();
559 vfs_caches_init_early();
560 sort_main_extable();
561 trap_init(); //初始化中断向量
562 mm_init(); //初始化内存管理模块
563
564 /*
565 * Set up the scheduler prior starting any interrupts (such as the
566 * timer interrupt). Full topology setup happens at smp_init()
567 * time - but meanwhile we still have a functioning scheduler.
568 */
569 sched_init(); //初始化调度模块
570 /*
571 * Disable preemption - early bootup scheduling is extremely
572 * fragile until we cpu_idle() for the first time.
573 */
574 preempt_disable(); //禁止抢占
575 if (WARN(!irqs_disabled(),
576 "Interrupts were enabled *very* early, fixing it\n"))
577 local_irq_disable();
578 idr_init_cache();
579 rcu_init();
580 context_tracking_init();
581 radix_tree_init();
582 /* init some links before init_ISA_irqs() */
583 early_irq_init();
584 init_IRQ();
585 tick_init();
586 rcu_init_nohz();
587 init_timers();
588 hrtimers_init();
589 softirq_init();
590 timekeeping_init();
591 time_init();
592 sched_clock_postinit();
593 perf_event_init();
594 profile_init();
595 call_function_init();
596 WARN(!irqs_disabled(), "Interrupts were enabled early\n");
597 early_boot_irqs_disabled = false;
598 local_irq_enable();
599
600 kmem_cache_init_late();
601
602 /*
603 * HACK ALERT! This is early. We're enabling the console before
604 * we've done PCI setups etc, and console_init() must be aware of
605 * this. But we do want output early, in case something goes wrong.
606 */
607 console_init(); //初始化控制模块
608 if (panic_later)
609 panic("Too many boot %s vars at `%s'", panic_later,
610 panic_param);
611
612 lockdep_info();
613
614 /*
615 * Need to run this when irqs are enabled, because it wants
616 * to self-test [hard/soft]-irqs on/off lock inversion bugs
617 * too:
618 */
619 locking_selftest();
620
621#ifdef CONFIG_BLK_DEV_INITRD
622 if (initrd_start && !initrd_below_start_ok &&
623 page_to_pfn(virt_to_page((void *)initrd_start)) < min_low_pfn) {
624 pr_crit("initrd overwritten (0x%08lx < 0x%08lx) - disabling it.\n",
625 page_to_pfn(virt_to_page((void *)initrd_start)),
626 min_low_pfn);
627 initrd_start = 0;
628 }
629#endif
630 page_cgroup_init();
631 debug_objects_mem_init();
632 kmemleak_init();
633 setup_per_cpu_pageset();
634 numa_policy_init();
635 if (late_time_init)
636 late_time_init();
637 sched_clock_init();
638 calibrate_delay();
639 pidmap_init();
640 anon_vma_init();
641 acpi_early_init();
642#ifdef CONFIG_X86
643 if (efi_enabled(EFI_RUNTIME_SERVICES))
644 efi_enter_virtual_mode();
645#endif
646#ifdef CONFIG_X86_ESPFIX64
647 /* Should be run before the first non-init thread is created */
648 init_espfix_bsp();
649#endif
650 thread_info_cache_init();
651 cred_init();
652 fork_init(totalram_pages);
653 proc_caches_init();
654 buffer_init();
655 key_init();
656 security_init();
657 dbg_late_init();
658 vfs_caches_init(totalram_pages);
659 signals_init();
660 /* rootfs populating might need page-writeback */
661 page_writeback_init();
662 proc_root_init();
663 cgroup_init();
664 cpuset_init();
665 taskstats_init_early();
666 delayacct_init();
667
668 check_bugs();
669
670 sfi_init_late();
671
672 if (efi_enabled(EFI_RUNTIME_SERVICES)) {
673 efi_late_init();
674 efi_free_boot_services();
675 }
676
677 ftrace_init();
678
679 /* Do the rest non-__init'ed, we're now alive */
680 rest_init(); //初始化其他模块
681}
注:rest_ init()函数
- rest_ init()调用了kernel_ thread(kernel_ init, NULL, CLONE_ FS); 然后又继续调用run_ init_ process(ramdisk_ execute_ command); run_ init_ process是1号进程,即第一个用户态进程。
创建进程:pid = kernel_ thread(kthreadd, NULL, CLONE_ FS | CLONE_FILES);其中kthreadd是被创建的内核线程,用来管理资源。
rest_ init的各部分启动完毕后,调用static void cpu_ idle_loop(void);该函数一直在循环,是0号进程。当系统没有进程需要执行时就调度idle进程。
四、总结
rest_ init实际上是start_ kernel在内核启动时就一直存在的,即0号进程。然后0号进程创建1号进程init,还有其他服务的内核线程,这样内核就能启动起来。
再附同学的精辟总结:道生一(start_ kernel....cpu_idle),一生二(kernel _ init和kthreadd),二生三(即前面0、1和2三个进程),三生万物(1号进程是所有用户态进程的祖先,2号进程是所有内核线程的祖先)
《Linux内核分析》第三周学习笔记的更多相关文章
- Linux内核分析第三周学习笔记
linux内核分析第三周学习笔记 标签(空格分隔): 20135328陈都 陈都 原创作品转载请注明出处 <Linux内核分析>MOOC课程http://mooc.study.163.co ...
- 20135320赵瀚青LINUX内核分析第三周学习笔记
赵瀚青原创作品转载请注明出处<Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 概述 本周是学习的主要是构造 ...
- Linux内核分析——第三周学习笔记
20135313吴子怡.北京电子科技学院 chapter1 知识点梳理 一.Linux内核源代码简介 (视频中对目录下的文件进行了简介,记录如下) arch目录 占有相当庞大的空间 arch/x86目 ...
- Linux内核分析——第三周学习笔记20135308
第三周 构造一个简单的Linux系统MenuOS 计算机三个法宝: 1.存储程序计算机 2.函数调用堆栈 3.中断 操作系统两把宝剑: 1.中断上下文的切换:保存现场和恢复现场 2.进程上下文的切换 ...
- 《Linux内核分析》第二周学习笔记
<Linux内核分析>第二周学习笔记 操作系统是如何工作的 郭垚 原创作品转载请注明出处 <Linux内核分析>MOOC课程http://mooc.study.163.com/ ...
- linux内核分析第五周学习笔记
linux内核分析第五周学习笔记 标签(空格分隔): 20135328陈都 陈都 原创作品转载请注明出处 <Linux内核分析>MOOC课程http://mooc.study.163.co ...
- Linux内核分析第六周学习笔记——分析Linux内核创建一个新进程的过程
Linux内核分析第六周学习笔记--分析Linux内核创建一个新进程的过程 zl + <Linux内核分析>MOOC课程http://mooc.study.163.com/course/U ...
- 《Linux内核分析》第一周学习笔记
<Linux内核分析>第一周学习笔记 计算机是如何工作的 郭垚 原创作品转载请注明出处 <Linux内核分析>MOOC课程http://mooc.study.163.com/c ...
- LINUX内核分析第三周学习总结——构造一个简单的Linux系统MenuOS
LINUX内核分析第三周学习总结——构造一个简单的Linux系统MenuOS 张忻(原创作品转载请注明出处) <Linux内核分析>MOOC课程http://mooc.study.163. ...
- Linux内核分析第三周学习博客——跟踪分析Linux内核的启动过程
Linux内核分析第三周学习博客--跟踪分析Linux内核的启动过程 实验过程截图: 过程分析: 在Linux内核的启动过程中,一共经历了start_kernel,rest_init,kernel_t ...
随机推荐
- node学习笔记_03 express框架
express api地址:http://www.expressjs.com.cn/starter/static-files.html 一.安装依赖 npm i --save express npm ...
- bootstrap模态框input不能获取焦点并编辑【转】
Bootstrap模态框时input标签[日期控件也有这样的问题]不能编辑的问题,下面是我的解决方法: 1.将下图中框出来的属性删掉即可: 2.兼容火狐浏览器,笔者在火狐中还是不能编辑,去掉下图属性即 ...
- Oracle_spatial的空间索引
空间索引 1.空间索引的创建 1)创建索引之前总是要为空间层插入元数据 2)如果之前创建的索引失败了,必须先删除才能创建 Drop index customers_sidx; 创建索引: Create ...
- redis cluster应用连接(password)
application.properties 集群配置 application.properties #各Redis节点信息spring.redis.cluster.nodes=47.96.*.*:6 ...
- grpc & pb 环境配置
grpc 官方中文文档:http://doc.oschina.net/grpc?t=60140 grpc github仓库:https://github.com/grpc/grpc protobuf ...
- python获得命令行参数的方法
#encoding=utf8 import sys reload(sys) sys.setdefaultencoding("utf8") print "参数名: &quo ...
- day57
JQ初级 一.认识jQuery 1.什么是jQuery jQuery是对原生JavaScript二次封装的工具函数集合 jQuery是一个简洁高效的且功能丰富的JavaScript工具库 2.jQue ...
- js 获取当前页url网址信息
转载地址:js如何准确获取当前页面url网址信息 摘录: 举例一个URL,然后获得它的各个组成部分:http://i.cnblogs.com/EditPosts.aspx?opt=1 1.window ...
- 【转】PHP之FastCGI与mod_php详解
原文地址:http://article.gitos.cn/2015/Aurthur/PHP-Mod-PHP-And-Fast-CGI-Explain.html 背景 PHP最常用的方式是以模块的方式( ...
- HUE配置HBase
HBase的配置 修改配置hue.ini的配置文件 [hbase] hbase_clusters=(Cluster|node1:) hbase_conf_dir=/usr/hbase-0.98.12. ...