Commit 497a5df7 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'stable/for-linus-4.1-rc0-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/xen/tip

Pull xen features and fixes from David Vrabel:

 - use a single source list of hypercalls, generating other tables etc.
   at build time.

 - add a "Xen PV" APIC driver to support >255 VCPUs in PV guests.

 - significant performance improve to guest save/restore/migration.

 - scsiback/front save/restore support.

 - infrastructure for multi-page xenbus rings.

 - misc fixes.

* tag 'stable/for-linus-4.1-rc0-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/xen/tip:
  xen/pci: Try harder to get PXM information for Xen
  xenbus_client: Extend interface to support multi-page ring
  xen-pciback: also support disabling of bus-mastering and memory-write-invalidate
  xen: support suspend/resume in pvscsi frontend
  xen: scsiback: add LUN of restored domain
  xen-scsiback: define a pr_fmt macro with xen-pvscsi
  xen/mce: fix up xen_late_init_mcelog() error handling
  xen/privcmd: improve performance of MMAPBATCH_V2
  xen: unify foreign GFN map/unmap for auto-xlated physmap guests
  x86/xen/apic: WARN with details.
  x86/xen: Provide a "Xen PV" APIC driver to support >255 VCPUs
  xen/pciback: Don't print scary messages when unsupported by hypervisor.
  xen: use generated hypercall symbols in arch/x86/xen/xen-head.S
  xen: use generated hypervisor symbols in arch/x86/xen/trace.c
  xen: synchronize include/xen/interface/xen.h with xen
  xen: build infrastructure for generating hypercall depending symbols
  xen: balloon: Use static attribute groups for sysfs entries
  xen: pcpu: Use static attribute groups for sysfs entry
