linux-old/arch/i386/mm/init.c History
<<
>>
Prefs
   1/*
   2 *  linux/arch/i386/mm/init.c
   3 *
   4 *  Copyright (C) 1995  Linus Torvalds
   5 *
   6 *  Support of BIGMEM added by Gerhard Wichert, Siemens AG, July 1999
   7 */
   8
   9#include <linux/config.h>
  10#include <linux/signal.h>
  11#include <linux/sched.h>
  12#include <linux/kernel.h>
  13#include <linux/errno.h>
  14#include <linux/string.h>
  15#include <linux/types.h>
  16#include <linux/ptrace.h>
  17#include <linux/mman.h>
  18#include <linux/mm.h>
  19#include <linux/swap.h>
  20#include <linux/smp.h>
  21#include <linux/init.h>
  22#ifdef CONFIG_BLK_DEV_INITRD
  23#include <linux/blk.h>
  24#endif
  25#include <linux/highmem.h>
  26#include <linux/pagemap.h>
  27#include <linux/bootmem.h>
  28
  29#include <asm/processor.h>
  30#include <asm/system.h>
  31#include <asm/uaccess.h>
  32#include <asm/pgtable.h>
  33#include <asm/pgalloc.h>
  34#include <asm/dma.h>
  35#include <asm/fixmap.h>
  36#include <asm/e820.h>
  37#include <asm/apic.h>
  38
  39unsigned long highstart_pfn, highend_pfn;
  40static unsigned long totalram_pages;
  41static unsigned long totalhigh_pages;
  42
  43/*
  44 * BAD_PAGE is the page that is used for page faults when linux
  45 * is out-of-memory. Older versions of linux just did a
  46 * do_exit(), but using this instead means there is less risk
  47 * for a process dying in kernel mode, possibly leaving an inode
  48 * unused etc..
  49 *
  50 * BAD_PAGETABLE is the accompanying page-table: it is initialized
  51 * to point to BAD_PAGE entries.
  52 *
  53 * ZERO_PAGE is a special page that is used for zero-initialized
  54 * data and COW.
  55 */
  56
  57/*
  58 * These are allocated in head.S so that we get proper page alignment.
  59 * If you change the size of these then change head.S as well.
  60 */
  61extern char empty_bad_page[PAGE_SIZE];
  62#if CONFIG_X86_PAE
  63extern pmd_t empty_bad_pmd_table[PTRS_PER_PMD];
  64#endif
  65extern pte_t empty_bad_pte_table[PTRS_PER_PTE];
  66
  67/*
  68 * We init them before every return and make them writable-shared.
  69 * This guarantees we get out of the kernel in some more or less sane
  70 * way.
  71 */
  72#if CONFIG_X86_PAE
  73static pmd_t * get_bad_pmd_table(void)
  74{
  75        pmd_t v;
  76        int i;
  77
  78        set_pmd(&v, __pmd(_PAGE_TABLE + __pa(empty_bad_pte_table)));
  79
  80        for (i = 0; i < PAGE_SIZE/sizeof(pmd_t); i++)
  81                empty_bad_pmd_table[i] = v;
  82
  83        return empty_bad_pmd_table;
  84}
  85#endif
  86
  87static pte_t * get_bad_pte_table(void)
  88{
  89        pte_t v;
  90        int i;
  91
  92        v = pte_mkdirty(mk_pte_phys(__pa(empty_bad_page), PAGE_SHARED));
  93
  94        for (i = 0; i < PAGE_SIZE/sizeof(pte_t); i++)
  95                empty_bad_pte_table[i] = v;
  96
  97        return empty_bad_pte_table;
  98}
  99
 100
 101
 102void __handle_bad_pmd(pmd_t *pmd)
 103{
 104        pmd_ERROR(*pmd);
 105        set_pmd(pmd, __pmd(_PAGE_TABLE + __pa(get_bad_pte_table())));
 106}
 107
 108void __handle_bad_pmd_kernel(pmd_t *pmd)
 109{
 110        pmd_ERROR(*pmd);
 111        set_pmd(pmd, __pmd(_KERNPG_TABLE + __pa(get_bad_pte_table())));
 112}
 113
 114pte_t *get_pte_kernel_slow(pmd_t *pmd, unsigned long offset)
 115{
 116        pte_t *pte;
 117
 118        pte = (pte_t *) __get_free_page(GFP_KERNEL);
 119        if (pmd_none(*pmd)) {
 120                if (pte) {
 121                        clear_page(pte);
 122                        set_pmd(pmd, __pmd(_KERNPG_TABLE + __pa(pte)));
 123                        return pte + offset;
 124                }
 125                set_pmd(pmd, __pmd(_KERNPG_TABLE + __pa(get_bad_pte_table())));
 126                return NULL;
 127        }
 128        free_page((unsigned long)pte);
 129        if (pmd_bad(*pmd)) {
 130                __handle_bad_pmd_kernel(pmd);
 131                return NULL;
 132        }
 133        return (pte_t *) pmd_page(*pmd) + offset;
 134}
 135
 136pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset)
 137{
 138        unsigned long pte;
 139
 140        pte = (unsigned long) __get_free_page(GFP_KERNEL);
 141        if (pmd_none(*pmd)) {
 142                if (pte) {
 143                        clear_page((void *)pte);
 144                        set_pmd(pmd, __pmd(_PAGE_TABLE + __pa(pte)));
 145                        return (pte_t *)pte + offset;
 146                }
 147                set_pmd(pmd, __pmd(_PAGE_TABLE + __pa(get_bad_pte_table())));
 148                return NULL;
 149        }
 150        free_page(pte);
 151        if (pmd_bad(*pmd)) {
 152                __handle_bad_pmd(pmd);
 153                return NULL;
 154        }
 155        return (pte_t *) pmd_page(*pmd) + offset;
 156}
 157
 158int do_check_pgt_cache(int low, int high)
 159{
 160        int freed = 0;
 161        if(pgtable_cache_size > high) {
 162                do {
 163                        if(pgd_quicklist)
 164                                free_pgd_slow(get_pgd_fast()), freed++;
 165                        if(pmd_quicklist)
 166                                free_pmd_slow(get_pmd_fast()), freed++;
 167                        if(pte_quicklist)
 168                                free_pte_slow(get_pte_fast()), freed++;
 169                } while(pgtable_cache_size > low);
 170        }
 171        return freed;
 172}
 173
 174/*
 175 * NOTE: pagetable_init alloc all the fixmap pagetables contiguous on the
 176 * physical space so we can cache the place of the first one and move
 177 * around without checking the pgd every time.
 178 */
 179
 180#if CONFIG_HIGHMEM
 181pte_t *kmap_pte;
 182pgprot_t kmap_prot;
 183
 184#define kmap_get_fixmap_pte(vaddr)                                      \
 185        pte_offset(pmd_offset(pgd_offset_k(vaddr), (vaddr)), (vaddr))
 186
 187void __init kmap_init(void)
 188{
 189        unsigned long kmap_vstart;
 190
 191        /* cache the first kmap pte */
 192        kmap_vstart = __fix_to_virt(FIX_KMAP_BEGIN);
 193        kmap_pte = kmap_get_fixmap_pte(kmap_vstart);
 194
 195        kmap_prot = PAGE_KERNEL;
 196}
 197#endif /* CONFIG_HIGHMEM */
 198
 199void show_mem(void)
 200{
 201        int i, total = 0, reserved = 0;
 202        int shared = 0, cached = 0;
 203        int highmem = 0;
 204
 205        printk("Mem-info:\n");
 206        show_free_areas();
 207        printk("Free swap:       %6dkB\n",nr_swap_pages<<(PAGE_SHIFT-10));
 208        i = max_mapnr;
 209        while (i-- > 0) {
 210                total++;
 211                if (PageHighMem(mem_map+i))
 212                        highmem++;
 213                if (PageReserved(mem_map+i))
 214                        reserved++;
 215                else if (PageSwapCache(mem_map+i))
 216                        cached++;
 217                else if (page_count(mem_map+i))
 218                        shared += page_count(mem_map+i) - 1;
 219        }
 220        printk("%d pages of RAM\n", total);
 221        printk("%d pages of HIGHMEM\n",highmem);
 222        printk("%d reserved pages\n",reserved);
 223        printk("%d pages shared\n",shared);
 224        printk("%d pages swap cached\n",cached);
 225        printk("%ld pages in page table cache\n",pgtable_cache_size);
 226        show_buffers();
 227}
 228
 229/* References to section boundaries */
 230
 231extern char _text, _etext, _edata, __bss_start, _end;
 232extern char __init_begin, __init_end;
 233
 234static inline void set_pte_phys (unsigned long vaddr,
 235                        unsigned long phys, pgprot_t flags)
 236{
 237        pgprot_t prot;
 238        pgd_t *pgd;
 239        pmd_t *pmd;
 240        pte_t *pte;
 241
 242        pgd = swapper_pg_dir + __pgd_offset(vaddr);
 243        if (pgd_none(*pgd)) {
 244                printk("PAE BUG #00!\n");
 245                return;
 246        }
 247        pmd = pmd_offset(pgd, vaddr);
 248        if (pmd_none(*pmd)) {
 249                printk("PAE BUG #01!\n");
 250                return;
 251        }
 252        pte = pte_offset(pmd, vaddr);
 253        if (pte_val(*pte))
 254                pte_ERROR(*pte);
 255        pgprot_val(prot) = pgprot_val(PAGE_KERNEL) | pgprot_val(flags);
 256        set_pte(pte, mk_pte_phys(phys, prot));
 257
 258        /*
 259         * It's enough to flush this one mapping.
 260         * (PGE mappings get flushed as well)
 261         */
 262        __flush_tlb_one(vaddr);
 263}
 264
 265void __set_fixmap (enum fixed_addresses idx, unsigned long phys, pgprot_t flags)
 266{
 267        unsigned long address = __fix_to_virt(idx);
 268
 269        if (idx >= __end_of_fixed_addresses) {
 270                printk("Invalid __set_fixmap\n");
 271                return;
 272        }
 273        set_pte_phys(address, phys, flags);
 274}
 275
 276static void __init fixrange_init (unsigned long start, unsigned long end, pgd_t *pgd_base)
 277{
 278        pgd_t *pgd;
 279        pmd_t *pmd;
 280        pte_t *pte;
 281        int i, j;
 282        unsigned long vaddr;
 283
 284        vaddr = start;
 285        i = __pgd_offset(vaddr);
 286        j = __pmd_offset(vaddr);
 287        pgd = pgd_base + i;
 288
 289        for ( ; (i < PTRS_PER_PGD) && (vaddr != end); pgd++, i++) {
 290#if CONFIG_X86_PAE
 291                if (pgd_none(*pgd)) {
 292                        pmd = (pmd_t *) alloc_bootmem_low_pages(PAGE_SIZE);
 293                        set_pgd(pgd, __pgd(__pa(pmd) + 0x1));
 294                        if (pmd != pmd_offset(pgd, 0))
 295                                printk("PAE BUG #02!\n");
 296                }
 297                pmd = pmd_offset(pgd, vaddr);
 298#else
 299                pmd = (pmd_t *)pgd;
 300#endif
 301                for (; (j < PTRS_PER_PMD) && (vaddr != end); pmd++, j++) {
 302                        if (pmd_none(*pmd)) {
 303                                pte = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE);
 304                                set_pmd(pmd, __pmd(_KERNPG_TABLE + __pa(pte)));
 305                                if (pte != pte_offset(pmd, 0))
 306                                        BUG();
 307                        }
 308                        vaddr += PMD_SIZE;
 309                }
 310                j = 0;
 311        }
 312}
 313
 314static void __init pagetable_init (void)
 315{
 316        unsigned long vaddr, end;
 317        pgd_t *pgd, *pgd_base;
 318        int i, j, k;
 319        pmd_t *pmd;
 320        pte_t *pte;
 321
 322        /*
 323         * This can be zero as well - no problem, in that case we exit
 324         * the loops anyway due to the PTRS_PER_* conditions.
 325         */
 326        end = (unsigned long)__va(max_low_pfn*PAGE_SIZE);
 327
 328        pgd_base = swapper_pg_dir;
 329#if CONFIG_X86_PAE
 330        for (i = 0; i < PTRS_PER_PGD; i++) {
 331                pgd = pgd_base + i;
 332                __pgd_clear(pgd);
 333        }
 334#endif
 335        i = __pgd_offset(PAGE_OFFSET);
 336        pgd = pgd_base + i;
 337
 338        for (; i < PTRS_PER_PGD; pgd++, i++) {
 339                vaddr = i*PGDIR_SIZE;
 340                if (end && (vaddr >= end))
 341                        break;
 342#if CONFIG_X86_PAE
 343                pmd = (pmd_t *) alloc_bootmem_low_pages(PAGE_SIZE);
 344                set_pgd(pgd, __pgd(__pa(pmd) + 0x1));
 345#else
 346                pmd = (pmd_t *)pgd;
 347#endif
 348                if (pmd != pmd_offset(pgd, 0))
 349                        BUG();
 350                for (j = 0; j < PTRS_PER_PMD; pmd++, j++) {
 351                        vaddr = i*PGDIR_SIZE + j*PMD_SIZE;
 352                        if (end && (vaddr >= end))
 353                                break;
 354                        if (cpu_has_pse) {
 355                                unsigned long __pe;
 356
 357                                set_in_cr4(X86_CR4_PSE);
 358                                boot_cpu_data.wp_works_ok = 1;
 359                                __pe = _KERNPG_TABLE + _PAGE_PSE + __pa(vaddr);
 360                                /* Make it "global" too if supported */
 361                                if (cpu_has_pge) {
 362                                        set_in_cr4(X86_CR4_PGE);
 363                                        __pe += _PAGE_GLOBAL;
 364                                }
 365                                set_pmd(pmd, __pmd(__pe));
 366                                continue;
 367                        }
 368
 369                        pte = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE);
 370                        set_pmd(pmd, __pmd(_KERNPG_TABLE + __pa(pte)));
 371
 372                        if (pte != pte_offset(pmd, 0))
 373                                BUG();
 374
 375                        for (k = 0; k < PTRS_PER_PTE; pte++, k++) {
 376                                vaddr = i*PGDIR_SIZE + j*PMD_SIZE + k*PAGE_SIZE;
 377                                if (end && (vaddr >= end))
 378                                        break;
 379                                *pte = mk_pte_phys(__pa(vaddr), PAGE_KERNEL);
 380                        }
 381                }
 382        }
 383
 384        /*
 385         * Fixed mappings, only the page table structure has to be
 386         * created - mappings will be set by set_fixmap():
 387         */
 388        vaddr = __fix_to_virt(__end_of_fixed_addresses - 1) & PMD_MASK;
 389        fixrange_init(vaddr, 0, pgd_base);
 390
 391#if CONFIG_HIGHMEM
 392        /*
 393         * Permanent kmaps:
 394         */
 395        vaddr = PKMAP_BASE;
 396        fixrange_init(vaddr, vaddr + PAGE_SIZE*LAST_PKMAP, pgd_base);
 397
 398        pgd = swapper_pg_dir + __pgd_offset(vaddr);
 399        pmd = pmd_offset(pgd, vaddr);
 400        pte = pte_offset(pmd, vaddr);
 401        pkmap_page_table = pte;
 402#endif
 403
 404#if CONFIG_X86_PAE
 405        /*
 406         * Add low memory identity-mappings - SMP needs it when
 407         * starting up on an AP from real-mode. In the non-PAE
 408         * case we already have these mappings through head.S.
 409         * All user-space mappings are explicitly cleared after
 410         * SMP startup.
 411         */
 412        pgd_base[0] = pgd_base[USER_PTRS_PER_PGD];
 413#endif
 414}
 415
 416void __init zap_low_mappings (void)
 417{
 418        int i;
 419        /*
 420         * Zap initial low-memory mappings.
 421         *
 422         * Note that "pgd_clear()" doesn't do it for
 423         * us in this case, because pgd_clear() is a
 424         * no-op in the 2-level case (pmd_clear() is
 425         * the thing that clears the page-tables in
 426         * that case).
 427         */
 428        for (i = 0; i < USER_PTRS_PER_PGD; i++)
 429#if CONFIG_X86_PAE
 430                pgd_clear(swapper_pg_dir+i);
 431#else
 432                set_pgd(swapper_pg_dir+i, __pgd(0));
 433#endif
 434        flush_tlb_all();
 435}
 436
 437/*
 438 * paging_init() sets up the page tables - note that the first 8MB are
 439 * already mapped by head.S.
 440 *
 441 * This routines also unmaps the page at virtual kernel address 0, so
 442 * that we can trap those pesky NULL-reference errors in the kernel.
 443 */
 444void __init paging_init(void)
 445{
 446        pagetable_init();
 447
 448        __asm__( "movl %%ecx,%%cr3\n" ::"c"(__pa(swapper_pg_dir)));
 449
 450#if CONFIG_X86_PAE
 451        /*
 452         * We will bail out later - printk doesnt work right now so
 453         * the user would just see a hanging kernel.
 454         */
 455        if (cpu_has_pae)
 456                set_in_cr4(X86_CR4_PAE);
 457#endif
 458
 459        __flush_tlb_all();
 460
 461#ifdef CONFIG_HIGHMEM
 462        kmap_init();
 463#endif
 464        {
 465                unsigned long zones_size[MAX_NR_ZONES] = {0, 0, 0};
 466                unsigned int max_dma, high, low;
 467
 468                max_dma = virt_to_phys((char *)MAX_DMA_ADDRESS) >> PAGE_SHIFT;
 469                low = max_low_pfn;
 470                high = highend_pfn;
 471
 472                if (low < max_dma)
 473                        zones_size[ZONE_DMA] = low;
 474                else {
 475                        zones_size[ZONE_DMA] = max_dma;
 476                        zones_size[ZONE_NORMAL] = low - max_dma;
 477#ifdef CONFIG_HIGHMEM
 478                        zones_size[ZONE_HIGHMEM] = high - low;
 479#endif
 480                }
 481                free_area_init(zones_size);
 482        }
 483        return;
 484}
 485
 486/*
 487 * Test if the WP bit works in supervisor mode. It isn't supported on 386's
 488 * and also on some strange 486's (NexGen etc.). All 586+'s are OK. The jumps
 489 * before and after the test are here to work-around some nasty CPU bugs.
 490 */
 491
 492/*
 493 * This function cannot be __init, since exceptions don't work in that
 494 * section.
 495 */
 496static int do_test_wp_bit(unsigned long vaddr);
 497
 498void __init test_wp_bit(void)
 499{
 500/*
 501 * Ok, all PSE-capable CPUs are definitely handling the WP bit right.
 502 */
 503        const unsigned long vaddr = PAGE_OFFSET;
 504        pgd_t *pgd;
 505        pmd_t *pmd;
 506        pte_t *pte, old_pte;
 507
 508        printk("Checking if this processor honours the WP bit even in supervisor mode... ");
 509
 510        pgd = swapper_pg_dir + __pgd_offset(vaddr);
 511        pmd = pmd_offset(pgd, vaddr);
 512        pte = pte_offset(pmd, vaddr);
 513        old_pte = *pte;
 514        *pte = mk_pte_phys(0, PAGE_READONLY);
 515        local_flush_tlb();
 516
 517        boot_cpu_data.wp_works_ok = do_test_wp_bit(vaddr);
 518
 519        *pte = old_pte;
 520        local_flush_tlb();
 521
 522        if (!boot_cpu_data.wp_works_ok) {
 523                printk("No.\n");
 524#ifdef CONFIG_X86_WP_WORKS_OK
 525                panic("This kernel doesn't support CPU's with broken WP. Recompile it for a 386!");
 526#endif
 527        } else {
 528                printk("Ok.\n");
 529        }
 530}
 531
 532static inline int page_is_ram (unsigned long pagenr)
 533{
 534        int i;
 535
 536        for (i = 0; i < e820.nr_map; i++) {
 537                unsigned long addr, end;
 538
 539                if (e820.map[i].type != E820_RAM)       /* not usable memory */
 540                        continue;
 541                /*
 542                 *      !!!FIXME!!! Some BIOSen report areas as RAM that
 543                 *      are not. Notably the 640->1Mb area. We need a sanity
 544                 *      check here.
 545                 */
 546                addr = (e820.map[i].addr+PAGE_SIZE-1) >> PAGE_SHIFT;
 547                end = (e820.map[i].addr+e820.map[i].size) >> PAGE_SHIFT;
 548                if  ((pagenr >= addr) && (pagenr < end))
 549                        return 1;
 550        }
 551        return 0;
 552}
 553
 554void __init mem_init(void)
 555{
 556        int codesize, reservedpages, datasize, initsize;
 557        int tmp;
 558
 559        if (!mem_map)
 560                BUG();
 561
 562#ifdef CONFIG_HIGHMEM
 563        highmem_start_page = mem_map + highstart_pfn;
 564        max_mapnr = num_physpages = highend_pfn;
 565#else
 566        max_mapnr = num_physpages = max_low_pfn;
 567#endif
 568        high_memory = (void *) __va(max_low_pfn * PAGE_SIZE);
 569
 570        /* clear the zero-page */
 571        memset(empty_zero_page, 0, PAGE_SIZE);
 572
 573        /* this will put all low memory onto the freelists */
 574        totalram_pages += free_all_bootmem();
 575
 576        reservedpages = 0;
 577        for (tmp = 0; tmp < max_low_pfn; tmp++)
 578                /*
 579                 * Only count reserved RAM pages
 580                 */
 581                if (page_is_ram(tmp) && PageReserved(mem_map+tmp))
 582                        reservedpages++;
 583#ifdef CONFIG_HIGHMEM
 584        for (tmp = highstart_pfn; tmp < highend_pfn; tmp++) {
 585                struct page *page = mem_map + tmp;
 586
 587                if (!page_is_ram(tmp)) {
 588                        SetPageReserved(page);
 589                        continue;
 590                }
 591                ClearPageReserved(page);
 592                set_bit(PG_highmem, &page->flags);
 593                atomic_set(&page->count, 1);
 594                __free_page(page);
 595                totalhigh_pages++;
 596        }
 597        totalram_pages += totalhigh_pages;
 598#endif
 599        codesize =  (unsigned long) &_etext - (unsigned long) &_text;
 600        datasize =  (unsigned long) &_edata - (unsigned long) &_etext;
 601        initsize =  (unsigned long) &__init_end - (unsigned long) &__init_begin;
 602
 603        printk("Memory: %luk/%luk available (%dk kernel code, %dk reserved, %dk data, %dk init, %ldk highmem)\n",
 604                (unsigned long) nr_free_pages() << (PAGE_SHIFT-10),
 605                max_mapnr << (PAGE_SHIFT-10),
 606                codesize >> 10,
 607                reservedpages << (PAGE_SHIFT-10),
 608                datasize >> 10,
 609                initsize >> 10,
 610                (unsigned long) (totalhigh_pages << (PAGE_SHIFT-10))
 611               );
 612
 613#if CONFIG_X86_PAE
 614        if (!cpu_has_pae)
 615                panic("cannot execute a PAE-enabled kernel on a PAE-less CPU!");
 616#endif
 617        if (boot_cpu_data.wp_works_ok < 0)
 618                test_wp_bit();
 619
 620        /*
 621         * Subtle. SMP is doing it's boot stuff late (because it has to
 622         * fork idle threads) - but it also needs low mappings for the
 623         * protected-mode entry to work. We zap these entries only after
 624         * the WP-bit has been tested.
 625         */
 626#ifndef CONFIG_SMP
 627        zap_low_mappings();
 628#endif
 629
 630}
 631
 632/* Put this after the callers, so that it cannot be inlined */
 633static int do_test_wp_bit(unsigned long vaddr)
 634{
 635        char tmp_reg;
 636        int flag;
 637
 638        __asm__ __volatile__(
 639                "       movb %0,%1      \n"
 640                "1:     movb %1,%0      \n"
 641                "       xorl %2,%2      \n"
 642                "2:                     \n"
 643                ".section __ex_table,\"a\"\n"
 644                "       .align 4        \n"
 645                "       .long 1b,2b     \n"
 646                ".previous              \n"
 647                :"=m" (*(char *) vaddr),
 648                 "=q" (tmp_reg),
 649                 "=r" (flag)
 650                :"2" (1)
 651                :"memory");
 652        
 653        return flag;
 654}
 655
 656void free_initmem(void)
 657{
 658        unsigned long addr;
 659
 660        addr = (unsigned long)(&__init_begin);
 661        for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) {
 662                ClearPageReserved(virt_to_page(addr));
 663                set_page_count(virt_to_page(addr), 1);
 664                free_page(addr);
 665                totalram_pages++;
 666        }
 667        printk ("Freeing unused kernel memory: %dk freed\n", (&__init_end - &__init_begin) >> 10);
 668}
 669
 670#ifdef CONFIG_BLK_DEV_INITRD
 671void free_initrd_mem(unsigned long start, unsigned long end)
 672{
 673        if (start < end)
 674                printk ("Freeing initrd memory: %ldk freed\n", (end - start) >> 10);
 675        for (; start < end; start += PAGE_SIZE) {
 676                ClearPageReserved(virt_to_page(start));
 677                set_page_count(virt_to_page(start), 1);
 678                free_page(start);
 679                totalram_pages++;
 680        }
 681}
 682#endif
 683
 684void si_meminfo(struct sysinfo *val)
 685{
 686        val->totalram = totalram_pages;
 687        val->sharedram = 0;
 688        val->freeram = nr_free_pages();
 689        val->bufferram = atomic_read(&buffermem_pages);
 690        val->totalhigh = totalhigh_pages;
 691        val->freehigh = nr_free_highpages();
 692        val->mem_unit = PAGE_SIZE;
 693        return;
 694}
 695
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.