Linux系统下ARM芯片内存分页的一个认知文档,

阅读本文前认为读者了解MMU

目 录

1. 概述... 5

2. LINUX的内存分页管理... 5

3. ARM的分页模式... 5

4. 内存分页相关的数据结构... 5

5. 重要的系统函数调用... 5

6.物理内存的定制... 5

7.虚拟空间到物理空间的映射... 5

8.几个相关问题的讨论... 5

一. 概述

内存管理是Linux系统的一个极其重要部分,涉及到虚拟-物理地址映射和寻址,内存分页,内存换页,内核和用户进程的内存分配,内存文件系统等许多内容,本文仅对Linux系统ARM体系结构的内存分页,映射寻址的认识作一个描述。

二.Linux支持的分页管理

为支持多种平台处理器的虚拟内存管理,Linux(2.6.1)版本以后采用了4级分页虚拟地址映射(此版本前采用3级分页映射)的模式,可满足64位CPU的寻址要求。不过,ARM9的MMU只支持两级页表地址转换,且两级能满足32位CPU的存储管理需求,因此ARM体系只使用linux四级中的两级分页。Linux四级分页模式如下图:

缺图 有机会补完整

第一级:

全局页目录表——对应于代码中的PGD (见代码pgtable.h),系统运行时这个页表的首地址存放于ARM协处理器CP15的寄存器C2中,C2寄存器是和堆栈指针SP,程序指针PC同等重要的寄存器,在进行任务(进程)切换时,没有虚拟内存的操作系统只切换SP和PC,有虚拟内存的操作系统增加切换C2,即每个进程都有自己的独立虚拟空间,也就有独立的全局页目录表PGD。

第2、3、4级

这三级行为基本相同,程序中分别缩写为

PUD——页上级目录

PMD——页中间目录

PTE——页表(最末级)

当系统访问一个32位虚拟地址时,假设cache未命中且TLB(页地址快表)中未存有这个地址页的情况下,MMU将全局页目录存放PGD的地址读出来,取虚拟地址的前若干位(32-宏PGDIR_SHIFT)在该表中进行索引,索引到的32位整数即是下一级页表PUD的首地址,一直索引到最末级页表PTE,PTE中对应的索引项内容(32位整数)前若干位为虚拟地址对应的物理页地址,页内偏移量为虚拟地址的后若干位,这样即可以得到一个32位的物理地址。

PTE索引项的后若干位,记录了本页的访问属性和访问权限,读写标志,访问标志等,以便MMU进行控制。

Linux中的宏PAGE_SHIFT, PMD_SHIFT,PUD_SHIFT,PGDIR_SHIFT分别定义了这四级分页各自占用的字段长度。(../arch/arm/include/asm/pgtable.h))

三.ARM9(32位)体系MMU支持的分页模式

ARM存储体系支持的页的大小有几种——1M,64KB,4KB,1KB,支持的二级页表大小有两种:粗粒度和细粒度。在linux中,ARM采用了粗粒度页表4K页的模式如下图,其中一级索引地址有效位为11位,二级索引有效位为9位,页内偏移量为12位:

缺图 有机会补完整

4KB的页大小决定了虚拟地址的低12bit留作偏移地址用。也决定了二级页描述符的低12位作为用户标志用,4K的页大小还决定了虚拟地址空间最多可以映射出(4GB/4KB=1024×1024)个页。程序中下列宏用于定义页的大小:(arch/arm/include/asm/page.h)

#define PAGE_SHIFT 12

#define PAGE_SIZE (1UL << PAGE_SHIFT)

由上可知二级页表加页内偏移的总长度为12+9=21,因此程序中定义中间页表PMD的位数为:(arch/arm/include/asm/pgtable.h)

#define PMD_SHIFT 21

#define PGDIR_SHIFT 21

由各索引表的位数可得到各表的长度:

#define PTRS_PER_PTE 512 表示每个末级页表PTE中含有512个条目(9bit)

#define PTRS_PER_PMD 1 表示中间页表PMD表等同于末级页表PTE

