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

📄 memory.c.bak

📁 一份精简的linux内核源代码
💻 BAK
📖 第 1 页 / 共 2 页
字号:
/* *	linux/mm/memory.c * *	(C)	1991  Linus	Torvalds *//* * demand-loading started 01.12.91 - seems it is high on the list of * things wanted, and it should	be easy	to implement. -	Linus *//* * Ok, demand-loading was easy,	shared pages a little bit tricker. Shared * pages started 02.12.91, seems to	work. -	Linus. * * Tested sharing by executing about 30	/bin/sh: under the old kernel it * would have taken	more than the 6M I have	free, but it worked	well as * far as I	could see. * * Also	corrected some "invalidate()"s - I wasn't doing	enough of them. */#include <signal.h>#include <asm/system.h>#include <linux/sched.h>#include <linux/head.h>#include <linux/kernel.h>volatile void do_exit(long code);static inline volatile void	oom(void){	printk("out	of memory\n\r");	do_exit(SIGSEGV);}#define	invalidate() \ /* 重新加载页目录表地址(起到刷新页变换高速缓冲器的作用) */__asm__("movl %%eax,%%cr3"::"a"	(0))/* these are not to	be changed without changing	head.s etc *//* 此处是物理内存分页的状况,非线性地址	*/#define	LOW_MEM	0x100000 /*	分页内存起始地址 */#define	PAGING_MEMORY (15*1024*1024) /*	分页内存大小 */#define	PAGING_PAGES (PAGING_MEMORY>>12) /*	分页内存页数 */#define	MAP_NR(addr) (((addr)-LOW_MEM)>>12)	/* 指定物理内存地址映射到页号 */#define	USED 100/* 页面被占用标志 */#define	CODE_SPACE(addr) ((((addr)+4095)&~4095)	< \	 /*	判断给定线性地址是否在当前进程代码断中 */current->start_code	+ current->end_code)static long	HIGH_MEMORY	= 0; /*	物理内存最高端地址 */#define	copy_page(from,to) \  /* 从from处复制一页内存到to处	*/__asm__("cld ; rep ; movsl"::"S" (from),"D"	(to),"c" (1024):"cx","di","si")static unsigned	char mem_map [ PAGING_PAGES	] =	{0,};/* * Get physical	address	of first (actually last	:-)	free page, and mark	it * used. If	no free	pages left,	return 0. */unsigned long get_free_page(void)  /* 从主内存区找空闲物理页面,从mem_map中找到一空闲项,将其所对应物理页清0并返回该页的物理地址 p561*/{                                   /*仅仅在物理地址空间中对mem_map(物理页)进行操作,未用到页表 */register unsigned long __res asm("ax");__asm__("std ; repne ; scasb\n\t"  /* scasb比较eax和[edi]中的值 */	"jne 1f\n\t"	"movb $1,1(%%edi)\n\t"	"sall $12,%%ecx\n\t"   /* sall 左移 */	"addl %2,%%ecx\n\t"	"movl %%ecx,%%edx\n\t"	"movl $1024,%%ecx\n\t"	"leal 4092(%%edx),%%edi\n\t"   /* leal 获得有效地址 */	"rep ; stosl\n\t"     /* 页清0 */	"movl %%edx,%%eax\n"   /*返回页面起始地址 */	"1:"	:"=a" (__res)	:"0" (0),"i" (LOW_MEM),"c" (PAGING_PAGES),	"D"	(mem_map+PAGING_PAGES-1)	:"di","cx","dx");return __res;}/* * Free	a page of memory at	physical address 'addr'. Used by * 'free_page_tables()' */void free_page(unsigned	long addr) /*释放一页物理内存,addr为该页的物理地址,根据addr算出该页在mem_map中的位置,然后将该项减1*/{                                  /*仅仅在物理地址空间中对mem_map(物理页)进行操作,未用到页表 */	if (addr < LOW_MEM)	return;	if (addr >=	HIGH_MEMORY)		panic("trying to free nonexistent page");	addr -=	LOW_MEM;	addr >>= 12;	if (mem_map[addr]--) return;	mem_map[addr]=0;	panic("trying to free free page");}/* * This	function frees a continuos block of	page tables, as	needed * by 'exit()'.	As does	copy_page_tables(),	this handles only 4Mb blocks. */int	free_page_tables(unsigned long from,unsigned long size)  /*释放指定位置,指定长度的页及页表(相对于线性地址而言,参数为线性地址) */{	unsigned long *pg_table;	unsigned long *	dir, nr;	if (from & 0x3fffff)		panic("free_page_tables	called with	wrong alignment");	if (!from)		panic("Trying to free up swapper memory	space");	size = (size + 0x3fffff) >>	22;    /* 算出共有几个页表 */	dir	= (unsigned	long *)	((from>>20)	& 0xffc); /*算出起始页目录项地址*/	for	( ;	size-->0 ; dir++) {		if (!(1	& *dir))/*页目录项中的p位是否为0*/			continue;		pg_table = (unsigned long *) (0xfffff000 & *dir);/* 取页表地址 */		for	(nr=0 ;	nr<1024	; nr++)	{			if (1 &	*pg_table)/*页表项中的p位是否为0*/				free_page(0xfffff000 & *pg_table);/* 释放页表项对应物理页 */			*pg_table =	0;/* 释放页表项 */			pg_table++;		}		free_page(0xfffff000 & *dir);/*释放页表 */		*dir = 0;/*页目录项清0*/	}	invalidate(); /* 重新加载页目录表地址(起到刷新页变换高速缓冲器的作用) */	return 0;}/* *	Well, here is one of the most complicated functions	in mm. It * copies a	range of linerar addresses by copying only the pages. * Let's hope this is bug-free,	'cause this	one	I don't	want to	debug :-) * * Note! We	don't copy just	any	chunks of memory - addresses have to * be divisible	by 4Mb (one	page-directory entry), as this makes the * function	easier.	It's used only by fork anyway. * * NOTE	2!!	When from==0 we	are	copying	kernel space for the first * fork(). Then	we DONT	want to	copy a full	page-directory entry, as * that	would lead to some serious memory waste	- we just copy the * first 160 pages - 640kB.	Even that is more than we need,	but	it * doesn't take	any	more memory	- we don't copy-on-write in	the	low * 1 Mb-range, so the pages	can	be shared with the kernel. Thus	the * special case	for	nr=xxxx. */int	copy_page_tables(unsigned long from,unsigned long to,long size) /* 复制指定位置,指定长度的页表(相对于线性地址而言,参数为线性地址)并将页表项设为只读,此后有两套页表映射到同一物理页上 */{                                                /* 该函数仅被fork使用 */	unsigned long *	from_page_table;	unsigned long *	to_page_table;	unsigned long this_page;	unsigned long *	from_dir, *	to_dir;	unsigned long nr;	if ((from&0x3fffff)	|| (to&0x3fffff))		panic("copy_page_tables	called with	wrong alignment");	from_dir = (unsigned long *) ((from>>20) & 0xffc); /*计算原目录项起始地址(物理) */	to_dir = (unsigned long	*) ((to>>20) & 0xffc);/*计算目标目录项起始地址(物理) */	size = ((unsigned) (size+0x3fffff))	>> 22;/*计算欲复制的页表数 */	for( ; size-->0	; from_dir++,to_dir++) {		if (1 &	*to_dir) /* 若目的页目录项已存在则死机*/			panic("copy_page_tables: already exist");		if (!(1	& *from_dir))/*若原页目录项不存在则跳过 */			continue;		from_page_table	= (unsigned	long *)	(0xfffff000	& *from_dir);/*页表地址 */		if (!(to_page_table	= (unsigned	long *)	get_free_page()))/*分配一新物理页给目的页表 */			return -1;	/* Out of memory, see freeing */		*to_dir	= ((unsigned long) to_page_table) |	7;/*复制目的目录项 */		nr = (from==0)?0xA0:1024;/*若原地址为0,说明是进程0复制进程1,此时仅需复制160项页表项(起到节约内存的作用);否则一律复制1024项 */		for	( ;	nr-- > 0 ; from_page_table++,to_page_table++) {/*逐项复制页表项 */			this_page =	*from_page_table;			if (!(1	& this_page))				continue;			this_page &= ~2;/*置新页表项为只读 */			*to_page_table = this_page;			if (this_page >	LOW_MEM) {/*若该页>1mb则需修改mem_map(mem_map以1mb处为起始点) */				*from_page_table = this_page;/*将原页表项也设为只读 */				this_page -= LOW_MEM;				this_page >>= 12;				mem_map[this_page]++;			}		}	}	invalidate();	return 0;}/* * This	function puts a	page in	memory at the wanted address. * It returns the physical address of the page gotten, 0 if * out of memory (either when trying to	access page-table or * page.) */unsigned long put_page(unsigned	long page,unsigned long	address) /*将一页物理内存映射到进程的线性地址空间中,参数page为页物理地址,aadress为欲映射的线性地址*/{	unsigned long tmp, *page_table;/* NOTE	!!!	This uses the fact that	_pg_dir=0 */	if (page < LOW_MEM || page >= HIGH_MEMORY)		printk("Trying to put page %p at %p\n",page,address);	if (mem_map[(page-LOW_MEM)>>12]	!= 1)		printk("mem_map	disagrees with %p at %p\n",page,address);	page_table = (unsigned long	*) ((address>>20) &	0xffc);/*根据线性地址获得目录项地址*/	if ((*page_table)&1)  /* 获得页表地址(若不存在则新建一页表) */		page_table = (unsigned long	*) (0xfffff000 & *page_table);	else {		if (!(tmp=get_free_page()))			return 0;		*page_table	= tmp|7;		page_table = (unsigned long	*) tmp;	}	page_table[(address>>12) & 0x3ff] =	page | 7;/*另页表项指向该物理页 */

⌨️ 快捷键说明

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