2010-08-09 55 views

回答

3

下面給出是代碼,以使物理和虛擬地址空間之間的一個一對一映射:

#define NUM_PAGE_TABLE_ENTRIES 4096 /* 1 entry per 1MB, so this covers 4G address space */ 
#define CACHE_DISABLED 0x12 
#define SDRAM_START  0x80000000 
#define SDRAM_END   0x8fffffff 
#define CACHE_WRITEBACK 0x1e 

static inline void enable_mmu(void) 
{ 
    static U32 __attribute__((aligned(16384))) page_table[NUM_PAGE_TABLE_ENTRIES]; 
    int i; 
    U32 reg; 

    /* Set up an identity-mapping for all 4GB, rw for everyone */ 
    for (i = 0; i < NUM_PAGE_TABLE_ENTRIES; i++) 
     page_table[i] = i << 20 | (3 << 10) | CACHE_DISABLED; 
    /* Then, enable cacheable and bufferable for RAM only */ 
    for (i = SDRAM_START >> 20; i <SDRAM_END>> 20; i++) 
    { 
     page_table[i] = i << 20 | (3 << 10) | CACHE_WRITEBACK; 
    } 

    /* Copy the page table address to cp15 */ 
    asm volatile("mcr p15, 0, %0, c2, c0, 0" 
      : : "r" (page_table) : "memory"); 
    /* Set the access control to all-supervisor */ 
    asm volatile("mcr p15, 0, %0, c3, c0, 0" : : "r" (~0)); 

    /* Enable the MMU */ 
    asm("mrc p15, 0, %0, c1, c0, 0" : "=r" (reg) : : "cc"); 
    reg|=0x1 
    asm volatile("mcr p15, 0, %0, c1, c0, 0" : : "r" (reg) : "cc"); 
} 
2

歡迎您嘗試類似的方式(見下文)。我想要做同樣的事情啓用數據緩存並進行一對一的操作。一些工具和文檔和代碼可能會使問題複雜化。你需要從你的核心中的特定mmu和/或核心的數據表中獲得mmu的文件。

我使用的arm11 mpcore很可能與您所擁有的類似,mmu與arm9相似。該mpcore有一些新的大塊表條目比下一個大16倍,但這是一個完全浪費,因爲你必須在mmu表中放入16個相同條目的副本。

您需要一塊RAM來存放mmu表,您需要在表中爲該塊可能查找的第一個RAM的物理地址放入一個條目,請在mmu表中查找找出有關mmu表的一種東西。同樣,中斷向量表區(地址零)應該在那裏。使用最粗糙的條目,你可以。

請記住,控制寄存器空間不應該被緩存,直到你的mmu表工作之前,你可能不應該啓用數據緩存,然後開始緩存區域,直到你的代碼崩潰,然後unc緩存最後一件事。

既然你打算做一對一的映射,而不是像操作系統那樣使用mmu,那麼你可以做我所做的事情並提前構建你的mmu表。操作系統將需要例程來實時進行。下面的代碼是在彙編程序中構建表,然後鏈接到程序中。您的解決方案可能有所不同

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 

#define MMUTABLEBASE 0x00000000 

#define MMUALLOC (0x8000>>2) 

unsigned int mmu_table[MMUALLOC]; 
unsigned int mmu_table_owner[MMUALLOC]; 

#define TOP_LEVEL_WORDS (1<<((31-20)+1)) 
#define COARSE_TABLE_WORDS (1<<((19-12)+1)) 
#define SMALL_TABLE_WORDS (1<<((11-0)+1)) 

unsigned int base; 
unsigned int nextfree; 


unsigned int next_coarse_offset (unsigned int x) 
{ 
    unsigned int mask; 

    mask=(~0)<<(10-2); 
    mask=~mask; 
    while(x&mask) x++; //lazy brute force 
    return(x); 
} 

unsigned int add_one (unsigned int add, unsigned int flags) 
{ 
    unsigned int ra; 
    unsigned int rb; 
    unsigned int rc; 

    ra=add>>20; 
    if(mmu_table[ra]) 
    { 
     printf("Address %08X already allocated\n",add); 
     return(1); 
    } 
    add=ra<<20; 

    rb=next_coarse_offset(nextfree); 
    rc=rb+COARSE_TABLE_WORDS; 

    if(rc>=MMUALLOC) 
    { 
     printf("Not enough room\n"); 
     return(1); 
    } 
    nextfree=rc; 

    mmu_table[ra]=(MMUTABLEBASE+(rb<<2))|0x00000001; 

    for(ra=0;ra<COARSE_TABLE_WORDS;ra++) 
    { 
     mmu_table[rb+ra]=(add+(ra<<12))|0x00000032|flags; 
     mmu_table_owner[rb+ra]=(add+(ra<<12)); 
    } 
    return(0); 
} 



int main (void) 
{ 

    memset(mmu_table,0xF0,sizeof(mmu_table)); 

    for(nextfree=0;nextfree<TOP_LEVEL_WORDS;nextfree++) 
    { 
     mmu_table[nextfree]=0x00000000; 
     mmu_table_owner[nextfree]=nextfree<<20; 
    } 

    if(add_one(0xD6000000,0x0000|8|4)) return(1); 
    if(add_one(0x00000000,0x0000|8|4)) return(1); 
    if(add_one(0xC3F00000,0x0000)) return(1); 
    if(add_one(0xCA000000,0x0000)) return(1); 


    printf(" .globl _start\n"); 
    printf("_start:\n"); 

    for(base=0;base<nextfree;base++) 
    { 
     printf(".word 0x%08X ;@ [0x%08X] 0x%08X\n",mmu_table[base],MMUTABLEBASE+(base<<2),mmu_table_owner[base]); 
    } 

    for(;base<MMUALLOC;base++) 
    { 
     printf(".word 0x00000000 ;@ [0x%08X]\n",MMUTABLEBASE+(base<<2)); 
    } 
    printf(" b zreset\n"); 
    for(base=0;base<15;base++) printf(" b zhang\n"); 
    printf("zhang: b zhang\n"); 
    printf("zreset:\n"); 
    printf(" ldr pc,=reset\n"); 
    printf("\n"); 


    return(0); 
} 
3

