Tech

WIFI基础知识汇总

Jan 20, 2024
本文阅读量
Tech
WIFI技术, WIFI基础知识, 无线网络知识, WiFi开发详解

WIFI基础知识汇总 # 1. Wi-Fi起源 # 现在我们大家对Wi-Fi肯定都不陌生,无论是笔记本,手机,智能电视,都离不开Wi-Fi。现在我们一般用的都是Wi-Fi5,Wi-Fi6也正在快速普及。 在90年代,IEEE成立著名的802.11工作组,同时也定义了802.11的标准(Wi-Fi的核心技术标准)。最终形成了IEEE802.11标准版本:802.11b 工作于2.4G频段,802.11a工作于5.8G频段。 于此同时,intersil、3Com、诺基亚…六家公司,也成立了WECA:Wireless Ethernet Compatibility Alliance无线以太网相容性联盟,最终将该技术正式更名为了Wi-Fi,该组织也改名为Wi-Fi联盟(Wi-Fi Alliance),并且Wi-Fi联盟不承认wifi、WiFi等其他字眼。 2. Wi-Fi定义 # Wi-Fi是Wi-Fi联盟制造商的商标做为产品的品牌认证,是一个基于IEEE 802.11标准的无线局域网技术。 无线网络上网可以简单的理解为无线上网,几乎所有智能手机、平板电脑和笔记本电脑都支持Wi-Fi上网,是当今使用最广的一种无线网络传输技术。 从宏观来说,也可以理解为Wi-Fi=IEEE802.11标准 3. WLAN # wlan:wireless local area network,无线局域网络的全称,它利用射频技术Radio Frequency; RF,使用电磁波构成局域网络,在空中实现通信。 该技术的出现绝不是用来取代有线局域网络,而是用来弥补有线局域网络之不足。 其实很多时候,人们将二者混用,其实实现wlan的方式有很多,wifi只是实现方式之一; 4. 802.11协议标准 # 802.11:802.11工作组所制定的一种无线局域网标准。 IEEE802家族是由一系列局域网络(Local Area Network,LAN)技术标准所组成,802.11属于其中一员。 WI-FI使用了802.11的媒体访问控制层(MAC)和物理层(PHY),其内部也包含了不同的协议。 IEEE802.11协议族成员如下: 802.11 a/b/g/n/ac:都是由802.11发展而来。不同的后缀代表着不同的物理层标准工作频段和不同的传输速率,也就是说它们的物理层和传输速度不同。 5.0GHz和2.4GHz指的是无线路由器的工作频段。双频无线路由器是同时工作在5.0GHz和2.4GHz的模式下,而单频无线路由器只能工作在2.4GHz模式下。 1、802.11b和802.11g工作在同一频段上,g能够兼容b,也就是说支持g的网卡都能支持b。 2、802.11n协议为双频工作模式(包含2.4GHz和5GHz两个工作频段)。这样11n保障了与以往的802.11a b, g标准兼容。 3、新一代wifi标准802.11 ac是从802.11 n上发展而来的,有着比802.11 n更高的速度。现在市面是说的双频路由器即支持2.4G和5G的路由器。 4、802.11n 和802.11ac是WiFi的技术标准,就像手机3G网络一样,移动、联通、电信zhi都有自己不同的3G技术标准,WiFi也有不同的标准,,WiFi标准历经了802.11a/g/b/n/ac五代标准,其中802.11n是目前主流的应用,802.11ac是最新一代标准,也就是第五代标准。 由于802.11ac标准可以达到千兆的无线速度,所以已经大有取代802.11n标准的趋势,估计为了一两年内,大部分无线产品报告手机、笔记本、平板、无线路由器都采用802.11ac标准, 5. Wi-Fi所采用的技术 # Wi-Fi使用的是无线电波技术,无线电波是电磁辐射的一种,而电磁辐射包括从伽玛射线到可见光到无线电波的种种。 笔记本、平板电脑使用无线适配器将数据转换为无线电波,通过天线发送信号;这些信号被无线路由器接收,无线路由器将无线电波转换为数据形式,再将数据转发到互联网;同理,从互联网获取信息,即为上面流程的逆转。 6. Wi-Fi相关术语 # LAN LAN(Local area network),局域网,路由和主机组成的内部局域网。 WAN WAN(Wide Area Network),广域网,可以看作更大的局域网。 ...

