[架构之路-35]:目标系统 - 系统软件 - Linux OS内核模块与内核设备驱动程序,一切皆文件,Linux虚拟文件系统与统一设备模型

Posted 文火冰糖的硅基工坊

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[架构之路-35]:目标系统 - 系统软件 - Linux OS内核模块与内核设备驱动程序,一切皆文件,Linux虚拟文件系统与统一设备模型相关的知识,希望对你有一定的参考价值。

目录

前言:

第1章 嵌入式系统概述

1.1 什么是嵌入式系统

1.2 嵌入式系统的架构

第2章 内核驱动程序架构 

2.1 什么驱动程序

2.2 驱动程序的作用

2.3 Linux下的内核硬件设备驱动程序

第3章 Linux驱动工程师学习路径

3.1 成长之路与必备的知识

3.2 C语言基础

3.3 自底向上的构建Linux系统

3.4 字符设备的层次结构

3.5 网络驱动的层次结构

第4章 内核模块的动态加载

4.1 什么是内核模块

4.2 内核模块的动态加载与静态编译比较

4.3 内核模块的源代码示例

4.4 Linux内核模块程序结构

4.5 Makefile与内核模块的编译

5.6 内核模块的shell操作命令

第5章 一切皆文件,Linux虚拟文件系统与统一设备模型

5.1 什么是文件

5.2 文件的组织方式:树型结构与Linux虚拟文件系统

5.3 硬件设备的树型组织方式:设备树

5.4 设备也是文件

5.4 虚拟文件系统的用户空间接口

5.5 虚拟文件系统的内核程序

5.6 虚拟文件系统与Dev文件系统

5.7 虚拟文件系统与SYSFS/PROC


前言:

在实际嵌入式系统中,大多数时候并不需要修改和编写Linux操作系统的代码,而是需要为自己的嵌入式硬件系统编写Linux的设备驱动程序。这是因为,实际的不同应用的嵌入式系统,其硬件设备是不同的,Linux自带的设备驱动程序往往无法满足自身系统的需要。因此,会花几篇文章重点介绍一下Linux下的设备驱动程序。

第1章 嵌入式系统概述

1.1 什么是嵌入式系统

1.2 嵌入式系统的架构

第2章 内核驱动程序架构 

2.1 什么驱动程序

驱动程序一般指的是设备驱动程序(Device Driver),是一种可以使计算机设备进行相互通信的特殊程序。相当于硬件的接口,操作系统只有通过设备驱动程序这个接口,才能控制硬件设备的工作,假如某设备的驱动程序未能正确安装,便不能正常工作。

因此,驱动程序被比作“ 硬件的灵魂”、“硬件的主宰”、“硬件和系统之间的桥梁”等。

内存也是一种特殊的硬件设备,内存的驱动程序是Linux操作系统自带的,不需要设备厂家额外编写硬件驱动程序。内存的驱动程序包括:uboot、Linux对内存控制器的初始化、Linux内部的内存管理单元MMU。

应用程序只需要通过内存地址就可以直接访问普通的RAM内存。

对于FLASH内存,可以直接通过地址进行“读”访问,但必须要通过特定的驱动程序才能进行"写"访问。

2.2 驱动程序的作用

 

没有操作系统的单片机就是采用的上述架构。

 

Linux环境下,采用的就是上述架构。

2.3 Linux下的内核硬件设备驱动程序

(1)Linux设备驱动程序与Linux内核模块

 (2)Linux设备驱动程序在内核中的位置

 (3)Linux设备驱动程序的特点

第3章 Linux驱动工程师学习路径

3.1 成长之路与必备的知识

(1)嵌入式系统的组成

(2)硬件基础

  • 必须熟悉硬件电路的基本组成与原理
  • 熟悉SOC芯片的架构与工作原理
  • 熟悉特定硬件设备的硬件接口协议
  • 熟悉芯片手册

