Linux开发--Linux内核开发移植

Linux内核开发移植

Linux内核版本变迁及其获得

Linux是最受欢迎的自由电脑操作系统内核, 是一个用C语言写成, 并且符合POSIX标准的类Unix操作系统

Linux是由芬兰黑客Linus Torvalds开发的, 目的是尝试在英特尔x86架构上提供自由免费的类Unix操作系统

Linux操作系统的诞生、 发展、 和成长过程依赖于五个重要支柱: unix操作系统、 minix操作系统、 GNU计划、 POSIX标准和互联网

内核版本号从Linux1.0以后主要分为两个阶段:

Linux1.0-2.6, 数字包括四部分“ A.B.C.D”

  • A代表主版本号, 如1994年的1.0, 1996年的2.0, 2011年的3.0
  • B代表次版本号, 表示一些重大的修改, 偶数表示稳定版, 奇数表示开发版
  • C代表末版本号, 代表着一个新版本的发布(包括安全补丁、 bug修复、 新增功能、 或驱动程序), 一般数字变化范围比较大
  • D代表一些BUG修复, 对已经加入的安全补丁、 bug修复、 新增功能或驱动程序做的微调或添加新的特性, 2.6版本之后经常出现

Linux2.6之后的版本, 数字主要包括三部分"A.B.C"或"A.B.C-rcn"

  • A代表主版本号
  • B代表次版本号, 随着一个新版本的发布而增加, 与上一阶段中的数字” C“功能类似, 但不再代表稳定与否
  • C代表稳定版本号, 如果只有数字则代表稳定版本, 如果带"-rcn"表示最终稳定版本之前的候选版本(Release Candidate), n代表候选版本号

各版本之间的关系及命名规则可以参考网站:https://zh.wikipedia.org/wiki/Linux%E5%86%85%E6%A0%B8

注意: page9中的EOL: end of life: 指从此往后不在对应的版本上进行更新。 下面展示了Linux内核的版本变迁过程:

image-20200701153655101

Linux内核结构

Linux内核是Linux系统软件的核心, 它的性能对整个系统的性能起决定作用

Linux内核文件数目将近4万个, 他们分别位于顶层目录下的20个子目录中, 了解Linux内核的工作过程,必须从了解其目录结构做起

我们后面研究并移植的内核为:3.4.39, 首先我们从官网上下载3.4.39的内核源码linux-3.4.39.tar.bz2将其在虚拟机上解压, 使用tree命令可以在虚拟机下查看其目录结构

Linux内核源代码主要包含以下子目录:

image-20200701155535511

  • arch 与体系结构相关的代码。 对应于每个支持的体系结构, 有一个相应的子目录如x86arm等与之对应, 相应目录下有对应的芯片与之对应
  • crypto 常用加密及散列算法, 和一些压缩及CRC校验算法
  • Documentation 内核相关文档, 关于内核各部分的通用解释和注释
  • drivers 设备驱动代码, 占整个内核代码量的一半以上, 里面的每个子目录对应一类驱动程序, 如: block:块设备、 char:字符设备、 net:网络设备等
  • fs 文件系统代码, 每个支持的文件系统有相应的子目录, 如cramfsyaffsjffs2
  • include 这里包括编译内核所需的大部分头文件 , 与平台无关的头文件放在include/linux子目录下 , 各类驱动或功能部件的头文件( /media/mtd/net等), 与体系相关的头文件 arch/arm/include/ , 与平台相关的头文件路径arch/arm/mach-s5p6818/include/mach
  • init 内核初始化代码,其中的main.c中的start_kernel函数是系统引导起来后运行的第1个函数, 这是研究内核工作过程的起点
  • ipc 内核进程间通信代码
  • kernel 内核管理的核心代码, 此目录下的文件实现了大多数linux系统的内核函数, 体系结构相关的代码在arch/arm/kernel
  • lib 与体系结构无关的内核库代码,与系统调用相关 , 与体系结构相关的内核库代码在arch/arm/lib
  • mm 与体系结构无关的内存管理代码 , 与处理器体系结构相关的代码在 arch/arm/mm
  • net 网络部分代码, 其每个目录对应于网络的一个方面
  • scripts 存放一些脚本文件, 如配置内核时用到的make menuconfig命令等