【一文秒懂】Linux字符设备驱动

Jan 19, 2024
本文阅读量
Tech
Linux字符设备驱动, Linux驱动开发基础

【一文秒懂】Linux字符设备驱动 # 1、前言 # 众所周知,Linux内核主要包括三种驱动模型,字符设备驱动,块设备驱动以及网络设备驱动。 其中,Linux字符设备驱动,可以说是Linux驱动开发中最常见的一种驱动模型。 我们该系列文章,主要为了帮助大家快速入门Linux驱动开发,该篇主要来了解一些字符设备驱动的框架和机制。 系列文章基于Kernel 4.19 2、关键数据结构 # 2.1 cdev # struct cdev { struct kobject kobj; struct module *owner; const struct file_operations *ops; struct list_head list; dev_t dev; unsigned int count; } __randomize_layout; 结构体名称:cdev 文件位置:include/linux/cdev.h 主要作用:cdev可以理解为char device,用来抽象一个字符设备。 核心成员及含义: kobj:表示一个内核对象。 owner:指向该模块的指针 ops:指向文件操作的指针,包括open、read、write等操作接口 list:用于将该设备加入到内核模块链表中 dev:设备号,由主设备号和次设备号构成 count:表示有多少个同类型设备,也间接表示设备号的范围 __randomize_layout:一个编译器指令,用于随机化结构体的布局,以增加安全性。 2.2 file_operations # struct file_operations { struct module *owner; loff_t (*llseek) (struct file *, loff_t, int); ssize_t (*read) (struct file *, char __user *, size_t, loff_t *); ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *); ssize_t (*read_iter) (struct kiocb *, struct iov_iter *); ssize_t (*write_iter) (struct kiocb *, struct iov_iter *); int (*iterate) (struct file *, struct dir_context *); int (*iterate_shared) (struct file *, struct dir_context *); __poll_t (*poll) (struct file *, struct poll_table_struct *); long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long); long (*compat_ioctl) (struct file *, unsigned int, unsigned long); int (*mmap) (struct file *, struct vm_area_struct *); unsigned long mmap_supported_flags; int (*open) (struct inode *, struct file *); int (*flush) (struct file *, fl_owner_t id); int (*release) (struct inode *, struct file *); int (*fsync) (struct file *, loff_t, loff_t, int datasync); int (*fasync) (int, struct file *, int); int (*lock) (struct file *, int, struct file_lock *); ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int); unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long); int (*check_flags)(int); int (*flock) (struct file *, int, struct file_lock *); ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int); ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int); int (*setlease)(struct file *, long, struct file_lock **, void **); long (*fallocate)(struct file *file, int mode, loff_t offset, loff_t len); void (*show_fdinfo)(struct seq_file *m, struct file *f); #ifndef CONFIG_MMU unsigned (*mmap_capabilities)(struct file *); #endif ssize_t (*copy_file_range)(struct file *, loff_t, struct file *, loff_t, size_t, unsigned int); int (*clone_file_range)(struct file *, loff_t, struct file *, loff_t, u64); int (*dedupe_file_range)(struct file *, loff_t, struct file *, loff_t, u64); int (*fadvise)(struct file *, loff_t, loff_t, int); } __randomize_layout; 结构体名称:file_operations ...

【一文秒懂】Linux内核调试工具——devmem

Jan 19, 2024
本文阅读量
Tech
Linux调试工具

