前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >《Linux内核分析》之构造一个简单的Linux系统MenuOS 实验总结

《Linux内核分析》之构造一个简单的Linux系统MenuOS 实验总结

作者头像
WindCoder
发布2018-09-20 15:34:14
2.2K0
发布2018-09-20 15:34:14
举报
文章被收录于专栏:WindCoder

环境搭建与配置过程

个人Linux系统环境搭建MenuOS的过程

Linux系统环境搭建MenuOS的过程

1、Linux系统环境搭建MenuOS的过程

代码语言:javascript
复制
# 下载内核源代码编译内核
cd ~/LinuxKernel/
wget https://www.kernel.org/pub/linux/kernel/v3.x/linux-3.18.6.tar.xz
xz -d linux-3.18.6.tar.xz
tar -xvf linux-3.18.6.tar
cd linux-3.18.6
make i386_defconfig
make # 一般要编译很长时间,少则20分钟多则数小时

# 制作根文件系统
cd ~/LinuxKernel/
mkdir rootfs
git clone  https://github.com/mengning/menu.git
cd menu
gcc -o init linktable.c menu.c test.c -m32 -static –lpthread
cd ../rootfs
cp ../menu/init ./
find . | cpio -o -Hnewc |gzip -9 > ../rootfs.img

# 启动MenuOS系统
cd ~/LinuxKernel/
qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img

2、重新配置编译Linux使之携带调试信息

在原来配置的基础上,make menuconfig选中如下选项重新配置Linux,使之携带调试信息

代码语言:javascript
复制
kernel hacking—>
[*] compile the kernel with debug info

make重新编译(时间较长)

3、使用gdb跟踪调试内核

代码语言:javascript
复制
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)
# -s shorthand for -gdb tcp::1234 若不想使用1234端口,则可以使用-gdb tcp:xxxx来取代-s选项

另开一个shell窗口

代码语言:javascript
复制
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之前,也可以在之后

实验楼中的过程

实验楼中实验过程

使用实验楼的虚拟机打开shell

代码语言:javascript
复制
cd LinuxKernel/
qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img

使用gdb跟踪调试内核

代码语言:javascript
复制
qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img -s -S

另开一个shell窗口

代码语言:javascript
复制
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之前,也可以在之后

部分步骤如下图所示

没有-S和-s时

有-s和-S时

gdb

break start_kernel

通过list查看break start_kernel后start_kernel前后文代码

相关代码分析

start_kernel函数

所在位置:xref: /linux-3.18.6/init/main.c

不管分析内核的哪一部分都会涉及到start_kernel

代码语言:javascript
复制
asmlinkage __visible void __init start_kernel(void)
{
.......
/*init_task即手工创建的PCB,0号进程就是最终的idle进程*/
set_task_stack_end_magic(&init_task);
........
/*初始化中断向量*/
trap_init();
/*内存管理模块初始化*/
mm_init();
/*调度模块初始化*/
sched_init();
....
/*其他初始化*/
rest_init()
}

trap_init();初始化一些中断向量,

主要分析函数所在地址: xref: /linux-3.18.6/arch/x86/kernel/traps.c

rest_init();中包含内核启动过程

所在位置:xref: /linux-3.18.6/init/main.c

rest_init()函数

从系统内核一启动,rest_init()会一直存在,是0号进程,并且创建了1号进程,并创建了一些其他的服务进程*/

代码语言:javascript
复制
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.
         */
        /*初始化了第一个用户态的进程1号进程*/
        kernel_thread(kernel_init, NULL, CLONE_FS);
        numa_default_policy();
        /*创建内核线程管理系统资源
         *kthreadd 为内核线程
         */
        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);
        schedule_preempt_disabled();
        /* Call into cpu_idle with preempt disabled */
        cpu_startup_entry(CPUHP_ONLINE);
}
kernel_init 

原语句:kernel_thread(kernel_init, NULL, CLONE_FS);

所在位置(非语句):xref: /linux-3.18.6/init/main.c

其中主要分析的代码所在的代码段

代码语言:javascript
复制
if (ramdisk_execute_command) {
		ret = run_init_process(ramdisk_execute_command);
        if (!ret)
                	return 0;
        pr_err("Failed to execute %s (error %d)n",
	    ramdisk_execute_command, ret);
}

run_init_process  init_process为一号进程,第一个用户态进程

cpu_startup_entry

原语句:cpu_startup_entry(CPUHP_ONLINE);

所在位置(非语句):xref: /linux-3.18.6/kernel/sched/idle.c

其中主要分析的代码

代码语言:javascript
复制
cpu_idle_loop();

所在位置(非语句):xref: /linux-3.18.6/kernel/sched/idle.c

主要作用:

cpu_idle_loop是一个while(1)循环,当系统没有进程需要执行时就调度到idle进程

其实是0号进程实现部分。

0号进程一直存在,并创建一号进程及其他服务的内核线程。

总结

Linux内核的启动,通过start_kernel()进行各种初始化工作,最终执行到rest_init()来初始化0号进程,同时0号进程创建1号用户态的进程以及其他服务的一些内核线程。然后操作系统就运行起来了。

windCoder原创作品转载请注明出处

参考资料

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

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2015-03-22,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 环境搭建与配置过程
    • 个人Linux系统环境搭建MenuOS的过程
      • 在实验楼中的过程
      • 相关代码分析
        • start_kernel函数
          • rest_init()函数
            • kernel_init 
            • cpu_startup_entry
        • 总结
        • 参考资料
        相关产品与服务
        腾讯云代码分析
        腾讯云代码分析(内部代号CodeDog)是集众多代码分析工具的云原生、分布式、高性能的代码综合分析跟踪管理平台,其主要功能是持续跟踪分析代码,观测项目代码质量,支撑团队传承代码文化。
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档