#define PTRS_PER_PGD 2048 表示全局页目录表中含有2048个条目(11bit)

因此概括为,ARM体系下物理内存和虚拟内存按照4KB的大小进行分页,页索引表分为两级,其中全局一级页表PGD一个,表中含有2048个条目,每个条目对应一个二级页表物理首地址。二级页表(PMD或PTE)最多2048个,每个表中含有512个条目,每个条目对应一页物理首地址。

结合起来,ARM体系在Linux系统下二级分页可简要表示如下:

缺图 有机会补完整

启动PUD这一级被屏蔽使用,而PMD则等同于PTE为同一个级别,因此ARM在linux下二级分页为:

虚拟地址——> PGD转换——> PTE转换——> 物理地址

四、相关数据结构

1、页描述符,定义在 include/linux/mm_types.h文件中

struct page {,

}

每个(物理)页具有一个此类型的数据结构,保存了该页的状态信息,例如该页是属于内核还是用户,是否空闲,引用计数,是否缓存等等信息,该结构占用32字节空间,内核通过这个结构掌握一个页的信息。有多少个页,就有多少个页描述符,页描述符统一由内核保存在mem_map数组中。需要占用整个物理内存的1/128

2、页表项,页中间目录项,页上级目录项和页全局目录项的数据结构均为32bit整数:

typedef struct { unsigned long pte; } pte_t; ——页表项的类型

typedef struct { unsigned long pmd; } pmd_t; ——页中间目录项类型

typedef struct { unsigned long pgd[2]; } pgd_t; ——页全局目录项类型

3、进程描述符task_struct中的mm_struct(include/linux/sched.h),这个结构负责描述进程的存储分配,一片被进程控制的连续线性称为一个VMA(vm_area_struct),进程的线性空间中由多个VMA链表连接而成。

五、内存相关的重要的调用

pgd_alloc 分配一个新的全局页目录表,通常用在进程初始化阶段

brk ——调节进程的动态数据段大小。

_get_free_pages 获得连续的页

_alloc_pages 获得连续的页

kmalloc 从slab cache分配空间且其物理内存为连续的

vmalloc 在虚存区分配空间其虚拟内存连续,但物理内存不一定连续

shmget 分配共享存储区,用于进程间共享

mmap ,munmap 将一个文件映射到内存

六、物理内存的定义

Linux系统只需要给出物理内存的首地址和大小,即可定义物理内存给内核使用,相关宏位于/arch/arm/include/asm/memory.h中的

定义物理内存首地址:

#define PHYS_OFFSET (CONFIG_DRAM_BASE)

/*
 * Physical DRAM offset.
 */
#if defined(CONFIG_ARCH_OMAP1)
#define PHYS_OFFSET UL(0x10000000)
#elif defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) || \
defined(CONFIG_ARCH_OMAP4)
#define PHYS_OFFSET UL(0x80000000)      //omap3530 物理地址
#endif

定义物理内存末地址:

#define END_MEM (CONFIG_DRAM_BASE + CONFIG_DRAM_SIZE)

定义物理页起始地址

#define PAGE_OFFSET (PHYS_OFFSET)

/*

define CONFIG_PAGE_OFFSET 0xC0000000    //omap3530

/*
 * PAGE_OFFSET - the virtual address of the start of the kernel image
 * TASK_SIZE - the maximum size of a user space task.
 * TASK_UNMAPPED_BASE - the lower boundary of the mmap VM area
 */
#define PAGE_OFFSET UL(CONFIG_PAGE_OFFSET)

*/

七、从虚拟空间到物理空间的映射

虚拟空间的低3GB部分从0-0XBFFFFFFF的虚拟线性地址,用户态和内核态都可以寻址,这部分也是每个进程的独立空间。

虚拟空间的高1G部分从0XC0000000到0XFFFFFFFF的虚拟地址,只有内核态的进程才能访问,这种限制由页目录和页表描述符的权限标志位决定,通过MMU自动控制。

从虚拟空间的分布,以及到物理地址的空间映射简要可见下图:

缺图 有机会补完整

高1G的内核空间又分为几部分:

1、 线性地址映射区kernel logical address:从0xc0开始之后的最大896M空间,当物理内存小于896M时等于物理内存大小。这部分区域的虚拟地址和物理地址线性映射,虚拟地址和物理地址之间只差一个相同的常数,所有物理内存也在这里纳入内核统一管理。通过kmalloc在本区域内申请到的物理内存是连续的。

2、 虚拟地址映射区(vmalloc区):这一区域内的虚拟地址是连续的,但对应的物理地址可能是不连续的(分页),通过vmalloc在此区域内申请到的存储块其物理地址可能是不连续的。

3、 高端映射区:当物理内存大于896M时,超出的物理内存部分无法由内核直接寻址,通过此段区域间接寻址。

低3G的用户空间主要分为静态的代码段,只读数据段,可写数据段,共享库和动态的栈和堆。动态的栈(stack)通过其自行向下生长调整,动态的堆可通过系统调用brk进行调整,当进程堆不足时,进程向内核申请分配更多的页进行调整。

综上所述,从虚拟空间到物理空间的映射存在多种情况,同一个物理页可能被映射到多个虚拟页,如下图:kernel logical地址即上面的线性地址映射区,其映射是线性连续的不交错,kernel virtual 地址即上面的vmalloc区,其映射到物理空间是交错的不连续。而用户进程空间各种数据映射到的物理地址,是交错的不连续的,且和内核使用的物理地址区域是重叠的。下图描述了一般的情况:

缺图 有机会补完整

八、几个其他和内存分页相关问题的讨论:

1、物理空间由谁控制?

物理空间统一由内核控制,在需要时分配给用户进程。

2、进程间如何隔离?

每个进程有自己的PGD(全局页目录表),因此每个进程有自己的空间映射,内核保证各进程映射使用不同的物理空间,从而隔离。

3、如何保证进程不能访问内核数据?

由页描述符的权限标志位(System/User)控制,联合ARM9上对应寄存器C1中的S,R位,虚拟地址大于0XC0000000的页,其页描述标志为只能由ARM系统模式访问。

4、虚拟内存到物理内存的映射真的能保证系统安全稳定吗?

主处理器使用的指针全部是虚拟地址,因此主处理器能访问的数据只能是映射以内的数据,从而保证了运行在主处理器中的用户任务不会访问不属于自己的数据。(基于内核对自己是信任的这个假设)

但主处理器以外的AMBA总线-Host设备除外,例如DMA控制器,其接到总线没有通过MMU,因此使用的还是物理地址。若用户进程给DMA这种控制器赋予一些非法的物理地址(对主处理器来讲是数据),则有可能冲毁物理内存的任何区域数据!!!

5、用户程序为何一般不和linux系统一起编译?

因用户程序一般都有新的进程,而进程的创建只能是复制的形式(fork或clone),因为要创建全新进程空间的需要,进程的入口函数只能通过exec启动一个二进制进程文件,而不能是一个静态编译的目标函数(因为静态编译无法使进程的主函数位于另一个独立的3G进程空间。)因此一般用户程序和各种库独立于linux编译。此问题我们在其他进程相关的认识文档中再作进一步讨论。

6、应用程序大于物理内存时是否可以执行?

可以执行。分页和换页的机制使得应用程序不必全部加载到内存,而只是加载当前使用的部分页面到内存,从而保证大于物理空间的应用程序能够运行。只是执行效率问题。

有关存储管理的其他问题本文暂不讨论,有关错误和不足望不佞指教

Linux系统中ARM体系的内存分页认识_gowyz的博客-CSDN博客

arm-linux 内存管理之一级页表及二级页表arm32(ARM64是不同的分页机制)

