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

📄 slice.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * address space "slices" (meta-segments) support * * Copyright (C) 2007 Benjamin Herrenschmidt, IBM Corporation. * * Based on hugetlb implementation * * Copyright (C) 2003 David Gibson, IBM Corporation. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */#undef DEBUG#include <linux/kernel.h>#include <linux/mm.h>#include <linux/pagemap.h>#include <linux/err.h>#include <linux/spinlock.h>#include <linux/module.h>#include <asm/mman.h>#include <asm/mmu.h>#include <asm/spu.h>static DEFINE_SPINLOCK(slice_convert_lock);#ifdef DEBUGint _slice_debug = 1;static void slice_print_mask(const char *label, struct slice_mask mask){	char	*p, buf[16 + 3 + 16 + 1];	int	i;	if (!_slice_debug)		return;	p = buf;	for (i = 0; i < SLICE_NUM_LOW; i++)		*(p++) = (mask.low_slices & (1 << i)) ? '1' : '0';	*(p++) = ' ';	*(p++) = '-';	*(p++) = ' ';	for (i = 0; i < SLICE_NUM_HIGH; i++)		*(p++) = (mask.high_slices & (1 << i)) ? '1' : '0';	*(p++) = 0;	printk(KERN_DEBUG "%s:%s\n", label, buf);}#define slice_dbg(fmt...) do { if (_slice_debug) pr_debug(fmt); } while(0)#elsestatic void slice_print_mask(const char *label, struct slice_mask mask) {}#define slice_dbg(fmt...)#endifstatic struct slice_mask slice_range_to_mask(unsigned long start,					     unsigned long len){	unsigned long end = start + len - 1;	struct slice_mask ret = { 0, 0 };	if (start < SLICE_LOW_TOP) {		unsigned long mend = min(end, SLICE_LOW_TOP);		unsigned long mstart = min(start, SLICE_LOW_TOP);		ret.low_slices = (1u << (GET_LOW_SLICE_INDEX(mend) + 1))			- (1u << GET_LOW_SLICE_INDEX(mstart));	}	if ((start + len) > SLICE_LOW_TOP)		ret.high_slices = (1u << (GET_HIGH_SLICE_INDEX(end) + 1))			- (1u << GET_HIGH_SLICE_INDEX(start));	return ret;}static int slice_area_is_free(struct mm_struct *mm, unsigned long addr,			      unsigned long len){	struct vm_area_struct *vma;	if ((mm->task_size - len) < addr)		return 0;	vma = find_vma(mm, addr);	return (!vma || (addr + len) <= vma->vm_start);}static int slice_low_has_vma(struct mm_struct *mm, unsigned long slice){	return !slice_area_is_free(mm, slice << SLICE_LOW_SHIFT,				   1ul << SLICE_LOW_SHIFT);}static int slice_high_has_vma(struct mm_struct *mm, unsigned long slice){	unsigned long start = slice << SLICE_HIGH_SHIFT;	unsigned long end = start + (1ul << SLICE_HIGH_SHIFT);	/* Hack, so that each addresses is controlled by exactly one	 * of the high or low area bitmaps, the first high area starts	 * at 4GB, not 0 */	if (start == 0)		start = SLICE_LOW_TOP;	return !slice_area_is_free(mm, start, end - start);}static struct slice_mask slice_mask_for_free(struct mm_struct *mm){	struct slice_mask ret = { 0, 0 };	unsigned long i;	for (i = 0; i < SLICE_NUM_LOW; i++)		if (!slice_low_has_vma(mm, i))			ret.low_slices |= 1u << i;	if (mm->task_size <= SLICE_LOW_TOP)		return ret;	for (i = 0; i < SLICE_NUM_HIGH; i++)		if (!slice_high_has_vma(mm, i))			ret.high_slices |= 1u << i;	return ret;}static struct slice_mask slice_mask_for_size(struct mm_struct *mm, int psize){	struct slice_mask ret = { 0, 0 };	unsigned long i;	u64 psizes;	psizes = mm->context.low_slices_psize;	for (i = 0; i < SLICE_NUM_LOW; i++)		if (((psizes >> (i * 4)) & 0xf) == psize)			ret.low_slices |= 1u << i;	psizes = mm->context.high_slices_psize;	for (i = 0; i < SLICE_NUM_HIGH; i++)		if (((psizes >> (i * 4)) & 0xf) == psize)			ret.high_slices |= 1u << i;	return ret;}static int slice_check_fit(struct slice_mask mask, struct slice_mask available){	return (mask.low_slices & available.low_slices) == mask.low_slices &&		(mask.high_slices & available.high_slices) == mask.high_slices;}static void slice_flush_segments(void *parm){	struct mm_struct *mm = parm;	unsigned long flags;	if (mm != current->active_mm)		return;	/* update the paca copy of the context struct */	get_paca()->context = current->active_mm->context;	local_irq_save(flags);	slb_flush_and_rebolt();	local_irq_restore(flags);}static void slice_convert(struct mm_struct *mm, struct slice_mask mask, int psize){	/* Write the new slice psize bits */	u64 lpsizes, hpsizes;	unsigned long i, flags;	slice_dbg("slice_convert(mm=%p, psize=%d)\n", mm, psize);	slice_print_mask(" mask", mask);	/* We need to use a spinlock here to protect against	 * concurrent 64k -> 4k demotion ...	 */	spin_lock_irqsave(&slice_convert_lock, flags);	lpsizes = mm->context.low_slices_psize;	for (i = 0; i < SLICE_NUM_LOW; i++)		if (mask.low_slices & (1u << i))			lpsizes = (lpsizes & ~(0xful << (i * 4))) |				(((unsigned long)psize) << (i * 4));	hpsizes = mm->context.high_slices_psize;	for (i = 0; i < SLICE_NUM_HIGH; i++)		if (mask.high_slices & (1u << i))			hpsizes = (hpsizes & ~(0xful << (i * 4))) |				(((unsigned long)psize) << (i * 4));	mm->context.low_slices_psize = lpsizes;	mm->context.high_slices_psize = hpsizes;	slice_dbg(" lsps=%lx, hsps=%lx\n",		  mm->context.low_slices_psize,		  mm->context.high_slices_psize);	spin_unlock_irqrestore(&slice_convert_lock, flags);	mb();	/* XXX this is sub-optimal but will do for now */	on_each_cpu(slice_flush_segments, mm, 0, 1);#ifdef CONFIG_SPU_BASE	spu_flush_all_slbs(mm);#endif}static unsigned long slice_find_area_bottomup(struct mm_struct *mm,					      unsigned long len,					      struct slice_mask available,					      int psize, int use_cache){	struct vm_area_struct *vma;	unsigned long start_addr, addr;	struct slice_mask mask;	int pshift = max_t(int, mmu_psize_defs[psize].shift, PAGE_SHIFT);	if (use_cache) {		if (len <= mm->cached_hole_size) {			start_addr = addr = TASK_UNMAPPED_BASE;			mm->cached_hole_size = 0;		} else			start_addr = addr = mm->free_area_cache;	} else		start_addr = addr = TASK_UNMAPPED_BASE;full_search:	for (;;) {		addr = _ALIGN_UP(addr, 1ul << pshift);		if ((TASK_SIZE - len) < addr)			break;		vma = find_vma(mm, addr);		BUG_ON(vma && (addr >= vma->vm_end));		mask = slice_range_to_mask(addr, len);		if (!slice_check_fit(mask, available)) {			if (addr < SLICE_LOW_TOP)				addr = _ALIGN_UP(addr + 1,  1ul << SLICE_LOW_SHIFT);			else				addr = _ALIGN_UP(addr + 1,  1ul << SLICE_HIGH_SHIFT);			continue;		}		if (!vma || addr + len <= vma->vm_start) {			/*			 * Remember the place where we stopped the search:			 */			if (use_cache)				mm->free_area_cache = addr + len;			return addr;		}		if (use_cache && (addr + mm->cached_hole_size) < vma->vm_start)		        mm->cached_hole_size = vma->vm_start - addr;		addr = vma->vm_end;	}	/* Make sure we didn't miss any holes */	if (use_cache && start_addr != TASK_UNMAPPED_BASE) {		start_addr = addr = TASK_UNMAPPED_BASE;		mm->cached_hole_size = 0;		goto full_search;	}	return -ENOMEM;}static unsigned long slice_find_area_topdown(struct mm_struct *mm,					     unsigned long len,					     struct slice_mask available,					     int psize, int use_cache){	struct vm_area_struct *vma;	unsigned long addr;	struct slice_mask mask;	int pshift = max_t(int, mmu_psize_defs[psize].shift, PAGE_SHIFT);	/* check if free_area_cache is useful for us */	if (use_cache) {		if (len <= mm->cached_hole_size) {			mm->cached_hole_size = 0;			mm->free_area_cache = mm->mmap_base;		}		/* either no address requested or can't fit in requested		 * address hole		 */		addr = mm->free_area_cache;		/* make sure it can fit in the remaining address space */		if (addr > len) {			addr = _ALIGN_DOWN(addr - len, 1ul << pshift);			mask = slice_range_to_mask(addr, len);			if (slice_check_fit(mask, available) &&			    slice_area_is_free(mm, addr, len))					/* remember the address as a hint for					 * next time					 */					return (mm->free_area_cache = addr);		}	}	addr = mm->mmap_base;

⌨️ 快捷键说明

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