在ARM系统中,MMU通过页式虚拟存储管理,将虚拟空间和物理空间分别分成一个个固定大小的页,并建立两者之间的映射关系,从而实现虚拟地址到物理地址的转换。MMU还可完成存储器访问权限的控制和虚拟存储器空间缓冲特性的设置。
- * 2002-07-15: Janghoon Lyu <NANDY@MIZI.COM>
- *
- */
- #include "config.h"
- #include "machine.h"
- #include "mmu.h"
- #include "vivi_string.h"
- static unsigned long *mmu_tlb_base = (unsigned long *) MMU_TABLE_BASE;
- /*
- * cpu_arm920_cache_clean_invalidate_all()
- *
- * clean and invalidate all cache lines
- *
- */
- static inline void cpu_arm920_cache_clean_invalidate_all(void)
- {
- __asm__(
- " mov r1, #0/n"
- " mov r1, #7 << 5/n" /* 8 segments */
- "1: orr r3, r1, #63 << 26/n" /* 64 entries */
- "2: mcr p15, 0, r3, c7, c14, 2/n" /* clean & invalidate D index *//*"c7,c14,2"清空并使无效数据cache中某块*/
- /*Clean and Invalidate DCache entry (using index), s3c2410 user manual P551*/
- /*Corperate Register 7 Index Format(arm r3):
- [31:26]=Index, [25:8, 4:0]=SBZ(should be zero),[7;5]=Segment
- 16k data cache = 8 segment, 1 segment = 64 lines, 1 line = 8 words*/
- " subs r3, r3, #1 << 26/n"
- " bcs 2b/n" /* entries 64 to 0 */
- " subs r1, r1, #1 << 5/n"
- " bcs 1b/n" /* segments 7 to 0 */
- " mcr p15, 0, r1, c7, c5, 0/n" /* invalidate I cache *//*s3c210 data sheet P551*/
- " mcr p15, 0, r1, c7, c10, 4/n" /* drain WB(清空写缓冲区) *//*Will stop execution until the write buffer has drained.*/
- );
- }
- void cache_clean_invalidate(void)
- {
- cpu_arm920_cache_clean_invalidate_all();
- }
- /*
- * cpu_arm920_tlb_invalidate_all()
- *
- * Invalidate all TLB entries
- */
- static inline void cpu_arm920_tlb_invalidate_all(void)
- {
- __asm__(
- "mov r0, #0/n"
- "mcr p15, 0, r0, c7, c10, 4/n" /* drain WB */
- "mcr p15, 0, r0, c8, c7, 0/n" /* invalidate I & D TLBs *//*s3c2410 data sheet P546*/
- );
- }
- void tlb_invalidate(void)
- {
- cpu_arm920_tlb_invalidate_all();
- }
- static inline void arm920_setup(void)
- {
- unsigned long ttb = MMU_TABLE_BASE;
- __asm__(
- /* Invalidate caches */
- "mov r0, #0/n"
- "mcr p15, 0, r0, c7, c7, 0/n" /* invalidate I,D caches on v4 */
- "mcr p15, 0, r0, c7, c10, 4/n" /* drain write buffer on v4 */
- "mcr p15, 0, r0, c8, c7, 0/n" /* invalidate I,D TLBs on v4 */
- /* Load page table pointer */
- "mov r4, %0/n"
- "mcr p15, 0, r4, c2, c0, 0/n" /* load page table pointer */
- /* Write domain id (cp15_r3) */
- "mvn r0, #0/n" /* Domains 0, 1 = client *//*11=Manager*/
- "mcr p15, 0, r0, c3, c0, 0/n" /* load domain access register *//*write domain 15:0 access permissions P548*/
- /* Set control register v4 */
- "mrc p15, 0, r0, c1, c0, 0/n" /* get control register v4 *//*read control register P545*/
- /* Clear out 'unwanted' bits (then put them in if we need them) */
- /* ..VI ..RS B... .CAM */ /*these bits's meanning are at data sheet P546*/
- "bic r0, r0, #0x3000/n" /* ..11 .... .... .... *//*I(bit[12])=0 = Instruction cache disabled*/
- /*V[bit[13]](Base location of exception registers)=0 = Low addresses = 0x0000 0000*/
- "bic r0, r0, #0x0300/n" /* .... ..11 .... .... */
- /*R(ROM protection bit[9])=0*/
- /*S(System protection bit[8])=0*/
- /*由于TTB中AP=0b11(line141),所以RS位不使用(P579)*/
- "bic r0, r0, #0x0087/n" /* .... .... 1... .111 */
- /*M(bit[0])=0 = MMU disabled*/
- /*A(bit[1])=0 =Data address alignment fault checking disable*/
- /*C(bit[2])=0 = Data cache disabled*/
- /*B(bit[7])=0 = Little-endian operation*/
- /* Turn on what we want */
- /* Fault checking enabled */
- "orr r0, r0, #0x0002/n" /* .... .... .... ..1. *//*A(bit[1])=1 = Data address alignment fault checking enable*/
- #ifdef CONFIG_CPU_D_CACHE_ON /*is not set*/
- "orr r0, r0, #0x0004/n" /* .... .... .... .1.. *//*C(bit[2])=1 = Data cache enabled*/
- #endif
- #ifdef CONFIG_CPU_I_CACHE_ON /*is not set*/
- "orr r0, r0, #0x1000/n" /* ...1 .... .... .... *//*I(bit[12])=1 = Instruction cache enabled*/
- #endif
- /* MMU enabled */
- "orr r0, r0, #0x0001/n" /* .... .... .... ...1 *//*M(bit[0])=1 = MMU enabled*/
- "mcr p15, 0, r0, c1, c0, 0/n" /* write control register *//*write control register P545*/
- : /* no outputs */
- : "r" (ttb) );
- }
- void mmu_init(void)
- {
- arm920_setup();
- }
- #ifndef CONFIG_S3C2410_NAND_BOOT
- static void copy_vivi_to_ram(void)
- {
- putstr_hex("Evacuating 1MB of Flash to DRAM at 0x", VIVI_RAM_BASE);
- memcpy((void *)VIVI_RAM_BASE, (void *)VIVI_ROM_BASE, VIVI_RAM_SIZE);
- }
- #endif
- /*********************************************************************
- * 段页表项entry:[31:20]段基址,[11:10]为AP(控制访问权限),[8:5]域,
- * [3:2]=CP(decide cached&buffered),[1:0]=0b10-->页表为段
- * MMU_SECDESC:
- * AP=0b11
- * DOMAIN=0
- * [1:0]=0b10--->页表为段
- * MMU_CACHEABLE:
- * C=1(bit[3])
- *
- * 本函数先将4G虚拟空间万全映射到相同的物理地址上:Section,not cacacheable, not bufferable
- * 再修改虚拟地址0x30000000到0x33f00000,映射到SDRAM的64M物理地址:Section, cacacheable, not bufferable(即write-through mode,写通)
- **********************************************************************/
- static inline void mem_mapping_linear(void)
- {
- unsigned long pageoffset, sectionNumber;
- putstr_hex("MMU table base address = 0x", (unsigned long)mmu_tlb_base);
- /* 4G 虚拟地址映射到相同的物理地址. not cacacheable, not bufferable */
- for (sectionNumber = 0; sectionNumber < 4096; sectionNumber++) {
- pageoffset = (sectionNumber << 20);
- *(mmu_tlb_base + (pageoffset >> 20)) = pageoffset | MMU_SECDESC;
- }
- /* make dram cacheable */
- /* SDRAM物理地址0x3000000-0x33ffffff,DRAM_BASE=0x30000000,DRAM_SIZE=64M*/
- for (pageoffset = DRAM_BASE; pageoffset < (DRAM_BASE+DRAM_SIZE); pageoffset += SZ_1M) {
- //DPRINTK(3, "Make DRAM section cacheable: 0x%08lx/n", pageoffset);
- *(mmu_tlb_base + (pageoffset >> 20)) = pageoffset | MMU_SECDESC | MMU_CACHEABLE;
- }
- }
- static inline void nor_flash_mapping(void)
- {
- unsigned long offset, cached_addr, uncached_addr;
- cached_addr = FLASH_BASE;
- uncached_addr = FLASH_UNCACHED_BASE;
- for (offset = 0; offset < FLASH_SIZE; offset += MMU_SECTION_SIZE) {
- cached_addr += offset;
- uncached_addr += offset;
- *(mmu_tlb_base + (cached_addr >> 20)) = /
- (cached_addr | MMU_SECDESC | MMU_CACHEABLE);
- *(mmu_tlb_base + (uncached_addr >> 20)) = /
- (cached_addr | MMU_SECDESC);
- }
- }
- /*
- * PC蔼狼 疙矫利牢 函拳 绝捞 何飘肺歹啊 伐俊辑 角青登档废
- * Flash狼 何飘肺歹 康开阑 RAM狼 何飘肺歹 康开栏肺 概俏矫诺聪促.
- */
- static inline void nor_flash_remapping(void)
- {
- putstr_hex("Map flash virtual section to DRAM at 0x", VIVI_RAM_BASE);
- *(mmu_tlb_base + (VIVI_ROM_BASE >> 20)) = /
- (VIVI_RAM_BASE | MMU_SECDESC | MMU_CACHEABLE);
- }
- void mem_map_nand_boot(void)
- {
- mem_mapping_linear();
- }
- #ifndef CONFIG_S3C2410_NAND_BOOT
- void mem_map_nor(void)
- {
- copy_vivi_to_ram();
- mem_mapping_linear();
- nor_flash_mapping();
- nor_flash_remapping();
- }
- #endif
- void mem_map_init(void)
- {
- #ifdef CONFIG_S3C2410_NAND_BOOT /* CONFIG_S3C2410_NAND_BOOT=y */
- mem_map_nand_boot(); /* 最终调用mem_mepping_linear, 建立页表 */
- #else
- mem_map_nor();
- #endif
- cache_clean_invalidate();/* 清空cache,使无效cache */
- tlb_invalidate(); /* 使无效快表TLB */
- }