• 一文深入理解Linux驱动整理


    【好文推荐】

    深入学习Linux内核(二)体系结构简析

    virtio-net 实现机制【一】(图文并茂)

    浅析linux内核网络协议栈--linux bridge

    深入理解SR-IOV和IO虚拟化

    一文了解Linux上TCP的几个内核参数调优

    字符设备与块设备

    字符设备:字符设备是个能够像字节流(类似文件)一样被访问的设备,由字符设备驱动程序来实现这种特性。

    字符设备驱动程序通常至少实现open,close,read和write系统调用——file_operation

    块设备:和字符设备类似,块设备也是通过/dev目录下的文件系统节点来访问。块设备上能够容纳文件系统,如:u盘,SD卡,磁盘等。

    VFS:

    是对各种具体文件系统的一种封装,用户程序访问文件提供统一的接口。例如: EXT2,FAT,NFS等

    系统架构—Cache:

    当用户发起文件访问请求的时候,首先回到Cache中寻址文件是否被缓存了,如果在Cache,则直接从cache中读取。如果数据不在缓存中,就必须要到具体的文件系统中读取数据了。

    Mapping Layer:

    首先确定文件系统的block size,然后计算所请求的数据包含多少个block. 调用具体文件系统的函数来访问文件的inode结构,确定所请求的数据在磁盘上的地址。

    Generic Block Layer:

    Linux内核把块设备看做是由若干个扇区组成的数据空间,上层的读写请求在通用块层被构造成一个或多个bio结构。 I/O Scheduler Layer,I/O调度层负责采用某种算法(如:电梯调度算法)将I/O操作进行排序。

    电梯调度算法的基本原则:如果电梯现在朝上运动,如果当前楼层的上方和下方都有请求,则先响应所有上方的请求,然后才向下响应下方的请求;如果电梯向下运动,则刚好相反。

    打印驱动log

    查看驱动模块中打印信息应该使用什么命令?如何查看内核中已有的字符设备的信息?如何查看正在使用的有哪些中断号?

    1) 查看驱动模块中打印信息的命令:dmesg

    2) 查看字符设备信息可以用lsmod 和modprobe,lsmod可以查看模块的依赖关系,modprobe在加载模块时会加载其他依赖的模块。

    3) 显示当前使用的中断号cat /proc/interrupt

    copy_to_user()和copy_from_user()

    copy_to_user()和copy_from_user()主要用于实现什么功能?一般用于file_operations结构的哪些函数里面?

    由于内核空间和用户空间是不能互相访问的,如果需要访问就必须借助内核函数进行数据读写。

    copy_to_user():完成内核空间到用户空间的复制

    copy_from_user():是完成用户空间到内核空间的复制

    主设备号和次设备号

    主设备号:主设备号标识设备对应的驱动程序。虽然现代的linux内核允许多个驱动程序共享主设备号,但我们看待的大多数设备仍然按照“一个主设备对应一个驱动程序”的原则组织

    次设备号:次设备号由内核使用,用于正确确定设备文件所指的设备。依赖于驱动程序的编写方式,我们可以通过次设备号获得一个指向内核设备的直接指针,也可将此设备号当作设备本地数组的索引

    DMA的作用

    DMA:是一种无须CPU的参与就可以让外设与系统内存之间进行双向数据传输的硬件机制,使用DMA可以使系统CPU从实际的I/O数据传输过程中摆脱出来,从而大大提高系统的吞吐率.

    中断服务

    调用过程:外部中断产生->发送中断信号到中断控制器->通知处理器产生中断的中断号,让其进一步处理。即处理器收到来自中断控制器的中断处理请求,保存中断上下文,跳转到中断对应的处理处,(快速完成中断中断上半部,中断上半部返回后执行中断下半部),中断处理函数返回时恢复现场。

    1. 中断处理例程应该尽量短,把能放在后半段(tasklet,workqueue等)的任务尽量放在后半段。
    2. 中断服务程序中不能有阻塞操作。中断期间是完全占用CPU的(即不存在内核调度),中断被阻塞住,其他进程将无法操作; tasklet 与 workqueue 前者是原子操作,不可休眠。后者类似于线程操作,比较随意。 中断不可以被阻塞:

    1. 中断处理的时候,不应该发生进程切换。中断不是一个task,无法被唤醒。所有的wake_up_xxx都是针对某个进程而言的
    2. 中断时则保存的进程上下文就不是当前的进程context了.无法恢复
    3. 中断handler会使用被中断的进程内核堆栈,但不会对它有任何影响,因为handler使用完后会完全清除它使用的那部分堆栈,恢复被中断前的原貌。
    4. 处于中断context时候,内核是不可抢占的。因此,如果休眠,则内核一定挂起。

    系统启动过程

    • bootRom

    1)初始化emmc,把preloader放进去执行

    DRAM: 动态存储(不停的刷新电路,否则数据消失)。空间大,读写比较慢

    SRAM: 静态存储。空间小,读写比较快。

    • preloader

    1)初始化DRAM

    2)USB、串口等初始化 --> 工具

    3)把uboot放进去,跳转执行

    • uboot

    1)LCM显示,USB、UART、i2c、gpio等初始化操作

    2)MMU初始化

    3)跳转到kernel

    • kernel的一系列操作
    • 用户空间的第一个init操作

    并发和同步

    • 原子操作
    • 信号量 初始值为1,则为互斥锁
    • 读写信号量
    • 自旋锁

    内存机制

    通过页管理资源。

    三个区: 前16M,DMA使用; 16~896M 正常存储; 大于部分 高端内存

    分配flag:

    GFP_KERNEL 用于睡眠上下文

    GFP_ATOMIC 不会引起睡眠

    GFP_USER 给用户空间分配内存

    kmalloc 物理连续内存;vmalloc 物理不连续内存; alloc_pages 2^n个连续物理页

    Mmap函数

    内核函数mmap的实现原理,机制?

    mmap函数实现把一个文件映射到一个内存区域,从而我们可以像读写内存一样读写文件,他比单纯调用read/write也要快上许多。

    mmap实现共享内存也是其主要应用之一,mmap系统调用使得进程之间通过映射同一个普通文件实现共享内存。

    同步/异步 阻塞/非阻塞 并发和并行、串行 同步和互斥

    同步:

    所谓同步,就是在发出一个"调用"时,在没有得到结果之前,该“调用”就不返回。但是一旦调用返回,就得到返回值了。换句话说,就是由“调用者”主动等待这个“调用”的结果。

    异步:

    异步则是相反,调用在发出之后,这个调用就直接返回了,所以没有返回结果。换句话说,当一个异步过程调用发出后,调用者不会立刻得到结果。而是在"调用"发出后,"被调用者"通过状态、通知来通知调用者,或通过回调函数处理这个调用。

    阻塞调用是指:调用结果返回之前,当前线程会被挂起。调用线程只有在得到结果之后才会返回。

    非阻塞调用指在不能立刻得到结果之前,该调用不会阻塞当前线程。

    并发:一个CPU上多个进程。 并行:多个CPU协作。 串行:单片机

    同步:

    是指散步在不同任务之间的若干程序片断,它们的运行必须严格按照规定的某种先后次序来运行,这种先后次序依赖于要完成的特定的任务。

    互斥:

    是指散步在不同任务之间的若干程序片断,当某个任务运行其中一个程序片段时,其它任务就不能运行它们之中的任一程序片段,只能等到该任务运行完这个程序片段后才可以运行

    进程与线程

    1).进程是系统资源分配的基本单位,线程是cpu调度执行的基本单位。一个进程中包含多条线程。

    2)多进程中,进程之间的资源都是独立的,同一进程中的多份线程资源共享。

    3)线程更加轻便小巧,从而使线程调度、切换都比线程效率高。进程切换效率低,代价大;线程切换效率高,代价小

    4)进程

    共享:代码段、公共数据、进程目录、进程ID

    私有:地址空间、堆、栈、全局变量、寄存器

    线程

    共享:堆、地址空间、全局变量、静态变量

    私有:线程栈、寄存器、程序寄存器

    多进程之间资源不共享的,只有父子进程共享在fork()之前打开的文件描述符;多线程之间资源共享,只有栈区不共享

    FIQ与IRQ的区别

    FIQ fast interrupt request,即快速中断请求

    FIQ和IRQ(外部中断模式)之间有很大的区别:

    • FIQ模式必须尽快处理,处理结束后离开这个模式;IRQ模式可以被FIQ模式中断,但IRQ不能中断FIQ模式;
    • FIQ模式必须禁用中断;如果一个中断例程必须重新启用中断,应使用IRQ模式而不是FIQ模式

    Kernel Panic常见原因以及解决方法

    • 中断执行异常
    • 内核堆栈溢出,或者指针异常访问时,会出现kernel panic。
    • 内核陷入死锁状态

    分析:

    1) 加打印复现

    2) 在可疑的地方,调用dump_stack()函数

    3) crash工具

    oops故障解决: 加log打印。辅助工具objdump来帮助分析问题。objdump可以用来反汇编

    linux中内核空间、用户空间的区别

    <先把系统调用号传递给内核,最后拉起一次软中断,自此cpu进入内核态运行。>

    Linux系统采取两级保护机制,对应两种不同的操作权限,内核空间权限高于用户空间权限。

    内核空间和用户空间都有属于自己的虚拟空间。在32位系统中,cpu最高有32位寻址范围,即对应4G空间,内核空间被划分在高1G虚拟空间,用户空间在低3G。

    普通应用程序运行在用户空间,执行一些贴近用户的低权限操作;系统内核程序、操作硬件的驱动程序等一些要求高级权限的程序运行在内核空间。

    用户空间程序不能直接访问内核空间的数据,内核空间程序也一样不能直接访问属于用户进程空间的数据,用户空间和内核空间之间的通信必须通过一些特定的方法。

    用户空间与内核通信方式

    1)系统调用。用户空间进程通过系统调用进入内核空间,访问指定的内核空间数据。

    2)驱动程序。用户空间进程可以使用封装后的系统调用接口访问驱动设备节点,以和运行在内核空间的驱动程序通信。

    3)proc文件系统。proc文件系统的主要功能是在内核空间提供一套机制为用户空间方便的查询,查看,设置内核信息,多用于查询类操作。

    4)共享内存mmap。在代码中调用接口,实现内核空间与用户空间的地址映射,在实时性要求很高的项目中为首选,省去拷贝数据的时间等资源,但缺点是不好控制。

    5)copy_to_user()、copy_from_user(),是在驱动程序中调用接口,实现用户空间与内核空间的数据拷贝操作,应用于实时性要求不高的项目中

    附带俩知识:

    驱动中操作物理绝对地址为什么要先ioremap?

    ioremp是内核中用来将外设寄存器物理地址映射到主存上去的接口,即将io地址空间映射到虚拟地址空间上去,便于操作。因为保护模式下的cpu只认虚拟地址

    写一段 C 代码让程序跳转到地址是 0x8000 0000 的位置执行

    ((void()(void))0x100000)();或者((void(*)(void))0x100000)();

     

  • 相关阅读:
    Django后端开发——mysql数据库连接遇到的问题及解决
    can sdo 报文
    2024年保安员证考试题库
    揭秘阿里双十一《百亿级并发系统设计》实战教程,实在是太香了
    Android-自定义三角形评分控件
    docker 安装 Node-RED
    学会Spring MVC文件上传、下载和JRebel的使用
    MyBatis学习:动态SQL中<where>标签的使用
    js如何把数组网页元素按分隔符返回字符串?document.getElementsByClassName(“class1“)
    阶段性总结
  • 原文地址:https://blog.csdn.net/m0_74282605/article/details/128202808