【一文秒懂】Linux内核调试工具——devmem # 1、介绍 # 我们在底层开发过程中,经常需要在终端查看或者修改设备寄存器的值,有这样一个工具—-devmem,可用于读取或者修改物理寄存器的值,非常方便! 简而言之,devmem就是在Linux命令行模式下,直接操作我们设备寄存器的值! 2、如何使用 # 2.1 配置devmem # 进入menuconfig选项中,按下/搜索关键词即可! 2.2、使用devmem # 进入Linux后,输入devmem -h查看帮助信息即可! Usage: devmem ADDRESS [WIDTH [VALUE]] Read/write from physical address ADDRESS Address to act upon WIDTH Width (8/16/...) VALUE Data to be written []内部为可选内容,比较简单,这里直接上使用代码! 读物理内存 devmem 0x10000000 #读指定的物理内存值 devmem 0x10000000 16 #读16bit物理内存的值 写物理内存 devmem 0x10000000 32 0x00000000 #以32bit写入给定的值到指定物理内存 devmem 0x10000000 8 0x010 #以8bit写入给定的值到指定物理内存 欢迎关注【嵌入式艺术】,董哥原创!

【MMC子系统】一、MMC_SD_SDIO介绍

Jan 19, 2024
本文阅读量
Tech
MMC子系统, MMC/SD/SDIO, Linux驱动开发

【MMC子系统】 一、MMC/SD/SDIO介绍 # 1、前言 # 该节学习Linux Kernel的MMC子系统,也称为块设备驱动,正如其名,与字符驱动相比,MMC子系统以块为单位进行操作。 同时,由于MMC Card、SD Card、SDIO Card等设备协议基本大同小异,所以在Linux Kernel中使用MMC子系统来统一管理! 2、MMC/SD/SDIO介绍 # 上面我们了解到,Linux Kernel使用统一的子系统模型来管理MMC、SD、SDIO等设备,那么为什么要这样设计呢? 答案当然是:三者协议有一定的共通性。 MMC(MultiMediaCard)多媒体卡设备,从本质上看,它是一种用于固态非易失性存储的内存卡(memory card)规范,定义了诸如卡的形态、尺寸、容量、电气信号、和主机之间的通信协议等方方面面的内容。 1997年,MMC规范正式发布,至今已经进化出了SD、MicroSD、SDIO、EMMC等多种不同的规范,虽然眼花缭乱,但是追其根源,都源于MMC规范,所以Linux Kernel可以将其统一管理! MMC:强调的是多媒体存储(MM:MultiMedia) SD:强调的是安全数据(SD:Secure Digital) SDIO:强调的是IO接口(IO:Input/Output) 更多干货可见:高级工程师聚集地,助力大家更上一层楼! 3、总线接口 # MMC、SD、SDIO其物理接口也十分相似,我们以MMC为例进行分析。 我们的MMC卡如上图所示,内部我们不展开分析,直接将其作为一个完整的设备来分析。 其通过CLK、CMD、DATA等管脚与我们的SOC通信,两者之间当然少不了Controller了。 把通信总线部分,拿出来看: CLK:提供SOC和设备之间的通信时钟,常用的通信频率为400KHz(识卡)、25MHz,50MHz CMD:提供SOC和设备之间的通信命令,标识不同的命令编号,类型多达50多种。 DATA:提供SOC和设备之间的数据通信,其通信总线有8根,可自定义设置,一般默认的是1-bit (默认)模式、4-bit模式和8-bit模式。当然数据线越多,传输越快嘛,但是处理起来也稍微繁琐。 除了上面的一些管脚,当然还少不了VCC、GND等管脚喽,与其它外设不同的是,MMC类的设备,还会有一个检测引脚DET,用于检测是否存在卡设备(热插拔)。 好啦,上面我们对MMC、SD、SDIO进行简单了解,也知道了通信的常用方式与物理接口,当然其最核心在于通信的协议啦!由于协议过于复杂,我们放到后面了解。 4、参考文章 # [1]:http://www.wowotech.net/basic_tech/mmc_sd_sdio_intro.html 欢迎关注【嵌入式艺术】,董哥原创!

