root/mm/memory.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. oom
  2. free_page
  3. free_page_tables
  4. copy_page_tables
  5. unmap_page_range
  6. remap_page_range
  7. put_page
  8. put_dirty_page
  9. un_wp_page
  10. do_wp_page
  11. write_verify
  12. get_empty_page
  13. try_to_share
  14. share_page
  15. get_empty_pgtable
  16. do_no_page
  17. show_mem
  18. do_page_fault
  19. mem_init

   1 /*
   2  *  linux/mm/memory.c
   3  *
   4  *  Copyright (C) 1991, 1992  Linus Torvalds
   5  */
   6 
   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 
  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 
  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  * 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)
     /* [previous][next][first][last][top][bottom][index][help] */
  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  * Free a page of memory at physical address 'addr'. Used by
  66  * 'free_page_tables()'
  67  */
  68 void free_page(unsigned long addr)
     /* [previous][next][first][last][top][bottom][index][help] */
  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  * 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)
     /* [previous][next][first][last][top][bottom][index][help] */
  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); /* _pg_dir = 0 */
 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  *  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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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); /* _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++) {
 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;      /* 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++) {
 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  * a more complete version of free_page_tables which performs with page
 210  * granularity.
 211  */
 212 int unmap_page_range(unsigned long from, unsigned long size)
     /* [previous][next][first][last][top][bottom][index][help] */
 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  */
 276 int remap_page_range(unsigned long from, unsigned long to, unsigned long size,
     /* [previous][next][first][last][top][bottom][index][help] */
 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); /* _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)) {
 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                          * 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                          */
 337                         if (mask == 4 || to >= high_memory)
 338                                 *page_table++ = 0;      /* not present */
 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  * 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  */
 364 static unsigned long put_page(unsigned long page,unsigned long address)
     /* [previous][next][first][last][top][bottom][index][help] */
 365 {
 366         unsigned long tmp, *page_table;
 367 
 368 /* NOTE !!! This uses the fact that _pg_dir=0 */
 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 /* no need for invalidate */
 398         return page;
 399 }
 400 
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 408 {
 409         unsigned long tmp, *page_table;
 410 
 411 /* NOTE !!! This uses the fact that _pg_dir=0 */
 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 /* no need for invalidate */
 434         return page;
 435 }
 436 
 437 static void un_wp_page(unsigned long * table_entry, struct task_struct * task)
     /* [previous][next][first][last][top][bottom][index][help] */
 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  * 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.
 484  *
 485  * If it's in code space we exit with a segment error.
 486  */
 487 void do_wp_page(unsigned long error_code, unsigned long address,
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)  /* non-writeable, present */
 529                 un_wp_page((unsigned long *) page, current);
 530         return;
 531 }
 532 
 533 static void get_empty_page(unsigned long address)
     /* [previous][next][first][last][top][bottom][index][help] */
 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  * 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
 552  * share the same executable or library.
 553  */
 554 static int try_to_share(unsigned long address, struct task_struct * p)
     /* [previous][next][first][last][top][bottom][index][help] */
 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;
 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 /* share them: write-protect */
 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  * 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  */
 608 static int share_page(struct inode * inode, unsigned long address)
     /* [previous][next][first][last][top][bottom][index][help] */
 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  * fill in an empty page-table if none exists
 638  */
 639 static unsigned long get_empty_pgtable(unsigned long * p)
     /* [previous][next][first][last][top][bottom][index][help] */
 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,
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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++;     /* one page/process for task_struct */
 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 /* This routine handles page faults.  It determines the address,
 809    and the problem then passes it off to one of the appropriate
 810    routines. */
 811 void do_page_fault(unsigned long *esp, unsigned long error_code)
     /* [previous][next][first][last][top][bottom][index][help] */
 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         /* get the address */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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 }

/* [previous][next][first][last][top][bottom][index][help] */