Armv7 MMU on the ZYNQ-7000 not starting the virtualization

Introduction

I have been trying to evaluate the MMU functionality for the Xilinx zynq7000 soc that contains 2 A9-Cortex processors.

Firstly I have tried using the xil_mmu.h library, however after reading the functions that were implemented there realised that the mapping does not allow real P to V or V to P translation. Further more this library does not include any notion of granularity and only supports 1M page table entries.
Lets analyse a function from this library to illustrate my concerns: xil_mmu.c

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>void Xil_SetTlbAttributes(INTPTR Addr, u32 attrib)
{
u32 *ptr;
u32 section;
section = Addr / 0x100000U;
ptr = &MMUTable;
ptr += section;
if(ptr != NULL) {
*ptr = (Addr & 0xFFF00000U) | attrib;
}
Xil_DCacheFlush();
mtcp(XREG_CP15_INVAL_UTLB_UNLOCKED, 0U);
/* Invalidate all branch predictors */
mtcp(XREG_CP15_INVAL_BRANCH_ARRAY, 0U);
dsb(); /* ensure completion of the BP and TLB invalidation */
isb(); /* synchronize context on this processor */
}
</code>
<code>void Xil_SetTlbAttributes(INTPTR Addr, u32 attrib) { u32 *ptr; u32 section; section = Addr / 0x100000U; ptr = &MMUTable; ptr += section; if(ptr != NULL) { *ptr = (Addr & 0xFFF00000U) | attrib; } Xil_DCacheFlush(); mtcp(XREG_CP15_INVAL_UTLB_UNLOCKED, 0U); /* Invalidate all branch predictors */ mtcp(XREG_CP15_INVAL_BRANCH_ARRAY, 0U); dsb(); /* ensure completion of the BP and TLB invalidation */ isb(); /* synchronize context on this processor */ } </code>
void Xil_SetTlbAttributes(INTPTR Addr, u32 attrib)
{
    u32 *ptr;
    u32 section;

    section = Addr / 0x100000U;
    ptr = &MMUTable;
    ptr += section;
    if(ptr != NULL) {
        *ptr = (Addr & 0xFFF00000U) | attrib;
    }

    Xil_DCacheFlush();

    mtcp(XREG_CP15_INVAL_UTLB_UNLOCKED, 0U);
    /* Invalidate all branch predictors */
    mtcp(XREG_CP15_INVAL_BRANCH_ARRAY, 0U);

    dsb(); /* ensure completion of the BP and TLB invalidation */
    isb(); /* synchronize context on this processor */
}

As you can tell the section variable (one of the 4096 1MB sections in a 4GB address space) is chosen in terms of the physical address, so for instance there is no way that I can map a physical address 0x100000 to correspond to a virtual 0x200000 or other.

Own implementation

