IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> 内存基础小知识(arm) -> 正文阅读

[嵌入式]内存基础小知识(arm)

?

?

?

处理器的cr0寄存器Pcd标志用来启用或者禁用高速缓存电路。

pcd标志是访问叶匡中的数据时高速缓存是否开启,pwt表示将数据写到叶匡的时候采用的回写策略是通写还是回写。

TLB用于缓存刚刚被访问的物理地址。每个cpu都有一个TLB。

常用宏功能:

PAGE_SHIFT:指定offset字段的位数,页框大小。

PMD_SHIFT指定线性地址的offset字段与table字段的总位数。32位当PAE被禁用的时候是22位offset(12)+table(10),PMD_MASK为0xffe00000。

PUD_SHIFT:页上级目录项所映射的区域大小的对数。32位的环境上由于是两级页表所以总是等于PMD_SHIF。

PGDIR_SHIFT:页全局目录项所能映射的区域大小的对数。PGDIR_MASK宏用于屏蔽offset、table、middle、upper字段的所有位。

PTRS_PER_PTE、OTRS_PED_PMD、PTRS_PER_PUD、PTRS_PER_PGD用于计算页表、页中间目录、页上级目录和页全局目录表中的表项个数。

pte_t、pmd_t、pud_t、pgd_t分别描述页表项、页中间目录项、页上级目录和页全局目录定义。

__pte\__pmd\__pud\__pgd\__pgprot和pte_val\pmd_val\pud_val\pgd_val\pgprot_val是将相应表项和无符号整数相互转换。

pte_none\pmd_none\pud_none\pgd_none表示相应的表项值为0则返回1否则返回0。

pte_clear\pmd_clear\pud_clear\pgd_clear清除相应的表项,set_pte\set_pmd\set_pud\set_pgd向一页表中写入指定的值。

pte_same表示两个页表项指向相同的页且有相同的访问优先级则返回1否则返回0。

pmd_large(e)当e指向大型页则返回1。

pmd_bad用于检查传入的页中间目录参数,如果页中间所指向的页表满足下列之一返回1。

a页不存在(present标志被清除)b页只允许读访问(read\write标志被清除) c access或者 dirty标志被清除。pud_bad和pgd_bad总是返回0,没有定义pte_bad。

pte_user\pte_read读取user/supervisor标志

pte_write\pte_exec读取read/write标志

pte_dirty 读取dirty标志

pte_young 读取accessed标志

pte_file读取dirty标志

设置页标志函数:

mk_pte_huge设置页表中的page size和present标志

pte_wrprotect 清除read/write标志

pte_rdprotect/pte_exprotect 清除user/supervisor标志

pte_mkwrite 设置read/write标志

pte_mkread/pte_mkexec ?设置user/supervisor标志

pte_mkclean 清除dirty标志

pte_mkdirty 设置dirty标志

pte_mkold/pte_mkyoung ?清除/清除accessd标志

pte_modify(p,v) 把页表p所有访问权限设置为v

ptep_set_wrprotect 与pet_protect类似但是只是针对页表项。

petp_set_access_flags 如果dirty为1则将页的存取权限设置为指定的值,并且调用flush_tlb_page函数刷新tlb。

ptep_test_and_clear_dirty 只是针对页表项

petp_test_and_clear_young 只是针对页表项

页表操作宏:

pgd_index(addr) 找到现行地址addr对应的目录项在页全局目录中的索引。

pgd_offset(mm,addr)根据addr找到页全局目录内的相应页目录项的线性地址。

pgd_offset_k(addr) 产生内核页全局目录包含addr的目录项。

pgd_page(pgd) 产生页上级目录所在页框的页描述符地址。

pud_offset(pgd,addr) 页上级目录中目录项addr对应的线性地址

pud_page(pud) 通过页上级目录pud产生相应的页中间目录的线性地址。

pmd_index(addr) 产生线性地址addr在页中间目录的目录项的索引

pmd_page(pmd) 页中间目录项pmd产生的页表描述符地址。

mk_pte(p,prot) 接收页描述符地址p和存取权限prot作为参数

pte_index(addr) 产生线性地址addr对应的表项在页表中的索引

pte_offdset_kernel(dir,addr),dir是页中间目录,线性地址addr在页中间目录dir中的对应的项即页表的线性地址。

pte_offset_map(dir,addr)接收指向一个页中间目录项的指针dir和线性地址addr作为参数,产生与线性地址addr相对应的页表项的线性地址。

pte_page(x) 返回页表项x所引用的描述符地址

pte_to_pgoff(pte) 从一个页表项的pte字段中提取文件偏移量,这个文件偏移量对应着一个非线性文件内存映射所在的页。

pgoff_to_pte(offset)为非线性文件内存所映射的页创建对应的页表项的内容

pgd_alloc(mm) \pgd_free分配一个新的页全局目录

pud_alloc(mm,pgd,addr)/pud_free分配pud

pmd_alloc(mm,pud,addr)/pmd_free,为addr分配个新的页中间目录

pte_alloc_(mm,pmd,addr) 如果页中间目录为空则分配个新的页表,addr对应的项目被创建且user/supervisor标志被设置为1。如果页表在高端内存则建立一个临时映射

pte_alloc_kernel(mm,pmd,addr)分配一个新的页表然后返回与addr相关的线性地址。

pte_free(pte)释放与页描述符指针相关的页表

pte_free_kernel(pte) 内核主页表使用类似与pte_free

clear_page_range(mmu,start,end)从线性地址start到end通过反复释放页表和清除页中间目录项来清除进程页表内容。

