最近在移植zynqmp设备树启动的过程中遇到关于mmu初始化的一些问题。
1 硬件内存相关信息:

根据上图可知,内存的范围为0x00000000~0x7ff00000(2G-1M)
2 主要发现问题
1 rt_hw_mmu_map
void *rt_hw_mmu_map(rt_aspace_t aspace, void *v_addr, void *p_addr, size_t size,
size_t attr)
该函数会为内核页表创建映射关系,并且会根据vaddr和size是否2M对齐来选择使用_kernel_map_4K或者_kernel_map_2M来作为映射函数。
if (((rt_ubase_t)v_addr & ARCH_SECTION_MASK) || (size & ARCH_SECTION_MASK))
{
/* legacy 4k mapping */
npages = size >> ARCH_PAGE_SHIFT;
stride = ARCH_PAGE_SIZE;
mapper = _kernel_map_4K;
}
else
{
/* 2m huge page */
npages = size >> ARCH_SECTION_SHIFT;
stride = ARCH_SECTION_SIZE;
mapper = _kernel_map_2M;
}
以本次移植的zynqmp开发板来说,vaddr=0,size=0x7ff00000,这里size=2047M,不是2M对齐,所以创建映射的函数为_kernel_map_4K。该函数会涉及到rt_pages_alloc_ext去分配物理页面。
在映射过程中出现如下错误。

_kernel_map_4K函数会调用几十次rt_pages_alloc_ext函数去分配物理页。多次分配后导致分配到的页面无法访问(内存是支持该地址的,只是早期mmu初始化只映射了1G空间,未建立映射关系)。

尝试解决方案:
- 修改系统entry_point.S中init_mmu_early函数,将早期mmu初始化的时候映射的内存变大(我这里修改为0x80000000(2G)),保证访问
0x000000007feff000地址不会出问题,测试通过。

- 修改setup.c中的platform_mem_region.start和platform_mem_region.end以2M方式进行对齐,这样就会使用_kernel_map_2M函数进行页表映射,该方式不会调用多次rt_pages_alloc_ext函数,所以不会分配到
0x000000007feff000这个地址,测试通过。

2 _do_named_map
此函数中调用rt_hw_mmu_map函数部分返回值判断有一点问题。
void *rt_hw_mmu_map(rt_aspace_t aspace, void *v_addr, void *p_addr, size_t size,
size_t attr)
首先这个函数,如果map映射成功的话,返回值是等于v_addr的,但是如果v_addr本身就为0,那么无论成功或是失败,其返回值都为(0)RT_NULL。
这里做了如下修改:

但是只要v_addr传入的值为0,仍然无法启动内核。我故意做出如下修改,可以启动内核:

想知道是否v_addr传入值是有什么规则吗??还是存在bug。
最近在移植zynqmp设备树启动的过程中遇到关于mmu初始化的一些问题。
1 硬件内存相关信息:
根据上图可知,内存的范围为0x00000000~0x7ff00000(2G-1M)
2 主要发现问题
1 rt_hw_mmu_map
该函数会为内核页表创建映射关系,并且会根据vaddr和size是否2M对齐来选择使用_kernel_map_4K或者_kernel_map_2M来作为映射函数。
以本次移植的zynqmp开发板来说,vaddr=0,size=0x7ff00000,这里size=2047M,不是2M对齐,所以创建映射的函数为
_kernel_map_4K。该函数会涉及到rt_pages_alloc_ext去分配物理页面。在映射过程中出现如下错误。
_kernel_map_4K函数会调用几十次rt_pages_alloc_ext函数去分配物理页。多次分配后导致分配到的页面无法访问(内存是支持该地址的,只是早期mmu初始化只映射了1G空间,未建立映射关系)。
尝试解决方案:
0x000000007feff000地址不会出问题,测试通过。0x000000007feff000这个地址,测试通过。2 _do_named_map
此函数中调用rt_hw_mmu_map函数部分返回值判断有一点问题。
首先这个函数,如果map映射成功的话,返回值是等于v_addr的,但是如果v_addr本身就为0,那么无论成功或是失败,其返回值都为(0)RT_NULL。
这里做了如下修改:
但是只要v_addr传入的值为0,仍然无法启动内核。我故意做出如下修改,可以启动内核:
想知道是否v_addr传入值是有什么规则吗??还是存在bug。