pgtable_32.c 9.6 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8
/*
 *  linux/arch/i386/mm/pgtable.c
 */

#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/mm.h>
9
#include <linux/nmi.h>
L
Linus Torvalds 已提交
10 11 12 13 14 15
#include <linux/swap.h>
#include <linux/smp.h>
#include <linux/highmem.h>
#include <linux/slab.h>
#include <linux/pagemap.h>
#include <linux/spinlock.h>
16
#include <linux/module.h>
C
Christoph Lameter 已提交
17
#include <linux/quicklist.h>
L
Linus Torvalds 已提交
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34

#include <asm/system.h>
#include <asm/pgtable.h>
#include <asm/pgalloc.h>
#include <asm/fixmap.h>
#include <asm/e820.h>
#include <asm/tlb.h>
#include <asm/tlbflush.h>

void show_mem(void)
{
	int total = 0, reserved = 0;
	int shared = 0, cached = 0;
	int highmem = 0;
	struct page *page;
	pg_data_t *pgdat;
	unsigned long i;
35
	unsigned long flags;
L
Linus Torvalds 已提交
36

37
	printk(KERN_INFO "Mem-info:\n");
L
Linus Torvalds 已提交
38
	show_free_areas();
39
	printk(KERN_INFO "Free swap:       %6ldkB\n", nr_swap_pages<<(PAGE_SHIFT-10));
40
	for_each_online_pgdat(pgdat) {
41
		pgdat_resize_lock(pgdat, &flags);
L
Linus Torvalds 已提交
42
		for (i = 0; i < pgdat->node_spanned_pages; ++i) {
43 44
			if (unlikely(i % MAX_ORDER_NR_PAGES == 0))
				touch_nmi_watchdog();
45
			page = pgdat_page_nr(pgdat, i);
L
Linus Torvalds 已提交
46 47 48 49 50 51 52 53 54 55
			total++;
			if (PageHighMem(page))
				highmem++;
			if (PageReserved(page))
				reserved++;
			else if (PageSwapCache(page))
				cached++;
			else if (page_count(page))
				shared += page_count(page) - 1;
		}
56
		pgdat_resize_unlock(pgdat, &flags);
L
Linus Torvalds 已提交
57
	}
58 59 60 61 62
	printk(KERN_INFO "%d pages of RAM\n", total);
	printk(KERN_INFO "%d pages of HIGHMEM\n", highmem);
	printk(KERN_INFO "%d reserved pages\n", reserved);
	printk(KERN_INFO "%d pages shared\n", shared);
	printk(KERN_INFO "%d pages swap cached\n", cached);
63

64
	printk(KERN_INFO "%lu pages dirty\n", global_page_state(NR_FILE_DIRTY));
65 66
	printk(KERN_INFO "%lu pages writeback\n",
					global_page_state(NR_WRITEBACK));
67
	printk(KERN_INFO "%lu pages mapped\n", global_page_state(NR_FILE_MAPPED));
68 69 70
	printk(KERN_INFO "%lu pages slab\n",
		global_page_state(NR_SLAB_RECLAIMABLE) +
		global_page_state(NR_SLAB_UNRECLAIMABLE));
71 72
	printk(KERN_INFO "%lu pages pagetables\n",
					global_page_state(NR_PAGETABLE));
L
Linus Torvalds 已提交
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
}

/*
 * Associate a virtual page frame with a given physical page frame 
 * and protection flags for that frame.
 */ 
static void set_pte_pfn(unsigned long vaddr, unsigned long pfn, pgprot_t flags)
{
	pgd_t *pgd;
	pud_t *pud;
	pmd_t *pmd;
	pte_t *pte;

	pgd = swapper_pg_dir + pgd_index(vaddr);
	if (pgd_none(*pgd)) {
		BUG();
		return;
	}
	pud = pud_offset(pgd, vaddr);
	if (pud_none(*pud)) {
		BUG();
		return;
	}
	pmd = pmd_offset(pud, vaddr);
	if (pmd_none(*pmd)) {
		BUG();
		return;
	}
	pte = pte_offset_kernel(pmd, vaddr);
102
	if (pgprot_val(flags))
103
		set_pte_present(&init_mm, vaddr, pte, pfn_pte(pfn, flags));
104 105
	else
		pte_clear(&init_mm, vaddr, pte);
L
Linus Torvalds 已提交
106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126

	/*
	 * It's enough to flush this one mapping.
	 * (PGE mappings get flushed as well)
	 */
	__flush_tlb_one(vaddr);
}