arm32(ARM64是不同的分页机制) 一个 vma 中 有 两个 index //  armv6 RM ref P730
    L1(一级页表,即页目录表)index 为 12位,所以一级页表的大小为 2^12*4B=16KB
    L2(二级页表,页表)index为8位,所以二级页表的大小为2^8*4B=1KB(单独一级索引对应的单独一个二级页表索引的占用字节大小)
    // 所以一套(一级和二级)页表的"最大"大小为
    // 16KB         + 16KB/4B * 1KB = 4MB + 16KB
    // 一级页表大小  + 所有的 二级页表大小

公式备注:L1*4B原因,4B是因为32为位宽度,一次寄存器操作是32位=4字节=4B  2022.11.12

所有一级索引占用的二级页表大小16KB/4B * 1KB原因,因为二级页表是复用,一级页表的每个索引占用一个全部的二级页表,所以需要乘以1KB,16KB/4B=一级索引的数目2022.11.12

arm32 硬件上 有 TTBR0 TTBR1 寄存器,但是linux不使用, Linux内核只使用TTBR1寄存器 (但是内核中页目录基地址是下文中讲述的swapper_pg_dir 为 0x50004000。备注时间2022.11.12)

// CONFIG_ARM_LPAE 的时候才会用 TTBR0
    //https://www.tiehichi.site/2021/11/15/ARMv7%E8%BF%9B%E7%A8%8B%E9%A1%B5%E8%A1%A8/
CP15 C2(决定TTBR0 TTBR1 ,32位系统其它资料说内核和用户都用共同的基址TTBR0,共用一个页表。TTBR1没使用) 用于 存储 页目录表的物理地址(基址)(不是对应I386的段寄存器(存放段选择子,也就是存放段描述符的地址)而是对应I386的页目录基地址的存放寄存器CR3,因为ARM没有段寄存器,所以线性地址直接用32寄存器可得2^32=4GB,线性地址直接进行分页内存管理2022.11.12)

一级页表和二级页表的位置

我们把 一套 (一级页表和二级页表) 称为 一套表,一套表对应一个pgd
如果有N个用户进程,那么有多少套表呢?
答案是N+1套表
    N个表
        对应N个用户进程,每个用户分别有一套表,其中包括(内核表+用户表)
    1个表
        对应M个内核进程(包括idle),只对应一套表,其中包括(内核表,基址为swapper_pg_dir内核表基址这个说法不对,应该在TTBR0中2022.11.12)
        这一套表的大小远远小于 4MB+16KB

// 每个进程有自己的pgd,pgd中包含了用户虚拟地址空间映射和内核虚拟地址空间映射
// 不同进程的内核虚拟地址空间映射是相同的,在arm32上都是从swapper_pg_dir复制过来的( 不一定对2022.11.12)

1
2
3
4
5
6
7
8
9
10
11
12
swapper_pg_dir

arch/arm/kernel/head.S
 48     .globl  swapper_pg_dir                                                       
 49     .equ    swapper_pg_dir, KERNEL_RAM_VADDR - PG_DIR_SIZE

// 在 ok6410中 , KERNEL_RAM_VADDR  = 0x50008000
// PG_DIR_SIZE 为 0x00004000
// 则 swapper_pg_dir 为 0x50004000(内核页目录的基地址没放在寄存器类似i386的CR3,和上文)

内核页目录表基址在swapper_pg_dir , 大小为16K
具体物理地址范围 为 0x50004000 - 0x50007FFF

上述两行的内核基址说法是错误的(ARM32内核基址在TTBR0中),好几篇文章都这么说,以下文是linux的swapper_pg_dir解释,也表明页基址在TTBR0中

