Ядро Linux в комментариях

       

Arch/i386/mm/init.c


7148 /* 7149 * linux/arch/i386/mm/init.c 7150 * 7151 * Copyright (C) 1995 Linus Torvalds 7152 */ 7153 7154 #include <linux/config.h> 7155 #include <linux/signal.h> 7156 #include <linux/sched.h> 7157 #include <linux/kernel.h> 7158 #include <linux/errno.h> 7159 #include <linux/string.h> 7160 #include <linux/types.h> 7161 #include <linux/ptrace.h> 7162 #include <linux/mman.h> 7163 #include <linux/mm.h> 7164 #include <linux/swap.h> 7165 #include <linux/smp.h> 7166 #include <linux/init.h> 7167 #ifdef CONFIG_BLK_DEV_INITRD 7168 #include <linux/blk.h> 7169 #endif 7170 7171 #include <asm/processor.h> 7172 #include <asm/system.h> 7173 #include <asm/uaccess.h> 7174 #include <asm/pgtable.h> 7175 #include <asm/dma.h> 7176 #include <asm/fixmap.h> 7177 7178 extern void show_net_buffers(void); 7179 extern unsigned long init_smp_mappings(unsigned long); 7180 7181 void __bad_pte_kernel(pmd_t *pmd) 7182 { 7183 printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd)); 7184 pmd_val(*pmd) = _KERNPG_TABLE + __pa(BAD_PAGETABLE); 7185 } 7186 7187 void __bad_pte(pmd_t *pmd) 7188 { 7189 printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd)); 7190 pmd_val(*pmd) = _PAGE_TABLE + __pa(BAD_PAGETABLE); 7191 } 7192 7193 pte_t *get_pte_kernel_slow(pmd_t *pmd, 7194 unsigned long offset) 7195 { 7196 pte_t *pte; 7197 7198 pte = (pte_t *) __get_free_page(GFP_KERNEL); 7199 if (pmd_none(*pmd)) { 7200 if (pte) { 7201 clear_page((unsigned long)pte); 7202 pmd_val(*pmd) = _KERNPG_TABLE + __pa(pte); 7203 return pte + offset; 7204 } 7205 pmd_val(*pmd) = _KERNPG_TABLE + __pa(BAD_PAGETABLE); 7206 return NULL; 7207 } 7208 free_page((unsigned long)pte); 7209 if (pmd_bad(*pmd)) { 7210 __bad_pte_kernel(pmd); 7211 return NULL; 7212 } 7213 return (pte_t *) pmd_page(*pmd) + offset; 7214 } 7215 7216 pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset) 7217 { 7218 unsigned long pte; 7219 7220 pte = (unsigned long) __get_free_page(GFP_KERNEL); 7221 if (pmd_none(*pmd)) { 7222 if (pte) { 7223 clear_page(pte); 7224 pmd_val(*pmd) = _PAGE_TABLE + __pa(pte); 7225 return (pte_t *)(pte + offset); 7226 } 7227 pmd_val(*pmd) = _PAGE_TABLE + __pa(BAD_PAGETABLE); 7228 return NULL; 7229 } 7230 free_page(pte); 7231 if (pmd_bad(*pmd)) { 7232 __bad_pte(pmd); 7233 return NULL; 7234 } 7235 return (pte_t *) (pmd_page(*pmd) + offset); 7236 } 7237 7238 int do_check_pgt_cache(int low, int high) 7239 { 7240 int freed = 0; 7241 if(pgtable_cache_size > high) { 7242 do { 7243 if(pgd_quicklist) 7244 free_pgd_slow(get_pgd_fast()), freed++; 7245 if(pmd_quicklist) 7246 free_pmd_slow(get_pmd_fast()), freed++; 7247 if(pte_quicklist) 7248 free_pte_slow(get_pte_fast()), freed++; 7249 } while(pgtable_cache_size > low); 7250 } 7251 return freed; 7252 } 7253 7254 /* BAD_PAGE is the page that is used for page faults when 7255 * linux is out-of-memory. Older versions of linux just 7256 * did a do_exit(), but using this instead means there is 7257 * less risk for a process dying in kernel mode, possibly 7258 * leaving an inode unused etc.. 7259 * 7260 * BAD_PAGETABLE is the accompanying page-table: it is 7261 * initialized to point to BAD_PAGE entries. 7262 * 7263 * ZERO_PAGE is a special page that is used for 7264 * zero-initialized data and COW. */ 7265 pte_t * __bad_pagetable(void) 7266 { 7267 extern char empty_bad_page_table[PAGE_SIZE]; 7268 int d0, d1; 7269 7270 __asm__ __volatile__("cld ; rep ; stosl" 7271 : "=&D" (d0), "=&c" (d1) 7272 : "a" (pte_val(BAD_PAGE)), 7273 "0" ((long) empty_bad_page_table), 7274 "1" (PAGE_SIZE/4) 7275 : "memory"); 7276 return (pte_t *) empty_bad_page_table; 7277 } 7278 7279 pte_t __bad_page(void) 7280 { 7281 extern char empty_bad_page[PAGE_SIZE]; 7282 int d0, d1; 7283 7284 __asm__ __volatile__("cld ; rep ; stosl" 7285 : "=&D" (d0), "=&c" (d1) 7286 : "a" (0), 7287 "0" ((long) empty_bad_page), 7288 "1" (PAGE_SIZE/4) 7289 : "memory"); 7290 return pte_mkdirty(mk_pte((unsigned long)empty_bad_page 7291 , PAGE_SHARED)); 7292 } 7293 7294 void show_mem(void) 7295 { 7296 int i,free = 0,total = 0,reserved = 0; 7297 int shared = 0, cached = 0; 7298 7299 printk("Mem-info:\n"); 7300 show_free_areas(); 7301 printk("Free swap: %6dkB\n", 7302 nr_swap_pages<<(PAGE_SHIFT-10)); 7303 i = max_mapnr; 7304 while (i-- > 0) { 7305 total++; 7306 if (PageReserved(mem_map+i)) 7307 reserved++; 7308 else if (PageSwapCache(mem_map+i)) 7309 cached++; 7310 else if (!atomic_read(&mem_map[i].count)) 7311 free++; 7312 else 7313 shared += atomic_read(&mem_map[i].count) - 1; 7314 } 7315 printk("%d pages of RAM\n",total); 7316 printk("%d reserved pages\n",reserved); 7317 printk("%d pages shared\n",shared); 7318 printk("%d pages swap cached\n",cached); 7319 printk("%ld pages in page table cache\n", 7320 pgtable_cache_size); 7321 show_buffers(); 7322 #ifdef CONFIG_NET 7323 show_net_buffers(); 7324 #endif 7325 } 7326 7327 extern unsigned long free_area_init(unsigned long, 7328 unsigned long); 7329 7330 /* References to section boundaries */ 7331 7332 extern char _text, _etext, _edata, __bss_start, _end; 7333 extern char __init_begin, __init_end; 7334 7335 #define X86_CR4_VME 0x0001 /* enable vm86 extensions */ 7336 #define X86_CR4_PVI 0x0002 /* virt intrs flag enable */ 7337 #define X86_CR4_TSD 0x0004 /* disable tm stamp at ipl 3*/ 7338 #define X86_CR4_DE 0x0008 /* enable debug extensions */ 7339 #define X86_CR4_PSE 0x0010 /* enable pg size extensions*/ 7340 #define X86_CR4_PAE 0x0020 /* enable phys addr extnsns */ 7341 #define X86_CR4_MCE 0x0040 /* Machine check enable */ 7342 #define X86_CR4_PGE 0x0080 /* enable global pages */ 7343 #define X86_CR4_PCE 0x0100 /* enable performance counters 7344 * at ipl 3 */ 7345 7346 /* Save the cr4 feature set we're using (ie Pentium 4MB 7347 * enable and PPro Global page enable), so that any CPU's 7348 * that boot up after us can get the correct flags. */ 7349 unsigned long mmu_cr4_features __initdata = 0; 7350 7351 static inline void set_in_cr4(unsigned long mask) 7352 { 7353 mmu_cr4_features |= mask; 7354 __asm__("movl %%cr4,%%eax\n\t" 7355 "orl %0,%%eax\n\t" 7356 "movl %%eax,%%cr4\n" 7357 : : "irg" (mask) 7358 :"ax"); 7359 } 7360 7361 /* allocate page table(s) for compile-time fixed 7362 * mappings */ 7363 static unsigned long __init fixmap_init( 7364 unsigned long start_mem) 7365 { 7366 pgd_t * pg_dir; 7367 unsigned int idx; 7368 unsigned long address; 7369 7370 start_mem = PAGE_ALIGN(start_mem); 7371 7372 for (idx=1; idx <= __end_of_fixed_addresses; 7373 idx += PTRS_PER_PTE) 7374 { 7375 address =__fix_to_virt(__end_of_fixed_addresses-idx); 7376 pg_dir = swapper_pg_dir + (address >> PGDIR_SHIFT); 7377 memset((void *)start_mem, 0, PAGE_SIZE); 7378 pgd_val(*pg_dir) = _PAGE_TABLE | __pa(start_mem); 7379 start_mem += PAGE_SIZE; 7380 } 7381 7382 return start_mem; 7383 } 7384 7385 static void set_pte_phys (unsigned long vaddr, 7386 unsigned long phys) 7387 { 7388 pgprot_t prot; 7389 pte_t * pte; 7390 7391 pte = pte_offset(pmd_offset(pgd_offset_k(vaddr), vaddr) 7392 , vaddr); 7393 prot = PAGE_KERNEL; 7394 if (boot_cpu_data.x86_capability & X86_FEATURE_PGE) 7395 pgprot_val(prot) |= _PAGE_GLOBAL; 7396 set_pte(pte, mk_pte_phys(phys, prot)); 7397 7398 local_flush_tlb(); 7399 } 7400 7401 void set_fixmap (enum fixed_addresses idx, 7402 unsigned long phys) 7403 { 7404 unsigned long address = __fix_to_virt(idx); 7405 7406 if (idx >= __end_of_fixed_addresses) { 7407 printk("Invalid set_fixmap\n"); 7408 return; 7409 } 7410 set_pte_phys (address,phys); 7411 } 7412 7413 /* paging_init() sets up the page tables - note that the 7414 * first 4MB are already mapped by head.S. 7415 * 7416 * This routines also unmaps the page at virtual kernel 7417 * address 0, so that we can trap those pesky 7418 * NULL-reference errors in the kernel. */ 7419 __initfunc(unsigned long paging_init( 7420 unsigned long start_mem, unsigned long end_mem)) 7421 { 7422 pgd_t * pg_dir; 7423 pte_t * pg_table; 7424 unsigned long tmp; 7425 unsigned long address; 7426 7427 /* Physical page 0 is special; it's not touched by Linux 7428 * since BIOS and SMM (for laptops with [34]86/SL chips) 7429 * may need it. It is read and write protected to detect 7430 * null pointer references in the kernel. It may also 7431 * hold the MP configuration table when we are booting 7432 * SMP. */ 7433 start_mem = PAGE_ALIGN(start_mem); 7434 address = PAGE_OFFSET; 7435 pg_dir = swapper_pg_dir; 7436 /* unmap the original low memory mappings */ 7437 pgd_val(pg_dir[0]) = 0; 7438 7439 /* Map whole memory from PAGE_OFFSET */ 7440 pg_dir += USER_PGD_PTRS; 7441 while (address < end_mem) { 7442 /* If we're running on a Pentium CPU, we can use the 7443 * 4MB page tables. 7444 * 7445 * The page tables we create span up to the next 4MB 7446 * virtual memory boundary, but that's OK as we won't 7447 * use that memory anyway. */ 7448 if (boot_cpu_data.x86_capability & X86_FEATURE_PSE) { 7449 unsigned long __pe; 7450 7451 set_in_cr4(X86_CR4_PSE); 7452 boot_cpu_data.wp_works_ok = 1; 7453 __pe = _KERNPG_TABLE + _PAGE_4M + __pa(address); 7454 /* Make it "global" too if supported */ 7455 if(boot_cpu_data.x86_capability & X86_FEATURE_PGE){ 7456 set_in_cr4(X86_CR4_PGE); 7457 __pe += _PAGE_GLOBAL; 7458 } 7459 pgd_val(*pg_dir) = __pe; 7460 pg_dir++; 7461 address += 4*1024*1024; 7462 continue; 7463 } 7464 7465 /* We're on a [34]86, use normal page tables. 7466 * pg_table is physical at this point */ 7467 pg_table = (pte_t *) (PAGE_MASK & pgd_val(*pg_dir)); 7468 if (!pg_table) { 7469 pg_table = (pte_t *) __pa(start_mem); 7470 start_mem += PAGE_SIZE; 7471 } 7472 7473 pgd_val(*pg_dir) = _PAGE_TABLE | 7474 (unsigned long) pg_table; 7475 pg_dir++; 7476 7477 /* now change pg_table to kernel virtual addresses */ 7478 pg_table = (pte_t *) __va(pg_table); 7479 for (tmp = 0; tmp < PTRS_PER_PTE; tmp++,pg_table++) { 7480 pte_t pte = mk_pte(address, PAGE_KERNEL); 7481 if (address >= end_mem) 7482 pte_val(pte) = 0; 7483 set_pte(pg_table, pte); 7484 address += PAGE_SIZE; 7485 } 7486 } 7487 start_mem = fixmap_init(start_mem); 7488 #ifdef __SMP__ 7489 start_mem = init_smp_mappings(start_mem); 7490 #endif 7491 local_flush_tlb(); 7492 7493 return free_area_init(start_mem, end_mem); 7494 } 7495 7496 /* Test if the WP bit works in supervisor mode. It isn't 7497 * supported on 386's and also on some strange 486's 7498 * (NexGen etc.). All 586+'s are OK. The jumps before and 7499 * after the test are here to work-around some nasty CPU 7500 * bugs. */ 7501 __initfunc(void test_wp_bit(void)) 7502 { 7503 unsigned char tmp_reg; 7504 unsigned long old = pg0[0]; 7505 7506 printk("Checking if this processor honours the WP bit " 7507 "even in supervisor mode... "); 7508 pg0[0] = pte_val(mk_pte(PAGE_OFFSET, PAGE_READONLY)); 7509 local_flush_tlb(); 7510 current->mm->mmap->vm_start += PAGE_SIZE; 7511 __asm__ __volatile__( 7512 "jmp 1f; 1:\n" 7513 "movb %0,%1\n" 7514 "movb %1,%0\n" 7515 "jmp 1f; 1:\n" 7516 :"=m" (*(char *) __va(0)), 7517 "=q" (tmp_reg) 7518 :/* no inputs */ 7519 :"memory"); 7520 pg0[0] = old; 7521 local_flush_tlb(); 7522 current->mm->mmap->vm_start -= PAGE_SIZE; 7523 if (boot_cpu_data.wp_works_ok < 0) { 7524 boot_cpu_data.wp_works_ok = 0; 7525 printk("No.\n"); 7526 #ifdef CONFIG_X86_WP_WORKS_OK 7527 panic("This kernel doesn't support CPU's with broken" 7528 " WP. Recompile it for a 386!"); 7529 #endif 7530 } else 7531 printk(".\n"); 7532 } 7533 7534 __initfunc(void mem_init(unsigned long start_mem, 7535 unsigned long end_mem)) 7536 { 7537 unsigned long start_low_mem = PAGE_SIZE; 7538 int codepages = 0; 7539 int reservedpages = 0; 7540 int datapages = 0; 7541 int initpages = 0; 7542 unsigned long tmp; 7543 7544 end_mem &= PAGE_MASK; 7545 high_memory = (void *) end_mem; 7546 max_mapnr = num_physpages = MAP_NR(end_mem); 7547 7548 /* clear the zero-page */ 7549 memset(empty_zero_page, 0, PAGE_SIZE); 7550 7551 /* mark usable pages in the mem_map[] */ 7552 start_low_mem = PAGE_ALIGN(start_low_mem)+PAGE_OFFSET; 7553 7554 #ifdef __SMP__ 7555 /* But first pinch a few for the stack/trampoline stuff 7556 * FIXME: Don't need the extra page at 4K, but need to 7557 * fix trampoline before removing it. (see the GDT 7558 * stuff) */ 7559 start_low_mem += PAGE_SIZE; /* 32bit startup code */ 7560 /* AP processor stacks */ 7561 start_low_mem = smp_alloc_memory(start_low_mem); 7562 #endif 7563 start_mem = PAGE_ALIGN(start_mem); 7564 7565 /* IBM messed up *AGAIN* in their thinkpad: 0xA0000 -> 7566 * 0x9F000. They seem to have done something stupid 7567 * with the floppy controller as well.. */ 7568 while (start_low_mem < 0x9f000+PAGE_OFFSET) { 7569 clear_bit(PG_reserved, 7570 &mem_map[MAP_NR(start_low_mem)].flags); 7571 start_low_mem += PAGE_SIZE; 7572 } 7573 7574 while (start_mem < end_mem) { 7575 clear_bit(PG_reserved, 7576 &mem_map[MAP_NR(start_mem)].flags); 7577 start_mem += PAGE_SIZE; 7578 } 7579 for (tmp = PAGE_OFFSET; tmp < end_mem; 7580 tmp += PAGE_SIZE) { 7581 if (tmp >= MAX_DMA_ADDRESS) 7582 clear_bit(PG_DMA, &mem_map[MAP_NR(tmp)].flags); 7583 if (PageReserved(mem_map+MAP_NR(tmp))) { 7584 if (tmp >= (unsigned long) &_text && 7585 tmp < (unsigned long) &_edata) { 7586 if (tmp < (unsigned long) &_etext) 7587 codepages++; 7588 else 7589 datapages++; 7590 } else if (tmp >= (unsigned long) &__init_begin 7591 && tmp < (unsigned long) &__init_end) 7592 initpages++; 7593 else if (tmp >= (unsigned long) &__bss_start 7594 && tmp < (unsigned long) start_mem) 7595 datapages++; 7596 else 7597 reservedpages++; 7598 continue; 7599 } 7600 atomic_set(&mem_map[MAP_NR(tmp)].count, 1); 7601 #ifdef CONFIG_BLK_DEV_INITRD 7602 if (!initrd_start (tmp < initrd_start tmp >= 7603 initrd_end)) 7604 #endif 7605 free_page(tmp); 7606 } 7607 printk("Memory: %luk/%luk available (%dk kernel code, " 7608 "%dk reserved, %dk data, %dk init)\n", 7609 (unsigned long) nr_free_pages << (PAGE_SHIFT-10), 7610 max_mapnr << (PAGE_SHIFT-10), 7611 codepages << (PAGE_SHIFT-10), 7612 reservedpages << (PAGE_SHIFT-10), 7613 datapages << (PAGE_SHIFT-10), 7614 initpages << (PAGE_SHIFT-10)); 7615 7616 if (boot_cpu_data.wp_works_ok < 0) 7617 test_wp_bit(); 7618 } 7619 7620 void free_initmem(void) 7621 { 7622 unsigned long addr; 7623 7624 addr = (unsigned long)(&__init_begin); 7625 for (; addr < (unsigned long)(&__init_end); 7626 addr += PAGE_SIZE) { 7627 mem_map[MAP_NR(addr)].flags &= ~(1 << PG_reserved); 7628 atomic_set(&mem_map[MAP_NR(addr)].count, 1); 7629 free_page(addr); 7630 } 7631 printk("Freeing unused kernel memory: %dk freed\n", 7632 (&__init_end - &__init_begin) >> 10); 7633 } 7634 7635 void si_meminfo(struct sysinfo *val) 7636 { 7637 int i; 7638 7639 i = max_mapnr; 7640 val->totalram = 0; 7641 val->sharedram = 0; 7642 val->freeram = nr_free_pages << PAGE_SHIFT; 7643 val->bufferram = buffermem; 7644 while (i-- > 0) { 7645 if (PageReserved(mem_map+i)) 7646 continue; 7647 val->totalram++; 7648 if (!atomic_read(&mem_map[i].count)) 7649 continue; 7650 val->sharedram += atomic_read(&mem_map[i].count) - 1; 7651 } 7652 val->totalram <<= PAGE_SHIFT; 7653 val->sharedram <<= PAGE_SHIFT; 7654 return; 7655 }



Содержание раздела