嵌入式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驱动,修改网络设备,保存修改后的图形化配置文件。

相关推荐
云飞云共享云桌面29 分钟前
8位机械工程师如何共享一台图形工作站算力?
linux·服务器·网络
Peter_chq1 小时前
【操作系统】基于环形队列的生产消费模型
linux·c语言·开发语言·c++·后端
一坨阿亮2 小时前
Linux 使用中的问题
linux·运维
dsywws3 小时前
Linux学习笔记之vim入门
linux·笔记·学习
幺零九零零4 小时前
【C++】socket套接字编程
linux·服务器·网络·c++
小林熬夜学编程5 小时前
【Linux系统编程】第四十一弹---线程深度解析:从地址空间到多线程实践
linux·c语言·开发语言·c++·算法
程思扬6 小时前
为什么Uptime+Kuma本地部署与远程使用是网站监控新选择?
linux·服务器·网络·经验分享·后端·网络协议·1024程序员节
sun0077006 小时前
拷贝 cp -rdp 和 cp -a
linux·运维·服务器
wowocpp6 小时前
ubuntu 22.04 server 安装 anaconda3
linux·运维·ubuntu
乡村农夫6 小时前
cuda 环境搭建
linux