Merge branch 'for-rc1/xen/core' of git://git.kernel.org/pub/scm/linux/kernel/git/jeremy/xen
* 'for-rc1/xen/core' of git://git.kernel.org/pub/scm/linux/kernel/git/jeremy/xen: xen: add FIX_TEXT_POKE to fixmap xen: honour VCPU availability on boot xen: clean up gate trap/interrupt constants xen: set _PAGE_NX in __supported_pte_mask before pagetable construction xen: resume interrupts before system devices. xen/mmu: weaken flush_tlb_other test xen/mmu: some early pagetable cleanups Xen: Add virt_to_pfn helper function x86-64: remove PGE from must-have feature list xen: mask XSAVE from cpuid NULL noise: arch/x86/xen/smp.c xen: remove xen_load_gdt debug xen: make xen_load_gdt simpler xen: clean up xen_load_gdt xen: split construction of p2m mfn tables from registration xen: separate p2m allocation from setting xen: disable preempt for leave_lazy_mmu
This commit is contained in:
commit
2e1c63b7ed
@ -50,7 +50,7 @@
|
|||||||
#ifdef CONFIG_X86_64
|
#ifdef CONFIG_X86_64
|
||||||
#define NEED_PSE 0
|
#define NEED_PSE 0
|
||||||
#define NEED_MSR (1<<(X86_FEATURE_MSR & 31))
|
#define NEED_MSR (1<<(X86_FEATURE_MSR & 31))
|
||||||
#define NEED_PGE (1<<(X86_FEATURE_PGE & 31))
|
#define NEED_PGE 0
|
||||||
#define NEED_FXSR (1<<(X86_FEATURE_FXSR & 31))
|
#define NEED_FXSR (1<<(X86_FEATURE_FXSR & 31))
|
||||||
#define NEED_XMM (1<<(X86_FEATURE_XMM & 31))
|
#define NEED_XMM (1<<(X86_FEATURE_XMM & 31))
|
||||||
#define NEED_XMM2 (1<<(X86_FEATURE_XMM2 & 31))
|
#define NEED_XMM2 (1<<(X86_FEATURE_XMM2 & 31))
|
||||||
|
@ -124,7 +124,8 @@ static inline unsigned long mfn_to_local_pfn(unsigned long mfn)
|
|||||||
|
|
||||||
/* VIRT <-> MACHINE conversion */
|
/* VIRT <-> MACHINE conversion */
|
||||||
#define virt_to_machine(v) (phys_to_machine(XPADDR(__pa(v))))
|
#define virt_to_machine(v) (phys_to_machine(XPADDR(__pa(v))))
|
||||||
#define virt_to_mfn(v) (pfn_to_mfn(PFN_DOWN(__pa(v))))
|
#define virt_to_pfn(v) (PFN_DOWN(__pa(v)))
|
||||||
|
#define virt_to_mfn(v) (pfn_to_mfn(virt_to_pfn(v)))
|
||||||
#define mfn_to_virt(m) (__va(mfn_to_pfn(m) << PAGE_SHIFT))
|
#define mfn_to_virt(m) (__va(mfn_to_pfn(m) << PAGE_SHIFT))
|
||||||
|
|
||||||
static inline unsigned long pte_mfn(pte_t pte)
|
static inline unsigned long pte_mfn(pte_t pte)
|
||||||
|
@ -42,6 +42,7 @@
|
|||||||
#include <asm/xen/hypervisor.h>
|
#include <asm/xen/hypervisor.h>
|
||||||
#include <asm/fixmap.h>
|
#include <asm/fixmap.h>
|
||||||
#include <asm/processor.h>
|
#include <asm/processor.h>
|
||||||
|
#include <asm/proto.h>
|
||||||
#include <asm/msr-index.h>
|
#include <asm/msr-index.h>
|
||||||
#include <asm/setup.h>
|
#include <asm/setup.h>
|
||||||
#include <asm/desc.h>
|
#include <asm/desc.h>
|
||||||
@ -168,21 +169,23 @@ static void __init xen_banner(void)
|
|||||||
xen_feature(XENFEAT_mmu_pt_update_preserve_ad) ? " (preserve-AD)" : "");
|
xen_feature(XENFEAT_mmu_pt_update_preserve_ad) ? " (preserve-AD)" : "");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static __read_mostly unsigned int cpuid_leaf1_edx_mask = ~0;
|
||||||
|
static __read_mostly unsigned int cpuid_leaf1_ecx_mask = ~0;
|
||||||
|
|
||||||
static void xen_cpuid(unsigned int *ax, unsigned int *bx,
|
static void xen_cpuid(unsigned int *ax, unsigned int *bx,
|
||||||
unsigned int *cx, unsigned int *dx)
|
unsigned int *cx, unsigned int *dx)
|
||||||
{
|
{
|
||||||
|
unsigned maskecx = ~0;
|
||||||
unsigned maskedx = ~0;
|
unsigned maskedx = ~0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Mask out inconvenient features, to try and disable as many
|
* Mask out inconvenient features, to try and disable as many
|
||||||
* unsupported kernel subsystems as possible.
|
* unsupported kernel subsystems as possible.
|
||||||
*/
|
*/
|
||||||
if (*ax == 1)
|
if (*ax == 1) {
|
||||||
maskedx = ~((1 << X86_FEATURE_APIC) | /* disable APIC */
|
maskecx = cpuid_leaf1_ecx_mask;
|
||||||
(1 << X86_FEATURE_ACPI) | /* disable ACPI */
|
maskedx = cpuid_leaf1_edx_mask;
|
||||||
(1 << X86_FEATURE_MCE) | /* disable MCE */
|
}
|
||||||
(1 << X86_FEATURE_MCA) | /* disable MCA */
|
|
||||||
(1 << X86_FEATURE_ACC)); /* thermal monitoring */
|
|
||||||
|
|
||||||
asm(XEN_EMULATE_PREFIX "cpuid"
|
asm(XEN_EMULATE_PREFIX "cpuid"
|
||||||
: "=a" (*ax),
|
: "=a" (*ax),
|
||||||
@ -190,9 +193,43 @@ static void xen_cpuid(unsigned int *ax, unsigned int *bx,
|
|||||||
"=c" (*cx),
|
"=c" (*cx),
|
||||||
"=d" (*dx)
|
"=d" (*dx)
|
||||||
: "0" (*ax), "2" (*cx));
|
: "0" (*ax), "2" (*cx));
|
||||||
|
|
||||||
|
*cx &= maskecx;
|
||||||
*dx &= maskedx;
|
*dx &= maskedx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static __init void xen_init_cpuid_mask(void)
|
||||||
|
{
|
||||||
|
unsigned int ax, bx, cx, dx;
|
||||||
|
|
||||||
|
cpuid_leaf1_edx_mask =
|
||||||
|
~((1 << X86_FEATURE_MCE) | /* disable MCE */
|
||||||
|
(1 << X86_FEATURE_MCA) | /* disable MCA */
|
||||||
|
(1 << X86_FEATURE_ACC)); /* thermal monitoring */
|
||||||
|
|
||||||
|
if (!xen_initial_domain())
|
||||||
|
cpuid_leaf1_edx_mask &=
|
||||||
|
~((1 << X86_FEATURE_APIC) | /* disable local APIC */
|
||||||
|
(1 << X86_FEATURE_ACPI)); /* disable ACPI */
|
||||||
|
|
||||||
|
ax = 1;
|
||||||
|
xen_cpuid(&ax, &bx, &cx, &dx);
|
||||||
|
|
||||||
|
/* cpuid claims we support xsave; try enabling it to see what happens */
|
||||||
|
if (cx & (1 << (X86_FEATURE_XSAVE % 32))) {
|
||||||
|
unsigned long cr4;
|
||||||
|
|
||||||
|
set_in_cr4(X86_CR4_OSXSAVE);
|
||||||
|
|
||||||
|
cr4 = read_cr4();
|
||||||
|
|
||||||
|
if ((cr4 & X86_CR4_OSXSAVE) == 0)
|
||||||
|
cpuid_leaf1_ecx_mask &= ~(1 << (X86_FEATURE_XSAVE % 32));
|
||||||
|
|
||||||
|
clear_in_cr4(X86_CR4_OSXSAVE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void xen_set_debugreg(int reg, unsigned long val)
|
static void xen_set_debugreg(int reg, unsigned long val)
|
||||||
{
|
{
|
||||||
HYPERVISOR_set_debugreg(reg, val);
|
HYPERVISOR_set_debugreg(reg, val);
|
||||||
@ -284,12 +321,11 @@ static void xen_set_ldt(const void *addr, unsigned entries)
|
|||||||
|
|
||||||
static void xen_load_gdt(const struct desc_ptr *dtr)
|
static void xen_load_gdt(const struct desc_ptr *dtr)
|
||||||
{
|
{
|
||||||
unsigned long *frames;
|
|
||||||
unsigned long va = dtr->address;
|
unsigned long va = dtr->address;
|
||||||
unsigned int size = dtr->size + 1;
|
unsigned int size = dtr->size + 1;
|
||||||
unsigned pages = (size + PAGE_SIZE - 1) / PAGE_SIZE;
|
unsigned pages = (size + PAGE_SIZE - 1) / PAGE_SIZE;
|
||||||
|
unsigned long frames[pages];
|
||||||
int f;
|
int f;
|
||||||
struct multicall_space mcs;
|
|
||||||
|
|
||||||
/* A GDT can be up to 64k in size, which corresponds to 8192
|
/* A GDT can be up to 64k in size, which corresponds to 8192
|
||||||
8-byte entries, or 16 4k pages.. */
|
8-byte entries, or 16 4k pages.. */
|
||||||
@ -297,19 +333,26 @@ static void xen_load_gdt(const struct desc_ptr *dtr)
|
|||||||
BUG_ON(size > 65536);
|
BUG_ON(size > 65536);
|
||||||
BUG_ON(va & ~PAGE_MASK);
|
BUG_ON(va & ~PAGE_MASK);
|
||||||
|
|
||||||
mcs = xen_mc_entry(sizeof(*frames) * pages);
|
|
||||||
frames = mcs.args;
|
|
||||||
|
|
||||||
for (f = 0; va < dtr->address + size; va += PAGE_SIZE, f++) {
|
for (f = 0; va < dtr->address + size; va += PAGE_SIZE, f++) {
|
||||||
frames[f] = arbitrary_virt_to_mfn((void *)va);
|
int level;
|
||||||
|
pte_t *ptep = lookup_address(va, &level);
|
||||||
|
unsigned long pfn, mfn;
|
||||||
|
void *virt;
|
||||||
|
|
||||||
|
BUG_ON(ptep == NULL);
|
||||||
|
|
||||||
|
pfn = pte_pfn(*ptep);
|
||||||
|
mfn = pfn_to_mfn(pfn);
|
||||||
|
virt = __va(PFN_PHYS(pfn));
|
||||||
|
|
||||||
|
frames[f] = mfn;
|
||||||
|
|
||||||
make_lowmem_page_readonly((void *)va);
|
make_lowmem_page_readonly((void *)va);
|
||||||
make_lowmem_page_readonly(mfn_to_virt(frames[f]));
|
make_lowmem_page_readonly(virt);
|
||||||
}
|
}
|
||||||
|
|
||||||
MULTI_set_gdt(mcs.mc, frames, size / sizeof(struct desc_struct));
|
if (HYPERVISOR_set_gdt(frames, size / sizeof(struct desc_struct)))
|
||||||
|
BUG();
|
||||||
xen_mc_issue(PARAVIRT_LAZY_CPU);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void load_TLS_descriptor(struct thread_struct *t,
|
static void load_TLS_descriptor(struct thread_struct *t,
|
||||||
@ -385,7 +428,7 @@ static void xen_write_ldt_entry(struct desc_struct *dt, int entrynum,
|
|||||||
static int cvt_gate_to_trap(int vector, const gate_desc *val,
|
static int cvt_gate_to_trap(int vector, const gate_desc *val,
|
||||||
struct trap_info *info)
|
struct trap_info *info)
|
||||||
{
|
{
|
||||||
if (val->type != 0xf && val->type != 0xe)
|
if (val->type != GATE_TRAP && val->type != GATE_INTERRUPT)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
info->vector = vector;
|
info->vector = vector;
|
||||||
@ -393,8 +436,8 @@ static int cvt_gate_to_trap(int vector, const gate_desc *val,
|
|||||||
info->cs = gate_segment(*val);
|
info->cs = gate_segment(*val);
|
||||||
info->flags = val->dpl;
|
info->flags = val->dpl;
|
||||||
/* interrupt gates clear IF */
|
/* interrupt gates clear IF */
|
||||||
if (val->type == 0xe)
|
if (val->type == GATE_INTERRUPT)
|
||||||
info->flags |= 4;
|
info->flags |= 1 << 2;
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -872,7 +915,6 @@ static const struct machine_ops __initdata xen_machine_ops = {
|
|||||||
.emergency_restart = xen_emergency_restart,
|
.emergency_restart = xen_emergency_restart,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/* First C function to be called on Xen boot */
|
/* First C function to be called on Xen boot */
|
||||||
asmlinkage void __init xen_start_kernel(void)
|
asmlinkage void __init xen_start_kernel(void)
|
||||||
{
|
{
|
||||||
@ -897,6 +939,8 @@ asmlinkage void __init xen_start_kernel(void)
|
|||||||
|
|
||||||
xen_init_irq_ops();
|
xen_init_irq_ops();
|
||||||
|
|
||||||
|
xen_init_cpuid_mask();
|
||||||
|
|
||||||
#ifdef CONFIG_X86_LOCAL_APIC
|
#ifdef CONFIG_X86_LOCAL_APIC
|
||||||
/*
|
/*
|
||||||
* set up the basic apic ops.
|
* set up the basic apic ops.
|
||||||
@ -938,6 +982,11 @@ asmlinkage void __init xen_start_kernel(void)
|
|||||||
if (!xen_initial_domain())
|
if (!xen_initial_domain())
|
||||||
__supported_pte_mask &= ~(_PAGE_PWT | _PAGE_PCD);
|
__supported_pte_mask &= ~(_PAGE_PWT | _PAGE_PCD);
|
||||||
|
|
||||||
|
#ifdef CONFIG_X86_64
|
||||||
|
/* Work out if we support NX */
|
||||||
|
check_efer();
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Don't do the full vcpu_info placement stuff until we have a
|
/* Don't do the full vcpu_info placement stuff until we have a
|
||||||
possible map and a non-dummy shared_info. */
|
possible map and a non-dummy shared_info. */
|
||||||
per_cpu(xen_vcpu, 0) = &HYPERVISOR_shared_info->vcpu_info[0];
|
per_cpu(xen_vcpu, 0) = &HYPERVISOR_shared_info->vcpu_info[0];
|
||||||
|
@ -184,7 +184,7 @@ static inline unsigned p2m_index(unsigned long pfn)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Build the parallel p2m_top_mfn structures */
|
/* Build the parallel p2m_top_mfn structures */
|
||||||
void xen_setup_mfn_list_list(void)
|
static void __init xen_build_mfn_list_list(void)
|
||||||
{
|
{
|
||||||
unsigned pfn, idx;
|
unsigned pfn, idx;
|
||||||
|
|
||||||
@ -198,7 +198,10 @@ void xen_setup_mfn_list_list(void)
|
|||||||
unsigned topidx = idx * P2M_ENTRIES_PER_PAGE;
|
unsigned topidx = idx * P2M_ENTRIES_PER_PAGE;
|
||||||
p2m_top_mfn_list[idx] = virt_to_mfn(&p2m_top_mfn[topidx]);
|
p2m_top_mfn_list[idx] = virt_to_mfn(&p2m_top_mfn[topidx]);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void xen_setup_mfn_list_list(void)
|
||||||
|
{
|
||||||
BUG_ON(HYPERVISOR_shared_info == &xen_dummy_shared_info);
|
BUG_ON(HYPERVISOR_shared_info == &xen_dummy_shared_info);
|
||||||
|
|
||||||
HYPERVISOR_shared_info->arch.pfn_to_mfn_frame_list_list =
|
HYPERVISOR_shared_info->arch.pfn_to_mfn_frame_list_list =
|
||||||
@ -218,6 +221,8 @@ void __init xen_build_dynamic_phys_to_machine(void)
|
|||||||
|
|
||||||
p2m_top[topidx] = &mfn_list[pfn];
|
p2m_top[topidx] = &mfn_list[pfn];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
xen_build_mfn_list_list();
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned long get_phys_to_machine(unsigned long pfn)
|
unsigned long get_phys_to_machine(unsigned long pfn)
|
||||||
@ -233,47 +238,74 @@ unsigned long get_phys_to_machine(unsigned long pfn)
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(get_phys_to_machine);
|
EXPORT_SYMBOL_GPL(get_phys_to_machine);
|
||||||
|
|
||||||
static void alloc_p2m(unsigned long **pp, unsigned long *mfnp)
|
/* install a new p2m_top page */
|
||||||
|
bool install_p2mtop_page(unsigned long pfn, unsigned long *p)
|
||||||
{
|
{
|
||||||
unsigned long *p;
|
unsigned topidx = p2m_top_index(pfn);
|
||||||
|
unsigned long **pfnp, *mfnp;
|
||||||
unsigned i;
|
unsigned i;
|
||||||
|
|
||||||
p = (void *)__get_free_page(GFP_KERNEL | __GFP_NOFAIL);
|
pfnp = &p2m_top[topidx];
|
||||||
BUG_ON(p == NULL);
|
mfnp = &p2m_top_mfn[topidx];
|
||||||
|
|
||||||
for (i = 0; i < P2M_ENTRIES_PER_PAGE; i++)
|
for (i = 0; i < P2M_ENTRIES_PER_PAGE; i++)
|
||||||
p[i] = INVALID_P2M_ENTRY;
|
p[i] = INVALID_P2M_ENTRY;
|
||||||
|
|
||||||
if (cmpxchg(pp, p2m_missing, p) != p2m_missing)
|
if (cmpxchg(pfnp, p2m_missing, p) == p2m_missing) {
|
||||||
free_page((unsigned long)p);
|
|
||||||
else
|
|
||||||
*mfnp = virt_to_mfn(p);
|
*mfnp = virt_to_mfn(p);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void alloc_p2m(unsigned long pfn)
|
||||||
|
{
|
||||||
|
unsigned long *p;
|
||||||
|
|
||||||
|
p = (void *)__get_free_page(GFP_KERNEL | __GFP_NOFAIL);
|
||||||
|
BUG_ON(p == NULL);
|
||||||
|
|
||||||
|
if (!install_p2mtop_page(pfn, p))
|
||||||
|
free_page((unsigned long)p);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Try to install p2m mapping; fail if intermediate bits missing */
|
||||||
|
bool __set_phys_to_machine(unsigned long pfn, unsigned long mfn)
|
||||||
|
{
|
||||||
|
unsigned topidx, idx;
|
||||||
|
|
||||||
|
if (unlikely(pfn >= MAX_DOMAIN_PAGES)) {
|
||||||
|
BUG_ON(mfn != INVALID_P2M_ENTRY);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
topidx = p2m_top_index(pfn);
|
||||||
|
if (p2m_top[topidx] == p2m_missing) {
|
||||||
|
if (mfn == INVALID_P2M_ENTRY)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
idx = p2m_index(pfn);
|
||||||
|
p2m_top[topidx][idx] = mfn;
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_phys_to_machine(unsigned long pfn, unsigned long mfn)
|
void set_phys_to_machine(unsigned long pfn, unsigned long mfn)
|
||||||
{
|
{
|
||||||
unsigned topidx, idx;
|
|
||||||
|
|
||||||
if (unlikely(xen_feature(XENFEAT_auto_translated_physmap))) {
|
if (unlikely(xen_feature(XENFEAT_auto_translated_physmap))) {
|
||||||
BUG_ON(pfn != mfn && mfn != INVALID_P2M_ENTRY);
|
BUG_ON(pfn != mfn && mfn != INVALID_P2M_ENTRY);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (unlikely(pfn >= MAX_DOMAIN_PAGES)) {
|
if (unlikely(!__set_phys_to_machine(pfn, mfn))) {
|
||||||
BUG_ON(mfn != INVALID_P2M_ENTRY);
|
alloc_p2m(pfn);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
topidx = p2m_top_index(pfn);
|
if (!__set_phys_to_machine(pfn, mfn))
|
||||||
if (p2m_top[topidx] == p2m_missing) {
|
BUG();
|
||||||
/* no need to allocate a page to store an invalid entry */
|
|
||||||
if (mfn == INVALID_P2M_ENTRY)
|
|
||||||
return;
|
|
||||||
alloc_p2m(&p2m_top[topidx], &p2m_top_mfn[topidx]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
idx = p2m_index(pfn);
|
|
||||||
p2m_top[topidx][idx] = mfn;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned long arbitrary_virt_to_mfn(void *vaddr)
|
unsigned long arbitrary_virt_to_mfn(void *vaddr)
|
||||||
@ -987,7 +1019,7 @@ static __init int xen_mark_pinned(struct mm_struct *mm, struct page *page,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void __init xen_mark_init_mm_pinned(void)
|
static void __init xen_mark_init_mm_pinned(void)
|
||||||
{
|
{
|
||||||
xen_pgd_walk(&init_mm, xen_mark_pinned, FIXADDR_TOP);
|
xen_pgd_walk(&init_mm, xen_mark_pinned, FIXADDR_TOP);
|
||||||
}
|
}
|
||||||
@ -1270,8 +1302,8 @@ static void xen_flush_tlb_others(const struct cpumask *cpus,
|
|||||||
} *args;
|
} *args;
|
||||||
struct multicall_space mcs;
|
struct multicall_space mcs;
|
||||||
|
|
||||||
BUG_ON(cpumask_empty(cpus));
|
if (cpumask_empty(cpus))
|
||||||
BUG_ON(!mm);
|
return; /* nothing to do */
|
||||||
|
|
||||||
mcs = xen_mc_entry(sizeof(*args));
|
mcs = xen_mc_entry(sizeof(*args));
|
||||||
args = mcs.args;
|
args = mcs.args;
|
||||||
@ -1438,10 +1470,29 @@ static __init void xen_set_pte_init(pte_t *ptep, pte_t pte)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static void pin_pagetable_pfn(unsigned cmd, unsigned long pfn)
|
||||||
|
{
|
||||||
|
struct mmuext_op op;
|
||||||
|
op.cmd = cmd;
|
||||||
|
op.arg1.mfn = pfn_to_mfn(pfn);
|
||||||
|
if (HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF))
|
||||||
|
BUG();
|
||||||
|
}
|
||||||
|
|
||||||
/* Early in boot, while setting up the initial pagetable, assume
|
/* Early in boot, while setting up the initial pagetable, assume
|
||||||
everything is pinned. */
|
everything is pinned. */
|
||||||
static __init void xen_alloc_pte_init(struct mm_struct *mm, unsigned long pfn)
|
static __init void xen_alloc_pte_init(struct mm_struct *mm, unsigned long pfn)
|
||||||
{
|
{
|
||||||
|
#ifdef CONFIG_FLATMEM
|
||||||
|
BUG_ON(mem_map); /* should only be used early */
|
||||||
|
#endif
|
||||||
|
make_lowmem_page_readonly(__va(PFN_PHYS(pfn)));
|
||||||
|
pin_pagetable_pfn(MMUEXT_PIN_L1_TABLE, pfn);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Used for pmd and pud */
|
||||||
|
static __init void xen_alloc_pmd_init(struct mm_struct *mm, unsigned long pfn)
|
||||||
|
{
|
||||||
#ifdef CONFIG_FLATMEM
|
#ifdef CONFIG_FLATMEM
|
||||||
BUG_ON(mem_map); /* should only be used early */
|
BUG_ON(mem_map); /* should only be used early */
|
||||||
#endif
|
#endif
|
||||||
@ -1450,18 +1501,15 @@ static __init void xen_alloc_pte_init(struct mm_struct *mm, unsigned long pfn)
|
|||||||
|
|
||||||
/* Early release_pte assumes that all pts are pinned, since there's
|
/* Early release_pte assumes that all pts are pinned, since there's
|
||||||
only init_mm and anything attached to that is pinned. */
|
only init_mm and anything attached to that is pinned. */
|
||||||
static void xen_release_pte_init(unsigned long pfn)
|
static __init void xen_release_pte_init(unsigned long pfn)
|
||||||
{
|
{
|
||||||
|
pin_pagetable_pfn(MMUEXT_UNPIN_TABLE, pfn);
|
||||||
make_lowmem_page_readwrite(__va(PFN_PHYS(pfn)));
|
make_lowmem_page_readwrite(__va(PFN_PHYS(pfn)));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pin_pagetable_pfn(unsigned cmd, unsigned long pfn)
|
static __init void xen_release_pmd_init(unsigned long pfn)
|
||||||
{
|
{
|
||||||
struct mmuext_op op;
|
make_lowmem_page_readwrite(__va(PFN_PHYS(pfn)));
|
||||||
op.cmd = cmd;
|
|
||||||
op.arg1.mfn = pfn_to_mfn(pfn);
|
|
||||||
if (HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF))
|
|
||||||
BUG();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This needs to make sure the new pte page is pinned iff its being
|
/* This needs to make sure the new pte page is pinned iff its being
|
||||||
@ -1773,6 +1821,9 @@ static void xen_set_fixmap(unsigned idx, phys_addr_t phys, pgprot_t prot)
|
|||||||
#ifdef CONFIG_X86_LOCAL_APIC
|
#ifdef CONFIG_X86_LOCAL_APIC
|
||||||
case FIX_APIC_BASE: /* maps dummy local APIC */
|
case FIX_APIC_BASE: /* maps dummy local APIC */
|
||||||
#endif
|
#endif
|
||||||
|
case FIX_TEXT_POKE0:
|
||||||
|
case FIX_TEXT_POKE1:
|
||||||
|
/* All local page mappings */
|
||||||
pte = pfn_pte(phys, prot);
|
pte = pfn_pte(phys, prot);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -1819,7 +1870,6 @@ __init void xen_post_allocator_init(void)
|
|||||||
xen_mark_init_mm_pinned();
|
xen_mark_init_mm_pinned();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const struct pv_mmu_ops xen_mmu_ops __initdata = {
|
const struct pv_mmu_ops xen_mmu_ops __initdata = {
|
||||||
.pagetable_setup_start = xen_pagetable_setup_start,
|
.pagetable_setup_start = xen_pagetable_setup_start,
|
||||||
.pagetable_setup_done = xen_pagetable_setup_done,
|
.pagetable_setup_done = xen_pagetable_setup_done,
|
||||||
@ -1843,9 +1893,9 @@ const struct pv_mmu_ops xen_mmu_ops __initdata = {
|
|||||||
|
|
||||||
.alloc_pte = xen_alloc_pte_init,
|
.alloc_pte = xen_alloc_pte_init,
|
||||||
.release_pte = xen_release_pte_init,
|
.release_pte = xen_release_pte_init,
|
||||||
.alloc_pmd = xen_alloc_pte_init,
|
.alloc_pmd = xen_alloc_pmd_init,
|
||||||
.alloc_pmd_clone = paravirt_nop,
|
.alloc_pmd_clone = paravirt_nop,
|
||||||
.release_pmd = xen_release_pte_init,
|
.release_pmd = xen_release_pmd_init,
|
||||||
|
|
||||||
#ifdef CONFIG_HIGHPTE
|
#ifdef CONFIG_HIGHPTE
|
||||||
.kmap_atomic_pte = xen_kmap_atomic_pte,
|
.kmap_atomic_pte = xen_kmap_atomic_pte,
|
||||||
@ -1883,8 +1933,8 @@ const struct pv_mmu_ops xen_mmu_ops __initdata = {
|
|||||||
.make_pud = PV_CALLEE_SAVE(xen_make_pud),
|
.make_pud = PV_CALLEE_SAVE(xen_make_pud),
|
||||||
.set_pgd = xen_set_pgd_hyper,
|
.set_pgd = xen_set_pgd_hyper,
|
||||||
|
|
||||||
.alloc_pud = xen_alloc_pte_init,
|
.alloc_pud = xen_alloc_pmd_init,
|
||||||
.release_pud = xen_release_pte_init,
|
.release_pud = xen_release_pmd_init,
|
||||||
#endif /* PAGETABLE_LEVELS == 4 */
|
#endif /* PAGETABLE_LEVELS == 4 */
|
||||||
|
|
||||||
.activate_mm = xen_activate_mm,
|
.activate_mm = xen_activate_mm,
|
||||||
|
@ -11,6 +11,9 @@ enum pt_level {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
bool __set_phys_to_machine(unsigned long pfn, unsigned long mfn);
|
||||||
|
bool install_p2mtop_page(unsigned long pfn, unsigned long *p);
|
||||||
|
|
||||||
void set_pte_mfn(unsigned long vaddr, unsigned long pfn, pgprot_t flags);
|
void set_pte_mfn(unsigned long vaddr, unsigned long pfn, pgprot_t flags);
|
||||||
|
|
||||||
|
|
||||||
|
@ -317,7 +317,7 @@ static int __cpuinit xen_cpu_up(unsigned int cpu)
|
|||||||
BUG_ON(rc);
|
BUG_ON(rc);
|
||||||
|
|
||||||
while(per_cpu(cpu_state, cpu) != CPU_ONLINE) {
|
while(per_cpu(cpu_state, cpu) != CPU_ONLINE) {
|
||||||
HYPERVISOR_sched_op(SCHEDOP_yield, 0);
|
HYPERVISOR_sched_op(SCHEDOP_yield, NULL);
|
||||||
barrier();
|
barrier();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -422,7 +422,7 @@ static void xen_smp_send_call_function_ipi(const struct cpumask *mask)
|
|||||||
/* Make sure other vcpus get a chance to run if they need to. */
|
/* Make sure other vcpus get a chance to run if they need to. */
|
||||||
for_each_cpu(cpu, mask) {
|
for_each_cpu(cpu, mask) {
|
||||||
if (xen_vcpu_stolen(cpu)) {
|
if (xen_vcpu_stolen(cpu)) {
|
||||||
HYPERVISOR_sched_op(SCHEDOP_yield, 0);
|
HYPERVISOR_sched_op(SCHEDOP_yield, NULL);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -57,8 +57,6 @@ irqreturn_t xen_debug_interrupt(int irq, void *dev_id);
|
|||||||
|
|
||||||
bool xen_vcpu_stolen(int vcpu);
|
bool xen_vcpu_stolen(int vcpu);
|
||||||
|
|
||||||
void xen_mark_init_mm_pinned(void);
|
|
||||||
|
|
||||||
void xen_setup_vcpu_info_placement(void);
|
void xen_setup_vcpu_info_placement(void);
|
||||||
|
|
||||||
#ifdef CONFIG_SMP
|
#ifdef CONFIG_SMP
|
||||||
|
@ -21,29 +21,41 @@ static void disable_hotplug_cpu(int cpu)
|
|||||||
set_cpu_present(cpu, false);
|
set_cpu_present(cpu, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void vcpu_hotplug(unsigned int cpu)
|
static int vcpu_online(unsigned int cpu)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
char dir[32], state[32];
|
char dir[32], state[32];
|
||||||
|
|
||||||
if (!cpu_possible(cpu))
|
|
||||||
return;
|
|
||||||
|
|
||||||
sprintf(dir, "cpu/%u", cpu);
|
sprintf(dir, "cpu/%u", cpu);
|
||||||
err = xenbus_scanf(XBT_NIL, dir, "availability", "%s", state);
|
err = xenbus_scanf(XBT_NIL, dir, "availability", "%s", state);
|
||||||
if (err != 1) {
|
if (err != 1) {
|
||||||
printk(KERN_ERR "XENBUS: Unable to read cpu state\n");
|
printk(KERN_ERR "XENBUS: Unable to read cpu state\n");
|
||||||
return;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strcmp(state, "online") == 0) {
|
if (strcmp(state, "online") == 0)
|
||||||
|
return 1;
|
||||||
|
else if (strcmp(state, "offline") == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
printk(KERN_ERR "XENBUS: unknown state(%s) on CPU%d\n", state, cpu);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
static void vcpu_hotplug(unsigned int cpu)
|
||||||
|
{
|
||||||
|
if (!cpu_possible(cpu))
|
||||||
|
return;
|
||||||
|
|
||||||
|
switch (vcpu_online(cpu)) {
|
||||||
|
case 1:
|
||||||
enable_hotplug_cpu(cpu);
|
enable_hotplug_cpu(cpu);
|
||||||
} else if (strcmp(state, "offline") == 0) {
|
break;
|
||||||
|
case 0:
|
||||||
(void)cpu_down(cpu);
|
(void)cpu_down(cpu);
|
||||||
disable_hotplug_cpu(cpu);
|
disable_hotplug_cpu(cpu);
|
||||||
} else {
|
break;
|
||||||
printk(KERN_ERR "XENBUS: unknown state(%s) on CPU%d\n",
|
default:
|
||||||
state, cpu);
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,12 +76,20 @@ static void handle_vcpu_hotplug_event(struct xenbus_watch *watch,
|
|||||||
static int setup_cpu_watcher(struct notifier_block *notifier,
|
static int setup_cpu_watcher(struct notifier_block *notifier,
|
||||||
unsigned long event, void *data)
|
unsigned long event, void *data)
|
||||||
{
|
{
|
||||||
|
int cpu;
|
||||||
static struct xenbus_watch cpu_watch = {
|
static struct xenbus_watch cpu_watch = {
|
||||||
.node = "cpu",
|
.node = "cpu",
|
||||||
.callback = handle_vcpu_hotplug_event};
|
.callback = handle_vcpu_hotplug_event};
|
||||||
|
|
||||||
(void)register_xenbus_watch(&cpu_watch);
|
(void)register_xenbus_watch(&cpu_watch);
|
||||||
|
|
||||||
|
for_each_possible_cpu(cpu) {
|
||||||
|
if (vcpu_online(cpu) == 0) {
|
||||||
|
(void)cpu_down(cpu);
|
||||||
|
cpu_clear(cpu, cpu_present_map);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return NOTIFY_DONE;
|
return NOTIFY_DONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,14 +62,15 @@ static int xen_suspend(void *data)
|
|||||||
gnttab_resume();
|
gnttab_resume();
|
||||||
xen_mm_unpin_all();
|
xen_mm_unpin_all();
|
||||||
|
|
||||||
sysdev_resume();
|
|
||||||
|
|
||||||
if (!*cancelled) {
|
if (!*cancelled) {
|
||||||
xen_irq_resume();
|
xen_irq_resume();
|
||||||
xen_console_resume();
|
xen_console_resume();
|
||||||
xen_timer_resume();
|
xen_timer_resume();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sysdev_resume();
|
||||||
|
device_power_up(PMSG_RESUME);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user