ia64/xen-unstable

changeset 9035:bf594e88f046

Add arch/i386/mm/pgtable.c to sparse tree.

Signed-off-by: Christian Limpach <Christian.Limpach@cl.cam.ac.uk>
author cl349@firebug.cl.cam.ac.uk
date Mon Feb 27 10:31:30 2006 +0000 (2006-02-27)
parents 55f597e929f3
children e480a5db8abb
files linux-2.6-xen-sparse/arch/i386/mm/pgtable.c
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/linux-2.6-xen-sparse/arch/i386/mm/pgtable.c	Mon Feb 27 10:31:30 2006 +0000
     1.3 @@ -0,0 +1,271 @@
     1.4 +/*
     1.5 + *  linux/arch/i386/mm/pgtable.c
     1.6 + */
     1.7 +
     1.8 +#include <linux/config.h>
     1.9 +#include <linux/sched.h>
    1.10 +#include <linux/kernel.h>
    1.11 +#include <linux/errno.h>
    1.12 +#include <linux/mm.h>
    1.13 +#include <linux/swap.h>
    1.14 +#include <linux/smp.h>
    1.15 +#include <linux/highmem.h>
    1.16 +#include <linux/slab.h>
    1.17 +#include <linux/pagemap.h>
    1.18 +#include <linux/spinlock.h>
    1.19 +
    1.20 +#include <asm/system.h>
    1.21 +#include <asm/pgtable.h>
    1.22 +#include <asm/pgalloc.h>
    1.23 +#include <asm/fixmap.h>
    1.24 +#include <asm/e820.h>
    1.25 +#include <asm/tlb.h>
    1.26 +#include <asm/tlbflush.h>
    1.27 +
    1.28 +void show_mem(void)
    1.29 +{
    1.30 +	int total = 0, reserved = 0;
    1.31 +	int shared = 0, cached = 0;
    1.32 +	int highmem = 0;
    1.33 +	struct page *page;
    1.34 +	pg_data_t *pgdat;
    1.35 +	unsigned long i;
    1.36 +	struct page_state ps;
    1.37 +	unsigned long flags;
    1.38 +
    1.39 +	printk(KERN_INFO "Mem-info:\n");
    1.40 +	show_free_areas();
    1.41 +	printk(KERN_INFO "Free swap:       %6ldkB\n", nr_swap_pages<<(PAGE_SHIFT-10));
    1.42 +	for_each_pgdat(pgdat) {
    1.43 +		pgdat_resize_lock(pgdat, &flags);
    1.44 +		for (i = 0; i < pgdat->node_spanned_pages; ++i) {
    1.45 +			page = pgdat_page_nr(pgdat, i);
    1.46 +			total++;
    1.47 +			if (PageHighMem(page))
    1.48 +				highmem++;
    1.49 +			if (PageReserved(page))
    1.50 +				reserved++;
    1.51 +			else if (PageSwapCache(page))
    1.52 +				cached++;
    1.53 +			else if (page_count(page))
    1.54 +				shared += page_count(page) - 1;
    1.55 +		}
    1.56 +		pgdat_resize_unlock(pgdat, &flags);
    1.57 +	}
    1.58 +	printk(KERN_INFO "%d pages of RAM\n", total);
    1.59 +	printk(KERN_INFO "%d pages of HIGHMEM\n", highmem);
    1.60 +	printk(KERN_INFO "%d reserved pages\n", reserved);
    1.61 +	printk(KERN_INFO "%d pages shared\n", shared);
    1.62 +	printk(KERN_INFO "%d pages swap cached\n", cached);
    1.63 +
    1.64 +	get_page_state(&ps);
    1.65 +	printk(KERN_INFO "%lu pages dirty\n", ps.nr_dirty);
    1.66 +	printk(KERN_INFO "%lu pages writeback\n", ps.nr_writeback);
    1.67 +	printk(KERN_INFO "%lu pages mapped\n", ps.nr_mapped);
    1.68 +	printk(KERN_INFO "%lu pages slab\n", ps.nr_slab);
    1.69 +	printk(KERN_INFO "%lu pages pagetables\n", ps.nr_page_table_pages);
    1.70 +}
    1.71 +
    1.72 +/*
    1.73 + * Associate a virtual page frame with a given physical page frame 
    1.74 + * and protection flags for that frame.
    1.75 + */ 
    1.76 +static void set_pte_pfn(unsigned long vaddr, unsigned long pfn, pgprot_t flags)
    1.77 +{
    1.78 +	pgd_t *pgd;
    1.79 +	pud_t *pud;
    1.80 +	pmd_t *pmd;
    1.81 +	pte_t *pte;
    1.82 +
    1.83 +	pgd = swapper_pg_dir + pgd_index(vaddr);
    1.84 +	if (pgd_none(*pgd)) {
    1.85 +		BUG();
    1.86 +		return;
    1.87 +	}
    1.88 +	pud = pud_offset(pgd, vaddr);
    1.89 +	if (pud_none(*pud)) {
    1.90 +		BUG();
    1.91 +		return;
    1.92 +	}
    1.93 +	pmd = pmd_offset(pud, vaddr);
    1.94 +	if (pmd_none(*pmd)) {
    1.95 +		BUG();
    1.96 +		return;
    1.97 +	}
    1.98 +	pte = pte_offset_kernel(pmd, vaddr);
    1.99 +	/* <pfn,flags> stored as-is, to permit clearing entries */
   1.100 +	set_pte(pte, pfn_pte(pfn, flags));
   1.101 +
   1.102 +	/*
   1.103 +	 * It's enough to flush this one mapping.
   1.104 +	 * (PGE mappings get flushed as well)
   1.105 +	 */
   1.106 +	__flush_tlb_one(vaddr);
   1.107 +}
   1.108 +
   1.109 +/*
   1.110 + * Associate a large virtual page frame with a given physical page frame 
   1.111 + * and protection flags for that frame. pfn is for the base of the page,
   1.112 + * vaddr is what the page gets mapped to - both must be properly aligned. 
   1.113 + * The pmd must already be instantiated. Assumes PAE mode.
   1.114 + */ 
   1.115 +void set_pmd_pfn(unsigned long vaddr, unsigned long pfn, pgprot_t flags)
   1.116 +{
   1.117 +	pgd_t *pgd;
   1.118 +	pud_t *pud;
   1.119 +	pmd_t *pmd;
   1.120 +
   1.121 +	if (vaddr & (PMD_SIZE-1)) {		/* vaddr is misaligned */
   1.122 +		printk(KERN_WARNING "set_pmd_pfn: vaddr misaligned\n");
   1.123 +		return; /* BUG(); */
   1.124 +	}
   1.125 +	if (pfn & (PTRS_PER_PTE-1)) {		/* pfn is misaligned */
   1.126 +		printk(KERN_WARNING "set_pmd_pfn: pfn misaligned\n");
   1.127 +		return; /* BUG(); */
   1.128 +	}
   1.129 +	pgd = swapper_pg_dir + pgd_index(vaddr);
   1.130 +	if (pgd_none(*pgd)) {
   1.131 +		printk(KERN_WARNING "set_pmd_pfn: pgd_none\n");
   1.132 +		return; /* BUG(); */
   1.133 +	}
   1.134 +	pud = pud_offset(pgd, vaddr);
   1.135 +	pmd = pmd_offset(pud, vaddr);
   1.136 +	set_pmd(pmd, pfn_pmd(pfn, flags));
   1.137 +	/*
   1.138 +	 * It's enough to flush this one mapping.
   1.139 +	 * (PGE mappings get flushed as well)
   1.140 +	 */
   1.141 +	__flush_tlb_one(vaddr);
   1.142 +}
   1.143 +
   1.144 +void __set_fixmap (enum fixed_addresses idx, unsigned long phys, pgprot_t flags)
   1.145 +{
   1.146 +	unsigned long address = __fix_to_virt(idx);
   1.147 +
   1.148 +	if (idx >= __end_of_fixed_addresses) {
   1.149 +		BUG();
   1.150 +		return;
   1.151 +	}
   1.152 +	set_pte_pfn(address, phys >> PAGE_SHIFT, flags);
   1.153 +}
   1.154 +
   1.155 +pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address)
   1.156 +{
   1.157 +	return (pte_t *)__get_free_page(GFP_KERNEL|__GFP_REPEAT|__GFP_ZERO);
   1.158 +}
   1.159 +
   1.160 +struct page *pte_alloc_one(struct mm_struct *mm, unsigned long address)
   1.161 +{
   1.162 +	struct page *pte;
   1.163 +
   1.164 +#ifdef CONFIG_HIGHPTE
   1.165 +	pte = alloc_pages(GFP_KERNEL|__GFP_HIGHMEM|__GFP_REPEAT|__GFP_ZERO, 0);
   1.166 +#else
   1.167 +	pte = alloc_pages(GFP_KERNEL|__GFP_REPEAT|__GFP_ZERO, 0);
   1.168 +#endif
   1.169 +	return pte;
   1.170 +}
   1.171 +
   1.172 +void pmd_ctor(void *pmd, kmem_cache_t *cache, unsigned long flags)
   1.173 +{
   1.174 +	memset(pmd, 0, PTRS_PER_PMD*sizeof(pmd_t));
   1.175 +}
   1.176 +
   1.177 +/*
   1.178 + * List of all pgd's needed for non-PAE so it can invalidate entries
   1.179 + * in both cached and uncached pgd's; not needed for PAE since the
   1.180 + * kernel pmd is shared. If PAE were not to share the pmd a similar
   1.181 + * tactic would be needed. This is essentially codepath-based locking
   1.182 + * against pageattr.c; it is the unique case in which a valid change
   1.183 + * of kernel pagetables can't be lazily synchronized by vmalloc faults.
   1.184 + * vmalloc faults work because attached pagetables are never freed.
   1.185 + * The locking scheme was chosen on the basis of manfred's
   1.186 + * recommendations and having no core impact whatsoever.
   1.187 + * -- wli
   1.188 + */
   1.189 +DEFINE_SPINLOCK(pgd_lock);
   1.190 +struct page *pgd_list;
   1.191 +
   1.192 +static inline void pgd_list_add(pgd_t *pgd)
   1.193 +{
   1.194 +	struct page *page = virt_to_page(pgd);
   1.195 +	page->index = (unsigned long)pgd_list;
   1.196 +	if (pgd_list)
   1.197 +		set_page_private(pgd_list, (unsigned long)&page->index);
   1.198 +	pgd_list = page;
   1.199 +	set_page_private(page, (unsigned long)&pgd_list);
   1.200 +}
   1.201 +
   1.202 +static inline void pgd_list_del(pgd_t *pgd)
   1.203 +{
   1.204 +	struct page *next, **pprev, *page = virt_to_page(pgd);
   1.205 +	next = (struct page *)page->index;
   1.206 +	pprev = (struct page **)page_private(page);
   1.207 +	*pprev = next;
   1.208 +	if (next)
   1.209 +		set_page_private(next, (unsigned long)pprev);
   1.210 +}
   1.211 +
   1.212 +void pgd_ctor(void *pgd, kmem_cache_t *cache, unsigned long unused)
   1.213 +{
   1.214 +	unsigned long flags;
   1.215 +
   1.216 +	if (PTRS_PER_PMD == 1) {
   1.217 +		memset(pgd, 0, USER_PTRS_PER_PGD*sizeof(pgd_t));
   1.218 +		spin_lock_irqsave(&pgd_lock, flags);
   1.219 +	}
   1.220 +
   1.221 +	clone_pgd_range((pgd_t *)pgd + USER_PTRS_PER_PGD,
   1.222 +			swapper_pg_dir + USER_PTRS_PER_PGD,
   1.223 +			KERNEL_PGD_PTRS);
   1.224 +	if (PTRS_PER_PMD > 1)
   1.225 +		return;
   1.226 +
   1.227 +	pgd_list_add(pgd);
   1.228 +	spin_unlock_irqrestore(&pgd_lock, flags);
   1.229 +}
   1.230 +
   1.231 +/* never called when PTRS_PER_PMD > 1 */
   1.232 +void pgd_dtor(void *pgd, kmem_cache_t *cache, unsigned long unused)
   1.233 +{
   1.234 +	unsigned long flags; /* can be called from interrupt context */
   1.235 +
   1.236 +	spin_lock_irqsave(&pgd_lock, flags);
   1.237 +	pgd_list_del(pgd);
   1.238 +	spin_unlock_irqrestore(&pgd_lock, flags);
   1.239 +}
   1.240 +
   1.241 +pgd_t *pgd_alloc(struct mm_struct *mm)
   1.242 +{
   1.243 +	int i;
   1.244 +	pgd_t *pgd = kmem_cache_alloc(pgd_cache, GFP_KERNEL);
   1.245 +
   1.246 +	if (PTRS_PER_PMD == 1 || !pgd)
   1.247 +		return pgd;
   1.248 +
   1.249 +	for (i = 0; i < USER_PTRS_PER_PGD; ++i) {
   1.250 +		pmd_t *pmd = kmem_cache_alloc(pmd_cache, GFP_KERNEL);
   1.251 +		if (!pmd)
   1.252 +			goto out_oom;
   1.253 +		set_pgd(&pgd[i], __pgd(1 + __pa(pmd)));
   1.254 +	}
   1.255 +	return pgd;
   1.256 +
   1.257 +out_oom:
   1.258 +	for (i--; i >= 0; i--)
   1.259 +		kmem_cache_free(pmd_cache, (void *)__va(pgd_val(pgd[i])-1));
   1.260 +	kmem_cache_free(pgd_cache, pgd);
   1.261 +	return NULL;
   1.262 +}
   1.263 +
   1.264 +void pgd_free(pgd_t *pgd)
   1.265 +{
   1.266 +	int i;
   1.267 +
   1.268 +	/* in the PAE case user pgd entries are overwritten before usage */
   1.269 +	if (PTRS_PER_PMD > 1)
   1.270 +		for (i = 0; i < USER_PTRS_PER_PGD; ++i)
   1.271 +			kmem_cache_free(pmd_cache, (void *)__va(pgd_val(pgd[i])-1));
   1.272 +	/* in the non-PAE case, free_pgtables() clears user pgd entries */
   1.273 +	kmem_cache_free(pgd_cache, pgd);
   1.274 +}