【Bluetooth蓝牙开发】一、打造全网最详细的Bluetooth开发教程

Jan 19, 2024
本文阅读量
Tech
Bluetooth开发, 蓝牙开发教程, Bluetooth开发详解

【Bluetooth|蓝牙开发】一、开篇词 | 打造全网最详细的Bluetooth开发教程 # 1、前言 # 大家好,我是董哥! 随着物联网技术的快速发展,WiFi、蓝牙成了物联网通信主力军,但是不得不说,这两个技术的门槛还是比较高的,尤其是蓝牙,单单其官方文档,就有将近3000Page,让人望而生畏! 纵观全网,蓝牙技术的学习有三大难点: 其一:学习资料之杂 其二:极少有系统学习蓝牙的文章 其三:蓝牙协议晦涩难懂 这样就导致了蓝牙学习成本之高,劝退人数之多。 因此,为了让初学者快速上手并且掌握蓝牙开发相关技术,我也根据自己的开发经验,精心打造了这一期专栏,主要目的是可以帮助大家零基础入门蓝牙开发,并且可以创建一个交流平台,以供大家交流! 本专栏从四个大方面来学习蓝牙技术:蓝牙基础知识,蓝牙协议栈,蓝牙调试方法,蓝牙应用。我也一定会尽最大努力,帮助大家快速敲开蓝牙开发的大门。 2、蓝牙综合介绍 # 下面我们看一下零基础入门蓝牙开发的学习步骤,希望能够帮助到大家!!! 3、精华文章汇总 # ==为了方便大家快速找到文章,这里按照学习流程进行汇总,点击即可访问!== 章节 内容 1、开篇词 1. 文章总览 2、蓝牙开发入门 2.1 蓝牙基本概念 2.2 蓝牙发展历程 2.3 常见蓝牙架构 3. 蓝牙协议栈总览 2.1 从两个视角,了解蓝牙协议栈 4. 蓝牙协议栈——物理层 3.1 物理层的划分 5. 蓝牙协议栈——链路层 4.1 链路层状态、角色定义 4.2 空中接口数据包格式,字段分析 6. 蓝牙协议栈——传输层 5.1 HCI接口功能介绍 5.2 HCI层包的格式,字段分析 7. 蓝牙协议栈——L2CAP协议 6.1 L2CAP协议作用 6.2 L2CAP协议包的格式,字段分析 8. 蓝牙协议栈——ATT协议 7.1 ATT协议作用及由来 7.2 ATT数据结构 7.3 ATT协议的数据包格式,字段分析 9. 蓝牙协议栈——GATT协议 8. ...

【LED子系统深度剖析】一、开篇词|Linux驱动开发新手必读

Jan 19, 2024
本文阅读量
Tech
LED子系统, LED子系统深度剖析, Linux驱动开发, LED驱动开发

【LED子系统深度剖析】一、开篇词|Linux驱动开发新手必读 # 1、前言 # 大家好,我是董哥! 俗话说:“万丈高楼平地起”,对于我们刚学习Linux驱动开发的小伙伴,Linux驱动开发的基础至关重要,无论我们是学习51单片机、STM32还是ARM,点灯的地位还是毋庸置疑的。 在Linux驱动开发的学习过程中,点灯对于大多数人来说,对着教程照葫芦画瓢,还是能快速点亮一颗LED灯的,但是你真的明白,一颗小小LED灯的背后,到底执行了哪些动作吗,Linux内核是如何管理的呢? 今天,作为在芯片原厂工作的我,有义务带着大家,深入扒一扒LED子系统的工作原理! 总结系列文章,花费时间较长,希望大家尊重原创! 2、LED子系统开发详细介绍 # 该系列文章整体预览如下: 3、LED子系统开发文章汇总 # 为了方便大家快速找到文章,这里按照学习流程进行汇总,点击即可访问! 章节 内容 1、开篇词 1. 文章总览 2、LED子系统框架分析 2.1 裸机处理 2.2 LED子系统框架 2.3 目录结构及核心文件 3、硬件驱动层详解 3.1 gpio_led_probe分析 3.2 gpio_leds_create分析 3.3 create_gpio_led分析 3.4 数据结构之间的关系,以及实现流程 4、核心层——led-class.c详解 4.1 leds_init分析 4.2 leds_class_dev_pm_ops分析 4.3 led_groups分析 4.4 led class的注册注销分析 5、核心层——led-core.c详解 5.1 led_init_core分析 5.2 led_timer_function分析 5.3 set_brightness_delayed分析 5.4 代码实现流程分析 6、核心层——led-triggers.c详解 6.1 触发器设置相关函数分析 6.2 触发器注册注销函数分析 6.3 闪烁功能相关函数分析 6.4 调用流程分析 7、触发器的实现 7.1 触发器介绍 7.2 heartbeat触发器的注册注销流程 7. ...

