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