(3)内核编程与编程语言

  • Linux系统内核架构
  • Linux启动流程
  • 汇编语言基础
  • C语言基础
  • 数据结构基础

(4)Linux设备模型与设备树

(5)Linux驱动程序模型

(6)Linux驱动的主要思想

3.2 C语言基础

 

3.3 自底向上的构建Linux系统

(1)自底向上构建驱动程序,为应用程序提供访问特定硬件设备的服务。

(2)设备驱动程序的根基是硬件

(3)设备驱动程序运行在内核空间,以两种方式存在:

  • 可以动态插入和去除的内核模块
  • 与Linux内核的基础代码编译在一起

3.4 字符设备的层次结构

字符设备是Linux内核驱动中,种类最多的一种硬件设备。

3.5 网络驱动的层次结构

第4章 内核模块的动态加载

Linux的大部分的驱动程序是以内核模块的方式存在的。

4.1 什么是内核模块

Linux内核的整体架构本就非常庞大,其包含的组件也非常多,而我们怎样把需要的部分都包含在内核中呢?

如果把需要的所有功能都编译到Linux内核中。这会导致两个问题,一是生成的内核会很大,二是如果我们要在现有的内核中新增或删除功能,将不得不重新编译内核。

有没有另一种机制可使得编译出的内核本身并不需要包含所有功能,而这些功能需要被使用的时候,其对应的代码被动态地加载到内核中呢?

Linux提供了这样的机制,这种机制被称为模块(module)。

模块具有这样的特点:

  • 模块本身不被编译人内核映像,从而控制了内核的大小。
  • 模块一旦被加载,它就和内核中的其他部分完全一样。

4.2 内核模块的动态加载与静态编译比较

 

4.3 内核模块的源代码示例

(1)案例1

(2)案例2

/*
 * a simple kernel module: hello world
 * 
 * Copyright (C) 2022 liefyuan (liefyuan@qq.com)
 * 
 * Licensed under GPL v2 or later
 */
#include <linux/init.h>
#include <linux/module.h>

static int __init hello_init(void)

	printk(KERN_INFO "Hello World enter\\n");
	return 0;


module_init(hello_init);

static void __exit hello_exit(void)

	printk(KERN_INRO "Hello World exit\\n");

module_exit(hello_exit);

MODULE_AUTHOR("Lief Yuan <liefyuan@qq.com>");
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("A simple Hello World Module");
MODULE_ALIAS("a simplest module");

4.4 Linux内核模块程序结构

一个Linux内核模块主要由如下几个部分组成:

(1)模块加载函数:module_init
当通过insmod或modprobe命令加载内核模块时,模块的加载函数会自动被内核执行,完成本模块的相关初始化工作。

(2)模块卸载函数:module_exit
当通过rmmod命令卸载某模块时,模块的卸载函数会自动被内核执行,完成与模块加载函数相关的功能。

(3)模块许可证声明:MODULE_LICENSE
许可证(LICENSE)声明描述内核模块的许可权限,如果不声明LICENSE,模块被加载时,将收到内核被污染(Kernel Tainted)的警告。

(4)模块参数(可选):module_param
模块参数是模块被加载的时候可以传递给它的值,它本身对应模块内部的全局变量。

(5)模块导出符号(可选):export symbol
内核模块可以导出的符号(symbol,对应于函数或变量),若导出,其他模块则可以使用本模块中的变量或函数。

(6)模块作者等信息声明(可选):MODULE_DESCRIPTION

4.5 Makefile与内核模块的编译

(1)案例1

(2)案例2

KERNEL_DIR := "....."
CURRENT_PATH := $(shell pwd)
obj-m := led.o

build: kernel_modules

kernel_modules:
	$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) modules

