- 博客(83)
- 收藏
- 关注
原创 ARMv8 内存属性
1、在linux arm64 中,共有MT_DEVICE_nGnRnE 等共6种内存属性2、arm64 系统寄存器MAIR 可以配置共8种内存属性,每个内存属性占用8bit。linux 仅配置了6种。3、页表描述符中,bit[4:2] 为AttrIndx。当前页的内存属性,就是MAIR 寄存器中下标为AttrIndx 的属性。参考。
2024-07-31 08:45:30
753
原创 linux 恒等映射 idmap 的作用
在head.S 中,__create_page_table时,将 __idmap_text_start 到 __idmap_text_end 的范围创建和恒等映射(物理地址与虚拟地址相同,详见。所以说,恒等映射保证了打开mmu 之后,cpu 仍然可以继续使用物理地址(因为物理地址会被mmu 作为虚拟地址翻译成相同的值)执行代码。通过搜索“idmap.text”,可以看到只有下表中的这些符合被放在了idmap.text 段中。
2024-04-16 08:52:14
259
原创 linux arm64 __create_page_tables 的结果验证
内核代码一开始,在完成了el2_setup, set_cpu_boot_mode_flag之后,就开始__create_page_tables本文主要概述__create_page_tables 的作用和过程。代码没必要一行一行分析,都是基础的汇编代码。并且内核本身有很全面的注释。本文目的是把这个过程拆解成很多个小段,从而更容易理解。
2024-04-08 08:30:39
860
原创 vscode GDB 调试linux内核 head.S
此前参考如下文章已经完成了在ubuntu 虚拟机用vscode 调试linux 内核。但是美中不足的是,断点最早只能加在__primary_switched() 函数。无法停在更早的断点上,比如ENTRY(stext) 位置。参考《奔跑吧linux 内核(第2版)》卷2,3.1.5节如下位置,可以在gdb -tui 中从 ENTRY(stext) 开始单步调试,但是远不如vs code 方便。于是在vs code 官方文档中寻找方法。
2023-08-29 09:13:35
681
原创 idmap_pg_dir 大小及作用
43ARM64_HW_PGTABLE_LEVELS 的含义是:在不使用段映射的情况下,需要多少个页表级别来寻址宽度为 ‘va_bits’ 的地址。因为我们用每个页表级别的 (PAGE_SHIFT - 3) 位来解析最高的 (va_bits - PAGE_SHIFT) 位。所以就需要(48-12) / (12-9) = 4 个级别,也就是PGD,PUD, PMD, PT (L0-L3)四级。即ARM64_HW_PGTABLE_LEVELS(48) = 41。
2023-08-10 08:40:15
278
原创 init_pg_dir 的大小及作用
在vmlinux.lds.S 中,有01EARLY_PGDSEARLY_PUDSEARLY_PMDS从System.map 中可以看到。
2023-08-08 08:18:21
330
原创 ARM64_HW_PGTABLE_LEVEL_SHIFT 宏的作用
所以,ARM64_HW_PGTABLE_LEVEL_SHIFT(4 - CONFIG_PGTABLE_LEVELS) 得到的其实是PGD, L0页表索引在64bit 虚拟地址所处的偏移量,即39。在 4K page 的情况下,因为pow(4, 12) = 4K,所以需要用bit11-0来表示某地址在该page中的偏移。比如四级页表,每级页表所占的bit 个数就是36/4 = 9,也就是下图所示的情况。设页表等级数 为n,那每级索引所占的bit个数就是36/n。
2023-07-18 08:50:48
217
原创 adrp 命令为何能获取符号的地址
adrp 在编译时,会记录label 地址与当前指令地址的offset。在运行时,pc + offset 就能得到label 的地址。又因为arm64 指令长度的限制,所以adrp 这条指令得到的地址仅仅精确到了label 所在的页的基地址,需要配合ADD 加上label 的lo12 位才能得到准确地址。
2023-01-14 22:02:08
963
原创 ubuntu apt-get update 失败 server certificate verification failed
apt update 失败,提示server certificate verification failed. CAfile: /etc/ssl/certs/ca-certificates.crt CRLfile: none
2022-10-29 08:00:50
1235
原创 static_branch_likely 原理及用法(完全剖析)
看irq-gic-v3.c时,发现中断回调中有static_branch_likely 这么一个函数。看起来是为了减少cpu 分支预测失败带来的巨大代价而做的优化。具体原理还没细看。内核源码中这里有个文档介绍 kernel/Documentation/static-keys.txt。...
2022-04-17 21:27:22
1755
1
原创 ctags 生成简明易用 linux 源码 tags
问题所在一般使用ctags 就是用ctags -R生成tags。不过这样看源码时会有两个问题:假如同一个函数在不同的处理器架构中都有实现,那么跳转时,会出现很多你不关心的架构的函数原型。比如你关注arm64,但是会出现power pc,mips 等等架构在跳转时,会出现很多struct member的标签。但是这通常不是你想要的。最典型的你可以在linux 源码中 :ta device,你期望的是跳到struct device 的定义处。结果出现了几百行结果,大部分都是device 作为其他stru
2022-04-14 08:05:39
1195
原创 浅谈 arch_local_irq_save 及arm64 debug exceptions
追__raw_spin_lock_irqsave 代码时,发现了arch_local_irq_save 这个函数,顺便看了下这个函数static inline unsigned long arch_local_irq_save(void){ unsigned long flags; asm volatile( "mrs %0, daif // arch_local_irq_save\n" "msr daifset, #2" : "=r" (flags) : : "memory"
2022-03-16 09:55:46
811
原创 linux arm64 中断处理流程完整分析 (二)—— 中断处理流程c代码部分 以gic_v3 为例
本文以gic 为例,探索中断中断控制器的注册过程,以及相关中断处理流程。GIC V3 结构详细可以参考这个页面。这里只做简单介绍。/*drivers/irqchip/irq-gic-v3.c*/IRQCHIP_DECLARE(gic_v3, "arm,gic-v3", gic_of_init);gic_of_init(struct device_node *node, struct device_node *parent) "从dts中获取distributor,以及redistributor
2022-03-08 08:53:01
3300
原创 linux arm64 中断处理流程完整分析 (一)—— 中断向量表、中断处理流程汇编部分
中断流程老生常谈,但我一直以来也只是知道中断过来之后,会保护现场,跳到中断向量表,执行中断,恢复现场,然后返回。至于更多细节,就不得而知了。这篇文章旨在把更完整的linux 中断处理流程梳理一遍。主要带着以下几个问题:中断向量表是在代码哪里配置的响应中断时,必然有一些读写gic 寄存器的操作,这些操作在什么位置/proc/interrupts 这个proc 文件是如何实现的linux 进入中断前,会屏蔽其他所有中断,这个是如何实现的系统调用的系统中断0x80,是如何从用户态调用到内核态file_
2022-03-03 09:11:02
4326
原创 页表映射及页表描述符
以4KB页表粒度,4级页表为例,分析虚拟地址到物理地址的转换过程:虚拟地址的bit63 用来选择TTBR0 还是TTBR1。这两个寄存器中保存了内核态和用户态的L0页表基地址。(这也是为什么内核地址高位总是0xFFFF…)在L0 基地址处,保存了512个页表项(512=pow(2,9), 因此L0 索引占用了9bit,下同),每一个页表项占用64bit。根据虚拟地址中的 L0 索引找到 L0 页表中的一个页表项(如红框所示)。该页表项的bit47-bit_m 保存了下一级页表的物理基地址。此处bit_
2022-01-13 08:28:54
824
原创 内核性能优化点
高速缓存伪共享当多个cpu 访问同一个高速缓存行中的不同数据时,两个cpu 会不断争夺对该高速缓存行的控制权,不断将对方的高速缓存行invalid,导致不断写内存,进而导致性能下降。解决方法就是让多线程操作的数据处在不同的高速缓存行。如struct data { long x; long y; long z;} __attribute__(__aligned__((64)))...
2021-11-08 08:56:23
103
原创 《程序员的自我修养——链接、装载与库》读书笔记—— 7.6 动态链接的步骤和实现
简述动态链接可以分为以下几个步骤:动态链接器的自举装载共享对象重定位和初始化
2021-10-18 08:54:50
212
原创 《程序员的自我修养——链接、装载与库》读书笔记—— 7.5 动态链接相关结构
7.5.x 这几小节看的有点懵,只能多看几遍,慢慢理解。定几个小目标:搞清楚.dynamic, .dynsym, .rel.dyn, .rel.plt 这几个段都保存了哪些信息?这些段能在什么阶段起到什么作用?
2021-10-15 08:35:10
542
原创 vim 常用插件包及快捷键
目录插件和vim脚本安装常用快捷键导航窗口符号跳转其他常用快捷键常见问题vim 中使用某些命令或者快捷键时,有报错本文简单介绍我目前使用的vim 插件的使用方法和快捷键。插件和vim脚本安装从一个大佬那里fork来的一份vimrc的配置,自己做了点改动。下载链接:https://github.com/zqxl/vimrc安装步骤:1、将其中的vimrc 复制为ubuntu 的~/.vimrc,如下2、将整个目录(.git所在目录的所有的文件及文件夹)复制到~/.vim/ 目录下,如下3、
2021-10-10 11:15:39
399
原创 hexdump 命令
大概整明白了-e 里边这个format 到底怎么写。模仿man 里边的命令demo改了一个能用hexdump -e ‘"0x%08_ax: " 4/4 "%08x " “\n”’ plt|less搞清楚的含义:%08_ax :08是输出按8个字符的长度输出,高位补0;_a是输出offset;x是按16进制;4/4:第一个4是每行四次输出;第二个4是每次输出4个byte0x00000000: 464c457f 00010101 00000000 000000000x00000010: 000300
2021-09-29 08:33:36
1112
原创 Android 编译框架下使用gcov 统计.so代码覆盖率
我的需求是在Android编译框架下,可执行程序需要在设备机中执行,而非宿主机。因此走了些弯路,这里记录一下。编译在相应的Andriod.mk 中添加如下CFLAGNATIVE_COVERAGE := trueLOCAL_STATIC_LIBRARIES += libgcovLOCAL_CFLAGS += -ftest-coverage -fprofile-arcsLOCAL_LDFLAGS += -ftest-coverage -fprofile-arcs结果解析运行后的.gcda 文件
2021-09-28 08:22:30
1323
原创 《程序员的自我修养——链接、装载与库》读书笔记—— 7.4 延迟绑定
为什么需要延迟绑定根据前文所述,动态链接的可执行程序在使用.so 中的符号时,依赖.got 中保存的地址,这个地址是链接器在程序运行时才去填充(或者说绑定)的。如果有大量的符号需要动态链接,这些符号查找地址重定位的工作必定会消耗可观的时间。并且,可能很多动态库中的函数在程序执行完时都不会被调用到,那么对这些函数的查找和重定位的工作就白白浪费了。什么是PLT 延迟绑定PLT(procesure linkage table) 延迟绑定的基本思路就是,在程序第一次被使用的时候,才去进行绑定(符号查找,填充.
2021-09-26 08:17:17
293
原创 《程序员的自我修养——链接、装载与库》读书笔记—— 7.1-7.3 动态链接、地址无关码
为什么要动态链接静态链接时,公共库函数会被链接到程序内部,同时运行多个程序时,公共库函数在内存中(磁盘中也一样)就存在多个副本,极大浪费空间。而动态链接库只在内存中有一个副本,所有使用这个动态库的程序都使用这一份副本。(此时你也想到了,对于动态链接库中的可修改数据,比如全局变量,静态局部变量等,每个程序都必须有自己的副本才可以,否则将导致冲突)程序的开发和发布。使用静态链接时,一旦静态库发生改动(比如修了一个小bug),整个程序都必须被重新下载。使用动态链接时则只需要重新下载更新这个动态链接库就可以了
2021-09-20 08:26:37
152
原创 《程序员的自我修养——链接、装载与库》读书笔记—— 6.4.5 进程栈初始化
一直以来有个疑惑,在编写一个类似下面的简单的应用程序时,main 函数的两个参数argc, argv谁传给它的?int main(int argc, char *argv[]){ ....}这一小节解答了我的这个疑问。操作系统在启动进程前,会把进程的运行参数argc, argv提前保存到进程的虚拟空间的栈中。同时被报错的栈中的还有系统环境变量。假如我们运行命令prog的同时传入参数123,也就是“./prog 123”,此时的进程栈如下图:栈顶寄存器esp 指向的地址0XBF801FBC
2021-09-12 11:24:11
128
原创 《程序员的自我修养——链接、装载与库》读书笔记—— 6.4.1 ELF 文件链接视图和执行视图
查看可执行程序的段表,可以看到一共有33个段。如下图。在ELF被映射时,是以页长度为单位的。如果按照段来映射,那么33个段每个段都要映射到页长的整数倍大小的空间里,这将造成极大的内存空间浪费。其实,操作系统在映射ELF时,关心的只是段的权限(可读、可写和可执行)。因此,可以将相同权限的段合并在一起来进行映射,从而避免大量因对齐导致的内存空间浪费。合并之后的段被称为“Segment”。如下命令可以查看ELF 的Segment。从下图红框位置,还可以看到每个“Segment” 都合并了哪些段(section
2021-09-12 09:12:59
387
原创 《程序员的自我修养——链接、装载与库》读书笔记 6.2 装载方式
程序必须从磁盘装载到内存中才可以被执行。最简单的方法就是把程序装载到加载地址即可,但是内存往往不够用。这里介绍了两种典型的装载方式:覆盖装入和页映射。书中的介绍已经很简洁明了,这里就不再概括了。请直接参照书中原文。...
2021-08-22 16:17:08
136
原创 objdump和 readelf 的区别
在查看section 时,发现两者的section 下标是不一样的,对于同一个.o,两者的结果如下。可以看到,readelf -S 下标为0的是一个类型为NULL 段,但是objdump -h 的结果不存在这个段。因此,同一个段,在两个结果中的下标是不一样的。比如我碰到的疑问就是,通过readelf -s查看符号表,发现符号所在的段下标和objdump -h出来的段对应不起来。。。所以才有了这篇blog,记录一下zqxl@ubuntu:~/work/practice/_3.4_SimpleSection
2021-08-19 08:31:13
260
原创 linux 内核启动串口log 等级配置
问题看kernel 代码的时候,总会重新烧内核,有时候乱改改挂了,但是发现串口启动log没有打出来,没法定位。于是乎想研究一下内核启动时的串口log 是如何控制的?什么情况下会都打出来,以及什么时候没有打印线索经高人指点,说看一下内核启动参数bootargs。于是在内核启动后,dmesg看了下,果然发现了个疑点,启动参数里有个quiet 选项。所以以此为线索看下内核是如何解析这个参数的。就从大名鼎鼎的start_kernel 开始找吧。/* 首先init/main.c中可以找到这么一个定义,看起
2021-07-17 22:18:02
1328
原创 imx6ull uboot 从tftp 加载内核
问题背景imx6ull 的mfgtool 烧录工具慢得要死,自己最近在看内核代码,经常烧内核,还经常烧完启动不了,如果每次都用mfg tool烧录,效率太低。有大佬提示可以通过tftp 启动,就找了个教程实践了一下。主要参考了这个页面,解决了自己遇到的几个小问题。在这里整理记录一下整个过程。tftp 服务器配置(ubuntu)步骤如下:1、xinetd 安装sudo apt-get install xinetd2、 配置xinetdsudo vi /etc/xinetd.conf/etc
2021-07-17 16:49:06
840
1
原创 dtb解析过程及platform_device 创建过程
目录内核解析dtb 文件,并构建树状devide_node 的过程platform_device 创建过程内核解析dtb 文件,并构建树状devide_node 的过程dtb被编译好传给内核之后,内核是如何解析的?解析的结果是什么?有必要追一下代码。/* 在 drivers/of/base.c 中,创建了一个全局的指针*/struct device_node *of_root;EXPORT_SYMBOL(of_root);/*drivers/of/fdt.c 看起来下边这个函数给of_root
2021-07-06 08:31:07
1980
1
原创 以spi_bus_type 为例梳理kobject. ktype, kset用法
spi_bus_type//bus_type 的定义如下struct bus_type spi_bus_type = { .name = "spi", .dev_groups = spi_dev_groups, .match = spi_match_device, .uevent = spi_uevent,};spi_dev_groups//这里是一个attribute group,应该对应在bus 目录下的一个个的文件static const struct attribute_
2021-07-01 08:55:47
474
原创 linux spi 驱动框架
spi.cpostcore_initcall(spi_init);static int __init spi_init(void) bus_register(&spi_bus_type); class_register(&spi_master_class); spidev.cmodule_init(spidev_init);static int __init spidev_init(void) register_chrdev(SPIDE
2021-02-24 08:50:39
114
转载 ubuntu 环境变量
一:设置环境变量的三种方法1.1 临时设置export PATH=/home/yan/share/usr/local/arm/3.4.1/bin:$PATH11.2 当前用户的全局设置打开~/.bashrc,添加行:export PATH=/home/yan/share/usr/local/arm/3.4.1/bin:$PATH1使生效:source .bashrc11.3 所有用户的全局设置$ vim /etc/profile1在里面加入:export PATH=/home/
2020-12-31 08:25:40
1708
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人