home *** CD-ROM | disk | FTP | other *** search
/ Whiteline: Alpha / Whiteline Alpha.iso / linux / atari / source / source.lzh / atari-linux-0.01pl3 / mm / vmalloc.c < prev   
Encoding:
C/C++ Source or Header  |  1994-06-05  |  6.5 KB  |  295 lines

  1. /*
  2.  *  linux/mm/vmalloc.c
  3.  *
  4.  *  Copyright (C) 1993  Linus Torvalds
  5.  */
  6.  
  7. #include <asm/system.h>
  8. #include <linux/config.h>
  9.  
  10. #include <linux/signal.h>
  11. #include <linux/sched.h>
  12. #include <linux/head.h>
  13. #include <linux/kernel.h>
  14. #include <linux/errno.h>
  15. #include <linux/types.h>
  16. #include <linux/malloc.h>
  17. #include <asm/segment.h>
  18.  
  19. struct vm_struct {
  20.     unsigned long flags;
  21.     void * addr;
  22.     unsigned long size;
  23.     struct vm_struct * next;
  24. };
  25.  
  26. static struct vm_struct * vmlist = NULL;
  27.  
  28. #define VMALLOC_OFFSET    (8*1024*1024)
  29.  
  30. #ifdef __i386__
  31.  
  32. static inline void set_pgdir(unsigned long dindex, unsigned long value)
  33. {
  34.     struct task_struct * p;
  35.  
  36.     p = &init_task;
  37.     do {
  38.         ((unsigned long *) p->tss.cr3)[dindex] = value;
  39.         p = p->next_task;
  40.     } while (p != &init_task);
  41. }
  42.  
  43. static int free_area_pages(unsigned long dindex, unsigned long index, unsigned long nr)
  44. {
  45.     unsigned long page, *pte;
  46.  
  47.     if (!(PAGE_PRESENT & (page = swapper_pg_dir[dindex])))
  48.         return 0;
  49.     page &= PAGE_MASK;
  50.     pte = index + (unsigned long *) page;
  51.     for ( ; nr > 0 ; nr--, pte++) {
  52.         unsigned long pg = *pte;
  53.         *pte = 0;
  54.         if (!(pg & PAGE_PRESENT))
  55.             continue;
  56.         free_page(pg);
  57.     }
  58.     pte = (unsigned long *) page;
  59.     for (nr = 0 ; nr < 1024 ; nr++, pte++)
  60.         if (*pte)
  61.             return 0;
  62.     set_pgdir(dindex,0);
  63.     mem_map[MAP_NR(page)] &= ~MAP_PAGE_RESERVED;
  64.     free_page(page);
  65.     return 0;
  66. }
  67.  
  68. static int alloc_area_pages(unsigned long dindex, unsigned long index, unsigned long nr)
  69. {
  70.     unsigned long page, *pte;
  71.  
  72.     page = swapper_pg_dir[dindex];
  73.     if (!page) {
  74.         page = get_free_page(GFP_KERNEL);
  75.         if (!page)
  76.             return -ENOMEM;
  77.         if (swapper_pg_dir[dindex]) {
  78.             free_page(page);
  79.             page = swapper_pg_dir[dindex];
  80.         } else {
  81.             mem_map[MAP_NR(page)] |= MAP_PAGE_RESERVED;
  82.             set_pgdir(dindex, page | PAGE_SHARED);
  83.         }
  84.     }
  85.     page &= PAGE_MASK;
  86.     pte = index + (unsigned long *) page;
  87.     *pte = PAGE_SHARED;        /* remove a race with vfree() */
  88.     for ( ; nr > 0 ; nr--, pte++) {
  89.         unsigned long pg = get_free_page(GFP_KERNEL);
  90.  
  91.         if (!pg)
  92.             return -ENOMEM;
  93.         *pte = pg | PAGE_SHARED;
  94.     }
  95.     return 0;
  96. }
  97.  
  98. static int do_area(void * addr, unsigned long size,
  99.     int (*area_fn)(unsigned long,unsigned long,unsigned long))
  100. {
  101.     unsigned long nr, dindex, index;
  102.  
  103.     nr = size >> PAGE_SHIFT;
  104.     dindex = (TASK_SIZE + (unsigned long) addr) >> 22;
  105.     index = (((unsigned long) addr) >> PAGE_SHIFT) & (PTRS_PER_PAGE-1);
  106.     while (nr > 0) {
  107.         unsigned long i = PTRS_PER_PAGE - index;
  108.  
  109.         if (i > nr)
  110.             i = nr;
  111.         if (area_fn(dindex, index, i))
  112.             return -1;
  113.         nr -= i;
  114.         index = 0;
  115.         dindex++;
  116.     }
  117.     return 0;
  118. }
  119.  
  120. #elif defined(__mc68000__)
  121.  
  122. static int free_area_pages(unsigned long dindex, unsigned long index, unsigned long nr)
  123. {
  124.     unsigned long ptr, *ptrp, page, *pte;
  125.     extern unsigned long *krt;
  126.  
  127.     if (!(PAGE_TABLE & (ptr = krt[dindex >> 3])))
  128.         return 0;
  129.     ptrp = (unsigned long *)PTOV(ptr & TABLE_MASK);
  130.     ptrp += (16*sizeof(long))*(dindex & (NUM_L2_ENTRIES-1));
  131.     if (!(PAGE_TABLE & (page = ptrp[16*(dindex & (NUM_L2_ENTRIES-1))])))
  132.         return 0;
  133.     page = PTOV(page & PAGE_MASK);
  134.     pte = index + (unsigned long *) page;
  135.     for ( ; nr > 0 ; nr--, pte++) {
  136.         unsigned long pg = *pte;
  137.         *pte = 0;
  138.         if (!(pg & PAGE_PRESENT))
  139.             continue;
  140.         free_page(PTOV(pg & PAGE_MASK));
  141.     }
  142.     pte = (unsigned long *) page;
  143.     for (nr = 0 ; nr < PTRS_PER_PAGE ; nr++, pte++)
  144.         if (*pte)
  145.             return 0;
  146.     mem_map[MAP_NR(page)] &= ~MAP_PAGE_RESERVED;
  147.     free_page_table(&ptrp[16*(dindex & (NUM_L2_ENTRIES-1))]);
  148.     return 0;
  149. }
  150.  
  151. static unsigned long get_pt (unsigned long dindex)
  152. {
  153.     unsigned long ptr, *ptrp, page;
  154.     extern unsigned long *krt;
  155.  
  156.     ptr = krt[dindex >> 3];
  157.     if (!ptr) {
  158.         ptrp = get_pointer_table();
  159.         if (!ptrp)
  160.             return -ENOMEM;
  161.         if (krt[dindex >> 3]) {
  162.             free_pointer_table(ptrp);
  163.             ptr = krt[dindex >> 3];
  164.         } else
  165.             krt[dindex >> 3] = VTOP(ptrp) | PAGE_TABLE;
  166.     } else
  167.         ptrp = (unsigned long *)PTOV(ptr & TABLE_MASK);
  168.     page = ptrp[16*(dindex & (NUM_L2_ENTRIES-1))];
  169.     if (!page) {
  170.         page = (unsigned long)get_page_table (&ptrp[16*(dindex & (NUM_L2_ENTRIES-1))]);
  171.         if (!page)
  172.             return -ENOMEM;
  173.         else
  174.             mem_map[MAP_NR(page)] |= MAP_PAGE_RESERVED;
  175.     } else
  176.         page = PTOV(page & PAGE_MASK);
  177.     return page;
  178. }
  179.  
  180. static int alloc_area_pages(unsigned long dindex, unsigned long index, unsigned long nr)
  181. {
  182.     unsigned long page, *pte;
  183.  
  184.     page = get_pt(dindex);
  185.     pte = index + (unsigned long *) page;
  186.     *pte = PAGE_SHARED;        /* remove a race with vfree() */
  187.     for ( ; nr > 0 ; nr--, pte++) {
  188.         unsigned long pg = get_free_page(GFP_KERNEL);
  189.  
  190.         if (!pg)
  191.             return -ENOMEM;
  192.         *pte = VTOP(pg) | PAGE_SHARED;
  193.     }
  194.     return 0;
  195. }
  196.  
  197. static int do_area(void * addr, unsigned long size,
  198.     int (*area_fn)(unsigned long,unsigned long,unsigned long))
  199. {
  200.     unsigned long nr, dindex, index;
  201.  
  202.     nr = size >> PAGE_SHIFT;
  203.     dindex = ((unsigned long) addr) >> 22;
  204.     index = (((unsigned long) addr) >> PAGE_SHIFT) & (PTRS_PER_PAGE-1);
  205.     while (nr > 0) {
  206.         unsigned long i = PTRS_PER_PAGE - index;
  207.  
  208.         if (i > nr)
  209.             i = nr;
  210.         if (area_fn(dindex, index, i))
  211.             return -1;
  212.         nr -= i;
  213.         index = 0;
  214.         dindex++;
  215.     }
  216.     return 0;
  217. }
  218. #endif
  219.  
  220. void vfree(void * addr)
  221. {
  222.     struct vm_struct **p, *tmp;
  223.  
  224.     if (!addr)
  225.         return;
  226.     if ((PAGE_SIZE-1) & (unsigned long) addr) {
  227.         printk("Trying to vfree() bad address (%p)\n", addr);
  228.         return;
  229.     }
  230.     for (p = &vmlist ; (tmp = *p) ; p = &tmp->next) {
  231.         if (tmp->addr == addr) {
  232.             *p = tmp->next;
  233.             do_area(tmp->addr, tmp->size, free_area_pages);
  234.             kfree(tmp);
  235.             return;
  236.         }
  237.     }
  238.     printk("Trying to vfree() nonexistent vm area (%p)\n", addr);
  239. }
  240.  
  241. void * vmalloc(unsigned long size)
  242. {
  243.     void * addr;
  244.     struct vm_struct **p, *tmp, *area;
  245.  
  246.     size = PAGE_ALIGN(size);
  247.     if (!size || size > high_memory)
  248.         return NULL;
  249.     area = (struct vm_struct *) kmalloc(sizeof(*area), GFP_KERNEL);
  250.     if (!area)
  251.         return NULL;
  252.     addr = (void *) ((high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1));
  253.     area->size = size + PAGE_SIZE;
  254.     area->next = NULL;
  255.     for (p = &vmlist; (tmp = *p) ; p = &tmp->next) {
  256.         if (size + (unsigned long) addr <= (unsigned long) tmp->addr)
  257.             break;
  258.         addr = (void *) (tmp->size + (unsigned long) tmp->addr);
  259.     }
  260.     area->addr = addr;
  261.     area->next = *p;
  262.     *p = area;
  263.     if (do_area(addr, size, alloc_area_pages)) {
  264.         vfree(addr);
  265.         return NULL;
  266.     }
  267.     return addr;
  268. }
  269.  
  270. int vread(char *buf, char *addr, int count)
  271. {
  272.     struct vm_struct **p, *tmp;
  273.     char *vaddr, *buf_start = buf;
  274.     int n;
  275.  
  276.     for (p = &vmlist; (tmp = *p) ; p = &tmp->next) {
  277.         vaddr = (char *) tmp->addr;
  278.         while (addr < vaddr) {
  279.             if (count == 0)
  280.                 goto finished;
  281.             put_fs_byte('\0', buf++), addr++, count--;
  282.         }
  283.         n = tmp->size - PAGE_SIZE;
  284.         if (addr > vaddr)
  285.             n -= addr - vaddr;
  286.         while (--n >= 0) {
  287.             if (count == 0)
  288.                 goto finished;
  289.             put_fs_byte(*addr++, buf++), count--;
  290.         }
  291.     }
  292. finished:
  293.     return buf - buf_start;
  294. }
  295.