linux 的启动涉及到一个解压与定位的过程,对于x86体系结构而言,系统被加载到0x100000的地方,那么swapper_pg_dir的值是什么呢?我们知道swapper_pg_dir是一个很重要的东西,它是所有进程内核空间的页表的模板,而且在涉及到896M以上的内存分配时,swapper_pg_dir也是一个同步的根,这些内存分配包括vmalloc区,高端永久区,高端临时区等。这里需要说明的是,swapper_pg_dir这个东西其实就是一个页目录的指针,页目录指针在x86中是要被加载到cr3寄存器的(使用的 arm产品芯片是没有实现LPAE(Large Physical Address Extension)的VMSA 架构 (即使用MMU管理内存的架构,区别于用MPU来管理内存的PMSA)时,可以使用TTBR0与TTBR1来做保存页表的起始地址,而一个VA具体是用哪一个寄存器中的地址来做translation table walk时,要看TTBCR寄存器的N值以及VA的具体值, 具体看: ARM? Architecture Reference Manual  ARMv7-A and ARMv7-R edition 的文档说明(ARMv7是32位,ARMv8引入64位)。而因为ARM不能用0xC0000000做为TTBR0与TTBR1所管理的VA的分界,所以Linux并没有使用TTBR1,而是不管是内核空间还是用户空间都只使用TTBR0做为Translation table的存储地址寄存器。(复制上面一段:

虚拟空间的低3GB部分从0-0XBFFFFFFF的虚拟线性地址,用户态和内核态都可以寻址,这部分也是每个进程的独立空间。

虚拟空间的高1G部分从0XC0000000到0XFFFFFFFF的虚拟地址,只有内核态的进程才能访问,这种限制由页目录和页表描述符的权限标志位决定,通过MMU自动控制。


),每个进程都有一个页目录指针,这个指针指示这个进程的内存映射信息,每当切换到一个进程时,该进程的页目录指针就被加载到了cr3,然后直到切换到别的进程的时候才更改,既然swapper_pg_dir是一个页目录指针,那么这个指针是被哪个进程用的呢?现代 操作系统 的含义指示了进程间内存隔离,那么一个页目录指针只能被一个进程使用,那么到底是哪个特定的进程使用了swapper_pg_dir指针呢?遗憾的是,答案是没有任何用户进程使用swapper_pg_dir作为页目录指针,swapper_pg_dir只是在内核初始化的时候被载入到cr3指示内存映射信息,之后在init进程启动后就成了idle内核线程的页目录指针了,/sbin/init由一个叫做init的内核线程exec而成,而init内核线程是原始的内核也就是后来的idle线程do_fork而成的,而在do_fork中会为新生的进程重启分配一个页目录指针,由此可见swapper_pg_dir只是在idle的内核线程中被使用,可是它的作用却不只是为idle进程指示内存映射信息,更多的,它作为一个内核空间的内存映射模板而存在,在 Linux 中,任何进程在内核空间就不分彼此了,所有的进程都会公用一份内核空间的内存映射,因此,内核空间是所有进程共享的,每当一个新的进程建立的时候,都会将swapper_pg_dir的768项以后的信息全部复制到新进程页目录的768项以后,代表内核空间。另外在操作3G+896M以上的虚拟内存时,只会更改swapper_pg_dir的映射信息,当别的进程访问到这些页面的时候会发生缺页,在缺页处理中会与swapper_pg_dir同步。

swapper_pg_dir
被定义在arch/arm/kernel/head.S
#ifdef CONFIG_ARM_LPAE                           
    /* LPAE requires an additional page for the PGD */
#define PG_DIR_SIZE 0x5000                       
#define PMD_ORDER   3                            
#else                                            
#define PG_DIR_SIZE 0x4000                                 
#define PMD_ORDER   2                            
#endif                                           
                                                 
    .globl  swapper_pg_dir                       
    .equ    swapper_pg_dir, KERNEL_RAM_VADDR - PG_DIR_SIZE
伪指令equ定义          swapper_pg_dir 值为                        KERNEL_RAM_VADDR - PG_DIR_SIZE

ARM linux内核启动时几个关键地址  
————————————————
版权声明:本文为CSDN博主「dumb_man」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/dahailantian1/article/details/78584821

(二级页表的地址范围就比较随意了, alloc获取的地址是哪里,就在哪里(i386也没明确规定二级页表的地址范围2022.11.12)
1
2
3
4
5
6
7
8
9
10
11
12

页表的填充本质是什么

本质是 对 写内存 和 CP15 C2 寄存器的改变

写 CP15 C2 寄存器的本质来说
    1. 将一级页表(有N+1套)的基址写入该寄存器

写内存详细一点来说是
    1. 确定写哪个  一级页表项 (即确定即将写入的一级页表项 的地址),并写入值
    2. 确定写哪个  二级页表项 (即确定即将写入的二级页表项 的地址),并写入值

1
2
3
4
5
6
7
8
9

页表的复制

内核页表是什么时候创建的
    内核初始化的时候(从_stext到start_kernel),创建了
        一级页表和二级页表
            包括 Image atags mmu_turn_on附近代码的映射
    从start_kernel 到 运行时,创建了
        1. 设备映射
        2. 内存管理相关映射等

为什么要复制
    ARM32位处理器,由于无法通过TTBR0、TTBR1同时设置内核页表项地址和用户空间页表项地址,所以采用创建进程时拷贝内核空间页表的方式来实现共享内核空间的操作。

参考代码 kernel/fork.c 中的 copy_mm

idle进程进程创建的时候有没有复制内核页表?
    没有,页目录表基址还是为swapper_pg_dir ,即0x50007000)
    // 内核进程直接使用swapper_pg_dir作为基址
其他(kthreadd)内核进程的时候有没有赋值内核页表
    没有,页目录表基址还是为swapper_pg_dir ,即0x50007000)
    // 内核进程直接使用swapper_pg_dir作为基址
