MMU initialization for an ARM multicore system


#1

I am working on an Arria10 SoC which has dual ARM Cortex-A9 MPCore. And I work on bare-metal environment with Intel SoCFPGA’s hardware library(HwLib).

On the shared SDRAM, I am planning to have dedicated memory regions for each core, and a shared non-cacheable memory area. And the FPGA does not get involved in the SDRAM. But my attemps to initialize MMU fails.

Here is what I have done:

For CPU0:

static void mmu_init(void)
{
    uint32_t *ttb1 = NULL;

    /* Populate the page table with sections (1 MiB regions). */
    ALT_MMU_MEM_REGION_t regions[] = {
            /* CPU0 Memory area: 256 MB */
            {
                    .va         = (void *)0x00000000,
                    .pa         = (void *)0x00000000,
                    .size       = 0x10000000,
                    .access     = ALT_MMU_AP_FULL_ACCESS,
                    .attributes = ALT_MMU_ATTR_WBA,
                    .shareable  = ALT_MMU_TTB_S_NON_SHAREABLE,
                    .execute    = ALT_MMU_TTB_XN_DISABLE,
                    .security   = ALT_MMU_TTB_NS_SECURE
            },
            /* CPU1 Memory area: 512 MB */
            /* CPU0 MUST NOT ACCESS THIS AREA */
            {
                    .va         = (void *)0x10000000,
                    .pa         = (void *)0x10000000,
                    .size       = 0x20000000,
                    .access     = ALT_MMU_AP_NO_ACCESS,
                    .attributes = ALT_MMU_ATTR_FAULT,
                    .shareable  = ALT_MMU_TTB_S_NON_SHAREABLE,
                    .execute    = ALT_MMU_TTB_XN_DISABLE,
                    .security   = ALT_MMU_TTB_NS_SECURE
            },
            /* Shared Memory area: 256 MB */
            {
                    .va         = (void *)0x30000000,
                    .pa         = (void *)0x30000000,
                    .size       = 0x10000000,
                    .access     = ALT_MMU_AP_FULL_ACCESS,
                    .attributes = ALT_MMU_ATTR_DEVICE_NS,
                    .shareable  = ALT_MMU_TTB_S_NON_SHAREABLE,
                    .execute    = ALT_MMU_TTB_XN_ENABLE,
                    .security   = ALT_MMU_TTB_NS_SECURE
            },
            /* Device area: Everything else */
            {
                    .va         = (void *)0x40000000,
                    .pa         = (void *)0x40000000,
                    .size       = 0xc0000000,
                    .access     = ALT_MMU_AP_FULL_ACCESS,
                    .attributes = ALT_MMU_ATTR_DEVICE_NS,
                    .shareable  = ALT_MMU_TTB_S_NON_SHAREABLE,
                    .execute    = ALT_MMU_TTB_XN_ENABLE,
                    .security   = ALT_MMU_TTB_NS_SECURE
            }
    };

    assert(ALT_E_SUCCESS == alt_mmu_init());
    assert(alt_mmu_va_space_storage_required(regions, ARRAY_SIZE(regions)) <= sizeof(alt_pt_storage));
    assert(ALT_E_SUCCESS == alt_mmu_va_space_create(&ttb1, regions, ARRAY_SIZE(regions), alt_pt_alloc, alt_pt_storage));
    assert(ALT_E_SUCCESS == alt_mmu_va_space_enable(ttb1));
}

For CPU1: Same initialization with CPU0 and CPU1’s .access and .attributes variables swapped.

This configuration results a system hang at alt_mmu_va_space_enable() function.

Since each CPU has its own MMU, I think this configuration is necessary for memory safety. I don’t see any mechanism that handles intercore MMU and since each core has its own MMU, I think that this is the only way to implement a safe shared memory. Is my method and inference right? If so, what am I doing wrong? Thanks in advance.