|
|
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.