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