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

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

unix.superglobalmegacorp.com

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