自定义博客皮肤VIP专享

*博客头图:

格式为PNG、JPG,宽度*高度大于1920*100像素,不超过2MB,主视觉建议放在右侧,请参照线上博客头图

请上传大于1920*100像素的图片!

博客底图:

图片格式为PNG、JPG,不超过1MB,可上下左右平铺至整个背景

栏目图:

图片格式为PNG、JPG,图片宽度*高度为300*38像素,不超过0.5MB

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

-+
  • 博客(60)
  • 资源 (1)
  • 收藏
  • 关注

原创 设备树节点和struct device的关系及示例

设备树节点-> device_node-> device-> i2c_client;一次呈包含关系。

2024-07-18 16:50:07 702

原创 简述linux通知链机制

Linux内核中各个子系统相互依赖,当其中某个子系统状态发生改变时,有时需要使用一定的机制告知使用其服务的其他子系统,以便其他子系统采取相应的措施。为满足这样的需求,内核实现了事件通知链机制(notification chain)。通知链只能用在各个子系统之间(当然一个子系统内部也可以使用),而不能在内核和用户空间进行事件的通知。事件通知链表是一个事件处理函数的列表,每个通知链都与某个或某些事件有关,当特定的事件发生时,就调用相应的事件通知链中的回调函数,进行相应的处理。

2024-07-12 16:58:11 332

原创 硬件中断号怎么跟irq映射的?

内核启动由这两个函数,完成中断的的初始化,包括硬件中断号和virq的映射。

2024-07-04 16:40:35 362

原创 linux内核编译流程、驱动加载顺序

根据这个展开 vmlinux-deps := arch/$(SRCARCH)/kernel/vmlinux.lds (head-y init-y core-y libs-y2 drivers-y net-y virt-y libs-y1)上面的xxxx-y就是,每个目录生成的各.o文件集合,会被打包成一个个built-in.a。

2024-07-03 17:37:48 455

原创 device_node和platform_device的生成流程

有介绍DT_MACHINE_START的一些初始化操作,匹配上就会在后续的初始化中调用DT_MACHINE_START的成员来初始化系统的设备树,时钟,中断等。

2024-07-01 16:05:23 645

原创 scatterlist的相关概念与实例分析

scatterlist用来描述一块内存,sg_table一般用于将物理不同大小的物理内存链接起来,一次性送给DMA控制器搬运page_link:(1).对于chain sg 来说,记录下一个 SG 数组的首地址,并且用bit[0] 和 bit[1] 来表示是chain sg 还是 end sg;(2).对于 end sg 来说,只有bit[1] 为1,其他无意义;(3).对于普通 sg 来说,记录的是关联的内存页块的地址;

2024-06-28 15:44:40 1115

原创 cache一致性的概念和场景

Cache是由cache Line组成 它是 CPU 从内存读取的基本单位;数据在Cache和内存之间传输时,不是一个字节一个字节进行传输的,而是以缓存行(Cache Line)为单位进行传输的。不同CPU的Cache line大小可能不同,典型的CPU Cache line大小是64个字节而cache Line 是由各种标志(Tag)+ 数据块(Data Block)组成;但是怎么写呢?:如果命中,直接将数据写到cache和主存;如果没命中,直接写到主存:写到Cache line,标记为脏;

2024-06-25 14:52:02 634

原创 内核模块的各种概念及示例

在Linux中,所有标识为__init的函数如果直接编译进入内核,成为内核镜像的一部分,在连接的时候都会放在.init.text这个区段内--#define _ _init _ _attribute_ _ ((_ _section_ _ (".init.text")))所有的__init函数在区段.initcall.init中还保存了一份函数指针,在初始化时内核会通过这些函数指针调用这些__init函数,并在初始化完成后,释放init区段(包括.init.text、.initcall.init等)的内存。

2024-06-20 11:28:06 796

原创 内核启动时的中断和时钟的初始化流程

内核通过start_kernel从汇编进入c世界,在用serup_arch设置体系架构的时候,会返回当前机器的machine_desc;然后init_IRQ和time_init来初始化中断。时钟子系统mdesc = setup_machine_fdt(atags_vaddr) //返回成功匹配的machine_desc//赋值给全局变量machine_desc,以供后续初始化等操作使用,比如给下面的中断和时钟子系统使用......init_IRQ......time_initelse。

