之前写过一篇《CPU是如何访问内存的?》的文章,简单介绍了cpu访问内存的过程。有了之前的感性认识,这篇站在arm的角度再深度讲解一下,看完你会发现不理解arm原理就直接撸内核代码简直是耍流氓。
作者简介: 周文嘉: 曾服务于ARM、阿里系子公司、HTC等公司。10年以上工作经验,主要从事系统软件开发,涵盖:系统库开发、指令集优化、Linux内核开发等。累计为某些开源社贡献过一定数量的patch。 在 Linux 内核启动之后,对于 32 位的系统来说,他会把 0 ~ 896M 这部分低端内存(low memory)都做线性映射,不管这部分内存是否需要用到。对于 64 位的系统,内核会把所有的物理(一般情况如此,除非物理内存特别大)内存都映射出来。这么做的目的是啥?这里先说结论,然后分析代码。 这么
前面我们提到Linux内核仅使用了较少的分段机制,但是却对分页机制的依赖性很强,其使用一种适合32位和64位结构的通用分页模型,该模型使用四级分页机制,即
在引入虚拟地址概念以后,程序员和CPU看到的都是虚拟地址。当CPU尝试去访问某个虚拟地址的时候,这时候硬件单元MMU就会将此虚拟地址转化为物理地址,然后CPU再去访问。
操作系统用于处理内存访问异常的入口操作系统的核心任务是对系统资源的管理,而重中之重的是对CPU和内存的管理。为了使进程摆脱系统内存的制约,用户进程运行在虚拟内存之上,每个用户进程都拥有完整的虚拟地址空间,互不干涉。而实现虚拟内存的关键就在于建立虚拟地址(Virtual Address,VA)与物理地址(Physical Address,PA)之间的关系,因为无论如何数据终究要存储到物理内存中才能被记录下来。
进程地址空间的隔离 是现代操作系统的一个显著特征。这也是区别于 “古代”操作系统 的显著特征。
基于ARMv8-A架构的处理器最大可以支持到48根地址线,也就是寻址2的48次方的虚拟地址空间,即虚拟地址空间范围为0x0000_0000_0000_0000~0x0000_FFFF_FFFF_FFFF,共256TB。
大家在看内核代码时会经常看的以上术语,但在ARM的芯片手册中并没有用到这些术语,而是使用L1,L2,L3页表这种术语。
Linux系统中每个进程对应用户空间的pgd是不一样的,但是linux内核 的pgd是一样的。当创建一个新的进程时,都要为新进程创建一个新的页面目录PGD,并从内核的页面目录swapper_pg_dir中复制内核区间页面目录项至新建进程页面目录PGD的相应位置,具体过程如下:do_fork() --> copy_mm() --> mm_init() --> pgd_alloc() --> set_pgd_fast() --> get_pgd_slow() --> memcpy(&PGD + USER_PTRS_PER_PGD, swapper_pg_dir +USER_PTRS_PER_PGD, (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t))
本文将介绍如何对NULL指针地址建立合法映射,从而合法访问NULL指针。本文表达的宗旨:
目录 前言 Intel四级页表 实操寻址 获取cr3 获取PGD 获取PUD 获取PMD 获取PTE 获取内容 最后 ---- 前言 Linux四级页表的作用主要就是地址映射, 将逻辑地址映射到物理地址. 很多时候, 有些地方想不明白就可以查看实际物理地址进行分析. ---- Intel 四级页表 其实很多设计的根源或者说原因都来自于CPU的设计, OS很多时候都是辅助CPU. Linux的四级页表就是依据CPU的四级页表来设计的. 这里主要说的就是Intel x64页面大小为4KB的情况, 如
内核文档Documentation/arm64/memory.rst描述了ARM64 Linux内核空间的内存映射情况,应该是此方面最权威文档。
在前面两篇介绍 mmap 的文章中,笔者分别从原理角度以及源码实现角度带着大家深入到内核世界深度揭秘了 mmap 内存映射的本质。从整个 mmap 映射的过程可以看出,内核只是在进程的虚拟地址空间中寻找出一段空闲的虚拟内存区域 vma 然后分配给本次映射而已。
http://bbs.chinaunix.net/thread-2083672-1-1.html
在32bit中的Linux内核中一般采用3层映射模型,第1层是页面目录(PGD),第2层是页面中间目录(PMD),第3层才是页面映射表(PTE)。但在ARM32系统中只用到两层映射,因此在实际代码中就要3层映射模型中合并一层。在ARM32架构中,可以按段(section)来映射,这时采用单层映射模式。使用页面映射需要两层映射结构,页面的选择可以是64KB的大页面或4KB的小页面,如图2.4所示。Linux内核通常使用4KB大小的小页面。
平时写过多进程多线程程序,比如使用linux的系统调用fork创建子进程和glibc中的nptl包里的pthread_create创建线程,甚至在java里使用Thread类创建线程等,虽然使用问题不大,但需要知道底层原理。这次在自己写操作系统的时候,看了一遍linux内核的进程创建过程。算是有了比较深入的理解。
我们知道LINUX的内存管理系统中有”反向映射“这一说,目的是为了快速去查找出一个特定的物理页在哪些进程中被映射到了什么地址,这样如果我们想把这一页换出(SWAP),或是迁移(Migrate)的时候,就能相应该更改所有相关进程的页表来达到这个目的。
现代处理器大部分都有MMU,除了一些小型嵌入式设备。MMU可以做虚拟地址到物理地址的转换,使用MMU我们就可以使用更多的内存空间,因为程序具有局部性原理,我们可以将暂时用不到的数据存放到磁盘,当访问到时会发生缺页中断,从磁盘中将所需要的数据加载到内存。所以我们可以通过mmu运行程序大小大于内存的程序和打开大于内存的文件。现代处理器通过分段分页机制实现虚拟地址到物理地址转换一般支持二级页表或四级页表。
在《你真的理解内存分配》一文中,我们介绍了 malloc 申请内存的原理,但其在内核怎么实现的呢?所以,本文主要分析在 Linux 内核中对堆内存分配的实现过程。
通用操作系统,通常都会开启mmu来支持虚拟内存管理,而页表管理是在虚拟内存管理中尤为重要,本文主要以回答几个页表管理中关键性问题来解析Linux内核页表管理,看一看页表管理中那些鲜为人知的秘密。
随着硬件能力的提升,系统内存容量变得越来越大。尤其是在服务器上,过T级别的内存容量也已经不罕见了。
基于前言中的内核配置,内核采用39位虚拟地址,因此可寻址范围为2^39 = 512G,采用(linux 默认为五级页表,另外还有PUD,P4D,由于本文只配置三级,其他两项不予罗列)3级页表结构,分别为:
随着linux的代码更新,阅读linux-4.15代码,从中发现很多与众不同的地方。之所以与众不同,就是因为和我之前从网上博客或者书籍中看到的内容有所差异。当然了,并不是为了表明书上或者博客的观点是错误的。而是因为linux代码更新的太快,网上的博客和书籍跟不上linux的步伐而已。究竟是哪些发生了差异了?例如:kernel image映射区域从原来的linear mapping region(线性映射区域)搬移到VMALLOC区域。因此,我希望通过本篇文章揭晓这些差异。当然,我相信不久的将来这篇文章也将会成为一段历史。
因为这是我被问的最频繁的问题,哎呀我的程序 OOM 了怎么办,我的程序内存超过配额被 k8s 杀掉了怎么办,我的程序看起来内存占用很高正常吗?
Linux 内存管理模型不是咱们这个系列的讨论重点,我们这里只会简单提一些对于咱们这个系列需要了解到的,如果读者想要深入理解,建议大家查看 bin 神(公众号:bin 的技术小屋)的系列文章:一步一图带你深入理解 Linux 虚拟内存管理
这篇文章是我在公司 TechDay 上分享的内容的文字实录版,本来不想写这么一篇冗长的文章,因为有不少的同学问是否能写一篇相关的文字版,本来没有的也就有了。
栈是编程中使用内存最简单的方式。例如,下面的简单代码中的局部变量 n 就是在堆栈中分配内存的。
上周确实事情挺多的,年会、公司聚餐,一到过年就有忙不完的事分心。还好C语言再学习总结的已经差不多了,年前也不展开别的了,接下来这十几天、总结几篇典型的面试题吧。
KSMA的全称是Kernel Space Mirror Attack,即内核镜像攻击。本文主要记录对该攻击方法的原理分析以及Linux内核中相关内存管理部分。
首先配置内核,使其支持导出内核页表到debugfs下面: Kernel hacking ---> ---> [*] Export kernel pagetable layout to userspace via debugfs 配置完后,重新编译内核,并用新内核启动,就会在/sys/kernel/debug下看到kernel_page_tables文件:
在介绍 HugePages 之前,我们先来回顾一下 Linux 下 虚拟内存 与 物理内存 之间的关系。
Linux的内存管理可谓是学好Linux的必经之路,也是Linux的关键知识点,有人说打通了内存管理的知识,也就打通了Linux的任督二脉,这一点不夸张。有人问网上有很多Linux内存管理的内容,为什么还要看你这一篇,这正是我写此文的原因,网上碎片化的相关知识点大都是东拼西凑,先不说正确性与否,就连基本的逻辑都没有搞清楚,我可以负责任的说Linux内存管理只需要看此文一篇就可以让你入Linux内核的大门,省去你东找西找的时间,让你形成内存管理知识的闭环。 文章比较长,做好准备,深呼吸,让我们一起打开Lin
我们都清楚malloc申请的内存不是立刻就建立虚拟地址和物理地址的映射的,当int *p = malloc(100*1024)执行这条指令之后,只是在用户空间给程序开辟一段100K左右的大小,然后就返回这段空间的首地址给程序员。
前面已经分析过了Intel的内存映射和linux的基本使用情况,已知head_32.S仅是建立临时页表,内核还是要建立内核页表,做到全面映射的。下面就基于RAM大于896MB,而小于4GB ,切CONFIG_HIGHMEM配置了高端内存的环境情况进行分析。
本文讲解Linux内核虚拟内存管理中的mmu_gather操作,看看它是如何保证刷tlb和释放物理页的顺序的,又是如何将更多的页面聚集起来统一释放的。
Hadoop是Apache的一个伪分布式文件系统的开源项目。作者名为Doug Cutting,Hadoop项目是他通过Google的发布三篇论文所启发,分别为GFS、MapReduce和BigTable。Hadoop最受欢迎是致力于搜索大量数据进行分类工具。
C:\Users\%Username%\AppData\Roaming\Autodesk\ADPSDK\UserConsent
https://github.com/pedroqin/RaspberryPi-based-multi-functional-USB-Device
广播通信中发出广播报文的一方称为Advertiser,接收广播报文的一方称为Scanner,连接通信中发起连接的一方称为Mater,接受连接的一方称为Slave,这些设备角色并不是固定的,一个蓝牙设备可以根据需要在多个角色之间切换,也可以同时身兼多个角色。为了方便管理蓝牙设备的角色,在链路层使用状态机来标识蓝牙设备当前的状态,蓝牙设备角色的切换也就相当于状态机中状态的迁移,Bluetooth 5.2 链路层状态机如下:
前面已经分析了内核页表的准备工作以及内核低端内存页表的建立,接着回到init_mem_mapping()中,低端内存页表建立后紧随着还有一个函数early_ioremap_page_table_range_init():
“C:\Users\%Username%\AppData\Roaming\Autodesk\ADPSDK\UserConsent”
前言: KVM的设备虚拟化,除了前文《PIO技术分析》,还有另外一个核心概念---MMIO。原计划这里分析一下KVM的MMIO虚拟化。考虑到MMIO比PIO复杂很多,涉及更多的概念,作者打算先分析几篇基本的Linux的内存管理概念,再来分析MMIO。 作者大概想了一下,主要由这几篇构成: 1,虚拟内存管理和内存映射。 2,物理内存管理。 3,内存回收。 分析: 1,虚拟内存概念 x86的CPU有两种运行模式---real mode和protected mode。在real mode下,CPU访问的是物理
特此声明:在本文中,引用另一篇文章和帖子,结合的概括的理解malloc()函数的实现机制。
尽管通过特征下采样获取多尺度特征融合是一种有效改善视觉识别性能的方案,但是特征下采样对于图像超分一种是反直觉的行为,这是因为超分需要将低分辨率输入映射到高分辨率输出。因此,鲜少在图像超分中看到下采样操作,就算是有,下采样操作也是打“辅助”。前段时间,有一篇paper对此进行了探索并设计了一种新的架构HPUN,用上了下采样,性能还有所提升!
本文主要从内存管理和进程管理两个维度来窥探一下fork背后隐藏的技术细节,希望能够通过本文让大家站在一个高度去看进程创建。
设备驱动程序是软件概念和硬件电路之间的一个抽象层,软件操作硬件的关键就是对寄存器的操作。笔者使用的S5PV210是IO与内存统一编址的,在裸机中直接操作IO端口的物理地址,而在驱动中必须使用虚拟地址。直接基于IO的虚拟地址用指针解引用的方式来读写有两种方式,静态映射和动态映射。除了可以直接将指针解引用的方式,内核中提供了专用的读写接口来读写寄存器。考虑到GPIO作为硬件资源,存在着被多个驱动使用,还有复用的问题,所以内核提供了GPIO驱动gpiolib框架来统一管控GPIO资源,gpiolib在内核中作为一个驱动所实现。
写笔记记录一下: 📷 在文件夹下执行这个,可以初始化一个Git项目 📷 建立文件以后,先add后提交对号 📷 报错了,emmmm 我之前配置的失败了 📷 git config --global user.name “you Account” git config --global user.email “you email@163.com” 先配置 ssh-keygen -t rsa -C “you email@163.com" 在生成ssh秘钥 📷 在这里。pud的文件,打开复制 📷 去自己的GitHub
作者:dengxuanshi,腾讯 IEG 后台开发工程师 以下源代码来自 linux-5.10.3 内核代码,主要以 x86-32 为例。 Linux 内存管理是一个很复杂的“工程”,它不仅仅是对物理内存的管理,也涉及到虚拟内存管理、内存交换和内存回收等 物理内存的探测 Linux 内核通过 detect_memory()函数实现对物理内存的探测 void detect_memory(void) { detect_memory_e820(); detect_memory_e801(); d
领取专属 10元无门槛券
手把手带您无忧上云