SylixOS 启动时mmu 初始化

armv8 mmu 操作函数集已经介绍了操作函数集。SylixOS在启动时会调用__vmmLibPrimaryInit函数进行页表的初始化。

/*********************************************************************************************************
** 函数名称: __vmmLibPrimaryInit
** 功能描述: 初始化 MMU 功能, CPU 构架相关。(多核模式下, 为主核 MMU 初始化)
** 输 入  : pphydesc          物理内存区描述表
**           pcMachineName     正在运行的机器名称
** 输 出  : BSP 函数返回值
** 全局变量: 
** 调用模块: 
*********************************************************************************************************/
ULONG  __vmmLibPrimaryInit (LW_MMU_PHYSICAL_DESC  pphydesc[], CPCHAR  pcMachineName)

此函数需要传入一个物理地址描述符,包含需要将物理地址映射到虚拟地址中位置。

上图是物理地址描述符结构体。 在全志h6中映射关系的一部分如下图

将物理地址的BSP_CFG_RAM_BASE 映射到了虚拟地址另。在链接脚本中将 BSP_CFG_RAM_BASE地址是异常入口,所以这里需要映射成虚拟地址零。SylixOS 系统中使用的是平映射,代码段在使用虚拟地址后并没有在高地址运行。linux是在虚拟地址的高地址运行。所以这里物理地址和虚拟地址都是BSP_CFG_RAM_BASE。

 

 __vmmLibPrimaryInit 首席获取mmu上下文,mmu上下文在SylixOS目前是一个全部变量。然后调用__VMM_MMU_MEM_INIT宏初始化mmu。

 在armv8中这个调用的函数对应的是 在mmu实现的操作函数集。

 此函数功能是初始化当前pgd,pmd,pts,pte的内存池。在分配完成缓冲区后,调用__vmm_pgd_alloc 分配一个pgd,此函数首先判断是否存在,如果不存在直接分配。

static LW_INLINE  LW_PGD_TRANSENTRY  *__vmm_pgd_alloc (PLW_MMU_CONTEXT  pmmuctx, addr_t  ulAddr)
{
    if (pmmuctx->MMUCTX_pgdEntry == LW_NULL) {
        return  (__VMM_MMU_PGD_ALLOC(pmmuctx, ulAddr));
    } else {
        return  (__VMM_MMU_PGD_OFFSET(pmmuctx, ulAddr));
    }
}

如果存在查找对应的entry,返回这个entry。在初始化时传入的地址是0,所以这里无论有没有都会返回pgd表的首地址。

__VMM_MMU_GLOBAL_INIT 宏是对 arm64MmuGlobalInit 函数的宏定义,此时初始化硬件相关部分。包含关闭TLB,关cache等等。然后调用__vmmLibGlobalMap函数,此函数将物理地址描述符的物理地址和虚拟地址一一映射。

/*********************************************************************************************************
** 函数名称: __vmmLibGlobalMap
** 功能描述: 全局页面映射关系设置
** 输 入  : pmmuctx        MMU 上下文
**           pphydesc       物理内存区描述表
** 输 出  : ERROR CODE
** 全局变量: 
** 调用模块: 
*********************************************************************************************************/
static INT  __vmmLibGlobalMap (PLW_MMU_CONTEXT   pmmuctx, LW_MMU_PHYSICAL_DESC  pphydesc[]) 
{
    INT     i;
    ULONG   ulError;
    ULONG   ulPageNum;

    for (i = 0; pphydesc[i].PHYD_stSize; i++) {
        if ((pphydesc[i].PHYD_uiType == LW_PHYSICAL_MEM_BUSPOOL) ||
            (pphydesc[i].PHYD_uiType == LW_PHYSICAL_MEM_APP)     ||
            (pphydesc[i].PHYD_uiType == LW_PHYSICAL_MEM_DMA)) {
            continue;
        }
        
        ulPageNum = (ULONG)(pphydesc[i].PHYD_stSize >> LW_CFG_VMM_PAGE_SHIFT);
        if (pphydesc[i].PHYD_stSize & ~LW_CFG_VMM_PAGE_MASK) {
            ulPageNum++;
        }
        
        _BugFormat(__vmmLibVirtualOverlap(pphydesc[i].PHYD_ulVirMap, 
                                          pphydesc[i].PHYD_stSize), LW_TRUE,
                   "global map vaddr 0x%08lx size: 0x%08zx overlap with virtual space.\r\n",
                   pphydesc[i].PHYD_ulVirMap, pphydesc[i].PHYD_stSize);
    
        switch (pphydesc[i].PHYD_uiType) {
        
        case LW_PHYSICAL_MEM_TEXT:
            ulError = __vmmLibPageMap(pphydesc[i].PHYD_ulPhyAddr, 
                                      pphydesc[i].PHYD_ulVirMap,
                                      ulPageNum, LW_VMM_FLAG_EXEC | LW_VMM_FLAG_RDWR);
            break;
            
        case LW_PHYSICAL_MEM_DATA:
            ulError = __vmmLibPageMap(pphydesc[i].PHYD_ulPhyAddr, 
                                      pphydesc[i].PHYD_ulVirMap,
                                      ulPageNum, LW_VMM_FLAG_RDWR);
            break;
            
        case LW_PHYSICAL_MEM_VECTOR:
            ulError = __vmmLibPageMap(pphydesc[i].PHYD_ulPhyAddr, 
                                      pphydesc[i].PHYD_ulVirMap,
                                      ulPageNum, LW_VMM_FLAG_EXEC);
            break;
            
        case LW_PHYSICAL_MEM_BOOTSFR:
            ulError = __vmmLibPageMap(pphydesc[i].PHYD_ulPhyAddr, 
                                      pphydesc[i].PHYD_ulVirMap,
                                      ulPageNum, LW_VMM_FLAG_DMA);
            break;
            
        default:
            ulError = ERROR_NONE;
            break;
        }
        
        if (ulError) {
            _DebugHandle(__ERRORMESSAGE_LEVEL, "vmm global map fail.\r\n");
            return  (PX_ERROR);
        }
    }
    
    return  (ERROR_NONE);
}

首先bus pool ,DMA,APP空间不映射。app空间在使用时才映射。 映射时按照4K对齐方式,所以以下代码将大小以4K对齐统计有多少页。也就是4K页面有多少个。不足4K页面的,按照4K计算,所以出现ulPageNum++。

     ulPageNum = (ULONG)(pphydesc[i].PHYD_stSize >> LW_CFG_VMM_PAGE_SHIFT);
        if (pphydesc[i].PHYD_stSize & ~LW_CFG_VMM_PAGE_MASK) {
            ulPageNum++;
        }

 __vmmLibPageMap函数最终会调用__vmmLibPageMap2,TEXT,DATA,VECTOR,启动时相关的寄存器映射都会调用此函数,只是是使用的标志不同,这里使用的是SylixOS定义的标志,在mmu操作函数集中会将系统标志属性,最后转化为对应的体系结构硬件的页面属性。

