zoukankan      html  css  js  c++  java
  • 20169211《Linux内核原理与分析》第五周作业

    1.在自己的linux系统中搭建实验环境;

    2.使用GDB调试内核跟踪启动过程;

    3.分析start_kernel的代码。

    1.在自己的linux系统中搭建实验环境

    1.1 下载linux-3.18.6的内核源码,并且编译

    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分钟多则数小时
    

    1.2 制作根文件系统

    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
    

    1.3 启动MenuOS

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


    2.使用GDB调试内核跟踪启动过程。

    在使用gdb跟踪调试内核之前需要先重新配置编译Linux使其携带调试信息。 由于make menuconfig需要ncurses-dev和tk4-dev库。 所以我们先输入命令sudo apt-get install ncurses-dev 和sudo apt-get install tk4-dev,然后输入make menuconfig进入Kernel Configuration界面 。

    选择Kernel hacking进入

    选择Compile-time checks and compilr options —>进入

    按Y选择Compile the kernel with debug info 然后执行make重新编译内核。 编译完成之后输入以下的命令,让CPU冻结在开始的时候。

    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选项
    

    然后打开GDB远程调试,另外开启一个终端 ,输入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设上断点,然后 ,(gdb)c 继续执行到达断点处 ,输出(gdb)list显示出上下文

    我们继续设置断点, break rest_init() ,然后输入c执行到断点处 ,然后输入list显示出上下文。

    代码分析补充

    3.分析start_kernel的代码

    从 start_kernel 开始到 init 进程启动

    set task stack end magic() #为了检测栈溢出
    
    smp setup processor_id() #设置对称多处理器
    
    cgroup init early () #初始化 Control Groups
    
    page address init() #页地址初始化(属于内存管理部分)
    
    setup log buf () #初始化log 缓冲区(kernel/printk/printk.c)
    
    pidhash_init ()	#初始化 pid 哈希表
    
    trap_init () #初始化中断向量
    
    mm_init () #内存管理初始化
    
    sched_init () #调度服务初始化
    
    rest_init() #剩余初始化
    
    - kernel_init:init进程
    - kthreadd:内核线程
    - cpu_idle进程:代码中一直循环,如果系统中没有可执行的进程时,执行 idle 进程
    

    总结

    在 start kernel执行到最后部分时,在 rest init 中 新建了kernel_init 进程, kernel_thread(kernel_init, NULL, CLONE_FS); ,init 进程是系统中的1号进程,是以后所有用户态进程的祖先,然后新建kthreadd进程, pid = kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES); ,kthreadd 作为2号进程,是所有内核线程的祖先,在 cpu_startup_entry(CPUHP_ONLINE) 中,是一个 while(1) 循环,始终有一个 idle 进程在执行,如果系统还总没有任何可以执行的进程时,idle 进程会执行。

    最后引用孟宁老师的一段话:

    道生一:(start kernel)

    二生三:(即0,1,2号进程)

    三生万物:(1号进程是所有用户态进程祖先,2号进程是所有内核线程祖先)

  • 相关阅读:
    MySQL SQL语言学习
    02-MySQL执行计划详解(EXPLAIN)
    linux下删除oracle11g单实例的方法
    01. Oracle 实例恢复
    替代变量与SQL*Plus环境设置
    9. Oracle 归档日志
    8. Oracle 联机重做日志文件(ONLINE LOG FILE)
    7. Oracle 控制文件(CONTROLFILE)
    6. Oracle 回滚(ROLLBACK)和撤销(UNDO)
    5. Oracle 表空间与数据文件
  • 原文地址:https://www.cnblogs.com/sharemi/p/5990930.html
Copyright © 2011-2022 走看看