/*
 * Associate a large virtual page frame with a given physical page frame 
 * and protection flags for that frame. pfn is for the base of the page,
 * vaddr is what the page gets mapped to - both must be properly aligned. 
 * The pmd must already be instantiated. Assumes PAE mode.
 */ 
void set_pmd_pfn(unsigned long vaddr, unsigned long pfn, pgprot_t flags)
{
	pgd_t *pgd;
	pud_t *pud;
	pmd_t *pmd;

	if (vaddr & (PMD_SIZE-1)) {		/* vaddr is misaligned */
127
		printk(KERN_WARNING "set_pmd_pfn: vaddr misaligned\n");
L
Linus Torvalds 已提交
128 129 130
		return; /* BUG(); */
	}
	if (pfn & (PTRS_PER_PTE-1)) {		/* pfn is misaligned */
131
		printk(KERN_WARNING "set_pmd_pfn: pfn misaligned\n");
L
Linus Torvalds 已提交
132 133 134 135
		return; /* BUG(); */
	}
	pgd = swapper_pg_dir + pgd_index(vaddr);
	if (pgd_none(*pgd)) {
136
		printk(KERN_WARNING "set_pmd_pfn: pgd_none\n");
L
Linus Torvalds 已提交
137 138 139 140 141 142 143 144 145 146 147 148
		return; /* BUG(); */
	}
	pud = pud_offset(pgd, vaddr);
	pmd = pmd_offset(pud, vaddr);
	set_pmd(pmd, pfn_pmd(pfn, flags));
	/*
	 * It's enough to flush this one mapping.
	 * (PGE mappings get flushed as well)
	 */
	__flush_tlb_one(vaddr);
}

149 150 151 152
static int fixmaps;
unsigned long __FIXADDR_TOP = 0xfffff000;
EXPORT_SYMBOL(__FIXADDR_TOP);

L
Linus Torvalds 已提交
153 154 155 156 157 158 159 160 161
void __set_fixmap (enum fixed_addresses idx, unsigned long phys, pgprot_t flags)
{
	unsigned long address = __fix_to_virt(idx);

	if (idx >= __end_of_fixed_addresses) {
		BUG();
		return;
	}
	set_pte_pfn(address, phys >> PAGE_SHIFT, flags);
162 163 164 165 166 167 168 169 170 171 172 173 174
	fixmaps++;
}

/**
 * reserve_top_address - reserves a hole in the top of kernel address space
 * @reserve - size of hole to reserve
 *
 * Can be used to relocate the fixmap area and poke a hole in the top
 * of kernel address space to make room for a hypervisor.
 */
void reserve_top_address(unsigned long reserve)
{
	BUG_ON(fixmaps > 0);
175 176
	printk(KERN_INFO "Reserving virtual address space above 0x%08x\n",
	       (int)-reserve);
177 178
	__FIXADDR_TOP = -reserve - PAGE_SIZE;
	__VMALLOC_RESERVE += reserve;
L
Linus Torvalds 已提交
179 180 181 182 183 184 185
}

pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address)
{
	return (pte_t *)__get_free_page(GFP_KERNEL|__GFP_REPEAT|__GFP_ZERO);
}

186
pgtable_t pte_alloc_one(struct mm_struct *mm, unsigned long address)
L
Linus Torvalds 已提交
187 188 189 190 191 192 193 194
{
	struct page *pte;

#ifdef CONFIG_HIGHPTE
	pte = alloc_pages(GFP_KERNEL|__GFP_HIGHMEM|__GFP_REPEAT|__GFP_ZERO, 0);
#else
	pte = alloc_pages(GFP_KERNEL|__GFP_REPEAT|__GFP_ZERO, 0);
#endif
195 196
	if (pte)
		pgtable_page_ctor(pte);
L
Linus Torvalds 已提交
197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212
	return pte;
}

