欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 文旅 > 旅游 > Linux内核编译流程

Linux内核编译流程

2024/11/30 14:38:51 来源:https://blog.csdn.net/qq_43495002/article/details/132070065  浏览:    关键词:Linux内核编译流程

删除之前编译生成的文件和配置文件

make mrproper

生成.config文件

make menuconfig

编译

make -j4

1. No rule to make target ‘debian/canonical-certs.pem‘, needed by ‘certs/x509_certificate_list‘

vim .config
修改CONFIG_SYSTEM_TRUSTED_KEYS为""
修改CONFIG_SYSTEM_REVOCATION_KEYS为""

2.BTF: .tmp_vmlinux.btf: pahole (pahole) is not available Failed to generate BTF for vmlinux

sudo apt install linux-tools-common
编辑.config文件,将CONFIG_DEBUG_INFO_BTF设置为n

后续

root@100ask:/home/book/Downloads/linux-5.19/arch/x86/boot# file bzImage
bzImage: Linux kernel x86 boot executable bzImage, version 5.19.0 (root@100ask) #2 SMP PREEMPT_DYNAMIC Wed Aug 2 09:35:26 EDT 2023, RO-rootFS, swap_dev 0xA, Normal VGA
  • 编译busybox
make menuconfig
勾选 Build static binary 生成静态链接的busybox二进制文件再make -j4进行编译
  • 安装
make install
会安装在当前busybox目录的_install目录下
  • 制作initramfs.img
    写如下Makefile文件:
    initramfs:cd ./initramfs_dir && find . -print0 | cpio -ov --null --format=newc | gzip -9 > ../initramfs.imgrun:qemu-system-x86_64 \-kernel bzImage \-initrd initramfs.img \-m 512M \-nographic \-append "earlyprintk=serial,ttyS0 console=ttyS0"
    

在启动Linux时,会执行以下步骤:
1.引导加载器加载内核映像(这里是bzImage)
2.内核加载并挂载根文件系统启动init进程
3.init进程使用根文件系统下的/init脚本来继续启动系统

root@100ask:/home/book/linux-demo#下
执行make initramfs即可生成根文件系统的映像文件initramfs.img
执行make run就会启动qemu虚拟机
  • /init脚本

    #!/bin/busybox sh/bin/busybox mkdir -p /proc && /bin/busybox mount -t proc none /proc
    /bin/busybox echo "Hello"/bin/busybox sh
    
  • 文件结构
    ├── bzImage
    ├── initramfs_dir
    │ ├── bin
    │ │ └── busybox
    │ └── init
    ├── initramfs.img
    └── Makefile

  • 使用

    root@100ask:/home/book/Downloads/busybox-1.36.1/_install/bin# busybox echo 123
    123
    
  • 退出:ctrl+a,then press x

  • 将内核中的proc文件系统挂载到/proc文件夹,这样就可以通过访问/proc下的文件和目录,获取到与内核和系统相关的信息

  • 显示进程
    init中加入下面这行:

    /bin/busybox mkdir -p /proc && /bin/busybox mount -t proc none /proc
    

    这样执行busybox ps就可以显示进程了

  • 修改shell提示符

    加一行 export $PS1='(kernel) =>'
    

文件系统

文件系统常用格式:ext2、yaffs2
内存文件系统:ramdisk:用内存模拟块设备,并格式化为文件系统格式ramfs:利用linux会把块设备的数据缓存到内存中的机制实现,不会将数据写回到存储设备tmpfs:tmpfs是ramfs的衍生物,有容量大小限制、允许向交换空间(swap) 写入数据
内核早期启动的临时根文件系统:initramfs:
linux最终使用的完整的文件系统:rootfs:是ramfs和tmpfs的一个实现,包含系统所有基本文件和目录,是完整的Linux文件系统

内核在启动初始化过程中会解压缩initrd文件,然后将解压后的initrd挂载为根目录,然后执行根目录中的/init脚本,您就可以在这个脚本中运行initrd文件系统中的内核模块自动加载机制udevd,让它来自动加载realfs(真实文件系统)存放设备的驱动程序,以及在/dev目录下建立必要的设备节点。在udevd自动加载磁盘驱动程序之后,就可以mount真正的根目录,并切换到这个根目录中来。
详细描述

