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

📄 memory.c

📁 最早的linux操作系统源代码(3)
💻 C
字号:
#include <signal.h>#include <linux/config.h>#include <linux/head.h>#include <linux/kernel.h>#include <asm/system.h>int do_exit(long code);#define invalidate() \__asm__("movl %%eax,%%cr3"::"a" (0))#if (BUFFER_END < 0x100000)#define LOW_MEM 0x100000#else#define LOW_MEM BUFFER_END#endif/* these are not to be changed - thay are calculated from the above */#define PAGING_MEMORY (HIGH_MEMORY - LOW_MEM)#define PAGING_PAGES (PAGING_MEMORY/4096)#define MAP_NR(addr) (((addr)-LOW_MEM)>>12)#if (PAGING_PAGES < 10)#error "Won't work"#endif#define copy_page(from,to) \__asm__("cld ; rep ; movsl"::"S" (from),"D" (to),"c" (1024))static unsigned short 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){register unsigned long __res asm("ax");__asm__("std ; repne ; scasw\n\t"	"jne 1f\n\t"	"movw $1,2(%%edi)\n\t"	"sall $12,%%ecx\n\t"	"movl %%ecx,%%edx\n\t"	"addl %2,%%edx\n\t"	"movl $1024,%%ecx\n\t"	"leal 4092(%%edx),%%edi\n\t"	"rep ; stosl\n\t"	"movl %%edx,%%eax\n"	"1:"	:"=a" (__res)	:"0" (0),"i" (LOW_MEM),"c" (PAGING_PAGES),	"D" (mem_map+PAGING_PAGES-1)	);return __res;}/* * Free a page of memory at physical address 'addr'. Used by * 'free_page_tables()' */void free_page(unsigned long addr){	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); /* _pg_dir = 0 */	for ( ; size-->0 ; dir++) {		if (!(1 & *dir))			continue;		pg_table = (unsigned long *) (0xfffff000 & *dir);		for (nr=0 ; nr<1024 ; nr++) {			if (1 & *pg_table)				free_page(0xfffff000 & *pg_table);			*pg_table = 0;			pg_table++;		}		free_page(0xfffff000 & *dir);		*dir = 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){	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); /* _pg_dir = 0 */	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;		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) {				*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){	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;	return page;}void un_wp_page(unsigned long * table_entry){	unsigned long old_page,new_page;	old_page = 0xfffff000 & *table_entry;	if (old_page >= LOW_MEM && mem_map[MAP_NR(old_page)]==1) {		*table_entry |= 2;		return;	}	if (!(new_page=get_free_page()))		do_exit(SIGSEGV);	if (old_page >= LOW_MEM)		mem_map[MAP_NR(old_page)]--;	*table_entry = new_page | 7;	copy_page(old_page,new_page);}	/* * This routine handles present pages, when users try to write * to a shared page. It is done by copying the page to a new address * and decrementing the shared-page counter for the old page. */void do_wp_page(unsigned long error_code,unsigned long address){	un_wp_page((unsigned long *)		(((address>>10) & 0xffc) + (0xfffff000 &		*((unsigned long *) ((address>>20) &0xffc)))));}void write_verify(unsigned long address){	unsigned long page;	if (!( (page = *((unsigned long *) ((address>>20) & 0xffc)) )&1))		return;	page &= 0xfffff000;	page += ((address>>10) & 0xffc);	if ((3 & *(unsigned long *) page) == 1)  /* non-writeable, present */		un_wp_page((unsigned long *) page);	return;}void do_no_page(unsigned long error_code,unsigned long address){	unsigned long tmp;	if (tmp=get_free_page())		if (put_page(tmp,address))			return;	do_exit(SIGSEGV);}void calc_mem(void){	int i,j,k,free=0;	long * pg_tbl;	for(i=0 ; i<PAGING_PAGES ; i++)		if (!mem_map[i]) free++;	printk("%d pages free (of %d)\n\r",free,PAGING_PAGES);	for(i=2 ; i<1024 ; i++) {		if (1&pg_dir[i]) {			pg_tbl=(long *) (0xfffff000 & pg_dir[i]);			for(j=k=0 ; j<1024 ; j++)				if (pg_tbl[j]&1)					k++;			printk("Pg-dir[%d] uses %d pages\n",i,k);		}	}}

⌨️ 快捷键说明

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