【深入理解Linux锁机制】一、内核锁的由来

Jan 18, 2024
本文阅读量
Tech
内核锁, Linux 锁机制, 操作系统锁, Linux 系统开发, Linux 内核

【深入理解Linux锁机制】一、内核锁的由来 # 在Linux设备驱动中,我们必须要解决的一个问题是:多个进程对共享资源的并发访问,并发的访问会导致竞态。 1、并发和竞态 # 并发(Concurrency):指的是多个执行单元同时、并行的被执行。 竞态(RaceConditions):并发执行的单元对共享资源的访问,容易导致竞态。 共享资源:硬件资源和软件上的全局变量、静态变量等。 解决竞态的途径是:保证对共享资源的互斥访问。 互斥访问:一个执行单元在访问共享资源的时候,其他执行单元被禁止访问。 临界区(Critical Sections):访问共享资源的代码区域成为临界区。临界区需要以某种互斥机制加以保护。 常见的互斥机制包括:中断屏蔽,原子操作,自旋锁,信号量,互斥体等。 2、竞态发生的场合 # 2.1 多对称处理器(SMP)的多个CPU之间 # 多个CPU使用共同的系统总线,可以访问共同的外设和存储器。在SMP的情况下,多核(CPU0、CPU1)的竞态可能发生于: CPU0的进程和CPU1的进程之间 CPU0的进程和CPU1的中断之间 CPU0的中断和CPU1的中断之间 2.2 单CPU内,该进程与抢占它的进程之间 # 在单CPU内,多个进程并发执行,当一个进程执行的时间片耗尽,也有可能被另一个高优先级进程打断,会发生竞态,即所谓的调度引发竞态。 2.3 中断(软中断、硬中断、Tasklet、底半部)与进程之间 # 当一个进程正在执行,一个外部/内部中断(软中断、硬中断、Tasklet等)将其打断,会导致竞态发生。 3、编译乱序和执行乱序 # 除了并发访问导致的竞态外,还需要了解编译器和处理器的一些特点所引发的一些问题。 3.1 编译乱序 # 现代的高性能编译器,为了提高Cache命中率以及CPU的Load/Store工作效率,会对目标代码进行乱序优化,减少逻辑上不必要的访存! 因此,在打开编译器优化后,生成的汇编码并没有严格按照代码的逻辑顺序执行,这是正常的。 为了解决编译乱序的问题,可以加入barrier()编译屏障。 顾名思义,编译屏障,也就是为了阻挡编译器的编译优化,加入barrier()编译屏障,即可保证正确的执行顺序。 编译屏障代码实现如下: #define barrier() __asm__ __volatile__("": : :"memory") 这里详细解释一下barrier的汇编实现: __asm__:向编译器说明在此插入汇编代码 __volatile__:用于告诉编译器,严禁将此处的汇编语句与其它的语句重组合优化。 ("": : :"memory"):一条汇编语句,第一个:前为汇编指令,这里是空操作;第二个:前表示输出操作数,为空;第三个冒号前为输入操作数,也是要修改的寄存器;最后memory表示该指令对内存进行访问,该指令确保了命令之前的内存操作需要完全执行,不被优化。 使用案例: int main(int argc,char *argv[]) { int a = 0,b,c,d[4096],e; e = d[4095]; barrier(); b = a; c = a; return 0; } 3. ...