clean:
	$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) clean
  • 第1行,指定内核源码文件目录,使用绝对路径
  • 第2行,CURRENT_PATH 表示当前路径,直接通过运行“pwd”命令来获取当前所处路径
  • 第3行,obj-m 表示将 led.c 这个文件编译为 led.ko 模块
  • 第8行,具体的编译命令,后面的 modules 表示编译模块,-C 表示将当前的工作目录切换到指定目录中,也就是 KERNERLDIR 目录。M 表示模块源码目录,“make modules”命令
  • 中加入 M=dir 以后程序会自动到指定的 dir 目录中读取模块的源码并将其编译为.ko 文件。

>> make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j16

5.6 内核模块的shell操作命令

Linux的模块,以两种方式进入内核:

  • 静态编译、连接
  • 动态编译、动态插入

(1)查看当前加载的全部模块

>> lsmod

(2)检测模块是否加载

>>  ismod

(3)加载新模块

>>  insmod

(4)尝试性加载模块

>> modprobe

modprobe和insmod类似,都是用来动态加载驱动模块的,区别在于modprobe可以解决load module的依赖关系,它是通过 /lib/modules/`uname -r`/modules.dep和modules.deo.bb文件来查找依赖关系的;而insmod不能解决依赖关系。

(5)显示模块信息

>> modinfo

(6)卸载模块

>>  rmmod

第5章 一切皆文件,Linux虚拟文件系统与统一设备模型

5.1 什么是文件

狭义的文件是指:存储计算机硬盘设备上的信息的组织方式,狭义的文件可以是文本文档图片程序等等。

广义的文件是指:存储计算机系统上的信息的组织方式,包括存储在硬盘设备上的信息,存储设备在内存中的信息,甚至可以是存在所有硬件设备中的信息。

Linux中文件,最初是狭义的文件内涵,后来扩展成了广义的文件内涵。

因此,在Linux中,有一句话是这样的:“一切皆文件:everything is file”。

5.2 文件的组织方式:树型结构与Linux虚拟文件系统

5.3 硬件设备的树型组织方式:设备树

一个复杂的嵌入式系统,会支持大量的硬件设备,是按照偏平的方式管理所有的硬件设备,还是分层的方式组织和管理硬件设备呢?

在Linux系统中,采用的是后者,即分层的方式组织硬件设备,在Linux系统中,称为设备树。

5.4 设备也是文件

在Linux中,硬件系统总的总线、总线上的设备,也是以文件的方式来组织和呈现的。

 (1)mnt:被映射成硬盘驱动器硬件设备

(2)dev:被映射成文件的硬件设备

(3)sys:被映射成文件的系统信息

(4)proc:被映射成文件的内核信息

(5)temp:内存中的临时性文件,掉电消失

(6)var:经常变化的各种多用户共享文件

(7)bin、sbin:相对稳定不变系统文件

5.5 虚拟文件系统的用户空间接口

5.6 虚拟文件系统的内核程序

5.7 虚拟文件系统与Dev文件系统

DevFS文件系统是挂接在虚拟文件系统之下的。

5.8 虚拟文件系统与SYSFS/PROC

SYSFS/PROC文件系统是挂接在虚拟文件系统之下的。 

以上是关于[架构之路-35]:目标系统 - 系统软件 - Linux OS内核模块与内核设备驱动程序,一切皆文件,Linux虚拟文件系统与统一设备模型的主要内容,如果未能解决你的问题,请参考以下文章

[架构之路-56]:目标系统 - 平台软件 - 总体架构概述

[架构之路-28]:目标系统 - 系统软件 - Linux OS内核功能架构图解内核构建内核启动流程

[架构之路-25]:目标系统 - 系统软件 - bootloader uboot内存映射与启动流程

[架构之路-21]:目标系统 - 系统软件 - 计算机系统架构计算机指令系统结构化程序与分层编程。

[架构之路-29]:目标系统 - 系统软件 - Linux OS内核以及内核驱动的调试技术

[架构之路-26]:目标系统 - 系统软件 - bootloader uboot使用方法常用命令