vm_kern.c

来自「基于组件方式开发操作系统的OSKIT源代码」· C语言 代码 · 共 188 行

C
188
字号
/* * Copyright (c) 1997-1998 University of Utah and the Flux Group. * All rights reserved. *  * This file is part of the Flux OSKit.  The OSKit is free software, also known * as "open source;" you can redistribute it and/or modify it under the terms * of the GNU General Public License (GPL), version 2, as published by the Free * Software Foundation (FSF).  To explore alternate licensing terms, contact * the University of Utah at csl-dist@cs.utah.edu or +1-801-585-3271. *  * The OSKit is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE.  See the GPL for more details.  You should have * received a copy of the GPL along with the OSKit; see the file COPYING.  If * not, write to the FSF, 59 Temple Place #330, Boston, MA 02111-1307, USA. */#include <sys/param.h>#include <sys/systm.h>#include <sys/malloc.h>#include <vm/vm.h>#include <vm/vm_param.h>#include <oskit/dev/dev.h>int mb_map_full=0;extern char *kmemlimit;extern struct kmemusage *kmemusage;extern char *kmembase;/* * We assign distinct bogus values to these * just so we can distinguish them below. */vm_map_t kernel_map = (vm_map_t)1;vm_map_t kmem_map = (vm_map_t)2;/* * Allocate wired-down memory in the kernel's address space. * This allocator is expected to manage memory at page granularity. */vm_offset_tkmem_alloc(vm_map_t map, vm_size_t size){	return (vm_offset_t)osenv_mem_alloc(round_page(size), 0, PAGE_SIZE);}/* * Free memory allocated with kmem_alloc() or kmem_malloc(). */voidkmem_free(vm_map_t map, vm_offset_t addr, vm_size_t size){	osenv_mem_free((void*)addr, 0, round_page(size));}/* * Function to allocate a submap in the kernel's address space * from which to further allocate kernel memory.  (An old Mach-ism.) * This is only called by kmeminit() in kern/kern_malloc.c, * but we never actually call kmeminit(), so no problem... */vm_map_tkmem_suballoc(vm_map_t parent, vm_offset_t *min, vm_offset_t *max,	      vm_size_t size, boolean_t pageable){	panic("freebsd_glue: kmem_suballoc not implemented");}/* * Function to allocate memory for higher-level allocators * such as the BSD kernel malloc (kern/kern_malloc.c). */vm_offset_tkmem_malloc(vm_map_t map, vm_size_t size, boolean_t waitflag){	osenv_memflags_t env_flags = waitflag == M_WAITOK ? 0 : OSENV_NONBLOCKING;	vm_offset_t blk;	size = round_page(size);	blk = (vm_offset_t)osenv_mem_alloc(size, env_flags, PAGE_SIZE);	if (blk == 0)		return 0;	/*	 * The kernel malloc code assumes that all memory blocks	 * we return will be between kmembase and kmemlimit	 * so that their addresses index into the kmemusage array.	 * Since we can't control what osenv_mem_alloc() gives us,	 * we instead check each allocated block it gives us,	 * and if it falls outside the current kmem range,	 * we dynamically alter BSD's view of reality to include the new range.	 * This hack fundamentally depends on BSD's malloc() 	 * not relying on these "constants" to remain constant	 * during calls to kmem_malloc(), which,	 * quite miraculously, appears to be true.	 * It also depends on osenv_mem_alloc() not returning memory blocks	 * with extremely huge holes between them	 * (e.g., a few blocks at very high addresses and a few very low);	 * otherwise we'll be trying to allocate a huge kmemusage array	 * and will probably run out of memory.	 */	retry:	if (map == kmem_map &&	    (blk < (vm_offset_t)kmembase || blk >= (vm_offset_t)kmemlimit)) {		char *newbase, *newlimit;		struct kmemusage *newusage, *oldusage;		int newnpg, oldnpg;		newbase = (char*)(blk & ~(VM_KMEM_SIZE-1));		newlimit = newbase + VM_KMEM_SIZE;		if (kmemlimit == 0) {			/*			 * This is the very first allocation -			 * create a kmemusage array for the VM_KMEM_SIZE chunk			 * around the allocated block.			 * Hopefully future blocks will also be around here.			 */			kmembase = newbase;			kmemlimit = newlimit;		} else {			/*			 * Reallocate the existing kmemusage array			 * to cover the new area in addition to the old.			 */			if (newbase > kmembase)				newbase = kmembase;			if (newlimit < kmemlimit)				newlimit = kmemlimit;		}		/* Allocate a new kmemusage array */		newnpg = (newlimit - newbase) / PAGE_SIZE;		newusage = osenv_mem_alloc(newnpg * sizeof(struct kmemusage),				          env_flags, 0);		if (newusage == NULL) {			osenv_mem_free((void*)blk, env_flags, size);			return 0;		} else			bzero(newusage, newnpg * sizeof(struct kmemusage));		/*		 * Ensure that the kmemusage array hasn't changed		 * while we were potentially blocked during the allocation.		 * Actually, it's OK if it's changed,		 * just as long as it hasn't changed		 * so as to cover an area outside of our new intended array.		 */		if (waitflag == M_WAITOK &&		    (kmembase < newbase || kmemlimit > newlimit)) {			osenv_mem_free(newusage, env_flags,				      newnpg * sizeof(struct kmemusage));			goto retry;		}		/*		 * Copy the existing array into the new array.		 * and start officially using the new array.		 */		if (kmemusage) 			memcpy(&newusage[(kmembase - newbase) / PAGE_SIZE],			       &kmemusage[0],			       sizeof(struct kmemusage) *			       ((kmemlimit - kmembase) / PAGE_SIZE));		oldusage = kmemusage;		oldnpg = (kmemlimit - kmembase) / PAGE_SIZE;		kmemusage = newusage;		kmembase = newbase;		kmemlimit = newlimit;		/*		 * Free the old array if there was one.		 * We can't do this until after the switch is complete		 * because the free call might block.		 */		if (oldusage)			osenv_mem_free(oldusage, env_flags,			      oldnpg * sizeof(struct kmemusage));	}	return blk;}

⌨️ 快捷键说明

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