mem.c

来自「优龙2410linux2.6.8内核源代码」· C语言 代码 · 共 845 行 · 第 1/2 页

C
845
字号
 again:	if(page == NULL) return(page);	if(PageHighMem(page)) return(page);	addr = (unsigned long) page_address(page);	for(i = 0; i < (1 << order); i++){		current->thread.fault_addr = (void *) addr;		if(__do_copy_to_user((void *) addr, &zero, 				     sizeof(zero),				     &current->thread.fault_addr,				     &current->thread.fault_catcher)){			if(!(mask & __GFP_WAIT)) return(NULL);			else break;		}		addr += PAGE_SIZE;	}	if(i == (1 << order)) return(page);	page = alloc_pages(mask, order);	goto again;}DECLARE_MUTEX(vm_reserved_sem);static struct list_head vm_reserved = LIST_HEAD_INIT(vm_reserved);/* Static structures, linked in to the list in early boot */static struct vm_reserved head = {	.list 		= LIST_HEAD_INIT(head.list),	.start 		= 0,	.end 		= 0xffffffff};static struct vm_reserved tail = {	.list 		= LIST_HEAD_INIT(tail.list),	.start 		= 0,	.end 		= 0xffffffff};void set_usable_vm(unsigned long start, unsigned long end){	list_add(&head.list, &vm_reserved);	list_add(&tail.list, &head.list);	head.end = start;	tail.start = end;}int reserve_vm(unsigned long start, unsigned long end, void *e)	       {	struct vm_reserved *entry = e, *reserved, *prev;	struct list_head *ele;	int err;	down(&vm_reserved_sem);	list_for_each(ele, &vm_reserved){		reserved = list_entry(ele, struct vm_reserved, list);		if(reserved->start >= end) goto found;	}	panic("Reserved vm out of range"); found:	prev = list_entry(ele->prev, struct vm_reserved, list);	if(prev->end > start)		panic("Can't reserve vm");	if(entry == NULL)		entry = kmalloc(sizeof(*entry), GFP_KERNEL);	if(entry == NULL){		printk("reserve_vm : Failed to allocate entry\n");		err = -ENOMEM;		goto out;	}	*entry = ((struct vm_reserved) 		{ .list 	= LIST_HEAD_INIT(entry->list),		  .start 	= start,		  .end 		= end });	list_add(&entry->list, &prev->list);	err = 0; out:	up(&vm_reserved_sem);	return(0);}unsigned long get_vm(unsigned long len){	struct vm_reserved *this, *next;	struct list_head *ele;	unsigned long start;	int err;		down(&vm_reserved_sem);	list_for_each(ele, &vm_reserved){		this = list_entry(ele, struct vm_reserved, list);		next = list_entry(ele->next, struct vm_reserved, list);		if((this->start < next->start) && 		   (this->end + len + PAGE_SIZE <= next->start))			goto found;	}	up(&vm_reserved_sem);	return(0); found:	up(&vm_reserved_sem);	start = (unsigned long) UML_ROUND_UP(this->end) + PAGE_SIZE;	err = reserve_vm(start, start + len, NULL);	if(err) return(0);	return(start);}int nregions(void){	return(NREGIONS);}void setup_range(int fd, char *driver, unsigned long start, unsigned long pfn,		 unsigned long len, int need_vm, struct mem_region *region, 		 void *reserved){	int i, cur;	do {		cur = min(len, (unsigned long) REGION_SIZE);		i = setup_one_range(fd, driver, start, pfn, cur, region);		region = regions[i];		if(need_vm && setup_region(region, reserved)){			kfree(region);			regions[i] = NULL;			return;		}		start += cur;		if(pfn != -1) pfn += cur;		len -= cur;	} while(len > 0);}struct iomem {	char *name;	int fd;	unsigned long size;};/* iomem regions can only be added on the command line at the moment.   * Locking will be needed when they can be added via mconsole. */struct iomem iomem_regions[NREGIONS] = { [ 0 ... NREGIONS - 1 ] =					 { .name  	= NULL,					   .fd  	= -1,					   .size 	= 0 } };int num_iomem_regions = 0;void add_iomem(char *name, int fd, unsigned long size){	if(num_iomem_regions == sizeof(iomem_regions)/sizeof(iomem_regions[0]))		return;	size = (size + PAGE_SIZE - 1) & PAGE_MASK;	iomem_regions[num_iomem_regions++] = 		((struct iomem) { .name 	= name,				  .fd 		= fd,				  .size 	= size } );}int setup_iomem(void){	struct iomem *iomem;	int i;	for(i = 0; i < num_iomem_regions; i++){		iomem = &iomem_regions[i];		setup_range(iomem->fd, iomem->name, -1, -1, iomem->size, 1, 			    NULL, NULL);	}	return(0);}__initcall(setup_iomem);#define PFN_UP(x)	(((x) + PAGE_SIZE-1) >> PAGE_SHIFT)#define PFN_DOWN(x)	((x) >> PAGE_SHIFT)/* Changed during early boot */static struct mem_region physmem_region;static struct vm_reserved physmem_reserved;void setup_physmem(unsigned long start, unsigned long reserve_end,		   unsigned long len){	struct mem_region *region = &physmem_region;	struct vm_reserved *reserved = &physmem_reserved;	unsigned long cur, pfn = 0;	int do_free = 1, bootmap_size;	do {		cur = min(len, (unsigned long) REGION_SIZE);		if(region == NULL) 			region = alloc_bootmem_low_pages(sizeof(*region));		if(reserved == NULL) 			reserved = alloc_bootmem_low_pages(sizeof(*reserved));		if((region == NULL) || (reserved == NULL))			panic("Couldn't allocate physmem region or vm "			      "reservation\n");		setup_range(-1, NULL, start, pfn, cur, 1, region, reserved);		if(do_free){			unsigned long reserve = reserve_end - start;			int pfn = PFN_UP(__pa(reserve_end));			int delta = (len - reserve) >> PAGE_SHIFT;			bootmap_size = init_bootmem(pfn, pfn + delta);			free_bootmem(__pa(reserve_end) + bootmap_size,				     cur - bootmap_size - reserve);			do_free = 0;		}		start += cur;		pfn += cur >> PAGE_SHIFT;		len -= cur;		region = NULL;		reserved = NULL;	} while(len > 0);}struct mem_region *phys_region(unsigned long phys){	unsigned int n = phys_region_index(phys);	if(regions[n] == NULL) 		panic("Physical address in uninitialized region");	return(regions[n]);}unsigned long phys_offset(unsigned long phys){	return(phys_addr(phys));}struct page *phys_mem_map(unsigned long phys){	return((struct page *) phys_region(phys)->mem_map);}struct page *pte_mem_map(pte_t pte){	return(phys_mem_map(pte_val(pte)));}struct mem_region *page_region(struct page *page, int *index_out){	int i;	struct mem_region *region;	struct page *map;	for(i = 0; i < NREGIONS; i++){		region = regions[i];		if(region == NULL) continue;		map = region->mem_map;		if((page >= map) && (page < &map[region->len >> PAGE_SHIFT])){			if(index_out != NULL) *index_out = i;			return(region);		}	}	panic("No region found for page");	return(NULL);}unsigned long page_to_pfn(struct page *page){	struct mem_region *region = page_region(page, NULL);	return(region->start_pfn + (page - (struct page *) region->mem_map));}struct mem_region *pfn_to_region(unsigned long pfn, int *index_out){	struct mem_region *region;	int i;	for(i = 0; i < NREGIONS; i++){		region = regions[i];		if(region == NULL)			continue;		if((region->start_pfn <= pfn) &&		   (region->start_pfn + (region->len >> PAGE_SHIFT) > pfn)){			if(index_out != NULL) 				*index_out = i;			return(region);		}	}	return(NULL);}struct page *pfn_to_page(unsigned long pfn){	struct mem_region *region = pfn_to_region(pfn, NULL);	struct page *mem_map = (struct page *) region->mem_map;	return(&mem_map[pfn - region->start_pfn]);}unsigned long phys_to_pfn(unsigned long p){	struct mem_region *region = regions[phys_region_index(p)];	return(region->start_pfn + (phys_addr(p) >> PAGE_SHIFT));}unsigned long pfn_to_phys(unsigned long pfn){	int n;	struct mem_region *region = pfn_to_region(pfn, &n);	return(mk_phys((pfn - region->start_pfn) << PAGE_SHIFT, n));}struct page *page_mem_map(struct page *page){	return((struct page *) page_region(page, NULL)->mem_map);}extern unsigned long region_pa(void *virt){	struct mem_region *region;	unsigned long addr = (unsigned long) virt;	int i;	for(i = 0; i < NREGIONS; i++){		region = regions[i];		if(region == NULL) continue;		if((region->start <= addr) && 		   (addr <= region->start + region->len))			return(mk_phys(addr - region->start, i));	}	panic("region_pa : no region for virtual address");	return(0);}extern void *region_va(unsigned long phys){	return((void *) (phys_region(phys)->start + phys_addr(phys)));}unsigned long page_to_phys(struct page *page){	int n;	struct mem_region *region = page_region(page, &n);	struct page *map = region->mem_map;	return(mk_phys((page - map) << PAGE_SHIFT, n));}struct page *phys_to_page(unsigned long phys){	struct page *mem_map;	mem_map = phys_mem_map(phys);	return(mem_map + (phys_offset(phys) >> PAGE_SHIFT));}static int setup_mem_maps(void){	struct mem_region *region;	int i;	for(i = 0; i < NREGIONS; i++){		region = regions[i];		if((region != NULL) && (region->fd > 0)) init_maps(region);	}	return(0);}__initcall(setup_mem_maps);/* * Allocate and free page tables. */pgd_t *pgd_alloc(struct mm_struct *mm){	pgd_t *pgd = (pgd_t *)__get_free_page(GFP_KERNEL);	if (pgd) {		memset(pgd, 0, USER_PTRS_PER_PGD * sizeof(pgd_t));		memcpy(pgd + USER_PTRS_PER_PGD, 		       swapper_pg_dir + USER_PTRS_PER_PGD, 		       (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t));	}	return pgd;}void pgd_free(pgd_t *pgd){	free_page((unsigned long) pgd);}pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address){	pte_t *pte;	pte = (pte_t *)__get_free_page(GFP_KERNEL|__GFP_REPEAT);	if (pte)		clear_page(pte);	return pte;}struct page *pte_alloc_one(struct mm_struct *mm, unsigned long address){	struct page *pte;   	pte = alloc_pages(GFP_KERNEL|__GFP_REPEAT, 0);	if (pte)		clear_highpage(pte);	return pte;}/* * Overrides for Emacs so that we follow Linus's tabbing style. * Emacs will notice this stuff at the end of the file and automatically * adjust the settings for this buffer only.  This must remain at the end * of the file. * --------------------------------------------------------------------------- * Local variables: * c-file-style: "linux" * End: */

⌨️ 快捷键说明

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