【NVMEM子系统深入剖析】一、Efuse介绍及安全启动浅析

Jan 18, 2024
本文阅读量
Tech
NVMEM子系统, NVMEM子系统深入剖析, Efuse, 安全启动

【NVMEM子系统深入剖析】一、Efuse介绍及安全启动浅析 # 1、Efuse是什么 # eFuse(electronic fuse):电子保险丝,熔丝性的一种器件,属于一次性可编程存储器。 之所以成为eFuse,因为其原理像电子保险丝一样,CPU出厂后,这片eFuse空间内所有比特全为1,如果向一位比特写入0,那么就彻底烧死这个比特了,再也无法改变它的值,也就是再也回不去 1 了。 一般OEM从CPU厂商购买芯片后,一般都要烧写eFuse,用于标识自己公司的版本信息,运行模式等相关信息。 同时,由于其一次性编程的特性,我们又将其用在Secure Boot安全启动中。 2、OTP是什么 # 了解完eFuse后,我们就顺便了解一下OTP OTP(One Time Programmable)是反熔丝的一种器件,就是说,当OTP存储单元未击穿时,它的逻辑状态为0;当击穿时,它的逻辑状态为1,也属于一次性可编程存储器。 它的物理状态和逻辑状态正好和eFuse相反! 两者区别如下: 从成本上讲,eFuse器件基本上是各个Foundry厂自己提供,因此通常意味着免费或者很少的费用,而OTP器件则通常是第三方IP厂家提供,这就要收费。 从器件面积上讲,eFuse的cell的面积更大,所以仅仅有小容量的器件可以考虑。当然如果需要大容量的,也可以多个eFuse Macro拼接,但是这意味着芯片面积的增加,成本也会增加;OTP的cell面积很小,所有相对来讲,可以提供更大容量的Macro可供使用。 OTP 比 eFuse 安全性更好,eFuse的编程位可以通过电子显微镜看到,因此其存储的内容可以被轻易破解,但OTP在显微镜下无法区分编程位和未编程位,因此无法读取数据。 eFuse默认导通,存储的是"1",而OTP默认是断开,存储的是"0",因此OTP的功耗也较eFuse小,面积也较eFuse小。 3、什么是Secure Boot # 上面我们也了解过了,efuse主要用于记录一些OEM的产品信息,并且也会用于安全启动,那么安全启动是什么,为什么要做安全启动? 安全启动Secure Boot,其主要目的是:以限制消费者能力,防止消费者从软硬件层面,对产品的部分关键系统进行读写,调试等高级权限,达到对产品的商业保密,知识产权的保护。 安全启动的安全模型是建立在消费者是攻击者的假设之上,一般常见的操作有: 刷机安装自定义的操作系统 绕过厂家封闭的支付平台 绕过系统保护,复制厂家保护的数字产品。 除此之外呢,有的比较专业的消费者,还可以: 使用数字示波器监听 CPU 和 RAM 、eMMC 之间的数据传输来读取非常底层的数据传输 而且像 eMMC 这种芯片通常都是业界标准化的,攻击者甚至可以把芯片拆下来,然后用市面上现成的通用 eMMC 编程工具来读写上面的内容。 安全启动等级也有一个上限:这个上限通常是认为攻击者不至于能够剥离芯片的封装,然后用电子显微镜等纳米级别精度的显像设备来逆向芯片的内部结构。 简单来说:能成功攻破芯片安全机制的一次性投资成本至少需要在十万美元以上才可以认为是安全的。 4、CPU内部安全机制 # 4.1 bootROM # BootROM是集成在CPU芯片的一个ROM空间,其主要用于存放一小段可执行程序,出厂的时候被烧录进去写死,不可修改。 CPU在通电之后,执行的第一条程序就在BootROM,用于初始化Secure Boot安全机制,加载Secure Boot Key密钥,从 存储介质中加载并验证 First Stage Bootloader(FSBL);最后跳转进 FSBL 中。 4.2 iRAM # 为了避免使用外部的RAM,支持Secure Boot的CPU都会内置一块很小的RAM,通常只有 16KB 到 64KB ,我们称之为 iRAM。 ...

