嵌入式linux移植篇之kernel

Linux的启动过程概述

Linux内核的启动过程是一个复杂而又有序的流程,涉及到硬件初始化、引导加载、内核初始化等多个步骤。以下是Linux内核的典型启动流程:

BIOS/UEFI阶段:

电源启动:计算机通电后,BIOS(基本输入/输出系统)或UEFI(统一扩展固件接口)开始执行。

POST(电源自检):进行硬件自检,检查系统中的硬件设备是否正常。

引导加载程序阶段:

MBR/UEFI固件:BIOS通过Master Boot Record(MBR)或UEFI固件加载引导加载程序(Boot Loader)。

Boot Loader:常见的引导加载程序包括GRUB(GRand Unified Bootloader)或LILO(LInux LOader)等。引导加载程序的作用是加载内核映像。

内核加载阶段:

加载内核映像:引导加载程序加载内核映像(通常是vmlinuz)到内存中。

初始化RAM磁盘:如果有RAM磁盘(ramdisk),则初始化RAM磁盘。

内核启动阶段:

启动内核:引导加载程序将控制权交给内核,开始执行内核代码。

初始化内核数据结构:内核初始化页表、中断描述符表(IDT)等数据结构。

启动第一个进程:内核启动第一个用户空间进程(通常是init)。

初始化阶段:

设备初始化:内核开始初始化各种硬件设备,包括CPU、内存控制器、输入输出控制器等。

文件系统初始化:挂载根文件系统,初始化文件系统模块。

初始化进程:内核初始化其他重要的内核线程和进程。

用户空间阶段:

启动用户空间:用户空间初始化完成后,控制权交给init或systemd等用户空间的第一个进程。

启动系统服务:用户空间进程负责启动各种系统服务和用户应用程序。

内核的初次编译

编译内核之前需要先在 ubuntu 上安装 lzop 库

bash 复制代码
sudo apt-get install lzop

编译脚本的内容如下

bash 复制代码
 #!/bin/sh
 make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- distclean
 make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- imx_v7_defconfig
 make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- menuconfig
 make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- all -j16

以上命令分别是清理工程,配置工程,打开图形配置页面,执行make编译linux源码

Linux 工程目录分析

编译之后,会有很多生成的文件,具体的文件夹和主要文件作用如下;


在 arch/arm/configs 中就包含有 I.MX6U-ALPHA 开发板的默认配置文件:imx_v7_defconfig,执行"make imx_v7_defconfig"即可完成配置。arch/arm/boot/dts 目录里面是对应开发平台的设备数文件。arch/arm/boot 目录下会保存编译出来的 Image 和 zImage 镜像文件,而 zImage 就是我们要用的 linux 镜像文件。arch/arm/mach-xxx 目录分别为相应平台的驱动和初始化文件,比如 mach-imx 目录里面就是 I.MX 系列 CPU 的驱动和初始化文件。

linux内核的启动流程

在Linux 内核的连接脚本文件 arch/arm/kernel/vmlinux.lds文件中,ENTRY指明了Linux的内核入口,入口为 stext,stext 定义在文件arch/arm/kernel/head.S。

stext 函数

Linux 内核启动之前要求如下:

  1. 关闭 MMU。
  2. 关闭 D-cache。
  3. I-Cache 无所谓。
  4. r0=0。
  5. r1=machine nr(也就是机器 ID)。
  6. r2=atags 或者设备树(dtb)首地址。

检查当前系统

在stext函数中,它做的主要操作是,确保CPU在SVC模式,关闭中断,读处理器的ID,检查当前的系统是否支持当前的CPU,这个就是通过比对proc_info_list 信息。

Linux 内核将每种处理器都抽象为一个 proc_info_list 结构体,每种处理器都对应一个procinfo。因此可以通过处理器 ID 来找到对应的 procinfo 结构,__lookup_processor_type 函数找到对应处理器的 procinfo 以后会将其保存到 r5 寄存器中。

同时该函数会验证设备数的合法性,创建页表,最终会调用__mmap_switched 函数。

__mmap_switched 函数

该函数定义在文件 arch/arm/kernel/head-common.S中。最终调用 start_kernel 来启动 Linux 内核,start_kernel 函数定义在文件 init/main.c中。

