2440 开启MMU

MMU也属于操作系统核心部分,主要功能:

a) 通过内存管理单元对每个进程进行不同的物理地址映射,实现了各进程间的相同虚拟地址到独立物理地址空间访问,是操作系统支持多进程的基本,相对多线程操作系统更安全;

b) 当物理内存不够时可以虚拟到外部存储设备,即使当物理内存不够时也能正常运行程序,当然需要足够的外部存储空间,如nand,nor,harddisk等这些外部存储器容量比内存大的多;

c) ARM的中断向量表需要在0地址,一般情况bank0为nor flash,当程序从内存运行时,需要开启MMU,映射中断向量表到0地址,否则中断时程序可能跑飞;

 

1.设置MMU的页表,页表本身存储在内存中(此示例为:0x32000000):

/*
* 设置页表
*/
void create_page_table(void)
{

/*
* 用于段描述符的一些宏定义
*/
#define MMU_FULL_ACCESS     (3 << 10)   /* 访问权限 */
#define MMU_DOMAIN          (0 << 5)    /* 属于哪个域 */
#define MMU_SPECIAL         (1 << 4)    /* 必须是1 */
#define MMU_CACHEABLE       (0 << 3)    /* cacheable */
#define MMU_BUFFERABLE      (0 << 2)    /* bufferable */
#define MMU_SECTION         (2)         /* 表示这是段描述符 */
#define MMU_SECDESC         (MMU_FULL_ACCESS | MMU_DOMAIN | MMU_SPECIAL | /
                             MMU_SECTION)
#define MMU_SECDESC_WB      (MMU_FULL_ACCESS | MMU_DOMAIN | MMU_SPECIAL | /
                             MMU_CACHEABLE | MMU_BUFFERABLE | MMU_SECTION)
#define MMU_SECTION_SIZE    0x00100000

    unsigned long virtuladdr, physicaladdr;
    volatile unsigned long *mmu_tlb_base = (unsigned long *)0x32000000;
  
    /*
     * Steppingstone的起始物理地址为0,第一部分程序的起始运行地址也是0,
     * 为了在开启MMU后仍能运行第一部分的程序,
     * 将0~1M的虚拟地址映射到同样的物理地址
     */
#if 0
    virtuladdr = 0;
    physicaladdr = 0;
    *(mmu_tlb_base + (virtuladdr >> 20)) = (physicaladdr & 0xFFF00000) | /
                                            MMU_SECDESC_WB;
#endif

    /*
     * 0x56000000是GPIO寄存器的起始物理地址,
     * GPBCON和GPBDAT这两个寄存器的物理地址0x56000010、0x56000014,
     * 为了在第二部分程序中能以地址0xA0000010、0xA0000014来操作GPBCON、GPBDAT,
     * 把从0xA0000000开始的1M虚拟地址空间映射到从0x56000000开始的1M物理地址空间
     */
    virtuladdr = 0x56000000;//0xA0000000;
    physicaladdr = 0x56000000;
    *(mmu_tlb_base + (virtuladdr >> 20)) = (physicaladdr & 0xFFF00000) | /
                                            MMU_SECDESC;

    /*
     * SDRAM的物理地址范围是0x30000000~0x33FFFFFF,
     * 将虚拟地址0xB0000000~0xB3FFFFFF映射到物理地址0x30000000~0x33FFFFFF上,
     * 总共64M,涉及64个段描述符
     */

    virtuladdr = 0;//0xB0000000;
    physicaladdr = 0x30000000;
    while (virtuladdr < 0x04000000)      //0xB4000000
    {
        *(mmu_tlb_base + (virtuladdr >> 20)) = (physicaladdr & 0xFFF00000) | /
                                                MMU_SECDESC_WB;
        virtuladdr += 0x100000;
        physicaladdr += 0x100000;
    }

    virtuladdr = 0x30000000;//0xB0000000;
    physicaladdr = 0x30000000; //映射到相同物理地址,保证MMU开启后能正确取下条指令,否则跑飞
    while (virtuladdr < 0xFF000000)      //0xB4000000
    {
        *(mmu_tlb_base + (virtuladdr >> 20)) = (physicaladdr & 0xFFF00000) | /
                                                MMU_SECDESC_WB;
        virtuladdr += 0x100000;
        physicaladdr += 0x100000;
    }
}

 

2.ARM通过协处理器p15访问MMU:

MMU_INIT
        stmfd sp!,{r0-r4,lr}

        mov    r0, #0x32000000 ;页表基址
        mcr    p15, 0, r0, c2, c0, 0

        mov    r0, #0x00000001 ;开启MMU,注意开启MMU后地址发生变化,为保证CPU能正确取下以条指令,将虚拟地址0x30000000映射到相同的物理地址0x30000000上,否则程序跑飞。
        mcr    p15,0,r0,c1,c0,0

        ldmfd sp!,{r0-r4,pc}
        END

 

3.init.s:

                bl         create_page_table
                bl         MMU_INIT

;                bl         LED_ON
                bl         Main

你可能感兴趣的:(2440 开启MMU)