Merge branch 'upstream/for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jeremy/xen
* 'upstream/for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jeremy/xen: (23 commits) xen/events: Use PIRQ instead of GSI value when unmapping MSI/MSI-X irqs. xen: set IO permission early (before early_cpu_init()) xen: re-enable boot-time ballooning xen/balloon: make sure we only include remaining extra ram xen/balloon: the balloon_lock is useless xen: add extra pages to balloon xen: make evtchn's name less generic xen/evtchn: the evtchn device is non-seekable Revert "xen/privcmd: create address space to allow writable mmaps" xen/events: use locked set|clear_bit() for cpu_evtchn_mask xen/evtchn: clear secondary CPUs' cpu_evtchn_mask[] after restore xen/xenfs: update xenfs_mount for new prototype xen: fix header export to userspace xen: implement XENMEM_machphys_mapping xen: set vma flag VM_PFNMAP in the privcmd mmap file_op xen: xenfs: privcmd: check put_user() return code xen/evtchn: add missing static xen/evtchn: Fix name of Xen event-channel device xen/evtchn: don't do unbind_from_irqhandler under spinlock xen/evtchn: remove spurious barrier ...
This commit is contained in:
commit
a4ec046c98
@ -61,9 +61,9 @@ DEFINE_GUEST_HANDLE(void);
|
|||||||
#define HYPERVISOR_VIRT_START mk_unsigned_long(__HYPERVISOR_VIRT_START)
|
#define HYPERVISOR_VIRT_START mk_unsigned_long(__HYPERVISOR_VIRT_START)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef machine_to_phys_mapping
|
#define MACH2PHYS_VIRT_START mk_unsigned_long(__MACH2PHYS_VIRT_START)
|
||||||
#define machine_to_phys_mapping ((unsigned long *)HYPERVISOR_VIRT_START)
|
#define MACH2PHYS_VIRT_END mk_unsigned_long(__MACH2PHYS_VIRT_END)
|
||||||
#endif
|
#define MACH2PHYS_NR_ENTRIES ((MACH2PHYS_VIRT_END-MACH2PHYS_VIRT_START)>>__MACH2PHYS_SHIFT)
|
||||||
|
|
||||||
/* Maximum number of virtual CPUs in multi-processor guests. */
|
/* Maximum number of virtual CPUs in multi-processor guests. */
|
||||||
#define MAX_VIRT_CPUS 32
|
#define MAX_VIRT_CPUS 32
|
||||||
|
@ -32,6 +32,11 @@
|
|||||||
/* And the trap vector is... */
|
/* And the trap vector is... */
|
||||||
#define TRAP_INSTR "int $0x82"
|
#define TRAP_INSTR "int $0x82"
|
||||||
|
|
||||||
|
#define __MACH2PHYS_VIRT_START 0xF5800000
|
||||||
|
#define __MACH2PHYS_VIRT_END 0xF6800000
|
||||||
|
|
||||||
|
#define __MACH2PHYS_SHIFT 2
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Virtual addresses beyond this are not modifiable by guest OSes. The
|
* Virtual addresses beyond this are not modifiable by guest OSes. The
|
||||||
* machine->physical mapping table starts at this address, read-only.
|
* machine->physical mapping table starts at this address, read-only.
|
||||||
|
@ -39,18 +39,7 @@
|
|||||||
#define __HYPERVISOR_VIRT_END 0xFFFF880000000000
|
#define __HYPERVISOR_VIRT_END 0xFFFF880000000000
|
||||||
#define __MACH2PHYS_VIRT_START 0xFFFF800000000000
|
#define __MACH2PHYS_VIRT_START 0xFFFF800000000000
|
||||||
#define __MACH2PHYS_VIRT_END 0xFFFF804000000000
|
#define __MACH2PHYS_VIRT_END 0xFFFF804000000000
|
||||||
|
#define __MACH2PHYS_SHIFT 3
|
||||||
#ifndef HYPERVISOR_VIRT_START
|
|
||||||
#define HYPERVISOR_VIRT_START mk_unsigned_long(__HYPERVISOR_VIRT_START)
|
|
||||||
#define HYPERVISOR_VIRT_END mk_unsigned_long(__HYPERVISOR_VIRT_END)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define MACH2PHYS_VIRT_START mk_unsigned_long(__MACH2PHYS_VIRT_START)
|
|
||||||
#define MACH2PHYS_VIRT_END mk_unsigned_long(__MACH2PHYS_VIRT_END)
|
|
||||||
#define MACH2PHYS_NR_ENTRIES ((MACH2PHYS_VIRT_END-MACH2PHYS_VIRT_START)>>3)
|
|
||||||
#ifndef machine_to_phys_mapping
|
|
||||||
#define machine_to_phys_mapping ((unsigned long *)HYPERVISOR_VIRT_START)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* int HYPERVISOR_set_segment_base(unsigned int which, unsigned long base)
|
* int HYPERVISOR_set_segment_base(unsigned int which, unsigned long base)
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
#include <linux/spinlock.h>
|
#include <linux/spinlock.h>
|
||||||
#include <linux/pfn.h>
|
#include <linux/pfn.h>
|
||||||
|
#include <linux/mm.h>
|
||||||
|
|
||||||
#include <asm/uaccess.h>
|
#include <asm/uaccess.h>
|
||||||
#include <asm/page.h>
|
#include <asm/page.h>
|
||||||
@ -35,6 +36,8 @@ typedef struct xpaddr {
|
|||||||
#define MAX_DOMAIN_PAGES \
|
#define MAX_DOMAIN_PAGES \
|
||||||
((unsigned long)((u64)CONFIG_XEN_MAX_DOMAIN_MEMORY * 1024 * 1024 * 1024 / PAGE_SIZE))
|
((unsigned long)((u64)CONFIG_XEN_MAX_DOMAIN_MEMORY * 1024 * 1024 * 1024 / PAGE_SIZE))
|
||||||
|
|
||||||
|
extern unsigned long *machine_to_phys_mapping;
|
||||||
|
extern unsigned int machine_to_phys_order;
|
||||||
|
|
||||||
extern unsigned long get_phys_to_machine(unsigned long pfn);
|
extern unsigned long get_phys_to_machine(unsigned long pfn);
|
||||||
extern bool set_phys_to_machine(unsigned long pfn, unsigned long mfn);
|
extern bool set_phys_to_machine(unsigned long pfn, unsigned long mfn);
|
||||||
@ -69,10 +72,8 @@ static inline unsigned long mfn_to_pfn(unsigned long mfn)
|
|||||||
if (xen_feature(XENFEAT_auto_translated_physmap))
|
if (xen_feature(XENFEAT_auto_translated_physmap))
|
||||||
return mfn;
|
return mfn;
|
||||||
|
|
||||||
#if 0
|
|
||||||
if (unlikely((mfn >> machine_to_phys_order) != 0))
|
if (unlikely((mfn >> machine_to_phys_order) != 0))
|
||||||
return max_mapnr;
|
return ~0;
|
||||||
#endif
|
|
||||||
|
|
||||||
pfn = 0;
|
pfn = 0;
|
||||||
/*
|
/*
|
||||||
|
@ -75,6 +75,11 @@ DEFINE_PER_CPU(struct vcpu_info, xen_vcpu_info);
|
|||||||
enum xen_domain_type xen_domain_type = XEN_NATIVE;
|
enum xen_domain_type xen_domain_type = XEN_NATIVE;
|
||||||
EXPORT_SYMBOL_GPL(xen_domain_type);
|
EXPORT_SYMBOL_GPL(xen_domain_type);
|
||||||
|
|
||||||
|
unsigned long *machine_to_phys_mapping = (void *)MACH2PHYS_VIRT_START;
|
||||||
|
EXPORT_SYMBOL(machine_to_phys_mapping);
|
||||||
|
unsigned int machine_to_phys_order;
|
||||||
|
EXPORT_SYMBOL(machine_to_phys_order);
|
||||||
|
|
||||||
struct start_info *xen_start_info;
|
struct start_info *xen_start_info;
|
||||||
EXPORT_SYMBOL_GPL(xen_start_info);
|
EXPORT_SYMBOL_GPL(xen_start_info);
|
||||||
|
|
||||||
@ -1090,6 +1095,8 @@ static void __init xen_setup_stackprotector(void)
|
|||||||
/* 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)
|
||||||
{
|
{
|
||||||
|
struct physdev_set_iopl set_iopl;
|
||||||
|
int rc;
|
||||||
pgd_t *pgd;
|
pgd_t *pgd;
|
||||||
|
|
||||||
if (!xen_start_info)
|
if (!xen_start_info)
|
||||||
@ -1097,6 +1104,8 @@ asmlinkage void __init xen_start_kernel(void)
|
|||||||
|
|
||||||
xen_domain_type = XEN_PV_DOMAIN;
|
xen_domain_type = XEN_PV_DOMAIN;
|
||||||
|
|
||||||
|
xen_setup_machphys_mapping();
|
||||||
|
|
||||||
/* Install Xen paravirt ops */
|
/* Install Xen paravirt ops */
|
||||||
pv_info = xen_info;
|
pv_info = xen_info;
|
||||||
pv_init_ops = xen_init_ops;
|
pv_init_ops = xen_init_ops;
|
||||||
@ -1202,10 +1211,18 @@ asmlinkage void __init xen_start_kernel(void)
|
|||||||
#else
|
#else
|
||||||
pv_info.kernel_rpl = 0;
|
pv_info.kernel_rpl = 0;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* set the limit of our address space */
|
/* set the limit of our address space */
|
||||||
xen_reserve_top();
|
xen_reserve_top();
|
||||||
|
|
||||||
|
/* We used to do this in xen_arch_setup, but that is too late on AMD
|
||||||
|
* were early_cpu_init (run before ->arch_setup()) calls early_amd_init
|
||||||
|
* which pokes 0xcf8 port.
|
||||||
|
*/
|
||||||
|
set_iopl.iopl = 1;
|
||||||
|
rc = HYPERVISOR_physdev_op(PHYSDEVOP_set_iopl, &set_iopl);
|
||||||
|
if (rc != 0)
|
||||||
|
xen_raw_printk("physdev_op failed %d\n", rc);
|
||||||
|
|
||||||
#ifdef CONFIG_X86_32
|
#ifdef CONFIG_X86_32
|
||||||
/* set up basic CPUID stuff */
|
/* set up basic CPUID stuff */
|
||||||
cpu_detect(&new_cpu_data);
|
cpu_detect(&new_cpu_data);
|
||||||
|
@ -2034,6 +2034,20 @@ static __init void xen_map_identity_early(pmd_t *pmd, unsigned long max_pfn)
|
|||||||
set_page_prot(pmd, PAGE_KERNEL_RO);
|
set_page_prot(pmd, PAGE_KERNEL_RO);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void __init xen_setup_machphys_mapping(void)
|
||||||
|
{
|
||||||
|
struct xen_machphys_mapping mapping;
|
||||||
|
unsigned long machine_to_phys_nr_ents;
|
||||||
|
|
||||||
|
if (HYPERVISOR_memory_op(XENMEM_machphys_mapping, &mapping) == 0) {
|
||||||
|
machine_to_phys_mapping = (unsigned long *)mapping.v_start;
|
||||||
|
machine_to_phys_nr_ents = mapping.max_mfn + 1;
|
||||||
|
} else {
|
||||||
|
machine_to_phys_nr_ents = MACH2PHYS_NR_ENTRIES;
|
||||||
|
}
|
||||||
|
machine_to_phys_order = fls(machine_to_phys_nr_ents - 1);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_X86_64
|
#ifdef CONFIG_X86_64
|
||||||
static void convert_pfn_mfn(void *v)
|
static void convert_pfn_mfn(void *v)
|
||||||
{
|
{
|
||||||
@ -2627,7 +2641,8 @@ int xen_remap_domain_mfn_range(struct vm_area_struct *vma,
|
|||||||
|
|
||||||
prot = __pgprot(pgprot_val(prot) | _PAGE_IOMAP);
|
prot = __pgprot(pgprot_val(prot) | _PAGE_IOMAP);
|
||||||
|
|
||||||
vma->vm_flags |= VM_IO | VM_RESERVED | VM_PFNMAP;
|
BUG_ON(!((vma->vm_flags & (VM_PFNMAP | VM_RESERVED | VM_IO)) ==
|
||||||
|
(VM_PFNMAP | VM_RESERVED | VM_IO)));
|
||||||
|
|
||||||
rmd.mfn = mfn;
|
rmd.mfn = mfn;
|
||||||
rmd.prot = prot;
|
rmd.prot = prot;
|
||||||
|
@ -248,8 +248,7 @@ char * __init xen_memory_setup(void)
|
|||||||
else
|
else
|
||||||
extra_pages = 0;
|
extra_pages = 0;
|
||||||
|
|
||||||
if (!xen_initial_domain())
|
xen_add_extra_mem(extra_pages);
|
||||||
xen_add_extra_mem(extra_pages);
|
|
||||||
|
|
||||||
return "Xen";
|
return "Xen";
|
||||||
}
|
}
|
||||||
@ -337,9 +336,6 @@ void __cpuinit xen_enable_syscall(void)
|
|||||||
|
|
||||||
void __init xen_arch_setup(void)
|
void __init xen_arch_setup(void)
|
||||||
{
|
{
|
||||||
struct physdev_set_iopl set_iopl;
|
|
||||||
int rc;
|
|
||||||
|
|
||||||
xen_panic_handler_init();
|
xen_panic_handler_init();
|
||||||
|
|
||||||
HYPERVISOR_vm_assist(VMASST_CMD_enable, VMASST_TYPE_4gb_segments);
|
HYPERVISOR_vm_assist(VMASST_CMD_enable, VMASST_TYPE_4gb_segments);
|
||||||
@ -356,11 +352,6 @@ void __init xen_arch_setup(void)
|
|||||||
xen_enable_sysenter();
|
xen_enable_sysenter();
|
||||||
xen_enable_syscall();
|
xen_enable_syscall();
|
||||||
|
|
||||||
set_iopl.iopl = 1;
|
|
||||||
rc = HYPERVISOR_physdev_op(PHYSDEVOP_set_iopl, &set_iopl);
|
|
||||||
if (rc != 0)
|
|
||||||
printk(KERN_INFO "physdev_op failed %d\n", rc);
|
|
||||||
|
|
||||||
#ifdef CONFIG_ACPI
|
#ifdef CONFIG_ACPI
|
||||||
if (!(xen_start_info->flags & SIF_INITDOMAIN)) {
|
if (!(xen_start_info->flags & SIF_INITDOMAIN)) {
|
||||||
printk(KERN_INFO "ACPI in unprivileged domain disabled\n");
|
printk(KERN_INFO "ACPI in unprivileged domain disabled\n");
|
||||||
|
@ -8,9 +8,12 @@ obj-$(CONFIG_BLOCK) += biomerge.o
|
|||||||
obj-$(CONFIG_HOTPLUG_CPU) += cpu_hotplug.o
|
obj-$(CONFIG_HOTPLUG_CPU) += cpu_hotplug.o
|
||||||
obj-$(CONFIG_XEN_XENCOMM) += xencomm.o
|
obj-$(CONFIG_XEN_XENCOMM) += xencomm.o
|
||||||
obj-$(CONFIG_XEN_BALLOON) += balloon.o
|
obj-$(CONFIG_XEN_BALLOON) += balloon.o
|
||||||
obj-$(CONFIG_XEN_DEV_EVTCHN) += evtchn.o
|
obj-$(CONFIG_XEN_DEV_EVTCHN) += xen-evtchn.o
|
||||||
obj-$(CONFIG_XENFS) += xenfs/
|
obj-$(CONFIG_XENFS) += xenfs/
|
||||||
obj-$(CONFIG_XEN_SYS_HYPERVISOR) += sys-hypervisor.o
|
obj-$(CONFIG_XEN_SYS_HYPERVISOR) += sys-hypervisor.o
|
||||||
obj-$(CONFIG_XEN_PLATFORM_PCI) += platform-pci.o
|
obj-$(CONFIG_XEN_PLATFORM_PCI) += platform-pci.o
|
||||||
obj-$(CONFIG_SWIOTLB_XEN) += swiotlb-xen.o
|
obj-$(CONFIG_SWIOTLB_XEN) += swiotlb-xen.o
|
||||||
obj-$(CONFIG_XEN_DOM0) += pci.o
|
obj-$(CONFIG_XEN_DOM0) += pci.o
|
||||||
|
|
||||||
|
xen-evtchn-y := evtchn.o
|
||||||
|
|
||||||
|
@ -50,6 +50,7 @@
|
|||||||
#include <asm/pgtable.h>
|
#include <asm/pgtable.h>
|
||||||
#include <asm/uaccess.h>
|
#include <asm/uaccess.h>
|
||||||
#include <asm/tlb.h>
|
#include <asm/tlb.h>
|
||||||
|
#include <asm/e820.h>
|
||||||
|
|
||||||
#include <asm/xen/hypervisor.h>
|
#include <asm/xen/hypervisor.h>
|
||||||
#include <asm/xen/hypercall.h>
|
#include <asm/xen/hypercall.h>
|
||||||
@ -119,7 +120,7 @@ static void scrub_page(struct page *page)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* balloon_append: add the given page to the balloon. */
|
/* balloon_append: add the given page to the balloon. */
|
||||||
static void balloon_append(struct page *page)
|
static void __balloon_append(struct page *page)
|
||||||
{
|
{
|
||||||
/* Lowmem is re-populated first, so highmem pages go at list tail. */
|
/* Lowmem is re-populated first, so highmem pages go at list tail. */
|
||||||
if (PageHighMem(page)) {
|
if (PageHighMem(page)) {
|
||||||
@ -130,7 +131,11 @@ static void balloon_append(struct page *page)
|
|||||||
list_add(&page->lru, &ballooned_pages);
|
list_add(&page->lru, &ballooned_pages);
|
||||||
balloon_stats.balloon_low++;
|
balloon_stats.balloon_low++;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void balloon_append(struct page *page)
|
||||||
|
{
|
||||||
|
__balloon_append(page);
|
||||||
totalram_pages--;
|
totalram_pages--;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -191,7 +196,7 @@ static unsigned long current_target(void)
|
|||||||
|
|
||||||
static int increase_reservation(unsigned long nr_pages)
|
static int increase_reservation(unsigned long nr_pages)
|
||||||
{
|
{
|
||||||
unsigned long pfn, i, flags;
|
unsigned long pfn, i;
|
||||||
struct page *page;
|
struct page *page;
|
||||||
long rc;
|
long rc;
|
||||||
struct xen_memory_reservation reservation = {
|
struct xen_memory_reservation reservation = {
|
||||||
@ -203,8 +208,6 @@ static int increase_reservation(unsigned long nr_pages)
|
|||||||
if (nr_pages > ARRAY_SIZE(frame_list))
|
if (nr_pages > ARRAY_SIZE(frame_list))
|
||||||
nr_pages = ARRAY_SIZE(frame_list);
|
nr_pages = ARRAY_SIZE(frame_list);
|
||||||
|
|
||||||
spin_lock_irqsave(&xen_reservation_lock, flags);
|
|
||||||
|
|
||||||
page = balloon_first_page();
|
page = balloon_first_page();
|
||||||
for (i = 0; i < nr_pages; i++) {
|
for (i = 0; i < nr_pages; i++) {
|
||||||
BUG_ON(page == NULL);
|
BUG_ON(page == NULL);
|
||||||
@ -247,14 +250,12 @@ static int increase_reservation(unsigned long nr_pages)
|
|||||||
balloon_stats.current_pages += rc;
|
balloon_stats.current_pages += rc;
|
||||||
|
|
||||||
out:
|
out:
|
||||||
spin_unlock_irqrestore(&xen_reservation_lock, flags);
|
|
||||||
|
|
||||||
return rc < 0 ? rc : rc != nr_pages;
|
return rc < 0 ? rc : rc != nr_pages;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int decrease_reservation(unsigned long nr_pages)
|
static int decrease_reservation(unsigned long nr_pages)
|
||||||
{
|
{
|
||||||
unsigned long pfn, i, flags;
|
unsigned long pfn, i;
|
||||||
struct page *page;
|
struct page *page;
|
||||||
int need_sleep = 0;
|
int need_sleep = 0;
|
||||||
int ret;
|
int ret;
|
||||||
@ -292,8 +293,6 @@ static int decrease_reservation(unsigned long nr_pages)
|
|||||||
kmap_flush_unused();
|
kmap_flush_unused();
|
||||||
flush_tlb_all();
|
flush_tlb_all();
|
||||||
|
|
||||||
spin_lock_irqsave(&xen_reservation_lock, flags);
|
|
||||||
|
|
||||||
/* No more mappings: invalidate P2M and add to balloon. */
|
/* No more mappings: invalidate P2M and add to balloon. */
|
||||||
for (i = 0; i < nr_pages; i++) {
|
for (i = 0; i < nr_pages; i++) {
|
||||||
pfn = mfn_to_pfn(frame_list[i]);
|
pfn = mfn_to_pfn(frame_list[i]);
|
||||||
@ -308,8 +307,6 @@ static int decrease_reservation(unsigned long nr_pages)
|
|||||||
|
|
||||||
balloon_stats.current_pages -= nr_pages;
|
balloon_stats.current_pages -= nr_pages;
|
||||||
|
|
||||||
spin_unlock_irqrestore(&xen_reservation_lock, flags);
|
|
||||||
|
|
||||||
return need_sleep;
|
return need_sleep;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -395,7 +392,7 @@ static struct notifier_block xenstore_notifier;
|
|||||||
|
|
||||||
static int __init balloon_init(void)
|
static int __init balloon_init(void)
|
||||||
{
|
{
|
||||||
unsigned long pfn;
|
unsigned long pfn, extra_pfn_end;
|
||||||
struct page *page;
|
struct page *page;
|
||||||
|
|
||||||
if (!xen_pv_domain())
|
if (!xen_pv_domain())
|
||||||
@ -416,10 +413,15 @@ static int __init balloon_init(void)
|
|||||||
register_balloon(&balloon_sysdev);
|
register_balloon(&balloon_sysdev);
|
||||||
|
|
||||||
/* Initialise the balloon with excess memory space. */
|
/* Initialise the balloon with excess memory space. */
|
||||||
for (pfn = xen_start_info->nr_pages; pfn < max_pfn; pfn++) {
|
extra_pfn_end = min(e820_end_of_ram_pfn(),
|
||||||
|
(unsigned long)PFN_DOWN(xen_extra_mem_start + xen_extra_mem_size));
|
||||||
|
for (pfn = PFN_UP(xen_extra_mem_start);
|
||||||
|
pfn < extra_pfn_end;
|
||||||
|
pfn++) {
|
||||||
page = pfn_to_page(pfn);
|
page = pfn_to_page(pfn);
|
||||||
if (!PageReserved(page))
|
/* totalram_pages doesn't include the boot-time
|
||||||
balloon_append(page);
|
balloon extension, so don't subtract from it. */
|
||||||
|
__balloon_append(page);
|
||||||
}
|
}
|
||||||
|
|
||||||
target_watch.callback = watch_target;
|
target_watch.callback = watch_target;
|
||||||
|
@ -278,17 +278,17 @@ static void bind_evtchn_to_cpu(unsigned int chn, unsigned int cpu)
|
|||||||
cpumask_copy(irq_to_desc(irq)->affinity, cpumask_of(cpu));
|
cpumask_copy(irq_to_desc(irq)->affinity, cpumask_of(cpu));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
__clear_bit(chn, cpu_evtchn_mask(cpu_from_irq(irq)));
|
clear_bit(chn, cpu_evtchn_mask(cpu_from_irq(irq)));
|
||||||
__set_bit(chn, cpu_evtchn_mask(cpu));
|
set_bit(chn, cpu_evtchn_mask(cpu));
|
||||||
|
|
||||||
irq_info[irq].cpu = cpu;
|
irq_info[irq].cpu = cpu;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void init_evtchn_cpu_bindings(void)
|
static void init_evtchn_cpu_bindings(void)
|
||||||
{
|
{
|
||||||
|
int i;
|
||||||
#ifdef CONFIG_SMP
|
#ifdef CONFIG_SMP
|
||||||
struct irq_desc *desc;
|
struct irq_desc *desc;
|
||||||
int i;
|
|
||||||
|
|
||||||
/* By default all event channels notify CPU#0. */
|
/* By default all event channels notify CPU#0. */
|
||||||
for_each_irq_desc(i, desc) {
|
for_each_irq_desc(i, desc) {
|
||||||
@ -296,7 +296,10 @@ static void init_evtchn_cpu_bindings(void)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
memset(cpu_evtchn_mask(0), ~0, sizeof(struct cpu_evtchn_s));
|
for_each_possible_cpu(i)
|
||||||
|
memset(cpu_evtchn_mask(i),
|
||||||
|
(i == 0) ? ~0 : 0, sizeof(struct cpu_evtchn_s));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void clear_evtchn(int port)
|
static inline void clear_evtchn(int port)
|
||||||
@ -752,7 +755,7 @@ int xen_destroy_irq(int irq)
|
|||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
if (xen_initial_domain()) {
|
if (xen_initial_domain()) {
|
||||||
unmap_irq.pirq = info->u.pirq.gsi;
|
unmap_irq.pirq = info->u.pirq.pirq;
|
||||||
unmap_irq.domid = DOMID_SELF;
|
unmap_irq.domid = DOMID_SELF;
|
||||||
rc = HYPERVISOR_physdev_op(PHYSDEVOP_unmap_pirq, &unmap_irq);
|
rc = HYPERVISOR_physdev_op(PHYSDEVOP_unmap_pirq, &unmap_irq);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
|
@ -69,20 +69,51 @@ struct per_user_data {
|
|||||||
const char *name;
|
const char *name;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Who's bound to each port? */
|
/*
|
||||||
static struct per_user_data *port_user[NR_EVENT_CHANNELS];
|
* Who's bound to each port? This is logically an array of struct
|
||||||
|
* per_user_data *, but we encode the current enabled-state in bit 0.
|
||||||
|
*/
|
||||||
|
static unsigned long *port_user;
|
||||||
static DEFINE_SPINLOCK(port_user_lock); /* protects port_user[] and ring_prod */
|
static DEFINE_SPINLOCK(port_user_lock); /* protects port_user[] and ring_prod */
|
||||||
|
|
||||||
irqreturn_t evtchn_interrupt(int irq, void *data)
|
static inline struct per_user_data *get_port_user(unsigned port)
|
||||||
|
{
|
||||||
|
return (struct per_user_data *)(port_user[port] & ~1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void set_port_user(unsigned port, struct per_user_data *u)
|
||||||
|
{
|
||||||
|
port_user[port] = (unsigned long)u;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool get_port_enabled(unsigned port)
|
||||||
|
{
|
||||||
|
return port_user[port] & 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void set_port_enabled(unsigned port, bool enabled)
|
||||||
|
{
|
||||||
|
if (enabled)
|
||||||
|
port_user[port] |= 1;
|
||||||
|
else
|
||||||
|
port_user[port] &= ~1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static irqreturn_t evtchn_interrupt(int irq, void *data)
|
||||||
{
|
{
|
||||||
unsigned int port = (unsigned long)data;
|
unsigned int port = (unsigned long)data;
|
||||||
struct per_user_data *u;
|
struct per_user_data *u;
|
||||||
|
|
||||||
spin_lock(&port_user_lock);
|
spin_lock(&port_user_lock);
|
||||||
|
|
||||||
u = port_user[port];
|
u = get_port_user(port);
|
||||||
|
|
||||||
|
WARN(!get_port_enabled(port),
|
||||||
|
"Interrupt for port %d, but apparently not enabled; per-user %p\n",
|
||||||
|
port, u);
|
||||||
|
|
||||||
disable_irq_nosync(irq);
|
disable_irq_nosync(irq);
|
||||||
|
set_port_enabled(port, false);
|
||||||
|
|
||||||
if ((u->ring_prod - u->ring_cons) < EVTCHN_RING_SIZE) {
|
if ((u->ring_prod - u->ring_cons) < EVTCHN_RING_SIZE) {
|
||||||
u->ring[EVTCHN_RING_MASK(u->ring_prod)] = port;
|
u->ring[EVTCHN_RING_MASK(u->ring_prod)] = port;
|
||||||
@ -92,9 +123,8 @@ irqreturn_t evtchn_interrupt(int irq, void *data)
|
|||||||
kill_fasync(&u->evtchn_async_queue,
|
kill_fasync(&u->evtchn_async_queue,
|
||||||
SIGIO, POLL_IN);
|
SIGIO, POLL_IN);
|
||||||
}
|
}
|
||||||
} else {
|
} else
|
||||||
u->ring_overflow = 1;
|
u->ring_overflow = 1;
|
||||||
}
|
|
||||||
|
|
||||||
spin_unlock(&port_user_lock);
|
spin_unlock(&port_user_lock);
|
||||||
|
|
||||||
@ -198,9 +228,18 @@ static ssize_t evtchn_write(struct file *file, const char __user *buf,
|
|||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
spin_lock_irq(&port_user_lock);
|
spin_lock_irq(&port_user_lock);
|
||||||
for (i = 0; i < (count/sizeof(evtchn_port_t)); i++)
|
|
||||||
if ((kbuf[i] < NR_EVENT_CHANNELS) && (port_user[kbuf[i]] == u))
|
for (i = 0; i < (count/sizeof(evtchn_port_t)); i++) {
|
||||||
enable_irq(irq_from_evtchn(kbuf[i]));
|
unsigned port = kbuf[i];
|
||||||
|
|
||||||
|
if (port < NR_EVENT_CHANNELS &&
|
||||||
|
get_port_user(port) == u &&
|
||||||
|
!get_port_enabled(port)) {
|
||||||
|
set_port_enabled(port, true);
|
||||||
|
enable_irq(irq_from_evtchn(port));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
spin_unlock_irq(&port_user_lock);
|
spin_unlock_irq(&port_user_lock);
|
||||||
|
|
||||||
rc = count;
|
rc = count;
|
||||||
@ -222,8 +261,9 @@ static int evtchn_bind_to_user(struct per_user_data *u, int port)
|
|||||||
* interrupt handler yet, and our caller has already
|
* interrupt handler yet, and our caller has already
|
||||||
* serialized bind operations.)
|
* serialized bind operations.)
|
||||||
*/
|
*/
|
||||||
BUG_ON(port_user[port] != NULL);
|
BUG_ON(get_port_user(port) != NULL);
|
||||||
port_user[port] = u;
|
set_port_user(port, u);
|
||||||
|
set_port_enabled(port, true); /* start enabled */
|
||||||
|
|
||||||
rc = bind_evtchn_to_irqhandler(port, evtchn_interrupt, IRQF_DISABLED,
|
rc = bind_evtchn_to_irqhandler(port, evtchn_interrupt, IRQF_DISABLED,
|
||||||
u->name, (void *)(unsigned long)port);
|
u->name, (void *)(unsigned long)port);
|
||||||
@ -239,10 +279,7 @@ static void evtchn_unbind_from_user(struct per_user_data *u, int port)
|
|||||||
|
|
||||||
unbind_from_irqhandler(irq, (void *)(unsigned long)port);
|
unbind_from_irqhandler(irq, (void *)(unsigned long)port);
|
||||||
|
|
||||||
/* make sure we unbind the irq handler before clearing the port */
|
set_port_user(port, NULL);
|
||||||
barrier();
|
|
||||||
|
|
||||||
port_user[port] = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static long evtchn_ioctl(struct file *file,
|
static long evtchn_ioctl(struct file *file,
|
||||||
@ -333,15 +370,17 @@ static long evtchn_ioctl(struct file *file,
|
|||||||
spin_lock_irq(&port_user_lock);
|
spin_lock_irq(&port_user_lock);
|
||||||
|
|
||||||
rc = -ENOTCONN;
|
rc = -ENOTCONN;
|
||||||
if (port_user[unbind.port] != u) {
|
if (get_port_user(unbind.port) != u) {
|
||||||
spin_unlock_irq(&port_user_lock);
|
spin_unlock_irq(&port_user_lock);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
evtchn_unbind_from_user(u, unbind.port);
|
disable_irq(irq_from_evtchn(unbind.port));
|
||||||
|
|
||||||
spin_unlock_irq(&port_user_lock);
|
spin_unlock_irq(&port_user_lock);
|
||||||
|
|
||||||
|
evtchn_unbind_from_user(u, unbind.port);
|
||||||
|
|
||||||
rc = 0;
|
rc = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -355,7 +394,7 @@ static long evtchn_ioctl(struct file *file,
|
|||||||
|
|
||||||
if (notify.port >= NR_EVENT_CHANNELS) {
|
if (notify.port >= NR_EVENT_CHANNELS) {
|
||||||
rc = -EINVAL;
|
rc = -EINVAL;
|
||||||
} else if (port_user[notify.port] != u) {
|
} else if (get_port_user(notify.port) != u) {
|
||||||
rc = -ENOTCONN;
|
rc = -ENOTCONN;
|
||||||
} else {
|
} else {
|
||||||
notify_remote_via_evtchn(notify.port);
|
notify_remote_via_evtchn(notify.port);
|
||||||
@ -431,7 +470,7 @@ static int evtchn_open(struct inode *inode, struct file *filp)
|
|||||||
|
|
||||||
filp->private_data = u;
|
filp->private_data = u;
|
||||||
|
|
||||||
return 0;
|
return nonseekable_open(inode, filp);;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int evtchn_release(struct inode *inode, struct file *filp)
|
static int evtchn_release(struct inode *inode, struct file *filp)
|
||||||
@ -444,14 +483,21 @@ static int evtchn_release(struct inode *inode, struct file *filp)
|
|||||||
free_page((unsigned long)u->ring);
|
free_page((unsigned long)u->ring);
|
||||||
|
|
||||||
for (i = 0; i < NR_EVENT_CHANNELS; i++) {
|
for (i = 0; i < NR_EVENT_CHANNELS; i++) {
|
||||||
if (port_user[i] != u)
|
if (get_port_user(i) != u)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
evtchn_unbind_from_user(port_user[i], i);
|
disable_irq(irq_from_evtchn(i));
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_unlock_irq(&port_user_lock);
|
spin_unlock_irq(&port_user_lock);
|
||||||
|
|
||||||
|
for (i = 0; i < NR_EVENT_CHANNELS; i++) {
|
||||||
|
if (get_port_user(i) != u)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
evtchn_unbind_from_user(get_port_user(i), i);
|
||||||
|
}
|
||||||
|
|
||||||
kfree(u->name);
|
kfree(u->name);
|
||||||
kfree(u);
|
kfree(u);
|
||||||
|
|
||||||
@ -467,12 +513,12 @@ static const struct file_operations evtchn_fops = {
|
|||||||
.fasync = evtchn_fasync,
|
.fasync = evtchn_fasync,
|
||||||
.open = evtchn_open,
|
.open = evtchn_open,
|
||||||
.release = evtchn_release,
|
.release = evtchn_release,
|
||||||
.llseek = noop_llseek,
|
.llseek = no_llseek,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct miscdevice evtchn_miscdev = {
|
static struct miscdevice evtchn_miscdev = {
|
||||||
.minor = MISC_DYNAMIC_MINOR,
|
.minor = MISC_DYNAMIC_MINOR,
|
||||||
.name = "evtchn",
|
.name = "xen/evtchn",
|
||||||
.fops = &evtchn_fops,
|
.fops = &evtchn_fops,
|
||||||
};
|
};
|
||||||
static int __init evtchn_init(void)
|
static int __init evtchn_init(void)
|
||||||
@ -482,8 +528,11 @@ static int __init evtchn_init(void)
|
|||||||
if (!xen_domain())
|
if (!xen_domain())
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
|
port_user = kcalloc(NR_EVENT_CHANNELS, sizeof(*port_user), GFP_KERNEL);
|
||||||
|
if (port_user == NULL)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
spin_lock_init(&port_user_lock);
|
spin_lock_init(&port_user_lock);
|
||||||
memset(port_user, 0, sizeof(port_user));
|
|
||||||
|
|
||||||
/* Create '/dev/misc/evtchn'. */
|
/* Create '/dev/misc/evtchn'. */
|
||||||
err = misc_register(&evtchn_miscdev);
|
err = misc_register(&evtchn_miscdev);
|
||||||
@ -499,6 +548,9 @@ static int __init evtchn_init(void)
|
|||||||
|
|
||||||
static void __exit evtchn_cleanup(void)
|
static void __exit evtchn_cleanup(void)
|
||||||
{
|
{
|
||||||
|
kfree(port_user);
|
||||||
|
port_user = NULL;
|
||||||
|
|
||||||
misc_deregister(&evtchn_miscdev);
|
misc_deregister(&evtchn_miscdev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -265,9 +265,7 @@ static int mmap_return_errors(void *data, void *state)
|
|||||||
xen_pfn_t *mfnp = data;
|
xen_pfn_t *mfnp = data;
|
||||||
struct mmap_batch_state *st = state;
|
struct mmap_batch_state *st = state;
|
||||||
|
|
||||||
put_user(*mfnp, st->user++);
|
return put_user(*mfnp, st->user++);
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct vm_operations_struct privcmd_vm_ops;
|
static struct vm_operations_struct privcmd_vm_ops;
|
||||||
@ -322,10 +320,8 @@ static long privcmd_ioctl_mmap_batch(void __user *udata)
|
|||||||
up_write(&mm->mmap_sem);
|
up_write(&mm->mmap_sem);
|
||||||
|
|
||||||
if (state.err > 0) {
|
if (state.err > 0) {
|
||||||
ret = 0;
|
|
||||||
|
|
||||||
state.user = m.arr;
|
state.user = m.arr;
|
||||||
traverse_pages(m.num, sizeof(xen_pfn_t),
|
ret = traverse_pages(m.num, sizeof(xen_pfn_t),
|
||||||
&pagelist,
|
&pagelist,
|
||||||
mmap_return_errors, &state);
|
mmap_return_errors, &state);
|
||||||
}
|
}
|
||||||
@ -383,8 +379,9 @@ static int privcmd_mmap(struct file *file, struct vm_area_struct *vma)
|
|||||||
if (xen_feature(XENFEAT_auto_translated_physmap))
|
if (xen_feature(XENFEAT_auto_translated_physmap))
|
||||||
return -ENOSYS;
|
return -ENOSYS;
|
||||||
|
|
||||||
/* DONTCOPY is essential for Xen as copy_page_range is broken. */
|
/* DONTCOPY is essential for Xen because copy_page_range doesn't know
|
||||||
vma->vm_flags |= VM_RESERVED | VM_IO | VM_DONTCOPY;
|
* how to recreate these mappings */
|
||||||
|
vma->vm_flags |= VM_RESERVED | VM_IO | VM_DONTCOPY | VM_PFNMAP;
|
||||||
vma->vm_ops = &privcmd_vm_ops;
|
vma->vm_ops = &privcmd_vm_ops;
|
||||||
vma->vm_private_data = NULL;
|
vma->vm_private_data = NULL;
|
||||||
|
|
||||||
|
@ -12,8 +12,6 @@
|
|||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/fs.h>
|
#include <linux/fs.h>
|
||||||
#include <linux/magic.h>
|
#include <linux/magic.h>
|
||||||
#include <linux/mm.h>
|
|
||||||
#include <linux/backing-dev.h>
|
|
||||||
|
|
||||||
#include <xen/xen.h>
|
#include <xen/xen.h>
|
||||||
|
|
||||||
@ -24,28 +22,12 @@
|
|||||||
MODULE_DESCRIPTION("Xen filesystem");
|
MODULE_DESCRIPTION("Xen filesystem");
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
|
|
||||||
static int xenfs_set_page_dirty(struct page *page)
|
|
||||||
{
|
|
||||||
return !TestSetPageDirty(page);
|
|
||||||
}
|
|
||||||
|
|
||||||
static const struct address_space_operations xenfs_aops = {
|
|
||||||
.set_page_dirty = xenfs_set_page_dirty,
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct backing_dev_info xenfs_backing_dev_info = {
|
|
||||||
.ra_pages = 0, /* No readahead */
|
|
||||||
.capabilities = BDI_CAP_NO_ACCT_AND_WRITEBACK,
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct inode *xenfs_make_inode(struct super_block *sb, int mode)
|
static struct inode *xenfs_make_inode(struct super_block *sb, int mode)
|
||||||
{
|
{
|
||||||
struct inode *ret = new_inode(sb);
|
struct inode *ret = new_inode(sb);
|
||||||
|
|
||||||
if (ret) {
|
if (ret) {
|
||||||
ret->i_mode = mode;
|
ret->i_mode = mode;
|
||||||
ret->i_mapping->a_ops = &xenfs_aops;
|
|
||||||
ret->i_mapping->backing_dev_info = &xenfs_backing_dev_info;
|
|
||||||
ret->i_uid = ret->i_gid = 0;
|
ret->i_uid = ret->i_gid = 0;
|
||||||
ret->i_blocks = 0;
|
ret->i_blocks = 0;
|
||||||
ret->i_atime = ret->i_mtime = ret->i_ctime = CURRENT_TIME;
|
ret->i_atime = ret->i_mtime = ret->i_ctime = CURRENT_TIME;
|
||||||
@ -121,9 +103,9 @@ static int xenfs_fill_super(struct super_block *sb, void *data, int silent)
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int xenfs_mount(struct file_system_type *fs_type,
|
static struct dentry *xenfs_mount(struct file_system_type *fs_type,
|
||||||
int flags, const char *dev_name,
|
int flags, const char *dev_name,
|
||||||
void *data)
|
void *data)
|
||||||
{
|
{
|
||||||
return mount_single(fs_type, flags, data, xenfs_fill_super);
|
return mount_single(fs_type, flags, data, xenfs_fill_super);
|
||||||
}
|
}
|
||||||
@ -137,25 +119,11 @@ static struct file_system_type xenfs_type = {
|
|||||||
|
|
||||||
static int __init xenfs_init(void)
|
static int __init xenfs_init(void)
|
||||||
{
|
{
|
||||||
int err;
|
if (xen_domain())
|
||||||
if (!xen_domain()) {
|
return register_filesystem(&xenfs_type);
|
||||||
printk(KERN_INFO "xenfs: not registering filesystem on non-xen platform\n");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
err = register_filesystem(&xenfs_type);
|
printk(KERN_INFO "XENFS: not registering filesystem on non-xen platform\n");
|
||||||
if (err) {
|
return 0;
|
||||||
printk(KERN_ERR "xenfs: Unable to register filesystem!\n");
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
err = bdi_init(&xenfs_backing_dev_info);
|
|
||||||
if (err)
|
|
||||||
unregister_filesystem(&xenfs_type);
|
|
||||||
|
|
||||||
out:
|
|
||||||
|
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __exit xenfs_exit(void)
|
static void __exit xenfs_exit(void)
|
||||||
|
@ -140,6 +140,19 @@ struct xen_machphys_mfn_list {
|
|||||||
};
|
};
|
||||||
DEFINE_GUEST_HANDLE_STRUCT(xen_machphys_mfn_list);
|
DEFINE_GUEST_HANDLE_STRUCT(xen_machphys_mfn_list);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns the location in virtual address space of the machine_to_phys
|
||||||
|
* mapping table. Architectures which do not have a m2p table, or which do not
|
||||||
|
* map it by default into guest address space, do not implement this command.
|
||||||
|
* arg == addr of xen_machphys_mapping_t.
|
||||||
|
*/
|
||||||
|
#define XENMEM_machphys_mapping 12
|
||||||
|
struct xen_machphys_mapping {
|
||||||
|
unsigned long v_start, v_end; /* Start and end virtual addresses. */
|
||||||
|
unsigned long max_mfn; /* Maximum MFN that can be looked up. */
|
||||||
|
};
|
||||||
|
DEFINE_GUEST_HANDLE_STRUCT(xen_machphys_mapping_t);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Sets the GPFN at which a particular page appears in the specified guest's
|
* Sets the GPFN at which a particular page appears in the specified guest's
|
||||||
* pseudophysical address space.
|
* pseudophysical address space.
|
||||||
|
@ -1 +1,8 @@
|
|||||||
|
#ifndef _XEN_PAGE_H
|
||||||
|
#define _XEN_PAGE_H
|
||||||
|
|
||||||
#include <asm/xen/page.h>
|
#include <asm/xen/page.h>
|
||||||
|
|
||||||
|
extern phys_addr_t xen_extra_mem_start, xen_extra_mem_size;
|
||||||
|
|
||||||
|
#endif /* _XEN_PAGE_H */
|
||||||
|
@ -34,13 +34,10 @@
|
|||||||
#define __LINUX_PUBLIC_PRIVCMD_H__
|
#define __LINUX_PUBLIC_PRIVCMD_H__
|
||||||
|
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
|
#include <linux/compiler.h>
|
||||||
|
|
||||||
typedef unsigned long xen_pfn_t;
|
typedef unsigned long xen_pfn_t;
|
||||||
|
|
||||||
#ifndef __user
|
|
||||||
#define __user
|
|
||||||
#endif
|
|
||||||
|
|
||||||
struct privcmd_hypercall {
|
struct privcmd_hypercall {
|
||||||
__u64 op;
|
__u64 op;
|
||||||
__u64 arg[5];
|
__u64 arg[5];
|
||||||
|
Loading…
Reference in New Issue
Block a user