网站建设公司行情,wordpress 4.5 汉化主题,设计企业展厅的公司,经典logo设计初始化FPU、MMU和Cache组件 本来想在不初始化这些部件的情况下把SylixOS先启动起来感受下#xff0c;结果测试发现如果MMU不使能的话#xff0c;系统启动过程中线程无法进行调度emm。。。所以只好把这一章节提前来讲了。这三个组件的初始化都是在bspInit.c中进行的。 1. FPU初…初始化FPU、MMU和Cache组件 本来想在不初始化这些部件的情况下把SylixOS先启动起来感受下结果测试发现如果MMU不使能的话系统启动过程中线程无法进行调度emm。。。所以只好把这一章节提前来讲了。这三个组件的初始化都是在bspInit.c中进行的。 1. FPU初始化 我们首先来看下FPU的初始化
static VOID halFpuInit (VOID)
{API_KernelFpuInit(ARM_MACHINE_A7, ARM_FPU_VFPv3);
} 可以看出来FPU的初始化很简单只需要调用API_KernelFpuInit 即可。第一个参数表示当前CPU的架构第二个参数表示当前SOC中FPU使用的类型这两个参数根据芯片数据手册的信息然后使用内核提供好的宏填入就行了。
2. Cache初始化
再来看看Cache的初始化
static VOID halCacheInit (VOID)
{API_CacheLibInit(CACHE_COPYBACK, CACHE_COPYBACK, ARM_MACHINE_A7); /* 初始化 CACHE 系统 */API_CacheEnable(INSTRUCTION_CACHE);API_CacheEnable(DATA_CACHE); /* 使能 CACHE */
}
首先使用API_CacheLibInit 接口初始化了内核Cache组件
第一个参数表示指令Cache的工作方式一般有写回和写通两种模式实际中一般使用写回模式。第二个参数表示数据Cache的工作方式一般有写回和写通两种模式实际中一般使用写回模式。第三个表示当前CPU的架构类型。 初始化完了内核Cache组件接着使用了API_CacheEnable 接口使能了指令Cache和数据Cache可以看出Cache的初始化还是比较简单的因为内核已经为大部分arm架构封装好了Cache等部件的操作我们只需要调用接口即可。 另外有些平台上的L2 Cache是可以单独控制的比如zynq7000平台针对这些L2 Cache可以控制的的平台我们还需要实现bspLib.c中的bspL2CBase 和bspL2CAux 这两个接口 全志R16平台并没有单独L2 Cache控制器所以这两个接口我们直接使用默认实现即可。
3. MMU初始化 MMU的初始化需要做三部分工作一个是bspMap.h 中映射表的设置另外一个是内核VMM组件初始化最后是MMU页表池大小设置下面我们分别来学习下这两部分的内容。
3.1 映射表设置 映射表是定义在bspMap.h 中_G_physicalDesc 描述物理地址空间的关系_G_virtualDesc 描述虚拟地址空间关系VMM通过这两个表中定义的关系来管理物理地址和虚拟地址。
3.1.1 物理地址空间映射表 SylixOS中使用LW_MMU_PHYSICAL_DESC 这个数据结构来描述中断向量表、物理内存区、外设寄存器的物理地址和虚拟地址的映射关系
/*********************************************************************************************************物理内存信息描述注意:TEXT, DATA, DMA 物理段 PHYD_ulPhyAddr 必须等于 PHYD_ulVirMap,TEXT, DATA, VECTOR, BOOTSFR, DMA 物理段 PHYD_ulVirMap 区间不能与虚拟内存空间冲突.
*********************************************************************************************************/typedef struct __lw_vmm_physical_desc {addr_t PHYD_ulPhyAddr; /* 物理地址 (页对齐地址) */addr_t PHYD_ulVirMap; /* 需要初始化的映射关系 */size_t PHYD_stSize; /* 物理内存区长度 (页对齐长度) */#define LW_PHYSICAL_MEM_TEXT 0 /* 内核代码段 */
#define LW_PHYSICAL_MEM_DATA 1 /* 内核数据段 (包括 HEAP) */
#define LW_PHYSICAL_MEM_VECTOR 2 /* 硬件向量表 */
#define LW_PHYSICAL_MEM_BOOTSFR 3 /* 启动时需要的特殊功能寄存器 */
#define LW_PHYSICAL_MEM_BUSPOOL 4 /* 总线地址池, 不进行提前映射 */
#define LW_PHYSICAL_MEM_DMA 5 /* DMA 物理内存, 不进行提前映射*/
#define LW_PHYSICAL_MEM_APP 6 /* 装载程序内存, 不进行提前映射*/UINT32 PHYD_uiType; /* 物理内存区间类型 */UINT32 PHYD_uiReserve[8];
} LW_MMU_PHYSICAL_DESC;
typedef LW_MMU_PHYSICAL_DESC *PLW_MMU_PHYSICAL_DESC;
PHYD_ulPhyAddr表示物理地址空间起始地址。PHYD_ulVirMap表示起始虚拟地址。PHYD_stSize表示物理地址空间大小。PHYD_uiType物理空间的类型。
注意这里的地址和大小值必须是当前平台页对齐的值系统启动过程中会检测是否对齐如果不对齐则会启动失败。
让我们来看看R16平台上这个表的具体设置
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},/** TODO: 加入启动设备的寄存器映射, 参考代码如下:*/{ /* UART0 ~ 4 */0x01C28000,0x01C28000,2 * LW_CFG_VMM_PAGE_SIZE,LW_PHYSICAL_MEM_BOOTSFR},{ /* 结束 */0,0,0,0}
};
在以前比较老的arm平台中断向量表的地址必须是放在0地址处的当使能MMU之后需要将中断向量表所在的实际物理地址映射为虚拟地址0这样中断向量表才能被正常使用。内核代码段和内核数据段会在VMM初始化时将表中记录的物理地址和虚拟地址建立对等映射关系。DMA内存段中记录的映射关系不会再VMM初始化的时候使用但是会在申请DMA内存的时候使用一般都是对等映射。这个表中APP内存段中的虚拟地址不会被VMM使用VMM主要使用的是这里记录的物理基址和大小其对应的虚拟地址是再另一个表中配置的。这里为了表内容统一直接将物理地址填在虚拟地址的位置。SylixOS支持启动的时候静态映射寄存器和通过调用接口动态映射寄存器地址。如果需要静态映射就将映射关系填入上表中一般也都是对等映射动态映射在下一小节说明。由于使能MMU之后我们还需要串口进行输出信息所以这里需要将串口寄存器地址进行静态映射。
3.1.2虚拟地址空间表 SylixOS中使用LW_MMU_VIRTUAL_DESC 数据结构来描述虚拟地址空间信息
typedef struct __lw_mmu_virtual_desc {addr_t VIRD_ulVirAddr; /* 虚拟空间地址 (页对齐地址) */size_t VIRD_stSize; /* 虚拟空间长度 (页对齐长度) */#define LW_VIRTUAL_MEM_APP 0 /* 装载程序虚拟内存区间 */
#define LW_VIRTUAL_MEM_DEV 1 /* 设备映射虚拟内存空间 */UINT32 VIRD_uiType; /* 虚拟内存区间类型 */UINT32 VIRD_uiReserve[8];
} LW_MMU_VIRTUAL_DESC;
typedef LW_MMU_VIRTUAL_DESC *PLW_MMU_VIRTUAL_DESC;
VIRD_ulVirAddr虚拟地址空间起始地址。VIRD_stSize虚拟地址空间大小。VIRD_uiType虚拟空间类型。 同样的起始地址和大小值也必须是页对齐的值。VMM管理的虚拟地址空间只有两种LW_VIRTUAL_MEM_APP 表示系统动态加载的程序、动态库和内核模块所使用的虚拟地址空间LW_VIRTUAL_MEM_DEV 表示系统调用API_VmmIoRemap 这类接口动态映射寄存器地址时所使用的虚拟地址空间。 我们来看看R16平台上的实际配置
LW_MMU_VIRTUAL_DESC _G_virtualDesc[] {/** TODO: 加入虚拟地址空间的定义, 参考代码如下:*/
#if 1{ /* 应用程序虚拟空间 */0x80000000,((size_t)1 * LW_CFG_GB_SIZE),LW_VIRTUAL_MEM_APP},{0xC0000000, /* ioremap 空间 */(64 * LW_CFG_MB_SIZE),LW_VIRTUAL_MEM_DEV},
#endif{ /* 结束 */0,0,0}
}; 注意这里的虚拟地址和物理空间描述表中各个区域的虚拟地址不要有重复在满足这个前提下地址值可以任意配置。另外还需要注意的是起始地址加上大小之后不要超过4GB因为我们现在用的是32位的地址空间。
3.2 VMM组件初始化 在配置好上述的两个映射表后就可以使用API_VmmLibInit 这个接口来初始化VMM组件
static VOID halVmmInit (VOID)
{API_VmmLibInit(_G_physicalDesc, _G_virtualDesc, ARM_MACHINE_A7);API_VmmMmuEnable();
}
上述代码应该很好理解就不再赘述。初始化好VMM组件之后最后调用API_VmmMmuEnable 接口来使能MMU。
3.3 MMU页表池设置 MMU正常工作需要使用页表全志R16属于armv7架构在armv7架构下SylixOS内核使用的是二级页表机制。第一级页表叫全局页目录(Page Global Directory)也可以叫做一级页表页目录中单个条目就叫做页目录项一个页目录项可以映射1MB的物理页32位地址空间有4GB大小所以整个页目录共有4096个页目录项。第二级页表叫做二级页表二级页表中单个条目就叫做页表项(Page Table Entry)一般arm32位都是用4KB页大小也就是一个页表项可以映射4KB的物理页一个二级页表可以映射1MB大小所以一个二级页表中共有256个页表项 在SylixOS中一级页表和二级页表所占的内存是在内核堆上的也就是内核数据区空间所以在配置config.h时最好将内核数据区配置大点否则有可能因为MMU页表申请不到内存空间而导致系统启动失败。
在一个实际的嵌入式项目中并不会完全使用4GB的空间那么我们就可以将二级页表的个数减少点来节省下内存给其他的内核模块或者应用使用这是通过bspLib.c中的bspMmuPgdMaxNum 和bspMmuPteMaxNum 这两个接口实现的。
bspMmuPgdMaxNum 接口主要用来获取一级页表的个数一个一级页表已经能映射4GB的空间了所以这个函数一般都是返回1 bspMmuPteMaxNum 接口主要用来获取二级页表的个数注意是二级页表的个数而不是页表项的个数。如果是4096则表示映射完整的4GB空间这里实际返回的是2048也就是表示只映射2GB的空间 因为本次使用的开发板内存是1GB再加上其他的寄存器空间大小2GB空间已经足够使用了。如果开发板内存是2GB的话那么这个函数的返回值就需要改大一点了总之这个值根据实际情况进行设置。