This source file includes following definitions.
- set_pgdir
- free_area_pages
- alloc_area_pages
- do_area
- vfree
- vmalloc
- vread
1
2
3
4
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 static inline void set_pgdir(unsigned long dindex, unsigned long value)
31 {
32 struct task_struct * p;
33
34 p = &init_task;
35 do {
36 ((unsigned long *) p->tss.cr3)[dindex] = value;
37 p = p->next_task;
38 } while (p != &init_task);
39 }
40
41 static int free_area_pages(unsigned long dindex, unsigned long index, unsigned long nr)
42 {
43 unsigned long page, *pte;
44
45 if (!(PAGE_PRESENT & (page = swapper_pg_dir[dindex])))
46 return 0;
47 page &= PAGE_MASK;
48 pte = index + (unsigned long *) page;
49 for ( ; nr > 0 ; nr--, pte++) {
50 unsigned long pg = *pte;
51 *pte = 0;
52 if (!(pg & PAGE_PRESENT))
53 continue;
54 free_page(pg);
55 }
56 pte = (unsigned long *) page;
57 for (nr = 0 ; nr < 1024 ; nr++, pte++)
58 if (*pte)
59 return 0;
60 set_pgdir(dindex,0);
61 mem_map[MAP_NR(page)] &= ~MAP_PAGE_RESERVED;
62 free_page(page);
63 return 0;
64 }
65
66 static int alloc_area_pages(unsigned long dindex, unsigned long index, unsigned long nr)
67 {
68 unsigned long page, *pte;
69
70 page = swapper_pg_dir[dindex];
71 if (!page) {
72 page = get_free_page(GFP_KERNEL);
73 if (!page)
74 return -ENOMEM;
75 if (swapper_pg_dir[dindex]) {
76 free_page(page);
77 page = swapper_pg_dir[dindex];
78 } else {
79 mem_map[MAP_NR(page)] |= MAP_PAGE_RESERVED;
80 set_pgdir(dindex, page | PAGE_SHARED);
81 }
82 }
83 page &= PAGE_MASK;
84 pte = index + (unsigned long *) page;
85 *pte = PAGE_SHARED;
86 for ( ; nr > 0 ; nr--, pte++) {
87 unsigned long pg = get_free_page(GFP_KERNEL);
88
89 if (!pg)
90 return -ENOMEM;
91 *pte = pg | PAGE_SHARED;
92 }
93 return 0;
94 }
95
96 static int do_area(void * addr, unsigned long size,
97 int (*area_fn)(unsigned long,unsigned long,unsigned long))
98 {
99 unsigned long nr, dindex, index;
100
101 nr = size >> PAGE_SHIFT;
102 dindex = (TASK_SIZE + (unsigned long) addr) >> 22;
103 index = (((unsigned long) addr) >> PAGE_SHIFT) & (PTRS_PER_PAGE-1);
104 while (nr > 0) {
105 unsigned long i = PTRS_PER_PAGE - index;
106
107 if (i > nr)
108 i = nr;
109 if (area_fn(dindex, index, i))
110 return -1;
111 nr -= i;
112 index = 0;
113 dindex++;
114 }
115 return 0;
116 }
117
118 void vfree(void * addr)
119 {
120 struct vm_struct **p, *tmp;
121
122 if (!addr)
123 return;
124 if ((PAGE_SIZE-1) & (unsigned long) addr) {
125 printk("Trying to vfree() bad address (%p)\n", addr);
126 return;
127 }
128 for (p = &vmlist ; (tmp = *p) ; p = &tmp->next) {
129 if (tmp->addr == addr) {
130 *p = tmp->next;
131 do_area(tmp->addr, tmp->size, free_area_pages);
132 kfree(tmp);
133 return;
134 }
135 }
136 printk("Trying to vfree() nonexistent vm area (%p)\n", addr);
137 }
138
139 void * vmalloc(unsigned long size)
140 {
141 void * addr;
142 struct vm_struct **p, *tmp, *area;
143
144 size = PAGE_ALIGN(size);
145 if (!size || size > high_memory)
146 return NULL;
147 area = (struct vm_struct *) kmalloc(sizeof(*area), GFP_KERNEL);
148 if (!area)
149 return NULL;
150 addr = (void *) ((high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1));
151 area->size = size + PAGE_SIZE;
152 area->next = NULL;
153 for (p = &vmlist; (tmp = *p) ; p = &tmp->next) {
154 if (size + (unsigned long) addr <= (unsigned long) tmp->addr)
155 break;
156 addr = (void *) (tmp->size + (unsigned long) tmp->addr);
157 }
158 area->addr = addr;
159 area->next = *p;
160 *p = area;
161 if (do_area(addr, size, alloc_area_pages)) {
162 vfree(addr);
163 return NULL;
164 }
165 return addr;
166 }
167
168 int vread(char *buf, char *addr, int count)
169 {
170 struct vm_struct **p, *tmp;
171 char *vaddr, *buf_start = buf;
172 int n;
173
174 for (p = &vmlist; (tmp = *p) ; p = &tmp->next) {
175 vaddr = (char *) tmp->addr;
176 while (addr < vaddr) {
177 if (count == 0)
178 goto finished;
179 put_fs_byte('\0', buf++), addr++, count--;
180 }
181 n = tmp->size - PAGE_SIZE;
182 if (addr > vaddr)
183 n -= addr - vaddr;
184 while (--n >= 0) {
185 if (count == 0)
186 goto finished;
187 put_fs_byte(*addr++, buf++), count--;
188 }
189 }
190 finished:
191 return buf - buf_start;
192 }