⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mmu.c

📁 这是Linux环境下的内核引导程序miniboot0.8
💻 C
字号:
#include "mmu.h"
#include "cpu.h"
#include "types.h"

void clear_mem(u32 addr_start,u32 addr_end)
{
	asm volatile(
		"ldr r0,%0 \n\t"
		"ldr r1,%1 \n\t"
		"ldr r2,=0x00000000 \n\t"
		"1: str r2,[r0],#4 \n\t"
		"cmp r0,r1 \n\t"
		"bne 	1b \n\t"
		:
		:"m"(addr_start),"m"(addr_end)
		:"r0","r1","r2"
	);
}

/*
 *	页目录设置函数,页目录总共有4096个目录项。
 *	base和limit虚拟地址的基地址和范围。
 *	pg_table是页表基地址,pg_table必须是1kb的边界
 */
int setup_directory(u32 base,u32 limit,u32 pg_table,u32 attr)
{
	//页目录项
	u32 *dir_entry=(unsigned int *)DIRECTORY_BASE+(base>>20);
	u32 dirs;
	u32 dir_count;
	
	//pg_table不是1kb的边界,返回-1
	if(pg_table&0x3ff)
	{
		return -1;
	}
	
	//总共要多设置多少个目录项
	dirs=(limit-base)>>20;
	
	for(dir_count=0;dir_count<=dirs;dir_count++)
	{
		*dir_entry=pg_table|attr;
		pg_table+=PAGE_TABLE_SIZE;
		dir_entry++;

	}
	
	return 1;
}

/*
 *	页表设置函数,每页表总共有256个页表项。
 *	base和limit虚拟地址的基地址和范围。
 *	phy_addr是要映射的物理地址,phy_addr必须是4kb的边界
 */
int paging(u32 base,u32 limit,u32 phy_addr,u32 attr)
{
	u32 *dir_entry	=(unsigned int *)DIRECTORY_BASE+(base>>20);
	u32 *page_entry;
	u32 dir_count;
	u32 page_count;
	
	//phy_addr不是4kb的边界,返回-1
	if((phy_addr&0xfff))
	{
		return -1;
	}
	
	//总共要多设置的目录项个数为 (limit-base)>>20
	for(dir_count=0;dir_count<=(limit-base)>>20;dir_count++)
	{
		page_entry	=(unsigned int *)(*dir_entry&0xFFFFFC00);
		
		//每个页表有256个页表项
		for(page_count=0;page_count<256;page_count++)
		{
			*page_entry=phy_addr|attr;
			
			phy_addr+=SMALL_PAGE_SIZE;
			page_entry++;
		}
		dir_entry++;
	}
	
	return 1;
}

/*
 *	本函数将指定的虚拟地址映射到指定的物理地址
 *	是很好用的一个工具函数 : )
 */u32 address_map(u32 v_addr,u32 p_addr,u32 attr)
{
	u32 *dir_entry=(unsigned int *)DIRECTORY_BASE+(v_addr>>20);
	u32 *page_entry;
	
	if(p_addr&0xfff)
	{
		return -1;
	}
	
	page_entry=(unsigned int*)(*dir_entry&0xFFFFFC00)+((v_addr>>12)&0xff);

	*page_entry=p_addr|attr;
	
	return 1;
}


//设置sdram页目录项
void setup_sdram_directory()
{
	/*
	 *	CLIENT 将使分配的内存在被访问的时候进行权限检测
	 */
	setup_directory(SDRAM_BASE,(SDRAM_LIMIT-1),
		RAM_PAGE_TABLE_BASE,
		COARSE_PAGE_DESC|CLIENT);
}
//设置sfr页目录项
void setup_sfr_directory()
{
	/*
	 *	CLIENT 将使分配的内存在被访问的时候进行权限检测
	 */
	setup_directory(SFR_BASE,(SFR_LIMIT-1),
		SFR_PAGE_TABLE_BASE,
		COARSE_PAGE_DESC|CLIENT);
}
//设置异常向量表页目录项
void setup_exception_directory()
{
	/*
	 *	CLIENT 将使分配的内存在被访问的时候进行权限检测
	 */
	setup_directory(0xfff00000,0xffffffff,
		VECTOR_PAGE_TABLE_BASE,
		COARSE_PAGE_DESC|CLIENT);
}

//设置DSP表页目录项
void setup_dsp_directory()
{
	/*
	 *	CLIENT 将使分配的内存在被访问的时候进行权限检测
	 */
	setup_directory(DSP_BASE,(DSP_LIMIT-1),
		DSP_PAGE_TABLE_BASE,
		COARSE_PAGE_DESC|CLIENT);
}

/*
 *	sdram进行分页
 */
void setup_sdram_page()
{
	/*
	 *	SMALL_PAGE_DESC为SMALL_PAGE|AP0|AP1|AP2|AP3
	 *	其中AP0,AP1,Ap2,AP3使该页面对内核级的程序具
	 *	有读写许可,而对用户级的程序只具有读许可
	 */
	paging(SDRAM_BASE,(SDRAM_LIMIT-1),
		0x30000000,
		SMALL_PAGE_DESC|CACHEABLE);//CACHEABLE开启内存加速功能
}
/*
 *	sfr进行分页
 */
void setup_sfr_page()
{
	/*
	 *	SMALL_PAGE_DESC为SMALL_PAGE|AP0|AP1|AP2|AP3
	 *	其中AP0,AP1,Ap2,AP3使该页面对内核级的程序具
	 *	有读写许可,而对用户级的程序只具有读许可
	 */
	paging(SFR_BASE,(SFR_LIMIT-1),
		0x48000000,
		SMALL_PAGE_DESC);
}

/*
 *	DSP地址进行分页
 */
void setup_dsp_page()
{
	/*
	 *	SMALL_PAGE_DESC为SMALL_PAGE|AP0|AP1|AP2|AP3
	 *	其中AP0,AP1,Ap2,AP3使该页面对内核级的程序具
	 *	有读写许可,而对用户级的程序只具有读许可
	 */
	paging(DSP_BASE,(DSP_LIMIT-1),
		DSP_BASE,
		SMALL_PAGE_DESC);
}

/*
 *	设置中断向量的映射关系,本系统的中断向量采用高端模式(0xffff0000),
 *	故需要把0xffff0000映射到物理地址0x30075000(KERNEL_BASE)
 */
void setup_exception_vector()
{
	address_map(0xffff0000,KERNEL_BASE,SMALL_PAGE_DESC|CACHEABLE);
}


void init_page_directory()
{
	setup_sdram_directory();
	setup_sfr_directory();
	setup_exception_directory();
	setup_dsp_directory();
}

void mem_map()
{
	setup_sdram_page();
	setup_sfr_page();
	setup_exception_vector();
	setup_dsp_page();
	
}

void setup_ttb()
{
	invalidate_IDCache();
	invalidate_TLBs();

	//对页目录和页表所在内存区域清0
	clear_mem(DIRECTORY_BASE,KERNEL_BASE);
	init_page_directory();
	mem_map();
}


⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -