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