2024-06-19 11:22:41 811

原创 gpio-0设置成输出失败的原因

影响代码如下:of_property_read_u32返回0是找到节点里的属性了,返回负数是没找到;而且没对gpio_request做返回判断,如果有冲突的情况,这个地方还设置了gpio0为输入---那就异常了,该输出的gpio,被异常设置成了输入。但是后面其他驱动,使用of_property_read_u32获取设备树节点的属性时,没去判断返回值;而直接使用参数返回的0,导致gpio-0又被设置成了输入。修改如下:所以对接口的返回值做判断很重要,能避免一些奇葩的bug。正常的如下,gpio显示为输出。

2024-06-14 17:54:59 247

原创 poweroff, reboot流程

当传递特定的magic值如 LINUX_REBOOT_CMD_POWER_OFF时,内核会执行关机并尝试触发硬件层面的电源关闭。poweroff /halt /reboot操作通常由用户空间的systemd或其他初始化系统通过sys_reboot()系统调用触发。poweroff流程,pm_power_off函数被各平台赋值到具体函数,比如通过操作PMIC来实现关机。reboot流程,arm_pm_restart函数可能被具体平台赋值到具体函数,比如操作WDT实现重启。

2024-06-06 15:22:16 248

原创 简述等待队列的概念和实例

就是创建队列头,和队列元素;然后将元素加入队列;然后让出调度器;等资源满足,就将该元素从队列移除for (;;) {break;break;schedule();内核封装了一些步骤,统一简化使用方法for (;;) {break;schedule();

2024-06-03 11:20:41 420

原创 Kprobe实现原理

上面这个函数我们可以看到,会调用kprobe的pre_handler和post_handler,这两个函数被我们实现好,装填进kprobe,并用register_kprobe注册到kprobe子系统;kprobe其实就是将某个要检测的指令备份,再替换成int3(x86)或者未定义指令(arm)来触发异常,再调用对应体系的异常处理函数来执行我们自定义的hook,执行完我们自定义的hook,再将备份的指令放回原来的位置继续往下执行。替换成未定义指令后,就会触发的未定义指令异常处理函数。

2024-05-29 17:17:21 305

原创 qemu使用简介

【代码】qemu使用简介。

2024-05-29 16:40:38 209

原创 ARM64的KASLR分析

上述操作执行完_text变了,kimage_vaddr(_text - TEXT_OFFSET)也就跟着变了,kimage_voffset也就成了虚拟地址转物理地址函数的实际偏移了,就可以通过start_kernel进内核的C语言部分了。3.分配完的地址跟编译时的链接地址不一样了,所以需要重定位内核镜像---对符号地址进行重定位,校正内核代码的符号寻址,以此确保内核代码的正常执行。,介绍了kimage_voffset,就是运行时的内核的虚拟地址跟物理地址映射的真实偏移,不管经过与否kaslr。

2024-05-28 17:02:04 328

原创 linux内核符号表

所以arm架构,如果是1/3的内核和用户空间的分配的话;内核在编译过程中生成的System.map与proc/kallsyms的区别在于System.map是在编译阶段生成的内核符号表,我们可以称为静态Linux内核符号表,而proc/kallsyms方式看到的是在内核启动后生成的动态符号表。对于ARM构架的设备,模块挂载后,模块中包含的函数和静态变量的虚拟地址不在3G(0xC0000000)以上,而是3G以下一点的位置,可能以0xBF000000开始。直接虚拟地址偏移 + 物理内存起始地址。

2024-05-24 16:50:43 282

原创 sdhci怎么通过dma/pio传输数据

sdio设备驱动调用sdio_memcpy_toio/sdio_memcpy_fromio来读写sdio设备,都会调用到host->ops->request(host, mrq),其框架如下。如果是dma传输完成中断,就会走sdhci_set_sdma_addr重新设置需要传输数据块的dma地址。对于adma就要通过dma_map_sg对一个sgl做映射,并返回sg_count。通过for_each_sg遍历每个sg,并通过__sdhci_adma_write_desc将描述符依次写进对应寄存器。

2024-05-17 17:47:50 426

原创 runtime pm的实例分析

他们会来执行设备驱动实现的对应操作;比如在drivers/spi/spi_qsd.c中,unprepare_transfer_hardware接口会去通过pm_runtime_put_autosuspend,去调用pm_dev_ops的runtime_suspend成员。比如在drivers/spi/spi_qsd.c中,prepare_transfer_hardware接口会去通过pm_runtime_get_sync,去调用pm_dev_ops的runtime_resume成员。

2024-05-15 11:23:09 935

原创 pci设备枚举流程

PCI桥设备:由于电子负载限制,每条PCI总线上可以挂载的设备数目是有限的因此使用了一种特殊的设备,即PCI-PCI桥设备将两条独立的PCI总线连接起来,PCI-PCI桥设备简称PCI桥。PCI设备:遵循PCI规范,工作在PCI局部总线环境下的设备。通讯:PCI设备也有自己内存空间和IO空间,这些空间被映射到CPU的内存空间和IO空间,在映射之后,PCI设备上的物理资源“变成”了CPU的本地资源。主桥设备:和CPU以及内存连在一起的Host-PCI桥设备为主桥设备,主桥设备引出的总线也称为PCI根总线。

2024-05-13 09:22:48 365

原创 linux系统休眠时的中断操作

无论是gpio控制器,还是其他外设控制器,捕获到中断,会发给gic;gic根据mask决定是否分发给cpu;cpu如果调用local_irq_disable,就不会来响应中断信号。linux进入休眠,中断相关操作如下:1.会打开中断控制器的irq_set_wake函数(有些架构有这个实现;有些架构,打开中断就有这个功能),来一一打开,那些标记了唤醒功能的中断的唤醒功能;2.然后关闭其他没标记唤醒功能的中断3.打开cpu的中断响应对应代码如下int error;if (error)

2024-05-08 16:13:24 445

原创 pinctrl驱动详解

pinmux_enable_setting调用pinctrl_ops->get_group_pins获取对应的group,及其里面的pin信息;还是从pcs_parse_one_pinctrl_entry和pcs_parse_pinconf看到 ----每个state会有两个type的map;pinctrl主机驱动会用devm_pinctrl_register注册时,放进去的那三个ops(下面的代码前几行就可以看出)来真正的配置pin的复用功能和电气属性;根据从设备树获取的pinctrl的信息;

2024-04-30 14:57:55 450

原创 dwc3控制器是怎么处理otg

我们直接看支持otg的dwc3是怎么处理otg的,从设备开始看驱动,usb3_0的这个节点一般就是厂商自己定义的,主要包括中断,一般用于vbus检测,usb的插拔情况;为高就是DWC3_OTG_ROLE_DEVICE,为低就是DWC3_OTG_ROLE_HOST;xhci_init_driver将通用的xhci_hc_driver,赋值给xhci_plat_hc_driver;dwc3_core_init_mode根据设备树获得的模式,初始化控制器为对应模式,初始化控制器的操作函数:主机有主机的操作函数;

2024-04-26 22:03:18 980

原创 linux信号机制分析

对于有通过 signal、sigaction 注册信号处理函数的信号,设定堆栈后跳转到用户态的信号处理函数开始执行,此函数返回后触发一个 sigreturn 系统调用后再次回到内核,然后恢复旧的堆栈继续运行。

2024-04-23 17:02:55 772

原创 linux休眠唤醒流程,及示例分析

应用请求休眠,系统进入休眠流程,此时如果设备触发了中断,中断处理程序中首先关闭中断,然后调度内核线程去处理work,但假如这个时候此work还未被调度到,系统就进入休眠了,那么这个设备就被永久关闭中断了,再也不能唤醒系统。休眠后系统卡住,组织串口来休眠,并开启相关打印;设置pm_debug_messages,打印来自系统的调试消息的暂停/休眠内核日志的基础结构。平台休眠的最后,会开启中断,用与响应外部中断,来唤醒系统并继续执行接下来的代码唤醒系统。设备进入休眠,被唤醒或者休眠失败,就会走对应的唤醒流程;

2024-04-22 11:27:00 775

原创 USB设备热插拔流程解析

usb_hcd_poll_rh_status函数中,调用主机控制器的hub_status_data函数获取端口状态。如果端口的状态有变化,那么length > 0,把获取到的端口状态的数组拷贝到urb->transfer_buffer中,就是前面的hub->buffer中,同时调用usb_hcd_giveback_urb函数。在usb_hub_init函数中完成了注册hub驱动,然后创建一个工作队列hub_wq,每当有设备连接到USB接口时;sdio的话,主机驱动初始化的时候,会去枚举卡;

2024-04-15 16:55:24 538

原创 USB主机驱动分析

ehci_hc_driver实现了绝大多数ECHI主机驱动的工作,具体的EHCI实例简单地调用ehci_init_driver(struct hc_driver *drv,const struct ehci_driver_overrides *over)来初始化hc_driver即可,上层通过usb_submit_urb提交1个USB请求后,该函数调用usb_hcd_submit_urb,并最终调用至usb_hcd的driver成员(hc_driver类型的urb_enqueue成员函数)

2024-04-11 17:03:46 291

原创 块设备的读写框架

open系统调用打开字符设备文件时,会调用do_dentry_open,里面的f->f_op = fops_get(inode->i_fop);就是把上面init_special_inode里的inode->i_fop = &def_blk_fops赋给f->f_op;vfs_read里的file->f_op->read_iter就等于def_blk_fops的read_iter成员。其中file->f_op->write_iter就等于def_blk_fops的write_iter成员。

2024-04-03 16:06:27 432

原创 驱动的阻塞与非阻塞IO

(1)select,poll实现需要自己不断轮询所有fd集合,直到设备就绪,期间可能要睡眠和唤醒多次交替。而epoll其实也需要调用epoll_wait不断轮询就绪链表,期间也可能多次睡眠和唤醒交替,但是它是设备就绪时,调用回调函数(ep_ptable_queue_proc),把就绪fd放入就绪链表中,并唤醒在epoll_wait中进入睡眠的进程。

2024-03-27 10:28:10 243

原创 YT8531调试记录

还是从设备树,mac驱动,mac驱动对mdio总线的注册,phy驱动 ,phy的datasheet,cpu的datasheet 几个方面来看来看0.确认供电,以及phy的地址(一般会有多个地址,根据相关引脚电平可配置)1.确认reset的有效电平2.确认IO的有效电平3.确认phy-mode,以及它的pinctrl的复用情况 (cat /sys/kernel/debug/pinctrl/pinctrl-handles 看current state)

2024-03-26 09:45:35 944

原创 PCIe的<配置/IO/MEM空间>的区别

首先是root bus中io和mem的基地址,然后是给bridge(type 01)分配的mem地址,然后写到bridge的bar0;如上图设备树中,pcie两组地址转换关系,每一组的几个数字分别定义了属性(32bit),pci地址空间(64bit),cpu地址(32bit/64bit),长度(64bit)配置空间是一段特殊的IO空间,它的作用是为外设内存空间、IO空间分配物理地址基地址,即配置BAR(Base Address Registers)内存空间:访问内存的地址空间,32位平台为4G。

2024-03-22 16:29:29 586

原创 DMA控制器驱动分析

驱动按上面的步骤1,2分配通道和传输信息后,通过通道找到dma设备,再调用设备的device_prep_dma_memcpy这个成员,就会调用到dma控制器的这个具体实现。4、dma数据提交, dmaengine_submit(),主要是将DMA处理事务提交到dma通道处理链上,这个submit用的是第四步得到的DMA TX结构。2、dma通道配置, dmaengine_slave_config(), 用户通过该函数,可以配置指定通道的参数,比如目的和源地址,位宽,传输方向等。

2024-03-07 16:41:13 1037

原创 并发和竟态的基本概念

有的还允许访存的非阻塞,即如果前面一条访存指令因为缓存不命中,造成长延时的存储访问时,后面的访存指令可以先执行,以便从缓存中取数。因此,即使是从汇编上看顺序正确的指令,其执行的顺序也是不可预知的。解决竞态问题的途径是保证对共享资源的互斥访问,所谓互斥访问是指一个执行单元在访问共享资源的时候,其他的执行单元被禁止访问,中断屏蔽、原子操作、自旋锁、信号量、互斥体等是。这一乱序对于单核的程序执行是不可见 的,因为单个CPU在碰到依赖点(后面的指令依赖于前面指令的执行结果)的时候会等待。指令之前的内存访问完成;

2024-02-28 17:56:40 905 1

原创 ARM体系在linux中的中断抢占

gic主要提供如下功能,主要是四种中断服务,中断掩码和优先级gic框架中的各组件的通路如下中断最终分发给一个或多个PE的cpu interface,通过硬件中断号来区分各中断,各PE的运行优先级就是当前运行中断的优先级;一个中断是否进入PE,会先看优先级掩码能否到PE;还要通过中断抢占设置,和运行优先级,来判断是否能抢占当前PE。

2024-02-19 15:30:24 598

原创 详解kobject_uevent_env上报机制

在用户层,通过一个进程来创建一个netlink,这个应用程序可以是mdev,udev或者openwrt的procd,这三种方式都是基于netlink来管理热插拔的,比如procd通过NETLINK_KOBJECT_UEVENT参数来通过socket系统调用创建一个fd来与内核的netlink交互数据,内核上报uevent被这个进程接受后,然后调用/etc/hotplug.d/的各脚本来执行热插拔操作。这是热插拔触后,触发的事件给应用层,然后执行的脚本,跟上面的信息是对上的。比如插拔sim卡会打印如下信息。

2024-02-04 10:15:02 578

原创 内核Oops的几种定位方法

addr2line定位。addr2line定位。

2024-02-02 12:14:58 201

原创 给驱动设备添加属性文件

先动态分配内存,存放kobject对象,并调用kobject_init完成目录属性文件的操作接口设置,设置kobject对象的ktype为dynamic_kobj_ktype,设置dynamic_kobj_ktype中的sysfs_ops变量为kobj_sysfs_ops,设置kobj_sysfs_ops为show变量为kobj_attr_show,store变量为kobj_attr_store,这就是该kobject对象默认的属性文件操作接口,分别对应着读写操作。就会在sysfs生成如下节点,便于操作。

2024-02-01 16:11:01 886

原创 arm64之系统调用原理

SYSCALL_DEFINE3(open,***)展开就是 sys_open,就是系统调用的内核实例fs/open.cif (fd)return fd;

2024-02-01 14:57:55 415

原创 详解PHY设备驱动的工作原理

不管什么驱动,简单的说:我们总是按照设备-驱动-总线的方式去看。

2024-01-14 11:29:30 798

原创 内核启动时的各参数详解

TEXT_OFFSET 通常为 0x8000,因此解压后的内核将位于物理内存起始地址 + TEXT_OFFSET。内核的.config文件里会有如下一些启动选项,来控制内核的启动,比如传参是通过dtb,还是atags,还是两种方式一起组合;PAGE_OFFSET一般就是内核空间的起始地址,对于不同架构,不同内核版本,也是差异的,并不是一个固定的值;内核会通过将 PC 寄存器进行 128MB 的对齐的方式来获得物理内存的起始地址,内核总是假设它是在物理内存的第一块的第一部分加载和执行。

2024-01-14 10:25:36 1114

原创 USB设备的检测,枚举和数据传输

USB采用差分信号传输,使用的是NRZI编码方式:数据为0时,电平翻转;数据为1时,电平不翻转。如果出现6个连续的数据1,则插入一个数据0,强制电平翻转,以便时钟同步。上面的一条线表示的是原始数据序列,下面的一条线表示的是经过NRZI编码后的数据序列。同步信号的抓包如下。

2023-12-23 22:11:19 1073

空空如也

空空如也

TA创建的收藏夹 TA关注的收藏夹

TA关注的人

提示
确定要删除当前文章?
取消 删除