Commit 0165d7f4 authored by Linus Torvalds's avatar Linus Torvalds

Merge git://git.kernel.org/pub/scm/linux/kernel/git/x86/linux-2.6-x86

* git://git.kernel.org/pub/scm/linux/kernel/git/x86/linux-2.6-x86:
  x86: fix lguest build failure
  x86: reenable support for system without on node0
  x86: CPA: avoid double checking of alias ranges
  x86: CPA no alias checking for _NX
  x86: zap invalid and unused pmds in early boot
  x86: CPA, fix alias checks
parents 20ef0f1a f6c540cd
...@@ -20,10 +20,8 @@ ...@@ -20,10 +20,8 @@
#include <xen/interface/xen.h> #include <xen/interface/xen.h>
#ifdef CONFIG_LGUEST_GUEST
#include <linux/lguest.h> #include <linux/lguest.h>
#include "../../../drivers/lguest/lg.h" #include "../../../drivers/lguest/lg.h"
#endif
#define DEFINE(sym, val) \ #define DEFINE(sym, val) \
asm volatile("\n->" #sym " %0 " #val : : "i" (val)) asm volatile("\n->" #sym " %0 " #val : : "i" (val))
...@@ -134,6 +132,10 @@ void foo(void) ...@@ -134,6 +132,10 @@ void foo(void)
BLANK(); BLANK();
OFFSET(LGUEST_DATA_irq_enabled, lguest_data, irq_enabled); OFFSET(LGUEST_DATA_irq_enabled, lguest_data, irq_enabled);
OFFSET(LGUEST_DATA_pgdir, lguest_data, pgdir); OFFSET(LGUEST_DATA_pgdir, lguest_data, pgdir);
#endif
#ifdef CONFIG_LGUEST
BLANK();
OFFSET(LGUEST_PAGES_host_gdt_desc, lguest_pages, state.host_gdt_desc); OFFSET(LGUEST_PAGES_host_gdt_desc, lguest_pages, state.host_gdt_desc);
OFFSET(LGUEST_PAGES_host_idt_desc, lguest_pages, state.host_idt_desc); OFFSET(LGUEST_PAGES_host_idt_desc, lguest_pages, state.host_idt_desc);
OFFSET(LGUEST_PAGES_host_cr3, lguest_pages, state.host_cr3); OFFSET(LGUEST_PAGES_host_cr3, lguest_pages, state.host_cr3);
......
...@@ -88,6 +88,9 @@ void __init x86_64_start_kernel(char * real_mode_data) ...@@ -88,6 +88,9 @@ void __init x86_64_start_kernel(char * real_mode_data)
/* Make NULL pointers segfault */ /* Make NULL pointers segfault */
zap_identity_mappings(); zap_identity_mappings();
/* Cleanup the over mapped high alias */
cleanup_highmap();
for (i = 0; i < IDT_ENTRIES; i++) { for (i = 0; i < IDT_ENTRIES; i++) {
#ifdef CONFIG_EARLY_PRINTK #ifdef CONFIG_EARLY_PRINTK
set_intr_gate(i, &early_idt_handlers[i]); set_intr_gate(i, &early_idt_handlers[i]);
......
...@@ -107,8 +107,13 @@ startup_64: ...@@ -107,8 +107,13 @@ startup_64:
movq %rdx, 0(%rbx, %rax, 8) movq %rdx, 0(%rbx, %rax, 8)
ident_complete: ident_complete:
/* Fixup the kernel text+data virtual addresses /*
* Fixup the kernel text+data virtual addresses. Note that
* we might write invalid pmds, when the kernel is relocated
* cleanup_highmap() fixes this up along with the mappings
* beyond _end.
*/ */
leaq level2_kernel_pgt(%rip), %rdi leaq level2_kernel_pgt(%rip), %rdi
leaq 4096(%rdi), %r8 leaq 4096(%rdi), %r8
/* See if it is a valid page table entry */ /* See if it is a valid page table entry */
......
...@@ -171,6 +171,33 @@ set_pte_phys(unsigned long vaddr, unsigned long phys, pgprot_t prot) ...@@ -171,6 +171,33 @@ set_pte_phys(unsigned long vaddr, unsigned long phys, pgprot_t prot)
__flush_tlb_one(vaddr); __flush_tlb_one(vaddr);
} }
/*
* The head.S code sets up the kernel high mapping from:
* __START_KERNEL_map to __START_KERNEL_map + KERNEL_TEXT_SIZE
*
* phys_addr holds the negative offset to the kernel, which is added
* to the compile time generated pmds. This results in invalid pmds up
* to the point where we hit the physaddr 0 mapping.
*
* We limit the mappings to the region from _text to _end. _end is
* rounded up to the 2MB boundary. This catches the invalid pmds as
* well, as they are located before _text:
*/
void __init cleanup_highmap(void)
{
unsigned long vaddr = __START_KERNEL_map;
unsigned long end = round_up((unsigned long)_end, PMD_SIZE) - 1;
pmd_t *pmd = level2_kernel_pgt;
pmd_t *last_pmd = pmd + PTRS_PER_PMD;
for (; pmd < last_pmd; pmd++, vaddr += PMD_SIZE) {
if (!pmd_present(*pmd))
continue;
if (vaddr < (unsigned long) _text || vaddr > end)
set_pmd(pmd, __pmd(0));
}
}
/* NOTE: this is meant to be run only at boot */ /* NOTE: this is meant to be run only at boot */
void __init void __init
__set_fixmap(enum fixed_addresses idx, unsigned long phys, pgprot_t prot) __set_fixmap(enum fixed_addresses idx, unsigned long phys, pgprot_t prot)
......
...@@ -494,11 +494,13 @@ void __init numa_initmem_init(unsigned long start_pfn, unsigned long end_pfn) ...@@ -494,11 +494,13 @@ void __init numa_initmem_init(unsigned long start_pfn, unsigned long end_pfn)
int i; int i;
nodes_clear(node_possible_map); nodes_clear(node_possible_map);
nodes_clear(node_online_map);
#ifdef CONFIG_NUMA_EMU #ifdef CONFIG_NUMA_EMU
if (cmdline && !numa_emulation(start_pfn, end_pfn)) if (cmdline && !numa_emulation(start_pfn, end_pfn))
return; return;
nodes_clear(node_possible_map); nodes_clear(node_possible_map);
nodes_clear(node_online_map);
#endif #endif
#ifdef CONFIG_ACPI_NUMA #ifdef CONFIG_ACPI_NUMA
...@@ -506,6 +508,7 @@ void __init numa_initmem_init(unsigned long start_pfn, unsigned long end_pfn) ...@@ -506,6 +508,7 @@ void __init numa_initmem_init(unsigned long start_pfn, unsigned long end_pfn)
end_pfn << PAGE_SHIFT)) end_pfn << PAGE_SHIFT))
return; return;
nodes_clear(node_possible_map); nodes_clear(node_possible_map);
nodes_clear(node_online_map);
#endif #endif
#ifdef CONFIG_K8_NUMA #ifdef CONFIG_K8_NUMA
...@@ -513,6 +516,7 @@ void __init numa_initmem_init(unsigned long start_pfn, unsigned long end_pfn) ...@@ -513,6 +516,7 @@ void __init numa_initmem_init(unsigned long start_pfn, unsigned long end_pfn)
end_pfn<<PAGE_SHIFT)) end_pfn<<PAGE_SHIFT))
return; return;
nodes_clear(node_possible_map); nodes_clear(node_possible_map);
nodes_clear(node_online_map);
#endif #endif
printk(KERN_INFO "%s\n", printk(KERN_INFO "%s\n",
numa_off ? "NUMA turned off" : "No NUMA configuration found"); numa_off ? "NUMA turned off" : "No NUMA configuration found");
...@@ -524,7 +528,6 @@ void __init numa_initmem_init(unsigned long start_pfn, unsigned long end_pfn) ...@@ -524,7 +528,6 @@ void __init numa_initmem_init(unsigned long start_pfn, unsigned long end_pfn)
memnode_shift = 63; memnode_shift = 63;
memnodemap = memnode.embedded_map; memnodemap = memnode.embedded_map;
memnodemap[0] = 0; memnodemap[0] = 0;
nodes_clear(node_online_map);
node_set_online(0); node_set_online(0);
node_set(0, node_possible_map); node_set(0, node_possible_map);
for (i = 0; i < NR_CPUS; i++) for (i = 0; i < NR_CPUS; i++)
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <asm/sections.h> #include <asm/sections.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/pgalloc.h> #include <asm/pgalloc.h>
#include <asm/proto.h>
/* /*
* The current flushing context - we pass it instead of 5 arguments: * The current flushing context - we pass it instead of 5 arguments:
...@@ -26,8 +27,23 @@ struct cpa_data { ...@@ -26,8 +27,23 @@ struct cpa_data {
pgprot_t mask_clr; pgprot_t mask_clr;
int numpages; int numpages;
int flushtlb; int flushtlb;
unsigned long pfn;
}; };
#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
static inline int static inline int
within(unsigned long addr, unsigned long start, unsigned long end) within(unsigned long addr, unsigned long start, unsigned long end)
{ {
...@@ -123,29 +139,14 @@ static void cpa_flush_range(unsigned long start, int numpages, int cache) ...@@ -123,29 +139,14 @@ static void cpa_flush_range(unsigned long start, int numpages, int cache)
} }
} }
#define HIGH_MAP_START __START_KERNEL_map
#define HIGH_MAP_END (__START_KERNEL_map + KERNEL_TEXT_SIZE)
/*
* Converts a virtual address to a X86-64 highmap address
*/
static unsigned long virt_to_highmap(void *address)
{
#ifdef CONFIG_X86_64
return __pa((unsigned long)address) + HIGH_MAP_START - phys_base;
#else
return (unsigned long)address;
#endif
}
/* /*
* Certain areas of memory on x86 require very specific protection flags, * 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 * 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 * right (again, ioremap() on BIOS memory is not uncommon) so this function
* checks and fixes these known static required protection bits. * checks and fixes these known static required protection bits.
*/ */
static inline pgprot_t static_protections(pgprot_t prot, unsigned long address) static inline pgprot_t static_protections(pgprot_t prot, unsigned long address,
unsigned long pfn)
{ {
pgprot_t forbidden = __pgprot(0); pgprot_t forbidden = __pgprot(0);
...@@ -153,30 +154,23 @@ static inline pgprot_t static_protections(pgprot_t prot, unsigned long address) ...@@ -153,30 +154,23 @@ static inline pgprot_t static_protections(pgprot_t prot, unsigned long address)
* The BIOS area between 640k and 1Mb needs to be executable for * The BIOS area between 640k and 1Mb needs to be executable for
* PCI BIOS based config access (CONFIG_PCI_GOBIOS) support. * PCI BIOS based config access (CONFIG_PCI_GOBIOS) support.
*/ */
if (within(__pa(address), BIOS_BEGIN, BIOS_END)) if (within(pfn, BIOS_BEGIN >> PAGE_SHIFT, BIOS_END >> PAGE_SHIFT))
pgprot_val(forbidden) |= _PAGE_NX; pgprot_val(forbidden) |= _PAGE_NX;
/* /*
* The kernel text needs to be executable for obvious reasons * The kernel text needs to be executable for obvious reasons
* Does not cover __inittext since that is gone later on * 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)) if (within(address, (unsigned long)_text, (unsigned long)_etext))
pgprot_val(forbidden) |= _PAGE_NX; pgprot_val(forbidden) |= _PAGE_NX;
/*
* Do the same for the x86-64 high kernel mapping
*/
if (within(address, virt_to_highmap(_text), virt_to_highmap(_etext)))
pgprot_val(forbidden) |= _PAGE_NX;
/* The .rodata section needs to be read-only */
if (within(address, (unsigned long)__start_rodata,
(unsigned long)__end_rodata))
pgprot_val(forbidden) |= _PAGE_RW;
/* /*
* Do the same for the x86-64 high kernel mapping * The .rodata section needs to be read-only. Using the pfn
* catches all aliases.
*/ */
if (within(address, virt_to_highmap(__start_rodata), if (within(pfn, __pa((unsigned long)__start_rodata) >> PAGE_SHIFT,
virt_to_highmap(__end_rodata))) __pa((unsigned long)__end_rodata) >> PAGE_SHIFT))
pgprot_val(forbidden) |= _PAGE_RW; pgprot_val(forbidden) |= _PAGE_RW;
prot = __pgprot(pgprot_val(prot) & ~pgprot_val(forbidden)); prot = __pgprot(pgprot_val(prot) & ~pgprot_val(forbidden));
...@@ -253,7 +247,7 @@ static int ...@@ -253,7 +247,7 @@ static int
try_preserve_large_page(pte_t *kpte, unsigned long address, try_preserve_large_page(pte_t *kpte, unsigned long address,
struct cpa_data *cpa) struct cpa_data *cpa)
{ {
unsigned long nextpage_addr, numpages, pmask, psize, flags, addr; unsigned long nextpage_addr, numpages, pmask, psize, flags, addr, pfn;
pte_t new_pte, old_pte, *tmp; pte_t new_pte, old_pte, *tmp;
pgprot_t old_prot, new_prot; pgprot_t old_prot, new_prot;
int i, do_split = 1; int i, do_split = 1;
...@@ -301,7 +295,15 @@ try_preserve_large_page(pte_t *kpte, unsigned long address, ...@@ -301,7 +295,15 @@ try_preserve_large_page(pte_t *kpte, unsigned long address,
pgprot_val(new_prot) &= ~pgprot_val(cpa->mask_clr); pgprot_val(new_prot) &= ~pgprot_val(cpa->mask_clr);
pgprot_val(new_prot) |= pgprot_val(cpa->mask_set); pgprot_val(new_prot) |= pgprot_val(cpa->mask_set);
new_prot = static_protections(new_prot, address);
/*
* old_pte points to the large page base address. So we need
* to add the offset of the virtual address:
*/
pfn = pte_pfn(old_pte) + ((address & (psize - 1)) >> PAGE_SHIFT);
cpa->pfn = pfn;
new_prot = static_protections(new_prot, address, pfn);
/* /*
* We need to check the full range, whether * We need to check the full range, whether
...@@ -309,8 +311,9 @@ try_preserve_large_page(pte_t *kpte, unsigned long address, ...@@ -309,8 +311,9 @@ try_preserve_large_page(pte_t *kpte, unsigned long address,
* the pages in the range we try to preserve: * the pages in the range we try to preserve:
*/ */
addr = address + PAGE_SIZE; addr = address + PAGE_SIZE;
for (i = 1; i < cpa->numpages; i++, addr += PAGE_SIZE) { pfn++;
pgprot_t chk_prot = static_protections(new_prot, addr); for (i = 1; i < cpa->numpages; i++, addr += PAGE_SIZE, pfn++) {
pgprot_t chk_prot = static_protections(new_prot, addr, pfn);
if (pgprot_val(chk_prot) != pgprot_val(new_prot)) if (pgprot_val(chk_prot) != pgprot_val(new_prot))
goto out_unlock; goto out_unlock;
...@@ -505,46 +508,51 @@ out_unlock: ...@@ -505,46 +508,51 @@ out_unlock:
return 0; return 0;
} }
static int __change_page_attr(unsigned long address, struct cpa_data *cpa) static int __change_page_attr(struct cpa_data *cpa, int primary)
{ {
unsigned long address = cpa->vaddr;
int do_split, err; int do_split, err;
unsigned int level; unsigned int level;
struct page *kpte_page; struct page *kpte_page;
pte_t *kpte; pte_t *kpte, old_pte;
repeat: repeat:
kpte = lookup_address(address, &level); kpte = lookup_address(address, &level);
if (!kpte) if (!kpte)
return primary ? -EINVAL : 0;
old_pte = *kpte;
if (!pte_val(old_pte)) {
if (!primary)
return 0;
printk(KERN_WARNING "CPA: called for zero pte. "
"vaddr = %lx cpa->vaddr = %lx\n", address,
cpa->vaddr);
WARN_ON(1);
return -EINVAL; return -EINVAL;
}
kpte_page = virt_to_page(kpte); kpte_page = virt_to_page(kpte);
BUG_ON(PageLRU(kpte_page)); BUG_ON(PageLRU(kpte_page));
BUG_ON(PageCompound(kpte_page)); BUG_ON(PageCompound(kpte_page));
if (level == PG_LEVEL_4K) { if (level == PG_LEVEL_4K) {
pte_t new_pte, old_pte = *kpte; pte_t new_pte;
pgprot_t new_prot = pte_pgprot(old_pte); pgprot_t new_prot = pte_pgprot(old_pte);
unsigned long pfn = pte_pfn(old_pte);
if(!pte_val(old_pte)) {
printk(KERN_WARNING "CPA: called for zero pte. "
"vaddr = %lx cpa->vaddr = %lx\n", address,
cpa->vaddr);
WARN_ON(1);
return -EINVAL;
}
pgprot_val(new_prot) &= ~pgprot_val(cpa->mask_clr); pgprot_val(new_prot) &= ~pgprot_val(cpa->mask_clr);
pgprot_val(new_prot) |= pgprot_val(cpa->mask_set); pgprot_val(new_prot) |= pgprot_val(cpa->mask_set);
new_prot = static_protections(new_prot, address); new_prot = static_protections(new_prot, address, pfn);
/* /*
* We need to keep the pfn from the existing PTE, * We need to keep the pfn from the existing PTE,
* after all we're only going to change it's attributes * after all we're only going to change it's attributes
* not the memory it points to * not the memory it points to
*/ */
new_pte = pfn_pte(pte_pfn(old_pte), canon_pgprot(new_prot)); new_pte = pfn_pte(pfn, canon_pgprot(new_prot));
cpa->pfn = pfn;
/* /*
* Do we really change anything ? * Do we really change anything ?
*/ */
...@@ -581,67 +589,59 @@ repeat: ...@@ -581,67 +589,59 @@ repeat:
return err; return err;
} }
/** static int __change_page_attr_set_clr(struct cpa_data *cpa, int checkalias);
* change_page_attr_addr - Change page table attributes in linear mapping
* @address: Virtual address in linear mapping. static int cpa_process_alias(struct cpa_data *cpa)
* @prot: New page table attribute (PAGE_*)
*
* Change page attributes of a page in the direct mapping. This is a variant
* of change_page_attr() that also works on memory holes that do not have
* mem_map entry (pfn_valid() is false).
*
* See change_page_attr() documentation for more details.
*
* Modules and drivers should use the set_memory_* APIs instead.
*/
static int change_page_attr_addr(struct cpa_data *cpa)
{ {
int err; struct cpa_data alias_cpa;
unsigned long address = cpa->vaddr; int ret = 0;
#ifdef CONFIG_X86_64 if (cpa->pfn > max_pfn_mapped)
unsigned long phys_addr = __pa(address); return 0;
/* /*
* If we are inside the high mapped kernel range, then we * No need to redo, when the primary call touched the direct
* fixup the low mapping first. __va() returns the virtual * mapping already:
* address in the linear mapping:
*/ */
if (within(address, HIGH_MAP_START, HIGH_MAP_END)) if (!within(cpa->vaddr, PAGE_OFFSET,
address = (unsigned long) __va(phys_addr); PAGE_OFFSET + (max_pfn_mapped << PAGE_SHIFT))) {
#endif
err = __change_page_attr(address, cpa); alias_cpa = *cpa;
if (err) alias_cpa.vaddr = (unsigned long) __va(cpa->pfn << PAGE_SHIFT);
return err;
ret = __change_page_attr_set_clr(&alias_cpa, 0);
}
#ifdef CONFIG_X86_64 #ifdef CONFIG_X86_64
if (ret)
return ret;
/* /*
* If the physical address is inside the kernel map, we need * No need to redo, when the primary call touched the high
* to touch the high mapped kernel as well: * mapping already:
*/ */
if (within(phys_addr, 0, KERNEL_TEXT_SIZE)) { if (within(cpa->vaddr, (unsigned long) _text, (unsigned long) _end))
return 0;
/* /*
* Calc the high mapping address. See __phys_addr() * If the physical address is inside the kernel map, we need
* for the non obvious details. * to touch the high mapped kernel as well:
*
* Note that NX and other required permissions are
* checked in static_protections().
*/ */
address = phys_addr + HIGH_MAP_START - phys_base; if (!within(cpa->pfn, highmap_start_pfn(), highmap_end_pfn()))
return 0;
alias_cpa = *cpa;
alias_cpa.vaddr =
(cpa->pfn << PAGE_SHIFT) + __START_KERNEL_map - phys_base;
/* /*
* Our high aliases are imprecise, because we check * The high mapping range is imprecise, so ignore the return value.
* everything between 0 and KERNEL_TEXT_SIZE, so do
* not propagate lookup failures back to users:
*/ */
__change_page_attr(address, cpa); __change_page_attr_set_clr(&alias_cpa, 0);
}
#endif #endif
return err; return ret;
} }
static int __change_page_attr_set_clr(struct cpa_data *cpa) static int __change_page_attr_set_clr(struct cpa_data *cpa, int checkalias)
{ {
int ret, numpages = cpa->numpages; int ret, numpages = cpa->numpages;
...@@ -651,10 +651,17 @@ static int __change_page_attr_set_clr(struct cpa_data *cpa) ...@@ -651,10 +651,17 @@ static int __change_page_attr_set_clr(struct cpa_data *cpa)
* preservation check. * preservation check.
*/ */
cpa->numpages = numpages; cpa->numpages = numpages;
ret = change_page_attr_addr(cpa);
ret = __change_page_attr(cpa, checkalias);
if (ret) if (ret)
return ret; return ret;
if (checkalias) {
ret = cpa_process_alias(cpa);
if (ret)
return ret;
}
/* /*
* Adjust the number of pages with the result of the * Adjust the number of pages with the result of the
* CPA operation. Either a large page has been * CPA operation. Either a large page has been
...@@ -677,7 +684,7 @@ static int change_page_attr_set_clr(unsigned long addr, int numpages, ...@@ -677,7 +684,7 @@ static int change_page_attr_set_clr(unsigned long addr, int numpages,
pgprot_t mask_set, pgprot_t mask_clr) pgprot_t mask_set, pgprot_t mask_clr)
{ {
struct cpa_data cpa; struct cpa_data cpa;
int ret, cache; int ret, cache, checkalias;
/* /*
* Check, if we are requested to change a not supported * Check, if we are requested to change a not supported
...@@ -703,7 +710,10 @@ static int change_page_attr_set_clr(unsigned long addr, int numpages, ...@@ -703,7 +710,10 @@ static int change_page_attr_set_clr(unsigned long addr, int numpages,
cpa.mask_clr = mask_clr; cpa.mask_clr = mask_clr;
cpa.flushtlb = 0; cpa.flushtlb = 0;
ret = __change_page_attr_set_clr(&cpa); /* No alias checking for _NX bit modifications */
checkalias = (pgprot_val(mask_set) | pgprot_val(mask_clr)) != _PAGE_NX;
ret = __change_page_attr_set_clr(&cpa, checkalias);
/* /*
* Check whether we really changed something: * Check whether we really changed something:
...@@ -841,7 +851,7 @@ static int __set_pages_p(struct page *page, int numpages) ...@@ -841,7 +851,7 @@ static int __set_pages_p(struct page *page, int numpages)
.mask_set = __pgprot(_PAGE_PRESENT | _PAGE_RW), .mask_set = __pgprot(_PAGE_PRESENT | _PAGE_RW),
.mask_clr = __pgprot(0)}; .mask_clr = __pgprot(0)};
return __change_page_attr_set_clr(&cpa); return __change_page_attr_set_clr(&cpa, 1);
} }
static int __set_pages_np(struct page *page, int numpages) static int __set_pages_np(struct page *page, int numpages)
...@@ -851,7 +861,7 @@ static int __set_pages_np(struct page *page, int numpages) ...@@ -851,7 +861,7 @@ static int __set_pages_np(struct page *page, int numpages)
.mask_set = __pgprot(0), .mask_set = __pgprot(0),
.mask_clr = __pgprot(_PAGE_PRESENT | _PAGE_RW)}; .mask_clr = __pgprot(_PAGE_PRESENT | _PAGE_RW)};
return __change_page_attr_set_clr(&cpa); return __change_page_attr_set_clr(&cpa, 1);
} }
void kernel_map_pages(struct page *page, int numpages, int enable) void kernel_map_pages(struct page *page, int numpages, int enable)
......
...@@ -246,6 +246,7 @@ static inline int pud_large(pud_t pte) ...@@ -246,6 +246,7 @@ static inline int pud_large(pud_t pte)
#define __swp_entry_to_pte(x) ((pte_t) { .pte = (x).val }) #define __swp_entry_to_pte(x) ((pte_t) { .pte = (x).val })
extern int kern_addr_valid(unsigned long addr); extern int kern_addr_valid(unsigned long addr);
extern void cleanup_highmap(void);
#define io_remap_pfn_range(vma, vaddr, pfn, size, prot) \ #define io_remap_pfn_range(vma, vaddr, pfn, size, prot) \
remap_pfn_range(vma, vaddr, pfn, size, prot) remap_pfn_range(vma, vaddr, pfn, size, prot)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment