内核启动过程中调用关系:
API_KernelStart
->usrStartup
->halPrimaryCpuInit
->API_VmmLibPrimaryInit
->__vmmLibPrimaryInit
->__vmmLibGlobalMap
->if(i == 17) {
pphydesc[i].PHYD_uiType = LW_PHYSICAL_MEM_BOOTSFR;
__vmmLibPageMap //占用大概7s时间
}
注意这个函数,主要时间消耗都在这里:
//初始化 vmm 库
API_VmmLibPrimaryInit(_G_physicalDesc,
_G_virtualDesc,
ARM_MACHINE_A9);
物理地址映射表_G_physicalDesc:
static LW_MMU_PHYSICAL_DESC _G_physicalDesc[] = {
{ /* 中断向量表 */
BSP_CFG_RAM_BASE,
0,
LW_CFG_VMM_PAGE_SIZE,
LW_PHYSICAL_MEM_VECTOR,
},
{ /* 内核代码段 */
BSP_CFG_RAM_BASE,
BSP_CFG_RAM_BASE,
BSP_CFG_TEXT_SIZE,
LW_PHYSICAL_MEM_TEXT,
},
{ /* 内核数据段 */
BSP_CFG_RAM_BASE + BSP_CFG_TEXT_SIZE,
BSP_CFG_RAM_BASE + BSP_CFG_TEXT_SIZE,
BSP_CFG_DATA_SIZE,
LW_PHYSICAL_MEM_DATA,
},
{ /* DMA 缓冲区 */
BSP_CFG_RAM_BASE + BSP_CFG_TEXT_SIZE + BSP_CFG_DATA_SIZE,
BSP_CFG_RAM_BASE + BSP_CFG_TEXT_SIZE + BSP_CFG_DATA_SIZE,
BSP_CFG_DMA_SIZE,
LW_PHYSICAL_MEM_DMA,
},
{ /* APP 通用内存 */
BSP_CFG_RAM_BASE + BSP_CFG_TEXT_SIZE + BSP_CFG_DATA_SIZE + BSP_CFG_DMA_SIZE,
BSP_CFG_RAM_BASE + BSP_CFG_TEXT_SIZE + BSP_CFG_DATA_SIZE + BSP_CFG_DMA_SIZE,
BSP_CFG_APP_SIZE,
LW_PHYSICAL_MEM_APP,
},
/*
* sfr
*/
{
0xF8900000 , /* intc 中断的物理地址 */
0xF8900000 , /* 映射到的虚拟地址 */
0xF8F02FFF - 0xF8900000 + 1, /* 映射的大小 */
LW_PHYSICAL_MEM_BOOTSFR
},
{
0xE0000000, /* Debug 串口0 的物理地址 */
0xE0000000, /* 映射到的虚拟地址 */
LW_CFG_VMM_PAGE_SIZE, /* 映射的大小 */
LW_PHYSICAL_MEM_BOOTSFR
},
{
0xE0001000, /* Debug 串口1的物理地址 */
0xE0001000, /* 映射到的虚拟地址 */
LW_CFG_VMM_PAGE_SIZE, /* 映射的大小 */
LW_PHYSICAL_MEM_BOOTSFR /* 映射的属性 */
},
{
0xE000A000, /* GPIO 的物理地址 */
0xE000A000, /* 映射到的虚拟地址 */
LW_CFG_VMM_PAGE_SIZE, /* 映射的大小 */
LW_PHYSICAL_MEM_BOOTSFR /* 映射的属性 */
},
{
0xE0002000, /* USB0 的物理地址 */
0xE0002000, /* 映射到的虚拟地址 */
LW_CFG_VMM_PAGE_SIZE, /* 映射的大小 */
LW_PHYSICAL_MEM_BOOTSFR /* 映射的属性 */
},
{
0xE0003000, /* USB1 的物理地址 */
0xE0003000, /* 映射到的虚拟地址 */
LW_CFG_VMM_PAGE_SIZE, /* 映射的大小 */
LW_PHYSICAL_MEM_BOOTSFR /* 映射的属性 */
},
{
0xE000B000, /* GMAC0(MDIO) 的物理地址 */
0xE000B000, /* 映射到的虚拟地址 */
LW_CFG_VMM_PAGE_SIZE, /* 映射的大小 */
LW_PHYSICAL_MEM_BOOTSFR /* 映射的属性 */
},
{
0xF8000000, /* SLCR 的物理地址 */
0xF8000000, /* 映射到的虚拟地址 */
LW_CFG_VMM_PAGE_SIZE, /* 映射的大小 */
LW_PHYSICAL_MEM_BOOTSFR /* 映射的属性 */
},
{
0xF8005000, /* SWDT 的物理地址 */
0xF8005000, /* 映射到的虚拟地址 */
LW_CFG_VMM_PAGE_SIZE, /* 映射的大小 */
LW_PHYSICAL_MEM_BOOTSFR /* 映射的属性 */
},
{
0xF8007000, /* device config 的物理地址 */
0xF8007000, /* 映射到的虚拟地址 */
LW_CFG_VMM_PAGE_SIZE, /* 映射的大小 */
LW_PHYSICAL_MEM_BOOTSFR /* 映射的属性 */
},
{
0xF8F00000, /* SCU Timer0 的物理地址 */
0xF8F00000,
LW_CFG_VMM_PAGE_SIZE,
LW_PHYSICAL_MEM_BOOTSFR,
},
{
0xFFFFF000, /* CPU1 启动物理地址 */
0xFFFFF000, /* 映射到的虚拟地址 */
LW_CFG_VMM_PAGE_SIZE, /* 映射的大小 */
LW_PHYSICAL_MEM_BOOTSFR /* 映射的属性 */
},
#ifdef BSP_ZYNQ_FPGA_MAP
BSP_ZYNQ_FPGA_MAP
#endif
#ifdef BSP_PL_HDMI_MAP
BSP_PL_HDMI_MAP
#endif
#ifdef BSP_CFG_QEMU_MAP
BSP_CFG_QEMU_MAP
#endif
{ /* 结束 */
0,
0,
0,
0
}
};
其中pphydesc[17]的映射最耗时,大约7s左右,主要时间都在做PL端寄存器空间的映射:
/*********************************************************************************************************
PL(FPGA)端寄存器映射
*********************************************************************************************************/
#define LW_CFG_VMM_PGD_SHIFT 20 /* 2^20 = 1MB */
#define LW_CFG_VMM_PGD_SIZE (1ul << LW_CFG_VMM_PGD_SHIFT)
#define BSP_ZYNQ_FPGA_MAP \
{ \
0x40000000, \
0x40000000, \
LW_CFG_VMM_PGD_SIZE * 1024, \
LW_PHYSICAL_MEM_BOOTSFR \
},
当i = 17时,ulPageNum = 262144,1页是4Kb,换算一下就是1G的PL空间
//当i = 17时,ulPageNum[262144]
ulError = __vmmLibPageMap(pphydesc[i].PHYD_ulPhyAddr,
pphydesc[i].PHYD_ulVirMap,
ulPageNum, LW_VMM_FLAG_DMA);
可以看出__vmmLibPageMap是按页映射的,页越多占用时间越长
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;
}
如果抛开zynq,如果不需要做PL寄存器地址的映射,启动过程大约需要3s左右。