/*
 * List of all pgd's needed for non-PAE so it can invalidate entries
 * in both cached and uncached pgd's; not needed for PAE since the
 * kernel pmd is shared. If PAE were not to share the pmd a similar
 * tactic would be needed. This is essentially codepath-based locking
 * against pageattr.c; it is the unique case in which a valid change
 * of kernel pagetables can't be lazily synchronized by vmalloc faults.
 * vmalloc faults work because attached pagetables are never freed.
 * -- wli
 */
static inline void pgd_list_add(pgd_t *pgd)
{
	struct page *page = virt_to_page(pgd);
213 214

	list_add(&page->lru, &pgd_list);
L
Linus Torvalds 已提交
215 216 217 218
}

static inline void pgd_list_del(pgd_t *pgd)
{
219 220 221
	struct page *page = virt_to_page(pgd);

	list_del(&page->lru);
L
Linus Torvalds 已提交
222 223
}

224 225
#define UNSHARED_PTRS_PER_PGD				\
	(SHARED_KERNEL_PMD ? USER_PTRS_PER_PGD : PTRS_PER_PGD)
C
Christoph Lameter 已提交
226

227
static void pgd_ctor(void *p)
L
Linus Torvalds 已提交
228
{
229
	pgd_t *pgd = p;
L
Linus Torvalds 已提交
230 231
	unsigned long flags;

232
	/* Clear usermode parts of PGD */
233 234 235
	memset(pgd, 0, USER_PTRS_PER_PGD*sizeof(pgd_t));

	spin_lock_irqsave(&pgd_lock, flags);
L
Linus Torvalds 已提交
236

237 238 239 240 241 242
	/* If the pgd points to a shared pagetable level (either the
	   ptes in non-PAE, or shared PMD in PAE), then just copy the
	   references from swapper_pg_dir. */
	if (PAGETABLE_LEVELS == 2 ||
	    (PAGETABLE_LEVELS == 3 && SHARED_KERNEL_PMD)) {
		clone_pgd_range(pgd + USER_PTRS_PER_PGD,
243 244
				swapper_pg_dir + USER_PTRS_PER_PGD,
				KERNEL_PGD_PTRS);
245 246 247 248 249
		paravirt_alloc_pd_clone(__pa(pgd) >> PAGE_SHIFT,
					__pa(swapper_pg_dir) >> PAGE_SHIFT,
					USER_PTRS_PER_PGD,
					KERNEL_PGD_PTRS);
	}
250

251 252
	/* list required to sync kernel mapping updates */
	if (!SHARED_KERNEL_PMD)
253
		pgd_list_add(pgd);
254 255

	spin_unlock_irqrestore(&pgd_lock, flags);
256
}
L
Linus Torvalds 已提交
257

A
Adrian Bunk 已提交
258
static void pgd_dtor(void *pgd)
L
Linus Torvalds 已提交
259 260 261
{
	unsigned long flags; /* can be called from interrupt context */

C
Christoph Lameter 已提交
262 263
	if (SHARED_KERNEL_PMD)
		return;
264

L
Linus Torvalds 已提交
265 266 267 268 269
	spin_lock_irqsave(&pgd_lock, flags);
	pgd_list_del(pgd);
	spin_unlock_irqrestore(&pgd_lock, flags);
}

270 271 272 273 274 275 276
#ifdef CONFIG_X86_PAE
/*
 * Mop up any pmd pages which may still be attached to the pgd.
 * Normally they will be freed by munmap/exit_mmap, but any pmd we
 * preallocate which never got a corresponding vma will need to be
 * freed manually.
 */
277
static void pgd_mop_up_pmds(struct mm_struct *mm, pgd_t *pgdp)
278 279 280
{
	int i;

281
	for(i = 0; i < UNSHARED_PTRS_PER_PGD; i++) {
282 283 284 285 286 287 288 289
		pgd_t pgd = pgdp[i];

		if (pgd_val(pgd) != 0) {
			pmd_t *pmd = (pmd_t *)pgd_page_vaddr(pgd);

			pgdp[i] = native_make_pgd(0);

			paravirt_release_pd(pgd_val(pgd) >> PAGE_SHIFT);
290
			pmd_free(mm, pmd);
291 292 293 294 295 296 297 298 299 300
		}
	}
}