initfd和initramfs

  • initrd:有image格式和cpio格式。基于ramdisk的小型根目录,包含启动阶段中需要的文件和脚本,会在系统启动时被读入到内存,执行其中的/init脚本。
    为了精简内核代码,将加载各种设备驱动和模块的代码写在init脚本中,放在大小固定大小的块设备上,放在用户态来做。
    由于其基于块设备,因此需要内核有文件系统驱动
  • initramfs:本质上是cpio格式的initrd

initramfs是initrd的继承者,都用来做一些内核不容易做的事情,比如挂载文件系统、加载模块等

怎样在linux中添加一个系统调用

下面以获得cpu个数为例:
  • 在arch/x86/entry/syscalls/syscall_64.tbl中注册系统调用号
    451 common get_cpu_number sys_get_cpu_number
    
  • 在include/linux/syscalls.h中声明系统调用函数
    asmlinkage long sys_get_cpu_number(void);
    
  • 在kernel/sys.c中实现系统调用函数
    SYSCALL_DEFINE0(get_cpu_number)
    {return num_present_cpus();
    }
    
  • 然后重新编译linux内核(使用默认配置即可)
  • 测试程序get_cpu.c:
    #include <sys/syscall.h>int main()
    {int cpu_numbers= syscall(451);return 0;
    }
    
    结构和之前的linux-demo类似,只是bzImage是重新编译内核生成的
    ├── get_cpu.c 测试程序
    ├── bzImage 编译内核生成的镜像
    ├── initramfs_dir 目录
    │ ├── bin 目录
    │ │ └── busybox 编译busybox生成的可执行文件
    │ └── get_cpu 可执行文件
    │ └── init 脚本文件
    ├── initramfs.img 执行Makefile下的make initramfs会生成该镜像文件
    └── Makefile 也和linux-demo中写的一样
    执行gcc -static get_cpu.c -o get_cpu生成静态可执行文件,所有的依赖库都会被静态链接到可执行文件中,从而使可执行文件在其他系统上运行时不需要依赖动态库

qemu的按键驱动程序

  • 编译内核
    我的linux内核目录为~/100ask_imx6ull-qemu/linux-4.9.88

    • 设置环境变量

      export ARCH=arm
      export CROSS_COMPILE=arm-linux-gnueabihf-
      
    • 生成.config文件 make menuconfig

      为避免后期报错:button_drv: version magic '4.9.88-g8f6c88de SMP mod_unload modversions ARMv7 p2v8 ’ should be '4.9.88-g8f6c88de SMP preempt mod_unload modversions ARMv7 p2v8 ',要做如下设置

      编译内核时使用抢占式模型,需要设置Kernel Features -> Preemption Model为Preemptible Kernel (Low-Latency Desktop)

    • make -j4

    • 修改内核源码的version magic
      为避免加载的驱动所使用的内核版本和系统运行的版本不一致,导致后期报错:Unknown symbol __gnu_mcount_nc
      打开内核include/generated/utsrelease.h文件,修改version magic为开发板的版本。
      #define UTS_RELEASE "4.9.88-g8f6c88de"

  • 编译按键驱动程序

    • 在Makefile中指定内核路径KERN_DIR

      KERN_DIR = /home/book/100ask_imx6ull-qemu/linux-4.9.88
      all:make -C $(KERN_DIR) M=`pwd` modules$(CROSS_COMPILE)gcc -o button_test button_test.c
      clean:make -C $(KERN_DIR) M=`pwd` modules cleanrm -rf modules.orderrm -f ledtest
      obj-m   += button_drv.o
      obj-m   += board_100ask_imx6ull-qemu.o
      
    • make编译,然后将ko文件和程序复制到nfs文件夹
      cp *.ko button_test /home/book/nfs_rootfs/

  • 启动qemu,挂载nfs
    mount -t nfs -o nolock,vers=3 10.0.2.2:/home/book/nfs_rootfs /mnt

  • 安装模块
    insmod button_drv.ko
    insmod board_100ask_imx6ull-qemu.ko

  • 查看内核日志
    dmesg | grep hello

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com