set_fixmap(idx,phyaddr)将idx指定的页表设置为phyaddr指定的物理地址

set_fixmap_nocache(idx,phyaddr)类似set_fixmap 只是多设置了pcd标志表示不使用cache缓存。

L1_CACHE_BYTES?表示高速缓存行的L1的大小以字节为单位

flush_tlb_all ??刷新所有的TLB表项。

flush_tlb_kernel_range刷新给定范围内的所有的TLB表

flush_tlb 刷新当前进程拥有的非全局页相关的所有TLB

flush_tlb_mm 刷新指定进程拥有的TLB非页全局相关的所有TLB

flush_tlb_range 刷新指定进程的线性地址间隔对应的TLB表项

flush_tlb_pgtables 刷新指定进程中特定的相邻页表集相关的TLB

flush_tlb_page 刷新指定进程中单个页表项相关的TLB表项

任何进程切换都会更新活动页表集,本地tlb必须刷新

_count 页的引用计数 ?page_count()函数返回_count+1后的值

flags ?页框状态的标志

使用GFP_KERNEL的标志分配内存页面即使没有足够的页面也不会被阻塞,仅仅是分配失败而已,,一般情况下内核会保留一个页框池,在内存不足时供GFP_KERNEL使用,保留内存数量存放在min_free_kbytes(KB);

请求页框标志:?

?

组合标志:

?

?

page_address(mm/highmem.c):返回页框对应的线性地址

1 根据PG_highmem标志判断页框是否在高端地址,不在则直接根据页框下标转换成物理地址再转换成线性地址。

2 是高端地址,则到page_address_htable散列表查找,找到对应的页框则返回线性地址否则返回NULL;

永久映射:

高端内存映射函数(arm arch/arm/mm/highmem.c):

kamp

1 首先判断页框是否是高端地址通过PG_highmem标志。不是则通过page_address直接返回对应的线性地址。

2 是高端地址调用kmap_high

  1. 调用page_address检查是否已经被映射,没有则调用map_new_virtual
  2. 增加引用计数
  3. 如果刷新完所有的kamp_count依旧没有找到空闲的则进入睡眠阻塞,唤醒之后调用page_address查看是否别人已经映射了,如果没有则重新查找。

?map_new_virtual:

  1. 遍历pkmap_count查找一个空项,保存查找到的索引值
  2. 设置特殊页表pkmap_page_table的索引值对应的项,设置 ???????????????????

pkmap_count表示已经使用。

对应的函数kunmap

??1 如果不是高端地址页框则直接返回,因为永远线性映射区不需要释放

2 调用 kunmap_high去释放

kunmap_high:

  1. 将pkmap_count对应的项减一
  2. 如果减一之后为1则判断是否存在睡眠等待的进程,存在则唤醒

struct vm_struct {

????struct vm_struct ???*next;//指向下一个vm,链表第一个元素被vmlist变量指向

????void ???????????*addr;//内存区的第一个内存单元线性地址

????unsigned long ??????size;//内存区大小+4096

????unsigned long ??????flags;//非连续内存区映射的内存类型

????struct page ????**pages;//指向nr_pages数组指针,该数组由指向页描述符的指针组成

????unsigned int ???????nr_pages;//内存区填充的页面的个数

????phys_addr_t ????phys_addr;//该字段为0,除非内存已经被创建来映射一个硬件设备的io共享内存

????const void ?????*caller;

};

flags:

VM_ALLOC表示vmalloc得到的页

VM_MAP 使用vmap映射的已经被分配的页

IO_IOREMAP 表示使用ioremap映射的硬件设备的板上内存

get_vm_area如果flags没有指定VM_NO_GUARD则添加vmalloc的间隙。

vmalloc函数的解析:

{

return __vmalloc_node_flags(size, NUMA_NO_NODE,GFP_KERNEL);

}

return __vmalloc_node(size, 1, flags, PAGE_KERNEL,node, __builtin_return_address(0));

??1 ???获取vm且设置va(首先查找全局free_vmap_cache红黑树找到开始地址最小的va,然后从此vm开始遍历查找两个va之间最小的且合适的间隙如果没有找到则在va末尾添加一个,然后将va信息填充到vm里)

2 ???调用__vmalloc_area_node去获取物理页面并且设置页表。

临时映射:可以用在中断或者可延迟函数内部不会阻塞上下文。注意是在kmap_atomic关抢占在__kunmap_atomic才会打开抢占。pagefault也一样。

kmap_atomic:建立临时映射

1 判断是否是高端地址,如果不是直接调用page_address返回线性地址

2 对于高端地址则设置pte页表为page构造的pte。

__kunmap_atomic:解除临时映射

????1 刷新dcache 。

2 清除对应的页表。

__zone_watermark_ok:检查水位是否符合指定的值

1 首先判断是否设置了ALLOC_HARDER或者ALLOC_OOM值,如果设置了则认为是alloc_harder申请。如果没有指定则将free_pages减去nr_reserved_highatomic,去掉高端保留内存

2 指定了则继续判断是否指定了ALLOC_OOM,如果指定了则设置min减半否则min减少1/4。

3 判断free_pages是否小于min+z->lowmem_reserve,如果小于则返回false

4 判断传入参数order为0 则立即返回真

5 从order开始遍历存在非空的则返回true,如果是alloc_harder,则MIGRATE_HIGHATOMIC不空则也返回true。

总结就是判断在mark和保留内存水位之上且存在一个大于等于order的连续内存。

?

?

?

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2021-09-11 18:59:12  更:2021-09-11 19:01:03 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/19 20:15:28-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码