init 内核进程 转换为 用户进程 的时候有没有赋值内核页表
    有,创建了一套页表,并复制了内核页表中的内容到新的一套页表中
用户进程创建的
    有,创建了一套页表,并复制了内核页表中的内容到新的一套页表中

复制之后怎么实时同步多套页表中的"内核页表内容"?
    Linux arm进程内核空间页表同步机制 https://codeleading.com/article/77246118335/
    
    性能分析
        内核空间的虚拟地址也是在不停的变换的,
        如果映射一段地址就去主动更新所有进程页表的内核部分,显然是相当不划算的。
        一个进程映射的地址,其他进程很大概率是不会用到的。
        所以采用缺页中断的方式,在需要使用时,去拷贝页表。
        init_mm的pgd,则保存了完整的内核空间页表。
    
    实际情况
        在vmalloc、vmap亦或者ioremap时,内核空间页表会进程调整
        会修改 init_mm.pgd(swapper_pg_dir)中的一套页表内容 (即N+1中的那1套表),
        并没有修改用户进程中的那套表中的该内容
        
        在用户进程访问时,会产生缺页异常,在异常中,"拷贝内核对应页表到进程中"

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44

页表的切换

进程陷入内核空间时,不进行页表切换 // 因为切不切换都一样
进程退出内核空间时,如果要切换到与之前不同的进程,则要切换,否则,不需要切换

当进程切换时,有可能进行 页表的切换
switch_mm // switch_mm 只在内核态下运行
有几种情况 // 只要即将切入的进程为用户进程,就切换
    内核进程->内核进程 不切换
    内核进程->用户进程 切换
    用户进程->内核进程 不切换
    用户进程->用户进程 切换 
1
2
3
4
5
6
7
8
9
10
11

early_pte_alloc

arch/arm/mm/mmu.c
early_pte_alloc 
    arm_pte_alloc
        pte_t *pte = alloc(PTE_HWTABLE_OFF + PTE_HWTABLE_SIZE); 
            // 申请内存 , 512*4 + 512*4
            // 申请了 hwtable[0]和hwtable[1]
            // 申请了 linuxtable[0]和linuxtable[1] 
            // 为什么要申请 linuxtable??? ,查看 "linux 页表 与 arm32硬件页表是如何兼容的"
            // 即申请4KB空间(2个linux页表,2个arm页表)// 一个页表大小为1KB
        __pmd_populate(pmd, __pa(pte), prot);
            // 填充 pmd[0] 为 hwtable[0]的基址
            // 填充 pmd[1] 为 hwtable[1]的基址
            // 即将2个arm页表的基地址写入2个l1页表表项(pmd[0]和pmd[1])
        return pte_offset_kernel(pmd, addr);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