/*********************************************************************************************************
** 函数名称: __vmmLibPageMap2
** 功能描述: 将物理页面重新映射 (for ioremap2 )
** 输 入  : paPhysicalAddr        物理页面地址
**           ulVirtualAddr         需要映射的虚拟地址
**           ulPageNum             需要映射的页面个数
**           ulFlag                页面标志
** 输 出  : ERROR CODE
** 全局变量: 
** 调用模块: 
*********************************************************************************************************/
ULONG  __vmmLibPageMap2 (phys_addr_t paPhysicalAddr, addr_t ulVirtualAddr, ULONG ulPageNum, ULONG ulFlag)
{
    ULONG                    i;
    PLW_MMU_CONTEXT          pmmuctx = __vmmGetCurCtx();
    
#if LW_CFG_VMM_L4_HYPERVISOR_EN == 0
    INTREG                   iregInterLevel;
    addr_t                   ulVirtualTlb = ulVirtualAddr;
    
    LW_PGD_TRANSENTRY       *p_pgdentry;
    LW_PMD_TRANSENTRY       *p_pmdentry;
#if LW_CFG_VMM_PAGE_4L_EN > 0
    LW_PTS_TRANSENTRY       *p_ptsentry;
#endif                                                                  /*  LW_CFG_VMM_PAGE_4L_EN > 0   */
    LW_PTE_TRANSENTRY       *p_pteentry;
#endif                                                                  /* !LW_CFG_VMM_L4_HYPERVISOR_EN */
    
#if LW_CFG_VMM_L4_HYPERVISOR_EN > 0
    if (ulFlag & LW_VMM_FLAG_ACCESS) {
        for (i = 0; i < ulPageNum; i++) {
            if (__VMM_MMU_PAGE_MAP(pmmuctx, paPhysicalAddr, 
                                   ulVirtualAddr, ulFlag) < ERROR_NONE) {
                return  (ERROR_VMM_LOW_LEVEL);
            }
            paPhysicalAddr += LW_CFG_VMM_PAGE_SIZE;
            ulVirtualAddr  += LW_CFG_VMM_PAGE_SIZE;
        }
    
    } else {
        for (i = 0; i < ulPageNum; i++) {
            if (__VMM_MMU_PAGE_UNMAP(pmmuctx, ulVirtualAddr) < ERROR_NONE) {
                return  (ERROR_VMM_LOW_LEVEL);
            }
            ulVirtualAddr += LW_CFG_VMM_PAGE_SIZE;
        }
    }
    
#else
    for (i = 0; i < ulPageNum; i++) {
        p_pgdentry = __vmm_pgd_alloc(pmmuctx, ulVirtualAddr);
        if (p_pgdentry == LW_NULL) {
            return  (ERROR_VMM_LOW_LEVEL);
        }
        
        p_pmdentry = __vmm_pmd_alloc(pmmuctx, p_pgdentry, ulVirtualAddr);
        if (p_pmdentry == LW_NULL) {
            return  (ERROR_VMM_LOW_LEVEL);
        }
        
#if LW_CFG_VMM_PAGE_4L_EN > 0
        p_ptsentry = __vmm_pts_alloc(pmmuctx, p_pmdentry, ulVirtualAddr);
        if (p_ptsentry == LW_NULL) {
            return  (ERROR_VMM_LOW_LEVEL);
        }
        
        p_pteentry = __vmm_pte_alloc(pmmuctx, p_ptsentry, ulVirtualAddr);
#else
        p_pteentry = __vmm_pte_alloc(pmmuctx, p_pmdentry, ulVirtualAddr);
#endif                                                                  /*  LW_CFG_VMM_PAGE_4L_EN > 0   */

        if (p_pteentry == LW_NULL) {
            return  (ERROR_VMM_LOW_LEVEL);
        }
        
        iregInterLevel = KN_INT_DISABLE();                              /*  关闭中断                    */
        __VMM_MMU_MAKE_TRANS(pmmuctx, p_pteentry,
                             ulVirtualAddr,
                             paPhysicalAddr, ulFlag);                   /*  创建映射关系                */
        KN_INT_ENABLE(iregInterLevel);                                  /*  打开中断                    */
        
        paPhysicalAddr += LW_CFG_VMM_PAGE_SIZE;
        ulVirtualAddr  += LW_CFG_VMM_PAGE_SIZE;
    }
    
    __vmmLibFlushTlb(pmmuctx, ulVirtualTlb, ulPageNum);                 /*  同步刷新所有 CPU TLB        */
#endif                                                                  /* !LW_CFG_VMM_L4_HYPERVISOR_EN */
    
    return  (ERROR_NONE);
}

根据需要的4K页数,不断做pgd->pmd->pts->pte->物理地址  的映射过程。首先获取的pgd,然后在看pgd中是否填充了pmd。检测是否填充是调用arm64MmuPgdIsOk 函数,这个函数在mmu函数集中。是在首次往pgd中填写pmd地址时将第三位设置为一个标志位。通过检测这个标志位判断是否有填写数据。如果有pmd就算出当前地址在pmd表中的偏移,获得pmd entry。pts,pte都是一样的原理,然后到pte时调用__VMM_MMU_MAKE_TRAN 这个宏实现将SylixOS标志位 转换为物理页属性,将pte地址和物理地址绑定。是通过调用mmu功能函数集中的arm64MmuMakeTrans函数实现的,映射完成后刷新TLB块表。循环这样过程将物理地址描述符中的所有的页映射完成后。代用__VMM_MMU_MAKE_CURCTX 这个宏,调用mmu函数中的arm64MmuMakeCurCtx 函数,将pgd的基地址填写到TTBR1寄存器中。启动时的物理页面的整个映射就结束了。此时还需要mmu使能工作,全志h6是等cache和vmm子系统都完成后启动muu。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值