一步一步写嵌入式操作系统----MMU

MMU作为一个硬件单元有把虚拟地址转换成物理地址的作用,操作系统可以让用户运行大量的程序,这些程序都需要分配内存,而一段程序重复运行的时候,如果没有MMU,一段物理地址不可能被重复使用,而有MMU的时候可以把同一虚拟地址映射到不同的物理地址段,这样就避免地址冲突了。而且大家都有体验,以linux为例,存在交换分区,它可以把硬盘的存储空间映射到虚拟地址中,这样一来相当于内存被扩容了,当然这样的便利也伴随着访问效率的降低。

mmu.c

/*mask for page table base addr*/
#define PAGE_TABLE_L1_BASE_ADDR_MASK	(0xffffc000)

#define VIRT_TO_PTE_L1_INDEX(addr)		(((addr)&0xfff00000)>>18)

#define PTE_L1_SECTION_NO_CACHE_AND_WB	(0x0<<2)
#define PTE_L1_SECTION_DOMAIN_DEFAULT	(0x0<<5)
#define PTE_ALL_AP_L1_SECTION_DEFAULT	(0x1<<10)

#define PTE_L1_SECTION_PADDR_BASE_MASK	(0xfff00000)
#define PTE_BITS_L1_SECTION				(0x2)

#define L1_PTR_BASE_ADDR				0x30700000
#define PHYSICAL_MEM_ADDR				0x30000000
#define VIRTUAL_MEM_ADDR				0x30000000
#define MEM_MAP_SIZE					0x800000
#define PHYSICAL_IO_ADDR				0x48000000
#define VIRTUAL_IO_ADDR					0xc8000000
#define IO_MAP_SIZE						0x18000000

void start_mmu(void)
{
	unsigned int ttb = L1_PTR_BASE_ADDR;

	asm (
		"mcr p15,0,%0,c2,c0,0\n"    /* set base address of page table*/
		"mvn r0,#0\n"                  
		"mcr p15,0,r0,c3,c0,0\n"    /* enable all region access*/

		"mov r0,#0x1\n"
		"mcr p15,0,r0,c1,c0,0\n"    /* set back to control register */
		"mov r0,r0\n"
		"mov r0,r0\n"
		"mov r0,r0\n"
		:
		: "r" (ttb)
		:"r0"
	);
}

unsigned int gen_l1_pte(unsigned int paddr)
{
	return (paddr & PTE_L1_SECTION_PADDR_BASE_MASK) | PTE_BITS_L1_SECTION;
}

unsigned int gen_l1_pte_addr(unsigned int baddr, unsigned int vaddr)
{
	return (baddr & PAGE_TABLE_L1_BASE_ADDR_MASK) | VIRT_TO_PTE_L1_INDEX(vaddr);
}

void init_sys_mmu(void)
{
	unsigned int pte;
	unsigned int pte_addr;
	int j;

	for(j = 0; j < MEM_MAP_SIZE>>20; j++) {
		pte = gen_l1_pte(PHYSICAL_MEM_ADDR + (j<<20));
		pte |= PTE_ALL_AP_L1_SECTION_DEFAULT;
		pte |= PTE_L1_SECTION_NO_CACHE_AND_WB;
		pte |= PTE_L1_SECTION_DOMAIN_DEFAULT;
		pte_addr = gen_l1_pte_addr(L1_PTR_BASE_ADDR, VIRTUAL_MEM_ADDR + (j<<20));
		*(volatile unsigned int *)pte_addr = pte;
	}

	for(j = 0; j< IO_MAP_SIZE>>20; j++) {
		pte = gen_l1_pte(PHYSICAL_IO_ADDR+(j<<20));
		pte |= PTE_ALL_AP_L1_SECTION_DEFAULT;
		pte |= PTE_L1_SECTION_NO_CACHE_AND_WB;
		pte |= PTE_L1_SECTION_DOMAIN_DEFAULT;
		pte_addr = gen_l1_pte_addr(L1_PTR_BASE_ADDR, VIRTUAL_IO_ADDR + (j<<20));
		*(volatile unsigned int *)pte_addr = pte;
	}
}

 

你可能感兴趣的:(linux)