我想启用数据缓存。我没有太多的ARM经验,因为我主要为IA32编程。我的理解是我需要启用MMU来启用数据缓存。由于我不需要其他明智的虚拟内存,因此我希望MMU能够在所有应用程序的物理和虚拟地址空间之间进行一对一映射。如何启用ARM1136JFS(ARM v6)MMU在物理地址空间与虚拟地址空间之间具有一对一的映射关系?
任何帮助/指针/文章或代码表示赞赏。
我想启用数据缓存。我没有太多的ARM经验,因为我主要为IA32编程。我的理解是我需要启用MMU来启用数据缓存。由于我不需要其他明智的虚拟内存,因此我希望MMU能够在所有应用程序的物理和虚拟地址空间之间进行一对一映射。如何启用ARM1136JFS(ARM v6)MMU在物理地址空间与虚拟地址空间之间具有一对一的映射关系?
任何帮助/指针/文章或代码表示赞赏。
下面给出是代码,以使物理和虚拟地址空间之间的一个一对一映射:
#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");
}
欢迎您尝试类似的方式(见下文)。我想要做同样的事情启用数据缓存并进行一对一的操作。一些工具和文档和代码可能会使问题复杂化。你需要从你的核心中的特定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);
}
含有一到一个虚拟/物理映射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
功能仍然需要被写入,这将需要:
这些指令中的每一条都倾向于CPU特定的,但例子应该(希望)可以在其他地方用于您的硬件(或者通过查看其他操作系统(如Linux或FreeBSD)的源代码) 。另外,对于测试,您可能只需要担心最后两点入门。
为了完整性起见,这里的这是需要实际使数据缓存一次额外的代码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
}
关于其他例子:值得指出的是,TLB表本身不能被缓存** - make确定你在未缓存的aread中找到它! – roffez 2014-04-08 10:22:26
表为什么不能缓存?当然,在访问它们时,你必须手动刷新/无效,以确保当mmu走过时它们处于良好状态。 – rsaxvc 2015-04-28 20:18:41