Linux kernel组成:

img

image-20200701160147862

Linux内核部分模块:

进程管理、 进程调度、 系统调用、 中断处理、 下半部和工作队列、 内核同步、 定时管理、 内存管理、虚拟文件系统、 块设备、 网络子系统、 进程地址空间、 模块机制等等…

Linux编程风格 :

像所有其他大型软件项目一样, Linux制定了一套编码风格

跟选择一个唯一确定的风格相比, 到底选择什么样的风格反而显得不是那么重要

编码风格的主要规范伴随着Linus一贯的幽默,都记录在内核源码的Documentation/Coding Style中了。

制定编码风格的目的, 是为了提高编程效率, 吸引更多的开发者眼球

缩进

  • 采用制表符(Tab)进行缩进, 而不是空格
  • 禁止制表符和空格混合使用

花括号使用如下:

if (flag) {
	fun();
	//...
}

void fun (void)
{ 
	//..
}

if (flag)
	fun();
//...

命名规范

  • Linux规定名称中不允许使用混合大小写字符
  • 单词之间用下划线分隔
  • 避免取有疑惑的简单名称, 如pad(), 应该写成 platform_add_devices()

代码长度

  • 每行尽量不超过80个字符(可进行有意义分行切割)
  • 函数体代码长度尽量不超过两屏
  • 函数局部变量尽量不超过十个
  • 根据函数使用频率和函数体大小可以使用inline声明, 以提高调用效率

注释

  • 一般情况用于描述代码可以做什么和为什么要做, 尽量不写实现方式
  • 函数的修改和维护日志统一集中在文件开头

在程序中对ifdef的处理

一般不这么用:

//...
#ifdef CONFIG_FUN
	fun();
#endif
//...

而是在声明处使用ifdef

#ifdef CONFIG_FUN
void fun (void)
{
	//...
} 
#else
inline void fun (void) { }
#endif

其他

  • 指针中的“ *” 号应靠近变量名, 而不是类型关键字
  • 函数之间用空行隔开
  • 函数导出申明紧跟在函数定义的下面

代码风格的事后修正

indent命令是大多数Linux系统中都带有的工具, 当得到一段与内核编码风格大相径庭的代码时, 可以通过这个工具进行
调整:

#indent -kr -i8 -ts8 -sob -l80 -ss -bs -psl
<filename>

Linux内核启动引导过程

了解Linux镜像的格式及其产生过程

Linux内核有多种镜像格式:

Image : 直接生成并且无头部未压缩的内核, 一般用于PC机

zImage : Image的压缩版, 采用gzip进行压缩, 比Image体积小,但启动时需要进行自解压, 嵌入式系统中一般采用此种方法

uImage : 是u-boot专用的一种内核镜像格式, 它是在zImage的基础上又添加了一个长度为64字节的标签头, 在u-boot启动时会去掉此头信息, 仍按zImage启动, 头信息主要用于区分不同格式的内核镜像

xipImage : 片上执行的未压缩内核, (如norflash等)

zImage镜像产生过程:

vmlinux -> Image -> compressed / vmlinux -> zImage

vmlinux 是由以下内核代码生成的非压缩镜像 (arch/arm/kernel/head.s、 kernel/、 mm/、 fs/、 ipc/、 crypto/、 lib/、drivers/、 net/等等)

Image 是使用objcopy工具对vmlinux进行二进制化处理得到的镜像

arch/arm/boot/compressed/vmlinux由压缩的Imagecompressed/head.Smisc.c等文件组成

zImage是由compressed/vmlinux使用objcopy工具二进制化得到

再对zImage加上头部就成为了uImage

image-20200701161524245

boot.img的生成过程 :

image-20200701161846753

boot.img是使用一种文件系统打包工具制作的, 相当于把各种非必须文件打包在一起成为一整个文件, 然后被烧写进设备

Linux内核的启动过程大体上可以分为3个阶段:

内核解压( 汇编+C)

  • 主要由arch/arm/boot/compressed/zImage完成解压(C语言),并跳转到下阶段代码

板级引导阶段( 汇编)

  • 主要进行对cpu和体系结构的检查、 cpu本身的初始化以及页表的建立等

通用内核启动阶段( C语言)

  • 进入init/main.c文件, 从start_kernel开始进行内核初始化工作,最后调用rest_init

rest_init()创建并进入内核第一个线程, 线程函数为 kernel_init()

kernel_init()中会初始化各种驱动并建立起标准输入/ 标准输出/错误输出, 最后调用

init_post()中会释放初始化内存段, 标志着内核启动完成, 并努力寻找一个用户进程, 通过kernel_execve()函数加载, 将该进程作为系统的第一个用户进程init,进程号为1

内核启动完成, 接下来就是用户的事儿了

Linux内核的配置与编译

Linux内核配置裁剪过程

make menuconfig

Linux内核编译过程

根据配置裁剪的结果配合Makefile完成内核编译

Linux内核这一配置编译机制

把驱动程序v_motor_driver.c(振动马达驱动)添加 到内核源码来验证整个过程

在Linux2.6以后的版本中, 文件的组织是通过 Kconfig 和 Makefile 来实现的

通过每层目录的 Kconfig 和 Makefile 实现了整个Linux 内核的分布式配置

  • Kconfig: 对应内核模块的配置菜单
  • Makefile: 对应内核模块的编译选项

Kconfig包含了当前目录下所有模块的配置

子目录的Makefile在被顶层Makefile调用时, 会负责编译当前目录下的所有模块

当有新的模块被加入时, 需要更改当前目录下的Kconfig文件, 并且更改对应的Makefile文件, 这样在最终编译之前, 可以通过

make menuconfig 对需要添加的模块进行配置和添加

当保存make menuconfig时, 系统除了会自动更新.config外, 还会将选项以宏的形式保存在内核根目录下的include/generated/autoconf.h文件下

当执行make menuconfig时, 配置工具会自动根据根目录下的ARCH变量读取arch/$(ARCH)/Kconfig文件来生成配置界面, 这个文件是所有文件的总入口, 其它目录的Kconfig都由它来引用, 如图所示:

image-20200701165024280

ARM平台为例讲解其具体配置过程

当执行make menuconfig时, 系统首先读取 arch/arm/Kconfig生成整个配置界面

在读取配置界面的同时, 系统会读取顶层目录下的.config文件生成所有配置选项的默认值

当修改完配置并保存后, 系统会更新顶层目录下的.config文件

当执行make时, 各层的Makefile会根据.config文件中的编译选项来决定哪些文件会被编译到内核中, 或编译成模块

Kconfig语法格式可以参考具体文件, 如:drivers/char/Kconfig

# SPDX-License-Identifier: GPL-2.0
#
# Character device configuration

# comment: 注释信息, 菜单和.config文件中都会出现
# string: 字符串; hex: 16进制的数; int: 10进制的数
# choice/endchoice: 表示选择性的菜单条目

# menu/endmenu: 表示生成一个菜单
menu "Character devices"
# source: 用于包含其它Kconfig
source "drivers/tty/Kconfig"
#config代表一个选项的开始,最终会出现在.config中(会自动增加一个CONFIG_前缀)
config DEVMEM
	#bool代表此选项仅能选中或不选中,bool后面的字符串代表此选项在make menuconfig中的名字
	bool "/dev/mem virtual device support"
	#default: 默认选项值
	default y
	help
	  Say Y here if you want to support the /dev/mem device.
	  The /dev/mem device is used to access areas of physical
	  memory.
	  When in doubt, say "Y".

config DEVKMEM
	bool "/dev/kmem virtual device support"
	# On arm64, VMALLOC_START < PAGE_OFFSET, which confuses kmem read/write
	# depends on:依赖其余的选项
	depends on !ARM64
	help
	  Say Y here if you want to support the /dev/kmem device. The
	  /dev/kmem device is rarely used, but can be used for certain
	  kind of kernel debugging operations.
	  When in doubt, say "N".

source "drivers/tty/serial/Kconfig"
source "drivers/tty/serdev/Kconfig"

config TTY_PRINTK
	#tristate: 代表可以选择编译、 不编译、 编译成模块
	tristate "TTY driver to output user messages via printk"
	depends on EXPERT && TTY
	default n
	---help---
	  If you say Y here, the support for writing user messages (i.e.
	  console messages) via printk is available.

	  The feature is useful to inline user messages with kernel
	  messages.
	  In order to use this feature, you should output user messages
	  to /dev/ttyprintk or redirect console to this TTY.

	  If unsure, say N.

config VIRTIO_CONSOLE
	tristate "Virtio console"
	depends on VIRTIO && TTY
	# select: 表示当前config被选中时, 此选项也被选中
	select HVC_DRIVER
	help
	  Virtio console for use with hypervisors.

	  Also serves as a general-purpose serial device for data
	  transfer between the guest and host.  Character devices at
	  /dev/vportNpn will be created when corresponding ports are
	  found, where N is the device number and n is the port number
	  within that device.  If specified by the host, a sysfs
	  attribute called 'name' will be populated with a name for
	  the port which can be used by udev scripts to create a
	  symlink to the device.

//....

endmenu

将自己开发的内核代码加入到Linux内核中, 需要有3个步骤:

把自己编写的代码放到内核中合适的位置

把自己开发的功能增加到Linux内核的配置选项中, 使用户能够选中这项功能并编译

构建或修改Makefile, 根据用户的选择, 将相应的代码编译到最终生成的Linux内核中去

将 振动马达的驱动添加进内核为例 , 讲解配置机制的具体应用

添加步骤如下:

Step1: 将v_motor_driver.c拷到drivers/char/目录下

Step2: vi driver/char/Kconfig,在Kconfig文件结尾, 在endmenu的前面加入一个config选项

config 6818_VMOTOR
	bool "The Vibration motor driver ofr S5P6818"
	default y
	help
		The driver for Vibration motor device

endmenu

Step3: make menuconfig(添加配置选项)

Device driver —> character devices —> [*] The Vibration motor driver for S5P6818

Step4: vi driver/char/Makefile添加内容如下:

obj-$(CONFIG_6818_VMOTOR)		+= v_motor_driver.c

Step5: make (更新内核镜像到开发板)

Step6: 交叉编译 测试程序, 并放到开发板运行

arm-linux-gcc v_motor_test.c -o v_motor_test

./v_motor_test 1

Linux3.4.39内核移植

以Linux3.4.39内核在开发板上的移植为例, 学习如何从一个纯净的Linux内核编译、 配置得到适合在一个特定平台运行的镜像。 具体移植步骤如下:

  • 源码解压
  • 添加BSP
  • 修改顶层和BSPMakefile
  • 修改链接地址机器ID号并拷贝默认配置文件
  • 移植串口驱动支持
  • emmc驱动移植
  • ext4文件系统的支持移植
  • 内核配置、 编译

练习:

  • 添加键盘驱动到Linux-3.4.39
  • Linux-3.4.39内核移植
  • Linux-3.4.39内核LCD移植
  • Linux-3.4.39内核修改开机logo

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/617058.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

十个最适合论文写作的GPTs及其应用

文章目录 一、GPTs让一切皆有可能二、最适合论文写作的GPTs及其应用1、[Paper Search Engine](https://chat.openai.com/g/g-9v5gHG9Bo)2、[Academic Paper Specialist&#xff08;学术论文撰写专家&#xff09;](https://chat.openai.com/g/g-jryw3pfsH)3、[Paper Connect 论文…

DE2-115串口通信

目录 一、 内容概要二、 Hello Nios-II2.1 Nios-II编程2.1.1 硬件Ⅰ 搭建环境Ⅱ 编写代码 2.1.2 软件2.1.3 烧录Ⅰ硬件Ⅱ 软件 2.2 verilog编程 三、 心得体会 一、 内容概要 分别用Verilog和Nios软件编程, 实现DE2-115开发板串口输出“Hello Nios-II”字符到笔记本电脑串口助…

train_gpt2_fp32.cu - cudaCheck

源码 // CUDA error checking void cudaCheck(cudaError_t error, const char *file, int line) {if (error ! cudaSuccess) {printf("[CUDA ERROR] at file %s:%d:\n%s\n", file, line,cudaGetErrorString(error));exit(EXIT_FAILURE);} }; 解释 该函数用于检查CU…

基于gin框架的文件上传(逐行解析)

基于gin框架的文件上传(逐行解析)记录一下使用gin框架完成一个文件上传的功能&#xff0c;一下是实现该功能的代码&#xff0c;适合小白&#xff0c;代码都有逐行解释&#xff01; app.go: package routerimport ("chat/service""github.com/gin-gonic/gin&qu…

素数伴侣最大组合数

若两个正数之和为素数&#xff0c;则这两个数称之为“素数伴侣”。利用此特性找出给定数组中最大的“素数伴侣”对数。 (笔记模板由python脚本于2024年05月11日 18:17:40创建&#xff0c;本篇笔记适合熟悉基本编程且了解素数的coder翻阅) 【学习的细节是欢悦的历程】 Python 官…

LeetCode 题目 119:杨辉三角 II

作者介绍&#xff1a;10年大厂数据\经营分析经验&#xff0c;现任字节跳动数据部门负责人。 会一些的技术&#xff1a;数据分析、算法、SQL、大数据相关、python&#xff0c;欢迎探讨交流 欢迎加入社区&#xff1a;码上找工作 作者专栏每日更新&#xff1a; LeetCode解锁1000题…

iOS 提交项目到github(本地没有该项目)

流程简介 申请github账号&#xff08;如果有请跳过&#xff09; add repository创建项目开心的提交就好 具体过程 1. 申请账号&#xff08;本部分不做介绍&#xff0c;请自行研究&#xff09; 2. 如果有账号&#xff0c;按照下面图片依次操作就好 点击该图中的New reposito…

Qt开发常见报错大全与解决办法

下面的报错是我日常开发经常遇到的,对着下面的解决方法一招搞定就行了。 我们没必要都去记住,只需要见方抓药即可。 目前版本有27个常见报错,持续更新中。 常见报错 翻译不起作用 你可能改了类名字,但是.ts文件里没有跟着改。 Cannot send events to objects owned by a…

物联网杀虫灯—新型的环保杀虫设备

型号推荐&#xff1a;云境天合TH-FD2S】物联网杀虫灯是一种新型环保杀虫设备&#xff0c;其中风吸式太阳能杀虫灯作为其一种特殊类型&#xff0c;展现了独特的工作原理和优势。 风吸式太阳能杀虫灯以太阳能电池板为电源&#xff0c;白天储存电源&#xff0c;晚上为杀虫灯提供电…

在系统学习C语言之前所需要了解的知识

C语言常见概念 前言1. C语言是什么2. C语言的历史和辉煌3. 编译器的选择VS20223.1 编译和链接3.2 编译器的对比3.3 VS2022的优缺点优点&#xff1a;缺点&#xff1a; 4. VS项目和源文件、头文件介绍5. 第⼀个C语言程序6. main函数7. printf和库函数8. 关键字介绍9. 字符和ASCII…

[muduo网络库]——muduo库三大核心组件之EventLoop类(剖析muduo网络库核心部分、设计思想)

接着上一节[muduo网络库]——muduo库三大核心组件之 Poller/EpollPoller类&#xff08;剖析muduo网络库核心部分、设计思想&#xff09;&#xff0c;我们来剖析muduo库中最后一类核心组件&#xff0c;EventLoop类。 先回顾一下三大核心组件之间的关系。 接着我们进入正题。 Ev…

通过acl设置阻止数据包通过

实验拓扑和信息如图&#xff08;配置信息参考上一章内容&#xff09; acl设置代码 AR4 系统是视图下 acl 2000 rule 5 deny source 10.10.10.1 0 接口0视图下 数据接收时 traffic-filter inbound acl 2000 测试结果

【数据结构练习题】Map与Set——1.只出过一次的数字2.复制带随机指针的链表3.宝石与石头4.坏键盘打字

♥♥♥♥♥个人主页♥♥♥♥♥ ♥♥♥♥♥数据结构练习题总结专栏♥♥♥♥♥ ♥♥♥♥♥【数据结构练习题】堆——top-k问题♥♥♥♥♥ 文章目录 1.只出过一次的数字1.1问题描述1.2思路分析1.3绘图分析1.4代码实现2.复制带随机指针的链表2.1问题描述2.2思路分析2.3绘图分析2.4代…

Electron学习笔记(六)

文章目录 相关笔记笔记说明 七、系统5、托盘图标(1)、设置托盘图标(2)、托盘图标闪烁(3)、托盘图标菜单 6、剪切板(1)、写入剪切板(2)、读取剪切板 7、系统通知8、其他(1)、使用系统默认应用打开文件(2)、接收拖拽到窗口中的文件(3)、使用系统字体 相关笔记 Electron学习笔记&…

基于Java+SpringBoot+Mybaties-plus+Vue+elememt 驾校管理 设计与实现

一.项目介绍 系统角色&#xff1a;管理员、驾校教练、学员 管理员&#xff1a; 个人中心&#xff1a;修改密码以及个人信息修改 学员管理&#xff1a;维护学员信息&#xff0c;维护学员成绩信息 驾校教练管理&#xff1a;驾校教练信息的维护 驾校车辆管理&…

基于python的旅游爬虫可视化与实现

摘要 本项目为基于python的旅游爬虫可视化的设计与实现&#xff0c;项目以Web系统形式展示&#xff0c;利用Xpath爬虫爬取去哪儿网针对旅游业的需求&#xff0c;对国内热门旅游景点数据可视化系统&#xff0c;将爬取好的数据保存为CSV文件&#xff0c;再通过ORM框架导入MySQL数…

[muduo网络库]——muduo库Buffer类(剖析muduo网络库核心部分、设计思想)

接着之前我们[muduo网络库]——muduo库Socket类&#xff08;剖析muduo网络库核心部分、设计思想&#xff09;&#xff0c;我们接下来继续看muduo库中的Buffer类。其实Buffer在我的另一篇博客里面已经介绍过了深究muduo网络库的Buffer类&#xff01;&#xff01;&#xff01;&am…

十四、Redis Cluster集群

Redis Cluster是Redis提供的一个分布式解决方案&#xff0c;在3.0推出。Redis Cluster可以自动将数据分片分布到不同的master节点上&#xff0c;同时提供了高可用的支持&#xff0c;当某个master节点挂了之后&#xff0c;整个集群还是可以正常工作。1、为什么要用Redis Cluster…

Kafka 业务日志采集最佳实践

简介 Apache Kafka 是一个分布式流处理平台&#xff0c;主要用于构建实时数据流管道和应用程序。在收集业务日志的场景中&#xff0c;Kafka 可以作为一个消息中间件&#xff0c;用于接收、存储和转发大量的日志数据。将 Kafka 与其他系统&#xff08;如 Elasticsearch、Flume、…

AtCoder Beginner Contest 353 A~E(F,G更新中...)

A.Buildings 题意 给出若干个建筑&#xff0c;每个建筑有一个高度&#xff0c;问&#xff0c;从第二个建筑开始&#xff0c;比第一个建筑高的建筑中编号最小的是多少&#xff1f;如果不存在&#xff0c;输出-1. 分析 边输入边比较即可&#xff0c;如果循环结束还未找到&…