Annotation of linux/mm/memory.c, revision 1.1.1.11

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.