zoukankan      html  css  js  c++  java
  • 20135202闫佳歆--week3 构造一个简单的Linux系统MenuOs--学习笔记

    此为个人学习笔记存档

    week 3 构造一个简单的Linux系统MenuOs

    复习:
    计算机有三个法宝:存储程序计算机,函数调用堆栈,中断
    操作系统有两把剑:
    1.中断上下文的切换,保存现场和恢复现场
    2.进程上下文的切换。

    一、Linux内核源代码简介

    实现视图。

    1. arch目录
      占有相当庞大的空间
      arch/x86目录下的代码是需要重点关注的。
      arch下其他目录可以删掉。

    2. init目录
      内核启动相关的基本代码基本都在init目录下。
      main.c 文件中有一个start_kernel函数,初始化Linux内核的起点,这个函数相当于普通c程序的main函数。

    3. kernel目录
      Linux内核的核心代码在kernel目录中

    4. 其他
      Documentation 文档
      drivers 驱动
      fs-filesystem 文件系统
      include
      ipc 进程间通信

    5. README:
      INSTALLING 怎样安装内核源代码——怎么解压怎么打补丁
      make mrproper 把生成的中间代码清理干净
      menuconfig

    二、构造一个简单的Linux系统

    实验指导(以下内容来自课程,整理在此方便查看)

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

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

    内核启动完成后进入menu程序,支持三个命令help、version和quit。

    • 通过gdb跟踪内核的启动过程参见视频演示。

    • 使用自己的Linux系统环境搭建MenuOS的过程

      //下载内核源代码编译内核
      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 # 如果被墙,可以使用附件menu.zip
      cd menu
      gcc -o init linktable.c menu.c test.c -m32 -static –lpthread # 系统会默认启动init,即第一个用户态进程,1号进程
      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

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

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

    2. 如下这步和第三步实验楼可以不做

       kernel hacking—>
       [*] compile the kernel with debug info
      
    3. make重新编译(时间较长)

    • 使用gdb跟踪调试内核

      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初始化之前把它冻结起来
      //-s shorthand for -gdb tcp::1234 在1234端口上建立了一个gdb server
      若不想使用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之前,也可以在之后
    

    老刘给的,新版本的方法:

    1. Download kali-linux-2016.1 and install
      Notice: to use LVM to manage disks

    2. VMWare Tools

       apt-cache search open-vm*
       apt-get install open-vm-tools
       apt-get install open-vm-tools-desktop//重启后,剪贴板就可以共享了	
      
    3. Qemu

       apt-get install qemu
      
    4. Source

    5. menu

    6.  git clone https://github.com/mengning/menu.git
       //缺少库文件sys/cdefs.hß
       apt-get install build-essential libc6-dev libc6-dev-i386
       gcc -o init2 linktable.c menu.c test.c -m32 -static -lpthread
      
    7. finally

       mkdir rootfs
       ls
       cd rootfs/
       cp ../init2 ./init
       ls
       find . | cpio -o -Hnewc | gzip -9 > ../rootfs.img
       qemu-system-x86_64 -kernel /boot/vmlinuz-4.3.0-kali1-amd64 -initrd ../rootfs.img
      

    三、跟踪调试Linux内核的启动过程

    1.使用gdb跟踪调试内核的方法

    前面有贴:

    • 使用gdb跟踪调试内核

      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初始化之前把它冻结起来
      //-s shorthand for -gdb tcp::1234 在1234端口上建立了一个gdb server
      若不想使用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之前,也可以在之后
    
    (gdb)c # 系统开始启动,启动到start_kernel
    (gdb)list # 可以看到start_kernel上下的代码
    (gdb)break rest_init
    (gdb)c # 当前系统执行到rest_init
    (gdb)list # 可以看到rest_init是在start_kernel的尾部调用的。
    

    2.简单分析一下start_kernel

    首先在init目录下main.c里找到start_kernel函数

    有一个全局变量init_task,即手工创建的PCB,0号进程即最终的idle进程。

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

    trap_init() 初始化一些中断向量
    mm_init() 内存管理模块
    sched_init() 调度模块

    rest_init()中有kernel_thread(kernel_init,NULL,CLONE_FS),kernel_init中有run_init_process,创建了一号进程,默认路径下的程序。

    init_process 一号进程,默认的

    还创建了kthreadd,一个内核线程来管理系统的资源。
    启动完了之后进入了一个cpu_idle,cpu_idle_loop,就是一个while(0)的无限循环,即idle进程,0号进程,一直存在
    当系统没有进程需要执行时就调度到idle进程。

    3.课程中给的参考资料,在此存档。

    Linux内核启动过程相关的参考资料

    • 计算机的启动过程概述

      • x86 CPU启动的第一个动作CS:EIP=FFFF:0000H(换算为物理地址为000FFFF0H,因为16位CPU有20根地址线),即BIOS程序的位置。
      • BIOS例行程序检测完硬件并完成相应的初始化之后就会寻找可引导介质,找到后把引导程序加载到指定内存区域后,就把控制权交给了引导程序。这里一般是把硬盘的第一个扇区MBR和活动分区的引导程序加载到内存(即加载BootLoader),加载完整后把控制权交给BootLoader。
      • 引导程序BootLoader开始负责操作系统初始化,然后起动操作系统。启动操作系统时一般会指定kernel、initrd和root所在的分区和目录,比如root (hd0,0),kernel (hd0,0)/bzImage root=/dev/ram init=/bin/ash,initrd (hd0,0)/myinitrd4M.img
      • 内核启动过程包括start_kernel之前和之后,之前全部是做初始化的汇编指令,之后开始C代码的操作系统初始化,最后执行第一个用户态进程init。
      • 一般分两阶段启动,先是利用initrd的内存文件系统,然后切换到硬盘文件系统继续启动。
        • initrd文件的功能主要有两个:
        • 1、提供开机必需的但kernel文件(即vmlinuz)没有提供的驱动模块(modules)
        • 2、负责加载硬盘上的根文件系统并执行其中的/sbin/init程序进而将开机过程持续下去
    • =init进程详解

    • =Linux内核中的init_task进程和idle进程

    • 道生一(start_kernel....cpu_idle),一生二(kernel_init和kthreadd),二生三(即前面0、1和2三个进程),三生万物(1号进程是所有用户态进程的祖先,2号进程是所有内核线程的祖先),新内核的核心代码已经优化的相当干净,都符合中国传统文化精神了。

  • 相关阅读:
    【BZOJ】1045: [HAOI2008]糖果传递(中位数)
    【BZOJ】1011: [HNOI2008]遥远的行星(近似)
    【BZOJ】1034: [ZJOI2008]泡泡堂BNB(贪心)
    【BZOJ】1029: [JSOI2007]建筑抢修(贪心)
    【BZOJ】1022: [SHOI2008]小约翰的游戏John(博弈论)
    【BZOJ】1010: [HNOI2008]玩具装箱toy(dp+斜率优化)
    noip2014滚粗记
    【NOIP模拟题】Permutation(dp+高精度)
    MySQL 关于自定义函数的操作
    MySQL 关于存储过程的操作
  • 原文地址:https://www.cnblogs.com/20135202yjx/p/5252102.html
Copyright © 2011-2022 走看看