编译 linux 内核:
Linux操作系统框架
Linux内核的主要功能:
进程管理、内存管理、驱动、系统调用
Linux的内核目录结构:
结构图:
详细介绍:
a. arch/:这个目录包含了不同架构处理器的代码,如x86,arm,mips等。每个架构都有自己的子目录,如arch/x86/,arch/arm/等。在每个架构的子目录中,又有一些子目录和文件,如boot/,lib/,mm/,include/等,分别包含了特定平台的启动代码,库函数,内存管理,头文件
b. block/:这个目录包含了块设备的代码,如硬盘,光驱等。block/目录中主要包含了块设备的基本框架和I/O调度算法,以及一些通用的块设备驱动
c. crypto/:这个目录包含了加密算法的代码,如AES,SHA1,MD5等
d. drivers/:这个目录包含了设备驱动程序的代码,如键盘,鼠标,网卡,声卡,摄像头等。drivers/目录中的代码按照设备的类别进行分类,如char/,block/,input/,i2c/,spi/,pci/,usb/等
e. fs/:这个目录包含了文件系统的代码,如ext4,fat,ntfs,nfs,cifs等。fs/目录中的代码按照文件系统的类型进行分类,如ext4/,fat/,ntfs/等。在fs/目录中,还有一些通用的文件和子目录,如mount.h,dentry.c,proc/,sysfs/等,它们用于实现文件系统的基本功能和接口
f. include/:这个目录包含了内核所需的头文件,如linux/,asm/,uapi/等。头文件是用于声明变量,函数,结构,宏,常量等的文件,它们可以被其他的源文件引用,以便共享和重用代码。include/目录中的头文件按照不同的层次和用途进行分类,如linux/目录中的头文件是与平台无关的,asm/目录中的头文件是与平台相关的,uapi/目录中的头文件是用于内核和用户空间的API的
g. init/:这个目录包含了内核初始化的代码,如main.c,version.c,do_mounts.c等。init/目录中的代码是内核的入口和核心,它们负责调用其他子系统和模块的初始化函数
• ipc/:这个目录包含了进程间通信的代码,如sem.c,msg.c,shm.c等。进程间通信是指在不同的进程之间传递数据和信号的方法,它们可以让进程之间实现协作和同步。ipc/目录中的代码实现了一些常用的进程间通信机制,如信号量,消息队列,共享内存等
• kernel/:这个目录包含了内核的核心代码,如sched/,irq/,time/,fork.c,exit.c,signal.c等。kernel/目录中的代码实现了一些内核的基本功能和服务,如进程调度,中断处理,时间管理,进程创建,进程终止,信号处理等
• lib/:这个目录包含了内核需要引用的一些库函数的代码,如string.c,vsprintf.c,crc32.c等
• mm/:这个目录包含了内存管理的代码
**• net/**:这个目录包含了网络协议的代码,和网卡驱动不相关代码、
• scripts/:这个目录包含了内核编译所需的一些脚本,如Makefile,Kconfig,checkpatch.pl等
• tools/:这个目录包含了一些和内核交互的工具,如perf/,ftrace/,cpupower/,objtool/等。工具是用于分析和调试内核的程序,它们可以让内核的性能和稳定性更加优化和提高
uname - a 补充
uname -a 是一个在 Linux 和 Unix 系统上常用的命令,用于显示当前系统的信息。
具体来说,-a 选项(代表 "all")用于显示尽可能多的系统信息。
输出通常包含以下几个部分(但可能会因不同的系统和版本而异):
内核名称:例如 Linux
主机名:系统的主机名,这通常是你在 /etc/hostname 或使用 hostname 命令设置的名称。
内核版本号:当前运行的内核的版本。
内核发布日期:内核的发布或编译日期。
机器硬件名称:例如 x86_64 表示 64 位的 x86 架构。
处理器类型:例如 x86_64、i686 等。
操作系统:例如 GNU/Linux(但注意,这个信息并不总是显示)
例如,一个可能的输出是:bash
Linux myhostname 5.4.0-7642-generic #38
159890341720.04~385a5d2-Ubuntu SMP PREEMPT Wed Sep 2 21:30:07 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux在这个例子中:
内核名称是 Linux
主机名是 myhostname
内核版本是 5.4.0-7642-generic
内核发布日期(或编译日期)是 Wed Sep 2 21:30:07 UTC 2020
机器硬件名称和处理器类型都是 x86_64
操作系统是 GNU/Linux
这个命令在需要快速查看系统信息、诊断问题或编写与特定系统相关的脚本时非常有用。
编译之前
注意这里的时间是UTC 时间
后续我们会通过这个命令验证内核编译是否成功
UTC 时间补充
UTC 时间和北京时间相差 8h
UTC(协调世界时,Coordinated Universal Time)是一种全球标准的时间标准,用于协调世界各地的时间。以下是关于UTC时间的详细介绍:定义:UTC是根据原子钟生成的时间,被认为是“最精确的时间”。它的时间间隔被称为“秒”,并且具有高度的精确性和稳定性,不受地理位置的影响。
历史:UTC的概念在1960年由国际无线电咨询委员会规范统一,并在次年投入实际使用。它的计时基准是国际原子时(TAI),并通过加入闰秒来与世界时(UT1)保持同步。
应用:UTC在科学、政府、商业、金融等领域被广泛应用,如GPS导航、航天和通信。许多计算机和通信系统都以其为基准进行时间同步,以确保全球各地的时间一致性和协调性。
与GMT的关系:在1972年之前,格林威治时间(GMT)一直是世界时间的标准。然而,由于GMT是基于地球自转速度的观测和计算,其精度受到自然现象(如潮汐和季节变化)的影响。而UTC则基于原子钟的时间测量,具有更高的精度和稳定性。
特点:UTC以24小时制表示时间,并使用时区来调整不同地区的时间差异。它的特点是具有高度的精确性和稳定性,能够确保全球各地的时间准确性和一致性。
DTS 设备树补充:
DTS(Device Tree Source)设备树是一种用于描述硬件设备和资源的数据结构,它在嵌入式系统开发中扮演着重要的角色。以下是关于DTS设备树的详细介绍:
基本概念:DTS设备树采用树形结构来描述硬件设备的层次关系,每个节点代表一个硬件设备或子系统。节点可以包含设备的名称、类型、地址、中断号等信息,还可以包含子节点来表示该设备所连接的其他设备。
作用:通过DTS设备树,操作系统可以在运行时动态地识别和配置硬件,而无需在代码中硬编码驱动程序。这大大简化了硬件驱动的编写和管理工作,提高了系统的可移植性和可扩展性。
文件格式:DTS文件通常使用文本格式编写,易于阅读和编辑。文件名通常以.dts为扩展名,而.dtsi文件则用于描述SOC级信息(如CPU数量、主频、外设控制器信息等),可以被多个DTS文件共享以提高可重用性。
工作流程:在嵌入式系统开发中,DTS文件首先被编译成DTB(Device Tree Blob)二进制文件。这个编译过程通常使用设备树编译器(DTC)来完成。然后,在boot loader运行时,DTB文件被传递给操作系统。操作系统通过解析DTB文件来获取系统中所有硬件设备的配置信息,并据此进行初始化和配置。
应用:DTS设备树在嵌入式系统中的应用非常广泛,尤其是在嵌入式Linux系统中。通过DTS设备树,Linux内核可以自动识别并配置各种硬件设备,如CPU、内存、网卡、串口等。此外,DTS还支持热插拔功能,即在系统运行时动态添加或删除硬件设备,这对于需要频繁更换硬件设备的场景非常有用。
优点:DTS设备树将硬件信息从内核代码中分离出来,使得硬件信息更加清晰、易于管理和维护。同时,它也提高了系统的可移植性和可扩展性,使得开发人员可以更加容易地将代码移植到不同的硬件平台上。
总之,DTS设备树是一种非常重要的数据结构,它简化了硬件驱动的编写和管理工作,提高了系统的可移植性和可扩展性。在嵌入式系统开发中,DTS设备树发挥着不可替代的作用。dtbs 可能是指Device Tree Blob Source的缩写,用于描述或存储设备树源文件的集合。Device Tree Blob(DTB)是设备树描述(Device Tree Description)的二进制表示,它描述了硬件的结构和配置,特别是在嵌入式系统中。
=====================================
Linux内核编译流程:
方法一: 官方内核编译:
//参考自官方的编译方式,详见(《OrangePi_Zero2_H616用户手册v4.0》 6.4 编译Linux内核)
1. 运行 build.sh 脚本, 记得加 sudo 权限
sudo ./build.sh
2. 选择 Kernel package, 然后回车
3. 然后会提示是否需要显示内核配置界面
如果不需要修改内核配置, 则选择第一个即可
如果需要修改内核配置, 则选择第二个
4. 接着选择开发板的型号
因为我们使用的板子是 orangepi02 ,so我们选 orangepizero2
然后就进行编译了,注意这里编译耗时很长,我耗时一个半小时,可能其他条件因素,耗时几小时也是可能得。
编译完成
<h2 id="mySection">编译之前</h2>
- 查看编译生成的内核相关的 deb 包 -- 生成在这个 output/debs/ 路径下
a. linux-dtb-next-sun50iw9_3.1.0_arm64.deb 包含有内核使用的 dtb 文件
b. linux-headers-next-sun50iw9_3.1.0_arm64.deb 包含内核头文件
c. linux-image-next-sun50iw9_3.0.1_arm64.deb 包含内核镜像和内核模块
如下图
我们需要的是镜像文件
解压 linux-image 的deb包得到如下目录:
其中 ./boot/下的:
config -- 是配置文件
vmlinuz 是我们需要的内核文件
- 重复编译 kernel
使用下面的命令无需通过图形界面选择, 可以直接开始编译kernel
sudo ./build.sh BOARD=orangepizero2 BRANCH=next BUILD_OPT=kernel KERNEL_CONFIGURE=no
7. 如果对内核做了修改 可以使用下面的方法来更新开发板 linux 系统的内核和内核模块
这里的ip 和用户名根据自身的修改
scp linux-image-next-sun50iw9_3.1.0_arm64.deb orangepi@192.168.1.11:/home/orangepi/
查看之前安装的内核:
dpkg -l | grep linux-image
卸载之前安装的内核
sudo apt purge -y linux-image-next-sun50iw9 # 也有可能是linux-image-next-sun50iw9
安装我们scp 过来的新内核, -i --> install
sudo dpkg -i linux-image-next-sun50iw9_3.1.0_arm64.deb
reboot -- 重启,我们的内核才生效
编译之后
// 和之前 编译之前 的对比,发现我们的日期时间 已经修改为了今天的UTC,说明我们已经编译成功了
如果对dpkg不够了解的朋友请看这一篇:
一文带你了解 dpkg-CSDN博客
报错小插曲:
dpkg -i 下载的时候出现问题:dpkg-deb: error: paste subprocess was killed by signal
解决:
sudo dpkg -i --force-overwrite linux-image-next-sun50iw9_3.1.0_arm64.deb
sudo apt-get -f install
可以尝试的方法:
我们这样解决,一次执行下面命令:
sudo apt-get clean
sudo apt-get update
sudo apt-get upgrade
sudo apt-get clean 是一个在Debian和Ubuntu等基于Debian的Linux发行版中常用的命令,它用于清理本地存储的已下载的.deb软件包文件。这些.deb文件通常在你使用apt-get命令安装、升级或删除软件包时被下载到/var/cache/apt/archives/目录中。
具体来说,sudo apt-get clean命令的作用如下:
清理下载的包:它删除/var/cache/apt/archives/目录下所有已下载的.deb软件包文件。这些文件在你成功安装软件包后通常是不再需要的,但它们会占用磁盘空间。
节省磁盘空间:如果你的系统经常进行软件包的安装、升级或删除操作,那么/var/cache/apt/archives/目录可能会积累大量的.deb文件,从而占用大量的磁盘空间。sudo apt-get clean命令可以帮助你释放这些空间。
不影响已安装的软件包:这个命令只会删除已下载的.deb文件,而不会影响已经安装在你的系统上的软件包。因此,你不需要担心运行这个命令会导致已安装的软件包被删除或损坏。
需要注意的是,虽然sudo apt-get clean命令可以释放磁盘空间,但如果你希望更深入地管理你的软件包缓存,你还可以考虑使用sudo apt-get autoclean命令。这个命令会删除过时的.deb文件(即那些在新版本的软件包管理器中不再需要的文件),而不仅仅是所有已下载的.deb文件。这样可以在保持一些可能在未来需要的.deb文件的同时,进一步节省磁盘空间。
=====================================================
方法二:
上述官方编译kernel的方法可以用以下步骤代替:
1. 清理旧配置文件及生成的文件
sudo apt-get install ccache #安装ccahe,用于编译加速
export PATH=$PATH:/home/mxjun/orangepi-build/toolchains/gcc-arm-9.2-2019.12-x86_64-aarch64-none-linux-gnu/bin #给root用户导入交叉编译环境,需要先切换到root用户
// 注意这里不能使用 whoami --> 我们需要切换到 root 用户操作 , 得到的用户名是root
make ARCH=arm64 distclean
- 配置内核, 更新内核依赖属性和新属性, 生成.config:
cp ../../external/config/kernel/linux-5.16-sun50iw9-current.config .config #拷贝默认配置
make ARCH=arm64 CROSS_COMPILE="aarch64-none-linux-gnu-" olddefconfig #这里执行make menuconfig 然后exit也是可以的
a. make olddefconfig 的作用是根据已有的 .config 文件生成一个新的 .config 文件,同时更新内核的依赖属性和新属性。它会使用旧的 .config 文件中的参数作为默认参数,不会询问用户的选择。它会将新添加的内核选项设置为默认值,也不会提醒用户。它会将旧的 .config 文件重命名为 .config.old 文件,以备后用.
b. make olddefconfig 的作用和 make oldconfig 类似,但是 make oldconfig 会以交互方式询问用户对
新配置的选择,而 make olddefconfig 不会
c. make menuconfig 是基于 Ncurses 图形界面去配置 .config 文件,它可以让用户在一个菜单式的界面
中选择和修改内核的各种选项,也可以查看选项的帮助信息,它是一种比较方便和直观的配置方式
- 编译内核:
make -j6 ARCH=arm64 'CROSS_COMPILE=ccache aarch64-none-linux-gnu-' LOCALVERSION=-sun50iw9 Image modules dtbs
// 以ccache 高速缓存去加速交叉编译, modules-->编译模块 dtbs -->编译设备树
- 安装 内核 和 驱动:
make modules_install INSTALL_MOD_STRIP=1 INSTALL_MOD_PATH=$PWD/_install ARCH=arm64 'CROSS_COMPILE=ccache aarch64-none-linux-gnu-' #安装驱动
make install INSTALL_PATH=$PWD/_install/boot #安装内核
// 参数:** INSTALL_MOD_STRIP=1** --> 删除调试信息 or 链接调试符,节省编译空间,对orangepi不太明显,对×86 内核会明显
或者直接打包成deb包:
cp external/patch/misc/headers-debian-byteshift.patch /tmp
make -j6 bindeb-pkg KDEB_PKGVERSION=3.1.0 KDEB_COMPRESS=xz BRANCH=next
LOCALVERSION=-sun50iw9 KBUILD_DEBARCH=arm64 ARCH=arm64 DEBFULLNAME="Orange Pi"
CROSS_COMPILE="ccache aarch64-none-linux-gnu-”
解读:
a.bindeb-pkg 是指定 make 命令使用 Debian 的格式来打包内核,生成一个 .deb 文件,这样可以方便
地在 Debian 系的系统中安装内核 。
b. KDEB_PKGVERSION=3.1.0 是指定打包的内核的版本号为 3.1.0,这个版本号可以自定义,也可以使用
内核的默认版本号 。
c. KDEB_COMPRESS=xz 是指定打包的内核使用 xz 的压缩格式,这样可以减少打包文件的大小,也可以
使用其他的压缩格式,如 gzip, bzip2 等 。
d. BRANCH=next 是指定编译的内核的分支为 next
c. LOCALVERSION=-sun50iw9 是指定编译的内核的本地版本为 -sun50iw9
d. KBUILD_DEBARCH=arm64 是指定打包的内核的架构为 arm64,这个架构是用来表示 64 位的 ARM
处理器。
e. ARCH=arm64 是指定编译的内核的架构为 arm64 。
f. DEBFULLNAME=Orange Pi 是指定打包的姓名为 Orange Pi。
======================================================
Linux根文件系统
根文件系统也叫roofs,Linux 根文件系统是指整个文件系统的最顶层,以 "/" 来表示。它是内核启动时所挂载的第一个文件系统,包含了系统运行所必需的目录和文件:
- /bin目录下存放着系统需要的可执行文件比如ls、mv、cp等命令,现在新根文件系统的像ubuntu等
debian系的rootfs, 基本都是软链接到/usr/bin目录下- /dev目录下面存放着的文件都与设备有关,此目录下的文件都是设备文件。
- /etc目录存放Linux下所必须的库文件
- /mnt目录, 临时挂载目录,可以在从目录下创建空的子目录
- /proc、sys 目录, Linux虚拟文件系统,由内核生成各类节点
- /sbin 一般软链到/usr/sbin下,一般存放一些root权限才能执行的命令
- /lib 软链接到/usr/lib目录,用于存放库文件
- /usr/ 存放lib bin sbin目录, 另外的share目录里面存放的是共享、只读的程序和数据
- /tmp/存放临时文件或目录
- /root目录 系统管理员(root)的主文件夹,即是根用户的目录,与此对应,普通用户的目录
是/home下的某个子目录。- /var目录、与/usr目录相反,/var目录中存放可变的数据,比如log文件\临时文件等。
- /home目录,系统默认的用户文件夹,它是可选的,对于每个普通用户,在/home目录下都有一个以用户名命名的子目录,里面存放用户相关的配置文件。
根文件系统的编译详见(《OrangePi_Zero2_H616用户手册v4.0》 6.5. 编译 rootfs )
版权归原作者 mx_jun 所有, 如有侵权,请联系我们删除。