start_kernel 函数

这个函数里面有很多的子函数,实现的功能很复杂,主要是进行系统各个异常的检测和各个设备模块的初始化。start_kernel 函数最后调用了 rest_init。

rest_init 函数

该函数定义在文件 init/main.c 中

该函数主要进行的是启动RCU锁调度器,kernel_thread 创建 kernel_init 进程,也就是的init 内核进程,进程的PID是1,在这个进程会实现由内核态带用户态的转变。接下来会调用函数 kernel_thread 创建 kthreadd 内核进程,此内核进程的 PID 为 2。kthreadd,进程负责所有内核进程的调度和管理。也会创建空闲进程,空闲进程的PID是0。

linux内核的移植过程

以I.MX6ULL EVK 开发板为参考,然后将 Linux 内核移植到正点原子的 I.MX6U-ALPHA 开发板上。

先对NXP官方开发板的linux内核进行修改和编译

修改顶层Makefile

bash 复制代码
ARCH    ?=ARM
CROSS_COMPILE    ?=arm-linux-gnueabihf-

配置并编译 Linux 内核

bash 复制代码
make clean
make imx_v7_mfg_defconfig
make -j16

Linux 内核编译完成以后会在 arch/arm/boot 目录下生成 zImage 镜像文件,如果使用设备树的话还会在 arch/arm/boot/dts 目录下开发板对应的.dtb(设备树)文件。

在测试之前,需要修改些环境变量,烧录到 I.MX6U-ALPHA 开发板会提示,提示内核崩溃,因为 VFS(虚拟文件系统)不能挂载根文件系统。

在linux内核添加自己的开发板

添加开发板默认配置文件

将 arch/arm/configs 目 录 下 的 imx_v7_mfg_defconfig 重 新 复 制 一 份 , 命 名 为

imx_alientek_emmc_defconfig

bash 复制代码
cd arch/arm/configs
cp imx_v7_mfg_defconfig imx_alientek_emmc_defconfig

后续可以使用以下命令配置内核

bash 复制代码
make imx_alientek_emmc_defconfig

添加开发板对应的设备树文件

进入目录 arch/arm/boot/dts 中,复制一份 imx6ull-14x14-evk.dts,然后将其重命名为 imx6ull-alientek-emmc.dts

bash 复制代码
cd arch/arm/boot/dts
cp imx6ull-14x14-evk.dts imx6ull-alientek-emmc.dts

.dts 是设备树源码文件,编译 Linux 的时候会将其编译为.dtb 文件, 需 要 修 改 文 件 arch/arm/boot/dts/Makefile , 找 到 " dtb-$(CONFIG_SOC_IMX6ULL)"配置项,在此配置项中加入"imx6ull-alientek-emmc.dtb

编译脚本如下

bash 复制代码
#!/bin/sh
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- distclean
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihfimx_alientek_emmc_defconfig
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- menuconfig
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- all -j16

后续就是进行主频的修改,是能8线EMMC驱动,修改网络设备,保存修改后的图形化配置文件。

相关推荐
小卓笔记1 小时前
keepalived应用
linux·服务器·数据库
Hurry63 小时前
Rocky Linux 9.x 基于 kubeadm部署k8s 1.32
linux·运维·kubernetes
极客代码3 小时前
Unix 域套接字(本地套接字)
linux·c语言·开发语言·unix·socket·unix域套接字·本地套接字
zxnbmk4 小时前
ansible速查手册
linux·服务器·ansible
巷子里的童年ya4 小时前
Ansible模块
linux·centos·ansible
阿正的梦工坊4 小时前
Linux 命令:按内存使用大小排序查看 PID 的完全指南
linux·运维·服务器
神秘的土鸡4 小时前
Centos搭建Tomcat服务器:我的实战经验分享(成功版本 详细!)
linux·开发语言·python·tomcat·web
IT小饕餮5 小时前
linux 基础网络配置文件
linux·服务器·网络
未来之窗软件服务5 小时前
lite_avatar 数字人命令行-安装故障解决
linux·运维·服务器·数字人
m0_694845575 小时前
什么是站群服务器?站群服务器应该怎么选?
linux·运维·服务器·云计算·github