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

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

unix.superglobalmegacorp.com

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