Skip to content

移植ZYNQMP设备树启动过程遇到的一些关于初始化MMU的问题 #8846

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
liYony opened this issue Apr 23, 2024 · 6 comments
Closed

Comments

@liYony
Copy link
Contributor

liYony commented Apr 23, 2024

最近在移植zynqmp设备树启动的过程中遇到关于mmu初始化的一些问题。

1 硬件内存相关信息:

image

根据上图可知,内存的范围为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去分配物理页面。

在映射过程中出现如下错误。

image

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

image

尝试解决方案:

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

image

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

image

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。

这里做了如下修改:

image

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

image

想知道是否v_addr传入值是有什么规则吗??还是存在bug。

@polarvid
Copy link
Contributor

polarvid commented Apr 23, 2024

首先这个函数,如果map映射成功的话,返回值是等于v_addr的,但是如果v_addr本身就为0,那么无论成功或是失败,其返回值都为(0)RT_NULL。

因为逻辑上 va 是不允许传 0 的,否则无法触发 NULL 异常。所以返回值为 0 无论任何情况下都视为错误。

@liYony
Copy link
Contributor Author

liYony commented Apr 23, 2024

首先这个函数,如果map映射成功的话,返回值是等于v_addr的,但是如果v_addr本身就为0,那么无论成功或是失败,其返回值都为(0)RT_NULL。

因为逻辑上 va 是不允许传 0 的,否则无法触发 NULL 异常。所以返回值为 0 无论任何情况下都视为错误。

那比如我这个开发板,DDR的起始地址就是0,那是不是得给它专门做一下2M的向上对齐呢?

@polarvid
Copy link
Contributor

以本次移植的zynqmp开发板来说,vaddr=0,size=0x7ff00000,这里size=2047M,不是2M对齐,所以创建映射的函数为_kernel_map_4K。该函数会涉及到rt_pages_alloc_ext去分配物理页面。

rt_page_init 不要注册超过 1 G 范围的地址。一般就是拆成多段。等内核第二次页表切换完成后,通过 rt_page_install 装入剩余部分。

@liYony
Copy link
Contributor Author

liYony commented Apr 23, 2024

以本次移植的zynqmp开发板来说,vaddr=0,size=0x7ff00000,这里size=2047M,不是2M对齐,所以创建映射的函数为_kernel_map_4K。该函数会涉及到rt_pages_alloc_ext去分配物理页面。

rt_page_init 不要注册超过 1 G 范围的地址。一般就是拆成多段。等内核第二次页表切换完成后,通过 rt_page_install 装入剩余部分。

那看样子要修改一下setup.c里面的一些逻辑了

@polarvid
Copy link
Contributor

这个 BSP 不使能用户态(RT_USING_SMART)的时候应该把 KERNEL_VADDR_START 定义为 0。否则无法正常完成 mapping。

@liYony
Copy link
Contributor Author

liYony commented Apr 23, 2024

这个 BSP 不使能用户态(RT_USING_SMART)的时候应该把 KERNEL_VADDR_START 定义为 0。否则无法正常完成 mapping。

image

在不开启用户态的时候,这个值来源于ARCH_TEXT_OFFSET,难道我必须强制这个值为0吗?

@liYony liYony closed this as completed Apr 26, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants