phyPage.c是对物理页面管理相关的内容。在SylixOS中虚拟页面和物理页面都是使用相同的数据结构管理,下文使用vmpage代表这个结构体,如下图

在物理页面中不管存在zone数组,还有一个内核内存信息的数组,用来保存代码段和数据段的大小。

/*********************************************************************************************************物理 zone 控制块数组
*********************************************************************************************************/
LW_VMM_ZONE                 _G_vmzonePhysical[LW_CFG_VMM_ZONE_NUM];     /*  物理区域                    */
/*********************************************************************************************************物理内存 text data 段大小
*********************************************************************************************************/
static LW_MMU_PHYSICAL_DESC _G_vmphydescKernel[2];                      /*  内核内存信息                */

 __vmmPhysicalCreate

此函数是物理内核页面创建函数

/*********************************************************************************************************
** 函数名称: __vmmPhysicalCreate
** 功能描述: 创建一个物理分页区域.
** 输 入  : pphydesc          物理区域描述表
** 输 出  : ERROR CODE
** 全局变量:
** 调用模块:
*********************************************************************************************************/
ULONG  __vmmPhysicalCreate (LW_MMU_PHYSICAL_DESC  pphydesc[])
{REGISTER ULONG  ulError = ERROR_NONE;static   ULONG  ulZone  = 0;                                        /*  可多次追尾添加内存          */INT    i;for (i = 0; ; i++) {if (pphydesc[i].PHYD_stSize == 0) {break;}_BugFormat(!ALIGNED(pphydesc[i].PHYD_ulPhyAddr, LW_CFG_VMM_PAGE_SIZE), LW_TRUE,"physical zone vaddr 0x%08lx not page aligned.\r\n", pphydesc[i].PHYD_ulPhyAddr);switch (pphydesc[i].PHYD_uiType) {case LW_PHYSICAL_MEM_TEXT:if (_G_vmphydescKernel[LW_PHYSICAL_MEM_TEXT].PHYD_stSize) {_G_vmphydescKernel[LW_PHYSICAL_MEM_TEXT].PHYD_stSize += pphydesc[i].PHYD_stSize;} else {_G_vmphydescKernel[LW_PHYSICAL_MEM_TEXT] = pphydesc[i];}break;case LW_PHYSICAL_MEM_DATA:if (_G_vmphydescKernel[LW_PHYSICAL_MEM_DATA].PHYD_stSize) {_G_vmphydescKernel[LW_PHYSICAL_MEM_DATA].PHYD_stSize += pphydesc[i].PHYD_stSize;} else {_G_vmphydescKernel[LW_PHYSICAL_MEM_DATA] = pphydesc[i];}break;case LW_PHYSICAL_MEM_DMA:_BugHandle((pphydesc[i].PHYD_ulPhyAddr == (addr_t)LW_NULL), LW_TRUE,"physical DMA zone can not use NULL address, you can move offset page.\r\n");/*  目前不支持 NULL 起始地址    */if (ulZone < LW_CFG_VMM_ZONE_NUM) {_BugFormat(__vmmLibVirtualOverlap(pphydesc[i].PHYD_ulPhyAddr, pphydesc[i].PHYD_stSize), LW_TRUE,"physical zone paddr 0x%08lx size: 0x%08zx overlap with virtual space.\r\n",pphydesc[i].PHYD_ulPhyAddr, pphydesc[i].PHYD_stSize);ulError = __pageZoneCreate(&_G_vmzonePhysical[ulZone], pphydesc[i].PHYD_ulPhyAddr, pphydesc[i].PHYD_stSize,LW_ZONE_ATTR_DMA, __VMM_PAGE_TYPE_PHYSICAL);   /*  初始化物理 zone             */if (ulError) {_DebugHandle(__ERRORMESSAGE_LEVEL, "kernel low memory.\r\n");_ErrorHandle(ulError);return  (ulError);}ulZone++;}break;case LW_PHYSICAL_MEM_APP:_BugHandle((pphydesc[i].PHYD_ulPhyAddr == (addr_t)LW_NULL), LW_TRUE,"physical APP zone can not use NULL address, you can move offset page.\r\n");/*  目前不支持 NULL 起始地址    */if (ulZone < LW_CFG_VMM_ZONE_NUM) {ulError = __pageZoneCreate(&_G_vmzonePhysical[ulZone], pphydesc[i].PHYD_ulPhyAddr, pphydesc[i].PHYD_stSize,LW_ZONE_ATTR_NONE, __VMM_PAGE_TYPE_PHYSICAL);   /*  初始化物理 zone             */if (ulError) {_DebugHandle(__ERRORMESSAGE_LEVEL, "kernel low memory.\r\n");_ErrorHandle(ulError);return  (ulError);}ulZone++;}break;default:break;}}return  (ERROR_NONE);
}

首先判断当前物理区域的类型,地址,大小和属性都是在bsp的bspMap.h 文件里指定的

当时TEXT和DATA段时将其统计到内核信息数组中。 如果是APP和DMA区域就要创建一个zone。这里创建的是物理的zone。zone分为物理的和虚拟地址的两种。调用__pageZoneCreate函数创建一个zone 。此函数在pageLib.c中,可以参考链接链接

创建完成zone以后,以下函数都是和分配空间释放空间相关。分配和释放操作会大量调用pageLib.c中的函数来实现。

 __vmmPhysicalPageAlloc

此函数的功能是从zone中分配一个物理页面控制制块出来,页就是最开始介绍的结构体,里面包含了其实地址,和页面数,使用

vmpage代表这个结构体实体。

/*********************************************************************************************************
** 函数名称: __vmmPhysicalPageAlloc
** 功能描述: 分配指定的连续物理页面
** 输 入  : ulPageNum     需要分配的物理页面个数
**           uiAttr        需要满足的物理页面属性
**           pulZoneIndex  物理 zone 下标
** 输 出  : 页面控制块
** 全局变量:
** 调用模块:
*********************************************************************************************************/
PLW_VMM_PAGE  __vmmPhysicalPageAlloc (ULONG  ulPageNum, UINT  uiAttr, ULONG  *pulZoneIndex)
{INT            i;REGISTER PLW_VMM_ZONE   pvmzone;REGISTER PLW_VMM_PAGE   pvmpage = LW_NULL;for (i = 0; i < LW_CFG_VMM_ZONE_NUM; i++) {                         /*  优先选择 uiAttr 相同的 zone */pvmzone = &_G_vmzonePhysical[i];if (!pvmzone->ZONE_stSize) {                                    /*  无效 zone                   */break;}if (pvmzone->ZONE_uiAttr == uiAttr) {if (pvmzone->ZONE_ulFreePage >= ulPageNum) {pvmpage = __pageAllocate(pvmzone, ulPageNum, __VMM_PAGE_TYPE_PHYSICAL);if (pvmpage) {*pulZoneIndex = (ULONG)i;return  (pvmpage);}}}}for (i = 0; i < LW_CFG_VMM_ZONE_NUM; i++) {pvmzone = &_G_vmzonePhysical[i];if (!pvmzone->ZONE_stSize) {                                    /*  无效 zone                   */break;}if ((pvmzone->ZONE_uiAttr & uiAttr) == uiAttr) {                /*  其次选择拥有 uiAttr 的 zone */if (pvmzone->ZONE_ulFreePage >= ulPageNum) {pvmpage = __pageAllocate(pvmzone, ulPageNum, __VMM_PAGE_TYPE_PHYSICAL);if (pvmpage) {*pulZoneIndex = (ULONG)i;return  (pvmpage);}}}}return  (LW_NULL);
}