Seeing the lack of modularity with this approach (basically no real virtualization) I decided to implement an extension to the basic xil_mmu library.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>/*
* Function to flush, invalidate the TLBs and synchronize the processors
*/
static void hwi_mmu_picoZed_7010_sync()
{
Xil_DCacheFlush();
mtcp(XREG_CP15_INVAL_UTLB_UNLOCKED, 0U);
/* Invalidate all branch predictors */
mtcp(XREG_CP15_INVAL_BRANCH_ARRAY, 0U);
dsb(); /* ensure completion of the BP and TLB invalidation */
isb(); /* synchronize context on this processor */
}
/*
* This function sets an entry in the L1 table given the attributes
*/
static void hwi_mmu_picoZed_7010_set_table_entry(uint32_t entry, uint32_t properties)
{
// Manage entries out of bound
// You can add some type of fault here
if (entry > 4095)
return;
// Get one of the 4096 entries
uintptr_t *new_entry = (uintptr_t *)&MMUTable + entry;
if (new_entry)
*new_entry = properties;
}
// Wrapper functions calling hwi_mmu_picoZed_7010_set_table_entry for specific entry types
// Sets a section in the L1 table with the given properties and the physical address
// bits [31:20] of the address
void hwi_mmu_set_L1_Section(uint32_t addr, uint32_t entry, uint32_t properties)
{
// Verify that this is effectively a section
if (!IS_ENTRY_SECTION(properties))
return;
hwi_mmu_picoZed_7010_set_table_entry(entry, (addr & 0xFFF00000) | properties);
}
</code>
<code>/* * Function to flush, invalidate the TLBs and synchronize the processors */ static void hwi_mmu_picoZed_7010_sync() { Xil_DCacheFlush(); mtcp(XREG_CP15_INVAL_UTLB_UNLOCKED, 0U); /* Invalidate all branch predictors */ mtcp(XREG_CP15_INVAL_BRANCH_ARRAY, 0U); dsb(); /* ensure completion of the BP and TLB invalidation */ isb(); /* synchronize context on this processor */ } /* * This function sets an entry in the L1 table given the attributes */ static void hwi_mmu_picoZed_7010_set_table_entry(uint32_t entry, uint32_t properties) { // Manage entries out of bound // You can add some type of fault here if (entry > 4095) return; // Get one of the 4096 entries uintptr_t *new_entry = (uintptr_t *)&MMUTable + entry; if (new_entry) *new_entry = properties; } // Wrapper functions calling hwi_mmu_picoZed_7010_set_table_entry for specific entry types // Sets a section in the L1 table with the given properties and the physical address // bits [31:20] of the address void hwi_mmu_set_L1_Section(uint32_t addr, uint32_t entry, uint32_t properties) { // Verify that this is effectively a section if (!IS_ENTRY_SECTION(properties)) return; hwi_mmu_picoZed_7010_set_table_entry(entry, (addr & 0xFFF00000) | properties); } </code>
/*
 *  Function to flush, invalidate the TLBs and synchronize the processors
 */

static void hwi_mmu_picoZed_7010_sync()
{
    Xil_DCacheFlush();

    mtcp(XREG_CP15_INVAL_UTLB_UNLOCKED, 0U);
    /* Invalidate all branch predictors */
    mtcp(XREG_CP15_INVAL_BRANCH_ARRAY, 0U);

    dsb(); /* ensure completion of the BP and TLB invalidation */
    isb(); /* synchronize context on this processor */
}

/*
 *  This function sets an entry in the L1 table given the attributes
 */
static void hwi_mmu_picoZed_7010_set_table_entry(uint32_t entry, uint32_t properties)
{
    // Manage entries out of bound
    // You can add some type of fault here
    if (entry > 4095)
        return;
    // Get one of the 4096 entries
    uintptr_t *new_entry = (uintptr_t *)&MMUTable + entry;
    if (new_entry)
        *new_entry = properties;
}

// Wrapper functions calling hwi_mmu_picoZed_7010_set_table_entry for specific entry types

// Sets a section in the L1 table with the given properties and the physical address
// bits [31:20] of the address
void hwi_mmu_set_L1_Section(uint32_t addr, uint32_t entry, uint32_t properties)
{
    // Verify that this is effectively a section
    if (!IS_ENTRY_SECTION(properties))
        return;
    hwi_mmu_picoZed_7010_set_table_entry(entry, (addr & 0xFFF00000) | properties);
}

As well as some macros to easier set the required memory attributes

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>
# define SECTION_ENTRY 0x00000002
# define IS_ENTRY_SECTION(entry) (((entry)&0x04000003) == SECTION_ENTRY)
// NONE for Privileged, NONE for User
# define SECTION_AP_PERMISSION_FAULT 0x0000
// R/W for Privileged, NONE for User
# define SECTION_AP_PRIVILEDGE_ACCESS 0x0400
// R/W for Privileged, R for User
# define SECTION_AP_USER_NO_WRITE 0x0800
// R/W for Privileged, R/W for User
# define SECTION_AP_FULL_ACCESS 0x0C00
// R for Privileged, NONE for User
# define SECTION_AP_PRIVELEDGE_READ 0x8400
// R for Privileged, R for User
# define SECTION_AP_READ_ONLY 0x8800
// Basically non cacheable
# define SECTION_STRONGLY_ORDERED 0x0000
// Write to cache only (memory is stale) and allocate new entries
# define SECTION_SHAREABLE_DEVICE 0x0004
// Write to both cache and memory
# define SECTION_WRITE_THROUGH_NO_ALLOC_ON_WRITE 0x0008
// Write to cache only (memory is stale) no allocation
# define SECTION_WRITE_BACK_NO_ALLOC_ON_WRITE 0x000C
// Non cacheable in Normal memory
# define SECTION_NON_CACHEABLE 0x1000
// Cacheable in normal memory
# define SECTION_CACHEABLE 0x100C
// Non shareable device specific memory
# define SECTION_NON_SHAREABLE 0x2000
# define SECTION_SHARE_BIT_SET 0x00010000
# define SECTION_SHARE_BIT_CLEAR 0x00000000
# define SECTION_NON_GLOBAL_SET 0x02000000
# define SECTION_NON_GLOBAL_CLEAR 0x00000000
# define SECTION_EXECUTE_NEVER_SET 0x00000010
# define SECTION_EXECUTE_NEVER_CLEAR 0x00000000
</code>
<code> # define SECTION_ENTRY 0x00000002 # define IS_ENTRY_SECTION(entry) (((entry)&0x04000003) == SECTION_ENTRY) // NONE for Privileged, NONE for User # define SECTION_AP_PERMISSION_FAULT 0x0000 // R/W for Privileged, NONE for User # define SECTION_AP_PRIVILEDGE_ACCESS 0x0400 // R/W for Privileged, R for User # define SECTION_AP_USER_NO_WRITE 0x0800 // R/W for Privileged, R/W for User # define SECTION_AP_FULL_ACCESS 0x0C00 // R for Privileged, NONE for User # define SECTION_AP_PRIVELEDGE_READ 0x8400 // R for Privileged, R for User # define SECTION_AP_READ_ONLY 0x8800 // Basically non cacheable # define SECTION_STRONGLY_ORDERED 0x0000 // Write to cache only (memory is stale) and allocate new entries # define SECTION_SHAREABLE_DEVICE 0x0004 // Write to both cache and memory # define SECTION_WRITE_THROUGH_NO_ALLOC_ON_WRITE 0x0008 // Write to cache only (memory is stale) no allocation # define SECTION_WRITE_BACK_NO_ALLOC_ON_WRITE 0x000C // Non cacheable in Normal memory # define SECTION_NON_CACHEABLE 0x1000 // Cacheable in normal memory # define SECTION_CACHEABLE 0x100C // Non shareable device specific memory # define SECTION_NON_SHAREABLE 0x2000 # define SECTION_SHARE_BIT_SET 0x00010000 # define SECTION_SHARE_BIT_CLEAR 0x00000000 # define SECTION_NON_GLOBAL_SET 0x02000000 # define SECTION_NON_GLOBAL_CLEAR 0x00000000 # define SECTION_EXECUTE_NEVER_SET 0x00000010 # define SECTION_EXECUTE_NEVER_CLEAR 0x00000000 </code>

#    define SECTION_ENTRY 0x00000002
#    define IS_ENTRY_SECTION(entry) (((entry)&0x04000003) == SECTION_ENTRY)

// NONE for Privileged, NONE for User
#    define SECTION_AP_PERMISSION_FAULT 0x0000
// R/W for Privileged, NONE for User
#    define SECTION_AP_PRIVILEDGE_ACCESS 0x0400
// R/W for Privileged, R for User
#    define SECTION_AP_USER_NO_WRITE 0x0800
// R/W for Privileged, R/W for User
#    define SECTION_AP_FULL_ACCESS 0x0C00
// R for Privileged, NONE for User
#    define SECTION_AP_PRIVELEDGE_READ 0x8400
// R for Privileged, R for User
#    define SECTION_AP_READ_ONLY 0x8800

// Basically non cacheable
#    define SECTION_STRONGLY_ORDERED 0x0000
// Write to cache only (memory is stale) and allocate new entries
#    define SECTION_SHAREABLE_DEVICE 0x0004
// Write to both cache and memory
#    define SECTION_WRITE_THROUGH_NO_ALLOC_ON_WRITE 0x0008
// Write to cache only (memory is stale) no allocation
#    define SECTION_WRITE_BACK_NO_ALLOC_ON_WRITE 0x000C
// Non cacheable in Normal memory
#    define SECTION_NON_CACHEABLE 0x1000
// Cacheable in normal memory
#    define SECTION_CACHEABLE 0x100C
// Non shareable device specific memory
#    define SECTION_NON_SHAREABLE 0x2000

#    define SECTION_SHARE_BIT_SET 0x00010000
#    define SECTION_SHARE_BIT_CLEAR 0x00000000

#    define SECTION_NON_GLOBAL_SET 0x02000000
#    define SECTION_NON_GLOBAL_CLEAR 0x00000000

#    define SECTION_EXECUTE_NEVER_SET 0x00000010
#    define SECTION_EXECUTE_NEVER_CLEAR 0x00000000

All of these macros are based upon the UG585 trm: Chapter 3, Figure 3-5

The problem

Here is the code I have tried to write to test the MMU

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>#include "hwi_mmu_picoZed_7010.h"
#include <stdint.h>
#include <xil_mmu.h>
int main(void) {
Xil_EnableMMU();
uint32_t addr1 = 0x6400000;
uint32_t addr0 = 0x6300000;
hwi_mmu_set_L1_Section(addr1, 0x63, SECTION_ENTRY | SECTION_SHARE_BIT_SET | SECTION_AP_FULL_ACCESS | SECTION_SHAREABLE_DEVICE);
hwi_mmu_sync();
hwi_mmu_set_L1_Section(addr0, 0x64, SECTION_ENTRY | SECTION_SHARE_BIT_SET | SECTION_AP_FULL_ACCESS | SECTION_SHAREABLE_DEVICE);
hwi_mmu_sync();
*((uint32_t *)(uintptr_t)addr1) = 123;
return 1;
}
</code>
<code>#include "hwi_mmu_picoZed_7010.h" #include <stdint.h> #include <xil_mmu.h> int main(void) { Xil_EnableMMU(); uint32_t addr1 = 0x6400000; uint32_t addr0 = 0x6300000; hwi_mmu_set_L1_Section(addr1, 0x63, SECTION_ENTRY | SECTION_SHARE_BIT_SET | SECTION_AP_FULL_ACCESS | SECTION_SHAREABLE_DEVICE); hwi_mmu_sync(); hwi_mmu_set_L1_Section(addr0, 0x64, SECTION_ENTRY | SECTION_SHARE_BIT_SET | SECTION_AP_FULL_ACCESS | SECTION_SHAREABLE_DEVICE); hwi_mmu_sync(); *((uint32_t *)(uintptr_t)addr1) = 123; return 1; } </code>
#include "hwi_mmu_picoZed_7010.h"
#include <stdint.h>
#include <xil_mmu.h>




int main(void) {


    Xil_EnableMMU();

    uint32_t addr1 = 0x6400000;
    uint32_t addr0 = 0x6300000;

    hwi_mmu_set_L1_Section(addr1, 0x63, SECTION_ENTRY | SECTION_SHARE_BIT_SET | SECTION_AP_FULL_ACCESS | SECTION_SHAREABLE_DEVICE);
    hwi_mmu_sync();
    hwi_mmu_set_L1_Section(addr0, 0x64, SECTION_ENTRY | SECTION_SHARE_BIT_SET | SECTION_AP_FULL_ACCESS | SECTION_SHAREABLE_DEVICE);
    hwi_mmu_sync();


    *((uint32_t *)(uintptr_t)addr1) = 123;
    return 1;
}

As you can tell the test is quite simple, I set the entry at 0x63M to translate to 0x64M and vice versa, after that I write a value at addr1 (0x6400000) and of course I expect it to be written at addr0 (0x6300000).

However it still writes at 0x6400000 like if the MMU has never been activated.

Looking at CP15 C1 register I can tell that it is however active!
I am clueless as to why my code does not work as intended, am I missing something in the initialization of the MMU?

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật