This source file includes following definitions.
- get_free_page
- free_page
- free_page_tables
- copy_page_tables
- put_page
- un_wp_page
- do_wp_page
- write_verify
- do_no_page
- mem_init
- calc_mem
1
2
3
4
5
6
7 #include <signal.h>
8
9 #include <linux/head.h>
10 #include <linux/kernel.h>
11 #include <asm/system.h>
12
13 int do_exit(long code);
14
15 #define invalidate() \
16 __asm__("movl %%eax,%%cr3"::"a" (0))
17
18
19 #define LOW_MEM 0x100000
20 #define PAGING_MEMORY (15*1024*1024)
21 #define PAGING_PAGES (PAGING_MEMORY>>12)
22 #define MAP_NR(addr) (((addr)-LOW_MEM)>>12)
23 #define USED 100
24
25 static long HIGH_MEMORY = 0;
26
27 #define copy_page(from,to) \
28 __asm__("cld ; rep ; movsl"::"S" (from),"D" (to),"c" (1024):"cx","di","si")
29
30 static unsigned char mem_map [ PAGING_PAGES ] = {0,};
31
32
33
34
35
36 unsigned long get_free_page(void)
37 {
38 register unsigned long __res asm("ax");
39
40 __asm__("std ; repne ; scasb\n\t"
41 "jne 1f\n\t"
42 "movb $1,1(%%edi)\n\t"
43 "sall $12,%%ecx\n\t"
44 "addl %2,%%ecx\n\t"
45 "movl %%ecx,%%edx\n\t"
46 "movl $1024,%%ecx\n\t"
47 "leal 4092(%%edx),%%edi\n\t"
48 "rep ; stosl\n\t"
49 "movl %%edx,%%eax\n"
50 "1:"
51 :"=a" (__res)
52 :"0" (0),"i" (LOW_MEM),"c" (PAGING_PAGES),
53 "D" (mem_map+PAGING_PAGES-1)
54 :"di","cx","dx");
55 return __res;
56 }
57
58
59
60
61
62 void free_page(unsigned long addr)
63 {
64 if (addr < LOW_MEM) return;
65 if (addr > HIGH_MEMORY)
66 panic("trying to free nonexistent page");
67 addr -= LOW_MEM;
68 addr >>= 12;
69 if (mem_map[addr]--) return;
70 mem_map[addr]=0;
71 panic("trying to free free page");
72 }
73
74
75
76
77
78 int free_page_tables(unsigned long from,unsigned long size)
79 {
80 unsigned long *pg_table;
81 unsigned long * dir, nr;
82
83 if (from & 0x3fffff)
84 panic("free_page_tables called with wrong alignment");
85 if (!from)
86 panic("Trying to free up swapper memory space");
87 size = (size + 0x3fffff) >> 22;
88 dir = (unsigned long *) ((from>>20) & 0xffc);
89 for ( ; size-->0 ; dir++) {
90 if (!(1 & *dir))
91 continue;
92 pg_table = (unsigned long *) (0xfffff000 & *dir);
93 for (nr=0 ; nr<1024 ; nr++) {
94 if (1 & *pg_table)
95 free_page(0xfffff000 & *pg_table);
96 *pg_table = 0;
97 pg_table++;
98 }
99 free_page(0xfffff000 & *dir);
100 *dir = 0;
101 }
102 invalidate();
103 return 0;
104 }
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123 int copy_page_tables(unsigned long from,unsigned long to,long size)
124 {
125 unsigned long * from_page_table;
126 unsigned long * to_page_table;
127 unsigned long this_page;
128 unsigned long * from_dir, * to_dir;
129 unsigned long nr;
130
131 if ((from&0x3fffff) || (to&0x3fffff))
132 panic("copy_page_tables called with wrong alignment");
133 from_dir = (unsigned long *) ((from>>20) & 0xffc);
134 to_dir = (unsigned long *) ((to>>20) & 0xffc);
135 size = ((unsigned) (size+0x3fffff)) >> 22;
136 for( ; size-->0 ; from_dir++,to_dir++) {
137 if (1 & *to_dir)
138 panic("copy_page_tables: already exist");
139 if (!(1 & *from_dir))
140 continue;
141 from_page_table = (unsigned long *) (0xfffff000 & *from_dir);
142 if (!(to_page_table = (unsigned long *) get_free_page()))
143 return -1;
144 *to_dir = ((unsigned long) to_page_table) | 7;
145 nr = (from==0)?0xA0:1024;
146 for ( ; nr-- > 0 ; from_page_table++,to_page_table++) {
147 this_page = *from_page_table;
148 if (!(1 & this_page))
149 continue;
150 this_page &= ~2;
151 *to_page_table = this_page;
152 if (this_page > LOW_MEM) {
153 *from_page_table = this_page;
154 this_page -= LOW_MEM;
155 this_page >>= 12;
156 mem_map[this_page]++;
157 }
158 }
159 }
160 invalidate();
161 return 0;
162 }
163
164
165
166
167
168
169
170 unsigned long put_page(unsigned long page,unsigned long address)
171 {
172 unsigned long tmp, *page_table;
173
174
175
176 if (page < LOW_MEM || page > HIGH_MEMORY)
177 printk("Trying to put page %p at %p\n",page,address);
178 if (mem_map[(page-LOW_MEM)>>12] != 1)
179 printk("mem_map disagrees with %p at %p\n",page,address);
180 page_table = (unsigned long *) ((address>>20) & 0xffc);
181 if ((*page_table)&1)
182 page_table = (unsigned long *) (0xfffff000 & *page_table);
183 else {
184 if (!(tmp=get_free_page()))
185 return 0;
186 *page_table = tmp|7;
187 page_table = (unsigned long *) tmp;
188 }
189 page_table[(address>>12) & 0x3ff] = page | 7;
190 return page;
191 }
192
193 void un_wp_page(unsigned long * table_entry)
194 {
195 unsigned long old_page,new_page;
196
197 old_page = 0xfffff000 & *table_entry;
198 if (old_page >= LOW_MEM && mem_map[MAP_NR(old_page)]==1) {
199 *table_entry |= 2;
200 return;
201 }
202 if (!(new_page=get_free_page()))
203 do_exit(SIGSEGV);
204 if (old_page >= LOW_MEM)
205 mem_map[MAP_NR(old_page)]--;
206 *table_entry = new_page | 7;
207 copy_page(old_page,new_page);
208 }
209
210
211
212
213
214
215 void do_wp_page(unsigned long error_code,unsigned long address)
216 {
217 un_wp_page((unsigned long *)
218 (((address>>10) & 0xffc) + (0xfffff000 &
219 *((unsigned long *) ((address>>20) &0xffc)))));
220
221 }
222
223 void write_verify(unsigned long address)
224 {
225 unsigned long page;
226
227 if (!( (page = *((unsigned long *) ((address>>20) & 0xffc)) )&1))
228 return;
229 page &= 0xfffff000;
230 page += ((address>>10) & 0xffc);
231 if ((3 & *(unsigned long *) page) == 1)
232 un_wp_page((unsigned long *) page);
233 return;
234 }
235
236 void do_no_page(unsigned long error_code,unsigned long address)
237 {
238 unsigned long tmp;
239
240 if (tmp=get_free_page())
241 if (put_page(tmp,address))
242 return;
243 do_exit(SIGSEGV);
244 }
245
246 void mem_init(long start_mem, long end_mem)
247 {
248 int i;
249
250 HIGH_MEMORY = end_mem;
251 for (i=0 ; i<PAGING_PAGES ; i++)
252 mem_map[i] = USED;
253 i = MAP_NR(start_mem);
254 end_mem -= start_mem;
255 end_mem >>= 12;
256 while (end_mem-->0)
257 mem_map[i++]=0;
258 }
259
260 void calc_mem(void)
261 {
262 int i,j,k,free=0;
263 long * pg_tbl;
264
265 for(i=0 ; i<PAGING_PAGES ; i++)
266 if (!mem_map[i]) free++;
267 printk("%d pages free (of %d)\n\r",free,PAGING_PAGES);
268 for(i=2 ; i<1024 ; i++) {
269 if (1&pg_dir[i]) {
270 pg_tbl=(long *) (0xfffff000 & pg_dir[i]);
271 for(j=k=0 ; j<1024 ; j++)
272 if (pg_tbl[j]&1)
273 k++;
274 printk("Pg-dir[%d] uses %d pages\n",i,k);
275 }
276 }
277 }