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

1.1       root        1: #include <signal.h>
                      2: 
                      3: #include <linux/config.h>
                      4: #include <linux/head.h>
                      5: #include <linux/kernel.h>
                      6: #include <asm/system.h>
                      7: 
                      8: int do_exit(long code);
                      9: 
                     10: #define invalidate() \
                     11: __asm__("movl %%eax,%%cr3"::"a" (0))
                     12: 
                     13: #if (BUFFER_END < 0x100000)
                     14: #define LOW_MEM 0x100000
                     15: #else
                     16: #define LOW_MEM BUFFER_END
                     17: #endif
                     18: 
                     19: /* these are not to be changed - thay are calculated from the above */
                     20: #define PAGING_MEMORY (HIGH_MEMORY - LOW_MEM)
                     21: #define PAGING_PAGES (PAGING_MEMORY/4096)
                     22: #define MAP_NR(addr) (((addr)-LOW_MEM)>>12)
                     23: 
                     24: #if (PAGING_PAGES < 10)
                     25: #error "Won't work"
                     26: #endif
                     27: 
                     28: #define copy_page(from,to) \
                     29: __asm__("cld ; rep ; movsl"::"S" (from),"D" (to),"c" (1024):"cx","di","si")
                     30: 
                     31: static unsigned short mem_map [ PAGING_PAGES ] = {0,};
                     32: 
                     33: /*
                     34:  * Get physical address of first (actually last :-) free page, and mark it
                     35:  * used. If no free pages left, return 0.
                     36:  */
                     37: unsigned long get_free_page(void)
                     38: {
                     39: register unsigned long __res asm("ax");
                     40: 
                     41: __asm__("std ; repne ; scasw\n\t"
                     42:        "jne 1f\n\t"
                     43:        "movw $1,2(%%edi)\n\t"
                     44:        "sall $12,%%ecx\n\t"
                     45:        "movl %%ecx,%%edx\n\t"
                     46:        "addl %2,%%edx\n\t"
                     47:        "movl $1024,%%ecx\n\t"
                     48:        "leal 4092(%%edx),%%edi\n\t"
                     49:        "rep ; stosl\n\t"
                     50:        "movl %%edx,%%eax\n"
                     51:        "1:"
                     52:        :"=a" (__res)
                     53:        :"0" (0),"i" (LOW_MEM),"c" (PAGING_PAGES),
                     54:        "D" (mem_map+PAGING_PAGES-1)
                     55:        :"di","cx","dx");
                     56: return __res;
                     57: }
                     58: 
                     59: /*
                     60:  * Free a page of memory at physical address 'addr'. Used by
                     61:  * 'free_page_tables()'
                     62:  */
                     63: void free_page(unsigned long addr)
                     64: {
                     65:        if (addr<LOW_MEM) return;
                     66:        if (addr>HIGH_MEMORY)
                     67:                panic("trying to free nonexistent page");
                     68:        addr -= LOW_MEM;
                     69:        addr >>= 12;
                     70:        if (mem_map[addr]--) return;
                     71:        mem_map[addr]=0;
                     72:        panic("trying to free free page");
                     73: }
                     74: 
                     75: /*
                     76:  * This function frees a continuos block of page tables, as needed
                     77:  * by 'exit()'. As does copy_page_tables(), this handles only 4Mb blocks.
                     78:  */
                     79: int free_page_tables(unsigned long from,unsigned long size)
                     80: {
                     81:        unsigned long *pg_table;
                     82:        unsigned long * dir, nr;
                     83: 
                     84:        if (from & 0x3fffff)
                     85:                panic("free_page_tables called with wrong alignment");
                     86:        if (!from)
                     87:                panic("Trying to free up swapper memory space");
                     88:        size = (size + 0x3fffff) >> 22;
                     89:        dir = (unsigned long *) ((from>>20) & 0xffc); /* _pg_dir = 0 */
                     90:        for ( ; size-->0 ; dir++) {
                     91:                if (!(1 & *dir))
                     92:                        continue;
                     93:                pg_table = (unsigned long *) (0xfffff000 & *dir);
                     94:                for (nr=0 ; nr<1024 ; nr++) {
                     95:                        if (1 & *pg_table)
                     96:                                free_page(0xfffff000 & *pg_table);
                     97:                        *pg_table = 0;
                     98:                        pg_table++;
                     99:                }
                    100:                free_page(0xfffff000 & *dir);
                    101:                *dir = 0;
                    102:        }
                    103:        invalidate();
                    104:        return 0;
                    105: }
                    106: 
                    107: /*
                    108:  *  Well, here is one of the most complicated functions in mm. It
                    109:  * copies a range of linerar addresses by copying only the pages.
                    110:  * Let's hope this is bug-free, 'cause this one I don't want to debug :-)
                    111:  *
                    112:  * Note! We don't copy just any chunks of memory - addresses have to
                    113:  * be divisible by 4Mb (one page-directory entry), as this makes the
                    114:  * function easier. It's used only by fork anyway.
                    115:  *
                    116:  * NOTE 2!! When from==0 we are copying kernel space for the first
                    117:  * fork(). Then we DONT want to copy a full page-directory entry, as
                    118:  * that would lead to some serious memory waste - we just copy the
                    119:  * first 160 pages - 640kB. Even that is more than we need, but it
                    120:  * doesn't take any more memory - we don't copy-on-write in the low
                    121:  * 1 Mb-range, so the pages can be shared with the kernel. Thus the
                    122:  * special case for nr=xxxx.
                    123:  */
                    124: int copy_page_tables(unsigned long from,unsigned long to,long size)
                    125: {
                    126:        unsigned long * from_page_table;
                    127:        unsigned long * to_page_table;
                    128:        unsigned long this_page;
                    129:        unsigned long * from_dir, * to_dir;
                    130:        unsigned long nr;
                    131: 
                    132:        if ((from&0x3fffff) || (to&0x3fffff))
                    133:                panic("copy_page_tables called with wrong alignment");
                    134:        from_dir = (unsigned long *) ((from>>20) & 0xffc); /* _pg_dir = 0 */
                    135:        to_dir = (unsigned long *) ((to>>20) & 0xffc);
                    136:        size = ((unsigned) (size+0x3fffff)) >> 22;
                    137:        for( ; size-->0 ; from_dir++,to_dir++) {
                    138:                if (1 & *to_dir)
                    139:                        panic("copy_page_tables: already exist");
                    140:                if (!(1 & *from_dir))
                    141:                        continue;
                    142:                from_page_table = (unsigned long *) (0xfffff000 & *from_dir);
                    143:                if (!(to_page_table = (unsigned long *) get_free_page()))
                    144:                        return -1;      /* Out of memory, see freeing */
                    145:                *to_dir = ((unsigned long) to_page_table) | 7;
                    146:                nr = (from==0)?0xA0:1024;
                    147:                for ( ; nr-- > 0 ; from_page_table++,to_page_table++) {
                    148:                        this_page = *from_page_table;
                    149:                        if (!(1 & this_page))
                    150:                                continue;
                    151:                        this_page &= ~2;
                    152:                        *to_page_table = this_page;
                    153:                        if (this_page > LOW_MEM) {
                    154:                                *from_page_table = this_page;
                    155:                                this_page -= LOW_MEM;
                    156:                                this_page >>= 12;
                    157:                                mem_map[this_page]++;
                    158:                        }
                    159:                }
                    160:        }
                    161:        invalidate();
                    162:        return 0;
                    163: }
                    164: 
                    165: /*
                    166:  * This function puts a page in memory at the wanted address.
                    167:  * It returns the physical address of the page gotten, 0 if
                    168:  * out of memory (either when trying to access page-table or
                    169:  * page.)
                    170:  */
                    171: unsigned long put_page(unsigned long page,unsigned long address)
                    172: {
                    173:        unsigned long tmp, *page_table;
                    174: 
                    175: /* NOTE !!! This uses the fact that _pg_dir=0 */
                    176: 
                    177:        if (page < LOW_MEM || page > HIGH_MEMORY)
                    178:                printk("Trying to put page %p at %p\n",page,address);
                    179:        if (mem_map[(page-LOW_MEM)>>12] != 1)
                    180:                printk("mem_map disagrees with %p at %p\n",page,address);
                    181:        page_table = (unsigned long *) ((address>>20) & 0xffc);
                    182:        if ((*page_table)&1)
                    183:                page_table = (unsigned long *) (0xfffff000 & *page_table);
                    184:        else {
                    185:                if (!(tmp=get_free_page()))
                    186:                        return 0;
                    187:                *page_table = tmp|7;
                    188:                page_table = (unsigned long *) tmp;
                    189:        }
                    190:        page_table[(address>>12) & 0x3ff] = page | 7;
                    191:        return page;
                    192: }
                    193: 
                    194: void un_wp_page(unsigned long * table_entry)
                    195: {
                    196:        unsigned long old_page,new_page;
                    197: 
                    198:        old_page = 0xfffff000 & *table_entry;
                    199:        if (old_page >= LOW_MEM && mem_map[MAP_NR(old_page)]==1) {
                    200:                *table_entry |= 2;
                    201:                return;
                    202:        }
                    203:        if (!(new_page=get_free_page()))
                    204:                do_exit(SIGSEGV);
                    205:        if (old_page >= LOW_MEM)
                    206:                mem_map[MAP_NR(old_page)]--;
                    207:        *table_entry = new_page | 7;
                    208:        copy_page(old_page,new_page);
                    209: }      
                    210: 
                    211: /*
                    212:  * This routine handles present pages, when users try to write
                    213:  * to a shared page. It is done by copying the page to a new address
                    214:  * and decrementing the shared-page counter for the old page.
                    215:  */
                    216: void do_wp_page(unsigned long error_code,unsigned long address)
                    217: {
                    218:        un_wp_page((unsigned long *)
                    219:                (((address>>10) & 0xffc) + (0xfffff000 &
                    220:                *((unsigned long *) ((address>>20) &0xffc)))));
                    221: 
                    222: }
                    223: 
                    224: void write_verify(unsigned long address)
                    225: {
                    226:        unsigned long page;
                    227: 
                    228:        if (!( (page = *((unsigned long *) ((address>>20) & 0xffc)) )&1))
                    229:                return;
                    230:        page &= 0xfffff000;
                    231:        page += ((address>>10) & 0xffc);
                    232:        if ((3 & *(unsigned long *) page) == 1)  /* non-writeable, present */
                    233:                un_wp_page((unsigned long *) page);
                    234:        return;
                    235: }
                    236: 
                    237: void do_no_page(unsigned long error_code,unsigned long address)
                    238: {
                    239:        unsigned long tmp;
                    240: 
                    241:        if (tmp=get_free_page())
                    242:                if (put_page(tmp,address))
                    243:                        return;
                    244:        do_exit(SIGSEGV);
                    245: }
                    246: 
                    247: void calc_mem(void)
                    248: {
                    249:        int i,j,k,free=0;
                    250:        long * pg_tbl;
                    251: 
                    252:        for(i=0 ; i<PAGING_PAGES ; i++)
                    253:                if (!mem_map[i]) free++;
                    254:        printk("%d pages free (of %d)\n\r",free,PAGING_PAGES);
                    255:        for(i=2 ; i<1024 ; i++) {
                    256:                if (1&pg_dir[i]) {
                    257:                        pg_tbl=(long *) (0xfffff000 & pg_dir[i]);
                    258:                        for(j=k=0 ; j<1024 ; j++)
                    259:                                if (pg_tbl[j]&1)
                    260:                                        k++;
                    261:                        printk("Pg-dir[%d] uses %d pages\n",i,k);
                    262:                }
                    263:        }
                    264: }

unix.superglobalmegacorp.com

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