netlib.narod.ru< Назад | Оглавление | Далее >

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 }

netlib.narod.ru< Назад | Оглавление | Далее >

Сайт управляется системой uCoz