/*
* Copyright 2002 Andi Kleen, SuSE Labs.
* Thanks to Ben LaHaise for precious feedback.
*/
#include <linux/highmem.h>
#include <linux/bootmem.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/interrupt.h>
#include <linux/seq_file.h>
#include <linux/debugfs.h>
#include <asm/e820.h>
#include <asm/processor.h>
#include <asm/tlbflush.h>
#include <asm/sections.h>
#include <asm/uaccess.h>
#include <asm/pgalloc.h>
#include <asm/proto.h>
#include <asm/pat.h>
/*
* The current flushing context - we pass it instead of 5 arguments:
*/
struct cpa_data {
unsigned long vaddr;
pgprot_t mask_set;
pgprot_t mask_clr;
int numpages;
int flushtlb;
unsigned long pfn;
unsigned force_split : 1;
};
#ifdef CONFIG_X86_64
static inline unsigned long highmap_start_pfn(void)
{
return __pa(_text) >> PAGE_SHIFT;
}
static inline unsigned long highmap_end_pfn(void)
{
return __pa(round_up((unsigned long)_end, PMD_SIZE)) >> PAGE_SHIFT;
}
#endif
#ifdef CONFIG_DEBUG_PAGEALLOC
# define debug_pagealloc 1
#else
# define debug_pagealloc 0
#endif
static inline int
within(unsigned long addr, unsigned long start, unsigned long end)
{
return addr >= start && addr < end;
}
/*
* Flushing functions
*/
/**
* clflush_cache_range - flush a cache range with clflush
* @addr: virtual start address
* @size: number of bytes to flush
*
* clflush is an unordered instruction which needs fencing with mfence
* to avoid ordering issues.
*/
void clflush_cache_range(void *vaddr, unsigned int size)
{
void *vend = vaddr + size - 1;
mb();
for (; vaddr < vend; vaddr += boot_cpu_data.x86_clflush_size)
clflush(vaddr);
/*
* Flush any possible final partial cacheline:
*/
clflush(vend);
mb();
}
static void __cpa_flush_all(void *arg)
{
unsigned long cache = (unsigned long)arg;
/*
* Flush all to work around Errata in early athlons regarding
* large page flushing.
*/
__flush_tlb_all();
if (cache && boot_cpu_data.x86_model >= 4)
wbinvd();
}
static void cpa_flush_all(unsigned long cache)
{
BUG_ON(irqs_disabled());
on_each_cpu(__cpa_flush_all, (void *) cache, 1, 1);
}
static void __cpa_flush_range(void *arg)
{
/*
* We could optimize that further and do individual per page
* tlb invalidates for a low number of pages. Caveat: we must
* flush the high aliases on 64bit as well.
*/
__flush_tlb_all();
}
static void cpa_flush_range(unsigned long start, int numpages, int cache)
{
unsigned int i, level;
unsigned long addr;
BUG_ON(irqs_disabled());
WARN_ON(PAGE_ALIGN(start) != start);
on_each_cpu(__cpa_flush_range, NULL, 1, 1);
if (!cache)
return;
/*
* We only need to flush on one CPU,
* clflush is a MESI-coherent instruction that
* will cause all other CPUs to flush the same
* cachelines:
*/
for (i = 0, addr = start; i < numpages; i++, addr += PAGE_SIZE) {
pte_t *pte = lookup_address(addr, &level);
/*
* Only flush present addresses:
*/
if (pte && (pte_val(*pte) & _PAGE_PRESENT))
clflush_cache_range((void *) addr, PAGE_SIZE);
}
}
/*
* Certain areas of memory on x86 require very specific protection flags,
* for example the BIOS area or kernel text. Callers don't always get this
* right (again, ioremap() on BIOS memory is not uncommon) so this function
* checks and fixes these known static required protection bits.
*/
static inline pgprot_t static_protections(pgprot_t prot, unsigned long address,
unsigned long pfn)
{
pgprot_t forbidden = __pgprot(0);
/*
* The BIOS area between 640k and 1Mb needs to be executable for
* PCI BIOS based config access (CONFIG_PCI_GOBIOS) support.
*/
if (within(pfn, BIOS_BEGIN >> PAGE_SHIFT, BIOS_END >> PAGE_SHIFT))
pgprot_val(forbidden) |= _PAGE_NX;
/*
* The kernel text needs to be executable for obvious reasons
* Does not cover __inittext since that is gone later on. On
* 64bit we do not enforce !NX on the low mapping
*/
if (within(address, (unsigned long)_text, (unsigned long)_etext))
pgprot_val(forbidden) |= _PAGE_NX;
/*
* The .rodata section needs to be read-only. Using the pfn
* catches all aliases.
*/
if (within(pfn, __pa((unsigned long)__start_rodata) >> PAGE_SHIFT,