This source file includes following definitions.
- oom
- free_page
- free_page_tables
- copy_page_tables
- unmap_page_range
- remap_page_range
- put_page
- put_dirty_page
- un_wp_page
- do_wp_page
- write_verify
- get_empty_page
- try_to_share
- share_page
- get_empty_pgtable
- do_no_page
- show_mem
- do_page_fault
- mem_init
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31 #include <asm/system.h>
32
33 #include <linux/signal.h>
34 #include <linux/sched.h>
35 #include <linux/head.h>
36 #include <linux/kernel.h>
37 #include <linux/string.h>
38
39 #define CODE_SPACE(addr) ((((addr)+4095)&~4095) < \
40 current->start_code + current->end_code)
41
42 unsigned long low_memory = 0;
43 unsigned long high_memory = 0;
44 unsigned long paging_pages = 0;
45
46 #define copy_page(from,to) \
47 __asm__("cld ; rep ; movsl"::"S" (from),"D" (to),"c" (1024):"cx","di","si")
48
49 unsigned char * mem_map = NULL;
50
51
52
53
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 }
62
63 int nr_free_pages = 0;
64
65
66
67
68 void free_page(unsigned long addr)
69 {
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]--)
80 return;
81 mem_map[i] = 0;
82 }
83 printk("trying to free free page (%08x): memory probably corrupted\n",addr);
84 }
85
86
87
88
89
90 int free_page_tables(unsigned long from,unsigned long size)
91 {
92 unsigned long page;
93 unsigned long page_dir;
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);
103 for ( ; size-->0 ; dir++) {
104 if (!(page_dir = *dir))
105 continue;
106 *dir = 0;
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);
122 }
123 invalidate();
124 return 0;
125 }
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
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;
150 unsigned long new_page;
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);
156 to_dir = (unsigned long *) ((to>>20) & 0xffc);
157 size = ((unsigned) (size+0x3fffff)) >> 22;
158 for( ; size-->0 ; from_dir++,to_dir++) {
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;
168 continue;
169 }
170 from_page_table = (unsigned long *) (0xfffff000 & *from_dir);
171 if (!(to_page_table = (unsigned long *) get_free_page(GFP_KERNEL)))
172 return -1;
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++) {
176 repeat:
177 this_page = *from_page_table;
178 if (!this_page)
179 continue;
180 if (!(1 & this_page)) {
181 if (!(new_page = get_free_page(GFP_KERNEL)))
182 return -1;
183 ++current->rss;
184 read_swap_page(this_page>>1, (char *) new_page);
185 if (*from_page_table != this_page) {
186 free_page(new_page);
187 goto repeat;
188 }
189 *to_page_table = this_page;
190 *from_page_table = new_page | (PAGE_DIRTY | 7);
191 continue;
192 }
193 this_page &= ~2;
194 *to_page_table = this_page;
195 if (this_page > low_memory) {
196 *from_page_table = this_page;
197 this_page -= low_memory;
198 this_page >>= 12;
199 if (!mem_map[this_page]++)
200 --nr_free_pages;
201 }
202 }
203 }
204 invalidate();
205 return 0;
206 }
207
208
209
210
211
212 int unmap_page_range(unsigned long from, unsigned long size)
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);
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
264
265
266
267
268
269
270
271
272
273
274
275
276 int remap_page_range(unsigned long from, unsigned long to, unsigned long size,
277 int permiss)
278 {
279 unsigned long *page_table, *dir;
280 unsigned long poff, pcnt;
281 unsigned long page;
282
283 if ((from & 0xfff) || (to & 0xfff))
284 panic("remap_page_range called with wrong alignment");
285 dir = (unsigned long *) ((from >> 20) & 0xffc);
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)) {
293 if (!(page_table = (unsigned long *)get_free_page(GFP_KERNEL))) {
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
321 if (page = *page_table) {
322 *page_table = 0;
323 --current->rss;
324 if (1 & page)
325 free_page(0xfffff000 & page);
326 else
327 swap_free(page >> 1);
328 }
329
330
331
332
333
334
335
336
337 if (mask == 4 || to >= high_memory)
338 *page_table++ = 0;
339 else {
340 ++current->rss;
341 *page_table++ = (to | mask);
342 if (to > low_memory) {
343 unsigned long frame;
344 frame = to - low_memory;
345 frame >>= 12;
346 if (!mem_map[frame]++)
347 --nr_free_pages;
348 }
349 }
350 to += PAGE_SIZE;
351 }
352 pcnt = (size > 1024 ? 1024 : size);
353 }
354 invalidate();
355 return 0;
356 }
357
358
359
360
361
362
363
364 static unsigned long put_page(unsigned long page,unsigned long address)
365 {
366 unsigned long tmp, *page_table;
367
368
369
370 if (page >= high_memory) {
371 printk("put_page: trying to put page %p at %p\n",page,address);
372 return 0;
373 }
374 if (page >= low_memory && mem_map[(page-low_memory)>>12] != 1) {
375 printk("put_page: mem_map disagrees with %p at %p\n",page,address);
376 return 0;
377 }
378 page_table = (unsigned long *) ((address>>20) & 0xffc);
379 if ((*page_table)&1)
380 page_table = (unsigned long *) (0xfffff000 & *page_table);
381 else {
382 tmp = get_free_page(GFP_KERNEL);
383 if (!tmp) {
384 oom(current);
385 tmp = BAD_PAGETABLE;
386 }
387 *page_table = tmp | 7;
388 return 0;
389 }
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;
397
398 return page;
399 }
400
401
402
403
404
405
406
407 unsigned long put_dirty_page(unsigned long page, unsigned long address)
408 {
409 unsigned long tmp, *page_table;
410
411
412
413 if (page < low_memory || page >= high_memory)
414 printk("put_dirty_page: trying to put page %p at %p\n",page,address);
415 if (mem_map[(page-low_memory)>>12] != 1)
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 {
421 if (!(tmp=get_free_page(GFP_KERNEL)))
422 return 0;
423 *page_table = tmp|7;
424 page_table = (unsigned long *) tmp;
425 }
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);
433
434 return page;
435 }
436
437 static void un_wp_page(unsigned long * table_entry, struct task_struct * task)
438 {
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 }
450 dirty = old_page & PAGE_DIRTY;
451 old_page &= 0xfffff000;
452 if (old_page >= high_memory) {
453 if (new_page)
454 free_page(new_page);
455 printk("bad page address\n\r");
456 send_sig(SIGSEGV, task, 1);
457 *table_entry = BAD_PAGE | 7;
458 return;
459 }
460 if (old_page >= low_memory && mem_map[MAP_NR(old_page)]==1) {
461 *table_entry |= 2;
462 invalidate();
463 if (new_page)
464 free_page(new_page);
465 return;
466 }
467 if (!new_page && (new_page=get_free_page(GFP_KERNEL)))
468 goto repeat;
469 if (new_page)
470 copy_page(old_page,new_page);
471 else {
472 new_page = BAD_PAGE;
473 send_sig(SIGSEGV,task,1);
474 }
475 *table_entry = new_page | dirty | 7;
476 free_page(old_page);
477 invalidate();
478 }
479
480
481
482
483
484
485
486
487 void do_wp_page(unsigned long error_code, unsigned long address,
488 struct task_struct * tsk, unsigned long user_esp)
489 {
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 }
500 if (address < TASK_SIZE) {
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;
505 }
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;
514 }
515 ++current->min_flt;
516 un_wp_page((unsigned long *) pte, tsk);
517 }
518
519 void write_verify(unsigned long address)
520 {
521 unsigned long page;
522
523 page = *(unsigned long *) ((address>>20) & 0xffc);
524 if (!(page & PAGE_PRESENT))
525 return;
526 page &= 0xfffff000;
527 page += ((address>>10) & 0xffc);
528 if ((3 & *(unsigned long *) page) == 1)
529 un_wp_page((unsigned long *) page, current);
530 return;
531 }
532
533 static void get_empty_page(unsigned long address)
534 {
535 unsigned long tmp;
536
537 tmp = get_free_page(GFP_KERNEL);
538 if (!tmp) {
539 oom(current);
540 tmp = BAD_PAGE;
541 }
542 if (!put_page(tmp,address))
543 free_page(tmp);
544 }
545
546
547
548
549
550
551
552
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
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
573 if ((phys_addr & 0x41) != 0x01)
574 return 0;
575 phys_addr &= 0xfffff000;
576 if (phys_addr >= high_memory || phys_addr < low_memory)
577 return 0;
578 to = *(unsigned long *) to_page;
579 if (!(to & 1)) {
580 to = get_free_page(GFP_KERNEL);
581 if (!to)
582 return 0;
583 *(unsigned long *) to_page = to | 7;
584 }
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
590 *(unsigned long *) from_page &= ~2;
591 *(unsigned long *) to_page = *(unsigned long *) from_page;
592 invalidate();
593 phys_addr -= low_memory;
594 phys_addr >>= 12;
595 if (!mem_map[phys_addr]++)
596 --nr_free_pages;
597 return 1;
598 }
599
600
601
602
603
604
605
606
607
608 static int share_page(struct inode * inode, unsigned long address)
609 {
610 struct task_struct ** p;
611 int i;
612
613 if (!inode || inode->i_count < 2)
614 return 0;
615 for (p = &LAST_TASK ; p > &FIRST_TASK ; --p) {
616 if (!*p)
617 continue;
618 if (current == *p)
619 continue;
620 if (address < LIBRARY_OFFSET) {
621 if (inode != (*p)->executable)
622 continue;
623 } else {
624 for (i=0; i < (*p)->numlibraries; i++)
625 if (inode == (*p)->libraries[i].library)
626 break;
627 if (i >= (*p)->numlibraries)
628 continue;
629 }
630 if (try_to_share(address,*p))
631 return 1;
632 }
633 return 0;
634 }
635
636
637
638
639 static unsigned long get_empty_pgtable(unsigned long * p)
640 {
641 unsigned long page = 0;
642
643 repeat:
644 if (1 & *p) {
645 free_page(page);
646 return *p;
647 }
648 if (*p) {
649 printk("get_empty_pgtable: bad page-directory entry \n");
650 *p = 0;
651 }
652 if (page) {
653 *p = page | 7;
654 return *p;
655 }
656 if (page = get_free_page(GFP_KERNEL))
657 goto repeat;
658 oom(current);
659 *p = BAD_PAGETABLE | 7;
660 return 0;
661 }
662
663 void do_no_page(unsigned long error_code, unsigned long address,
664 struct task_struct *tsk, unsigned long user_esp)
665 {
666 int nr[4];
667 unsigned long tmp;
668 unsigned long page;
669 unsigned int block,i;
670 struct inode * inode;
671
672 if (address < TASK_SIZE) {
673 printk("\n\rBAD!! KERNEL PAGE MISSING\n\r");
674 do_exit(SIGSEGV);
675 }
676 if (address - tsk->start_code >= TASK_SIZE) {
677 printk("Bad things happen: nonexistent page error in do_no_page\n\r");
678 do_exit(SIGSEGV);
679 }
680 page = get_empty_pgtable((unsigned long *) ((address >> 20) & 0xffc));
681 if (!page)
682 return;
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 }
690 ++tsk->rss;
691 if (tmp) {
692 ++tsk->maj_flt;
693 swap_in((unsigned long *) page);
694 return;
695 }
696 address &= 0xfffff000;
697 tmp = address - tsk->start_code;
698 inode = NULL;
699 block = 0;
700 if (tmp < tsk->end_data) {
701 inode = tsk->executable;
702 block = 1 + tmp / BLOCK_SIZE;
703 } else {
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 }
715 }
716 if (!inode) {
717 ++tsk->min_flt;
718 get_empty_page(address);
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);
726 return;
727 }
728 if (tsk == current)
729 if (share_page(inode,tmp)) {
730 ++tsk->min_flt;
731 return;
732 }
733 ++tsk->maj_flt;
734 page = get_free_page(GFP_KERNEL);
735 if (!page) {
736 oom(current);
737 put_page(BAD_PAGE,address);
738 return;
739 }
740 for (i=0 ; i<4 ; block++,i++)
741 nr[i] = bmap(inode,block);
742 bread_page(page,inode->i_dev,nr);
743 i = tmp + 4096 - tsk->end_data;
744 if (i>4095)
745 i = 0;
746 tmp = page + 4096;
747 while (i--) {
748 tmp--;
749 *(char *)tmp = 0;
750 }
751 if (put_page(page,address))
752 return;
753 free_page(page);
754 oom(current);
755 }
756
757 void show_mem(void)
758 {
759 int i,j,k,free=0,total=0;
760 int shared = 0;
761 unsigned long * pg_tbl;
762
763 printk("Mem-info:\n\r");
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++) {
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);
776 printk("%d free pages via nr_free_pages\n\r", nr_free_pages);
777 k = 0;
778 for(i=4 ; i<1024 ;) {
779 if (1&pg_dir[i]) {
780 if (pg_dir[i]>high_memory) {
781 printk("page directory[%d]: %08X\n\r",
782 i,pg_dir[i]);
783 i++;
784 continue;
785 }
786 if (pg_dir[i]>low_memory)
787 free++,k++;
788 pg_tbl=(unsigned long *) (0xfffff000 & pg_dir[i]);
789 for(j=0 ; j<1024 ; j++)
790 if ((pg_tbl[j]&1) && pg_tbl[j]>low_memory)
791 if (pg_tbl[j]>high_memory)
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++;
800 printk("Process %d: %d pages\n\r",(i>>4)-1,k);
801 k = 0;
802 }
803 }
804 printk("Memory found: %d (%d)\n\r",free-shared,total);
805 }
806
807
808
809
810
811 void do_page_fault(unsigned long *esp, unsigned long error_code)
812 {
813 unsigned long address;
814 unsigned long user_esp;
815
816 if ((0xffff & esp[1]) == 0xf)
817 user_esp = esp[3];
818 else
819 user_esp = 0;
820
821 __asm__("movl %%cr2,%0":"=r" (address));
822 if (!(error_code & 1)) {
823 do_no_page(error_code, address, current, user_esp);
824 return;
825 } else {
826 do_wp_page(error_code, address, current, user_esp);
827 return;
828 }
829 }
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 }