linux 页表 与 arm32硬件页表是如何兼容的

https://elixir.bootlin.com/linux/v5.11/source/arch/arm/include/asm/pgtable-2level.h#L13

arm页表和"linux对页表的要求"有矛盾
    ARM32现状:Most of the bits in the second level entry are used by hardware, and there aren't any "accessed" and "dirty" bits.
    Linux要求:However, Linux also expects one "PTE" table per page, and at least a "dirty" bit.

解决方案:
    针对第一级页表的改变
        1.Therefore, we tweak the implementation slightly - we tell Linux that we have 2048 entries in the first level, each of which is 8 bytes (iow, two hardware pointers to the second level.)  
        // 这也是 pmd[0] 和 pmd[1]的由来
    针对第二级页表的改变
        2.The second level contains two hardware PTE tables arranged contiguously, preceded by Linux versions which contain the state information Linux needs.  We, therefore, end up with 512 entries in the "PTE" level.
        // 这里是 linuxtable[0] 和 linuxtable[1]的由来

现状:
    See L_PTE_xxx below for definitions of bits in the "Linux pt", 
    See PTE_xxx for definitions of bits appearing in the "h/w pt".
    PMD_xxx definitions refer to bits in the first level page table.
    
    dirty bit
        The "dirty" bit is emulated by only granting hardware write permission iff the page is marked "writable" and "dirty" in the Linux PTE.
        This means that a write to a clean page will cause a permission fault, and the Linux MM layer will mark the page dirty via handle_pte_fault().
    access bit
        For the hardware to notice the permission change, the TLB entry must be flushed, and ptep_set_access_flags() does that for us.
        The "accessed" or "young" bit is emulated by a similar method; we only allow accesses to the page if the "young" bit is set.
        Accesses to the page will cause a fault, and handle_pte_fault() will set the young bit for us as long as the page is marked present in the corresponding Linux PTE entry.
        Again, ptep_set_access_flags() will ensure that the TLB is up to date.
        However, when the "young" bit is cleared, we deny access to the page by clearing the hardware PTE.
        Currently Linux does not flush the TLB for us in this case, which means the TLB will retain the transation until either the TLB entry is evicted under pressure, or a context switch which changes the user space mapping occurs.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
文章知识点与官方知识档案匹配,可
————————————————
版权声明:本文为CSDN博主「__pop_」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/u011011827/article/details/122636894