一、内存管理的由来及思想

Jan 17, 2024
本文阅读量
Tech
Linux内存管理

Linux内存管理 | 一、内存管理的由来及思想 # 1、前言 # 《中庸》有:“九层之台,起于垒土” 之说,那么对于我们搞技术的人,同样如此! 对于Linux内存管理,你可以说没有留意过,但是它存在于我们日常开发的方方面面,你所打开的文件,你所创建的变量,你所运行的程序,无不以此为基础,它可以说是操作系统的基石;只是底层被封装的太好了,以至于我们在做开发的过程中,不需要关心的太多,哪有什么岁月静好,只是有人在负重前行罢了。 虽然日常开发中涉及的比较少,但是作为一个合格的Linux开发者,搞懂内存管理,又显得至关重要,同时也会对嵌入式开发大有脾益,今天我们就来详细聊聊内存管理的那点事。 该方面的文章,网上也有很多写的非常不错,但是100个人有100种理解方式,并且不同的人,基础不同,理解能力也不同,所以我写这系列的文章,也更有了意义。 2、内存管理的由来 # 为什么要有这个概念呢? 首先,内存管理,管理的是个什么东西? 管理的其实是我们的物理内存,也就是我们的RAM空间,在电脑上,表现为我们安装的内存条,有的人装个4G的、8G的、甚至64G的,这些就是实打实的物理空间大小,也就是我们的实际的硬件资源。 为什么要进行管理? 做嵌入式的都知道,像我们刚开始玩的C51单片机、STM32单片机,我们将程序烧录到Flash中后,开机启动后,然后CPU会将Flash程序加载到RAM中,也就是我们的物理内存,随后我们的所有操作都是基于这一个物理内存所进行的。 那么此时: 我们想再次运行一个一模一样的程序怎么办? 即使运行了,那两个程序同时操作了同一个变量,值被错误修改了怎么办? 这些就是Linux内存管理要做的事情。 顺便介绍一下 我的圈子:高级工程师聚集地,期待大家的加入。 3、Linux内存管理思想 # 为了解决上面的一些问题,Linux采用虚拟内存管理技术。 Linux操作系统抽象出来一个虚拟地址空间的概念,供上层用户使用,这么做的目的是为了让多个用户进程,都以为自己独享了内存空间。 而虚拟地址空间与物理地址空间的对应关系,就交给了一个MMU(Memory Managerment Unit)的家伙来管理,其主要负责将虚拟内存空间映射到真实的物理地址空间。 这么做的主要目的在于: 让每个进程都拥有相同大小的虚拟地址空间 避免用户直接访问物理内存,导致系统崩溃 这样,我们同时执行多个进程,虽然看起来虚拟地址操作都是相同的,但是通过MMU之后,就被映射到了不同的物理地址空间,这样就解决了以上的问题。 4、总结 # 熟悉了内存管理由来以及其思想,我们可以看出,操作系统的内存管理,主要分为以下几个方面: 虚拟内存空间管理:我们抽象出来的虚拟地址空间,该怎么使用,该怎么管理? 物理内存空间管理:虚拟地址映射到物理内存空间后,该如何管理,如何分配? 如何映射:虚拟内存如何映射到物理内存,是怎么操作的,映射方法有哪些? 下面我们来一一详细探究。 欢迎关注【嵌入式艺术】,董哥原创!

【一文秒懂】Ftrace系统调试工具使用终极指南