parents 714d8e7e 0b97b03d
...@@ -53,105 +53,33 @@ EXPORT_SYMBOL_GPL(xen_platform_pci_unplug); ...@@ -53,105 +53,33 @@ EXPORT_SYMBOL_GPL(xen_platform_pci_unplug);
static __read_mostly int xen_events_irq = -1; static __read_mostly int xen_events_irq = -1;
/* map fgmfn of domid to lpfn in the current domain */ int xen_remap_domain_mfn_array(struct vm_area_struct *vma,
static int map_foreign_page(unsigned long lpfn, unsigned long fgmfn, unsigned long addr,
unsigned int domid) xen_pfn_t *mfn, int nr,
int *err_ptr, pgprot_t prot,
unsigned domid,
struct page **pages)
{ {
int rc; return xen_xlate_remap_gfn_array(vma, addr, mfn, nr, err_ptr,
struct xen_add_to_physmap_range xatp = { prot, domid, pages);
.domid = DOMID_SELF,
.foreign_domid = domid,
.size = 1,
.space = XENMAPSPACE_gmfn_foreign,
};
xen_ulong_t idx = fgmfn;
xen_pfn_t gpfn = lpfn;
int err = 0;
set_xen_guest_handle(xatp.idxs, &idx);
set_xen_guest_handle(xatp.gpfns, &gpfn);
set_xen_guest_handle(xatp.errs, &err);
rc = HYPERVISOR_memory_op(XENMEM_add_to_physmap_range, &xatp);
if (rc || err) {
pr_warn("Failed to map pfn to mfn rc:%d:%d pfn:%lx mfn:%lx\n",
rc, err, lpfn, fgmfn);
return 1;
}
return 0;
}
struct remap_data {
xen_pfn_t fgmfn; /* foreign domain's gmfn */
pgprot_t prot;
domid_t domid;
struct vm_area_struct *vma;
int index;
struct page **pages;
struct xen_remap_mfn_info *info;
};
static int remap_pte_fn(pte_t *ptep, pgtable_t token, unsigned long addr,
void *data)
{
struct remap_data *info = data;
struct page *page = info->pages[info->index++];
unsigned long pfn = page_to_pfn(page);
pte_t pte = pte_mkspecial(pfn_pte(pfn, info->prot));
if (map_foreign_page(pfn, info->fgmfn, info->domid))
return -EFAULT;
set_pte_at(info->vma->vm_mm, addr, ptep, pte);
return 0;
} }
EXPORT_SYMBOL_GPL(xen_remap_domain_mfn_array);
/* Not used by XENFEAT_auto_translated guests. */
int xen_remap_domain_mfn_range(struct vm_area_struct *vma, int xen_remap_domain_mfn_range(struct vm_area_struct *vma,
unsigned long addr, unsigned long addr,
xen_pfn_t mfn, int nr, xen_pfn_t mfn, int nr,
pgprot_t prot, unsigned domid, pgprot_t prot, unsigned domid,
struct page **pages) struct page **pages)
{ {
int err; return -ENOSYS;
struct remap_data data;
/* TBD: Batching, current sole caller only does page at a time */
if (nr > 1)
return -EINVAL;
data.fgmfn = mfn;
data.prot = prot;
data.domid = domid;
data.vma = vma;
data.index = 0;
data.pages = pages;
err = apply_to_page_range(vma->vm_mm, addr, nr << PAGE_SHIFT,
remap_pte_fn, &data);
return err;
} }
EXPORT_SYMBOL_GPL(xen_remap_domain_mfn_range); EXPORT_SYMBOL_GPL(xen_remap_domain_mfn_range);
int xen_unmap_domain_mfn_range(struct vm_area_struct *vma, int xen_unmap_domain_mfn_range(struct vm_area_struct *vma,
int nr, struct page **pages) int nr, struct page **pages)
{ {
int i; return xen_xlate_unmap_gfn_range(vma, nr, pages);
for (i = 0; i < nr; i++) {
struct xen_remove_from_physmap xrp;
unsigned long rc, pfn;
pfn = page_to_pfn(pages[i]);
xrp.domid = DOMID_SELF;
xrp.gpfn = pfn;
rc = HYPERVISOR_memory_op(XENMEM_remove_from_physmap, &xrp);
if (rc) {
pr_warn("Failed to unmap pfn:%lx rc:%ld\n",
pfn, rc);
return rc;
}
}
return 0;
} }
EXPORT_SYMBOL_GPL(xen_unmap_domain_mfn_range); EXPORT_SYMBOL_GPL(xen_unmap_domain_mfn_range);
......
...@@ -19,6 +19,9 @@ quiet_cmd_syshdr = SYSHDR $@ ...@@ -19,6 +19,9 @@ quiet_cmd_syshdr = SYSHDR $@
quiet_cmd_systbl = SYSTBL $@ quiet_cmd_systbl = SYSTBL $@
cmd_systbl = $(CONFIG_SHELL) '$(systbl)' $< $@ cmd_systbl = $(CONFIG_SHELL) '$(systbl)' $< $@
quiet_cmd_hypercalls = HYPERCALLS $@
cmd_hypercalls = $(CONFIG_SHELL) '$<' $@ $(filter-out $<,$^)
syshdr_abi_unistd_32 := i386 syshdr_abi_unistd_32 := i386
$(uapi)/unistd_32.h: $(syscall32) $(syshdr) $(uapi)/unistd_32.h: $(syscall32) $(syshdr)
$(call if_changed,syshdr) $(call if_changed,syshdr)
...@@ -47,10 +50,16 @@ $(out)/syscalls_32.h: $(syscall32) $(systbl) ...@@ -47,10 +50,16 @@ $(out)/syscalls_32.h: $(syscall32) $(systbl)
$(out)/syscalls_64.h: $(syscall64) $(systbl) $(out)/syscalls_64.h: $(syscall64) $(systbl)
$(call if_changed,systbl) $(call if_changed,systbl)
$(out)/xen-hypercalls.h: $(srctree)/scripts/xen-hypercalls.sh
$(call if_changed,hypercalls)
$(out)/xen-hypercalls.h: $(srctree)/include/xen/interface/xen*.h
uapisyshdr-y += unistd_32.h unistd_64.h unistd_x32.h uapisyshdr-y += unistd_32.h unistd_64.h unistd_x32.h
syshdr-y += syscalls_32.h syshdr-y += syscalls_32.h
syshdr-$(CONFIG_X86_64) += unistd_32_ia32.h unistd_64_x32.h syshdr-$(CONFIG_X86_64) += unistd_32_ia32.h unistd_64_x32.h
syshdr-$(CONFIG_X86_64) += syscalls_64.h syshdr-$(CONFIG_X86_64) += syscalls_64.h
syshdr-$(CONFIG_XEN) += xen-hypercalls.h
targets += $(uapisyshdr-y) $(syshdr-y) targets += $(uapisyshdr-y) $(syshdr-y)
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include <xen/xen.h> #include <xen/xen.h>
#include <xen/interface/physdev.h> #include <xen/interface/physdev.h>
#include "xen-ops.h" #include "xen-ops.h"
#include "smp.h"
static unsigned int xen_io_apic_read(unsigned apic, unsigned reg) static unsigned int xen_io_apic_read(unsigned apic, unsigned reg)
{ {
...@@ -28,7 +29,186 @@ static unsigned int xen_io_apic_read(unsigned apic, unsigned reg) ...@@ -28,7 +29,186 @@ static unsigned int xen_io_apic_read(unsigned apic, unsigned reg)
return 0xfd; return 0xfd;
} }
static unsigned long xen_set_apic_id(unsigned int x)
{
WARN_ON(1);
return x;
}
static unsigned int xen_get_apic_id(unsigned long x)
{
return ((x)>>24) & 0xFFu;
}
static u32 xen_apic_read(u32 reg)
{
struct xen_platform_op op = {
.cmd = XENPF_get_cpuinfo,
.interface_version = XENPF_INTERFACE_VERSION,
.u.pcpu_info.xen_cpuid = 0,
};
int ret = 0;
/* Shouldn't need this as APIC is turned off for PV, and we only
* get called on the bootup processor. But just in case. */
if (!xen_initial_domain() || smp_processor_id())
return 0;
if (reg == APIC_LVR)
return 0x10;
#ifdef CONFIG_X86_32
if (reg == APIC_LDR)
return SET_APIC_LOGICAL_ID(1UL << smp_processor_id());
#endif
if (reg != APIC_ID)
return 0;
ret = HYPERVISOR_dom0_op(&op);
if (ret)
return 0;
return op.u.pcpu_info.apic_id << 24;
}
static void xen_apic_write(u32 reg, u32 val)
{
/* Warn to see if there's any stray references */
WARN(1,"register: %x, value: %x\n", reg, val);
}
static u64 xen_apic_icr_read(void)
{
return 0;
}
static void xen_apic_icr_write(u32 low, u32 id)
{
/* Warn to see if there's any stray references */
WARN_ON(1);
}
static u32 xen_safe_apic_wait_icr_idle(void)
{
return 0;
}
static int xen_apic_probe_pv(void)
{
if (xen_pv_domain())
return 1;
return 0;
}
static int xen_madt_oem_check(char *oem_id, char *oem_table_id)
{
return xen_pv_domain();
}
static int xen_id_always_valid(int apicid)
{
return 1;
}
static int xen_id_always_registered(void)
{
return 1;
}
static int xen_phys_pkg_id(int initial_apic_id, int index_msb)
{
return initial_apic_id >> index_msb;
}
#ifdef CONFIG_X86_32
static int xen_x86_32_early_logical_apicid(int cpu)
{
/* Match with APIC_LDR read. Otherwise setup_local_APIC complains. */
return 1 << cpu;
}
#endif
static void xen_noop(void)
{
}
static void xen_silent_inquire(int apicid)
{
}
static struct apic xen_pv_apic = {
.name = "Xen PV",
.probe = xen_apic_probe_pv,
.acpi_madt_oem_check = xen_madt_oem_check,
.apic_id_valid = xen_id_always_valid,
.apic_id_registered = xen_id_always_registered,
/* .irq_delivery_mode - used in native_compose_msi_msg only */
/* .irq_dest_mode - used in native_compose_msi_msg only */
.target_cpus = default_target_cpus,
.disable_esr = 0,
/* .dest_logical - default_send_IPI_ use it but we use our own. */
.check_apicid_used = default_check_apicid_used, /* Used on 32-bit */
.vector_allocation_domain = flat_vector_allocation_domain,
.init_apic_ldr = xen_noop, /* setup_local_APIC calls it */
.ioapic_phys_id_map = default_ioapic_phys_id_map, /* Used on 32-bit */
.setup_apic_routing = NULL,
.cpu_present_to_apicid = default_cpu_present_to_apicid,
.apicid_to_cpu_present = physid_set_mask_of_physid, /* Used on 32-bit */
.check_phys_apicid_present = default_check_phys_apicid_present, /* smp_sanity_check needs it */
.phys_pkg_id = xen_phys_pkg_id, /* detect_ht */
.get_apic_id = xen_get_apic_id,
.set_apic_id = xen_set_apic_id, /* Can be NULL on 32-bit. */
.apic_id_mask = 0xFF << 24, /* Used by verify_local_APIC. Match with what xen_get_apic_id does. */
.cpu_mask_to_apicid_and = flat_cpu_mask_to_apicid_and,
#ifdef CONFIG_SMP
.send_IPI_mask = xen_send_IPI_mask,
.send_IPI_mask_allbutself = xen_send_IPI_mask_allbutself,
.send_IPI_allbutself = xen_send_IPI_allbutself,
.send_IPI_all = xen_send_IPI_all,
.send_IPI_self = xen_send_IPI_self,
#endif
/* .wait_for_init_deassert- used by AP bootup - smp_callin which we don't use */
.inquire_remote_apic = xen_silent_inquire,
.read = xen_apic_read,
.write = xen_apic_write,
.eoi_write = xen_apic_write,
.icr_read = xen_apic_icr_read,
.icr_write = xen_apic_icr_write,
.wait_icr_idle = xen_noop,
.safe_wait_icr_idle = xen_safe_apic_wait_icr_idle,
#ifdef CONFIG_X86_32
/* generic_processor_info and setup_local_APIC. */
.x86_32_early_logical_apicid = xen_x86_32_early_logical_apicid,
#endif
};
static void __init xen_apic_check(void)
{
if (apic == &xen_pv_apic)
return;
pr_info("Switched APIC routing from %s to %s.\n", apic->name,
xen_pv_apic.name);
apic = &xen_pv_apic;
}
void __init xen_init_apic(void) void __init xen_init_apic(void)
{ {
x86_io_apic_ops.read = xen_io_apic_read; x86_io_apic_ops.read = xen_io_apic_read;
/* On PV guests the APIC CPUID bit is disabled so none of the
* routines end up executing. */
if (!xen_initial_domain())
apic = &xen_pv_apic;
x86_platform.apic_post_init = xen_apic_check;
} }
apic_driver(xen_pv_apic);
...@@ -928,92 +928,6 @@ static void xen_io_delay(void) ...@@ -928,92 +928,6 @@ static void xen_io_delay(void)
{ {
} }
#ifdef CONFIG_X86_LOCAL_APIC
static unsigned long xen_set_apic_id(unsigned int x)
{
WARN_ON(1);
return x;
}
static unsigned int xen_get_apic_id(unsigned long x)
{
return ((x)>>24) & 0xFFu;
}
static u32 xen_apic_read(u32 reg)
{
struct xen_platform_op op = {
.cmd = XENPF_get_cpuinfo,
.interface_version = XENPF_INTERFACE_VERSION,
.u.pcpu_info.xen_cpuid = 0,
};
int ret = 0;
/* Shouldn't need this as APIC is turned off for PV, and we only
* get called on the bootup processor. But just in case. */
if (!xen_initial_domain() || smp_processor_id())
return 0;
if (reg == APIC_LVR)
return 0x10;
if (reg != APIC_ID)
return 0;
ret = HYPERVISOR_dom0_op(&op);
if (ret)
return 0;
return op.u.pcpu_info.apic_id << 24;
}
static void xen_apic_write(u32 reg, u32 val)
{
/* Warn to see if there's any stray references */
WARN_ON(1);
}
static u64 xen_apic_icr_read(void)
{
return 0;
}
static void xen_apic_icr_write(u32 low, u32 id)
{
/* Warn to see if there's any stray references */
WARN_ON(1);
}
static void xen_apic_wait_icr_idle(void)
{
return;
}
static u32 xen_safe_apic_wait_icr_idle(void)
{
return 0;
}
static void set_xen_basic_apic_ops(void)
{
apic->read = xen_apic_read;
apic->write = xen_apic_write;
apic->icr_read = xen_apic_icr_read;
apic->icr_write = xen_apic_icr_write;
apic->wait_icr_idle = xen_apic_wait_icr_idle;
apic->safe_wait_icr_idle = xen_safe_apic_wait_icr_idle;
apic->set_apic_id = xen_set_apic_id;
apic->get_apic_id = xen_get_apic_id;
#ifdef CONFIG_SMP
apic->send_IPI_allbutself = xen_send_IPI_allbutself;
apic->send_IPI_mask_allbutself = xen_send_IPI_mask_allbutself;
apic->send_IPI_mask = xen_send_IPI_mask;
apic->send_IPI_all = xen_send_IPI_all;
apic->send_IPI_self = xen_send_IPI_self;
#endif
}
#endif
static void xen_clts(void) static void xen_clts(void)
{ {
struct multicall_space mcs; struct multicall_space mcs;
...@@ -1619,7 +1533,7 @@ asmlinkage __visible void __init xen_start_kernel(void) ...@@ -1619,7 +1533,7 @@ asmlinkage __visible void __init xen_start_kernel(void)
/* /*
* set up the basic apic ops. * set up the basic apic ops.
*/ */
set_xen_basic_apic_ops(); xen_init_apic();
#endif #endif
if (xen_feature(XENFEAT_mmu_pt_update_preserve_ad)) { if (xen_feature(XENFEAT_mmu_pt_update_preserve_ad)) {
...@@ -1732,8 +1646,6 @@ asmlinkage __visible void __init xen_start_kernel(void) ...@@ -1732,8 +1646,6 @@ asmlinkage __visible void __init xen_start_kernel(void)
if (HYPERVISOR_dom0_op(&op) == 0) if (HYPERVISOR_dom0_op(&op) == 0)
boot_params.kbd_status = op.u.firmware_info.u.kbd_shift_flags; boot_params.kbd_status = op.u.firmware_info.u.kbd_shift_flags;
xen_init_apic();
/* Make sure ACS will be enabled */ /* Make sure ACS will be enabled */
pci_request_acs(); pci_request_acs();
......
...@@ -2436,99 +2436,11 @@ void __init xen_hvm_init_mmu_ops(void) ...@@ -2436,99 +2436,11 @@ void __init xen_hvm_init_mmu_ops(void)
} }
#endif #endif
#ifdef CONFIG_XEN_PVH
/*
* Map foreign gfn (fgfn), to local pfn (lpfn). This for the user
* space creating new guest on pvh dom0 and needing to map domU pages.
*/
static int xlate_add_to_p2m(unsigned long lpfn, unsigned long fgfn,
unsigned int domid)
{
int rc, err = 0;
xen_pfn_t gpfn = lpfn;
xen_ulong_t idx = fgfn;
struct xen_add_to_physmap_range xatp = {
.domid = DOMID_SELF,
.foreign_domid = domid,
.size = 1,
.space = XENMAPSPACE_gmfn_foreign,
};
set_xen_guest_handle(xatp.idxs, &idx);
set_xen_guest_handle(xatp.gpfns, &gpfn);
set_xen_guest_handle(xatp.errs, &err);
rc = HYPERVISOR_memory_op(XENMEM_add_to_physmap_range, &xatp);
if (rc < 0)
return rc;
return err;
}
static int xlate_remove_from_p2m(unsigned long spfn, int count)
{
struct xen_remove_from_physmap xrp;
int i, rc;
for (i = 0; i < count; i++) {
xrp.domid = DOMID_SELF;
xrp.gpfn = spfn+i;
rc = HYPERVISOR_memory_op(XENMEM_remove_from_physmap, &xrp);
if (rc)
break;
}
return rc;
}
struct xlate_remap_data {
unsigned long fgfn; /* foreign domain's gfn */
pgprot_t prot;
domid_t domid;
int index;
struct page **pages;
};
static int xlate_map_pte_fn(pte_t *ptep, pgtable_t token, unsigned long addr,
void *data)
{
int rc;
struct xlate_remap_data *remap = data;
unsigned long pfn = page_to_pfn(remap->pages[remap->index++]);
pte_t pteval = pte_mkspecial(pfn_pte(pfn, remap->prot));
rc = xlate_add_to_p2m(pfn, remap->fgfn, remap->domid);
if (rc)
return rc;
native_set_pte(ptep, pteval);
return 0;
}
static int xlate_remap_gfn_range(struct vm_area_struct *vma,
unsigned long addr, unsigned long mfn,
int nr, pgprot_t prot, unsigned domid,
struct page **pages)
{
int err;
struct xlate_remap_data pvhdata;
BUG_ON(!pages);
pvhdata.fgfn = mfn;
pvhdata.prot = prot;
pvhdata.domid = domid;
pvhdata.index = 0;
pvhdata.pages = pages;
err = apply_to_page_range(vma->vm_mm, addr, nr << PAGE_SHIFT,
xlate_map_pte_fn, &pvhdata);
flush_tlb_all();
return err;
}
#endif
#define REMAP_BATCH_SIZE 16 #define REMAP_BATCH_SIZE 16
struct remap_data { struct remap_data {
unsigned long mfn; xen_pfn_t *mfn;
bool contiguous;
pgprot_t prot; pgprot_t prot;
struct mmu_update *mmu_update; struct mmu_update *mmu_update;
}; };
...@@ -2537,7 +2449,14 @@ static int remap_area_mfn_pte_fn(pte_t *ptep, pgtable_t token, ...@@ -2537,7 +2449,14 @@ static int remap_area_mfn_pte_fn(pte_t *ptep, pgtable_t token,
unsigned long addr, void *data) unsigned long addr, void *data)
{ {
struct remap_data *rmd = data; struct remap_data *rmd = data;
pte_t pte = pte_mkspecial(mfn_pte(rmd->mfn++, rmd->prot)); pte_t pte = pte_mkspecial(mfn_pte(*rmd->mfn, rmd->prot));
/* If we have a contigious range, just update the mfn itself,
else update pointer to be "next mfn". */
if (rmd->contiguous)
(*rmd->mfn)++;
else
rmd->mfn++;
rmd->mmu_update->ptr = virt_to_machine(ptep).maddr; rmd->mmu_update->ptr = virt_to_machine(ptep).maddr;
rmd->mmu_update->val = pte_val_ma(pte); rmd->mmu_update->val = pte_val_ma(pte);
...@@ -2546,26 +2465,26 @@ static int remap_area_mfn_pte_fn(pte_t *ptep, pgtable_t token, ...@@ -2546,26 +2465,26 @@ static int remap_area_mfn_pte_fn(pte_t *ptep, pgtable_t token,
return 0; return 0;
} }
int xen_remap_domain_mfn_range(struct vm_area_struct *vma, static int do_remap_mfn(struct vm_area_struct *vma,
unsigned long addr, unsigned long addr,
xen_pfn_t mfn, int nr, xen_pfn_t *mfn, int nr,
pgprot_t prot, unsigned domid, int *err_ptr, pgprot_t prot,
struct page **pages) unsigned domid,
struct page **pages)
{ {
int err = 0;
struct remap_data rmd; struct remap_data rmd;
struct mmu_update mmu_update[REMAP_BATCH_SIZE]; struct mmu_update mmu_update[REMAP_BATCH_SIZE];
int batch;
unsigned long range; unsigned long range;
int err = 0; int mapped = 0;
BUG_ON(!((vma->vm_flags & (VM_PFNMAP | VM_IO)) == (VM_PFNMAP | VM_IO))); BUG_ON(!((vma->vm_flags & (VM_PFNMAP | VM_IO)) == (VM_PFNMAP | VM_IO)));
if (xen_feature(XENFEAT_auto_translated_physmap)) { if (xen_feature(XENFEAT_auto_translated_physmap)) {
#ifdef CONFIG_XEN_PVH #ifdef CONFIG_XEN_PVH
/* We need to update the local page tables and the xen HAP */ /* We need to update the local page tables and the xen HAP */
return xlate_remap_gfn_range(vma, addr, mfn, nr, prot, return xen_xlate_remap_gfn_array(vma, addr, mfn, nr, err_ptr,
domid, pages); prot, domid, pages);
#else #else
return -EINVAL; return -EINVAL;
#endif #endif
...@@ -2573,9 +2492,15 @@ int xen_remap_domain_mfn_range(struct vm_area_struct *vma, ...@@ -2573,9 +2492,15 @@ int xen_remap_domain_mfn_range(struct vm_area_struct *vma,
rmd.mfn = mfn; rmd.mfn = mfn;
rmd.prot = prot; rmd.prot = prot;
/* We use the err_ptr to indicate if there we are doing a contigious
* mapping or a discontigious mapping. */
rmd.contiguous = !err_ptr;
while (nr) { while (nr) {
batch = min(REMAP_BATCH_SIZE, nr); int index = 0;
int done = 0;
int batch = min(REMAP_BATCH_SIZE, nr);
int batch_left = batch;
range = (unsigned long)batch << PAGE_SHIFT; range = (unsigned long)batch << PAGE_SHIFT;
rmd.mmu_update = mmu_update; rmd.mmu_update = mmu_update;
...@@ -2584,23 +2509,72 @@ int xen_remap_domain_mfn_range(struct vm_area_struct *vma, ...@@ -2584,23 +2509,72 @@ int xen_remap_domain_mfn_range(struct vm_area_struct *vma,
if (err) if (err)
goto out; goto out;
err = HYPERVISOR_mmu_update(mmu_update, batch, NULL, domid); /* We record the error for each page that gives an error, but
if (err < 0) * continue mapping until the whole set is done */
goto out; do {
int i;
err = HYPERVISOR_mmu_update(&mmu_update[index],
batch_left, &done, domid);
/*
* @err_ptr may be the same buffer as @mfn, so
* only clear it after each chunk of @mfn is
* used.
*/
if (err_ptr) {
for (i = index; i < index + done; i++)
err_ptr[i] = 0;
}
if (err < 0) {
if (!err_ptr)
goto out;
err_ptr[i] = err;
done++; /* Skip failed frame. */
} else
mapped += done;
batch_left -= done;
index += done;
} while (batch_left);
nr -= batch; nr -= batch;
addr += range; addr += range;
if (err_ptr)
err_ptr += batch;
} }
err = 0;
out: out:
xen_flush_tlb_all(); xen_flush_tlb_all();
return err; return err < 0 ? err : mapped;
}
int xen_remap_domain_mfn_range(struct vm_area_struct *vma,
unsigned long addr,
xen_pfn_t mfn, int nr,
pgprot_t prot, unsigned domid,
struct page **pages)
{
return do_remap_mfn(vma, addr, &mfn, nr, NULL, prot, domid, pages);
} }
EXPORT_SYMBOL_GPL(xen_remap_domain_mfn_range); EXPORT_SYMBOL_GPL(xen_remap_domain_mfn_range);
int xen_remap_domain_mfn_array(struct vm_area_struct *vma,
unsigned long addr,
xen_pfn_t *mfn, int nr,
int *err_ptr, pgprot_t prot,
unsigned domid, struct page **pages)
{
/* We BUG_ON because it's a programmer error to pass a NULL err_ptr,
* and the consequences later is quite hard to detect what the actual
* cause of "wrong memory was mapped in".
*/
BUG_ON(err_ptr == NULL);
return do_remap_mfn(vma, addr, mfn, nr, err_ptr, prot, domid, pages);
}
EXPORT_SYMBOL_GPL(xen_remap_domain_mfn_array);
/* Returns: 0 success */ /* Returns: 0 success */
int xen_unmap_domain_mfn_range(struct vm_area_struct *vma, int xen_unmap_domain_mfn_range(struct vm_area_struct *vma,
int numpgs, struct page **pages) int numpgs, struct page **pages)
...@@ -2609,22 +2583,7 @@ int xen_unmap_domain_mfn_range(struct vm_area_struct *vma, ...@@ -2609,22 +2583,7 @@ int xen_unmap_domain_mfn_range(struct vm_area_struct *vma,
return 0; return 0;
#ifdef CONFIG_XEN_PVH #ifdef CONFIG_XEN_PVH
while (numpgs--) { return xen_xlate_unmap_gfn_range(vma, numpgs, pages);
/*
* The mmu has already cleaned up the process mmu
* resources at this point (lookup_address will return
* NULL).
*/
unsigned long pfn = page_to_pfn(pages[numpgs]);
xlate_remove_from_p2m(pfn, 1);
}
/*
* We don't need to flush tlbs because as part of
* xlate_remove_from_p2m, the hypervisor will do tlb flushes
* after removing the p2m entries from the EPT/NPT
*/
return 0;
#else #else
return -EINVAL; return -EINVAL;
#endif #endif
......
#include <linux/ftrace.h> #include <linux/ftrace.h>
#include <xen/interface/xen.h> #include <xen/interface/xen.h>
#include <xen/interface/xen-mca.h>
#define N(x) [__HYPERVISOR_##x] = "("#x")" #define HYPERCALL(x) [__HYPERVISOR_##x] = "("#x")",
static const char *xen_hypercall_names[] = { static const char *xen_hypercall_names[] = {
N(set_trap_table), #include <asm/xen-hypercalls.h>
N(mmu_update),
N(set_gdt),
N(stack_switch),
N(set_callbacks),
N(fpu_taskswitch),
N(sched_op_compat),
N(dom0_op),
N(set_debugreg),
N(get_debugreg),
N(update_descriptor),
N(memory_op),
N(multicall),
N(update_va_mapping),
N(set_timer_op),
N(event_channel_op_compat),
N(xen_version),
N(console_io),
N(physdev_op_compat),
N(grant_table_op),
N(vm_assist),
N(update_va_mapping_otherdomain),
N(iret),
N(vcpu_op),
N(set_segment_base),
N(mmuext_op),
N(acm_op),
N(nmi_op),
N(sched_op),
N(callback_op),
N(xenoprof_op),
N(event_channel_op),
N(physdev_op),
N(hvm_op),
/* Architecture-specific hypercall definitions. */
N(arch_0),
N(arch_1),
N(arch_2),
N(arch_3),
N(arch_4),
N(arch_5),
N(arch_6),
N(arch_7),
}; };
#undef N #undef HYPERCALL
static const char *xen_hypercall_name(unsigned op) static const char *xen_hypercall_name(unsigned op)
{ {
......
...@@ -12,6 +12,8 @@ ...@@ -12,6 +12,8 @@
#include <xen/interface/elfnote.h> #include <xen/interface/elfnote.h>
#include <xen/interface/features.h> #include <xen/interface/features.h>
#include <xen/interface/xen.h>
#include <xen/interface/xen-mca.h>
#include <asm/xen/interface.h> #include <asm/xen/interface.h>
#ifdef CONFIG_XEN_PVH #ifdef CONFIG_XEN_PVH
...@@ -85,59 +87,14 @@ ENTRY(xen_pvh_early_cpu_init) ...@@ -85,59 +87,14 @@ ENTRY(xen_pvh_early_cpu_init)
.pushsection .text .pushsection .text
.balign PAGE_SIZE .balign PAGE_SIZE
ENTRY(hypercall_page) ENTRY(hypercall_page)
#define NEXT_HYPERCALL(x) \ .skip PAGE_SIZE
ENTRY(xen_hypercall_##x) \
.skip 32 #define HYPERCALL(n) \
.equ xen_hypercall_##n, hypercall_page + __HYPERVISOR_##n * 32; \
NEXT_HYPERCALL(set_trap_table) .type xen_hypercall_##n, @function; .size xen_hypercall_##n, 32
NEXT_HYPERCALL(mmu_update) #include <asm/xen-hypercalls.h>
NEXT_HYPERCALL(set_gdt) #undef HYPERCALL
NEXT_HYPERCALL(stack_switch)
NEXT_HYPERCALL(set_callbacks)
NEXT_HYPERCALL(fpu_taskswitch)
NEXT_HYPERCALL(sched_op_compat)
NEXT_HYPERCALL(platform_op)
NEXT_HYPERCALL(set_debugreg)
NEXT_HYPERCALL(get_debugreg)
NEXT_HYPERCALL(update_descriptor)
NEXT_HYPERCALL(ni)
NEXT_HYPERCALL(memory_op)
NEXT_HYPERCALL(multicall)
NEXT_HYPERCALL(update_va_mapping)
NEXT_HYPERCALL(set_timer_op)
NEXT_HYPERCALL(event_channel_op_compat)
NEXT_HYPERCALL(xen_version)
NEXT_HYPERCALL(console_io)
NEXT_HYPERCALL(physdev_op_compat)
NEXT_HYPERCALL(grant_table_op)
NEXT_HYPERCALL(vm_assist)
NEXT_HYPERCALL(update_va_mapping_otherdomain)
NEXT_HYPERCALL(iret)
NEXT_HYPERCALL(vcpu_op)
NEXT_HYPERCALL(set_segment_base)
NEXT_HYPERCALL(mmuext_op)
NEXT_HYPERCALL(xsm_op)
NEXT_HYPERCALL(nmi_op)
NEXT_HYPERCALL(sched_op)
NEXT_HYPERCALL(callback_op)
NEXT_HYPERCALL(xenoprof_op)
NEXT_HYPERCALL(event_channel_op)
NEXT_HYPERCALL(physdev_op)
NEXT_HYPERCALL(hvm_op)
NEXT_HYPERCALL(sysctl)
NEXT_HYPERCALL(domctl)
NEXT_HYPERCALL(kexec_op)
NEXT_HYPERCALL(tmem_op) /* 38 */
ENTRY(xen_hypercall_rsvr)
.skip 320
NEXT_HYPERCALL(mca) /* 48 */
NEXT_HYPERCALL(arch_1)
NEXT_HYPERCALL(arch_2)
NEXT_HYPERCALL(arch_3)
NEXT_HYPERCALL(arch_4)
NEXT_HYPERCALL(arch_5)
NEXT_HYPERCALL(arch_6)
.balign PAGE_SIZE
.popsection .popsection
ELFNOTE(Xen, XEN_ELFNOTE_GUEST_OS, .asciz "linux") ELFNOTE(Xen, XEN_ELFNOTE_GUEST_OS, .asciz "linux")
......
...@@ -193,7 +193,7 @@ static struct xen_blkif *xen_blkif_alloc(domid_t domid) ...@@ -193,7 +193,7 @@ static struct xen_blkif *xen_blkif_alloc(domid_t domid)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
} }
static int xen_blkif_map(struct xen_blkif *blkif, unsigned long shared_page, static int xen_blkif_map(struct xen_blkif *blkif, grant_ref_t gref,
unsigned int evtchn) unsigned int evtchn)
{ {
int err; int err;
...@@ -202,7 +202,8 @@ static int xen_blkif_map(struct xen_blkif *blkif, unsigned long shared_page, ...@@ -202,7 +202,8 @@ static int xen_blkif_map(struct xen_blkif *blkif, unsigned long shared_page,
if (blkif->irq) if (blkif->irq)
return 0; return 0;
err = xenbus_map_ring_valloc(blkif->be->dev, shared_page, &blkif->blk_ring); err = xenbus_map_ring_valloc(blkif->be->dev, &gref, 1,
&blkif->blk_ring);
if (err < 0) if (err < 0)
return err; return err;
......
...@@ -1245,6 +1245,7 @@ static int setup_blkring(struct xenbus_device *dev, ...@@ -1245,6 +1245,7 @@ static int setup_blkring(struct xenbus_device *dev,
struct blkfront_info *info) struct blkfront_info *info)
{ {
struct blkif_sring *sring; struct blkif_sring *sring;
grant_ref_t gref;
int err; int err;
info->ring_ref = GRANT_INVALID_REF; info->ring_ref = GRANT_INVALID_REF;
...@@ -1257,13 +1258,13 @@ static int setup_blkring(struct xenbus_device *dev, ...@@ -1257,13 +1258,13 @@ static int setup_blkring(struct xenbus_device *dev,
SHARED_RING_INIT(sring); SHARED_RING_INIT(sring);
FRONT_RING_INIT(&info->ring, sring, PAGE_SIZE); FRONT_RING_INIT(&info->ring, sring, PAGE_SIZE);
err = xenbus_grant_ring(dev, virt_to_mfn(info->ring.sring)); err = xenbus_grant_ring(dev, info->ring.sring, 1, &gref);
if (err < 0) { if (err < 0) {
free_page((unsigned long)sring); free_page((unsigned long)sring);
info->ring.sring = NULL; info->ring.sring = NULL;
goto fail; goto fail;
} }
info->ring_ref = err; info->ring_ref = gref;
err = xenbus_alloc_evtchn(dev, &info->evtchn); err = xenbus_alloc_evtchn(dev, &info->evtchn);
if (err) if (err)
......
...@@ -193,6 +193,7 @@ static int setup_ring(struct xenbus_device *dev, struct tpm_private *priv) ...@@ -193,6 +193,7 @@ static int setup_ring(struct xenbus_device *dev, struct tpm_private *priv)
struct xenbus_transaction xbt; struct xenbus_transaction xbt;
const char *message = NULL; const char *message = NULL;
int rv; int rv;
grant_ref_t gref;
priv->shr = (void *)__get_free_page(GFP_KERNEL|__GFP_ZERO); priv->shr = (void *)__get_free_page(GFP_KERNEL|__GFP_ZERO);
if (!priv->shr) { if (!priv->shr) {
...@@ -200,11 +201,11 @@ static int setup_ring(struct xenbus_device *dev, struct tpm_private *priv) ...@@ -200,11 +201,11 @@ static int setup_ring(struct xenbus_device *dev, struct tpm_private *priv)
return -ENOMEM; return -ENOMEM;
} }
rv = xenbus_grant_ring(dev, virt_to_mfn(priv->shr)); rv = xenbus_grant_ring(dev, &priv->shr, 1, &gref);
if (rv < 0) if (rv < 0)
return rv; return rv;
priv->ring_ref = rv; priv->ring_ref = gref;
rv = xenbus_alloc_evtchn(dev, &priv->evtchn); rv = xenbus_alloc_evtchn(dev, &priv->evtchn);
if (rv) if (rv)
......
...@@ -1780,7 +1780,7 @@ int xenvif_map_frontend_rings(struct xenvif_queue *queue, ...@@ -1780,7 +1780,7 @@ int xenvif_map_frontend_rings(struct xenvif_queue *queue,
int err = -ENOMEM; int err = -ENOMEM;
err = xenbus_map_ring_valloc(xenvif_to_xenbus_device(queue->vif), err = xenbus_map_ring_valloc(xenvif_to_xenbus_device(queue->vif),
tx_ring_ref, &addr); &tx_ring_ref, 1, &addr);
if (err) if (err)
goto err; goto err;
...@@ -1788,7 +1788,7 @@ int xenvif_map_frontend_rings(struct xenvif_queue *queue, ...@@ -1788,7 +1788,7 @@ int xenvif_map_frontend_rings(struct xenvif_queue *queue,
BACK_RING_INIT(&queue->tx, txs, PAGE_SIZE); BACK_RING_INIT(&queue->tx, txs, PAGE_SIZE);
err = xenbus_map_ring_valloc(xenvif_to_xenbus_device(queue->vif), err = xenbus_map_ring_valloc(xenvif_to_xenbus_device(queue->vif),
rx_ring_ref, &addr); &rx_ring_ref, 1, &addr);
if (err) if (err)
goto err; goto err;
......
...@@ -1483,6 +1483,7 @@ static int setup_netfront(struct xenbus_device *dev, ...@@ -1483,6 +1483,7 @@ static int setup_netfront(struct xenbus_device *dev,
{ {
struct xen_netif_tx_sring *txs; struct xen_netif_tx_sring *txs;
struct xen_netif_rx_sring *rxs; struct xen_netif_rx_sring *rxs;
grant_ref_t gref;
int err; int err;
queue->tx_ring_ref = GRANT_INVALID_REF; queue->tx_ring_ref = GRANT_INVALID_REF;
...@@ -1499,10 +1500,10 @@ static int setup_netfront(struct xenbus_device *dev, ...@@ -1499,10 +1500,10 @@ static int setup_netfront(struct xenbus_device *dev,
SHARED_RING_INIT(txs); SHARED_RING_INIT(txs);
FRONT_RING_INIT(&queue->tx, txs, PAGE_SIZE); FRONT_RING_INIT(&queue->tx, txs, PAGE_SIZE);
err = xenbus_grant_ring(dev, virt_to_mfn(txs)); err = xenbus_grant_ring(dev, txs, 1, &gref);
if (err < 0) if (err < 0)
goto grant_tx_ring_fail; goto grant_tx_ring_fail;
queue->tx_ring_ref = err; queue->tx_ring_ref = gref;
rxs = (struct xen_netif_rx_sring *)get_zeroed_page(GFP_NOIO | __GFP_HIGH); rxs = (struct xen_netif_rx_sring *)get_zeroed_page(GFP_NOIO | __GFP_HIGH);
if (!rxs) { if (!rxs) {
...@@ -1513,10 +1514,10 @@ static int setup_netfront(struct xenbus_device *dev, ...@@ -1513,10 +1514,10 @@ static int setup_netfront(struct xenbus_device *dev,
SHARED_RING_INIT(rxs); SHARED_RING_INIT(rxs);
FRONT_RING_INIT(&queue->rx, rxs, PAGE_SIZE); FRONT_RING_INIT(&queue->rx, rxs, PAGE_SIZE);
err = xenbus_grant_ring(dev, virt_to_mfn(rxs)); err = xenbus_grant_ring(dev, rxs, 1, &gref);
if (err < 0) if (err < 0)
goto grant_rx_ring_fail; goto grant_rx_ring_fail;
queue->rx_ring_ref = err; queue->rx_ring_ref = gref;
if (feature_split_evtchn) if (feature_split_evtchn)
err = setup_netfront_split(queue); err = setup_netfront_split(queue);
......
...@@ -777,12 +777,13 @@ static int pcifront_publish_info(struct pcifront_device *pdev) ...@@ -777,12 +777,13 @@ static int pcifront_publish_info(struct pcifront_device *pdev)
{ {
int err = 0; int err = 0;
struct xenbus_transaction trans; struct xenbus_transaction trans;
grant_ref_t gref;
err = xenbus_grant_ring(pdev->xdev, virt_to_mfn(pdev->sh_info)); err = xenbus_grant_ring(pdev->xdev, pdev->sh_info, 1, &gref);
if (err < 0) if (err < 0)
goto out; goto out;
pdev->gnt_ref = err; pdev->gnt_ref = gref;
err = xenbus_alloc_evtchn(pdev->xdev, &pdev->evtchn); err = xenbus_alloc_evtchn(pdev->xdev, &pdev->evtchn);
if (err) if (err)
......
This diff is collapsed.
...@@ -270,4 +270,10 @@ config XEN_EFI ...@@ -270,4 +270,10 @@ config XEN_EFI
def_bool y def_bool y
depends on X86_64 && EFI depends on X86_64 && EFI
config XEN_AUTO_XLATE
def_bool y
depends on ARM || ARM64 || XEN_PVHVM
help
Support for auto-translated physmap guests.
endmenu endmenu
...@@ -37,6 +37,7 @@ obj-$(CONFIG_XEN_ACPI_HOTPLUG_CPU) += xen-acpi-cpuhotplug.o ...@@ -37,6 +37,7 @@ obj-$(CONFIG_XEN_ACPI_HOTPLUG_CPU) += xen-acpi-cpuhotplug.o
obj-$(CONFIG_XEN_ACPI_PROCESSOR) += xen-acpi-processor.o obj-$(CONFIG_XEN_ACPI_PROCESSOR) += xen-acpi-processor.o
obj-$(CONFIG_XEN_EFI) += efi.o obj-$(CONFIG_XEN_EFI) += efi.o
obj-$(CONFIG_XEN_SCSI_BACKEND) += xen-scsiback.o obj-$(CONFIG_XEN_SCSI_BACKEND) += xen-scsiback.o
obj-$(CONFIG_XEN_AUTO_XLATE) += xlate_mmu.o
xen-evtchn-y := evtchn.o xen-evtchn-y := evtchn.o
xen-gntdev-y := gntdev.o xen-gntdev-y := gntdev.o
xen-gntalloc-y := gntalloc.o xen-gntalloc-y := gntalloc.o
......
...@@ -393,14 +393,25 @@ static int bind_virq_for_mce(void) ...@@ -393,14 +393,25 @@ static int bind_virq_for_mce(void)
static int __init xen_late_init_mcelog(void) static int __init xen_late_init_mcelog(void)
{ {
int ret;
/* Only DOM0 is responsible for MCE logging */ /* Only DOM0 is responsible for MCE logging */
if (xen_initial_domain()) { if (!xen_initial_domain())
/* register character device /dev/mcelog for xen mcelog */ return -ENODEV;
if (misc_register(&xen_mce_chrdev_device))
return -ENODEV; /* register character device /dev/mcelog for xen mcelog */
return bind_virq_for_mce(); ret = misc_register(&xen_mce_chrdev_device);
} if (ret)
return ret;
ret = bind_virq_for_mce();
if (ret)
goto deregister;
return -ENODEV; return 0;
deregister:
misc_deregister(&xen_mce_chrdev_device);
return ret;
} }
device_initcall(xen_late_init_mcelog); device_initcall(xen_late_init_mcelog);
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/acpi.h> #include <linux/acpi.h>
#include <linux/pci-acpi.h>
#include <xen/xen.h> #include <xen/xen.h>
#include <xen/interface/physdev.h> #include <xen/interface/physdev.h>
#include <xen/interface/xen.h> #include <xen/interface/xen.h>
...@@ -67,12 +68,22 @@ static int xen_add_device(struct device *dev) ...@@ -67,12 +68,22 @@ static int xen_add_device(struct device *dev)
#ifdef CONFIG_ACPI #ifdef CONFIG_ACPI
handle = ACPI_HANDLE(&pci_dev->dev); handle = ACPI_HANDLE(&pci_dev->dev);
if (!handle && pci_dev->bus->bridge)
handle = ACPI_HANDLE(pci_dev->bus->bridge);
#ifdef CONFIG_PCI_IOV #ifdef CONFIG_PCI_IOV
if (!handle && pci_dev->is_virtfn) if (!handle && pci_dev->is_virtfn)
handle = ACPI_HANDLE(physfn->bus->bridge); handle = ACPI_HANDLE(physfn->bus->bridge);
#endif #endif
if (!handle) {
/*
* This device was not listed in the ACPI name space at
* all. Try to get acpi handle of parent pci bus.
*/
struct pci_bus *pbus;
for (pbus = pci_dev->bus; pbus; pbus = pbus->parent) {
handle = acpi_pci_get_bridge_handle(pbus);
if (handle)
break;
}
}
if (handle) { if (handle) {
acpi_status status; acpi_status status;
......
...@@ -132,6 +132,33 @@ static ssize_t __ref store_online(struct device *dev, ...@@ -132,6 +132,33 @@ static ssize_t __ref store_online(struct device *dev,
} }
static DEVICE_ATTR(online, S_IRUGO | S_IWUSR, show_online, store_online); static DEVICE_ATTR(online, S_IRUGO | S_IWUSR, show_online, store_online);
static struct attribute *pcpu_dev_attrs[] = {
&dev_attr_online.attr,
NULL
};
static umode_t pcpu_dev_is_visible(struct kobject *kobj,
struct attribute *attr, int idx)
{
struct device *dev = kobj_to_dev(kobj);
/*
* Xen never offline cpu0 due to several restrictions
* and assumptions. This basically doesn't add a sys control
* to user, one cannot attempt to offline BSP.
*/
return dev->id ? attr->mode : 0;
}
static const struct attribute_group pcpu_dev_group = {
.attrs = pcpu_dev_attrs,
.is_visible = pcpu_dev_is_visible,
};
static const struct attribute_group *pcpu_dev_groups[] = {
&pcpu_dev_group,
NULL
};
static bool xen_pcpu_online(uint32_t flags) static bool xen_pcpu_online(uint32_t flags)
{ {
return !!(flags & XEN_PCPU_FLAGS_ONLINE); return !!(flags & XEN_PCPU_FLAGS_ONLINE);
...@@ -181,9 +208,6 @@ static void unregister_and_remove_pcpu(struct pcpu *pcpu) ...@@ -181,9 +208,6 @@ static void unregister_and_remove_pcpu(struct pcpu *pcpu)
return; return;
dev = &pcpu->dev; dev = &pcpu->dev;
if (dev->id)
device_remove_file(dev, &dev_attr_online);
/* pcpu remove would be implicitly done */ /* pcpu remove would be implicitly done */
device_unregister(dev); device_unregister(dev);
} }
...@@ -200,6 +224,7 @@ static int register_pcpu(struct pcpu *pcpu) ...@@ -200,6 +224,7 @@ static int register_pcpu(struct pcpu *pcpu)
dev->bus = &xen_pcpu_subsys; dev->bus = &xen_pcpu_subsys;
dev->id = pcpu->cpu_id; dev->id = pcpu->cpu_id;
dev->release = pcpu_release; dev->release = pcpu_release;
dev->groups = pcpu_dev_groups;
err = device_register(dev); err = device_register(dev);
if (err) { if (err) {
...@@ -207,19 +232,6 @@ static int register_pcpu(struct pcpu *pcpu) ...@@ -207,19 +232,6 @@ static int register_pcpu(struct pcpu *pcpu)
return err; return err;
} }
/*
* Xen never offline cpu0 due to several restrictions
* and assumptions. This basically doesn't add a sys control
* to user, one cannot attempt to offline BSP.
*/
if (dev->id) {
err = device_create_file(dev, &dev_attr_online);
if (err) {
device_unregister(dev);
return err;
}
}
return 0; return 0;
} }
......
...@@ -159,6 +159,40 @@ static int traverse_pages(unsigned nelem, size_t size, ...@@ -159,6 +159,40 @@ static int traverse_pages(unsigned nelem, size_t size,
return ret; return ret;
} }
/*
* Similar to traverse_pages, but use each page as a "block" of
* data to be processed as one unit.
*/
static int traverse_pages_block(unsigned nelem, size_t size,
struct list_head *pos,
int (*fn)(void *data, int nr, void *state),
void *state)
{
void *pagedata;
unsigned pageidx;
int ret = 0;
BUG_ON(size > PAGE_SIZE);
pageidx = PAGE_SIZE;
while (nelem) {
int nr = (PAGE_SIZE/size);
struct page *page;
if (nr > nelem)
nr = nelem;
pos = pos->next;
page = list_entry(pos, struct page, lru);
pagedata = page_address(page);
ret = (*fn)(pagedata, nr, state);
if (ret)
break;
nelem -= nr;
}
return ret;
}
struct mmap_mfn_state { struct mmap_mfn_state {
unsigned long va; unsigned long va;
struct vm_area_struct *vma; struct vm_area_struct *vma;
...@@ -274,39 +308,25 @@ struct mmap_batch_state { ...@@ -274,39 +308,25 @@ struct mmap_batch_state {
/* auto translated dom0 note: if domU being created is PV, then mfn is /* auto translated dom0 note: if domU being created is PV, then mfn is
* mfn(addr on bus). If it's auto xlated, then mfn is pfn (input to HAP). * mfn(addr on bus). If it's auto xlated, then mfn is pfn (input to HAP).
*/ */
static int mmap_batch_fn(void *data, void *state) static int mmap_batch_fn(void *data, int nr, void *state)
{ {
xen_pfn_t *mfnp = data; xen_pfn_t *mfnp = data;
struct mmap_batch_state *st = state; struct mmap_batch_state *st = state;
struct vm_area_struct *vma = st->vma; struct vm_area_struct *vma = st->vma;
struct page **pages = vma->vm_private_data; struct page **pages = vma->vm_private_data;
struct page *cur_page = NULL; struct page **cur_pages = NULL;
int ret; int ret;
if (xen_feature(XENFEAT_auto_translated_physmap)) if (xen_feature(XENFEAT_auto_translated_physmap))
cur_page = pages[st->index++]; cur_pages = &pages[st->index];
ret = xen_remap_domain_mfn_range(st->vma, st->va & PAGE_MASK, *mfnp, 1, BUG_ON(nr < 0);
st->vma->vm_page_prot, st->domain, ret = xen_remap_domain_mfn_array(st->vma, st->va & PAGE_MASK, mfnp, nr,
&cur_page); (int *)mfnp, st->vma->vm_page_prot,
st->domain, cur_pages);
/* Store error code for second pass. */ /* Adjust the global_error? */
if (st->version == 1) { if (ret != nr) {
if (ret < 0) {
/*
* V1 encodes the error codes in the 32bit top nibble of the
* mfn (with its known limitations vis-a-vis 64 bit callers).
*/
*mfnp |= (ret == -ENOENT) ?
PRIVCMD_MMAPBATCH_PAGED_ERROR :
PRIVCMD_MMAPBATCH_MFN_ERROR;
}
} else { /* st->version == 2 */
*((int *) mfnp) = ret;
}
/* And see if it affects the global_error. */
if (ret < 0) {
if (ret == -ENOENT) if (ret == -ENOENT)
st->global_error = -ENOENT; st->global_error = -ENOENT;
else { else {
...@@ -315,23 +335,35 @@ static int mmap_batch_fn(void *data, void *state) ...@@ -315,23 +335,35 @@ static int mmap_batch_fn(void *data, void *state)
st->global_error = 1; st->global_error = 1;
} }
} }
st->va += PAGE_SIZE; st->va += PAGE_SIZE * nr;
st->index += nr;
return 0; return 0;
} }
static int mmap_return_errors(void *data, void *state) static int mmap_return_error(int err, struct mmap_batch_state *st)
{ {
struct mmap_batch_state *st = state; int ret;
if (st->version == 1) { if (st->version == 1) {
xen_pfn_t mfnp = *((xen_pfn_t *) data); if (err) {
if (mfnp & PRIVCMD_MMAPBATCH_MFN_ERROR) xen_pfn_t mfn;
return __put_user(mfnp, st->user_mfn++);
else ret = get_user(mfn, st->user_mfn);
if (ret < 0)
return ret;
/*
* V1 encodes the error codes in the 32bit top
* nibble of the mfn (with its known
* limitations vis-a-vis 64 bit callers).
*/
mfn |= (err == -ENOENT) ?
PRIVCMD_MMAPBATCH_PAGED_ERROR :
PRIVCMD_MMAPBATCH_MFN_ERROR;
return __put_user(mfn, st->user_mfn++);
} else
st->user_mfn++; st->user_mfn++;
} else { /* st->version == 2 */ } else { /* st->version == 2 */
int err = *((int *) data);
if (err) if (err)
return __put_user(err, st->user_err++); return __put_user(err, st->user_err++);
else else
...@@ -341,6 +373,21 @@ static int mmap_return_errors(void *data, void *state) ...@@ -341,6 +373,21 @@ static int mmap_return_errors(void *data, void *state)
return 0; return 0;
} }
static int mmap_return_errors(void *data, int nr, void *state)
{
struct mmap_batch_state *st = state;
int *errs = data;
int i;
int ret;
for (i = 0; i < nr; i++) {
ret = mmap_return_error(errs[i], st);
if (ret < 0)
return ret;
}
return 0;
}
/* Allocate pfns that are then mapped with gmfns from foreign domid. Update /* Allocate pfns that are then mapped with gmfns from foreign domid. Update
* the vma with the page info to use later. * the vma with the page info to use later.
* Returns: 0 if success, otherwise -errno * Returns: 0 if success, otherwise -errno
...@@ -472,8 +519,8 @@ static long privcmd_ioctl_mmap_batch(void __user *udata, int version) ...@@ -472,8 +519,8 @@ static long privcmd_ioctl_mmap_batch(void __user *udata, int version)
state.version = version; state.version = version;
/* mmap_batch_fn guarantees ret == 0 */ /* mmap_batch_fn guarantees ret == 0 */
BUG_ON(traverse_pages(m.num, sizeof(xen_pfn_t), BUG_ON(traverse_pages_block(m.num, sizeof(xen_pfn_t),
&pagelist, mmap_batch_fn, &state)); &pagelist, mmap_batch_fn, &state));
up_write(&mm->mmap_sem); up_write(&mm->mmap_sem);
...@@ -481,8 +528,8 @@ static long privcmd_ioctl_mmap_batch(void __user *udata, int version) ...@@ -481,8 +528,8 @@ static long privcmd_ioctl_mmap_batch(void __user *udata, int version)
/* Write back errors in second pass. */ /* Write back errors in second pass. */
state.user_mfn = (xen_pfn_t *)m.arr; state.user_mfn = (xen_pfn_t *)m.arr;
state.user_err = m.err; state.user_err = m.err;
ret = traverse_pages(m.num, sizeof(xen_pfn_t), ret = traverse_pages_block(m.num, sizeof(xen_pfn_t),
&pagelist, mmap_return_errors, &state); &pagelist, mmap_return_errors, &state);
} else } else
ret = 0; ret = 0;
......
...@@ -193,13 +193,18 @@ static DEVICE_ATTR(target, S_IRUGO | S_IWUSR, ...@@ -193,13 +193,18 @@ static DEVICE_ATTR(target, S_IRUGO | S_IWUSR,
show_target, store_target); show_target, store_target);
static struct device_attribute *balloon_attrs[] = { static struct attribute *balloon_attrs[] = {
&dev_attr_target_kb, &dev_attr_target_kb.attr,
&dev_attr_target, &dev_attr_target.attr,
&dev_attr_schedule_delay.attr, &dev_attr_schedule_delay.attr.attr,
&dev_attr_max_schedule_delay.attr, &dev_attr_max_schedule_delay.attr.attr,
&dev_attr_retry_count.attr, &dev_attr_retry_count.attr.attr,
&dev_attr_max_retry_count.attr &dev_attr_max_retry_count.attr.attr,
NULL
};
static const struct attribute_group balloon_group = {
.attrs = balloon_attrs
}; };
static struct attribute *balloon_info_attrs[] = { static struct attribute *balloon_info_attrs[] = {
...@@ -214,6 +219,12 @@ static const struct attribute_group balloon_info_group = { ...@@ -214,6 +219,12 @@ static const struct attribute_group balloon_info_group = {
.attrs = balloon_info_attrs .attrs = balloon_info_attrs
}; };
static const struct attribute_group *balloon_groups[] = {
&balloon_group,
&balloon_info_group,
NULL
};
static struct bus_type balloon_subsys = { static struct bus_type balloon_subsys = {
.name = BALLOON_CLASS_NAME, .name = BALLOON_CLASS_NAME,
.dev_name = BALLOON_CLASS_NAME, .dev_name = BALLOON_CLASS_NAME,
...@@ -221,7 +232,7 @@ static struct bus_type balloon_subsys = { ...@@ -221,7 +232,7 @@ static struct bus_type balloon_subsys = {
static int register_balloon(struct device *dev) static int register_balloon(struct device *dev)
{ {
int i, error; int error;
error = subsys_system_register(&balloon_subsys, NULL); error = subsys_system_register(&balloon_subsys, NULL);
if (error) if (error)
...@@ -229,6 +240,7 @@ static int register_balloon(struct device *dev) ...@@ -229,6 +240,7 @@ static int register_balloon(struct device *dev)
dev->id = 0; dev->id = 0;
dev->bus = &balloon_subsys; dev->bus = &balloon_subsys;
dev->groups = balloon_groups;
error = device_register(dev); error = device_register(dev);
if (error) { if (error) {
...@@ -236,24 +248,7 @@ static int register_balloon(struct device *dev) ...@@ -236,24 +248,7 @@ static int register_balloon(struct device *dev)
return error; return error;
} }
for (i = 0; i < ARRAY_SIZE(balloon_attrs); i++) {
error = device_create_file(dev, balloon_attrs[i]);
if (error)
goto fail;
}
error = sysfs_create_group(&dev->kobj, &balloon_info_group);
if (error)
goto fail;
return 0; return 0;
fail:
while (--i >= 0)
device_remove_file(dev, balloon_attrs[i]);
device_unregister(dev);
bus_unregister(&balloon_subsys);
return error;
} }
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
...@@ -88,9 +88,15 @@ static int command_write(struct pci_dev *dev, int offset, u16 value, void *data) ...@@ -88,9 +88,15 @@ static int command_write(struct pci_dev *dev, int offset, u16 value, void *data)
printk(KERN_DEBUG DRV_NAME ": %s: set bus master\n", printk(KERN_DEBUG DRV_NAME ": %s: set bus master\n",
pci_name(dev)); pci_name(dev));
pci_set_master(dev); pci_set_master(dev);
} else if (dev->is_busmaster && !is_master_cmd(value)) {
if (unlikely(verbose_request))
printk(KERN_DEBUG DRV_NAME ": %s: clear bus master\n",
pci_name(dev));
pci_clear_master(dev);
} }
if (value & PCI_COMMAND_INVALIDATE) { if (!(cmd->val & PCI_COMMAND_INVALIDATE) &&
(value & PCI_COMMAND_INVALIDATE)) {
if (unlikely(verbose_request)) if (unlikely(verbose_request))
printk(KERN_DEBUG printk(KERN_DEBUG
DRV_NAME ": %s: enable memory-write-invalidate\n", DRV_NAME ": %s: enable memory-write-invalidate\n",
...@@ -101,6 +107,13 @@ static int command_write(struct pci_dev *dev, int offset, u16 value, void *data) ...@@ -101,6 +107,13 @@ static int command_write(struct pci_dev *dev, int offset, u16 value, void *data)
pci_name(dev), err); pci_name(dev), err);
value &= ~PCI_COMMAND_INVALIDATE; value &= ~PCI_COMMAND_INVALIDATE;
} }
} else if ((cmd->val & PCI_COMMAND_INVALIDATE) &&
!(value & PCI_COMMAND_INVALIDATE)) {
if (unlikely(verbose_request))
printk(KERN_DEBUG
DRV_NAME ": %s: disable memory-write-invalidate\n",
pci_name(dev));
pci_clear_mwi(dev);
} }
cmd->val = value; cmd->val = value;
......
...@@ -118,7 +118,7 @@ static void pcistub_device_release(struct kref *kref) ...@@ -118,7 +118,7 @@ static void pcistub_device_release(struct kref *kref)
int err = HYPERVISOR_physdev_op(PHYSDEVOP_release_msix, int err = HYPERVISOR_physdev_op(PHYSDEVOP_release_msix,
&ppdev); &ppdev);
if (err) if (err && err != -ENOSYS)
dev_warn(&dev->dev, "MSI-X release failed (%d)\n", dev_warn(&dev->dev, "MSI-X release failed (%d)\n",
err); err);
} }
...@@ -402,7 +402,7 @@ static int pcistub_init_device(struct pci_dev *dev) ...@@ -402,7 +402,7 @@ static int pcistub_init_device(struct pci_dev *dev)
}; };
err = HYPERVISOR_physdev_op(PHYSDEVOP_prepare_msix, &ppdev); err = HYPERVISOR_physdev_op(PHYSDEVOP_prepare_msix, &ppdev);
if (err) if (err && err != -ENOSYS)
dev_err(&dev->dev, "MSI-X preparation failed (%d)\n", dev_err(&dev->dev, "MSI-X preparation failed (%d)\n",
err); err);
} }
......
...@@ -113,7 +113,7 @@ static int xen_pcibk_do_attach(struct xen_pcibk_device *pdev, int gnt_ref, ...@@ -113,7 +113,7 @@ static int xen_pcibk_do_attach(struct xen_pcibk_device *pdev, int gnt_ref,
"Attaching to frontend resources - gnt_ref=%d evtchn=%d\n", "Attaching to frontend resources - gnt_ref=%d evtchn=%d\n",
gnt_ref, remote_evtchn); gnt_ref, remote_evtchn);
err = xenbus_map_ring_valloc(pdev->xdev, gnt_ref, &vaddr); err = xenbus_map_ring_valloc(pdev->xdev, &gnt_ref, 1, &vaddr);
if (err < 0) { if (err < 0) {
xenbus_dev_fatal(pdev->xdev, err, xenbus_dev_fatal(pdev->xdev, err,
"Error mapping other domain page in ours."); "Error mapping other domain page in ours.");
......
This diff is collapsed.
This diff is collapsed.
/*
* MMU operations common to all auto-translated physmap guests.
*
* Copyright (C) 2015 Citrix Systems R&D Ltd.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation; or, when distributed
* separately from the Linux kernel or incorporated into other
* software packages, subject to the following license:
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this source file (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy, modify,
* merge, publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include <linux/kernel.h>
#include <linux/mm.h>
#include <asm/xen/hypercall.h>
#include <asm/xen/hypervisor.h>
#include <xen/xen.h>
#include <xen/page.h>
#include <xen/interface/xen.h>
#include <xen/interface/memory.h>
/* map fgmfn of domid to lpfn in the current domain */
static int map_foreign_page(unsigned long lpfn, unsigned long fgmfn,
unsigned int domid)
{
int rc;
struct xen_add_to_physmap_range xatp = {
.domid = DOMID_SELF,
.foreign_domid = domid,
.size = 1,
.space = XENMAPSPACE_gmfn_foreign,
};
xen_ulong_t idx = fgmfn;
xen_pfn_t gpfn = lpfn;
int err = 0;
set_xen_guest_handle(xatp.idxs, &idx);
set_xen_guest_handle(xatp.gpfns, &gpfn);
set_xen_guest_handle(xatp.errs, &err);
rc = HYPERVISOR_memory_op(XENMEM_add_to_physmap_range, &xatp);
return rc < 0 ? rc : err;
}
struct remap_data {
xen_pfn_t *fgmfn; /* foreign domain's gmfn */
pgprot_t prot;
domid_t domid;
struct vm_area_struct *vma;
int index;
struct page **pages;
struct xen_remap_mfn_info *info;
int *err_ptr;
int mapped;
};
static int remap_pte_fn(pte_t *ptep, pgtable_t token, unsigned long addr,
void *data)
{
struct remap_data *info = data;
struct page *page = info->pages[info->index++];
unsigned long pfn = page_to_pfn(page);
pte_t pte = pte_mkspecial(pfn_pte(pfn, info->prot));
int rc;
rc = map_foreign_page(pfn, *info->fgmfn, info->domid);
*info->err_ptr++ = rc;
if (!rc) {
set_pte_at(info->vma->vm_mm, addr, ptep, pte);
info->mapped++;
}
info->fgmfn++;
return 0;
}
int xen_xlate_remap_gfn_array(struct vm_area_struct *vma,
unsigned long addr,
xen_pfn_t *mfn, int nr,
int *err_ptr, pgprot_t prot,
unsigned domid,
struct page **pages)
{
int err;
struct remap_data data;
unsigned long range = nr << PAGE_SHIFT;
/* Kept here for the purpose of making sure code doesn't break
x86 PVOPS */
BUG_ON(!((vma->vm_flags & (VM_PFNMAP | VM_IO)) == (VM_PFNMAP | VM_IO)));
data.fgmfn = mfn;
data.prot = prot;
data.domid = domid;
data.vma = vma;
data.pages = pages;
data.index = 0;
data.err_ptr = err_ptr;
data.mapped = 0;
err = apply_to_page_range(vma->vm_mm, addr, range,
remap_pte_fn, &data);
return err < 0 ? err : data.mapped;
}
EXPORT_SYMBOL_GPL(xen_xlate_remap_gfn_array);
int xen_xlate_unmap_gfn_range(struct vm_area_struct *vma,
int nr, struct page **pages)
{
int i;
for (i = 0; i < nr; i++) {
struct xen_remove_from_physmap xrp;
unsigned long pfn;
pfn = page_to_pfn(pages[i]);
xrp.domid = DOMID_SELF;
xrp.gpfn = pfn;
(void)HYPERVISOR_memory_op(XENMEM_remove_from_physmap, &xrp);
}
return 0;
}
EXPORT_SYMBOL_GPL(xen_xlate_unmap_gfn_range);
...@@ -67,7 +67,7 @@ ...@@ -67,7 +67,7 @@
#define __HYPERVISOR_vcpu_op 24 #define __HYPERVISOR_vcpu_op 24
#define __HYPERVISOR_set_segment_base 25 /* x86/64 only */ #define __HYPERVISOR_set_segment_base 25 /* x86/64 only */
#define __HYPERVISOR_mmuext_op 26 #define __HYPERVISOR_mmuext_op 26
#define __HYPERVISOR_acm_op 27 #define __HYPERVISOR_xsm_op 27
#define __HYPERVISOR_nmi_op 28 #define __HYPERVISOR_nmi_op 28
#define __HYPERVISOR_sched_op 29 #define __HYPERVISOR_sched_op 29
#define __HYPERVISOR_callback_op 30 #define __HYPERVISOR_callback_op 30
...@@ -75,7 +75,11 @@ ...@@ -75,7 +75,11 @@
#define __HYPERVISOR_event_channel_op 32 #define __HYPERVISOR_event_channel_op 32
#define __HYPERVISOR_physdev_op 33 #define __HYPERVISOR_physdev_op 33
#define __HYPERVISOR_hvm_op 34 #define __HYPERVISOR_hvm_op 34
#define __HYPERVISOR_sysctl 35
#define __HYPERVISOR_domctl 36
#define __HYPERVISOR_kexec_op 37
#define __HYPERVISOR_tmem_op 38 #define __HYPERVISOR_tmem_op 38
#define __HYPERVISOR_xc_reserved_op 39 /* reserved for XenClient */
/* Architecture-specific hypercall definitions. */ /* Architecture-specific hypercall definitions. */
#define __HYPERVISOR_arch_0 48 #define __HYPERVISOR_arch_0 48
......
...@@ -27,13 +27,58 @@ int xen_create_contiguous_region(phys_addr_t pstart, unsigned int order, ...@@ -27,13 +27,58 @@ int xen_create_contiguous_region(phys_addr_t pstart, unsigned int order,
void xen_destroy_contiguous_region(phys_addr_t pstart, unsigned int order); void xen_destroy_contiguous_region(phys_addr_t pstart, unsigned int order);
struct vm_area_struct; struct vm_area_struct;
/*
* xen_remap_domain_mfn_array() - map an array of foreign frames
* @vma: VMA to map the pages into
* @addr: Address at which to map the pages
* @gfn: Array of GFNs to map
* @nr: Number entries in the GFN array
* @err_ptr: Returns per-GFN error status.
* @prot: page protection mask
* @domid: Domain owning the pages
* @pages: Array of pages if this domain has an auto-translated physmap
*
* @gfn and @err_ptr may point to the same buffer, the GFNs will be
* overwritten by the error codes after they are mapped.
*
* Returns the number of successfully mapped frames, or a -ve error
* code.
*/
int xen_remap_domain_mfn_array(struct vm_area_struct *vma,
unsigned long addr,
xen_pfn_t *gfn, int nr,
int *err_ptr, pgprot_t prot,
unsigned domid,
struct page **pages);
/* xen_remap_domain_mfn_range() - map a range of foreign frames
* @vma: VMA to map the pages into
* @addr: Address at which to map the pages
* @gfn: First GFN to map.
* @nr: Number frames to map
* @prot: page protection mask
* @domid: Domain owning the pages
* @pages: Array of pages if this domain has an auto-translated physmap
*
* Returns the number of successfully mapped frames, or a -ve error
* code.
*/
int xen_remap_domain_mfn_range(struct vm_area_struct *vma, int xen_remap_domain_mfn_range(struct vm_area_struct *vma,
unsigned long addr, unsigned long addr,
xen_pfn_t mfn, int nr, xen_pfn_t gfn, int nr,
pgprot_t prot, unsigned domid, pgprot_t prot, unsigned domid,
struct page **pages); struct page **pages);
int xen_unmap_domain_mfn_range(struct vm_area_struct *vma, int xen_unmap_domain_mfn_range(struct vm_area_struct *vma,
int numpgs, struct page **pages); int numpgs, struct page **pages);
int xen_xlate_remap_gfn_array(struct vm_area_struct *vma,
unsigned long addr,
xen_pfn_t *gfn, int nr,
int *err_ptr, pgprot_t prot,
unsigned domid,
struct page **pages);
int xen_xlate_unmap_gfn_range(struct vm_area_struct *vma,
int nr, struct page **pages);
bool xen_running_on_version_or_later(unsigned int major, unsigned int minor); bool xen_running_on_version_or_later(unsigned int major, unsigned int minor);
......
...@@ -46,6 +46,10 @@ ...@@ -46,6 +46,10 @@
#include <xen/interface/io/xenbus.h> #include <xen/interface/io/xenbus.h>
#include <xen/interface/io/xs_wire.h> #include <xen/interface/io/xs_wire.h>
#define XENBUS_MAX_RING_PAGE_ORDER 4
#define XENBUS_MAX_RING_PAGES (1U << XENBUS_MAX_RING_PAGE_ORDER)
#define INVALID_GRANT_HANDLE (~0U)
/* Register callback to watch this node. */ /* Register callback to watch this node. */
struct xenbus_watch struct xenbus_watch
{ {
...@@ -199,15 +203,19 @@ int xenbus_watch_pathfmt(struct xenbus_device *dev, struct xenbus_watch *watch, ...@@ -199,15 +203,19 @@ int xenbus_watch_pathfmt(struct xenbus_device *dev, struct xenbus_watch *watch,
const char *pathfmt, ...); const char *pathfmt, ...);
int xenbus_switch_state(struct xenbus_device *dev, enum xenbus_state new_state); int xenbus_switch_state(struct xenbus_device *dev, enum xenbus_state new_state);
int xenbus_grant_ring(struct xenbus_device *dev, unsigned long ring_mfn); int xenbus_grant_ring(struct xenbus_device *dev, void *vaddr,
int xenbus_map_ring_valloc(struct xenbus_device *dev, unsigned int nr_pages, grant_ref_t *grefs);
int gnt_ref, void **vaddr); int xenbus_map_ring_valloc(struct xenbus_device *dev, grant_ref_t *gnt_refs,
int xenbus_map_ring(struct xenbus_device *dev, int gnt_ref, unsigned int nr_grefs, void **vaddr);
grant_handle_t *handle, void *vaddr); int xenbus_map_ring(struct xenbus_device *dev,
grant_ref_t *gnt_refs, unsigned int nr_grefs,
grant_handle_t *handles, unsigned long *vaddrs,
bool *leaked);
int xenbus_unmap_ring_vfree(struct xenbus_device *dev, void *vaddr); int xenbus_unmap_ring_vfree(struct xenbus_device *dev, void *vaddr);
int xenbus_unmap_ring(struct xenbus_device *dev, int xenbus_unmap_ring(struct xenbus_device *dev,
grant_handle_t handle, void *vaddr); grant_handle_t *handles, unsigned int nr_handles,
unsigned long *vaddrs);
int xenbus_alloc_evtchn(struct xenbus_device *dev, int *port); int xenbus_alloc_evtchn(struct xenbus_device *dev, int *port);
int xenbus_free_evtchn(struct xenbus_device *dev, int port); int xenbus_free_evtchn(struct xenbus_device *dev, int port);
......
#!/bin/sh
out="$1"
shift
in="$@"
for i in $in; do
eval $CPP $LINUXINCLUDE -dD -imacros "$i" -x c /dev/null
done | \
awk '$1 == "#define" && $2 ~ /__HYPERVISOR_[a-z][a-z_0-9]*/ { v[$3] = $2 }
END { print "/* auto-generated by scripts/xen-hypercall.sh */"
for (i in v) if (!(v[i] in v))
print "HYPERCALL("substr(v[i], 14)")"}' | sort -u >$out
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