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

📄 mm.c.bak

📁 os arm os arm os arm os arm os arm os arm os arm os arm os arm os arm os arm os arm os arm os arm
💻 BAK
字号:
/* *	ApOS (Another Project software for s3c2410) *	 *	This program is free software; you can redistribute it and/or modify *	it under the terms of the GNU General Public License version 2 as *	published by the Free Software Foundation. *			 *						Copyright caiyuqing * */#include "../include/mm/mm.h"#include "../include/kernel/task.h"extern struct task_struct* current;//#define _MEM_DEBUG/* *	很重要的一个数组,ram_map是对主内存区域(用户空间)0x30a00000~0x33ffffff *	的一个映射,该内存区域被分成13824(RAM_PAGES)个页,每个页对应ram_map中 *	的一个元素,当该页是干净的(未被映射的),则对应的ram_map数组 *	元素的值为0 */unsigned char ram_map[RAM_PAGES];int memcpy(unsigned char* dest,unsigned char* src,int n){	for(;n>0;n--)	{		*dest++=*src++;	}}/* *	将ram_map数组清0 */void clear_ram_map(){	unsigned char *ram_map_base=ram_map;	unsigned int pages=RAM_PAGES;		asm volatile(		"ldr r0,%0 \n\t"		"ldr r1,%1 \n\t"		"add r1,r0,r1 \n\t"		"ldrb r2,=0x00 \n\t"		"1: strb r2,[r0],#1 \n\t"		"cmp r0,r1 \n\t"		"bne 1b \n\t"		:		:"m"(ram_map_base),"m"(pages)		:"r0","r1","r2","memory"	);}void ram_init(){	init_kmalloc();	clear_ram_map();}void oom(){	panic("error:out of memory.\n");}/* *	获得"干净"的物理页地址,并将该页对应的ram_map元素增1 */unsigned int get_free_physical_page(){	unsigned int ram_page_index;	unsigned int page_address;		for(ram_page_index=0;		ram_page_index<RAM_PAGES&&ram_map[ram_page_index];		ram_page_index++);		if(ram_page_index==RAM_PAGES)	{		return 0;	}		ram_map[ram_page_index]++;	page_address=USER_RAM_BASE+ram_page_index*PAGE_SIZE;	/*	 *	将新获得的页面清零。	 */ 	 	asm volatile(		"ldr r0,%0 \n\t"		"ldr r1,=4096 \n\t"		"add r1,r0,r1 \n\t"		"ldr r2,=0x00000000 \n\t"		"1: str r2,[r0],#4 \n\t"		"cmp r0,r1 \n\t"		"bne 1b \n\t"		:		:"m"(page_address)		:"r0","r1","r2"	);		return page_address;}/* *	释放物理地址 p_page 指定的一页内存 */int free_physical_page(unsigned int p_page){	unsigned int ram_page_index;	//页面号		/*	 *	若该页地址属于内核地址范围内则不进行处理,只打印警告信息并返回-1,	 */	if(p_page>=SYS_RAM_BASE && p_page<SYS_RAM_LIMIT)	{		#ifdef _MEM_DEBUG			printk("warning: free_physical_page trying to free the kernel's page\n");		#endif 				return -1;	}	/*	 *	若该页地址大于系统所含物理内存的最高端(0x34000000)则显示出错信息	 *	并死机	 */	 	if(p_page>=(SDRAM_LIMIT))	{		panic("error: free_physical_page trying to free nonexistent page\n");	}	/*	 *	否则将物理页地址转换成页面号(ram_map数组中的索引号),根据该页面号对	 *	ram_map数组中的元素进行递减操作,页面号 = (page_addr-USER_RAM_BASE)/PAGE_SIZE	 *	在递减操作之间先判断该元素是否为0,若该元素不为0,则递减并返回该页面号,	 *	若该元素为0,则说明我们要释放一个空闲页,则报错死机	 */	else	{		ram_page_index=(p_page-USER_RAM_BASE)/PAGE_SIZE;		if(ram_map[ram_page_index])		{			ram_map[ram_page_index]--;						return ram_page_index;		}		else		{			panic("error: free_physical_page tryint to free free page\n");		}	}}int free_virtual_page(unsigned int v_page){	unsigned int *dir_entry;	unsigned int *page_entry;		//若v_page不是4KB的边界,说明该地址不是页地址,报错死机	if(v_page&0xfff)	{		panic("error: free_virtual_page called with wrong alignment\n");	}	/*	 *	若v_page为EXCEPTION_BASE或为内核使用的地址范围则警告并返回-1	 */	if( (v_page>=SYS_VADDR_BASE&&v_page<SYS_VADDR_LIMIT)||v_page==EXCEPTION_BASE)	{		printk("warning: free_virtual_page trying to free kernel's page\n");		return -1;	}		dir_entry=(unsigned int *)DIRECTORY_BASE+(v_page>>20);	if(DIR_VALID(*dir_entry))	{		page_entry= *dir_entry&0xfffffc00;		if(PAGE_VALID(*page_entry))		{			free_physical_page(*page_entry&0xFFFFF000);			*page_entry=0;		}		//刷新 TLB		invalidate_TLBs();		return v_page;	}		return -1;}/* *	free_page_tables 用于释放连续的内存区域。 *	注意	这个函数只能够处理1MB为单位的内存块,也就是说若size<1MB *		也按1MB处理。 *		mv_addr必须处于1MB的边界 * */void free_page_tables(unsigned int mv_addr,unsigned int size){	unsigned int *dir_entry;	unsigned int *page_entry;	unsigned int nr;		//检查mv_addr是否处于1MB的边界	if(mv_addr&0xfffff)	{		panic("error: free_page_table called with wrong alignment\n");	}		/*	 *	size用于表明总共有多少MB(有多少个页目录项)。或许你会感到奇怪,为什么	 *	size必须先加上0xfffff?	 *	size+0xfffff的原因是因为会发生这种情况,若size=1.1MB,则 size>>20=1,	 *	也就是说余数部分被去掉了。但size=1.1MB的话,我们要按2MB进行处理,所以	 *	必须加上0xfffff	 */	size=(size+0xfffff)>>20;		dir_entry=(unsigned int *)DIRECTORY_BASE+(mv_addr>>20);	#ifdef _MEM_DEBUG		printk("free page_table\n");		printk("@virtual address:0x%0x\n",mv_addr);	#endif	for(;size-->0;dir_entry++)	{		if(DIR_INVALID(*dir_entry))		{			panic("error: free_page_table trying to free unmap virtual address\n");					continue;		}		page_entry=(*dir_entry&0xFFFFFC00);						for(nr=0;nr<256;nr++)		{			if(*page_entry&0x00000003)			{				//若p_addr为0xfff00000或为SYS_RAM地址范围,报错死机				if(((*page_entry&0xFFFFF000)>=SYS_RAM_BASE&&(*page_entry&0xFFFFF000)<SYS_RAM_LIMIT ))				{					panic("error: free_page_table trying to free kernel memory space\n");				}				#ifdef _MEM_DEBUG					printk("	#physic address:0x%0x \n",*page_entry&0xFFFFF000);				#endif				free_physical_page(*page_entry&0xFFFFF000);				*page_entry=0;			}			else 			{				panic("error: free_page_table trying to free unmap virtual address\n");			}			page_entry++;		}		*dir_entry=0;	}	//刷新 TLB	invalidate_TLBs();}/* *	内存复制函数,实际上是复制页表 */void copy_page_tables(unsigned int mv_addr_src,	unsigned int mv_addr_dest,	unsigned int size){	unsigned int *dir_entry_src=(unsigned int *)DIRECTORY_BASE+(mv_addr_src>>20);	unsigned int *dir_entry_dest=(unsigned int *)DIRECTORY_BASE+(mv_addr_dest>>20);	unsigned int *page_entry_src;	unsigned int *page_entry_desc;	unsigned int tmp;	unsigned int page_count;			//源地址和目标地址必须从1MB边界开始	if((mv_addr_src&0xfffff)||(mv_addr_dest&0xfffff))	{		panic("error: copy_page_tables called with wrong alignment\n");	}		//size的单位由byte变为MB	size=(size+0xfffff)>>20;			//每次至少复制1MB(一个目录项)	for(;size--;dir_entry_src++,dir_entry_dest++)	{		//源目录没有使用,不用复制		if(DIR_INVALID(*dir_entry_src))			continue;					if(DIR_INVALID(*dir_entry_dest))//目标地址页目录对应的页表不存在		{			//分配一页内存给目标地址存放页表			if((tmp=get_free_physical_page())==0)				oom();			*dir_entry_dest=tmp|COARSE_PAGE_DESC|CLIENT;		}						page_entry_src=(unsigned int *)(*dir_entry_src&0xFFFFFC00);		page_entry_desc=(unsigned int *)(*dir_entry_dest&0xFFFFFC00);				for(page_count=0;page_count<256;page_count++)		{			/*			 *	该页面被父进程和子进程共项,我们要从新设置该内存页面			 *	的访问权限。User模式只读,System模式允许读写,这样当			 *	两个进程中的某一个要对其进行写操作时将引起permission fault			 */			*page_entry_src=(*page_entry_src&~(0xfff))|USER_SMALL_PAGE_DESC_R;			*page_entry_desc=*page_entry_src;						//若该页地址属于用户空间,则将内存引用数组的对应项增一			if((*page_entry_src&~(0xfff))>=USER_RAM_BASE)				ram_map[(((*page_entry_src&~(0xfff))-USER_RAM_BASE)/PAGE_SIZE)]++;						page_entry_desc++;			page_entry_src++;					}	}		//刷新 TLB	invalidate_TLBs();}void see_addr_map(unsigned int mv_addr){	unsigned int *dir_entry=(unsigned int *)DIRECTORY_BASE+(mv_addr>>20);	unsigned int *page_entry=(*dir_entry&0xFFFFFC00);	unsigned int phy_page_index=(((*page_entry&~(0xfff))-USER_RAM_BASE)/PAGE_SIZE);		printk("TLB index  :0x%0x  [0x%0x]	",(mv_addr>>20),*dir_entry);	printk("page_entry :0x%0x  [0x%0x]\n",page_entry,*page_entry);	printk("physic page index:%	reference count%d",			phy_page_index,ram_map[phy_page_index]);}/* *	缺页处理函数 */void do_no_page(unsigned int mv_addr){	unsigned int *dir_entry=(unsigned int *)DIRECTORY_BASE+(mv_addr>>20);	unsigned int *page_entry;	unsigned int tmp;		if(DIR_INVALID(*dir_entry))	{		#ifdef _MEM_DEBUG			printk("\nlevel one descriptor translate fail\n");			printk("	dir address:0x%0x\n",dir_entry);			printk("	dir context:0x%0x\n",*dir_entry);		#endif		if((tmp=get_free_physical_page())==0)			oom();		/*		 *	CLIENT 将使分配的内存在被访问的时候进行权限检测		 */		*dir_entry=tmp|COARSE_PAGE_DESC|CLIENT;		#ifdef _MEM_DEBUG			printk("map.\n");			printk("	dir address:0x%0x\n",dir_entry);			printk("	dir context:0x%0x\n",*dir_entry&0xFFFFFC00);				#endif		page_entry=(unsigned int *)(*dir_entry&0xFFFFFC00)+((mv_addr>>12)&0xff);		if((tmp=get_free_physical_page())==0)			oom();				/*		 *	USER_SMALL_PAGE_DESC_RW 将使分配的内存在内核		 *	级和用户级都具有读写的访问许可		 */		*page_entry=tmp|USER_SMALL_PAGE_DESC_RW;	}	else	{		page_entry=(unsigned int *)(*dir_entry&0xFFFFFC00)+((mv_addr>>12)&0xff);		if(PAGE_INVALID(*page_entry))		{			#ifdef _MEM_DEBUG				printk("\nlevel two descriptor translate fail\n");				printk("	page address:0x%0x\n",page_entry);				printk("	page context:0x%0x\n",*page_entry&0xFFFFF000);			#endif			if((tmp=get_free_physical_page())==0)				oom();			*page_entry=tmp|USER_SMALL_PAGE_DESC_RW;			#ifdef _MEM_DEBUG				printk("map.\n");				printk("	page_entry address:0x%0x\n",page_entry);				printk("	page_entry context:0x%0x\n",*page_entry&0xFFFFF000);			#endif		}	}}void do_permission_fault(unsigned int mv_addr){	unsigned int *dir_entry=(unsigned int *)DIRECTORY_BASE+(mv_addr>>20);	unsigned int *page_entry;	unsigned int tmp;			printk("permission fault.\n");	printk("	pid: %d\n",current->pid);	printk("	fault address :0x%0x\n",mv_addr);			panic("system is rebooting...\n");}

⌨️ 快捷键说明

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