Dec 13, 2023
本文阅读量
Tech
Linux调试工具

【一文秒懂】Ftrace系统调试工具使用终极指南 # 1、Ftrace是什么 # Ftrace是Function Trace的简写,由 Steven Rostedt 开发的,从 2008 年发布的内核 2.6.27 中开始就内置了。 Ftrace是一个系统内部提供的追踪工具,旨在帮助内核设计和开发人员去追踪系统内部的函数调用流程。 随着Ftrace的不断完善,除了追踪函数调用流程外,还可以用来调试和分析系统的延迟和性能问题,并发展成为一个追踪类调试工具的框架。 除了Ftrace外,追踪类调试工具还包括: 2、Ftrace的实现原理 # 为了帮助我们更好的使用Ftrace,我们有必要简单了解Ftrace的实现原理。 2.1 Ftrace框架图 # Ftrace的框架图如下: 由框架图我们可以知道: ftrace包括多种类型的tracers,每个tracer完成不同的功能 将这些不同类型的tracers注册进入ftrace framework 各类tracers收集不同的信息,并放入到Ring buffer缓冲区以供调用。 2.2 Ftrace是如何记录信息的 # Ftrace采用了静态插桩和动态插桩两种方式来实现。 静态插桩: 我们在Kernel中打开了CONFIG_FUNCTION_TRACER功能后,会增加一个-pg的一个编译选项,这个编译选项的作用就是为每个函数入口处,都会插入bl mcount跳转指令,使得每个函数运行时都会进入mcount函数。 Ftrace一旦使能,对kernel中所有的函数插桩,这带来的性能开销是惊人的,有可能导致人们弃用Ftrace功能。 为了解决这个问题,开发者推出了Dynamic ftrace,以此来优化整体的性能。 动态插桩: 这里的动态,是指的动态修改函数指令。 编译时,记录所有被添加跳转指令的函数,这里表示所有支持追踪的函数。 内核将所有跳转指令替换为nop指令,以实现非调试状态性能零损失。 根据 function tracer 设置,动态将被调试函数的nop指令,替换为跳转指令,以实现追踪。 总而言之,Ftrace记录数据可以总结为以下几个步骤: 打开编译选项-pg,为每个函数都增加跳转指令 记录这些可追踪的函数,并为了减少性能消耗,将跳转函数替换为nop指令 通过flag标志位来动态管理,将需要追踪的函数预留的nop指令替换回追踪指令,记录调试信息。 3、如何使用Ftrace # 3.1 配置详解 # CONFIG_FTRACE=y # 启用了 Ftrace CONFIG_FUNCTION_TRACER=y # 启用函数级别的追踪器 CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y # 表示内核支持图形显示 CONFIG_FUNCTION_GRAPH_TRACER=y # 以图形的方式显示函数追踪过程 CONFIG_STACK_TRACER=y # 启用堆栈追踪器,用于跟踪内核函数调用的堆栈信息。 CONFIG_DYNAMIC_FTRACE=y # 启用动态 Ftrace,允许在运行时启用和禁用 Ftrace 功能。 CONFIG_HAVE_FTRACE_NMI_ENTER=y # 表示内核支持非屏蔽中断(NMI)时进入 Ftrace 的功能 CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y # 表示内核支持通过 mcount 记录函数调用关系。 CONFIG_FTRACE_NMI_ENTER=y # 表示内核支持通过 mcount 记录函数调用关系。 CONFIG_FTRACE_SYSCALLS=y # 系统调用的追踪 CONFIG_FTRACE_MCOUNT_RECORD=y # 启用 mcount 记录函数调用关系。 CONFIG_SCHED_TRACER=y # 支持调度追踪 CONFIG_FUNCTION_PROFILER=y # 启用函数分析器,主要用于记录函数的执行时间和调用次数 CONFIG_DEBUG_FS=y # 启用 Debug 文件系统支持 上面只是介绍了部分配置,更多详细配置可自行了解。 ...