
Linux内核
文章平均质量分 56
关 峥
这个作者很懒,什么都没留下…
展开
-
Linux驱动---内核定时器
1、Linux内核定时器timer_list内核定时器是内核用来控制在未来某个时间点(基于jiffies)调度执行某个函数的一种机制2、timer_list 4.15之前的版本void callback(unsigned long arg)struct timer_list { /* * A1l fields that change during normal runtime grouped to the * same cacheline */ struct list_head ent原创 2021-08-27 16:16:54 · 247 阅读 · 0 评论 -
Linux驱动---platform进阶
1、platform架构硬件资源是在plat from_device里面用u32 num_resources(资源个数)和struct resource *resource(资源)来表示2、增加硬件信息flags:start和end:如果这个寄存器占四个地址,那么start:开始地址end:最后一个(开始地址+0x3)3、举例这是内核里面数组的一种赋值方式,[0]{} 表示数组第一个成员,里面的元素用.来赋值4、示例代码device:#include <linux/原创 2021-08-27 10:38:08 · 236 阅读 · 0 评论 -
Linux驱动---platform总线
1、什么是总线SOC上:数据总线、地址总线、控制总线物理总线:USB、I2C、SPI虚拟总线-Linux内核中:设备树依赖Platform2、为什么引入platform为了让硬件信息和驱动程序分离举例:串口驱动、网口驱动设备树3、内核如果表示总线每一个总线必须要定义有个叫bus_type的这样有个结构体变量,比如platform就要定义一个叫platform_bus_type这样一个结构体变量bus_register用来注册一个总线4、platform架构platform总线要原创 2021-08-25 20:33:10 · 273 阅读 · 0 评论 -
Linux驱动---信号驱动IO-sigio
1、Linux中的信号2、处理方式忽略:接收到信号后不做任何反应。捕获:用自定义的信号处理函数来执行特定的动作。默认:接收到信号后按系统默认的行为处理该信号。这是多数应用采取的处理方式。3、信号注册#include <signal.h>typedef void(*sighandler_t)(int);//参数的信号sighandler_t signal(int signum, sighandler_t handler);4、信号驱动IO工作过程fasync方法原创 2021-08-24 17:30:26 · 917 阅读 · 0 评论 -
Linux驱动---字符设备poll方法的实现
1、多路复用机制Select、poll、epollIO多路复用就是通过一种机制,一个进程就可以监视多个描述符,一旦某个描述符就位(一般是读就绪或者写就绪),能够通知程序进行相应的读写操作select、poll、epoll是Linux API提供的IO复用方式2、API原型selectselect系统调用是用来让我们的程序监视多个文件句柄的状态变化的select函数监视的文件描述符分3类:writefds、readfds、exceptfds调用后select函数会阻塞,直到有描述符就绪(有数原创 2021-08-24 16:02:54 · 643 阅读 · 0 评论 -
Linux驱动---等待队列
1、等待队列waitqueue(等待队列)就是内核用于管理等待资源的进程,当某个进程获取的资源没有准备好的时候,可以通过调用add_wait_queue()函数把进程添加到waitqueue中,然后切换到其他进程继续执行。当资源准备好,由资源提供方通过调用wake_up()函数来唤醒等待的进程2、定义定义头文件#include <linux/wait.h>定义实例wait_queue_head_t wq;init_waitqueue_head(&wq);3、阻塞接口原创 2021-08-23 17:12:52 · 699 阅读 · 0 评论 -
Linux驱动---IO模型
1、什么是IO在计算机系统中I/O就是输入和输出的意思,只要具有输入输出类型的交互系统都可以认为是I/O系统也可以说I/O是整个操作系统数据交换与人机交互的通道针对不同的操作对象,可以划分为磁盘I/O模型,网络I/O模型,内存映射I/O,Direct I/O,数据库等2、那么数据被Input到哪,Output到哪呢?Input(输入)数据到内存中,Output(输出)数据到IO设备(磁盘、网络等需要与内存进行数据交互的设备)中3、IO重要性4、五种IO模型阻塞式IO非阻塞式IOI/原创 2021-08-23 15:53:08 · 209 阅读 · 0 评论 -
Linux驱动---同步机制的总结
自旋锁和互斥体使用场合信号量和互斥体原创 2021-08-23 11:28:01 · 119 阅读 · 0 评论 -
Linux驱动---自旋锁死锁
1、自旋锁的死锁的两种情况(1)拥有自旋锁的进程A在内核态阻塞了,内核调度B进程,碰巧B进程也要获得自旋锁,此时B只能自旋转。而此时抢占已经关闭,(在单核条件下)不会调度A进程了,B永远自旋,产生死锁(2)进程A拥有自旋锁,中断到来,CPU执行中断函数,中断处理函数,中断处理函数需要获得自旋锁,访问共享资源,此时无法获得锁,只能自旋,获得死锁。2、死锁举例...原创 2021-08-22 17:28:04 · 1015 阅读 · 0 评论 -
Linux驱动---自旋锁
1、概念内核当发生访问资源冲突的时候,可以有两种锁的解决方案选择:一个是原地等待,一个是挂起当前进程,调度其他进程执行(睡眠)Spinlock是内核中提供的一种比较常见的锁机制,自旋锁的“原地等待”的方式解决资源冲突的,即:一个线程获取了一个自旋锁后,另外一个线程期望获取该自旋锁但获取不到 ,自能够原地“打转”(忙等待)自旋锁的优点:自旋锁不会使线程状态发生切换,一直处于用户态,即线程一直都是active的;不会使线程进入阻塞状态,减少不必要的上下文切换,执行速度快。非自旋锁在获取不到锁的时原创 2021-08-22 17:02:14 · 360 阅读 · 0 评论 -
Linux驱动---信号量
1、信号量概念信号量又称为信号灯它是用来协调不同进程间的数据对象的,而最主要的应用是共享内存方式的进程间通信。本质上,信号量是一个计数器,它用来记录对某个资源(如共享内存)的存取状况。2、Linux下几种的信号量3、核心操作·P·如果有一个任务想要获得已经被占用的信号量时,信号量会将其放入一个等待队列然后让其睡眠·V·当持有信号量的进程将信号释放后,处于等待队列中的一个任务将被唤醒(因为队列中可能不止一个任务),并让其获得信号量。4、初始化#include <linux/se原创 2021-08-22 15:20:06 · 112 阅读 · 0 评论 -
Linux驱动---内核互斥锁
1、互斥体概述互斥概念:只能有一个人使用信号量是在并行处理环境中对多个处理器访问某个公共资源进行保护的机制,Muter用于互斥操作。mutex的语义相对于信号量要简单轻便一些,在锁争用激烈的测试场景下,Mutex比信号量执行速度更快,可拓展性更好,另外Mutex数据结构的定义比信号量小2、Mutex(互斥体)的使用注意事项·同一时刻只有一个线程可以持有Mutex·只有锁持有着可以解锁,不能在一个进程中持有Mutex,在另外一个进程中释放它·不允许递归的加锁和解锁·当进程持有Mutex时,原创 2021-08-21 17:13:42 · 1001 阅读 · 0 评论 -
Linux驱动---原子操作
概念原子操作是指不被打断的操作,即它是最小的执行单位最简单的原子操作就是一条条的汇编指令(不包括一些伪指令,伪指令会被汇编器解释成多条汇编指令)定义在Linux中原子操作对应的数据结构为atomic_t,定义如下:typedef struct{ int counter;}atomic_t;常用操作1赋值操作#define atomic_set(v,i) (((v)->counter) = (i))读操作#define atomic_read(v,i) (*(volatil原创 2021-08-21 15:50:38 · 568 阅读 · 0 评论 -
Linux驱动---一个有问题的并发控制
举例要求:1、多个进程打开同一个设备的情况2、如果设备忙(有进程打开)返回-EBUSY3、不用互斥机制用flag来实现,分析一下可能出现的问题实例代码:用flag来区别是否忙,好像看起可行,但是有问题...原创 2021-08-20 17:35:13 · 70 阅读 · 0 评论 -
Linux驱动---并发机制
1、并发多个执行单元同时进行或多个执行单元微观串行执行,宏观并行执行。微观串行,宏观并行:理解成把时间轴放大以后,各个任务是串行执行,然后每个任务执行一定的时间片,执行完后由调度系统调度到另一个任务去执行。因为CPU的速度很快,所以宏观人看来是并行执行。2、 竞态并发的执行单元对共享资源(硬件资源和软件上的全局变量)的访问而导致的竞态状态3、临界资源临界资源多个进程访问的资源临界区多个进程访问的代码段4、并发场合并发场合1单CPU之间进程间的并发时间片轮转,调度进程。如:A原创 2021-08-20 17:12:56 · 212 阅读 · 0 评论 -
Linux驱动---如何同时支持多个次设备
1、原理一个驱动要支持两个次设备,两个次设备之间比较类似(例如com0、com1),区别就是地址不同。所以我们去操作这些不同的次设备时,去访问不同的基地址就行,但是我们的read、write等函数没有关于次设备的信息(inode),通过其他参数传递信息也不合适,所以我们把设备间有区别的信息放在file参数里面ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);在open里面怎么区别不同设备呢?open里面两个参数,i.原创 2021-08-19 20:50:23 · 2522 阅读 · 1 评论 -
Linux驱动---进程、文件描述符、file、inode、设备号关系
1、文件、inode每创建一个文件,都有一个inode;可以通过inode找到设备号,然后找到cdv;驱动只有一份,存在多个次设备号的时候,得由驱动来区分不同的次设备,怎么区别呢?无论是哪个次设备,都要通过file_operations里面的open来打开int (*open) (struct inode *, struct file *);open会传递一个inode参数,所以驱动可以据此分辨不同次设备2、进程与文件描述符当我们的进程去打开一个文件的时候,内核是怎么来维护这个操作的呢l原创 2021-08-19 13:15:15 · 1200 阅读 · 0 评论 -
Linux驱动---字符设备ioctl接口
1、为什么要引入ioctl2、应用层系统调用3、内核接口4、调用关系5、cmd及封装命令封装命令这些宏定义,内核空间已经提供给我们,我们直接调用就可从根目录找,有一个Documentation/ioctl/ioctl-number.txt,在这个目录里面有一些说明文档,里面放的一些内核已经使用过的一些设备类型(type),有一些是已经被占用;这时我们写0,1,2这些就会和内核冲突(但是不太影响,也能用)6、任何检测命令、地址的正确性?头文件:#ifndef _BEEP_原创 2021-08-18 19:50:20 · 360 阅读 · 0 评论 -
Linux驱动---增加read、write接口
1、为什么要加我们在编写驱动的时候,尤其是字符设备驱动,往往给这个驱动编写一些应用程序,我们最常用的两个就是read和write。在Linux里面一切皆文件,所以我们可以通过read或write这个文件来操作这个驱动readfd:对应VFS层的file;当前进程打开一个文件以后,这个fd就会唯一的分配给它,如果再重新打开一次的话,fd也会不同。后续如果我们要操作这个文件,我们只需要填充整个fd即可,内核会根据这个fd找到这个filebuf:读取数据存放的缓冲区;一定是用户空间的一个地址coun.原创 2021-08-18 13:35:46 · 838 阅读 · 0 评论 -
Linux驱动---自动创建设备节点
1、自动创建设备节点需要依赖于几个函数:函数device_create差不多就是将一些硬件信息什么的导入用户空间,创建一个设备节点2、代码#include <linux/init.h>#include <linux/module.h>#include <linux/kdev_t.h>#include <linux/fs.h>#include <linux/cdev.h>static int major = 237;sta.原创 2021-08-04 22:35:13 · 2878 阅读 · 0 评论 -
Linux驱动---字符设备注册
1、cdev函数cdev_init() 是初始化cdev结构体变量,其实就是吧file_operations这个结构体的成员变量填充给cdev里面的ops,就把file_operations的地址填充给它cdev_add() 把cdev这个结构体真真正正的注册到我们结构体里面,把cdev串在相应链表里面cdev_del() 注销一个cdev2、示例#include <linux/init.h>#include <linux/module.h>#include <原创 2021-07-30 11:26:01 · 140 阅读 · 0 评论 -
Linux驱动---字符设备注册-更简单的方式
1、字符设备驱动编写步骤2、更简单的注册static int register_chrdev(unsigned int major, const char *name, const struct file_operations *fops)static void unregister_chrdev(unsigned int major, const char *name)3、编写实例:驱动函数#include <linux/hdreg.h>#include <l原创 2021-07-29 16:59:18 · 462 阅读 · 0 评论 -
Linux驱动---字符设备架构
1、内核态里面的架构设备号是在内核态里进行申请,那么设备号是怎么进行维护的呢,有很重要的一个全局变量叫做chadevsstatic struct char_device_struct { struct char_device_struct *next; unsigned int major; unsigned int baseminor; int minorct; char name[64]; struct cdev *cdev; /* will die */} *chrdevs[CHR原创 2021-07-24 22:37:12 · 152 阅读 · 0 评论 -
Linux驱动---字符设备号
在这个知识点之前我们先补充一个知识点:modinfo可以查看一个模块(.ko文件)里面的一些信息1、设备分类2、设备号字符设备是同一个架构,我们怎么区分这些字符设备呢,用主设备号和次设备号从编程角度来看,设备号就是一个32位无符号整形值:高20位:主设备号,低12位:次设备号如果我们的主设备号是50,次设备号是1,我们需要做移位操作:50<<20 | 1但是我们不需要哈,内核里面有申请设备号的函数:3、查看设备号在/proc/device里面每个设备号对应一个名原创 2021-07-24 16:17:17 · 889 阅读 · 1 评论 -
Linux驱动---加载模块传参
(这只是一套传参函数中的一个)类型其他原型实例先不带参数加载卸载模块打印的就是原文件里面的 whom=hello,var=1带参数加载模块sudo insmod hello.ko var_out=2 whom="guanzheng"加载和卸载打印信息:我们看到参数就发生了变化sysfs–系统文件系统内核里面重要的资源和信息,它会通过文件的形式呈现给我们我们通过module_param()导出的变量它会创建一个文件节点在/sys/module下面(这里面每个模块都有个.原创 2021-07-24 15:22:32 · 279 阅读 · 0 评论 -
Linux驱动---符号导出
1、什么是符号?在Linux中所有的符号都会放在一个表里面,模块中如果需要方位全局变量或者函数,就从表里面去找Ubuntu是定制好操作系统2、实例我们加载两个模块,模块B里面调用模块A里面的变量a:b:first:先make和加载a模块(因为b依赖于a里的东西,所以先加载a)second:把make后的 Module.symvers 文件复制到b模块目录third:make和加载b模块我们发现b模块打印信息中就出现了a中的变量注意:假设我们来先卸载a会提原创 2021-07-23 21:45:45 · 205 阅读 · 0 评论 -
Linux驱动---Makefile
基于hello.c的Makefile:(在我的《Linux驱动—模块化编程》)执行模块的Makefile要进来 三次!!!!!!!!第一次:KERNELRELEASE是内核源码树的一个变量,我们第一次敲make的时候,其实它是没有的,为空,逗号右边也没有填东西,也为空故而 ifneq ($(KERNELRELEASE),)的结果“真”,执行 else 的语句:进入else后:KDIR是一个内核的环境变量,绝对路径 ,“:=”为赋值变量$(shell uname -r)取字符串拼接起来让原创 2021-07-22 22:21:19 · 3656 阅读 · 0 评论 -
Linux驱动---模块化编程实例
头文件这个头文件和平时见的头文件不同,这个程序是放在内核空间的,像include<stdio.h>这种头文件是在用户空间里调用,内核空间和用户空间是两种不同的地址空间(应用程序所看到的地址一般是用户空间的虚拟地址)MODILE_LICENSE(“GPL”);和MODILE_AUTHOR(“ZJY”);“GPL”:这玩意就是一个证书:①免费使用,不侵权;②基于GPL,开发出的新东西也必须开源MODILE_AUTHOR(“ZJY”):作者module_init(hello_init);和.原创 2021-07-22 19:24:47 · 179 阅读 · 0 评论