xref: /openbmc/linux/mm/vmalloc.c (revision 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2)
1*1da177e4SLinus Torvalds /*
2*1da177e4SLinus Torvalds  *  linux/mm/vmalloc.c
3*1da177e4SLinus Torvalds  *
4*1da177e4SLinus Torvalds  *  Copyright (C) 1993  Linus Torvalds
5*1da177e4SLinus Torvalds  *  Support of BIGMEM added by Gerhard Wichert, Siemens AG, July 1999
6*1da177e4SLinus Torvalds  *  SMP-safe vmalloc/vfree/ioremap, Tigran Aivazian <tigran@veritas.com>, May 2000
7*1da177e4SLinus Torvalds  *  Major rework to support vmap/vunmap, Christoph Hellwig, SGI, August 2002
8*1da177e4SLinus Torvalds  */
9*1da177e4SLinus Torvalds 
10*1da177e4SLinus Torvalds #include <linux/mm.h>
11*1da177e4SLinus Torvalds #include <linux/module.h>
12*1da177e4SLinus Torvalds #include <linux/highmem.h>
13*1da177e4SLinus Torvalds #include <linux/slab.h>
14*1da177e4SLinus Torvalds #include <linux/spinlock.h>
15*1da177e4SLinus Torvalds #include <linux/interrupt.h>
16*1da177e4SLinus Torvalds 
17*1da177e4SLinus Torvalds #include <linux/vmalloc.h>
18*1da177e4SLinus Torvalds 
19*1da177e4SLinus Torvalds #include <asm/uaccess.h>
20*1da177e4SLinus Torvalds #include <asm/tlbflush.h>
21*1da177e4SLinus Torvalds 
22*1da177e4SLinus Torvalds 
23*1da177e4SLinus Torvalds DEFINE_RWLOCK(vmlist_lock);
24*1da177e4SLinus Torvalds struct vm_struct *vmlist;
25*1da177e4SLinus Torvalds 
26*1da177e4SLinus Torvalds static void vunmap_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end)
27*1da177e4SLinus Torvalds {
28*1da177e4SLinus Torvalds 	pte_t *pte;
29*1da177e4SLinus Torvalds 
30*1da177e4SLinus Torvalds 	pte = pte_offset_kernel(pmd, addr);
31*1da177e4SLinus Torvalds 	do {
32*1da177e4SLinus Torvalds 		pte_t ptent = ptep_get_and_clear(&init_mm, addr, pte);
33*1da177e4SLinus Torvalds 		WARN_ON(!pte_none(ptent) && !pte_present(ptent));
34*1da177e4SLinus Torvalds 	} while (pte++, addr += PAGE_SIZE, addr != end);
35*1da177e4SLinus Torvalds }
36*1da177e4SLinus Torvalds 
37*1da177e4SLinus Torvalds static inline void vunmap_pmd_range(pud_t *pud, unsigned long addr,
38*1da177e4SLinus Torvalds 						unsigned long end)
39*1da177e4SLinus Torvalds {
40*1da177e4SLinus Torvalds 	pmd_t *pmd;
41*1da177e4SLinus Torvalds 	unsigned long next;
42*1da177e4SLinus Torvalds 
43*1da177e4SLinus Torvalds 	pmd = pmd_offset(pud, addr);
44*1da177e4SLinus Torvalds 	do {
45*1da177e4SLinus Torvalds 		next = pmd_addr_end(addr, end);
46*1da177e4SLinus Torvalds 		if (pmd_none_or_clear_bad(pmd))
47*1da177e4SLinus Torvalds 			continue;
48*1da177e4SLinus Torvalds 		vunmap_pte_range(pmd, addr, next);
49*1da177e4SLinus Torvalds 	} while (pmd++, addr = next, addr != end);
50*1da177e4SLinus Torvalds }
51*1da177e4SLinus Torvalds 
52*1da177e4SLinus Torvalds static inline void vunmap_pud_range(pgd_t *pgd, unsigned long addr,
53*1da177e4SLinus Torvalds 						unsigned long end)
54*1da177e4SLinus Torvalds {
55*1da177e4SLinus Torvalds 	pud_t *pud;
56*1da177e4SLinus Torvalds 	unsigned long next;
57*1da177e4SLinus Torvalds 
58*1da177e4SLinus Torvalds 	pud = pud_offset(pgd, addr);
59*1da177e4SLinus Torvalds 	do {
60*1da177e4SLinus Torvalds 		next = pud_addr_end(addr, end);
61*1da177e4SLinus Torvalds 		if (pud_none_or_clear_bad(pud))
62*1da177e4SLinus Torvalds 			continue;
63*1da177e4SLinus Torvalds 		vunmap_pmd_range(pud, addr, next);
64*1da177e4SLinus Torvalds 	} while (pud++, addr = next, addr != end);
65*1da177e4SLinus Torvalds }
66*1da177e4SLinus Torvalds 
67*1da177e4SLinus Torvalds void unmap_vm_area(struct vm_struct *area)
68*1da177e4SLinus Torvalds {
69*1da177e4SLinus Torvalds 	pgd_t *pgd;
70*1da177e4SLinus Torvalds 	unsigned long next;
71*1da177e4SLinus Torvalds 	unsigned long addr = (unsigned long) area->addr;
72*1da177e4SLinus Torvalds 	unsigned long end = addr + area->size;
73*1da177e4SLinus Torvalds 
74*1da177e4SLinus Torvalds 	BUG_ON(addr >= end);
75*1da177e4SLinus Torvalds 	pgd = pgd_offset_k(addr);
76*1da177e4SLinus Torvalds 	flush_cache_vunmap(addr, end);
77*1da177e4SLinus Torvalds 	do {
78*1da177e4SLinus Torvalds 		next = pgd_addr_end(addr, end);
79*1da177e4SLinus Torvalds 		if (pgd_none_or_clear_bad(pgd))
80*1da177e4SLinus Torvalds 			continue;
81*1da177e4SLinus Torvalds 		vunmap_pud_range(pgd, addr, next);
82*1da177e4SLinus Torvalds 	} while (pgd++, addr = next, addr != end);
83*1da177e4SLinus Torvalds 	flush_tlb_kernel_range((unsigned long) area->addr, end);
84*1da177e4SLinus Torvalds }
85*1da177e4SLinus Torvalds 
86*1da177e4SLinus Torvalds static int vmap_pte_range(pmd_t *pmd, unsigned long addr,
87*1da177e4SLinus Torvalds 			unsigned long end, pgprot_t prot, struct page ***pages)
88*1da177e4SLinus Torvalds {
89*1da177e4SLinus Torvalds 	pte_t *pte;
90*1da177e4SLinus Torvalds 
91*1da177e4SLinus Torvalds 	pte = pte_alloc_kernel(&init_mm, pmd, addr);
92*1da177e4SLinus Torvalds 	if (!pte)
93*1da177e4SLinus Torvalds 		return -ENOMEM;
94*1da177e4SLinus Torvalds 	do {
95*1da177e4SLinus Torvalds 		struct page *page = **pages;
96*1da177e4SLinus Torvalds 		WARN_ON(!pte_none(*pte));
97*1da177e4SLinus Torvalds 		if (!page)
98*1da177e4SLinus Torvalds 			return -ENOMEM;
99*1da177e4SLinus Torvalds 		set_pte_at(&init_mm, addr, pte, mk_pte(page, prot));
100*1da177e4SLinus Torvalds 		(*pages)++;
101*1da177e4SLinus Torvalds 	} while (pte++, addr += PAGE_SIZE, addr != end);
102*1da177e4SLinus Torvalds 	return 0;
103*1da177e4SLinus Torvalds }
104*1da177e4SLinus Torvalds 
105*1da177e4SLinus Torvalds static inline int vmap_pmd_range(pud_t *pud, unsigned long addr,
106*1da177e4SLinus Torvalds 			unsigned long end, pgprot_t prot, struct page ***pages)
107*1da177e4SLinus Torvalds {
108*1da177e4SLinus Torvalds 	pmd_t *pmd;
109*1da177e4SLinus Torvalds 	unsigned long next;
110*1da177e4SLinus Torvalds 
111*1da177e4SLinus Torvalds 	pmd = pmd_alloc(&init_mm, pud, addr);
112*1da177e4SLinus Torvalds 	if (!pmd)
113*1da177e4SLinus Torvalds 		return -ENOMEM;
114*1da177e4SLinus Torvalds 	do {
115*1da177e4SLinus Torvalds 		next = pmd_addr_end(addr, end);
116*1da177e4SLinus Torvalds 		if (vmap_pte_range(pmd, addr, next, prot, pages))
117*1da177e4SLinus Torvalds 			return -ENOMEM;
118*1da177e4SLinus Torvalds 	} while (pmd++, addr = next, addr != end);
119*1da177e4SLinus Torvalds 	return 0;
120*1da177e4SLinus Torvalds }
121*1da177e4SLinus Torvalds 
122*1da177e4SLinus Torvalds static inline int vmap_pud_range(pgd_t *pgd, unsigned long addr,
123*1da177e4SLinus Torvalds 			unsigned long end, pgprot_t prot, struct page ***pages)
124*1da177e4SLinus Torvalds {
125*1da177e4SLinus Torvalds 	pud_t *pud;
126*1da177e4SLinus Torvalds 	unsigned long next;
127*1da177e4SLinus Torvalds 
128*1da177e4SLinus Torvalds 	pud = pud_alloc(&init_mm, pgd, addr);
129*1da177e4SLinus Torvalds 	if (!pud)
130*1da177e4SLinus Torvalds 		return -ENOMEM;
131*1da177e4SLinus Torvalds 	do {
132*1da177e4SLinus Torvalds 		next = pud_addr_end(addr, end);
133*1da177e4SLinus Torvalds 		if (vmap_pmd_range(pud, addr, next, prot, pages))
134*1da177e4SLinus Torvalds 			return -ENOMEM;
135*1da177e4SLinus Torvalds 	} while (pud++, addr = next, addr != end);
136*1da177e4SLinus Torvalds 	return 0;
137*1da177e4SLinus Torvalds }
138*1da177e4SLinus Torvalds 
139*1da177e4SLinus Torvalds int map_vm_area(struct vm_struct *area, pgprot_t prot, struct page ***pages)
140*1da177e4SLinus Torvalds {
141*1da177e4SLinus Torvalds 	pgd_t *pgd;
142*1da177e4SLinus Torvalds 	unsigned long next;
143*1da177e4SLinus Torvalds 	unsigned long addr = (unsigned long) area->addr;
144*1da177e4SLinus Torvalds 	unsigned long end = addr + area->size - PAGE_SIZE;
145*1da177e4SLinus Torvalds 	int err;
146*1da177e4SLinus Torvalds 
147*1da177e4SLinus Torvalds 	BUG_ON(addr >= end);
148*1da177e4SLinus Torvalds 	pgd = pgd_offset_k(addr);
149*1da177e4SLinus Torvalds 	spin_lock(&init_mm.page_table_lock);
150*1da177e4SLinus Torvalds 	do {
151*1da177e4SLinus Torvalds 		next = pgd_addr_end(addr, end);
152*1da177e4SLinus Torvalds 		err = vmap_pud_range(pgd, addr, next, prot, pages);
153*1da177e4SLinus Torvalds 		if (err)
154*1da177e4SLinus Torvalds 			break;
155*1da177e4SLinus Torvalds 	} while (pgd++, addr = next, addr != end);
156*1da177e4SLinus Torvalds 	spin_unlock(&init_mm.page_table_lock);
157*1da177e4SLinus Torvalds 	flush_cache_vmap((unsigned long) area->addr, end);
158*1da177e4SLinus Torvalds 	return err;
159*1da177e4SLinus Torvalds }
160*1da177e4SLinus Torvalds 
161*1da177e4SLinus Torvalds #define IOREMAP_MAX_ORDER	(7 + PAGE_SHIFT)	/* 128 pages */
162*1da177e4SLinus Torvalds 
163*1da177e4SLinus Torvalds struct vm_struct *__get_vm_area(unsigned long size, unsigned long flags,
164*1da177e4SLinus Torvalds 				unsigned long start, unsigned long end)
165*1da177e4SLinus Torvalds {
166*1da177e4SLinus Torvalds 	struct vm_struct **p, *tmp, *area;
167*1da177e4SLinus Torvalds 	unsigned long align = 1;
168*1da177e4SLinus Torvalds 	unsigned long addr;
169*1da177e4SLinus Torvalds 
170*1da177e4SLinus Torvalds 	if (flags & VM_IOREMAP) {
171*1da177e4SLinus Torvalds 		int bit = fls(size);
172*1da177e4SLinus Torvalds 
173*1da177e4SLinus Torvalds 		if (bit > IOREMAP_MAX_ORDER)
174*1da177e4SLinus Torvalds 			bit = IOREMAP_MAX_ORDER;
175*1da177e4SLinus Torvalds 		else if (bit < PAGE_SHIFT)
176*1da177e4SLinus Torvalds 			bit = PAGE_SHIFT;
177*1da177e4SLinus Torvalds 
178*1da177e4SLinus Torvalds 		align = 1ul << bit;
179*1da177e4SLinus Torvalds 	}
180*1da177e4SLinus Torvalds 	addr = ALIGN(start, align);
181*1da177e4SLinus Torvalds 	size = PAGE_ALIGN(size);
182*1da177e4SLinus Torvalds 
183*1da177e4SLinus Torvalds 	area = kmalloc(sizeof(*area), GFP_KERNEL);
184*1da177e4SLinus Torvalds 	if (unlikely(!area))
185*1da177e4SLinus Torvalds 		return NULL;
186*1da177e4SLinus Torvalds 
187*1da177e4SLinus Torvalds 	if (unlikely(!size)) {
188*1da177e4SLinus Torvalds 		kfree (area);
189*1da177e4SLinus Torvalds 		return NULL;
190*1da177e4SLinus Torvalds 	}
191*1da177e4SLinus Torvalds 
192*1da177e4SLinus Torvalds 	/*
193*1da177e4SLinus Torvalds 	 * We always allocate a guard page.
194*1da177e4SLinus Torvalds 	 */
195*1da177e4SLinus Torvalds 	size += PAGE_SIZE;
196*1da177e4SLinus Torvalds 
197*1da177e4SLinus Torvalds 	write_lock(&vmlist_lock);
198*1da177e4SLinus Torvalds 	for (p = &vmlist; (tmp = *p) != NULL ;p = &tmp->next) {
199*1da177e4SLinus Torvalds 		if ((unsigned long)tmp->addr < addr) {
200*1da177e4SLinus Torvalds 			if((unsigned long)tmp->addr + tmp->size >= addr)
201*1da177e4SLinus Torvalds 				addr = ALIGN(tmp->size +
202*1da177e4SLinus Torvalds 					     (unsigned long)tmp->addr, align);
203*1da177e4SLinus Torvalds 			continue;
204*1da177e4SLinus Torvalds 		}
205*1da177e4SLinus Torvalds 		if ((size + addr) < addr)
206*1da177e4SLinus Torvalds 			goto out;
207*1da177e4SLinus Torvalds 		if (size + addr <= (unsigned long)tmp->addr)
208*1da177e4SLinus Torvalds 			goto found;
209*1da177e4SLinus Torvalds 		addr = ALIGN(tmp->size + (unsigned long)tmp->addr, align);
210*1da177e4SLinus Torvalds 		if (addr > end - size)
211*1da177e4SLinus Torvalds 			goto out;
212*1da177e4SLinus Torvalds 	}
213*1da177e4SLinus Torvalds 
214*1da177e4SLinus Torvalds found:
215*1da177e4SLinus Torvalds 	area->next = *p;
216*1da177e4SLinus Torvalds 	*p = area;
217*1da177e4SLinus Torvalds 
218*1da177e4SLinus Torvalds 	area->flags = flags;
219*1da177e4SLinus Torvalds 	area->addr = (void *)addr;
220*1da177e4SLinus Torvalds 	area->size = size;
221*1da177e4SLinus Torvalds 	area->pages = NULL;
222*1da177e4SLinus Torvalds 	area->nr_pages = 0;
223*1da177e4SLinus Torvalds 	area->phys_addr = 0;
224*1da177e4SLinus Torvalds 	write_unlock(&vmlist_lock);
225*1da177e4SLinus Torvalds 
226*1da177e4SLinus Torvalds 	return area;
227*1da177e4SLinus Torvalds 
228*1da177e4SLinus Torvalds out:
229*1da177e4SLinus Torvalds 	write_unlock(&vmlist_lock);
230*1da177e4SLinus Torvalds 	kfree(area);
231*1da177e4SLinus Torvalds 	if (printk_ratelimit())
232*1da177e4SLinus Torvalds 		printk(KERN_WARNING "allocation failed: out of vmalloc space - use vmalloc=<size> to increase size.\n");
233*1da177e4SLinus Torvalds 	return NULL;
234*1da177e4SLinus Torvalds }
235*1da177e4SLinus Torvalds 
236*1da177e4SLinus Torvalds /**
237*1da177e4SLinus Torvalds  *	get_vm_area  -  reserve a contingous kernel virtual area
238*1da177e4SLinus Torvalds  *
239*1da177e4SLinus Torvalds  *	@size:		size of the area
240*1da177e4SLinus Torvalds  *	@flags:		%VM_IOREMAP for I/O mappings or VM_ALLOC
241*1da177e4SLinus Torvalds  *
242*1da177e4SLinus Torvalds  *	Search an area of @size in the kernel virtual mapping area,
243*1da177e4SLinus Torvalds  *	and reserved it for out purposes.  Returns the area descriptor
244*1da177e4SLinus Torvalds  *	on success or %NULL on failure.
245*1da177e4SLinus Torvalds  */
246*1da177e4SLinus Torvalds struct vm_struct *get_vm_area(unsigned long size, unsigned long flags)
247*1da177e4SLinus Torvalds {
248*1da177e4SLinus Torvalds 	return __get_vm_area(size, flags, VMALLOC_START, VMALLOC_END);
249*1da177e4SLinus Torvalds }
250*1da177e4SLinus Torvalds 
251*1da177e4SLinus Torvalds /**
252*1da177e4SLinus Torvalds  *	remove_vm_area  -  find and remove a contingous kernel virtual area
253*1da177e4SLinus Torvalds  *
254*1da177e4SLinus Torvalds  *	@addr:		base address
255*1da177e4SLinus Torvalds  *
256*1da177e4SLinus Torvalds  *	Search for the kernel VM area starting at @addr, and remove it.
257*1da177e4SLinus Torvalds  *	This function returns the found VM area, but using it is NOT safe
258*1da177e4SLinus Torvalds  *	on SMP machines.
259*1da177e4SLinus Torvalds  */
260*1da177e4SLinus Torvalds struct vm_struct *remove_vm_area(void *addr)
261*1da177e4SLinus Torvalds {
262*1da177e4SLinus Torvalds 	struct vm_struct **p, *tmp;
263*1da177e4SLinus Torvalds 
264*1da177e4SLinus Torvalds 	write_lock(&vmlist_lock);
265*1da177e4SLinus Torvalds 	for (p = &vmlist ; (tmp = *p) != NULL ;p = &tmp->next) {
266*1da177e4SLinus Torvalds 		 if (tmp->addr == addr)
267*1da177e4SLinus Torvalds 			 goto found;
268*1da177e4SLinus Torvalds 	}
269*1da177e4SLinus Torvalds 	write_unlock(&vmlist_lock);
270*1da177e4SLinus Torvalds 	return NULL;
271*1da177e4SLinus Torvalds 
272*1da177e4SLinus Torvalds found:
273*1da177e4SLinus Torvalds 	unmap_vm_area(tmp);
274*1da177e4SLinus Torvalds 	*p = tmp->next;
275*1da177e4SLinus Torvalds 	write_unlock(&vmlist_lock);
276*1da177e4SLinus Torvalds 
277*1da177e4SLinus Torvalds 	/*
278*1da177e4SLinus Torvalds 	 * Remove the guard page.
279*1da177e4SLinus Torvalds 	 */
280*1da177e4SLinus Torvalds 	tmp->size -= PAGE_SIZE;
281*1da177e4SLinus Torvalds 	return tmp;
282*1da177e4SLinus Torvalds }
283*1da177e4SLinus Torvalds 
284*1da177e4SLinus Torvalds void __vunmap(void *addr, int deallocate_pages)
285*1da177e4SLinus Torvalds {
286*1da177e4SLinus Torvalds 	struct vm_struct *area;
287*1da177e4SLinus Torvalds 
288*1da177e4SLinus Torvalds 	if (!addr)
289*1da177e4SLinus Torvalds 		return;
290*1da177e4SLinus Torvalds 
291*1da177e4SLinus Torvalds 	if ((PAGE_SIZE-1) & (unsigned long)addr) {
292*1da177e4SLinus Torvalds 		printk(KERN_ERR "Trying to vfree() bad address (%p)\n", addr);
293*1da177e4SLinus Torvalds 		WARN_ON(1);
294*1da177e4SLinus Torvalds 		return;
295*1da177e4SLinus Torvalds 	}
296*1da177e4SLinus Torvalds 
297*1da177e4SLinus Torvalds 	area = remove_vm_area(addr);
298*1da177e4SLinus Torvalds 	if (unlikely(!area)) {
299*1da177e4SLinus Torvalds 		printk(KERN_ERR "Trying to vfree() nonexistent vm area (%p)\n",
300*1da177e4SLinus Torvalds 				addr);
301*1da177e4SLinus Torvalds 		WARN_ON(1);
302*1da177e4SLinus Torvalds 		return;
303*1da177e4SLinus Torvalds 	}
304*1da177e4SLinus Torvalds 
305*1da177e4SLinus Torvalds 	if (deallocate_pages) {
306*1da177e4SLinus Torvalds 		int i;
307*1da177e4SLinus Torvalds 
308*1da177e4SLinus Torvalds 		for (i = 0; i < area->nr_pages; i++) {
309*1da177e4SLinus Torvalds 			if (unlikely(!area->pages[i]))
310*1da177e4SLinus Torvalds 				BUG();
311*1da177e4SLinus Torvalds 			__free_page(area->pages[i]);
312*1da177e4SLinus Torvalds 		}
313*1da177e4SLinus Torvalds 
314*1da177e4SLinus Torvalds 		if (area->nr_pages > PAGE_SIZE/sizeof(struct page *))
315*1da177e4SLinus Torvalds 			vfree(area->pages);
316*1da177e4SLinus Torvalds 		else
317*1da177e4SLinus Torvalds 			kfree(area->pages);
318*1da177e4SLinus Torvalds 	}
319*1da177e4SLinus Torvalds 
320*1da177e4SLinus Torvalds 	kfree(area);
321*1da177e4SLinus Torvalds 	return;
322*1da177e4SLinus Torvalds }
323*1da177e4SLinus Torvalds 
324*1da177e4SLinus Torvalds /**
325*1da177e4SLinus Torvalds  *	vfree  -  release memory allocated by vmalloc()
326*1da177e4SLinus Torvalds  *
327*1da177e4SLinus Torvalds  *	@addr:		memory base address
328*1da177e4SLinus Torvalds  *
329*1da177e4SLinus Torvalds  *	Free the virtually contiguous memory area starting at @addr, as
330*1da177e4SLinus Torvalds  *	obtained from vmalloc(), vmalloc_32() or __vmalloc().
331*1da177e4SLinus Torvalds  *
332*1da177e4SLinus Torvalds  *	May not be called in interrupt context.
333*1da177e4SLinus Torvalds  */
334*1da177e4SLinus Torvalds void vfree(void *addr)
335*1da177e4SLinus Torvalds {
336*1da177e4SLinus Torvalds 	BUG_ON(in_interrupt());
337*1da177e4SLinus Torvalds 	__vunmap(addr, 1);
338*1da177e4SLinus Torvalds }
339*1da177e4SLinus Torvalds 
340*1da177e4SLinus Torvalds EXPORT_SYMBOL(vfree);
341*1da177e4SLinus Torvalds 
342*1da177e4SLinus Torvalds /**
343*1da177e4SLinus Torvalds  *	vunmap  -  release virtual mapping obtained by vmap()
344*1da177e4SLinus Torvalds  *
345*1da177e4SLinus Torvalds  *	@addr:		memory base address
346*1da177e4SLinus Torvalds  *
347*1da177e4SLinus Torvalds  *	Free the virtually contiguous memory area starting at @addr,
348*1da177e4SLinus Torvalds  *	which was created from the page array passed to vmap().
349*1da177e4SLinus Torvalds  *
350*1da177e4SLinus Torvalds  *	May not be called in interrupt context.
351*1da177e4SLinus Torvalds  */
352*1da177e4SLinus Torvalds void vunmap(void *addr)
353*1da177e4SLinus Torvalds {
354*1da177e4SLinus Torvalds 	BUG_ON(in_interrupt());
355*1da177e4SLinus Torvalds 	__vunmap(addr, 0);
356*1da177e4SLinus Torvalds }
357*1da177e4SLinus Torvalds 
358*1da177e4SLinus Torvalds EXPORT_SYMBOL(vunmap);
359*1da177e4SLinus Torvalds 
360*1da177e4SLinus Torvalds /**
361*1da177e4SLinus Torvalds  *	vmap  -  map an array of pages into virtually contiguous space
362*1da177e4SLinus Torvalds  *
363*1da177e4SLinus Torvalds  *	@pages:		array of page pointers
364*1da177e4SLinus Torvalds  *	@count:		number of pages to map
365*1da177e4SLinus Torvalds  *	@flags:		vm_area->flags
366*1da177e4SLinus Torvalds  *	@prot:		page protection for the mapping
367*1da177e4SLinus Torvalds  *
368*1da177e4SLinus Torvalds  *	Maps @count pages from @pages into contiguous kernel virtual
369*1da177e4SLinus Torvalds  *	space.
370*1da177e4SLinus Torvalds  */
371*1da177e4SLinus Torvalds void *vmap(struct page **pages, unsigned int count,
372*1da177e4SLinus Torvalds 		unsigned long flags, pgprot_t prot)
373*1da177e4SLinus Torvalds {
374*1da177e4SLinus Torvalds 	struct vm_struct *area;
375*1da177e4SLinus Torvalds 
376*1da177e4SLinus Torvalds 	if (count > num_physpages)
377*1da177e4SLinus Torvalds 		return NULL;
378*1da177e4SLinus Torvalds 
379*1da177e4SLinus Torvalds 	area = get_vm_area((count << PAGE_SHIFT), flags);
380*1da177e4SLinus Torvalds 	if (!area)
381*1da177e4SLinus Torvalds 		return NULL;
382*1da177e4SLinus Torvalds 	if (map_vm_area(area, prot, &pages)) {
383*1da177e4SLinus Torvalds 		vunmap(area->addr);
384*1da177e4SLinus Torvalds 		return NULL;
385*1da177e4SLinus Torvalds 	}
386*1da177e4SLinus Torvalds 
387*1da177e4SLinus Torvalds 	return area->addr;
388*1da177e4SLinus Torvalds }
389*1da177e4SLinus Torvalds 
390*1da177e4SLinus Torvalds EXPORT_SYMBOL(vmap);
391*1da177e4SLinus Torvalds 
392*1da177e4SLinus Torvalds void *__vmalloc_area(struct vm_struct *area, unsigned int __nocast gfp_mask, pgprot_t prot)
393*1da177e4SLinus Torvalds {
394*1da177e4SLinus Torvalds 	struct page **pages;
395*1da177e4SLinus Torvalds 	unsigned int nr_pages, array_size, i;
396*1da177e4SLinus Torvalds 
397*1da177e4SLinus Torvalds 	nr_pages = (area->size - PAGE_SIZE) >> PAGE_SHIFT;
398*1da177e4SLinus Torvalds 	array_size = (nr_pages * sizeof(struct page *));
399*1da177e4SLinus Torvalds 
400*1da177e4SLinus Torvalds 	area->nr_pages = nr_pages;
401*1da177e4SLinus Torvalds 	/* Please note that the recursion is strictly bounded. */
402*1da177e4SLinus Torvalds 	if (array_size > PAGE_SIZE)
403*1da177e4SLinus Torvalds 		pages = __vmalloc(array_size, gfp_mask, PAGE_KERNEL);
404*1da177e4SLinus Torvalds 	else
405*1da177e4SLinus Torvalds 		pages = kmalloc(array_size, (gfp_mask & ~__GFP_HIGHMEM));
406*1da177e4SLinus Torvalds 	area->pages = pages;
407*1da177e4SLinus Torvalds 	if (!area->pages) {
408*1da177e4SLinus Torvalds 		remove_vm_area(area->addr);
409*1da177e4SLinus Torvalds 		kfree(area);
410*1da177e4SLinus Torvalds 		return NULL;
411*1da177e4SLinus Torvalds 	}
412*1da177e4SLinus Torvalds 	memset(area->pages, 0, array_size);
413*1da177e4SLinus Torvalds 
414*1da177e4SLinus Torvalds 	for (i = 0; i < area->nr_pages; i++) {
415*1da177e4SLinus Torvalds 		area->pages[i] = alloc_page(gfp_mask);
416*1da177e4SLinus Torvalds 		if (unlikely(!area->pages[i])) {
417*1da177e4SLinus Torvalds 			/* Successfully allocated i pages, free them in __vunmap() */
418*1da177e4SLinus Torvalds 			area->nr_pages = i;
419*1da177e4SLinus Torvalds 			goto fail;
420*1da177e4SLinus Torvalds 		}
421*1da177e4SLinus Torvalds 	}
422*1da177e4SLinus Torvalds 
423*1da177e4SLinus Torvalds 	if (map_vm_area(area, prot, &pages))
424*1da177e4SLinus Torvalds 		goto fail;
425*1da177e4SLinus Torvalds 	return area->addr;
426*1da177e4SLinus Torvalds 
427*1da177e4SLinus Torvalds fail:
428*1da177e4SLinus Torvalds 	vfree(area->addr);
429*1da177e4SLinus Torvalds 	return NULL;
430*1da177e4SLinus Torvalds }
431*1da177e4SLinus Torvalds 
432*1da177e4SLinus Torvalds /**
433*1da177e4SLinus Torvalds  *	__vmalloc  -  allocate virtually contiguous memory
434*1da177e4SLinus Torvalds  *
435*1da177e4SLinus Torvalds  *	@size:		allocation size
436*1da177e4SLinus Torvalds  *	@gfp_mask:	flags for the page level allocator
437*1da177e4SLinus Torvalds  *	@prot:		protection mask for the allocated pages
438*1da177e4SLinus Torvalds  *
439*1da177e4SLinus Torvalds  *	Allocate enough pages to cover @size from the page level
440*1da177e4SLinus Torvalds  *	allocator with @gfp_mask flags.  Map them into contiguous
441*1da177e4SLinus Torvalds  *	kernel virtual space, using a pagetable protection of @prot.
442*1da177e4SLinus Torvalds  */
443*1da177e4SLinus Torvalds void *__vmalloc(unsigned long size, unsigned int __nocast gfp_mask, pgprot_t prot)
444*1da177e4SLinus Torvalds {
445*1da177e4SLinus Torvalds 	struct vm_struct *area;
446*1da177e4SLinus Torvalds 
447*1da177e4SLinus Torvalds 	size = PAGE_ALIGN(size);
448*1da177e4SLinus Torvalds 	if (!size || (size >> PAGE_SHIFT) > num_physpages)
449*1da177e4SLinus Torvalds 		return NULL;
450*1da177e4SLinus Torvalds 
451*1da177e4SLinus Torvalds 	area = get_vm_area(size, VM_ALLOC);
452*1da177e4SLinus Torvalds 	if (!area)
453*1da177e4SLinus Torvalds 		return NULL;
454*1da177e4SLinus Torvalds 
455*1da177e4SLinus Torvalds 	return __vmalloc_area(area, gfp_mask, prot);
456*1da177e4SLinus Torvalds }
457*1da177e4SLinus Torvalds 
458*1da177e4SLinus Torvalds EXPORT_SYMBOL(__vmalloc);
459*1da177e4SLinus Torvalds 
460*1da177e4SLinus Torvalds /**
461*1da177e4SLinus Torvalds  *	vmalloc  -  allocate virtually contiguous memory
462*1da177e4SLinus Torvalds  *
463*1da177e4SLinus Torvalds  *	@size:		allocation size
464*1da177e4SLinus Torvalds  *
465*1da177e4SLinus Torvalds  *	Allocate enough pages to cover @size from the page level
466*1da177e4SLinus Torvalds  *	allocator and map them into contiguous kernel virtual space.
467*1da177e4SLinus Torvalds  *
468*1da177e4SLinus Torvalds  *	For tight cotrol over page level allocator and protection flags
469*1da177e4SLinus Torvalds  *	use __vmalloc() instead.
470*1da177e4SLinus Torvalds  */
471*1da177e4SLinus Torvalds void *vmalloc(unsigned long size)
472*1da177e4SLinus Torvalds {
473*1da177e4SLinus Torvalds        return __vmalloc(size, GFP_KERNEL | __GFP_HIGHMEM, PAGE_KERNEL);
474*1da177e4SLinus Torvalds }
475*1da177e4SLinus Torvalds 
476*1da177e4SLinus Torvalds EXPORT_SYMBOL(vmalloc);
477*1da177e4SLinus Torvalds 
478*1da177e4SLinus Torvalds /**
479*1da177e4SLinus Torvalds  *	vmalloc_exec  -  allocate virtually contiguous, executable memory
480*1da177e4SLinus Torvalds  *
481*1da177e4SLinus Torvalds  *	@size:		allocation size
482*1da177e4SLinus Torvalds  *
483*1da177e4SLinus Torvalds  *	Kernel-internal function to allocate enough pages to cover @size
484*1da177e4SLinus Torvalds  *	the page level allocator and map them into contiguous and
485*1da177e4SLinus Torvalds  *	executable kernel virtual space.
486*1da177e4SLinus Torvalds  *
487*1da177e4SLinus Torvalds  *	For tight cotrol over page level allocator and protection flags
488*1da177e4SLinus Torvalds  *	use __vmalloc() instead.
489*1da177e4SLinus Torvalds  */
490*1da177e4SLinus Torvalds 
491*1da177e4SLinus Torvalds #ifndef PAGE_KERNEL_EXEC
492*1da177e4SLinus Torvalds # define PAGE_KERNEL_EXEC PAGE_KERNEL
493*1da177e4SLinus Torvalds #endif
494*1da177e4SLinus Torvalds 
495*1da177e4SLinus Torvalds void *vmalloc_exec(unsigned long size)
496*1da177e4SLinus Torvalds {
497*1da177e4SLinus Torvalds 	return __vmalloc(size, GFP_KERNEL | __GFP_HIGHMEM, PAGE_KERNEL_EXEC);
498*1da177e4SLinus Torvalds }
499*1da177e4SLinus Torvalds 
500*1da177e4SLinus Torvalds /**
501*1da177e4SLinus Torvalds  *	vmalloc_32  -  allocate virtually contiguous memory (32bit addressable)
502*1da177e4SLinus Torvalds  *
503*1da177e4SLinus Torvalds  *	@size:		allocation size
504*1da177e4SLinus Torvalds  *
505*1da177e4SLinus Torvalds  *	Allocate enough 32bit PA addressable pages to cover @size from the
506*1da177e4SLinus Torvalds  *	page level allocator and map them into contiguous kernel virtual space.
507*1da177e4SLinus Torvalds  */
508*1da177e4SLinus Torvalds void *vmalloc_32(unsigned long size)
509*1da177e4SLinus Torvalds {
510*1da177e4SLinus Torvalds 	return __vmalloc(size, GFP_KERNEL, PAGE_KERNEL);
511*1da177e4SLinus Torvalds }
512*1da177e4SLinus Torvalds 
513*1da177e4SLinus Torvalds EXPORT_SYMBOL(vmalloc_32);
514*1da177e4SLinus Torvalds 
515*1da177e4SLinus Torvalds long vread(char *buf, char *addr, unsigned long count)
516*1da177e4SLinus Torvalds {
517*1da177e4SLinus Torvalds 	struct vm_struct *tmp;
518*1da177e4SLinus Torvalds 	char *vaddr, *buf_start = buf;
519*1da177e4SLinus Torvalds 	unsigned long n;
520*1da177e4SLinus Torvalds 
521*1da177e4SLinus Torvalds 	/* Don't allow overflow */
522*1da177e4SLinus Torvalds 	if ((unsigned long) addr + count < count)
523*1da177e4SLinus Torvalds 		count = -(unsigned long) addr;
524*1da177e4SLinus Torvalds 
525*1da177e4SLinus Torvalds 	read_lock(&vmlist_lock);
526*1da177e4SLinus Torvalds 	for (tmp = vmlist; tmp; tmp = tmp->next) {
527*1da177e4SLinus Torvalds 		vaddr = (char *) tmp->addr;
528*1da177e4SLinus Torvalds 		if (addr >= vaddr + tmp->size - PAGE_SIZE)
529*1da177e4SLinus Torvalds 			continue;
530*1da177e4SLinus Torvalds 		while (addr < vaddr) {
531*1da177e4SLinus Torvalds 			if (count == 0)
532*1da177e4SLinus Torvalds 				goto finished;
533*1da177e4SLinus Torvalds 			*buf = '\0';
534*1da177e4SLinus Torvalds 			buf++;
535*1da177e4SLinus Torvalds 			addr++;
536*1da177e4SLinus Torvalds 			count--;
537*1da177e4SLinus Torvalds 		}
538*1da177e4SLinus Torvalds 		n = vaddr + tmp->size - PAGE_SIZE - addr;
539*1da177e4SLinus Torvalds 		do {
540*1da177e4SLinus Torvalds 			if (count == 0)
541*1da177e4SLinus Torvalds 				goto finished;
542*1da177e4SLinus Torvalds 			*buf = *addr;
543*1da177e4SLinus Torvalds 			buf++;
544*1da177e4SLinus Torvalds 			addr++;
545*1da177e4SLinus Torvalds 			count--;
546*1da177e4SLinus Torvalds 		} while (--n > 0);
547*1da177e4SLinus Torvalds 	}
548*1da177e4SLinus Torvalds finished:
549*1da177e4SLinus Torvalds 	read_unlock(&vmlist_lock);
550*1da177e4SLinus Torvalds 	return buf - buf_start;
551*1da177e4SLinus Torvalds }
552*1da177e4SLinus Torvalds 
553*1da177e4SLinus Torvalds long vwrite(char *buf, char *addr, unsigned long count)
554*1da177e4SLinus Torvalds {
555*1da177e4SLinus Torvalds 	struct vm_struct *tmp;
556*1da177e4SLinus Torvalds 	char *vaddr, *buf_start = buf;
557*1da177e4SLinus Torvalds 	unsigned long n;
558*1da177e4SLinus Torvalds 
559*1da177e4SLinus Torvalds 	/* Don't allow overflow */
560*1da177e4SLinus Torvalds 	if ((unsigned long) addr + count < count)
561*1da177e4SLinus Torvalds 		count = -(unsigned long) addr;
562*1da177e4SLinus Torvalds 
563*1da177e4SLinus Torvalds 	read_lock(&vmlist_lock);
564*1da177e4SLinus Torvalds 	for (tmp = vmlist; tmp; tmp = tmp->next) {
565*1da177e4SLinus Torvalds 		vaddr = (char *) tmp->addr;
566*1da177e4SLinus Torvalds 		if (addr >= vaddr + tmp->size - PAGE_SIZE)
567*1da177e4SLinus Torvalds 			continue;
568*1da177e4SLinus Torvalds 		while (addr < vaddr) {
569*1da177e4SLinus Torvalds 			if (count == 0)
570*1da177e4SLinus Torvalds 				goto finished;
571*1da177e4SLinus Torvalds 			buf++;
572*1da177e4SLinus Torvalds 			addr++;
573*1da177e4SLinus Torvalds 			count--;
574*1da177e4SLinus Torvalds 		}
575*1da177e4SLinus Torvalds 		n = vaddr + tmp->size - PAGE_SIZE - addr;
576*1da177e4SLinus Torvalds 		do {
577*1da177e4SLinus Torvalds 			if (count == 0)
578*1da177e4SLinus Torvalds 				goto finished;
579*1da177e4SLinus Torvalds 			*addr = *buf;
580*1da177e4SLinus Torvalds 			buf++;
581*1da177e4SLinus Torvalds 			addr++;
582*1da177e4SLinus Torvalds 			count--;
583*1da177e4SLinus Torvalds 		} while (--n > 0);
584*1da177e4SLinus Torvalds 	}
585*1da177e4SLinus Torvalds finished:
586*1da177e4SLinus Torvalds 	read_unlock(&vmlist_lock);
587*1da177e4SLinus Torvalds 	return buf - buf_start;
588*1da177e4SLinus Torvalds }
589