|
|
1.1.1.2 root 1: /*
2: * linux/mm/memory.c
3: *
1.1.1.11! root 4: * Copyright (C) 1991, 1992 Linus Torvalds
1.1.1.2 root 5: */
6:
1.1.1.3 root 7: /*
8: * demand-loading started 01.12.91 - seems it is high on the list of
9: * things wanted, and it should be easy to implement. - Linus
10: */
11:
12: /*
13: * Ok, demand-loading was easy, shared pages a little bit tricker. Shared
14: * pages started 02.12.91, seems to work. - Linus.
15: *
16: * Tested sharing by executing about 30 /bin/sh: under the old kernel it
17: * would have taken more than the 6M I have free, but it worked well as
18: * far as I could see.
19: *
20: * Also corrected some "invalidate()"s - I wasn't doing enough of them.
21: */
22:
1.1.1.4 root 23: /*
24: * Real VM (paging to/from disk) started 18.12.91. Much more work and
25: * thought has to go into this. Oh, well..
26: * 19.12.91 - works, somewhat. Sometimes I get faults, don't know why.
27: * Found it. Everything seems to work now.
28: * 20.12.91 - Ok, making the swap-device changeable like the root.
29: */
30:
1.1.1.3 root 31: #include <asm/system.h>
32:
1.1.1.11! root 33: #include <linux/signal.h>
1.1.1.3 root 34: #include <linux/sched.h>
1.1 root 35: #include <linux/head.h>
36: #include <linux/kernel.h>
1.1.1.11! root 37: #include <linux/string.h>
1.1 root 38:
1.1.1.3 root 39: #define CODE_SPACE(addr) ((((addr)+4095)&~4095) < \
40: current->start_code + current->end_code)
41:
1.1.1.11! root 42: unsigned long low_memory = 0;
! 43: unsigned long high_memory = 0;
! 44: unsigned long paging_pages = 0;
1.1 root 45:
46: #define copy_page(from,to) \
47: __asm__("cld ; rep ; movsl"::"S" (from),"D" (to),"c" (1024):"cx","di","si")
48:
1.1.1.11! root 49: unsigned char * mem_map = NULL;
1.1.1.5 root 50:
1.1.1.11! root 51: /*
! 52: * oom() prints a message (so that the user knows why the process died),
! 53: * and gives the process an untrappable SIGSEGV.
! 54: */
! 55: void oom(struct task_struct * task)
! 56: {
! 57: printk("\nout of memory\n");
! 58: task->sigaction[SIGSEGV-1].sa_handler = NULL;
! 59: task->blocked &= ~(1<<(SIGSEGV-1));
! 60: send_sig(SIGSEGV,task,1);
! 61: }
1.1 root 62:
1.1.1.11! root 63: int nr_free_pages = 0;
1.1 root 64: /*
65: * Free a page of memory at physical address 'addr'. Used by
66: * 'free_page_tables()'
67: */
68: void free_page(unsigned long addr)
69: {
1.1.1.11! root 70: unsigned long i;
! 71:
! 72: if (addr < low_memory)
! 73: return;
! 74: if (addr < high_memory) {
! 75: i = addr - low_memory;
! 76: i >>= 12;
! 77: if (mem_map[i] == 1)
! 78: ++nr_free_pages;
! 79: if (mem_map[i]--)
1.1.1.5 root 80: return;
1.1.1.11! root 81: mem_map[i] = 0;
1.1.1.5 root 82: }
1.1.1.11! root 83: printk("trying to free free page (%08x): memory probably corrupted\n",addr);
1.1 root 84: }
85:
86: /*
87: * This function frees a continuos block of page tables, as needed
88: * by 'exit()'. As does copy_page_tables(), this handles only 4Mb blocks.
89: */
90: int free_page_tables(unsigned long from,unsigned long size)
91: {
1.1.1.5 root 92: unsigned long page;
93: unsigned long page_dir;
1.1 root 94: unsigned long *pg_table;
95: unsigned long * dir, nr;
96:
97: if (from & 0x3fffff)
98: panic("free_page_tables called with wrong alignment");
99: if (!from)
100: panic("Trying to free up swapper memory space");
101: size = (size + 0x3fffff) >> 22;
102: dir = (unsigned long *) ((from>>20) & 0xffc); /* _pg_dir = 0 */
103: for ( ; size-->0 ; dir++) {
1.1.1.5 root 104: if (!(page_dir = *dir))
1.1 root 105: continue;
106: *dir = 0;
1.1.1.5 root 107: if (!(page_dir & 1)) {
108: printk("free_page_tables: bad page directory.");
109: continue;
110: }
111: pg_table = (unsigned long *) (0xfffff000 & page_dir);
112: for (nr=0 ; nr<1024 ; nr++,pg_table++) {
113: if (!(page = *pg_table))
114: continue;
115: *pg_table = 0;
116: if (1 & page)
117: free_page(0xfffff000 & page);
118: else
119: swap_free(page >> 1);
120: }
121: free_page(0xfffff000 & page_dir);
1.1 root 122: }
123: invalidate();
124: return 0;
125: }
126:
127: /*
128: * Well, here is one of the most complicated functions in mm. It
129: * copies a range of linerar addresses by copying only the pages.
130: * Let's hope this is bug-free, 'cause this one I don't want to debug :-)
131: *
132: * Note! We don't copy just any chunks of memory - addresses have to
133: * be divisible by 4Mb (one page-directory entry), as this makes the
134: * function easier. It's used only by fork anyway.
135: *
136: * NOTE 2!! When from==0 we are copying kernel space for the first
137: * fork(). Then we DONT want to copy a full page-directory entry, as
138: * that would lead to some serious memory waste - we just copy the
139: * first 160 pages - 640kB. Even that is more than we need, but it
140: * doesn't take any more memory - we don't copy-on-write in the low
141: * 1 Mb-range, so the pages can be shared with the kernel. Thus the
142: * special case for nr=xxxx.
143: */
144: int copy_page_tables(unsigned long from,unsigned long to,long size)
145: {
146: unsigned long * from_page_table;
147: unsigned long * to_page_table;
148: unsigned long this_page;
149: unsigned long * from_dir, * to_dir;
1.1.1.4 root 150: unsigned long new_page;
1.1 root 151: unsigned long nr;
152:
153: if ((from&0x3fffff) || (to&0x3fffff))
154: panic("copy_page_tables called with wrong alignment");
155: from_dir = (unsigned long *) ((from>>20) & 0xffc); /* _pg_dir = 0 */
156: to_dir = (unsigned long *) ((to>>20) & 0xffc);
157: size = ((unsigned) (size+0x3fffff)) >> 22;
158: for( ; size-->0 ; from_dir++,to_dir++) {
1.1.1.5 root 159: if (*to_dir)
160: printk("copy_page_tables: already exist, "
161: "probable memory corruption\n");
162: if (!*from_dir)
163: continue;
164: if (!(1 & *from_dir)) {
165: printk("copy_page_tables: page table swapped out, "
166: "probable memory corruption");
167: *from_dir = 0;
1.1 root 168: continue;
1.1.1.5 root 169: }
1.1 root 170: from_page_table = (unsigned long *) (0xfffff000 & *from_dir);
1.1.1.11! root 171: if (!(to_page_table = (unsigned long *) get_free_page(GFP_KERNEL)))
1.1 root 172: return -1; /* Out of memory, see freeing */
173: *to_dir = ((unsigned long) to_page_table) | 7;
174: nr = (from==0)?0xA0:1024;
175: for ( ; nr-- > 0 ; from_page_table++,to_page_table++) {
1.1.1.11! root 176: repeat:
1.1 root 177: this_page = *from_page_table;
1.1.1.4 root 178: if (!this_page)
1.1 root 179: continue;
1.1.1.4 root 180: if (!(1 & this_page)) {
1.1.1.11! root 181: if (!(new_page = get_free_page(GFP_KERNEL)))
1.1.1.4 root 182: return -1;
1.1.1.7 root 183: ++current->rss;
1.1.1.4 root 184: read_swap_page(this_page>>1, (char *) new_page);
1.1.1.11! root 185: if (*from_page_table != this_page) {
! 186: free_page(new_page);
! 187: goto repeat;
! 188: }
1.1.1.4 root 189: *to_page_table = this_page;
190: *from_page_table = new_page | (PAGE_DIRTY | 7);
191: continue;
192: }
1.1 root 193: this_page &= ~2;
194: *to_page_table = this_page;
1.1.1.11! root 195: if (this_page > low_memory) {
1.1 root 196: *from_page_table = this_page;
1.1.1.11! root 197: this_page -= low_memory;
1.1 root 198: this_page >>= 12;
1.1.1.11! root 199: if (!mem_map[this_page]++)
! 200: --nr_free_pages;
1.1 root 201: }
202: }
203: }
204: invalidate();
205: return 0;
206: }
207:
208: /*
1.1.1.8 root 209: * a more complete version of free_page_tables which performs with page
210: * granularity.
211: */
1.1.1.10 root 212: int unmap_page_range(unsigned long from, unsigned long size)
1.1.1.8 root 213: {
214: unsigned long page, page_dir;
215: unsigned long *page_table, *dir;
216: unsigned long poff, pcnt, pc;
217:
218: if (from & 0xfff)
219: panic("unmap_page_range called with wrong alignment");
220: if (!from)
221: panic("unmap_page_range trying to free swapper memory space");
222: size = (size + 0xfff) >> 12;
223: dir = (unsigned long *) ((from >> 20) & 0xffc); /* _pg_dir = 0 */
224: poff = (from >> 12) & 0x3ff;
225: if ((pcnt = 1024 - poff) > size)
226: pcnt = size;
227:
228: for ( ; size > 0; ++dir, size -= pcnt,
229: pcnt = (size > 1024 ? 1024 : size)) {
230: if (!(page_dir = *dir)) {
231: poff = 0;
232: continue;
233: }
234: if (!(page_dir & 1)) {
235: printk("unmap_page_range: bad page directory.");
236: continue;
237: }
238: page_table = (unsigned long *)(0xfffff000 & page_dir);
239: if (poff) {
240: page_table += poff;
241: poff = 0;
242: }
243: for (pc = pcnt; pc--; page_table++) {
244: if (page = *page_table) {
245: --current->rss;
246: *page_table = 0;
247: if (1 & page)
248: free_page(0xfffff000 & page);
249: else
250: swap_free(page >> 1);
251: }
252: }
253: if (pcnt == 1024) {
254: free_page(0xfffff000 & page_dir);
255: *dir = 0;
256: }
257: }
258: invalidate();
259: return 0;
260: }
261:
262: /*
263: * maps a range of physical memory into the requested pages. the old
264: * mappings are removed. any references to nonexistent pages results
265: * in null mappings (currently treated as "copy-on-access")
266: *
267: * permiss is encoded as cxwr (copy,exec,write,read) where copy modifies
268: * the behavior of write to be copy-on-write.
269: *
270: * due to current limitations, we actually have the following
271: * on off
272: * read: yes yes
273: * write/copy: yes/copy copy/copy
274: * exec: yes yes
275: */
1.1.1.10 root 276: int remap_page_range(unsigned long from, unsigned long to, unsigned long size,
1.1.1.8 root 277: int permiss)
278: {
279: unsigned long *page_table, *dir;
280: unsigned long poff, pcnt;
1.1.1.11! root 281: unsigned long page;
1.1.1.8 root 282:
283: if ((from & 0xfff) || (to & 0xfff))
284: panic("remap_page_range called with wrong alignment");
285: dir = (unsigned long *) ((from >> 20) & 0xffc); /* _pg_dir = 0 */
286: size = (size + 0xfff) >> 12;
287: poff = (from >> 12) & 0x3ff;
288: if ((pcnt = 1024 - poff) > size)
289: pcnt = size;
290:
291: while (size > 0) {
292: if (!(1 & *dir)) {
1.1.1.11! root 293: if (!(page_table = (unsigned long *)get_free_page(GFP_KERNEL))) {
1.1.1.8 root 294: invalidate();
295: return -1;
296: }
297: *dir++ = ((unsigned long) page_table) | 7;
298: }
299: else
300: page_table = (unsigned long *)(0xfffff000 & *dir++);
301: if (poff) {
302: page_table += poff;
303: poff = 0;
304: }
305:
306: for (size -= pcnt; pcnt-- ;) {
307: int mask;
308:
309: mask = 4;
310: if (permiss & 1)
311: mask |= 1;
312: if (permiss & 2) {
313: if (permiss & 8)
314: mask |= 1;
315: else
316: mask |= 3;
317: }
318: if (permiss & 4)
319: mask |= 1;
320:
1.1.1.11! root 321: if (page = *page_table) {
! 322: *page_table = 0;
1.1.1.8 root 323: --current->rss;
1.1.1.11! root 324: if (1 & page)
! 325: free_page(0xfffff000 & page);
1.1.1.8 root 326: else
1.1.1.11! root 327: swap_free(page >> 1);
1.1.1.8 root 328: }
329:
330: /*
331: * i'm not sure of the second cond here. should we
332: * report failure?
333: * the first condition should return an invalid access
334: * when the page is referenced. current assumptions
335: * cause it to be treated as demand allocation.
336: */
1.1.1.11! root 337: if (mask == 4 || to >= high_memory)
1.1.1.8 root 338: *page_table++ = 0; /* not present */
339: else {
340: ++current->rss;
341: *page_table++ = (to | mask);
1.1.1.11! root 342: if (to > low_memory) {
1.1.1.8 root 343: unsigned long frame;
1.1.1.11! root 344: frame = to - low_memory;
1.1.1.8 root 345: frame >>= 12;
1.1.1.11! root 346: if (!mem_map[frame]++)
! 347: --nr_free_pages;
1.1.1.8 root 348: }
349: }
350: to += PAGE_SIZE;
351: }
352: pcnt = (size > 1024 ? 1024 : size);
353: }
354: invalidate();
355: return 0;
356: }
357:
358: /*
1.1 root 359: * This function puts a page in memory at the wanted address.
360: * It returns the physical address of the page gotten, 0 if
361: * out of memory (either when trying to access page-table or
362: * page.)
363: */
1.1.1.4 root 364: static unsigned long put_page(unsigned long page,unsigned long address)
1.1 root 365: {
366: unsigned long tmp, *page_table;
367:
368: /* NOTE !!! This uses the fact that _pg_dir=0 */
369:
1.1.1.11! root 370: if (page >= high_memory) {
1.1.1.5 root 371: printk("put_page: trying to put page %p at %p\n",page,address);
372: return 0;
373: }
1.1.1.11! root 374: if (page >= low_memory && mem_map[(page-low_memory)>>12] != 1) {
1.1.1.8 root 375: printk("put_page: mem_map disagrees with %p at %p\n",page,address);
1.1.1.5 root 376: return 0;
377: }
1.1 root 378: page_table = (unsigned long *) ((address>>20) & 0xffc);
379: if ((*page_table)&1)
380: page_table = (unsigned long *) (0xfffff000 & *page_table);
381: else {
1.1.1.11! root 382: tmp = get_free_page(GFP_KERNEL);
! 383: if (!tmp) {
! 384: oom(current);
! 385: tmp = BAD_PAGETABLE;
! 386: }
1.1.1.4 root 387: *page_table = tmp | 7;
1.1.1.11! root 388: return 0;
1.1 root 389: }
1.1.1.6 root 390: page_table += (address>>12) & 0x3ff;
391: if (*page_table) {
392: printk("put_page: page already exists\n");
393: *page_table = 0;
394: invalidate();
395: }
396: *page_table = page | 7;
1.1.1.3 root 397: /* no need for invalidate */
1.1 root 398: return page;
399: }
400:
1.1.1.4 root 401: /*
402: * The previous function doesn't work very well if you also want to mark
403: * the page dirty: exec.c wants this, as it has earlier changed the page,
404: * and we want the dirty-status to be correct (for VM). Thus the same
405: * routine, but this time we mark it dirty too.
406: */
407: unsigned long put_dirty_page(unsigned long page, unsigned long address)
408: {
409: unsigned long tmp, *page_table;
410:
411: /* NOTE !!! This uses the fact that _pg_dir=0 */
412:
1.1.1.11! root 413: if (page < low_memory || page >= high_memory)
1.1.1.5 root 414: printk("put_dirty_page: trying to put page %p at %p\n",page,address);
1.1.1.11! root 415: if (mem_map[(page-low_memory)>>12] != 1)
1.1.1.4 root 416: printk("mem_map disagrees with %p at %p\n",page,address);
417: page_table = (unsigned long *) ((address>>20) & 0xffc);
418: if ((*page_table)&1)
419: page_table = (unsigned long *) (0xfffff000 & *page_table);
420: else {
1.1.1.11! root 421: if (!(tmp=get_free_page(GFP_KERNEL)))
1.1.1.4 root 422: return 0;
423: *page_table = tmp|7;
424: page_table = (unsigned long *) tmp;
425: }
1.1.1.6 root 426: page_table += (address>>12) & 0x3ff;
427: if (*page_table) {
428: printk("put_dirty_page: page already exists\n");
429: *page_table = 0;
430: invalidate();
431: }
432: *page_table = page | (PAGE_DIRTY | 7);
1.1.1.4 root 433: /* no need for invalidate */
434: return page;
435: }
436:
1.1.1.11! root 437: static void un_wp_page(unsigned long * table_entry, struct task_struct * task)
1.1 root 438: {
1.1.1.5 root 439: unsigned long old_page;
440: unsigned long new_page = 0;
441: unsigned long dirty;
442:
443: repeat:
444: old_page = *table_entry;
445: if (!(old_page & 1)) {
446: if (new_page)
447: free_page(new_page);
448: return;
449: }
1.1.1.11! root 450: dirty = old_page & PAGE_DIRTY;
1.1.1.5 root 451: old_page &= 0xfffff000;
1.1.1.11! root 452: if (old_page >= high_memory) {
1.1.1.5 root 453: if (new_page)
454: free_page(new_page);
455: printk("bad page address\n\r");
1.1.1.11! root 456: send_sig(SIGSEGV, task, 1);
! 457: *table_entry = BAD_PAGE | 7;
! 458: return;
1.1.1.5 root 459: }
1.1.1.11! root 460: if (old_page >= low_memory && mem_map[MAP_NR(old_page)]==1) {
1.1 root 461: *table_entry |= 2;
1.1.1.3 root 462: invalidate();
1.1.1.5 root 463: if (new_page)
464: free_page(new_page);
1.1 root 465: return;
466: }
1.1.1.11! root 467: if (!new_page && (new_page=get_free_page(GFP_KERNEL)))
1.1.1.5 root 468: goto repeat;
1.1.1.11! root 469: if (new_page)
! 470: copy_page(old_page,new_page);
! 471: else {
! 472: new_page = BAD_PAGE;
! 473: send_sig(SIGSEGV,task,1);
1.1.1.5 root 474: }
475: *table_entry = new_page | dirty | 7;
476: free_page(old_page);
1.1.1.3 root 477: invalidate();
1.1 root 478: }
479:
480: /*
481: * This routine handles present pages, when users try to write
482: * to a shared page. It is done by copying the page to a new address
483: * and decrementing the shared-page counter for the old page.
1.1.1.3 root 484: *
485: * If it's in code space we exit with a segment error.
1.1 root 486: */
1.1.1.11! root 487: void do_wp_page(unsigned long error_code, unsigned long address,
! 488: struct task_struct * tsk, unsigned long user_esp)
1.1 root 489: {
1.1.1.11! root 490: unsigned long pde, pte, page;
! 491:
! 492: pde = (address>>20) & 0xffc;
! 493: pte = *(unsigned long *) pde;
! 494: if ((pte & 3) != 3) {
! 495: printk("do_wp_page: bogus page-table at address %08x (%08x)\n",address,pte);
! 496: *(unsigned long *) pde = BAD_PAGETABLE | 7;
! 497: send_sig(SIGSEGV, tsk, 1);
! 498: return;
! 499: }
1.1.1.6 root 500: if (address < TASK_SIZE) {
1.1.1.11! root 501: printk("do_wp_page: kernel WP error at address %08x (%08x)\n",address,pte);
! 502: *(unsigned long *) pde = BAD_PAGETABLE | 7;
! 503: send_sig(SIGSEGV, tsk, 1);
! 504: return;
1.1.1.6 root 505: }
1.1.1.11! root 506: pte &= 0xfffff000;
! 507: pte += (address>>10) & 0xffc;
! 508: page = *(unsigned long *) pte;
! 509: if ((page & 3) != 1) {
! 510: printk("do_wp_page: bogus page at address %08x (%08x)\n",address,page);
! 511: *(unsigned long *) pte = BAD_PAGE | 7;
! 512: send_sig(SIGSEGV, tsk, 1);
! 513: return;
1.1.1.4 root 514: }
1.1.1.7 root 515: ++current->min_flt;
1.1.1.11! root 516: un_wp_page((unsigned long *) pte, tsk);
1.1 root 517: }
518:
519: void write_verify(unsigned long address)
520: {
521: unsigned long page;
522:
1.1.1.11! root 523: page = *(unsigned long *) ((address>>20) & 0xffc);
! 524: if (!(page & PAGE_PRESENT))
1.1 root 525: return;
526: page &= 0xfffff000;
527: page += ((address>>10) & 0xffc);
528: if ((3 & *(unsigned long *) page) == 1) /* non-writeable, present */
1.1.1.11! root 529: un_wp_page((unsigned long *) page, current);
1.1 root 530: return;
531: }
532:
1.1.1.10 root 533: static void get_empty_page(unsigned long address)
1.1.1.3 root 534: {
535: unsigned long tmp;
536:
1.1.1.11! root 537: tmp = get_free_page(GFP_KERNEL);
! 538: if (!tmp) {
! 539: oom(current);
! 540: tmp = BAD_PAGE;
1.1.1.3 root 541: }
1.1.1.11! root 542: if (!put_page(tmp,address))
! 543: free_page(tmp);
1.1.1.3 root 544: }
545:
546: /*
547: * try_to_share() checks the page at address "address" in the task "p",
548: * to see if it exists, and if it is clean. If so, share it with the current
549: * task.
550: *
551: * NOTE! This assumes we have checked that p != current, and that they
1.1.1.4 root 552: * share the same executable or library.
1.1.1.3 root 553: */
554: static int try_to_share(unsigned long address, struct task_struct * p)
555: {
556: unsigned long from;
557: unsigned long to;
558: unsigned long from_page;
559: unsigned long to_page;
560: unsigned long phys_addr;
561:
562: from_page = to_page = ((address>>20) & 0xffc);
563: from_page += ((p->start_code>>20) & 0xffc);
564: to_page += ((current->start_code>>20) & 0xffc);
565: /* is there a page-directory at from? */
566: from = *(unsigned long *) from_page;
567: if (!(from & 1))
568: return 0;
569: from &= 0xfffff000;
570: from_page = from + ((address>>10) & 0xffc);
571: phys_addr = *(unsigned long *) from_page;
572: /* is the page clean and present? */
573: if ((phys_addr & 0x41) != 0x01)
574: return 0;
575: phys_addr &= 0xfffff000;
1.1.1.11! root 576: if (phys_addr >= high_memory || phys_addr < low_memory)
1.1.1.3 root 577: return 0;
578: to = *(unsigned long *) to_page;
1.1.1.5 root 579: if (!(to & 1)) {
1.1.1.11! root 580: to = get_free_page(GFP_KERNEL);
! 581: if (!to)
! 582: return 0;
! 583: *(unsigned long *) to_page = to | 7;
1.1.1.5 root 584: }
1.1.1.3 root 585: to &= 0xfffff000;
586: to_page = to + ((address>>10) & 0xffc);
587: if (1 & *(unsigned long *) to_page)
588: panic("try_to_share: to_page already exists");
589: /* share them: write-protect */
590: *(unsigned long *) from_page &= ~2;
591: *(unsigned long *) to_page = *(unsigned long *) from_page;
592: invalidate();
1.1.1.11! root 593: phys_addr -= low_memory;
1.1.1.3 root 594: phys_addr >>= 12;
1.1.1.11! root 595: if (!mem_map[phys_addr]++)
! 596: --nr_free_pages;
1.1.1.3 root 597: return 1;
598: }
599:
600: /*
601: * share_page() tries to find a process that could share a page with
602: * the current one. Address is the address of the wanted page relative
603: * to the current data space.
604: *
605: * We first check if it is at all feasible by checking executable->i_count.
606: * It should be >1 if there are other tasks sharing this inode.
607: */
1.1.1.5 root 608: static int share_page(struct inode * inode, unsigned long address)
1.1.1.3 root 609: {
610: struct task_struct ** p;
1.1.1.8 root 611: int i;
1.1.1.3 root 612:
1.1.1.9 root 613: if (!inode || inode->i_count < 2)
1.1.1.3 root 614: return 0;
615: for (p = &LAST_TASK ; p > &FIRST_TASK ; --p) {
616: if (!*p)
617: continue;
618: if (current == *p)
619: continue;
1.1.1.4 root 620: if (address < LIBRARY_OFFSET) {
621: if (inode != (*p)->executable)
622: continue;
623: } else {
1.1.1.8 root 624: for (i=0; i < (*p)->numlibraries; i++)
625: if (inode == (*p)->libraries[i].library)
626: break;
627: if (i >= (*p)->numlibraries)
1.1.1.4 root 628: continue;
629: }
1.1.1.3 root 630: if (try_to_share(address,*p))
631: return 1;
632: }
633: return 0;
634: }
635:
1.1.1.8 root 636: /*
1.1.1.11! root 637: * fill in an empty page-table if none exists
1.1.1.8 root 638: */
1.1.1.11! root 639: static unsigned long get_empty_pgtable(unsigned long * p)
1.1.1.8 root 640: {
641: unsigned long page = 0;
642:
643: repeat:
644: if (1 & *p) {
645: free_page(page);
646: return *p;
647: }
648: if (*p) {
1.1.1.11! root 649: printk("get_empty_pgtable: bad page-directory entry \n");
1.1.1.8 root 650: *p = 0;
651: }
652: if (page) {
653: *p = page | 7;
654: return *p;
655: }
1.1.1.11! root 656: if (page = get_free_page(GFP_KERNEL))
! 657: goto repeat;
! 658: oom(current);
! 659: *p = BAD_PAGETABLE | 7;
! 660: return 0;
1.1.1.8 root 661: }
662:
1.1.1.7 root 663: void do_no_page(unsigned long error_code, unsigned long address,
1.1.1.8 root 664: struct task_struct *tsk, unsigned long user_esp)
1.1 root 665: {
1.1.1.3 root 666: int nr[4];
1.1 root 667: unsigned long tmp;
1.1.1.3 root 668: unsigned long page;
1.1.1.8 root 669: unsigned int block,i;
1.1.1.5 root 670: struct inode * inode;
1.1 root 671:
1.1.1.6 root 672: if (address < TASK_SIZE) {
1.1.1.4 root 673: printk("\n\rBAD!! KERNEL PAGE MISSING\n\r");
1.1.1.6 root 674: do_exit(SIGSEGV);
675: }
1.1.1.5 root 676: if (address - tsk->start_code >= TASK_SIZE) {
1.1.1.4 root 677: printk("Bad things happen: nonexistent page error in do_no_page\n\r");
678: do_exit(SIGSEGV);
679: }
1.1.1.11! root 680: page = get_empty_pgtable((unsigned long *) ((address >> 20) & 0xffc));
! 681: if (!page)
! 682: return;
1.1.1.8 root 683: page &= 0xfffff000;
684: page += (address >> 10) & 0xffc;
685: tmp = *(unsigned long *) page;
686: if (tmp & 1) {
687: printk("bogus do_no_page\n");
688: return;
689: }
1.1.1.7 root 690: ++tsk->rss;
1.1.1.8 root 691: if (tmp) {
692: ++tsk->maj_flt;
693: swap_in((unsigned long *) page);
694: return;
1.1.1.4 root 695: }
1.1.1.3 root 696: address &= 0xfffff000;
1.1.1.5 root 697: tmp = address - tsk->start_code;
1.1.1.8 root 698: inode = NULL;
699: block = 0;
700: if (tmp < tsk->end_data) {
1.1.1.5 root 701: inode = tsk->executable;
1.1.1.4 root 702: block = 1 + tmp / BLOCK_SIZE;
703: } else {
1.1.1.8 root 704: i = tsk->numlibraries;
705: while (i-- > 0) {
706: if (tmp < tsk->libraries[i].start)
707: continue;
708: block = tmp - tsk->libraries[i].start;
709: if (block >= tsk->libraries[i].length)
710: continue;
711: inode = tsk->libraries[i].library;
712: block = 1 + block / BLOCK_SIZE;
713: break;
714: }
1.1.1.4 root 715: }
716: if (!inode) {
1.1.1.7 root 717: ++tsk->min_flt;
1.1.1.3 root 718: get_empty_page(address);
1.1.1.8 root 719: if (tsk != current)
720: return;
721: if (tmp >= LIBRARY_OFFSET || tmp < tsk->brk)
722: return;
723: if (tmp+8192 >= (user_esp & 0xfffff000))
724: return;
725: send_sig(SIGSEGV,tsk,1);
1.1.1.3 root 726: return;
727: }
1.1.1.5 root 728: if (tsk == current)
1.1.1.7 root 729: if (share_page(inode,tmp)) {
730: ++tsk->min_flt;
731: return;
732: }
733: ++tsk->maj_flt;
1.1.1.11! root 734: page = get_free_page(GFP_KERNEL);
! 735: if (!page) {
! 736: oom(current);
! 737: put_page(BAD_PAGE,address);
! 738: return;
! 739: }
1.1.1.3 root 740: for (i=0 ; i<4 ; block++,i++)
1.1.1.4 root 741: nr[i] = bmap(inode,block);
742: bread_page(page,inode->i_dev,nr);
1.1.1.5 root 743: i = tmp + 4096 - tsk->end_data;
1.1.1.4 root 744: if (i>4095)
745: i = 0;
1.1.1.3 root 746: tmp = page + 4096;
1.1.1.8 root 747: while (i--) {
1.1.1.3 root 748: tmp--;
749: *(char *)tmp = 0;
750: }
751: if (put_page(page,address))
752: return;
753: free_page(page);
1.1.1.11! root 754: oom(current);
1.1.1.2 root 755: }
756:
1.1.1.4 root 757: void show_mem(void)
1.1 root 758: {
1.1.1.4 root 759: int i,j,k,free=0,total=0;
1.1.1.7 root 760: int shared = 0;
1.1.1.4 root 761: unsigned long * pg_tbl;
762:
763: printk("Mem-info:\n\r");
1.1.1.11! root 764: printk("Free pages: %6d\n",nr_free_pages);
! 765: printk("Buffer heads: %6d\n",nr_buffer_heads);
! 766: printk("Buffer blocks: %6d\n",nr_buffers);
! 767: for (i = 0 ; i < paging_pages ; i++) {
1.1.1.4 root 768: total++;
769: if (!mem_map[i])
770: free++;
771: else
772: shared += mem_map[i]-1;
773: }
774: printk("%d free pages of %d\n\r",free,total);
775: printk("%d pages shared\n\r",shared);
1.1.1.11! root 776: printk("%d free pages via nr_free_pages\n\r", nr_free_pages);
1.1.1.4 root 777: k = 0;
778: for(i=4 ; i<1024 ;) {
1.1 root 779: if (1&pg_dir[i]) {
1.1.1.11! root 780: if (pg_dir[i]>high_memory) {
1.1.1.4 root 781: printk("page directory[%d]: %08X\n\r",
782: i,pg_dir[i]);
1.1.1.5 root 783: i++;
1.1.1.4 root 784: continue;
785: }
1.1.1.11! root 786: if (pg_dir[i]>low_memory)
1.1.1.4 root 787: free++,k++;
788: pg_tbl=(unsigned long *) (0xfffff000 & pg_dir[i]);
789: for(j=0 ; j<1024 ; j++)
1.1.1.11! root 790: if ((pg_tbl[j]&1) && pg_tbl[j]>low_memory)
! 791: if (pg_tbl[j]>high_memory)
1.1.1.4 root 792: printk("page_dir[%d][%d]: %08X\n\r",
793: i,j, pg_tbl[j]);
794: else
795: k++,free++;
796: }
797: i++;
798: if (!(i&15) && k) {
799: k++,free++; /* one page/process for task_struct */
800: printk("Process %d: %d pages\n\r",(i>>4)-1,k);
801: k = 0;
1.1 root 802: }
803: }
1.1.1.4 root 804: printk("Memory found: %d (%d)\n\r",free-shared,total);
1.1 root 805: }
1.1.1.5 root 806:
807:
808: /* This routine handles page faults. It determines the address,
809: and the problem then passes it off to one of the appropriate
810: routines. */
1.1.1.6 root 811: void do_page_fault(unsigned long *esp, unsigned long error_code)
1.1.1.5 root 812: {
813: unsigned long address;
1.1.1.8 root 814: unsigned long user_esp;
1.1.1.5 root 815:
1.1.1.8 root 816: if ((0xffff & esp[1]) == 0xf)
817: user_esp = esp[3];
818: else
819: user_esp = 0;
820: /* get the address */
1.1.1.6 root 821: __asm__("movl %%cr2,%0":"=r" (address));
1.1.1.5 root 822: if (!(error_code & 1)) {
1.1.1.8 root 823: do_no_page(error_code, address, current, user_esp);
1.1.1.5 root 824: return;
825: } else {
1.1.1.11! root 826: do_wp_page(error_code, address, current, user_esp);
1.1.1.5 root 827: return;
828: }
829: }
1.1.1.11! root 830:
! 831: unsigned long mem_init(unsigned long start_mem, unsigned long end_mem)
! 832: {
! 833: end_mem &= 0xfffff000;
! 834: high_memory = end_mem;
! 835: mem_map = (char *) start_mem;
! 836: paging_pages = (end_mem - start_mem) >> 12;
! 837: start_mem += paging_pages;
! 838: start_mem += 0xfff;
! 839: start_mem &= 0xfffff000;
! 840: low_memory = start_mem;
! 841: paging_pages = (high_memory - low_memory) >> 12;
! 842: swap_device = 0;
! 843: swap_file = NULL;
! 844: memset(mem_map,0,paging_pages);
! 845: nr_free_pages = paging_pages;
! 846: return start_mem;
! 847: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.