Linux系统ARM32(64位不同)体系内存分页(ARM没段寄存器,分页内存内核和进程共用一套,页目录基址是CP15 C2控制的TTBR0,没用TTBR1,二级表基址alloc获取相关推荐

  1. LINUX系统ORACLE11G 64位安装文件,非官方下载,不需要登录ORACLE账户linux.x64_11gR2_database

    从oracle官方下载还得注册一个oracle的帐号,这个不需要,直接下载的文件. 注意这是linux版本的,64位,oracle11g的. 解压密码:123456 网盘文件,可能会有一个广告页面,请 ...

  2. linux系统snmpd服务内存偏高,Red Hat Enterprise Linux 5.4 64位系统SNMP内存泄漏(上)

    1.SNMP的内存泄漏问题 SNMP的内存泄漏问题,我最早是在CDN的一台负载均衡调度机上看到的.一个snmpd进程,占用的VIRT将近4G.重启snmpd后VIRT降到150M左右,机器为Red H ...

  3. 32位系统 和 64位系统 C 程序中 为什么 指针的内存大小的不一样

    以下均为自己猜想: 32位系统是因为有32根地址总线 ,64位系统由64根地址总线 所以从根本上有了32位和64位的系统的根本区别 指针就是地址,所不管什么类型的指针在32位的系统上,就是一个32位的 ...

  4. linux查看证书位数,查看Linux系统是32位还是64位(getconf WORD_BIT误区)

    在写脚本(如:lnmp)时,经常需要判断linux操作系统是64bit还是32bit,如果是64bit执行这个命令(ln -s/usr/local/lib/libmcrypt.la /usr/lib6 ...

  5. 【32位系统与64位系统可访问内存的大小】

    64位系统究竟能支持多大内存? 1.理论计算 对较大存储数据的形象解释: 一卷磁带:200MB 一张CD光盘:500MB 一部广播级质量电影:1GB 一卷大型数字磁带:100GB 五万棵树制成的纸:1 ...

  6. win10服务器只显示4g内存,系统win10 64位 两个内存条一个4g一共8g显示8g但是可用只有3.9g...

    点击查看系统win10 64位 两个内存条一个4g一共8g显示8g但是可用只有3.9g具体信息 系统win10 64位 两个内存条一个4g一共8g显示8g但是... 答:在开始图标上右键,选择运行,输 ...

  7. win7 php mysql apache 64_教你在64位win7体系中设备apache+mysql+php情况.doc

    教你在64位win7体系中设备apache+mysql+php情况.doc 还剩 4页未读, 继续阅读 下载文档到电脑,马上远离加班熬夜! 亲,喜欢就下载吧,价低环保! 内容要点: 在 DOS 命令提 ...

  8. linux 版本信息 64位,Centos查看版本信息

    作为一个开发人员,在拿到一台Linux服务器之后会先查看系统的版本信息,接下来吾爱编程为大家介绍一下Centos查看版本信息的相关命令,有需要的小伙伴可以参考一下: (一).查看已安装的信息 cat ...

  9. Win7纯净版系统镜像64位介绍

    Win7系统是一款非常经典的系统,这里想为大家介绍的是Win7纯净版系统镜像64位,主要特点就是非常稳定,运行流畅.占用CPU和内存都非常少.系统非常纯净,使用此系统,可让你的电脑焕然一新! 一.系统 ...

  10. steam linux 64位,Valve可能会很快为Linux发布原生64位Steam客户端

    原标题:Valve可能会很快为Linux发布原生64位Steam客户端 Valve在今天发布了一款针对Windows.Mac和Linux平台的全新稳定版本的Steam客户端,仅做了两项改动,其中一项改 ...

最新文章

  1. android使用C/C++调用SO库
  2. mac编译openresty报Undefined symbols for architecture x86_64
  3. pdo mysql.so不存在_PHP致命错误:找不到类’PDO’
  4. 在项目中遇到的一些bug
  5. MyBatisPlus的ActiveRecord(活动记录)简介以及怎样使用
  6. JavaScript基础01【简介、js编写位置、基本语法(6种基本数据类型)】
  7. android settext 参数,Android TextView.setTextColor()的参数设置方式
  8. 对话框大小与像素关系
  9. Linux引导流程(第二版)
  10. hibernate 继承映射(二)
  11. 【干货】腾讯员工职业发展框架.pdf(附下载链接)
  12. win7怎么安装消息队列 MSMQ
  13. arm linux docker,ARM64上的Docker编译与安装
  14. 自主创新生态圈再扩大,深度科技与金格科技完成产品兼容性认证
  15. Vue入门项目:学生管理系统之班级管理 【含源码】
  16. 记一次springboot应用偶发502错误的排查过程
  17. IEEE协会首次在京举办研讨会,王飞跃称不存在AI芯片
  18. Python数据处理016:Pandas 导入导出
  19. 计算机主板上的命名,电脑主板常见命名规则整理:微星;华硕;技嘉
  20. OD常用断点函数(转载)

热门文章

  1. Hybrid App(混合模式移动应用)
  2. ESP8266(WeMos D1 R1)+DHT22采集温湿度
  3. HDU-1317 XYZZY SPEA
  4. 星际争霸 虚空之遗 人族5BB 操作流程
  5. 05——去哪儿(旅游网站首页开发)
  6. 计算机网络技术-Mooc
  7. 11张好用的项目管理全流程图,支持下载保存(PMP项目管理可用)
  8. lol 8.21服务器维护,《LOL》8.16版本维护到几点 8月21日更新维护内容汇总
  9. Pymol一些命令及使用小技巧
  10. 产品商业需求文档_【器】我的产品需求文档心法