|
|
1.1 root 1: #include <signal.h>
2:
3: #include <linux/config.h>
4: #include <linux/head.h>
5: #include <linux/kernel.h>
6: #include <asm/system.h>
7:
8: int do_exit(long code);
9:
10: #define invalidate() \
11: __asm__("movl %%eax,%%cr3"::"a" (0))
12:
13: #if (BUFFER_END < 0x100000)
14: #define LOW_MEM 0x100000
15: #else
16: #define LOW_MEM BUFFER_END
17: #endif
18:
19: /* these are not to be changed - thay are calculated from the above */
20: #define PAGING_MEMORY (HIGH_MEMORY - LOW_MEM)
21: #define PAGING_PAGES (PAGING_MEMORY/4096)
22: #define MAP_NR(addr) (((addr)-LOW_MEM)>>12)
23:
24: #if (PAGING_PAGES < 10)
25: #error "Won't work"
26: #endif
27:
28: #define copy_page(from,to) \
29: __asm__("cld ; rep ; movsl"::"S" (from),"D" (to),"c" (1024):"cx","di","si")
30:
31: static unsigned short mem_map [ PAGING_PAGES ] = {0,};
32:
33: /*
34: * Get physical address of first (actually last :-) free page, and mark it
35: * used. If no free pages left, return 0.
36: */
37: unsigned long get_free_page(void)
38: {
39: register unsigned long __res asm("ax");
40:
41: __asm__("std ; repne ; scasw\n\t"
42: "jne 1f\n\t"
43: "movw $1,2(%%edi)\n\t"
44: "sall $12,%%ecx\n\t"
45: "movl %%ecx,%%edx\n\t"
46: "addl %2,%%edx\n\t"
47: "movl $1024,%%ecx\n\t"
48: "leal 4092(%%edx),%%edi\n\t"
49: "rep ; stosl\n\t"
50: "movl %%edx,%%eax\n"
51: "1:"
52: :"=a" (__res)
53: :"0" (0),"i" (LOW_MEM),"c" (PAGING_PAGES),
54: "D" (mem_map+PAGING_PAGES-1)
55: :"di","cx","dx");
56: return __res;
57: }
58:
59: /*
60: * Free a page of memory at physical address 'addr'. Used by
61: * 'free_page_tables()'
62: */
63: void free_page(unsigned long addr)
64: {
65: if (addr<LOW_MEM) return;
66: if (addr>HIGH_MEMORY)
67: panic("trying to free nonexistent page");
68: addr -= LOW_MEM;
69: addr >>= 12;
70: if (mem_map[addr]--) return;
71: mem_map[addr]=0;
72: panic("trying to free free page");
73: }
74:
75: /*
76: * This function frees a continuos block of page tables, as needed
77: * by 'exit()'. As does copy_page_tables(), this handles only 4Mb blocks.
78: */
79: int free_page_tables(unsigned long from,unsigned long size)
80: {
81: unsigned long *pg_table;
82: unsigned long * dir, nr;
83:
84: if (from & 0x3fffff)
85: panic("free_page_tables called with wrong alignment");
86: if (!from)
87: panic("Trying to free up swapper memory space");
88: size = (size + 0x3fffff) >> 22;
89: dir = (unsigned long *) ((from>>20) & 0xffc); /* _pg_dir = 0 */
90: for ( ; size-->0 ; dir++) {
91: if (!(1 & *dir))
92: continue;
93: pg_table = (unsigned long *) (0xfffff000 & *dir);
94: for (nr=0 ; nr<1024 ; nr++) {
95: if (1 & *pg_table)
96: free_page(0xfffff000 & *pg_table);
97: *pg_table = 0;
98: pg_table++;
99: }
100: free_page(0xfffff000 & *dir);
101: *dir = 0;
102: }
103: invalidate();
104: return 0;
105: }
106:
107: /*
108: * Well, here is one of the most complicated functions in mm. It
109: * copies a range of linerar addresses by copying only the pages.
110: * Let's hope this is bug-free, 'cause this one I don't want to debug :-)
111: *
112: * Note! We don't copy just any chunks of memory - addresses have to
113: * be divisible by 4Mb (one page-directory entry), as this makes the
114: * function easier. It's used only by fork anyway.
115: *
116: * NOTE 2!! When from==0 we are copying kernel space for the first
117: * fork(). Then we DONT want to copy a full page-directory entry, as
118: * that would lead to some serious memory waste - we just copy the
119: * first 160 pages - 640kB. Even that is more than we need, but it
120: * doesn't take any more memory - we don't copy-on-write in the low
121: * 1 Mb-range, so the pages can be shared with the kernel. Thus the
122: * special case for nr=xxxx.
123: */
124: int copy_page_tables(unsigned long from,unsigned long to,long size)
125: {
126: unsigned long * from_page_table;
127: unsigned long * to_page_table;
128: unsigned long this_page;
129: unsigned long * from_dir, * to_dir;
130: unsigned long nr;
131:
132: if ((from&0x3fffff) || (to&0x3fffff))
133: panic("copy_page_tables called with wrong alignment");
134: from_dir = (unsigned long *) ((from>>20) & 0xffc); /* _pg_dir = 0 */
135: to_dir = (unsigned long *) ((to>>20) & 0xffc);
136: size = ((unsigned) (size+0x3fffff)) >> 22;
137: for( ; size-->0 ; from_dir++,to_dir++) {
138: if (1 & *to_dir)
139: panic("copy_page_tables: already exist");
140: if (!(1 & *from_dir))
141: continue;
142: from_page_table = (unsigned long *) (0xfffff000 & *from_dir);
143: if (!(to_page_table = (unsigned long *) get_free_page()))
144: return -1; /* Out of memory, see freeing */
145: *to_dir = ((unsigned long) to_page_table) | 7;
146: nr = (from==0)?0xA0:1024;
147: for ( ; nr-- > 0 ; from_page_table++,to_page_table++) {
148: this_page = *from_page_table;
149: if (!(1 & this_page))
150: continue;
151: this_page &= ~2;
152: *to_page_table = this_page;
153: if (this_page > LOW_MEM) {
154: *from_page_table = this_page;
155: this_page -= LOW_MEM;
156: this_page >>= 12;
157: mem_map[this_page]++;
158: }
159: }
160: }
161: invalidate();
162: return 0;
163: }
164:
165: /*
166: * This function puts a page in memory at the wanted address.
167: * It returns the physical address of the page gotten, 0 if
168: * out of memory (either when trying to access page-table or
169: * page.)
170: */
171: unsigned long put_page(unsigned long page,unsigned long address)
172: {
173: unsigned long tmp, *page_table;
174:
175: /* NOTE !!! This uses the fact that _pg_dir=0 */
176:
177: if (page < LOW_MEM || page > HIGH_MEMORY)
178: printk("Trying to put page %p at %p\n",page,address);
179: if (mem_map[(page-LOW_MEM)>>12] != 1)
180: printk("mem_map disagrees with %p at %p\n",page,address);
181: page_table = (unsigned long *) ((address>>20) & 0xffc);
182: if ((*page_table)&1)
183: page_table = (unsigned long *) (0xfffff000 & *page_table);
184: else {
185: if (!(tmp=get_free_page()))
186: return 0;
187: *page_table = tmp|7;
188: page_table = (unsigned long *) tmp;
189: }
190: page_table[(address>>12) & 0x3ff] = page | 7;
191: return page;
192: }
193:
194: void un_wp_page(unsigned long * table_entry)
195: {
196: unsigned long old_page,new_page;
197:
198: old_page = 0xfffff000 & *table_entry;
199: if (old_page >= LOW_MEM && mem_map[MAP_NR(old_page)]==1) {
200: *table_entry |= 2;
201: return;
202: }
203: if (!(new_page=get_free_page()))
204: do_exit(SIGSEGV);
205: if (old_page >= LOW_MEM)
206: mem_map[MAP_NR(old_page)]--;
207: *table_entry = new_page | 7;
208: copy_page(old_page,new_page);
209: }
210:
211: /*
212: * This routine handles present pages, when users try to write
213: * to a shared page. It is done by copying the page to a new address
214: * and decrementing the shared-page counter for the old page.
215: */
216: void do_wp_page(unsigned long error_code,unsigned long address)
217: {
218: un_wp_page((unsigned long *)
219: (((address>>10) & 0xffc) + (0xfffff000 &
220: *((unsigned long *) ((address>>20) &0xffc)))));
221:
222: }
223:
224: void write_verify(unsigned long address)
225: {
226: unsigned long page;
227:
228: if (!( (page = *((unsigned long *) ((address>>20) & 0xffc)) )&1))
229: return;
230: page &= 0xfffff000;
231: page += ((address>>10) & 0xffc);
232: if ((3 & *(unsigned long *) page) == 1) /* non-writeable, present */
233: un_wp_page((unsigned long *) page);
234: return;
235: }
236:
237: void do_no_page(unsigned long error_code,unsigned long address)
238: {
239: unsigned long tmp;
240:
241: if (tmp=get_free_page())
242: if (put_page(tmp,address))
243: return;
244: do_exit(SIGSEGV);
245: }
246:
247: void calc_mem(void)
248: {
249: int i,j,k,free=0;
250: long * pg_tbl;
251:
252: for(i=0 ; i<PAGING_PAGES ; i++)
253: if (!mem_map[i]) free++;
254: printk("%d pages free (of %d)\n\r",free,PAGING_PAGES);
255: for(i=2 ; i<1024 ; i++) {
256: if (1&pg_dir[i]) {
257: pg_tbl=(long *) (0xfffff000 & pg_dir[i]);
258: for(j=k=0 ; j<1024 ; j++)
259: if (pg_tbl[j]&1)
260: k++;
261: printk("Pg-dir[%d] uses %d pages\n",i,k);
262: }
263: }
264: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.