/*
 * In PAE mode, we need to do a cr3 reload (=tlb flush) when
 * updating the top-level pagetable entries to guarantee the
 * processor notices the update.  Since this is expensive, and
 * all 4 top-level entries are used almost immediately in a
 * new process's life, we just pre-populate them here.
301 302 303 304
 *
 * Also, if we're in a paravirt environment where the kernel pmd is
 * not shared between pagetables (!SHARED_KERNEL_PMDS), we allocate
 * and initialize the kernel pmds here.
305 306 307 308 309 310 311 312
 */
static int pgd_prepopulate_pmd(struct mm_struct *mm, pgd_t *pgd)
{
	pud_t *pud;
	unsigned long addr;
	int i;

	pud = pud_offset(pgd, 0);
313 314
 	for (addr = i = 0; i < UNSHARED_PTRS_PER_PGD;
	     i++, pud++, addr += PUD_SIZE) {
315 316 317
		pmd_t *pmd = pmd_alloc_one(mm, addr);

		if (!pmd) {
318
			pgd_mop_up_pmds(mm, pgd);
319 320 321
			return 0;
		}

322 323 324 325
		if (i >= USER_PTRS_PER_PGD)
			memcpy(pmd, (pmd_t *)pgd_page_vaddr(swapper_pg_dir[i]),
			       sizeof(pmd_t) * PTRS_PER_PMD);

326 327 328 329 330 331 332 333 334 335 336 337
		pud_populate(mm, pud, pmd);
	}

	return 1;
}
#else  /* !CONFIG_X86_PAE */
/* No need to prepopulate any pagetable entries in non-PAE modes. */
static int pgd_prepopulate_pmd(struct mm_struct *mm, pgd_t *pgd)
{
	return 1;
}

338
static void pgd_mop_up_pmds(struct mm_struct *mm, pgd_t *pgdp)
339 340 341 342
{
}
#endif	/* CONFIG_X86_PAE */

L
Linus Torvalds 已提交
343 344
pgd_t *pgd_alloc(struct mm_struct *mm)
{
T
Thomas Gleixner 已提交
345
	pgd_t *pgd = (pgd_t *)__get_free_page(GFP_KERNEL | __GFP_ZERO);
L
Linus Torvalds 已提交
346

T
Thomas Gleixner 已提交
347 348 349 350
	/* so that alloc_pd can use it */
	mm->pgd = pgd;
	if (pgd)
		pgd_ctor(pgd);
351

352
	if (pgd && !pgd_prepopulate_pmd(mm, pgd)) {
T
Thomas Gleixner 已提交
353 354
		pgd_dtor(pgd);
		free_page((unsigned long)pgd);
355 356 357
		pgd = NULL;
	}

L
Linus Torvalds 已提交
358 359 360
	return pgd;
}

361
void pgd_free(struct mm_struct *mm, pgd_t *pgd)
L
Linus Torvalds 已提交
362
{
363
	pgd_mop_up_pmds(mm, pgd);
T
Thomas Gleixner 已提交
364 365
	pgd_dtor(pgd);
	free_page((unsigned long)pgd);
C
Christoph Lameter 已提交
366
}
367 368 369

void __pte_free_tlb(struct mmu_gather *tlb, struct page *pte)
{
370
	pgtable_page_dtor(pte);
371 372 373 374 375 376 377 378 379 380 381 382 383
	paravirt_release_pt(page_to_pfn(pte));
	tlb_remove_page(tlb, pte);
}

#ifdef CONFIG_X86_PAE

void __pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmd)
{
	paravirt_release_pd(__pa(pmd) >> PAGE_SHIFT);
	tlb_remove_page(tlb, virt_to_page(pmd));
}

#endif
I
Ingo Molnar 已提交
384 385 386 387 388 389 390

int pmd_bad(pmd_t pmd)
{
	WARN_ON_ONCE(pmd_bad_v1(pmd) != pmd_bad_v2(pmd));

	return pmd_bad_v1(pmd);
}