此函数主要是使用__pageAllocate 函数去分配指定的页面数量,__pageAllocate函数在pagelib.c中实现,现在其实可以更好的理解这个pageLib.c名称,无论是虚拟页面还是物理页面分配时都以调用其中的函数,像库一样使用。根据注释很容易明白这段代码的意思,首先zone是存在属性的,分配物理页面首先在属性相同的zone去分配,如果没有分配失败,则在不同属性的zone去分配。还有一个函数__vmmPhysicalPageAllocZone是在指定zone中分配空闲物理页面出来。

/*********************************************************************************************************
** 函数名称: __vmmPhysicalPageAllocZone
** 功能描述: 分配指定的连续物理页面 (指定物理区域)
** 输 入  : ulZoneIndex   物理区域
**           ulPageNum     需要分配的物理页面个数
**           uiAttr        需要满足的页面属性
** 输 出  : 页面控制块
** 全局变量:
** 调用模块:
*********************************************************************************************************/
PLW_VMM_PAGE  __vmmPhysicalPageAllocZone (ULONG  ulZoneIndex, ULONG  ulPageNum, UINT  uiAttr)

此函数只是在上一个函数的基础上少了在别的属性zone中查找。

以上分配函数并没有指定对齐,__vmmPhysicalPageAllocAlign函数指定了对齐方式

/*********************************************************************************************************
** 函数名称: __vmmPhysicalPageAllocAlign
** 功能描述: 分配指定的连续物理页面 (可指定对齐关系)
** 输 入  : ulPageNum     需要分配的物理页面个数
**           stAlign       内存对齐关系
**           uiAttr        需要满足的物理页面属性
**           pulZoneIndex  物理 zone 下标
** 输 出  : 页面控制块
** 全局变量:
** 调用模块:
*********************************************************************************************************/
PLW_VMM_PAGE  __vmmPhysicalPageAllocAlign (ULONG   ulPageNum, size_t  stAlign, UINT    uiAttr, ULONG  *pulZoneIndex)

__vmmPhysicalPageAllocAlign函数和__vmmPhysicalPageAlloc函数基本相同,在分配的时候换成了__pageAllocateAlign函数来分配,当然此函数也在pageLib.c文件中。

__vmmPhysicalPageClone

此函数的功能是克隆一个物理页面。不过有个概念需要理解,克隆物理页面并不能直接对物理页面进行操作,需要将分配出来的物理页面映射为虚拟地址,然后对虚拟地址进行拷贝。

/*********************************************************************************************************
** 函数名称: __vmmPhysicalPageClone
** 功能描述: 克隆一个物理页面
** 输 入  : pvmpage       页面控制块
** 输 出  : 新的物理页面
** 全局变量:
** 调用模块:
*********************************************************************************************************/
PLW_VMM_PAGE  __vmmPhysicalPageClone (PLW_VMM_PAGE  pvmpage)
{PLW_VMM_PAGE    pvmpageNew;addr_t          ulSwitchAddr = __vmmVirtualSwitch();ULONG           ulZoneIndex;ULONG           ulError;if ((pvmpage->PAGE_ulCount != 1) ||(pvmpage->PAGE_iPageType != __VMM_PAGE_TYPE_PHYSICAL) ||(pvmpage->PAGE_ulMapPageAddr == PAGE_MAP_ADDR_INV)) {           /*  必须是有映射关系的单页面    */_ErrorHandle(ERROR_VMM_PHYSICAL_PAGE);return  (LW_NULL);}pvmpageNew = __vmmPhysicalPageAlloc(1, LW_ZONE_ATTR_NONE, &ulZoneIndex);if (pvmpageNew == LW_NULL) {_ErrorHandle(ERROR_VMM_LOW_PHYSICAL_PAGE);return  (LW_NULL);}ulError = __vmmLibPageMap(pvmpageNew->PAGE_ulPageAddr,              /*  使用 CACHE 操作             */ulSwitchAddr, 1,                          /*  缓冲区虚拟地址              */LW_VMM_FLAG_RDWR);                        /*  映射指定的虚拟地址          */if (ulError) {__vmmPhysicalPageFree(pvmpageNew);return  (LW_NULL);}KN_COPY_PAGE((PVOID)ulSwitchAddr, (PVOID)pvmpage->PAGE_ulMapPageAddr);                   /*  拷贝页面内容                */if (API_CacheAliasProb()) {                                         /*  cache 别名可能              */API_CacheClearPage(DATA_CACHE, (PVOID)ulSwitchAddr,(PVOID)pvmpageNew->PAGE_ulPageAddr,LW_CFG_VMM_PAGE_SIZE);                       /*  将数据写入内存并不再命中    */}__vmmLibSetFlag(ulSwitchAddr, 1, LW_VMM_FLAG_FAIL, LW_TRUE);        /*  VIRTUAL_SWITCH 不允许访问   */return  (pvmpageNew);
}

首先要获得一个交换区,这里其实是临时的虚拟地址的作用,需要把分配出来的物理地址先映射到这个虚拟地址上来

_G_ulVmmSwitchAddr 初始化时在__vmmVirtualCreate函数中,在首次创建虚拟zone时会空出一个页面的大小(默认页面大小为4K)当做赋值 给_G_ulVmmSwitchAddr。

然后调用上面讲到的__vmmPhysicalPageAlloc分配一个页面,将分配出来的物理页面和_G_ulVmmSwitchAddr虚拟地址进行映射。__vmmLibPageMap函数在pageTable.c文件中,上一篇文章分析过这个函数链接。此时原物理页面控制块vmpage映射的虚拟地址和新分配出来的vmpage 虚拟已经都有了,然后调用拷贝函数进行拷贝一个页面,这个拷贝函数在不同体系结构下实现不同,是用对应的汇编实现的。如果拷贝成功,需要将cache数据回写到内存中。最后设置物理地址的访问属性并且刷新TLB。

__vmmPhysicalPageRef

此函数功能是引用一个物理页面,在SylixOS中物理页面可能存在引用关系,vmpage并不是真实的物理页面。

当时引用其他页面时需要使用这个几个参数。

/*********************************************************************************************************
** 函数名称: __vmmPhysicalPageRef
** 功能描述: 引用物理页面
** 输 入  : pvmpage       页面控制块
** 输 出  : NONE
** 全局变量:
** 调用模块:
*********************************************************************************************************/
PLW_VMM_PAGE  __vmmPhysicalPageRef (PLW_VMM_PAGE  pvmpage)
{PLW_VMM_PAGE    pvmpageFake = (PLW_VMM_PAGE)__KHEAP_ALLOC(sizeof(LW_VMM_PAGE));PLW_VMM_PAGE    pvmpageReal;if (pvmpageFake == LW_NULL) {_DebugHandle(__ERRORMESSAGE_LEVEL, "kernel low memory.\r\n");_ErrorHandle(ERROR_KERNEL_LOW_MEMORY);                          /*  缺少内核内存                */return  (LW_NULL);}*pvmpageFake = *pvmpage;if (LW_VMM_PAGE_IS_FAKE(pvmpage)) {pvmpageReal = LW_VMM_PAGE_GET_REAL(pvmpage);} else {pvmpageReal = pvmpage;}pvmpageReal->PAGE_ulRef++;                                          /*  真实页面引用++              */_INIT_LIST_LINE_HEAD(&pvmpageFake->PAGE_lineFreeHash);_INIT_LIST_LINE_HEAD(&pvmpageFake->PAGE_lineManage);pvmpageFake->PAGE_ulRef         = 0ul;                              /*  fake 页面, 引用计数无效     */pvmpageFake->PAGE_pvmpageReal   = pvmpageReal;pvmpageFake->PAGE_ulMapPageAddr = PAGE_MAP_ADDR_INV;return  (pvmpageFake);
}

首先需要判断当前的vmpage是否本身就不是一个真实的物理页面,是引用物理页面。 LW_VMM_PAGE_IS_FAKE这个宏首选判断PPAGE_pvmpageReal这个指针是否为空,如果不为空就代表这不是一个真实的页面,而是指向了其他页面。LW_VMM_PAGE_GET_REAL获得指向页面。如果PPAGE_pvmpageReal为空它本省就是个真实页面,pvmpageReal就直接等于vmpgage。在获得真实页面后pvmpageReal的引用计数加1.同事将新分配的vmpage指向pvmpageReal。

__vmmPhysicalPageFree 

此函数是释放一个物理页面控制块,不过需要根据是否是一个真实的页面进行不同的处理。

/*********************************************************************************************************
** 函数名称: __vmmPhysicalPageFree
** 功能描述: 回收指定的连续物理页面
** 输 入  : pvmpage       页面控制块
** 输 出  : NONE
** 全局变量:
** 调用模块:
*********************************************************************************************************/
VOID  __vmmPhysicalPageFree (PLW_VMM_PAGE  pvmpage)
{REGISTER PLW_VMM_ZONE   pvmzone = pvmpage->PAGE_pvmzoneOwner;PLW_VMM_PAGE   pvmpageReal;if (LW_VMM_PAGE_IS_FAKE(pvmpage)) {pvmpageReal = LW_VMM_PAGE_GET_REAL(pvmpage);__KHEAP_FREE(pvmpage);                                          /*  释放 fake 控制块            */} else {pvmpageReal = pvmpage;pvmpageReal->PAGE_ulMapPageAddr = PAGE_MAP_ADDR_INV;            /*  对应的地址不再有效          */}pvmpageReal->PAGE_ulRef--;if (pvmpageReal->PAGE_ulRef == 0) {__pageFree(pvmzone, pvmpageReal);                               /*  没有引用则直接释放          */}
}

如果是真实的页面同时没有引用,此时直接调用__pageFree释放函数,此函数在pageLib.c文件中。如果不是真实的页面,是其他的引用,首先释放vmpage的空间资源。因为不是真实的页面控制块都是从堆里分配出来的单独一个,真实的是在链表中。

然后将真实的引用页面引用值减1.

__vmmPhysicalPageFreeAll

此函数是遍历虚拟页面控制块中的物理地址哈希表,然后调用__vmmPhysicalPageFree 函数挨个释放。

__vmmPhysicalPageSetFlag

此函数是设置物理页面的属性,当时其实是通过虚拟地址调用将SylixOS系统标志转换物理页面属性函数实现,也就是说这个物理页面必须被映射过虚拟地址才能设置。

__vmmPhysicalPageFlush

此函数是刷cache,首先是这个物理地址也必须是映射过虚拟地址,通过虚拟地址调用sylixos封装的cache操作函数集。类似的还有物理页面的cache无效,cache会写等。

SylixOS 内存管理源代码分析--phyPage.c相关推荐

  1. linux内存管理、分析、泄露定位与工具整理

    linux内存管理.分析.泄露定位与工具整理 linux内存管理相关知识 1. 进程的内存申请与分配 2. 当前系统总内存的统计 linux内存分析 linux内存泄漏相关知识 内存泄露的分类 val ...

  2. iOS中引用计数内存管理机制分析

    在 iOS 中引用计数是内存的管理方式,虽然在 iOS5 版本中,已经支持了自动引用计数管理模式,但理解它的运行方式有助于我们了解程序的运行原理,有助于 debug 程序. 操作系统的内存管理分成堆和 ...

  3. 内存管理代码分析 stm32

    (1)malloc函数用于内存申请,free函数用于内存释放. (2)内存管理表的项值代表的意义:当该项值为0的时候,代表对应的内存块未被占用,当该项值非零的时候,代表该项对应的内存块已经被占用,其数 ...

  4. linux内核分为子系统,Linux内核内存管理子系统分析【转】

    还是那张熟悉的老图:Linux内核子系统简介(由七个部分组成) Linux内存管理模型: 1. 内存管子系统职能: 1>  管理虚拟地址与物理地址的映射 2>  管理物理内存的分配 2. ...

  5. Linux内存管理和分析vmalloc使用的地址范围

    From: http://www.cnblogs.com/dubingsky/archive/2010/04/20/1716158.html Vmalloc可以获得的地址在VMALLOC_START到 ...

  6. Spark的新方案UnifiedMemoryManager内存管理模型分析

    StaticMemoryManager继承与MemoryManager,它是静态的内存分配,是1.6版本以前的实现,就像是建筑商建造好了房子,用户来到直接住进去就好了(弊端:有的人多住了小房子,有的人 ...

  7. MTK:内存管理机制简单分析

    MTK内存管理机制简单分析 1:内存: 内存,在手机里面,是个较为紧缺的资源,特别是在功能机上面.经常在功能机上面产生的内存不足,申请失败的地方比比皆是, 更是屡见不鲜,经常会为了节省内存,会进行代码 ...

  8. Spark内存管理(1)—— 静态内存管理

    Spark内存管理简介 Spark从1.6开始引入了动态内存管理模式,即执行内存和存储内存之间可以相互抢占  Spark提供了2种内存分配模式: 静态内存管理 统一内存管理 本系列文章将分别对这两种内 ...

  9. 电脑是否存在内存泄漏_STM32裸机内存管理解析

    概述 在计算机系统中,变量.中间数据一般存放在系统存储空间中,只有实际使用的时候才将他们从存储空间调入到中央处理器内部进行计算.通常存储空间分为两类:内部存储空间和外部存储空间.对于电脑来讲,内部存储 ...

  10. Apache Spark 内存管理详解

    原文出处: IBM developerWorks Spark 作为一个基于内存的分布式计算引擎,其内存管理模块在整个系统中扮演着非常重要的角色.理解 Spark 内存管理的基本原理,有助于更好地开发 ...

最新文章

  1. python 文案自动生成_Python自动化测试如何自动生成测试用例?
  2. ISP_MPLS *** 理论笔记
  3. java中的线程安全是什么?
  4. django.db.utils.DataError: (1406, Data too long for column 'gender' at row 1)
  5. python读取excel送到网页_python怎么读取excel!怎么用python将excel数据写入网页中
  6. VHDL六层电梯控制器及仿真
  7. linux配置网卡自动获取的命令,linux 命令行下配置网卡自动获取 IP
  8. python3 正则表达式模块re相关
  9. .NET Web实时消息后台服务器推送技术-GoEasy
  10. HTML(一):HTML基本元素标签
  11. MediaPlayer/MediaRecorder与AudioTrack/AudioRecord区别(三十九)
  12. 【PID优化】基于matlab粒子群和遗传算法PID控制器优化设计【含Matlab源码 1311期】
  13. Java常用实现八种排序算法与代码实现
  14. java控制html弹出框,Selenium+java - 弹出框处理
  15. 商品库存的扣除过程中如何防止超卖?
  16. 计算三维空间中点到三角形平面的最短距离
  17. 数模系列(3):模糊综合评价法
  18. 如何解决eclipse桌面快捷方式无法打开,jre or jkd的问题
  19. Matlab模糊综合评价做空气质量经典例题
  20. 搜狗推送代码之搜狗百万蜘蛛实现

热门文章

  1. h3c使用acl控制ftp访问_H3C交换机典型访问控制列表(ACL)配置实例
  2. 电脑麦克风插孔是哪个_科唛BoomXD 2.4G数字无线麦克风
  3. 配置LVS + Keepalived高可用负载均衡集群之图文教程
  4. LeetCode刷题笔记-回溯法-分割回文串
  5. docker搭建sonarqube做代码审计
  6. wordpress迁移以及遇到的一些问题[mysql备份导入导出][固定链接404]
  7. MYSQL服务器my.cnf配置文档详解
  8. 写了个项目 Web-Rtmp: 使用 WebSocket 在网页上播放 RTMP 直播流
  9. MYSQL 取上一条记录,与下一条记录
  10. citrix4.5无法进入发布程序界面The supplied credentials could not be validated