含有一到一個虛擬/物理映射16K頁目錄可以用下面的(另)碼來創建:

/* Setup types for virtual addresses, physical address, and the page table. */ 
typedef unsigned long vaddr_t; 
typedef unsigned long paddr_t; 
typedef unsigned long pde_t; 

/* Reserve space for a page directory. Must be 16k aligned. */ 
pde_t page_directory[1 << 12] ALIGNED(1 << 12); 

/* Create a 1MB mapping in the given page directory from 'virt' to 'phys'. */ 
void set_large_page_mapping(pde_t *pd, vaddr_t virt, paddr_t phys) 
{ 
    pde_t entry = 0; 
    entry |= phys & 0xfff00000; /* Target of the mapping. */ 
    entry |= 2;     /* This is a 1MB section entry. */ 
    entry |= 1 << 4;   /* Enable caches (C). */ 
    entry |= 1 << 3;   /* Enable writeback (B). */ 
    entry |= 3 << 10;   /* Full read/write permission. */ 
    pd[virt >> 20] = entry;  /* Install the entry. */ 
} 

/* Setup a page directory with one-to-one physical/virtual mappings. */ 
void setup_one_to_one_mappings(void) 
{ 
    unsigned long i; 

    /* Setup a mapping for each 1MB region in the virtual address space. */ 
    for (i = 0; i < (1 << 12); i++) { 
     /* Map the virtual address "i << 20" to phys address "i << 20". */ 
     set_large_page_mapping(page_directory, i << 20, i << 20); 
    } 

    /* TODO: Write function to install this page directory and enable the MMU. */ 
    enable_mmu(page_directory); 
} 

enable_mmu功能仍然需要被寫入,這將需要:

  • 清理數據和指令高速緩存;
  • 無效的現有TLB條目;
  • 刷新其他緩存(預取緩衝區,分支目標緩存等);
  • 設置TTBR0包含一個指向上面生成的PD的指針;最後
  • 啓用緩存和MMU。

這些指令中的每一條都傾向於CPU特定的,但例子應該(希望)可以在其他地方用於您的硬件(或者通過查看其他操作系統(如Linux或FreeBSD)的源代碼) 。另外,對於測試,您可能只需要擔心最後兩點入門。

0

爲了完整性起見,這裏的這是需要實際使數據緩存一次額外的代碼MMU是建立起來的(也是指令緩存,但是這個工作也沒有MMU):

void enable_data_cache() 
    { 
     asm volatile(" mrc p15, 0, r0, c1, c0, 0"); // Read c1 into r0 
     asm volatile(" orr r0, r0, #4");    // Set bit 2: Dcache 
     asm volatile(" mcr p15, 0, r0, c1, c0, 0"); // Return r0 to c1 
    } 

    void disable_data_cache() 
    { 
     asm volatile("_disable_data_cache_start_:"); 
     asm volatile(" mrc p15, 0, r15, c7, c14, 3"); // test, clean and invalidate 
     asm volatile(" bne _disable_data_cache_start_"); 

     asm volatile(" mov r0,#0"); 
     asm volatile(" mcr p15, 0, r0, c7, c5, 0"); // invalidate I cache 
     asm volatile(" mcr p15, 0, r0, c7, c10, 4"); // drain write buffer 

     asm volatile(" mrc p15, 0, r0, c1, c0, 0"); // Read c1 into r0 
     asm volatile(" bic r0, r0, #4" );   // Clear bit 2: disable Dcache 
     asm volatile(" mcr p15, 0, r0, c1, c0, 0" ); // Return r0 to c1 
    } 

    void clean_data_cache() 
    { 
     asm volatile("_clean_data_cache_start_:"); 
     asm volatile(" mrc p15, 0, r15, c7, c14, 3"); // test, clean and invalidate 
     asm volatile(" bne _clean_data_cache_start_"); 
    } 

    void enable_instruction_cache() 
    { 
     asm volatile(" mrc p15, 0, r0, c1, c0, 0"); // Read c1 into r0 
     asm volatile(" orr r0, r0, #4096");   // Set bit 12: Icache 
     asm volatile(" mcr p15, 0, r0, c1, c0, 0"); // Return r0 to c1 
    } 

    void disable_instruction_cache() 
    { 
     asm volatile(" mrc p15, 0, r0, c1, c0, 0"); // Read c1 into r0 
     asm volatile(" bic r0, r0, #4096");   // Clearr bit 12: Icache 
     asm volatile(" mcr p15, 0, r0, c1, c0, 0"); // Return r0 to c1 
    } 
+0

關於其他例子:值得指出的是,TLB表本身不能被緩存** - make確定你在未緩存的aread中找到它! – roffez 2014-04-08 10:22:26

+0

表爲什麼不能緩存?當然,在訪問它們時,你必須手動刷新/無效,以確保當mmu走過時它們處於良好狀態。 – rsaxvc 2015-04-28 20:18:41