]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
Merge remote-tracking branch 'xen-two/linux-next'
authorStephen Rothwell <sfr@canb.auug.org.au>
Wed, 3 Oct 2012 05:39:02 +0000 (15:39 +1000)
committerStephen Rothwell <sfr@canb.auug.org.au>
Wed, 3 Oct 2012 05:41:16 +0000 (15:41 +1000)
Conflicts:
arch/arm/Kconfig
arch/arm/mach-vexpress/Makefile.boot
drivers/xen/Makefile

65 files changed:
Documentation/devicetree/bindings/arm/xen.txt [new file with mode: 0644]
MAINTAINERS
arch/arm/Kconfig
arch/arm/Makefile
arch/arm/boot/dts/Makefile
arch/arm/boot/dts/xenvm-4.2.dts [new file with mode: 0644]
arch/arm/include/asm/hypervisor.h [new file with mode: 0644]
arch/arm/include/asm/sync_bitops.h [new file with mode: 0644]
arch/arm/include/asm/xen/events.h [new file with mode: 0644]
arch/arm/include/asm/xen/hypercall.h [new file with mode: 0644]
arch/arm/include/asm/xen/hypervisor.h [new file with mode: 0644]
arch/arm/include/asm/xen/interface.h [new file with mode: 0644]
arch/arm/include/asm/xen/page.h [new file with mode: 0644]
arch/arm/mach-vexpress/v2m.c
arch/arm/xen/Makefile [new file with mode: 0644]
arch/arm/xen/enlighten.c [new file with mode: 0644]
arch/arm/xen/grant-table.c [new file with mode: 0644]
arch/arm/xen/hypercall.S [new file with mode: 0644]
arch/ia64/include/asm/xen/interface.h
arch/x86/include/asm/xen/interface.h
arch/x86/include/asm/xen/swiotlb-xen.h
arch/x86/xen/apic.c
arch/x86/xen/enlighten.c
arch/x86/xen/irq.c
arch/x86/xen/mmu.c
arch/x86/xen/p2m.c
arch/x86/xen/pci-swiotlb-xen.c
arch/x86/xen/platform-pci-unplug.c
arch/x86/xen/setup.c
arch/x86/xen/vga.c
arch/x86/xen/xen-head.S
arch/x86/xen/xen-ops.h
drivers/block/xen-blkback/blkback.c
drivers/net/xen-netback/netback.c
drivers/net/xen-netfront.c
drivers/pci/xen-pcifront.c
drivers/tty/hvc/hvc_xen.c
drivers/xen/Makefile
drivers/xen/events.c
drivers/xen/gntdev.c
drivers/xen/grant-table.c
drivers/xen/privcmd.c
drivers/xen/swiotlb-xen.c
drivers/xen/sys-hypervisor.c
drivers/xen/tmem.c
drivers/xen/xen-pciback/pci_stub.c
drivers/xen/xenbus/xenbus_comms.c
drivers/xen/xenbus/xenbus_dev_backend.c
drivers/xen/xenbus/xenbus_probe.c
drivers/xen/xenbus/xenbus_probe_frontend.c
drivers/xen/xenbus/xenbus_xs.c
include/linux/swiotlb.h
include/xen/events.h
include/xen/interface/features.h
include/xen/interface/grant_table.h
include/xen/interface/io/protocols.h
include/xen/interface/memory.h
include/xen/interface/physdev.h
include/xen/interface/platform.h
include/xen/interface/version.h
include/xen/interface/xen.h
include/xen/privcmd.h
include/xen/swiotlb-xen.h
include/xen/xen.h
lib/swiotlb.c

diff --git a/Documentation/devicetree/bindings/arm/xen.txt b/Documentation/devicetree/bindings/arm/xen.txt
new file mode 100644 (file)
index 0000000..0f7b9c2
--- /dev/null
@@ -0,0 +1,25 @@
+* Xen hypervisor device tree bindings
+
+Xen ARM virtual platforms shall have a top-level "hypervisor" node with
+the following properties:
+
+- compatible:
+       compatible = "xen,xen-<version>", "xen,xen";
+  where <version> is the version of the Xen ABI of the platform.
+
+- reg: specifies the base physical address and size of a region in
+  memory where the grant table should be mapped to, using an
+  HYPERVISOR_memory_op hypercall. The memory region is large enough to map
+  the whole grant table (it is larger or equal to gnttab_max_grant_frames()).
+
+- interrupts: the interrupt used by Xen to inject event notifications.
+  A GIC node is also required.
+
+
+Example (assuming #address-cells = <2> and #size-cells = <2>):
+
+hypervisor {
+       compatible = "xen,xen-4.3", "xen,xen";
+       reg = <0 0xb0000000 0 0x20000>;
+       interrupts = <1 15 0xf08>;
+};
index 5c268ef36f64d234ab5182cd0fde15c70fe01c2b..892782ea1dd59d9ff9525caa9f0a62367bb6bb67 100644 (file)
@@ -7793,6 +7793,13 @@ F:       drivers/xen/
 F:     arch/x86/include/asm/xen/
 F:     include/xen/
 
+XEN HYPERVISOR ARM
+M:     Stefano Stabellini <stefano.stabellini@eu.citrix.com>
+L:     xen-devel@lists.xensource.com (moderated for non-subscribers)
+S:     Supported
+F:     arch/arm/xen/
+F:     arch/arm/include/asm/xen/
+
 XEN NETWORK BACKEND DRIVER
 M:     Ian Campbell <ian.campbell@citrix.com>
 L:     xen-devel@lists.xensource.com (moderated for non-subscribers)
index d85d2cf9d1518ca1f15df4fb3ff1db83d295d6e7..644a5b8b45a7c2669bf54325241ce79f5f809018 100644 (file)
@@ -1836,6 +1836,16 @@ config CC_STACKPROTECTOR
          neutralized via a kernel panic.
          This feature requires gcc version 4.2 or above.
 
+config XEN_DOM0
+       def_bool y
+       depends on XEN
+
+config XEN
+       bool "Xen guest support on ARM (EXPERIMENTAL)"
+       depends on EXPERIMENTAL && ARM && OF
+       help
+         Say Y if you want to run Linux in a Virtual Machine on Xen on ARM.
+
 endmenu
 
 menu "Boot options"
index 14c8df5cd0d998949048ee63edbbed73a657efef..f023e3acdfbd8c7c17335cfa9518df05119f4ab7 100644 (file)
@@ -250,6 +250,7 @@ endif
 core-$(CONFIG_FPE_NWFPE)       += arch/arm/nwfpe/
 core-$(CONFIG_FPE_FASTFPE)     += $(FASTFPE_OBJ)
 core-$(CONFIG_VFP)             += arch/arm/vfp/
+core-$(CONFIG_XEN)             += arch/arm/xen/
 
 # If we have a machine-specific directory, then include it in the build.
 core-y                         += arch/arm/kernel/ arch/arm/mm/ arch/arm/common/
index 43c084c2cd6682074e45c57090c0d3ee4a2e38d0..4745c1f68b4983468e2e23b724deffe0085afacb 100644 (file)
@@ -96,6 +96,7 @@ dtb-$(CONFIG_ARCH_TEGRA) += tegra20-harmony.dtb \
 dtb-$(CONFIG_ARCH_VEXPRESS) += vexpress-v2p-ca5s.dtb \
        vexpress-v2p-ca9.dtb \
        vexpress-v2p-ca15-tc1.dtb \
-       vexpress-v2p-ca15_a7.dtb
+       vexpress-v2p-ca15_a7.dtb \
+       xenvm-4.2.dtb
 
 endif
diff --git a/arch/arm/boot/dts/xenvm-4.2.dts b/arch/arm/boot/dts/xenvm-4.2.dts
new file mode 100644 (file)
index 0000000..ec3f952
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Xen Virtual Machine for unprivileged guests
+ *
+ * Based on ARM Ltd. Versatile Express CoreTile Express (single CPU)
+ * Cortex-A15 MPCore (V2P-CA15)
+ *
+ */
+
+/dts-v1/;
+
+/ {
+       model = "XENVM-4.2";
+       compatible = "xen,xenvm-4.2", "xen,xenvm";
+       interrupt-parent = <&gic>;
+       #address-cells = <2>;
+       #size-cells = <2>;
+
+       chosen {
+               /* this field is going to be adjusted by the hypervisor */
+               bootargs = "console=hvc0 root=/dev/xvda";
+       };
+
+       cpus {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               cpu@0 {
+                       device_type = "cpu";
+                       compatible = "arm,cortex-a15";
+                       reg = <0>;
+               };
+       };
+
+       memory@80000000 {
+               device_type = "memory";
+               /* this field is going to be adjusted by the hypervisor */
+               reg = <0 0x80000000 0 0x08000000>;
+       };
+
+       gic: interrupt-controller@2c001000 {
+               compatible = "arm,cortex-a15-gic", "arm,cortex-a9-gic";
+               #interrupt-cells = <3>;
+               #address-cells = <0>;
+               interrupt-controller;
+               reg = <0 0x2c001000 0 0x1000>,
+                     <0 0x2c002000 0 0x100>;
+       };
+
+       timer {
+               compatible = "arm,armv7-timer";
+               interrupts = <1 13 0xf08>,
+                            <1 14 0xf08>,
+                            <1 11 0xf08>,
+                            <1 10 0xf08>;
+       };
+
+       hypervisor {
+               compatible = "xen,xen-4.2", "xen,xen";
+               /* this field is going to be adjusted by the hypervisor */
+               reg = <0 0xb0000000 0 0x20000>;
+               /* this field is going to be adjusted by the hypervisor */
+               interrupts = <1 15 0xf08>;
+       };
+
+       motherboard {
+               arm,v2m-memory-map = "rs1";
+       };
+};
diff --git a/arch/arm/include/asm/hypervisor.h b/arch/arm/include/asm/hypervisor.h
new file mode 100644 (file)
index 0000000..b90d9e5
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef _ASM_ARM_HYPERVISOR_H
+#define _ASM_ARM_HYPERVISOR_H
+
+#include <asm/xen/hypervisor.h>
+
+#endif
diff --git a/arch/arm/include/asm/sync_bitops.h b/arch/arm/include/asm/sync_bitops.h
new file mode 100644 (file)
index 0000000..63479ee
--- /dev/null
@@ -0,0 +1,27 @@
+#ifndef __ASM_SYNC_BITOPS_H__
+#define __ASM_SYNC_BITOPS_H__
+
+#include <asm/bitops.h>
+#include <asm/system.h>
+
+/* sync_bitops functions are equivalent to the SMP implementation of the
+ * original functions, independently from CONFIG_SMP being defined.
+ *
+ * We need them because _set_bit etc are not SMP safe if !CONFIG_SMP. But
+ * under Xen you might be communicating with a completely external entity
+ * who might be on another CPU (e.g. two uniprocessor guests communicating
+ * via event channels and grant tables). So we need a variant of the bit
+ * ops which are SMP safe even on a UP kernel.
+ */
+
+#define sync_set_bit(nr, p)            _set_bit(nr, p)
+#define sync_clear_bit(nr, p)          _clear_bit(nr, p)
+#define sync_change_bit(nr, p)         _change_bit(nr, p)
+#define sync_test_and_set_bit(nr, p)   _test_and_set_bit(nr, p)
+#define sync_test_and_clear_bit(nr, p) _test_and_clear_bit(nr, p)
+#define sync_test_and_change_bit(nr, p)        _test_and_change_bit(nr, p)
+#define sync_test_bit(nr, addr)                test_bit(nr, addr)
+#define sync_cmpxchg                   cmpxchg
+
+
+#endif
diff --git a/arch/arm/include/asm/xen/events.h b/arch/arm/include/asm/xen/events.h
new file mode 100644 (file)
index 0000000..94b4e90
--- /dev/null
@@ -0,0 +1,18 @@
+#ifndef _ASM_ARM_XEN_EVENTS_H
+#define _ASM_ARM_XEN_EVENTS_H
+
+#include <asm/ptrace.h>
+
+enum ipi_vector {
+       XEN_PLACEHOLDER_VECTOR,
+
+       /* Xen IPIs go here */
+       XEN_NR_IPIS,
+};
+
+static inline int xen_irqs_disabled(struct pt_regs *regs)
+{
+       return raw_irqs_disabled_flags(regs->ARM_cpsr);
+}
+
+#endif /* _ASM_ARM_XEN_EVENTS_H */
diff --git a/arch/arm/include/asm/xen/hypercall.h b/arch/arm/include/asm/xen/hypercall.h
new file mode 100644 (file)
index 0000000..8a82325
--- /dev/null
@@ -0,0 +1,69 @@
+/******************************************************************************
+ * hypercall.h
+ *
+ * Linux-specific hypervisor handling.
+ *
+ * Stefano Stabellini <stefano.stabellini@eu.citrix.com>, Citrix, 2012
+ *
+ * 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.
+ */
+
+#ifndef _ASM_ARM_XEN_HYPERCALL_H
+#define _ASM_ARM_XEN_HYPERCALL_H
+
+#include <xen/interface/xen.h>
+
+long privcmd_call(unsigned call, unsigned long a1,
+               unsigned long a2, unsigned long a3,
+               unsigned long a4, unsigned long a5);
+int HYPERVISOR_xen_version(int cmd, void *arg);
+int HYPERVISOR_console_io(int cmd, int count, char *str);
+int HYPERVISOR_grant_table_op(unsigned int cmd, void *uop, unsigned int count);
+int HYPERVISOR_sched_op(int cmd, void *arg);
+int HYPERVISOR_event_channel_op(int cmd, void *arg);
+unsigned long HYPERVISOR_hvm_op(int op, void *arg);
+int HYPERVISOR_memory_op(unsigned int cmd, void *arg);
+int HYPERVISOR_physdev_op(int cmd, void *arg);
+
+static inline void
+MULTI_update_va_mapping(struct multicall_entry *mcl, unsigned long va,
+                       unsigned int new_val, unsigned long flags)
+{
+       BUG();
+}
+
+static inline void
+MULTI_mmu_update(struct multicall_entry *mcl, struct mmu_update *req,
+                int count, int *success_count, domid_t domid)
+{
+       BUG();
+}
+
+static inline int
+HYPERVISOR_multicall(void *call_list, int nr_calls)
+{
+       BUG();
+}
+#endif /* _ASM_ARM_XEN_HYPERCALL_H */
diff --git a/arch/arm/include/asm/xen/hypervisor.h b/arch/arm/include/asm/xen/hypervisor.h
new file mode 100644 (file)
index 0000000..d7ab99a
--- /dev/null
@@ -0,0 +1,19 @@
+#ifndef _ASM_ARM_XEN_HYPERVISOR_H
+#define _ASM_ARM_XEN_HYPERVISOR_H
+
+extern struct shared_info *HYPERVISOR_shared_info;
+extern struct start_info *xen_start_info;
+
+/* Lazy mode for batching updates / context switch */
+enum paravirt_lazy_mode {
+       PARAVIRT_LAZY_NONE,
+       PARAVIRT_LAZY_MMU,
+       PARAVIRT_LAZY_CPU,
+};
+
+static inline enum paravirt_lazy_mode paravirt_get_lazy_mode(void)
+{
+       return PARAVIRT_LAZY_NONE;
+}
+
+#endif /* _ASM_ARM_XEN_HYPERVISOR_H */
diff --git a/arch/arm/include/asm/xen/interface.h b/arch/arm/include/asm/xen/interface.h
new file mode 100644 (file)
index 0000000..ae05e56
--- /dev/null
@@ -0,0 +1,73 @@
+/******************************************************************************
+ * Guest OS interface to ARM Xen.
+ *
+ * Stefano Stabellini <stefano.stabellini@eu.citrix.com>, Citrix, 2012
+ */
+
+#ifndef _ASM_ARM_XEN_INTERFACE_H
+#define _ASM_ARM_XEN_INTERFACE_H
+
+#include <linux/types.h>
+
+#define uint64_aligned_t uint64_t __attribute__((aligned(8)))
+
+#define __DEFINE_GUEST_HANDLE(name, type) \
+       typedef struct { union { type *p; uint64_aligned_t q; }; }  \
+        __guest_handle_ ## name
+
+#define DEFINE_GUEST_HANDLE_STRUCT(name) \
+       __DEFINE_GUEST_HANDLE(name, struct name)
+#define DEFINE_GUEST_HANDLE(name) __DEFINE_GUEST_HANDLE(name, name)
+#define GUEST_HANDLE(name)        __guest_handle_ ## name
+
+#define set_xen_guest_handle(hnd, val)                 \
+       do {                                            \
+               if (sizeof(hnd) == 8)                   \
+                       *(uint64_t *)&(hnd) = 0;        \
+               (hnd).p = val;                          \
+       } while (0)
+
+#ifndef __ASSEMBLY__
+/* Explicitly size integers that represent pfns in the interface with
+ * Xen so that we can have one ABI that works for 32 and 64 bit guests. */
+typedef uint64_t xen_pfn_t;
+typedef uint64_t xen_ulong_t;
+/* Guest handles for primitive C types. */
+__DEFINE_GUEST_HANDLE(uchar, unsigned char);
+__DEFINE_GUEST_HANDLE(uint,  unsigned int);
+__DEFINE_GUEST_HANDLE(ulong, unsigned long);
+DEFINE_GUEST_HANDLE(char);
+DEFINE_GUEST_HANDLE(int);
+DEFINE_GUEST_HANDLE(long);
+DEFINE_GUEST_HANDLE(void);
+DEFINE_GUEST_HANDLE(uint64_t);
+DEFINE_GUEST_HANDLE(uint32_t);
+DEFINE_GUEST_HANDLE(xen_pfn_t);
+
+/* Maximum number of virtual CPUs in multi-processor guests. */
+#define MAX_VIRT_CPUS 1
+
+struct arch_vcpu_info { };
+struct arch_shared_info { };
+
+/* TODO: Move pvclock definitions some place arch independent */
+struct pvclock_vcpu_time_info {
+       u32   version;
+       u32   pad0;
+       u64   tsc_timestamp;
+       u64   system_time;
+       u32   tsc_to_system_mul;
+       s8    tsc_shift;
+       u8    flags;
+       u8    pad[2];
+} __attribute__((__packed__)); /* 32 bytes */
+
+/* It is OK to have a 12 bytes struct with no padding because it is packed */
+struct pvclock_wall_clock {
+       u32   version;
+       u32   sec;
+       u32   nsec;
+} __attribute__((__packed__));
+#endif
+
+#endif /* _ASM_ARM_XEN_INTERFACE_H */
diff --git a/arch/arm/include/asm/xen/page.h b/arch/arm/include/asm/xen/page.h
new file mode 100644 (file)
index 0000000..1742023
--- /dev/null
@@ -0,0 +1,82 @@
+#ifndef _ASM_ARM_XEN_PAGE_H
+#define _ASM_ARM_XEN_PAGE_H
+
+#include <asm/page.h>
+#include <asm/pgtable.h>
+
+#include <linux/pfn.h>
+#include <linux/types.h>
+
+#include <xen/interface/grant_table.h>
+
+#define pfn_to_mfn(pfn)                        (pfn)
+#define phys_to_machine_mapping_valid  (1)
+#define mfn_to_pfn(mfn)                        (mfn)
+#define mfn_to_virt(m)                 (__va(mfn_to_pfn(m) << PAGE_SHIFT))
+
+#define pte_mfn            pte_pfn
+#define mfn_pte            pfn_pte
+
+/* Xen machine address */
+typedef struct xmaddr {
+       phys_addr_t maddr;
+} xmaddr_t;
+
+/* Xen pseudo-physical address */
+typedef struct xpaddr {
+       phys_addr_t paddr;
+} xpaddr_t;
+
+#define XMADDR(x)      ((xmaddr_t) { .maddr = (x) })
+#define XPADDR(x)      ((xpaddr_t) { .paddr = (x) })
+
+static inline xmaddr_t phys_to_machine(xpaddr_t phys)
+{
+       unsigned offset = phys.paddr & ~PAGE_MASK;
+       return XMADDR(PFN_PHYS(pfn_to_mfn(PFN_DOWN(phys.paddr))) | offset);
+}
+
+static inline xpaddr_t machine_to_phys(xmaddr_t machine)
+{
+       unsigned offset = machine.maddr & ~PAGE_MASK;
+       return XPADDR(PFN_PHYS(mfn_to_pfn(PFN_DOWN(machine.maddr))) | offset);
+}
+/* VIRT <-> MACHINE conversion */
+#define virt_to_machine(v)     (phys_to_machine(XPADDR(__pa(v))))
+#define virt_to_pfn(v)          (PFN_DOWN(__pa(v)))
+#define virt_to_mfn(v)         (pfn_to_mfn(virt_to_pfn(v)))
+#define mfn_to_virt(m)         (__va(mfn_to_pfn(m) << PAGE_SHIFT))
+
+static inline xmaddr_t arbitrary_virt_to_machine(void *vaddr)
+{
+       /* TODO: assuming it is mapped in the kernel 1:1 */
+       return virt_to_machine(vaddr);
+}
+
+/* TODO: this shouldn't be here but it is because the frontend drivers
+ * are using it (its rolled in headers) even though we won't hit the code path.
+ * So for right now just punt with this.
+ */
+static inline pte_t *lookup_address(unsigned long address, unsigned int *level)
+{
+       BUG();
+       return NULL;
+}
+
+static inline int m2p_add_override(unsigned long mfn, struct page *page,
+               struct gnttab_map_grant_ref *kmap_op)
+{
+       return 0;
+}
+
+static inline int m2p_remove_override(struct page *page, bool clear_pte)
+{
+       return 0;
+}
+
+static inline bool set_phys_to_machine(unsigned long pfn, unsigned long mfn)
+{
+       BUG();
+       return false;
+}
+#endif /* _ASM_ARM_XEN_PAGE_H */
index 5f6b7d543e55ffb5f519043a85466683b9557dd1..560e0df728f89931826f080cfe87dda6abcec128 100644 (file)
@@ -659,6 +659,7 @@ static void __init v2m_dt_init(void)
 
 const static char *v2m_dt_match[] __initconst = {
        "arm,vexpress",
+       "xen,xenvm",
        NULL,
 };
 
diff --git a/arch/arm/xen/Makefile b/arch/arm/xen/Makefile
new file mode 100644 (file)
index 0000000..4384103
--- /dev/null
@@ -0,0 +1 @@
+obj-y          := enlighten.o hypercall.o grant-table.o
diff --git a/arch/arm/xen/enlighten.c b/arch/arm/xen/enlighten.c
new file mode 100644 (file)
index 0000000..59bcb96
--- /dev/null
@@ -0,0 +1,168 @@
+#include <xen/xen.h>
+#include <xen/events.h>
+#include <xen/grant_table.h>
+#include <xen/hvm.h>
+#include <xen/interface/xen.h>
+#include <xen/interface/memory.h>
+#include <xen/interface/hvm/params.h>
+#include <xen/features.h>
+#include <xen/platform_pci.h>
+#include <xen/xenbus.h>
+#include <asm/xen/hypervisor.h>
+#include <asm/xen/hypercall.h>
+#include <linux/interrupt.h>
+#include <linux/irqreturn.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/of_address.h>
+
+struct start_info _xen_start_info;
+struct start_info *xen_start_info = &_xen_start_info;
+EXPORT_SYMBOL_GPL(xen_start_info);
+
+enum xen_domain_type xen_domain_type = XEN_NATIVE;
+EXPORT_SYMBOL_GPL(xen_domain_type);
+
+struct shared_info xen_dummy_shared_info;
+struct shared_info *HYPERVISOR_shared_info = (void *)&xen_dummy_shared_info;
+
+DEFINE_PER_CPU(struct vcpu_info *, xen_vcpu);
+
+/* TODO: to be removed */
+__read_mostly int xen_have_vector_callback;
+EXPORT_SYMBOL_GPL(xen_have_vector_callback);
+
+int xen_platform_pci_unplug = XEN_UNPLUG_ALL;
+EXPORT_SYMBOL_GPL(xen_platform_pci_unplug);
+
+static __read_mostly int xen_events_irq = -1;
+
+int xen_remap_domain_mfn_range(struct vm_area_struct *vma,
+                              unsigned long addr,
+                              unsigned long mfn, int nr,
+                              pgprot_t prot, unsigned domid)
+{
+       return -ENOSYS;
+}
+EXPORT_SYMBOL_GPL(xen_remap_domain_mfn_range);
+
+/*
+ * see Documentation/devicetree/bindings/arm/xen.txt for the
+ * documentation of the Xen Device Tree format.
+ */
+#define GRANT_TABLE_PHYSADDR 0
+static int __init xen_guest_init(void)
+{
+       struct xen_add_to_physmap xatp;
+       static struct shared_info *shared_info_page = 0;
+       struct device_node *node;
+       int len;
+       const char *s = NULL;
+       const char *version = NULL;
+       const char *xen_prefix = "xen,xen-";
+       struct resource res;
+
+       node = of_find_compatible_node(NULL, NULL, "xen,xen");
+       if (!node) {
+               pr_debug("No Xen support\n");
+               return 0;
+       }
+       s = of_get_property(node, "compatible", &len);
+       if (strlen(xen_prefix) + 3  < len &&
+                       !strncmp(xen_prefix, s, strlen(xen_prefix)))
+               version = s + strlen(xen_prefix);
+       if (version == NULL) {
+               pr_debug("Xen version not found\n");
+               return 0;
+       }
+       if (of_address_to_resource(node, GRANT_TABLE_PHYSADDR, &res))
+               return 0;
+       xen_hvm_resume_frames = res.start >> PAGE_SHIFT;
+       xen_events_irq = irq_of_parse_and_map(node, 0);
+       pr_info("Xen %s support found, events_irq=%d gnttab_frame_pfn=%lx\n",
+                       version, xen_events_irq, xen_hvm_resume_frames);
+       xen_domain_type = XEN_HVM_DOMAIN;
+
+       xen_setup_features();
+       if (xen_feature(XENFEAT_dom0))
+               xen_start_info->flags |= SIF_INITDOMAIN|SIF_PRIVILEGED;
+       else
+               xen_start_info->flags &= ~(SIF_INITDOMAIN|SIF_PRIVILEGED);
+
+       if (!shared_info_page)
+               shared_info_page = (struct shared_info *)
+                       get_zeroed_page(GFP_KERNEL);
+       if (!shared_info_page) {
+               pr_err("not enough memory\n");
+               return -ENOMEM;
+       }
+       xatp.domid = DOMID_SELF;
+       xatp.idx = 0;
+       xatp.space = XENMAPSPACE_shared_info;
+       xatp.gpfn = __pa(shared_info_page) >> PAGE_SHIFT;
+       if (HYPERVISOR_memory_op(XENMEM_add_to_physmap, &xatp))
+               BUG();
+
+       HYPERVISOR_shared_info = (struct shared_info *)shared_info_page;
+
+       /* xen_vcpu is a pointer to the vcpu_info struct in the shared_info
+        * page, we use it in the event channel upcall and in some pvclock
+        * related functions. We don't need the vcpu_info placement
+        * optimizations because we don't use any pv_mmu or pv_irq op on
+        * HVM.
+        * The shared info contains exactly 1 CPU (the boot CPU). The guest
+        * is required to use VCPUOP_register_vcpu_info to place vcpu info
+        * for secondary CPUs as they are brought up. */
+       per_cpu(xen_vcpu, 0) = &HYPERVISOR_shared_info->vcpu_info[0];
+
+       gnttab_init();
+       if (!xen_initial_domain())
+               xenbus_probe(NULL);
+
+       return 0;
+}
+core_initcall(xen_guest_init);
+
+static irqreturn_t xen_arm_callback(int irq, void *arg)
+{
+       xen_hvm_evtchn_do_upcall();
+       return IRQ_HANDLED;
+}
+
+static int __init xen_init_events(void)
+{
+       if (!xen_domain() || xen_events_irq < 0)
+               return -ENODEV;
+
+       xen_init_IRQ();
+
+       if (request_percpu_irq(xen_events_irq, xen_arm_callback,
+                       "events", xen_vcpu)) {
+               pr_err("Error requesting IRQ %d\n", xen_events_irq);
+               return -EINVAL;
+       }
+
+       enable_percpu_irq(xen_events_irq, 0);
+
+       return 0;
+}
+postcore_initcall(xen_init_events);
+
+/* XXX: only until balloon is properly working */
+int alloc_xenballooned_pages(int nr_pages, struct page **pages, bool highmem)
+{
+       *pages = alloc_pages(highmem ? GFP_HIGHUSER : GFP_KERNEL,
+                       get_order(nr_pages));
+       if (*pages == NULL)
+               return -ENOMEM;
+       return 0;
+}
+EXPORT_SYMBOL_GPL(alloc_xenballooned_pages);
+
+void free_xenballooned_pages(int nr_pages, struct page **pages)
+{
+       kfree(*pages);
+       *pages = NULL;
+}
+EXPORT_SYMBOL_GPL(free_xenballooned_pages);
diff --git a/arch/arm/xen/grant-table.c b/arch/arm/xen/grant-table.c
new file mode 100644 (file)
index 0000000..dbd1330
--- /dev/null
@@ -0,0 +1,53 @@
+/******************************************************************************
+ * grant_table.c
+ * ARM specific part
+ *
+ * Granting foreign access to our memory reservation.
+ *
+ * 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 <xen/interface/xen.h>
+#include <xen/page.h>
+#include <xen/grant_table.h>
+
+int arch_gnttab_map_shared(unsigned long *frames, unsigned long nr_gframes,
+                          unsigned long max_nr_gframes,
+                          void **__shared)
+{
+       return -ENOSYS;
+}
+
+void arch_gnttab_unmap(void *shared, unsigned long nr_gframes)
+{
+       return;
+}
+
+int arch_gnttab_map_status(uint64_t *frames, unsigned long nr_gframes,
+                          unsigned long max_nr_gframes,
+                          grant_status_t **__shared)
+{
+       return -ENOSYS;
+}
diff --git a/arch/arm/xen/hypercall.S b/arch/arm/xen/hypercall.S
new file mode 100644 (file)
index 0000000..074f5ed
--- /dev/null
@@ -0,0 +1,106 @@
+/******************************************************************************
+ * hypercall.S
+ *
+ * Xen hypercall wrappers
+ *
+ * Stefano Stabellini <stefano.stabellini@eu.citrix.com>, Citrix, 2012
+ *
+ * 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.
+ */
+
+/*
+ * The Xen hypercall calling convention is very similar to the ARM
+ * procedure calling convention: the first paramter is passed in r0, the
+ * second in r1, the third in r2 and the fourth in r3. Considering that
+ * Xen hypercalls have 5 arguments at most, the fifth paramter is passed
+ * in r4, differently from the procedure calling convention of using the
+ * stack for that case.
+ *
+ * The hypercall number is passed in r12.
+ *
+ * The return value is in r0.
+ *
+ * The hvc ISS is required to be 0xEA1, that is the Xen specific ARM
+ * hypercall tag.
+ */
+
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+#include <xen/interface/xen.h>
+
+
+/* HVC 0xEA1 */
+#ifdef CONFIG_THUMB2_KERNEL
+#define xen_hvc .word 0xf7e08ea1
+#else
+#define xen_hvc .word 0xe140ea71
+#endif
+
+#define HYPERCALL_SIMPLE(hypercall)            \
+ENTRY(HYPERVISOR_##hypercall)                  \
+       mov r12, #__HYPERVISOR_##hypercall;     \
+       xen_hvc;                                                        \
+       mov pc, lr;                                                     \
+ENDPROC(HYPERVISOR_##hypercall)
+
+#define HYPERCALL0 HYPERCALL_SIMPLE
+#define HYPERCALL1 HYPERCALL_SIMPLE
+#define HYPERCALL2 HYPERCALL_SIMPLE
+#define HYPERCALL3 HYPERCALL_SIMPLE
+#define HYPERCALL4 HYPERCALL_SIMPLE
+
+#define HYPERCALL5(hypercall)                  \
+ENTRY(HYPERVISOR_##hypercall)                  \
+       stmdb sp!, {r4}                                         \
+       ldr r4, [sp, #4]                                        \
+       mov r12, #__HYPERVISOR_##hypercall;     \
+       xen_hvc                                                         \
+       ldm sp!, {r4}                                           \
+       mov pc, lr                                                      \
+ENDPROC(HYPERVISOR_##hypercall)
+
+                .text
+
+HYPERCALL2(xen_version);
+HYPERCALL3(console_io);
+HYPERCALL3(grant_table_op);
+HYPERCALL2(sched_op);
+HYPERCALL2(event_channel_op);
+HYPERCALL2(hvm_op);
+HYPERCALL2(memory_op);
+HYPERCALL2(physdev_op);
+
+ENTRY(privcmd_call)
+       stmdb sp!, {r4}
+       mov r12, r0
+       mov r0, r1
+       mov r1, r2
+       mov r2, r3
+       ldr r3, [sp, #8]
+       ldr r4, [sp, #4]
+       xen_hvc
+       ldm sp!, {r4}
+       mov pc, lr
+ENDPROC(privcmd_call);
index 09d5f7fd9db164f28f0bd85ba7348af4834a2c00..e88c5de27410bde450885459467ef50db4c0d21c 100644 (file)
 #define set_xen_guest_handle(hnd, val) do { (hnd).p = val; } while (0)
 
 #ifndef __ASSEMBLY__
+/* Explicitly size integers that represent pfns in the public interface
+ * with Xen so that we could have one ABI that works for 32 and 64 bit
+ * guests. */
+typedef unsigned long xen_pfn_t;
+typedef unsigned long xen_ulong_t;
 /* Guest handles for primitive C types. */
 __DEFINE_GUEST_HANDLE(uchar, unsigned char);
 __DEFINE_GUEST_HANDLE(uint, unsigned int);
@@ -79,7 +84,6 @@ DEFINE_GUEST_HANDLE(void);
 DEFINE_GUEST_HANDLE(uint64_t);
 DEFINE_GUEST_HANDLE(uint32_t);
 
-typedef unsigned long xen_pfn_t;
 DEFINE_GUEST_HANDLE(xen_pfn_t);
 #define PRI_xen_pfn    "lx"
 #endif
@@ -265,6 +269,8 @@ typedef struct xen_callback xen_callback_t;
 
 #endif /* !__ASSEMBLY__ */
 
+#include <asm/pvclock-abi.h>
+
 /* Size of the shared_info area (this is not related to page size).  */
 #define XSI_SHIFT                      14
 #define XSI_SIZE                       (1 << XSI_SHIFT)
index cbf0c9d50b92840565d7aaa719612ee12c6d8667..28fc6211a79a158046f33c8e28652e2719963670 100644 (file)
 #endif
 
 #ifndef __ASSEMBLY__
+/* Explicitly size integers that represent pfns in the public interface
+ * with Xen so that on ARM we can have one ABI that works for 32 and 64
+ * bit guests. */
+typedef unsigned long xen_pfn_t;
+typedef unsigned long xen_ulong_t;
 /* Guest handles for primitive C types. */
 __DEFINE_GUEST_HANDLE(uchar, unsigned char);
 __DEFINE_GUEST_HANDLE(uint,  unsigned int);
@@ -57,6 +62,7 @@ DEFINE_GUEST_HANDLE(long);
 DEFINE_GUEST_HANDLE(void);
 DEFINE_GUEST_HANDLE(uint64_t);
 DEFINE_GUEST_HANDLE(uint32_t);
+DEFINE_GUEST_HANDLE(xen_pfn_t);
 #endif
 
 #ifndef HYPERVISOR_VIRT_START
@@ -121,6 +127,8 @@ struct arch_shared_info {
 #include "interface_64.h"
 #endif
 
+#include <asm/pvclock-abi.h>
+
 #ifndef __ASSEMBLY__
 /*
  * The following is all CPU context. Note that the fpu_ctxt block is filled
index 1be1ab7d6a4120d945aa22abf98a523f617196d8..ee52fcac6f72211ec3ac06e0e295193bc0e44817 100644 (file)
@@ -5,10 +5,12 @@
 extern int xen_swiotlb;
 extern int __init pci_xen_swiotlb_detect(void);
 extern void __init pci_xen_swiotlb_init(void);
+extern int pci_xen_swiotlb_init_late(void);
 #else
 #define xen_swiotlb (0)
 static inline int __init pci_xen_swiotlb_detect(void) { return 0; }
 static inline void __init pci_xen_swiotlb_init(void) { }
+static inline int pci_xen_swiotlb_init_late(void) { return -ENXIO; }
 #endif
 
 #endif /* _ASM_X86_SWIOTLB_XEN_H */
index ec57bd3818a4cdeb0c45d3c3b13cc7a79db85f9b..7005ced5d1ad7ab93a3862f269855da4cf9a9171 100644 (file)
@@ -6,8 +6,9 @@
 
 #include <xen/xen.h>
 #include <xen/interface/physdev.h>
+#include "xen-ops.h"
 
-unsigned int xen_io_apic_read(unsigned apic, unsigned reg)
+static unsigned int xen_io_apic_read(unsigned apic, unsigned reg)
 {
        struct physdev_apic apic_op;
        int ret;
index 1fbe75a95f15953d3d0ed6cd0dd7c911a88eac0b..bf788d34530df5fbb93e60bb64023d80f7bbedf3 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/memblock.h>
 
 #include <xen/xen.h>
+#include <xen/events.h>
 #include <xen/interface/xen.h>
 #include <xen/interface/version.h>
 #include <xen/interface/physdev.h>
@@ -80,6 +81,8 @@
 #include "smp.h"
 #include "multicalls.h"
 
+#include <xen/events.h>
+
 EXPORT_SYMBOL_GPL(hypercall_page);
 
 DEFINE_PER_CPU(struct vcpu_info *, xen_vcpu);
@@ -1288,7 +1291,6 @@ asmlinkage void __init xen_start_kernel(void)
 {
        struct physdev_set_iopl set_iopl;
        int rc;
-       pgd_t *pgd;
 
        if (!xen_start_info)
                return;
@@ -1380,8 +1382,6 @@ asmlinkage void __init xen_start_kernel(void)
        acpi_numa = -1;
 #endif
 
-       pgd = (pgd_t *)xen_start_info->pt_base;
-
        /* Don't do the full vcpu_info placement stuff until we have a
           possible map and a non-dummy shared_info. */
        per_cpu(xen_vcpu, 0) = &HYPERVISOR_shared_info->vcpu_info[0];
@@ -1390,7 +1390,7 @@ asmlinkage void __init xen_start_kernel(void)
        early_boot_irqs_disabled = true;
 
        xen_raw_console_write("mapping kernel into physical memory\n");
-       pgd = xen_setup_kernel_pagetable(pgd, xen_start_info->nr_pages);
+       xen_setup_kernel_pagetable((pgd_t *)xen_start_info->pt_base, xen_start_info->nr_pages);
 
        /* Allocate and initialize top and mid mfn levels for p2m structure */
        xen_build_mfn_list_list();
@@ -1441,11 +1441,19 @@ asmlinkage void __init xen_start_kernel(void)
                const struct dom0_vga_console_info *info =
                        (void *)((char *)xen_start_info +
                                 xen_start_info->console.dom0.info_off);
+               struct xen_platform_op op = {
+                       .cmd = XENPF_firmware_info,
+                       .interface_version = XENPF_INTERFACE_VERSION,
+                       .u.firmware_info.type = XEN_FW_KBD_SHIFT_FLAGS,
+               };
 
                xen_init_vga(info, xen_start_info->console.dom0.info_size);
                xen_start_info->console.domU.mfn = 0;
                xen_start_info->console.domU.evtchn = 0;
 
+               if (HYPERVISOR_dom0_op(&op) == 0)
+                       boot_params.kbd_status = op.u.firmware_info.u.kbd_shift_flags;
+
                xen_init_apic();
 
                /* Make sure ACS will be enabled */
index 1573376579714ec3b9a195a898090dba7ac20087..01a4dc015ae1e37206469df5ea45b3437da19cad 100644 (file)
@@ -5,6 +5,7 @@
 #include <xen/interface/xen.h>
 #include <xen/interface/sched.h>
 #include <xen/interface/vcpu.h>
+#include <xen/events.h>
 
 #include <asm/xen/hypercall.h>
 #include <asm/xen/hypervisor.h>
index 7a769b7526cb2d5209380d65836ba5b2449aecb2..5a16824cc2b3ca88919e484d79473af3f2e951a4 100644 (file)
@@ -84,6 +84,7 @@
  */
 DEFINE_SPINLOCK(xen_reservation_lock);
 
+#ifdef CONFIG_X86_32
 /*
  * Identity map, in addition to plain kernel map.  This needs to be
  * large enough to allocate page table pages to allocate the rest.
@@ -91,7 +92,7 @@ DEFINE_SPINLOCK(xen_reservation_lock);
  */
 #define LEVEL1_IDENT_ENTRIES   (PTRS_PER_PTE * 4)
 static RESERVE_BRK_ARRAY(pte_t, level1_ident_pgt, LEVEL1_IDENT_ENTRIES);
-
+#endif
 #ifdef CONFIG_X86_64
 /* l3 pud for userspace vsyscall mapping */
 static pud_t level3_user_vsyscall[PTRS_PER_PUD] __page_aligned_bss;
@@ -1176,13 +1177,6 @@ static void xen_exit_mmap(struct mm_struct *mm)
 
 static void xen_post_allocator_init(void);
 
-static void __init xen_pagetable_init(void)
-{
-       paging_init();
-       xen_setup_shared_info();
-       xen_post_allocator_init();
-}
-
 static __init void xen_mapping_pagetable_reserve(u64 start, u64 end)
 {
        /* reserve the range used */
@@ -1197,6 +1191,87 @@ static __init void xen_mapping_pagetable_reserve(u64 start, u64 end)
        }
 }
 
+#ifdef CONFIG_X86_64
+static void __init xen_cleanhighmap(unsigned long vaddr,
+                                   unsigned long vaddr_end)
+{
+       unsigned long kernel_end = roundup((unsigned long)_brk_end, PMD_SIZE) - 1;
+       pmd_t *pmd = level2_kernel_pgt + pmd_index(vaddr);
+
+       /* NOTE: The loop is more greedy than the cleanup_highmap variant.
+        * We include the PMD passed in on _both_ boundaries. */
+       for (; vaddr <= vaddr_end && (pmd < (level2_kernel_pgt + PAGE_SIZE));
+                       pmd++, vaddr += PMD_SIZE) {
+               if (pmd_none(*pmd))
+                       continue;
+               if (vaddr < (unsigned long) _text || vaddr > kernel_end)
+                       set_pmd(pmd, __pmd(0));
+       }
+       /* In case we did something silly, we should crash in this function
+        * instead of somewhere later and be confusing. */
+       xen_mc_flush();
+}
+#endif
+static void __init xen_pagetable_init(void)
+{
+#ifdef CONFIG_X86_64
+       unsigned long size;
+       unsigned long addr;
+#endif
+       paging_init();
+       xen_setup_shared_info();
+#ifdef CONFIG_X86_64
+       if (!xen_feature(XENFEAT_auto_translated_physmap)) {
+               unsigned long new_mfn_list;
+
+               size = PAGE_ALIGN(xen_start_info->nr_pages * sizeof(unsigned long));
+
+               /* On 32-bit, we get zero so this never gets executed. */
+               new_mfn_list = xen_revector_p2m_tree();
+               if (new_mfn_list && new_mfn_list != xen_start_info->mfn_list) {
+                       /* using __ka address and sticking INVALID_P2M_ENTRY! */
+                       memset((void *)xen_start_info->mfn_list, 0xff, size);
+
+                       /* We should be in __ka space. */
+                       BUG_ON(xen_start_info->mfn_list < __START_KERNEL_map);
+                       addr = xen_start_info->mfn_list;
+                       /* We roundup to the PMD, which means that if anybody at this stage is
+                        * using the __ka address of xen_start_info or xen_start_info->shared_info
+                        * they are in going to crash. Fortunatly we have already revectored
+                        * in xen_setup_kernel_pagetable and in xen_setup_shared_info. */
+                       size = roundup(size, PMD_SIZE);
+                       xen_cleanhighmap(addr, addr + size);
+
+                       size = PAGE_ALIGN(xen_start_info->nr_pages * sizeof(unsigned long));
+                       memblock_free(__pa(xen_start_info->mfn_list), size);
+                       /* And revector! Bye bye old array */
+                       xen_start_info->mfn_list = new_mfn_list;
+               } else
+                       goto skip;
+       }
+       /* At this stage, cleanup_highmap has already cleaned __ka space
+        * from _brk_limit way up to the max_pfn_mapped (which is the end of
+        * the ramdisk). We continue on, erasing PMD entries that point to page
+        * tables - do note that they are accessible at this stage via __va.
+        * For good measure we also round up to the PMD - which means that if
+        * anybody is using __ka address to the initial boot-stack - and try
+        * to use it - they are going to crash. The xen_start_info has been
+        * taken care of already in xen_setup_kernel_pagetable. */
+       addr = xen_start_info->pt_base;
+       size = roundup(xen_start_info->nr_pt_frames * PAGE_SIZE, PMD_SIZE);
+
+       xen_cleanhighmap(addr, addr + size);
+       xen_start_info->pt_base = (unsigned long)__va(__pa(xen_start_info->pt_base));
+#ifdef DEBUG
+       /* This is superflous and is not neccessary, but you know what
+        * lets do it. The MODULES_VADDR -> MODULES_END should be clear of
+        * anything at this stage. */
+       xen_cleanhighmap(MODULES_VADDR, roundup(MODULES_VADDR, PUD_SIZE) - 1);
+#endif
+skip:
+#endif
+       xen_post_allocator_init();
+}
 static void xen_write_cr2(unsigned long cr2)
 {
        this_cpu_read(xen_vcpu)->arch.cr2 = cr2;
@@ -1652,7 +1727,7 @@ static void set_page_prot(void *addr, pgprot_t prot)
        if (HYPERVISOR_update_va_mapping((unsigned long)addr, pte, 0))
                BUG();
 }
-
+#ifdef CONFIG_X86_32
 static void __init xen_map_identity_early(pmd_t *pmd, unsigned long max_pfn)
 {
        unsigned pmdidx, pteidx;
@@ -1703,7 +1778,7 @@ static void __init xen_map_identity_early(pmd_t *pmd, unsigned long max_pfn)
 
        set_page_prot(pmd, PAGE_KERNEL_RO);
 }
-
+#endif
 void __init xen_setup_machphys_mapping(void)
 {
        struct xen_machphys_mapping mapping;
@@ -1731,7 +1806,20 @@ static void convert_pfn_mfn(void *v)
        for (i = 0; i < PTRS_PER_PTE; i++)
                pte[i] = xen_make_pte(pte[i].pte);
 }
-
+static void __init check_pt_base(unsigned long *pt_base, unsigned long *pt_end,
+                                unsigned long addr)
+{
+       if (*pt_base == PFN_DOWN(__pa(addr))) {
+               set_page_prot((void *)addr, PAGE_KERNEL);
+               clear_page((void *)addr);
+               (*pt_base)++;
+       }
+       if (*pt_end == PFN_DOWN(__pa(addr))) {
+               set_page_prot((void *)addr, PAGE_KERNEL);
+               clear_page((void *)addr);
+               (*pt_end)--;
+       }
+}
 /*
  * Set up the initial kernel pagetable.
  *
@@ -1743,11 +1831,13 @@ static void convert_pfn_mfn(void *v)
  * of the physical mapping once some sort of allocator has been set
  * up.
  */
-pgd_t * __init xen_setup_kernel_pagetable(pgd_t *pgd,
-                                        unsigned long max_pfn)
+void __init xen_setup_kernel_pagetable(pgd_t *pgd, unsigned long max_pfn)
 {
        pud_t *l3;
        pmd_t *l2;
+       unsigned long addr[3];
+       unsigned long pt_base, pt_end;
+       unsigned i;
 
        /* max_pfn_mapped is the last pfn mapped in the initial memory
         * mappings. Considering that on Xen after the kernel mappings we
@@ -1755,32 +1845,53 @@ pgd_t * __init xen_setup_kernel_pagetable(pgd_t *pgd,
         * set max_pfn_mapped to the last real pfn mapped. */
        max_pfn_mapped = PFN_DOWN(__pa(xen_start_info->mfn_list));
 
+       pt_base = PFN_DOWN(__pa(xen_start_info->pt_base));
+       pt_end = pt_base + xen_start_info->nr_pt_frames;
+
        /* Zap identity mapping */
        init_level4_pgt[0] = __pgd(0);
 
        /* Pre-constructed entries are in pfn, so convert to mfn */
+       /* L4[272] -> level3_ident_pgt
+        * L4[511] -> level3_kernel_pgt */
        convert_pfn_mfn(init_level4_pgt);
+
+       /* L3_i[0] -> level2_ident_pgt */
        convert_pfn_mfn(level3_ident_pgt);
+       /* L3_k[510] -> level2_kernel_pgt
+        * L3_i[511] -> level2_fixmap_pgt */
        convert_pfn_mfn(level3_kernel_pgt);
 
+       /* We get [511][511] and have Xen's version of level2_kernel_pgt */
        l3 = m2v(pgd[pgd_index(__START_KERNEL_map)].pgd);
        l2 = m2v(l3[pud_index(__START_KERNEL_map)].pud);
 
-       memcpy(level2_ident_pgt, l2, sizeof(pmd_t) * PTRS_PER_PMD);
-       memcpy(level2_kernel_pgt, l2, sizeof(pmd_t) * PTRS_PER_PMD);
-
+       addr[0] = (unsigned long)pgd;
+       addr[1] = (unsigned long)l3;
+       addr[2] = (unsigned long)l2;
+       /* Graft it onto L4[272][0]. Note that we creating an aliasing problem:
+        * Both L4[272][0] and L4[511][511] have entries that point to the same
+        * L2 (PMD) tables. Meaning that if you modify it in __va space
+        * it will be also modified in the __ka space! (But if you just
+        * modify the PMD table to point to other PTE's or none, then you
+        * are OK - which is what cleanup_highmap does) */
+       copy_page(level2_ident_pgt, l2);
+       /* Graft it onto L4[511][511] */
+       copy_page(level2_kernel_pgt, l2);
+
+       /* Get [511][510] and graft that in level2_fixmap_pgt */
        l3 = m2v(pgd[pgd_index(__START_KERNEL_map + PMD_SIZE)].pgd);
        l2 = m2v(l3[pud_index(__START_KERNEL_map + PMD_SIZE)].pud);
-       memcpy(level2_fixmap_pgt, l2, sizeof(pmd_t) * PTRS_PER_PMD);
-
-       /* Set up identity map */
-       xen_map_identity_early(level2_ident_pgt, max_pfn);
+       copy_page(level2_fixmap_pgt, l2);
+       /* Note that we don't do anything with level1_fixmap_pgt which
+        * we don't need. */
 
        /* Make pagetable pieces RO */
        set_page_prot(init_level4_pgt, PAGE_KERNEL_RO);
        set_page_prot(level3_ident_pgt, PAGE_KERNEL_RO);
        set_page_prot(level3_kernel_pgt, PAGE_KERNEL_RO);
        set_page_prot(level3_user_vsyscall, PAGE_KERNEL_RO);
+       set_page_prot(level2_ident_pgt, PAGE_KERNEL_RO);
        set_page_prot(level2_kernel_pgt, PAGE_KERNEL_RO);
        set_page_prot(level2_fixmap_pgt, PAGE_KERNEL_RO);
 
@@ -1791,22 +1902,28 @@ pgd_t * __init xen_setup_kernel_pagetable(pgd_t *pgd,
        /* Unpin Xen-provided one */
        pin_pagetable_pfn(MMUEXT_UNPIN_TABLE, PFN_DOWN(__pa(pgd)));
 
-       /* Switch over */
-       pgd = init_level4_pgt;
-
        /*
         * At this stage there can be no user pgd, and no page
         * structure to attach it to, so make sure we just set kernel
         * pgd.
         */
        xen_mc_batch();
-       __xen_write_cr3(true, __pa(pgd));
+       __xen_write_cr3(true, __pa(init_level4_pgt));
        xen_mc_issue(PARAVIRT_LAZY_CPU);
 
-       memblock_reserve(__pa(xen_start_info->pt_base),
-                        xen_start_info->nr_pt_frames * PAGE_SIZE);
+       /* We can't that easily rip out L3 and L2, as the Xen pagetables are
+        * set out this way: [L4], [L1], [L2], [L3], [L1], [L1] ...  for
+        * the initial domain. For guests using the toolstack, they are in:
+        * [L4], [L3], [L2], [L1], [L1], order .. So for dom0 we can only
+        * rip out the [L4] (pgd), but for guests we shave off three pages.
+        */
+       for (i = 0; i < ARRAY_SIZE(addr); i++)
+               check_pt_base(&pt_base, &pt_end, addr[i]);
 
-       return pgd;
+       /* Our (by three pages) smaller Xen pagetable that we are using */
+       memblock_reserve(PFN_PHYS(pt_base), (pt_end - pt_base) * PAGE_SIZE);
+       /* Revector the xen_start_info */
+       xen_start_info = (struct start_info *)__va(__pa(xen_start_info));
 }
 #else  /* !CONFIG_X86_64 */
 static RESERVE_BRK_ARRAY(pmd_t, initial_kernel_pmd, PTRS_PER_PMD);
@@ -1831,8 +1948,7 @@ static void __init xen_write_cr3_init(unsigned long cr3)
         */
        swapper_kernel_pmd =
                extend_brk(sizeof(pmd_t) * PTRS_PER_PMD, PAGE_SIZE);
-       memcpy(swapper_kernel_pmd, initial_kernel_pmd,
-              sizeof(pmd_t) * PTRS_PER_PMD);
+       copy_page(swapper_kernel_pmd, initial_kernel_pmd);
        swapper_pg_dir[KERNEL_PGD_BOUNDARY] =
                __pgd(__pa(swapper_kernel_pmd) | _PAGE_PRESENT);
        set_page_prot(swapper_kernel_pmd, PAGE_KERNEL_RO);
@@ -1849,8 +1965,7 @@ static void __init xen_write_cr3_init(unsigned long cr3)
        pv_mmu_ops.write_cr3 = &xen_write_cr3;
 }
 
-pgd_t * __init xen_setup_kernel_pagetable(pgd_t *pgd,
-                                        unsigned long max_pfn)
+void __init xen_setup_kernel_pagetable(pgd_t *pgd, unsigned long max_pfn)
 {
        pmd_t *kernel_pmd;
 
@@ -1862,11 +1977,11 @@ pgd_t * __init xen_setup_kernel_pagetable(pgd_t *pgd,
                                  512*1024);
 
        kernel_pmd = m2v(pgd[KERNEL_PGD_BOUNDARY].pgd);
-       memcpy(initial_kernel_pmd, kernel_pmd, sizeof(pmd_t) * PTRS_PER_PMD);
+       copy_page(initial_kernel_pmd, kernel_pmd);
 
        xen_map_identity_early(initial_kernel_pmd, max_pfn);
 
-       memcpy(initial_page_table, pgd, sizeof(pgd_t) * PTRS_PER_PGD);
+       copy_page(initial_page_table, pgd);
        initial_page_table[KERNEL_PGD_BOUNDARY] =
                __pgd(__pa(initial_kernel_pmd) | _PAGE_PRESENT);
 
@@ -1882,8 +1997,6 @@ pgd_t * __init xen_setup_kernel_pagetable(pgd_t *pgd,
 
        memblock_reserve(__pa(xen_start_info->pt_base),
                         xen_start_info->nr_pt_frames * PAGE_SIZE);
-
-       return initial_page_table;
 }
 #endif /* CONFIG_X86_64 */
 
@@ -2333,6 +2446,9 @@ int xen_remap_domain_mfn_range(struct vm_area_struct *vma,
        unsigned long range;
        int err = 0;
 
+       if (xen_feature(XENFEAT_auto_translated_physmap))
+               return -EINVAL;
+
        prot = __pgprot(pgprot_val(prot) | _PAGE_IOMAP);
 
        BUG_ON(!((vma->vm_flags & (VM_PFNMAP | VM_RESERVED | VM_IO)) ==
@@ -2351,8 +2467,8 @@ int xen_remap_domain_mfn_range(struct vm_area_struct *vma,
                if (err)
                        goto out;
 
-               err = -EFAULT;
-               if (HYPERVISOR_mmu_update(mmu_update, batch, NULL, domid) < 0)
+               err = HYPERVISOR_mmu_update(mmu_update, batch, NULL, domid);
+               if (err < 0)
                        goto out;
 
                nr -= batch;
index 72213da605f50c07f3684ca07d351a8bbd7435ef..95fb2aa5927efc4678eccd8a51d91044b4dd9adb 100644 (file)
@@ -22,7 +22,7 @@
  *
  * P2M_PER_PAGE depends on the architecture, as a mfn is always
  * unsigned long (8 bytes on 64-bit, 4 bytes on 32), leading to
- * 512 and 1024 entries respectively. 
+ * 512 and 1024 entries respectively.
  *
  * In short, these structures contain the Machine Frame Number (MFN) of the PFN.
  *
  *      /    | ~0, ~0, ....  |
  *     |     \---------------/
  *     |
- *     p2m_missing             p2m_missing
- * /------------------\     /------------\
- * | [p2m_mid_missing]+---->| ~0, ~0, ~0 |
- * | [p2m_mid_missing]+---->| ..., ~0    |
- * \------------------/     \------------/
+ *   p2m_mid_missing           p2m_missing
+ * /-----------------\     /------------\
+ * | [p2m_missing]   +---->| ~0, ~0, ~0 |
+ * | [p2m_missing]   +---->| ..., ~0    |
+ * \-----------------/     \------------/
  *
  * where ~0 is INVALID_P2M_ENTRY. IDENTITY is (PFN | IDENTITY_BIT)
  */
@@ -396,7 +396,85 @@ void __init xen_build_dynamic_phys_to_machine(void)
 
        m2p_override_init();
 }
+#ifdef CONFIG_X86_64
+#include <linux/bootmem.h>
+unsigned long __init xen_revector_p2m_tree(void)
+{
+       unsigned long va_start;
+       unsigned long va_end;
+       unsigned long pfn;
+       unsigned long pfn_free = 0;
+       unsigned long *mfn_list = NULL;
+       unsigned long size;
+
+       va_start = xen_start_info->mfn_list;
+       /*We copy in increments of P2M_PER_PAGE * sizeof(unsigned long),
+        * so make sure it is rounded up to that */
+       size = PAGE_ALIGN(xen_start_info->nr_pages * sizeof(unsigned long));
+       va_end = va_start + size;
+
+       /* If we were revectored already, don't do it again. */
+       if (va_start <= __START_KERNEL_map && va_start >= __PAGE_OFFSET)
+               return 0;
+
+       mfn_list = alloc_bootmem_align(size, PAGE_SIZE);
+       if (!mfn_list) {
+               pr_warn("Could not allocate space for a new P2M tree!\n");
+               return xen_start_info->mfn_list;
+       }
+       /* Fill it out with INVALID_P2M_ENTRY value */
+       memset(mfn_list, 0xFF, size);
+
+       for (pfn = 0; pfn < ALIGN(MAX_DOMAIN_PAGES, P2M_PER_PAGE); pfn += P2M_PER_PAGE) {
+               unsigned topidx = p2m_top_index(pfn);
+               unsigned mididx;
+               unsigned long *mid_p;
+
+               if (!p2m_top[topidx])
+                       continue;
+
+               if (p2m_top[topidx] == p2m_mid_missing)
+                       continue;
+
+               mididx = p2m_mid_index(pfn);
+               mid_p = p2m_top[topidx][mididx];
+               if (!mid_p)
+                       continue;
+               if ((mid_p == p2m_missing) || (mid_p == p2m_identity))
+                       continue;
+
+               if ((unsigned long)mid_p == INVALID_P2M_ENTRY)
+                       continue;
+
+               /* The old va. Rebase it on mfn_list */
+               if (mid_p >= (unsigned long *)va_start && mid_p <= (unsigned long *)va_end) {
+                       unsigned long *new;
+
+                       if (pfn_free  > (size / sizeof(unsigned long))) {
+                               WARN(1, "Only allocated for %ld pages, but we want %ld!\n",
+                                    size / sizeof(unsigned long), pfn_free);
+                               return 0;
+                       }
+                       new = &mfn_list[pfn_free];
+
+                       copy_page(new, mid_p);
+                       p2m_top[topidx][mididx] = &mfn_list[pfn_free];
+                       p2m_top_mfn_p[topidx][mididx] = virt_to_mfn(&mfn_list[pfn_free]);
+
+                       pfn_free += P2M_PER_PAGE;
 
+               }
+               /* This should be the leafs allocated for identity from _brk. */
+       }
+       return (unsigned long)mfn_list;
+
+}
+#else
+unsigned long __init xen_revector_p2m_tree(void)
+{
+       return 0;
+}
+#endif
 unsigned long get_phys_to_machine(unsigned long pfn)
 {
        unsigned topidx, mididx, idx;
@@ -430,7 +508,7 @@ static void free_p2m_page(void *p)
        free_page((unsigned long)p);
 }
 
-/* 
+/*
  * Fully allocate the p2m structure for a given pfn.  We need to check
  * that both the top and mid levels are allocated, and make sure the
  * parallel mfn tree is kept in sync.  We may race with other cpus, so
index 967633ad98c48b262cf7739c7cdcdb7b8d79641a..969570491c3964d0023dc82a231ff683ee88f735 100644 (file)
@@ -8,6 +8,14 @@
 #include <xen/xen.h>
 #include <asm/iommu_table.h>
 
+
+#include <asm/xen/swiotlb-xen.h>
+#ifdef CONFIG_X86_64
+#include <asm/iommu.h>
+#include <asm/dma.h>
+#endif
+#include <linux/export.h>
+
 int xen_swiotlb __read_mostly;
 
 static struct dma_map_ops xen_swiotlb_dma_ops = {
@@ -34,34 +42,64 @@ static struct dma_map_ops xen_swiotlb_dma_ops = {
 int __init pci_xen_swiotlb_detect(void)
 {
 
+       if (!xen_pv_domain())
+               return 0;
+
        /* If running as PV guest, either iommu=soft, or swiotlb=force will
         * activate this IOMMU. If running as PV privileged, activate it
         * irregardless.
         */
-       if ((xen_initial_domain() || swiotlb || swiotlb_force) &&
-           (xen_pv_domain()))
+       if ((xen_initial_domain() || swiotlb || swiotlb_force))
                xen_swiotlb = 1;
 
        /* If we are running under Xen, we MUST disable the native SWIOTLB.
         * Don't worry about swiotlb_force flag activating the native, as
         * the 'swiotlb' flag is the only one turning it on. */
-       if (xen_pv_domain())
-               swiotlb = 0;
+       swiotlb = 0;
 
+#ifdef CONFIG_X86_64
+       /* pci_swiotlb_detect_4gb turns on native SWIOTLB if no_iommu == 0
+        * (so no iommu=X command line over-writes).
+        * Considering that PV guests do not want the *native SWIOTLB* but
+        * only Xen SWIOTLB it is not useful to us so set no_iommu=1 here.
+        */
+       if (max_pfn > MAX_DMA32_PFN)
+               no_iommu = 1;
+#endif
        return xen_swiotlb;
 }
 
 void __init pci_xen_swiotlb_init(void)
 {
        if (xen_swiotlb) {
-               xen_swiotlb_init(1);
+               xen_swiotlb_init(1, true /* early */);
                dma_ops = &xen_swiotlb_dma_ops;
 
                /* Make sure ACS will be enabled */
                pci_request_acs();
        }
 }
+
+int pci_xen_swiotlb_init_late(void)
+{
+       int rc;
+
+       if (xen_swiotlb)
+               return 0;
+
+       rc = xen_swiotlb_init(1, false /* late */);
+       if (rc)
+               return rc;
+
+       dma_ops = &xen_swiotlb_dma_ops;
+       /* Make sure ACS will be enabled */
+       pci_request_acs();
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(pci_xen_swiotlb_init_late);
+
 IOMMU_INIT_FINISH(pci_xen_swiotlb_detect,
-                 0,
+                 NULL,
                  pci_xen_swiotlb_init,
-                 0);
+                 NULL);
index ffcf2615640b0bd1f8e3596dbaf4d07c49d5dc51..0a7852483ffef27583fb6c4b5b7c3684c5b3847c 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/module.h>
 
 #include <xen/platform_pci.h>
+#include "xen-ops.h"
 
 #define XEN_PLATFORM_ERR_MAGIC -1
 #define XEN_PLATFORM_ERR_PROTOCOL -2
index e2d62d697b5dffc60ad6ea53e2ad3f1ce33282a3..8971a26d21abb943d5c9e23b5c6630a207f43536 100644 (file)
@@ -432,6 +432,24 @@ char * __init xen_memory_setup(void)
         *  - mfn_list
         *  - xen_start_info
         * See comment above "struct start_info" in <xen/interface/xen.h>
+        * We tried to make the the memblock_reserve more selective so
+        * that it would be clear what region is reserved. Sadly we ran
+        * in the problem wherein on a 64-bit hypervisor with a 32-bit
+        * initial domain, the pt_base has the cr3 value which is not
+        * neccessarily where the pagetable starts! As Jan put it: "
+        * Actually, the adjustment turns out to be correct: The page
+        * tables for a 32-on-64 dom0 get allocated in the order "first L1",
+        * "first L2", "first L3", so the offset to the page table base is
+        * indeed 2. When reading xen/include/public/xen.h's comment
+        * very strictly, this is not a violation (since there nothing is said
+        * that the first thing in the page table space is pointed to by
+        * pt_base; I admit that this seems to be implied though, namely
+        * do I think that it is implied that the page table space is the
+        * range [pt_base, pt_base + nt_pt_frames), whereas that
+        * range here indeed is [pt_base - 2, pt_base - 2 + nt_pt_frames),
+        * which - without a priori knowledge - the kernel would have
+        * difficulty to figure out)." - so lets just fall back to the
+        * easy way and reserve the whole region.
         */
        memblock_reserve(__pa(xen_start_info->mfn_list),
                         xen_start_info->pt_base - xen_start_info->mfn_list);
index 1cd7f4d11e298bdf7b55e087602e209df45827ae..6722e3733f02433e75bf2d91f185191e3ada65c0 100644 (file)
@@ -35,6 +35,7 @@ void __init xen_init_vga(const struct dom0_vga_console_info *info, size_t size)
                        info->u.text_mode_3.font_height;
                break;
 
+       case XEN_VGATYPE_EFI_LFB:
        case XEN_VGATYPE_VESA_LFB:
                if (size < offsetof(struct dom0_vga_console_info,
                                    u.vesa_lfb.gbl_caps))
@@ -54,6 +55,12 @@ void __init xen_init_vga(const struct dom0_vga_console_info *info, size_t size)
                screen_info->blue_pos = info->u.vesa_lfb.blue_pos;
                screen_info->rsvd_size = info->u.vesa_lfb.rsvd_size;
                screen_info->rsvd_pos = info->u.vesa_lfb.rsvd_pos;
+
+               if (info->video_type == XEN_VGATYPE_EFI_LFB) {
+                       screen_info->orig_video_isVGA = VIDEO_TYPE_EFI;
+                       break;
+               }
+
                if (size >= offsetof(struct dom0_vga_console_info,
                                     u.vesa_lfb.gbl_caps)
                    + sizeof(info->u.vesa_lfb.gbl_caps))
index aaa7291c9259f55c0fc5ac0aab5f09ff788511a0..7faed5869e5bf215cafe4c0fdbe24ba38fcd66d0 100644 (file)
@@ -28,9 +28,61 @@ ENTRY(startup_xen)
        __FINIT
 
 .pushsection .text
-       .align PAGE_SIZE
+       .balign PAGE_SIZE
 ENTRY(hypercall_page)
-       .skip PAGE_SIZE
+#define NEXT_HYPERCALL(x) \
+       ENTRY(xen_hypercall_##x) \
+       .skip 32
+
+NEXT_HYPERCALL(set_trap_table)
+NEXT_HYPERCALL(mmu_update)
+NEXT_HYPERCALL(set_gdt)
+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
 
        ELFNOTE(Xen, XEN_ELFNOTE_GUEST_OS,       .asciz "linux")
index 202d4c150154fb31ddb03da8f8144a45f21c02a7..a95b41744ad0bafdcde069cb965cabb67ab0f61b 100644 (file)
@@ -27,7 +27,7 @@ void xen_setup_mfn_list_list(void);
 void xen_setup_shared_info(void);
 void xen_build_mfn_list_list(void);
 void xen_setup_machphys_mapping(void);
-pgd_t *xen_setup_kernel_pagetable(pgd_t *pgd, unsigned long max_pfn);
+void xen_setup_kernel_pagetable(pgd_t *pgd, unsigned long max_pfn);
 void xen_reserve_top(void);
 extern unsigned long xen_max_p2m_pfn;
 
@@ -35,7 +35,6 @@ void xen_set_pat(u64);
 
 char * __init xen_memory_setup(void);
 void __init xen_arch_setup(void);
-void __init xen_init_IRQ(void);
 void xen_enable_sysenter(void);
 void xen_enable_syscall(void);
 void xen_vcpu_restore(void);
@@ -45,6 +44,7 @@ void xen_hvm_init_shared_info(void);
 void xen_unplug_emulated_devices(void);
 
 void __init xen_build_dynamic_phys_to_machine(void);
+unsigned long __init xen_revector_p2m_tree(void);
 
 void xen_init_irq_ops(void);
 void xen_setup_timer(int cpu);
index c6decb901e5e16f4ba09ccef7db33675aeecb189..280a13846e6cb06e1f774dd927598c1f3bfa5a8c 100644 (file)
@@ -42,6 +42,7 @@
 
 #include <xen/events.h>
 #include <xen/page.h>
+#include <xen/xen.h>
 #include <asm/xen/hypervisor.h>
 #include <asm/xen/hypercall.h>
 #include "common.h"
index 682633bfe00ff7fc35c7be97c427a6cf5d9dde45..1c0a30240d97c03ef56375ec75982903e94e60da 100644 (file)
@@ -40,6 +40,7 @@
 
 #include <net/tcp.h>
 
+#include <xen/xen.h>
 #include <xen/events.h>
 #include <xen/interface/memory.h>
 
index c934fe8583f5f17c33a577993a934205db2d3609..caa011008cd0c9fe11b38507e7f550552bd93170 100644 (file)
@@ -43,6 +43,7 @@
 #include <linux/slab.h>
 #include <net/ip.h>
 
+#include <asm/xen/page.h>
 #include <xen/xen.h>
 #include <xen/xenbus.h>
 #include <xen/events.h>
index def8d0b5620c01bf4b8fd372a0ee0f68f57dabab..0aab85a51559c1f46ce4567cd3de1ca27a0d7a07 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/bitops.h>
 #include <linux/time.h>
 
+#include <asm/xen/swiotlb-xen.h>
 #define INVALID_GRANT_REF (0)
 #define INVALID_EVTCHN    (-1)
 
@@ -236,7 +237,7 @@ static int pcifront_bus_write(struct pci_bus *bus, unsigned int devfn,
        return errno_to_pcibios_err(do_pci_op(pdev, &op));
 }
 
-struct pci_ops pcifront_bus_ops = {
+static struct pci_ops pcifront_bus_ops = {
        .read = pcifront_bus_read,
        .write = pcifront_bus_write,
 };
@@ -668,7 +669,7 @@ static irqreturn_t pcifront_handler_aer(int irq, void *dev)
        schedule_pcifront_aer_op(pdev);
        return IRQ_HANDLED;
 }
-static int pcifront_connect(struct pcifront_device *pdev)
+static int pcifront_connect_and_init_dma(struct pcifront_device *pdev)
 {
        int err = 0;
 
@@ -681,9 +682,13 @@ static int pcifront_connect(struct pcifront_device *pdev)
                dev_err(&pdev->xdev->dev, "PCI frontend already installed!\n");
                err = -EEXIST;
        }
-
        spin_unlock(&pcifront_dev_lock);
 
+       if (!err && !swiotlb_nr_tbl()) {
+               err = pci_xen_swiotlb_init_late();
+               if (err)
+                       dev_err(&pdev->xdev->dev, "Could not setup SWIOTLB!\n");
+       }
        return err;
 }
 
@@ -842,10 +847,10 @@ static int __devinit pcifront_try_connect(struct pcifront_device *pdev)
            XenbusStateInitialised)
                goto out;
 
-       err = pcifront_connect(pdev);
+       err = pcifront_connect_and_init_dma(pdev);
        if (err) {
                xenbus_dev_fatal(pdev->xdev, err,
-                                "Error connecting PCI Frontend");
+                                "Error setting up PCI Frontend");
                goto out;
        }
 
index 1e456dca4f60be02835d7503436fe8f26450c118..2944ff88fdc0b2ea9705850e080a755aca440a8d 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/console.h>
 #include <linux/delay.h>
 #include <linux/err.h>
+#include <linux/irq.h>
 #include <linux/init.h>
 #include <linux/types.h>
 #include <linux/list.h>
@@ -35,6 +36,7 @@
 #include <xen/page.h>
 #include <xen/events.h>
 #include <xen/interface/io/console.h>
+#include <xen/interface/sched.h>
 #include <xen/hvc-console.h>
 #include <xen/xenbus.h>
 
index a4a3cab2f4596c4f1681a999bebf6353307d5084..4dca78c204ced55ca0a96a04e4f948356d2cb952 100644 (file)
@@ -1,11 +1,19 @@
-obj-y  += grant-table.o features.o events.o manage.o balloon.o
+ifneq ($(CONFIG_ARM),y)
+obj-y  += manage.o balloon.o
+obj-$(CONFIG_HOTPLUG_CPU)              += cpu_hotplug.o
+endif
+obj-y  += grant-table.o features.o events.o
 obj-y  += xenbus/
 
 nostackp := $(call cc-option, -fno-stack-protector)
 CFLAGS_features.o                      := $(nostackp)
 
+dom0-$(CONFIG_PCI) += pci.o
+dom0-$(CONFIG_ACPI) += acpi.o
+dom0-$(CONFIG_X86) += pcpu.o
+dom0-$(CONFIG_USB_SUPPORT) += dbgp.o
+obj-$(CONFIG_XEN_DOM0)                 += $(dom0-y)
 obj-$(CONFIG_BLOCK)                    += biomerge.o
-obj-$(CONFIG_HOTPLUG_CPU)              += cpu_hotplug.o
 obj-$(CONFIG_XEN_XENCOMM)              += xencomm.o
 obj-$(CONFIG_XEN_BALLOON)              += xen-balloon.o
 obj-$(CONFIG_XEN_SELFBALLOONING)       += xen-selfballoon.o
@@ -17,8 +25,6 @@ obj-$(CONFIG_XEN_SYS_HYPERVISOR)      += sys-hypervisor.o
 obj-$(CONFIG_XEN_PVHVM)                        += platform-pci.o
 obj-$(CONFIG_XEN_TMEM)                 += tmem.o
 obj-$(CONFIG_SWIOTLB_XEN)              += swiotlb-xen.o
-obj-$(CONFIG_XEN_DOM0)                 += pcpu.o
-obj-$(CONFIG_XEN_DOM0)                 += pci.o dbgp.o acpi.o
 obj-$(CONFIG_XEN_MCE_LOG)              += mcelog.o
 obj-$(CONFIG_XEN_PCIDEV_BACKEND)       += xen-pciback/
 obj-$(CONFIG_XEN_PRIVCMD)              += xen-privcmd.o
index 7595581d032cc9d9c5a7f04ee12b861dc76051ee..59e10a1286d53ff73aa3e0a6c91a5aed9033de9e 100644 (file)
 #include <linux/irqnr.h>
 #include <linux/pci.h>
 
+#ifdef CONFIG_X86
 #include <asm/desc.h>
 #include <asm/ptrace.h>
 #include <asm/irq.h>
 #include <asm/idle.h>
 #include <asm/io_apic.h>
-#include <asm/sync_bitops.h>
 #include <asm/xen/page.h>
 #include <asm/xen/pci.h>
+#endif
+#include <asm/sync_bitops.h>
 #include <asm/xen/hypercall.h>
 #include <asm/xen/hypervisor.h>
 
@@ -50,6 +52,9 @@
 #include <xen/interface/event_channel.h>
 #include <xen/interface/hvm/hvm_op.h>
 #include <xen/interface/hvm/params.h>
+#include <xen/interface/physdev.h>
+#include <xen/interface/sched.h>
+#include <asm/hw_irq.h>
 
 /*
  * This lock protects updates to the following mapping and reference-count
@@ -373,11 +378,22 @@ static void unmask_evtchn(int port)
 {
        struct shared_info *s = HYPERVISOR_shared_info;
        unsigned int cpu = get_cpu();
+       int do_hypercall = 0, evtchn_pending = 0;
 
        BUG_ON(!irqs_disabled());
 
-       /* Slow path (hypercall) if this is a non-local port. */
-       if (unlikely(cpu != cpu_from_evtchn(port))) {
+       if (unlikely((cpu != cpu_from_evtchn(port))))
+               do_hypercall = 1;
+       else
+               evtchn_pending = sync_test_bit(port, &s->evtchn_pending[0]);
+
+       if (unlikely(evtchn_pending && xen_hvm_domain()))
+               do_hypercall = 1;
+
+       /* Slow path (hypercall) if this is a non-local port or if this is
+        * an hvm domain and an event is pending (hvm domains don't have
+        * their own implementation of irq_enable). */
+       if (do_hypercall) {
                struct evtchn_unmask unmask = { .port = port };
                (void)HYPERVISOR_event_channel_op(EVTCHNOP_unmask, &unmask);
        } else {
@@ -390,7 +406,7 @@ static void unmask_evtchn(int port)
                 * 'hw_resend_irq'. Just like a real IO-APIC we 'lose
                 * the interrupt edge' if the channel is masked.
                 */
-               if (sync_test_bit(port, &s->evtchn_pending[0]) &&
+               if (evtchn_pending &&
                    !sync_test_and_set_bit(port / BITS_PER_LONG,
                                           &vcpu_info->evtchn_pending_sel))
                        vcpu_info->evtchn_upcall_pending = 1;
@@ -831,6 +847,7 @@ int bind_evtchn_to_irq(unsigned int evtchn)
                struct irq_info *info = info_for_irq(irq);
                WARN_ON(info == NULL || info->type != IRQT_EVTCHN);
        }
+       irq_clear_status_flags(irq, IRQ_NOREQUEST|IRQ_NOAUTOEN);
 
 out:
        mutex_unlock(&irq_mapping_update_lock);
@@ -1374,7 +1391,9 @@ void xen_evtchn_do_upcall(struct pt_regs *regs)
 {
        struct pt_regs *old_regs = set_irq_regs(regs);
 
+#ifdef CONFIG_X86
        exit_idle();
+#endif
        irq_enter();
 
        __xen_evtchn_do_upcall();
@@ -1785,7 +1804,7 @@ void xen_callback_vector(void) {}
 
 void __init xen_init_IRQ(void)
 {
-       int i, rc;
+       int i;
 
        evtchn_to_irq = kcalloc(NR_EVENT_CHANNELS, sizeof(*evtchn_to_irq),
                                    GFP_KERNEL);
@@ -1801,6 +1820,7 @@ void __init xen_init_IRQ(void)
 
        pirq_needs_eoi = pirq_needs_eoi_flag;
 
+#ifdef CONFIG_X86
        if (xen_hvm_domain()) {
                xen_callback_vector();
                native_init_IRQ();
@@ -1808,6 +1828,7 @@ void __init xen_init_IRQ(void)
                 * __acpi_register_gsi can point at the right function */
                pci_xen_hvm_init();
        } else {
+               int rc;
                struct physdev_pirq_eoi_gmfn eoi_gmfn;
 
                irq_ctx_init(smp_processor_id());
@@ -1823,4 +1844,5 @@ void __init xen_init_IRQ(void)
                } else
                        pirq_needs_eoi = pirq_check_eoi_map;
        }
+#endif
 }
index 7f1241608489de05a33e957a77145f4faa605f0e..5df9fd847b2eebbc87fe668e136d1c0684a7905c 100644 (file)
@@ -446,7 +446,7 @@ static void mn_release(struct mmu_notifier *mn,
        spin_unlock(&priv->lock);
 }
 
-struct mmu_notifier_ops gntdev_mmu_ops = {
+static struct mmu_notifier_ops gntdev_mmu_ops = {
        .release                = mn_release,
        .invalidate_page        = mn_invl_page,
        .invalidate_range_start = mn_invl_range_start,
index 006726688baf4f0a535896dd38c9a3ea2198c617..f37faf6eac130cb92411def10d34fc2ffa3c7d0a 100644 (file)
@@ -47,6 +47,7 @@
 #include <xen/interface/memory.h>
 #include <xen/hvc-console.h>
 #include <asm/xen/hypercall.h>
+#include <asm/xen/interface.h>
 
 #include <asm/pgtable.h>
 #include <asm/sync_bitops.h>
@@ -285,10 +286,9 @@ int gnttab_grant_foreign_access(domid_t domid, unsigned long frame,
 }
 EXPORT_SYMBOL_GPL(gnttab_grant_foreign_access);
 
-void gnttab_update_subpage_entry_v2(grant_ref_t ref, domid_t domid,
-                                   unsigned long frame, int flags,
-                                   unsigned page_off,
-                                   unsigned length)
+static void gnttab_update_subpage_entry_v2(grant_ref_t ref, domid_t domid,
+                                          unsigned long frame, int flags,
+                                          unsigned page_off, unsigned length)
 {
        gnttab_shared.v2[ref].sub_page.frame = frame;
        gnttab_shared.v2[ref].sub_page.page_off = page_off;
@@ -345,9 +345,9 @@ bool gnttab_subpage_grants_available(void)
 }
 EXPORT_SYMBOL_GPL(gnttab_subpage_grants_available);
 
-void gnttab_update_trans_entry_v2(grant_ref_t ref, domid_t domid,
-                                 int flags, domid_t trans_domid,
-                                 grant_ref_t trans_gref)
+static void gnttab_update_trans_entry_v2(grant_ref_t ref, domid_t domid,
+                                        int flags, domid_t trans_domid,
+                                        grant_ref_t trans_gref)
 {
        gnttab_shared.v2[ref].transitive.trans_domid = trans_domid;
        gnttab_shared.v2[ref].transitive.gref = trans_gref;
index ccee0f16bcf8c10e994855a6efadff99b5b6bda1..ef6389580b8c78dd30a8c7738098c51b6ef3133a 100644 (file)
@@ -76,7 +76,7 @@ static void free_page_list(struct list_head *pages)
  */
 static int gather_array(struct list_head *pagelist,
                        unsigned nelem, size_t size,
-                       void __user *data)
+                       const void __user *data)
 {
        unsigned pageidx;
        void *pagedata;
@@ -246,61 +246,117 @@ struct mmap_batch_state {
        domid_t domain;
        unsigned long va;
        struct vm_area_struct *vma;
-       int err;
-
-       xen_pfn_t __user *user;
+       /* A tristate:
+        *      0 for no errors
+        *      1 if at least one error has happened (and no
+        *          -ENOENT errors have happened)
+        *      -ENOENT if at least 1 -ENOENT has happened.
+        */
+       int global_error;
+       /* An array for individual errors */
+       int *err;
+
+       /* User-space mfn array to store errors in the second pass for V1. */
+       xen_pfn_t __user *user_mfn;
 };
 
 static int mmap_batch_fn(void *data, void *state)
 {
        xen_pfn_t *mfnp = data;
        struct mmap_batch_state *st = state;
+       int ret;
+
+       ret = xen_remap_domain_mfn_range(st->vma, st->va & PAGE_MASK, *mfnp, 1,
+                                        st->vma->vm_page_prot, st->domain);
 
-       if (xen_remap_domain_mfn_range(st->vma, st->va & PAGE_MASK, *mfnp, 1,
-                                      st->vma->vm_page_prot, st->domain) < 0) {
-               *mfnp |= 0xf0000000U;
-               st->err++;
+       /* Store error code for second pass. */
+       *(st->err++) = ret;
+
+       /* And see if it affects the global_error. */
+       if (ret < 0) {
+               if (ret == -ENOENT)
+                       st->global_error = -ENOENT;
+               else {
+                       /* Record that at least one error has happened. */
+                       if (st->global_error == 0)
+                               st->global_error = 1;
+               }
        }
        st->va += PAGE_SIZE;
 
        return 0;
 }
 
-static int mmap_return_errors(void *data, void *state)
+static int mmap_return_errors_v1(void *data, void *state)
 {
        xen_pfn_t *mfnp = data;
        struct mmap_batch_state *st = state;
-
-       return put_user(*mfnp, st->user++);
+       int err = *(st->err++);
+
+       /*
+        * V1 encodes the error codes in the 32bit top nibble of the
+        * mfn (with its known limitations vis-a-vis 64 bit callers).
+        */
+       *mfnp |= (err == -ENOENT) ?
+                               PRIVCMD_MMAPBATCH_PAGED_ERROR :
+                               PRIVCMD_MMAPBATCH_MFN_ERROR;
+       return __put_user(*mfnp, st->user_mfn++);
 }
 
 static struct vm_operations_struct privcmd_vm_ops;
 
-static long privcmd_ioctl_mmap_batch(void __user *udata)
+static long privcmd_ioctl_mmap_batch(void __user *udata, int version)
 {
        int ret;
-       struct privcmd_mmapbatch m;
+       struct privcmd_mmapbatch_v2 m;
        struct mm_struct *mm = current->mm;
        struct vm_area_struct *vma;
        unsigned long nr_pages;
        LIST_HEAD(pagelist);
+       int *err_array = NULL;
        struct mmap_batch_state state;
 
        if (!xen_initial_domain())
                return -EPERM;
 
-       if (copy_from_user(&m, udata, sizeof(m)))
-               return -EFAULT;
+       switch (version) {
+       case 1:
+               if (copy_from_user(&m, udata, sizeof(struct privcmd_mmapbatch)))
+                       return -EFAULT;
+               /* Returns per-frame error in m.arr. */
+               m.err = NULL;
+               if (!access_ok(VERIFY_WRITE, m.arr, m.num * sizeof(*m.arr)))
+                       return -EFAULT;
+               break;
+       case 2:
+               if (copy_from_user(&m, udata, sizeof(struct privcmd_mmapbatch_v2)))
+                       return -EFAULT;
+               /* Returns per-frame error code in m.err. */
+               if (!access_ok(VERIFY_WRITE, m.err, m.num * (sizeof(*m.err))))
+                       return -EFAULT;
+               break;
+       default:
+               return -EINVAL;
+       }
 
        nr_pages = m.num;
        if ((m.num <= 0) || (nr_pages > (LONG_MAX >> PAGE_SHIFT)))
                return -EINVAL;
 
-       ret = gather_array(&pagelist, m.num, sizeof(xen_pfn_t),
-                          m.arr);
+       ret = gather_array(&pagelist, m.num, sizeof(xen_pfn_t), m.arr);
 
-       if (ret || list_empty(&pagelist))
+       if (ret)
                goto out;
+       if (list_empty(&pagelist)) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       err_array = kcalloc(m.num, sizeof(int), GFP_KERNEL);
+       if (err_array == NULL) {
+               ret = -ENOMEM;
+               goto out;
+       }
 
        down_write(&mm->mmap_sem);
 
@@ -315,24 +371,37 @@ static long privcmd_ioctl_mmap_batch(void __user *udata)
                goto out;
        }
 
-       state.domain = m.dom;
-       state.vma = vma;
-       state.va = m.addr;
-       state.err = 0;
+       state.domain        = m.dom;
+       state.vma           = vma;
+       state.va            = m.addr;
+       state.global_error  = 0;
+       state.err           = err_array;
 
-       ret = traverse_pages(m.num, sizeof(xen_pfn_t),
-                            &pagelist, mmap_batch_fn, &state);
+       /* mmap_batch_fn guarantees ret == 0 */
+       BUG_ON(traverse_pages(m.num, sizeof(xen_pfn_t),
+                            &pagelist, mmap_batch_fn, &state));
 
        up_write(&mm->mmap_sem);
 
-       if (state.err > 0) {
-               state.user = m.arr;
+       if (state.global_error && (version == 1)) {
+               /* Write back errors in second pass. */
+               state.user_mfn = (xen_pfn_t *)m.arr;
+               state.err      = err_array;
                ret = traverse_pages(m.num, sizeof(xen_pfn_t),
-                              &pagelist,
-                              mmap_return_errors, &state);
+                                    &pagelist, mmap_return_errors_v1, &state);
+       } else if (version == 2) {
+               ret = __copy_to_user(m.err, err_array, m.num * sizeof(int));
+               if (ret)
+                       ret = -EFAULT;
        }
 
+       /* If we have not had any EFAULT-like global errors then set the global
+        * error to -ENOENT if necessary. */
+       if ((ret == 0) && (state.global_error == -ENOENT))
+               ret = -ENOENT;
+
 out:
+       kfree(err_array);
        free_page_list(&pagelist);
 
        return ret;
@@ -354,7 +423,11 @@ static long privcmd_ioctl(struct file *file,
                break;
 
        case IOCTL_PRIVCMD_MMAPBATCH:
-               ret = privcmd_ioctl_mmap_batch(udata);
+               ret = privcmd_ioctl_mmap_batch(udata, 1);
+               break;
+
+       case IOCTL_PRIVCMD_MMAPBATCH_V2:
+               ret = privcmd_ioctl_mmap_batch(udata, 2);
                break;
 
        default:
@@ -380,10 +453,6 @@ static struct vm_operations_struct privcmd_vm_ops = {
 
 static int privcmd_mmap(struct file *file, struct vm_area_struct *vma)
 {
-       /* Unsupported for auto-translate guests. */
-       if (xen_feature(XENFEAT_auto_translated_physmap))
-               return -ENOSYS;
-
        /* DONTCOPY is essential for Xen because copy_page_range doesn't know
         * how to recreate these mappings */
        vma->vm_flags |= VM_RESERVED | VM_IO | VM_DONTCOPY | VM_PFNMAP;
index 4d519488d3045355672b8f48e3c1e2eb4ac64864..58db6df866ef3338f6fc787acd552fe03d0a0b69 100644 (file)
@@ -52,7 +52,7 @@ static unsigned long xen_io_tlb_nslabs;
  * Quick lookup value of the bus address of the IOTLB.
  */
 
-u64 start_dma_addr;
+static u64 start_dma_addr;
 
 static dma_addr_t xen_phys_to_bus(phys_addr_t paddr)
 {
@@ -144,31 +144,72 @@ xen_swiotlb_fixup(void *buf, size_t size, unsigned long nslabs)
        } while (i < nslabs);
        return 0;
 }
+static unsigned long xen_set_nslabs(unsigned long nr_tbl)
+{
+       if (!nr_tbl) {
+               xen_io_tlb_nslabs = (64 * 1024 * 1024 >> IO_TLB_SHIFT);
+               xen_io_tlb_nslabs = ALIGN(xen_io_tlb_nslabs, IO_TLB_SEGSIZE);
+       } else
+               xen_io_tlb_nslabs = nr_tbl;
 
-void __init xen_swiotlb_init(int verbose)
+       return xen_io_tlb_nslabs << IO_TLB_SHIFT;
+}
+
+enum xen_swiotlb_err {
+       XEN_SWIOTLB_UNKNOWN = 0,
+       XEN_SWIOTLB_ENOMEM,
+       XEN_SWIOTLB_EFIXUP
+};
+
+static const char *xen_swiotlb_error(enum xen_swiotlb_err err)
+{
+       switch (err) {
+       case XEN_SWIOTLB_ENOMEM:
+               return "Cannot allocate Xen-SWIOTLB buffer\n";
+       case XEN_SWIOTLB_EFIXUP:
+               return "Failed to get contiguous memory for DMA from Xen!\n"\
+                   "You either: don't have the permissions, do not have"\
+                   " enough free memory under 4GB, or the hypervisor memory"\
+                   " is too fragmented!";
+       default:
+               break;
+       }
+       return "";
+}
+int __ref xen_swiotlb_init(int verbose, bool early)
 {
-       unsigned long bytes;
+       unsigned long bytes, order;
        int rc = -ENOMEM;
-       unsigned long nr_tbl;
-       char *m = NULL;
+       enum xen_swiotlb_err m_ret = XEN_SWIOTLB_UNKNOWN;
        unsigned int repeat = 3;
 
-       nr_tbl = swiotlb_nr_tbl();
-       if (nr_tbl)
-               xen_io_tlb_nslabs = nr_tbl;
-       else {
-               xen_io_tlb_nslabs = (64 * 1024 * 1024 >> IO_TLB_SHIFT);
-               xen_io_tlb_nslabs = ALIGN(xen_io_tlb_nslabs, IO_TLB_SEGSIZE);
-       }
+       xen_io_tlb_nslabs = swiotlb_nr_tbl();
 retry:
-       bytes = xen_io_tlb_nslabs << IO_TLB_SHIFT;
-
+       bytes = xen_set_nslabs(xen_io_tlb_nslabs);
+       order = get_order(xen_io_tlb_nslabs << IO_TLB_SHIFT);
        /*
         * Get IO TLB memory from any location.
         */
-       xen_io_tlb_start = alloc_bootmem_pages(PAGE_ALIGN(bytes));
+       if (early)
+               xen_io_tlb_start = alloc_bootmem_pages(PAGE_ALIGN(bytes));
+       else {
+#define SLABS_PER_PAGE (1 << (PAGE_SHIFT - IO_TLB_SHIFT))
+#define IO_TLB_MIN_SLABS ((1<<20) >> IO_TLB_SHIFT)
+               while ((SLABS_PER_PAGE << order) > IO_TLB_MIN_SLABS) {
+                       xen_io_tlb_start = (void *)__get_free_pages(__GFP_NOWARN, order);
+                       if (xen_io_tlb_start)
+                               break;
+                       order--;
+               }
+               if (order != get_order(bytes)) {
+                       pr_warn("Warning: only able to allocate %ld MB "
+                               "for software IO TLB\n", (PAGE_SIZE << order) >> 20);
+                       xen_io_tlb_nslabs = SLABS_PER_PAGE << order;
+                       bytes = xen_io_tlb_nslabs << IO_TLB_SHIFT;
+               }
+       }
        if (!xen_io_tlb_start) {
-               m = "Cannot allocate Xen-SWIOTLB buffer!\n";
+               m_ret = XEN_SWIOTLB_ENOMEM;
                goto error;
        }
        xen_io_tlb_end = xen_io_tlb_start + bytes;
@@ -179,17 +220,22 @@ retry:
                               bytes,
                               xen_io_tlb_nslabs);
        if (rc) {
-               free_bootmem(__pa(xen_io_tlb_start), PAGE_ALIGN(bytes));
-               m = "Failed to get contiguous memory for DMA from Xen!\n"\
-                   "You either: don't have the permissions, do not have"\
-                   " enough free memory under 4GB, or the hypervisor memory"\
-                   "is too fragmented!";
+               if (early)
+                       free_bootmem(__pa(xen_io_tlb_start), PAGE_ALIGN(bytes));
+               else {
+                       free_pages((unsigned long)xen_io_tlb_start, order);
+                       xen_io_tlb_start = NULL;
+               }
+               m_ret = XEN_SWIOTLB_EFIXUP;
                goto error;
        }
        start_dma_addr = xen_virt_to_bus(xen_io_tlb_start);
-       swiotlb_init_with_tbl(xen_io_tlb_start, xen_io_tlb_nslabs, verbose);
-
-       return;
+       if (early) {
+               swiotlb_init_with_tbl(xen_io_tlb_start, xen_io_tlb_nslabs, verbose);
+               rc = 0;
+       } else
+               rc = swiotlb_late_init_with_tbl(xen_io_tlb_start, xen_io_tlb_nslabs);
+       return rc;
 error:
        if (repeat--) {
                xen_io_tlb_nslabs = max(1024UL, /* Min is 2MB */
@@ -198,10 +244,13 @@ error:
                      (xen_io_tlb_nslabs << IO_TLB_SHIFT) >> 20);
                goto retry;
        }
-       xen_raw_printk("%s (rc:%d)", m, rc);
-       panic("%s (rc:%d)", m, rc);
+       pr_err("%s (rc:%d)", xen_swiotlb_error(m_ret), rc);
+       if (early)
+               panic("%s (rc:%d)", xen_swiotlb_error(m_ret), rc);
+       else
+               free_pages((unsigned long)xen_io_tlb_start, order);
+       return rc;
 }
-
 void *
 xen_swiotlb_alloc_coherent(struct device *hwdev, size_t size,
                           dma_addr_t *dma_handle, gfp_t flags,
@@ -466,14 +515,6 @@ xen_swiotlb_map_sg_attrs(struct device *hwdev, struct scatterlist *sgl,
 }
 EXPORT_SYMBOL_GPL(xen_swiotlb_map_sg_attrs);
 
-int
-xen_swiotlb_map_sg(struct device *hwdev, struct scatterlist *sgl, int nelems,
-                  enum dma_data_direction dir)
-{
-       return xen_swiotlb_map_sg_attrs(hwdev, sgl, nelems, dir, NULL);
-}
-EXPORT_SYMBOL_GPL(xen_swiotlb_map_sg);
-
 /*
  * Unmap a set of streaming mode DMA translations.  Again, cpu read rules
  * concerning calls here are the same as for swiotlb_unmap_page() above.
@@ -494,14 +535,6 @@ xen_swiotlb_unmap_sg_attrs(struct device *hwdev, struct scatterlist *sgl,
 }
 EXPORT_SYMBOL_GPL(xen_swiotlb_unmap_sg_attrs);
 
-void
-xen_swiotlb_unmap_sg(struct device *hwdev, struct scatterlist *sgl, int nelems,
-                    enum dma_data_direction dir)
-{
-       return xen_swiotlb_unmap_sg_attrs(hwdev, sgl, nelems, dir, NULL);
-}
-EXPORT_SYMBOL_GPL(xen_swiotlb_unmap_sg);
-
 /*
  * Make physical memory consistent for a set of streaming mode DMA translations
  * after a transfer.
index fdb6d229c9bbf5e59198189f95e70502116a6ca2..5e5ad7e2885832f64f2131aa43aead50548cae0a 100644 (file)
@@ -114,7 +114,7 @@ static void xen_sysfs_version_destroy(void)
 
 /* UUID */
 
-static ssize_t uuid_show(struct hyp_sysfs_attr *attr, char *buffer)
+static ssize_t uuid_show_fallback(struct hyp_sysfs_attr *attr, char *buffer)
 {
        char *vm, *val;
        int ret;
@@ -135,6 +135,17 @@ static ssize_t uuid_show(struct hyp_sysfs_attr *attr, char *buffer)
        return ret;
 }
 
+static ssize_t uuid_show(struct hyp_sysfs_attr *attr, char *buffer)
+{
+       xen_domain_handle_t uuid;
+       int ret;
+       ret = HYPERVISOR_xen_version(XENVER_guest_handle, uuid);
+       if (ret)
+               return uuid_show_fallback(attr, buffer);
+       ret = sprintf(buffer, "%pU\n", uuid);
+       return ret;
+}
+
 HYPERVISOR_ATTR_RO(uuid);
 
 static int __init xen_sysfs_uuid_init(void)
index 89f264c67420c2448f9fe029e8193fa438369ae8..144564e5eb29e1ef59200fd079647656195280c8 100644 (file)
@@ -21,6 +21,7 @@
 #include <asm/xen/hypercall.h>
 #include <asm/xen/page.h>
 #include <asm/xen/hypervisor.h>
+#include <xen/tmem.h>
 
 #define TMEM_CONTROL               0
 #define TMEM_NEW_POOL              1
index 92ff01dbeb1036880dd747dae11d813a305dd569..961d664e2d2faacde4272fa83023919c6ebcf3ca 100644 (file)
@@ -362,6 +362,7 @@ static int __devinit pcistub_init_device(struct pci_dev *dev)
        else {
                dev_dbg(&dev->dev, "reseting (FLR, D3, etc) the device\n");
                __pci_reset_function_locked(dev);
+               pci_restore_state(dev);
        }
        /* Now disable the device (this also ensures some private device
         * data is setup before we export)
@@ -681,14 +682,14 @@ static pci_ers_result_t xen_pcibk_slot_reset(struct pci_dev *dev)
                dev_err(&dev->dev, DRV_NAME " device is not connected or owned"
                        " by HVM, kill it\n");
                kill_domain_by_device(psdev);
-               goto release;
+               goto end;
        }
 
        if (!test_bit(_XEN_PCIB_AERHANDLER,
                (unsigned long *)&psdev->pdev->sh_info->flags)) {
                dev_err(&dev->dev,
                        "guest with no AER driver should have been killed\n");
-               goto release;
+               goto end;
        }
        result = common_process(psdev, 1, XEN_PCI_OP_aer_slotreset, result);
 
@@ -698,9 +699,9 @@ static pci_ers_result_t xen_pcibk_slot_reset(struct pci_dev *dev)
                        "No AER slot_reset service or disconnected!\n");
                kill_domain_by_device(psdev);
        }
-release:
-       pcistub_device_put(psdev);
 end:
+       if (psdev)
+               pcistub_device_put(psdev);
        up_write(&pcistub_sem);
        return result;
 
@@ -739,14 +740,14 @@ static pci_ers_result_t xen_pcibk_mmio_enabled(struct pci_dev *dev)
                dev_err(&dev->dev, DRV_NAME " device is not connected or owned"
                        " by HVM, kill it\n");
                kill_domain_by_device(psdev);
-               goto release;
+               goto end;
        }
 
        if (!test_bit(_XEN_PCIB_AERHANDLER,
                (unsigned long *)&psdev->pdev->sh_info->flags)) {
                dev_err(&dev->dev,
                        "guest with no AER driver should have been killed\n");
-               goto release;
+               goto end;
        }
        result = common_process(psdev, 1, XEN_PCI_OP_aer_mmio, result);
 
@@ -756,9 +757,9 @@ static pci_ers_result_t xen_pcibk_mmio_enabled(struct pci_dev *dev)
                        "No AER mmio_enabled service or disconnected!\n");
                kill_domain_by_device(psdev);
        }
-release:
-       pcistub_device_put(psdev);
 end:
+       if (psdev)
+               pcistub_device_put(psdev);
        up_write(&pcistub_sem);
        return result;
 }
@@ -797,7 +798,7 @@ static pci_ers_result_t xen_pcibk_error_detected(struct pci_dev *dev,
                dev_err(&dev->dev, DRV_NAME " device is not connected or owned"
                        " by HVM, kill it\n");
                kill_domain_by_device(psdev);
-               goto release;
+               goto end;
        }
 
        /*Guest owns the device yet no aer handler regiested, kill guest*/
@@ -805,7 +806,7 @@ static pci_ers_result_t xen_pcibk_error_detected(struct pci_dev *dev,
                (unsigned long *)&psdev->pdev->sh_info->flags)) {
                dev_dbg(&dev->dev, "guest may have no aer driver, kill it\n");
                kill_domain_by_device(psdev);
-               goto release;
+               goto end;
        }
        result = common_process(psdev, error, XEN_PCI_OP_aer_detected, result);
 
@@ -815,9 +816,9 @@ static pci_ers_result_t xen_pcibk_error_detected(struct pci_dev *dev,
                        "No AER error_detected service or disconnected!\n");
                kill_domain_by_device(psdev);
        }
-release:
-       pcistub_device_put(psdev);
 end:
+       if (psdev)
+               pcistub_device_put(psdev);
        up_write(&pcistub_sem);
        return result;
 }
@@ -851,7 +852,7 @@ static void xen_pcibk_error_resume(struct pci_dev *dev)
                dev_err(&dev->dev, DRV_NAME " device is not connected or owned"
                        " by HVM, kill it\n");
                kill_domain_by_device(psdev);
-               goto release;
+               goto end;
        }
 
        if (!test_bit(_XEN_PCIB_AERHANDLER,
@@ -859,13 +860,13 @@ static void xen_pcibk_error_resume(struct pci_dev *dev)
                dev_err(&dev->dev,
                        "guest with no AER driver should have been killed\n");
                kill_domain_by_device(psdev);
-               goto release;
+               goto end;
        }
        common_process(psdev, 1, XEN_PCI_OP_aer_resume,
                       PCI_ERS_RESULT_RECOVERED);
-release:
-       pcistub_device_put(psdev);
 end:
+       if (psdev)
+               pcistub_device_put(psdev);
        up_write(&pcistub_sem);
        return;
 }
@@ -897,17 +898,41 @@ static inline int str_to_slot(const char *buf, int *domain, int *bus,
                              int *slot, int *func)
 {
        int err;
+       char wc = '*';
 
        err = sscanf(buf, " %x:%x:%x.%x", domain, bus, slot, func);
-       if (err == 4)
+       switch (err) {
+       case 3:
+               *func = -1;
+               err = sscanf(buf, " %x:%x:%x.%c", domain, bus, slot, &wc);
+               break;
+       case 2:
+               *slot = *func = -1;
+               err = sscanf(buf, " %x:%x:*.%c", domain, bus, &wc);
+               if (err >= 2)
+                       ++err;
+               break;
+       }
+       if (err == 4 && wc == '*')
                return 0;
        else if (err < 0)
                return -EINVAL;
 
        /* try again without domain */
        *domain = 0;
+       wc = '*';
        err = sscanf(buf, " %x:%x.%x", bus, slot, func);
-       if (err == 3)
+       switch (err) {
+       case 2:
+               *func = -1;
+               err = sscanf(buf, " %x:%x.%c", bus, slot, &wc);
+               break;
+       case 1:
+               *slot = *func = -1;
+               err = sscanf(buf, " %x:*.%c", bus, &wc) + 1;
+               break;
+       }
+       if (err == 3 && wc == '*')
                return 0;
 
        return -EINVAL;
@@ -930,6 +955,19 @@ static int pcistub_device_id_add(int domain, int bus, int slot, int func)
 {
        struct pcistub_device_id *pci_dev_id;
        unsigned long flags;
+       int rc = 0;
+
+       if (slot < 0) {
+               for (slot = 0; !rc && slot < 32; ++slot)
+                       rc = pcistub_device_id_add(domain, bus, slot, func);
+               return rc;
+       }
+
+       if (func < 0) {
+               for (func = 0; !rc && func < 8; ++func)
+                       rc = pcistub_device_id_add(domain, bus, slot, func);
+               return rc;
+       }
 
        pci_dev_id = kmalloc(sizeof(*pci_dev_id), GFP_KERNEL);
        if (!pci_dev_id)
@@ -952,15 +990,15 @@ static int pcistub_device_id_add(int domain, int bus, int slot, int func)
 static int pcistub_device_id_remove(int domain, int bus, int slot, int func)
 {
        struct pcistub_device_id *pci_dev_id, *t;
-       int devfn = PCI_DEVFN(slot, func);
        int err = -ENOENT;
        unsigned long flags;
 
        spin_lock_irqsave(&device_ids_lock, flags);
        list_for_each_entry_safe(pci_dev_id, t, &pcistub_device_ids,
                                 slot_list) {
-               if (pci_dev_id->domain == domain
-                   && pci_dev_id->bus == bus && pci_dev_id->devfn == devfn) {
+               if (pci_dev_id->domain == domain && pci_dev_id->bus == bus
+                   && (slot < 0 || PCI_SLOT(pci_dev_id->devfn) == slot)
+                   && (func < 0 || PCI_FUNC(pci_dev_id->devfn) == func)) {
                        /* Don't break; here because it's possible the same
                         * slot could be in the list more than once
                         */
@@ -987,7 +1025,7 @@ static int pcistub_reg_add(int domain, int bus, int slot, int func, int reg,
        struct config_field *field;
 
        psdev = pcistub_device_find(domain, bus, slot, func);
-       if (!psdev || !psdev->dev) {
+       if (!psdev) {
                err = -ENODEV;
                goto out;
        }
@@ -1011,6 +1049,8 @@ static int pcistub_reg_add(int domain, int bus, int slot, int func, int reg,
        if (err)
                kfree(field);
 out:
+       if (psdev)
+               pcistub_device_put(psdev);
        return err;
 }
 
@@ -1115,10 +1155,9 @@ static ssize_t pcistub_irq_handler_switch(struct device_driver *drv,
 
        err = str_to_slot(buf, &domain, &bus, &slot, &func);
        if (err)
-               goto out;
+               return err;
 
        psdev = pcistub_device_find(domain, bus, slot, func);
-
        if (!psdev)
                goto out;
 
@@ -1134,6 +1173,8 @@ static ssize_t pcistub_irq_handler_switch(struct device_driver *drv,
        if (dev_data->isr_on)
                dev_data->ack_intr = 1;
 out:
+       if (psdev)
+               pcistub_device_put(psdev);
        if (!err)
                err = count;
        return err;
@@ -1216,15 +1257,16 @@ static ssize_t permissive_add(struct device_driver *drv, const char *buf,
        err = str_to_slot(buf, &domain, &bus, &slot, &func);
        if (err)
                goto out;
+       if (slot < 0 || func < 0) {
+               err = -EINVAL;
+               goto out;
+       }
        psdev = pcistub_device_find(domain, bus, slot, func);
        if (!psdev) {
                err = -ENODEV;
                goto out;
        }
-       if (!psdev->dev) {
-               err = -ENODEV;
-               goto release;
-       }
+
        dev_data = pci_get_drvdata(psdev->dev);
        /* the driver data for a device should never be null at this point */
        if (!dev_data) {
@@ -1297,17 +1339,51 @@ static int __init pcistub_init(void)
 
        if (pci_devs_to_hide && *pci_devs_to_hide) {
                do {
+                       char wc = '*';
+
                        parsed = 0;
 
                        err = sscanf(pci_devs_to_hide + pos,
                                     " (%x:%x:%x.%x) %n",
                                     &domain, &bus, &slot, &func, &parsed);
-                       if (err != 4) {
+                       switch (err) {
+                       case 3:
+                               func = -1;
+                               err = sscanf(pci_devs_to_hide + pos,
+                                            " (%x:%x:%x.%c) %n",
+                                            &domain, &bus, &slot, &wc,
+                                            &parsed);
+                               break;
+                       case 2:
+                               slot = func = -1;
+                               err = sscanf(pci_devs_to_hide + pos,
+                                            " (%x:%x:*.%c) %n",
+                                            &domain, &bus, &wc, &parsed) + 1;
+                               break;
+                       }
+
+                       if (err != 4 || wc != '*') {
                                domain = 0;
+                               wc = '*';
                                err = sscanf(pci_devs_to_hide + pos,
                                             " (%x:%x.%x) %n",
                                             &bus, &slot, &func, &parsed);
-                               if (err != 3)
+                               switch (err) {
+                               case 2:
+                                       func = -1;
+                                       err = sscanf(pci_devs_to_hide + pos,
+                                                    " (%x:%x.%c) %n",
+                                                    &bus, &slot, &wc,
+                                                    &parsed);
+                                       break;
+                               case 1:
+                                       slot = func = -1;
+                                       err = sscanf(pci_devs_to_hide + pos,
+                                                    " (%x:*.%c) %n",
+                                                    &bus, &wc, &parsed) + 1;
+                                       break;
+                               }
+                               if (err != 3 || wc != '*')
                                        goto parse_error;
                        }
 
index 52fe7ad076669ce40992d0d423c26c37f1568819..c5aa55c5d371e495e1a5c4a39051225d5fc27dd7 100644 (file)
@@ -224,7 +224,7 @@ int xb_init_comms(void)
                int err;
                err = bind_evtchn_to_irqhandler(xen_store_evtchn, wake_waiting,
                                                0, "xenbus", &xb_waitq);
-               if (err <= 0) {
+               if (err < 0) {
                        printk(KERN_ERR "XENBUS request irq failed %i\n", err);
                        return err;
                }
index be738c43104bea15dfca7422055d2f0cd79ecf9f..d730008007624b4227780457a96c77f8662c248e 100644 (file)
@@ -107,7 +107,7 @@ static int xenbus_backend_mmap(struct file *file, struct vm_area_struct *vma)
        return 0;
 }
 
-const struct file_operations xenbus_backend_fops = {
+static const struct file_operations xenbus_backend_fops = {
        .open = xenbus_backend_open,
        .mmap = xenbus_backend_mmap,
        .unlocked_ioctl = xenbus_backend_ioctl,
index b793723e724de767ad7cf9abac808548d78a21ba..038b71dbf03c980fd9024284f2e5cca1bfb3db95 100644 (file)
@@ -324,8 +324,8 @@ static int cmp_dev(struct device *dev, void *data)
        return 0;
 }
 
-struct xenbus_device *xenbus_device_find(const char *nodename,
-                                        struct bus_type *bus)
+static struct xenbus_device *xenbus_device_find(const char *nodename,
+                                               struct bus_type *bus)
 {
        struct xb_find_info info = { .dev = NULL, .nodename = nodename };
 
@@ -719,17 +719,47 @@ static int __init xenstored_local_init(void)
        return err;
 }
 
+enum xenstore_init {
+       UNKNOWN,
+       PV,
+       HVM,
+       LOCAL,
+};
 static int __init xenbus_init(void)
 {
        int err = 0;
+       enum xenstore_init usage = UNKNOWN;
+       uint64_t v = 0;
 
        if (!xen_domain())
                return -ENODEV;
 
        xenbus_ring_ops_init();
 
-       if (xen_hvm_domain()) {
-               uint64_t v = 0;
+       if (xen_pv_domain())
+               usage = PV;
+       if (xen_hvm_domain())
+               usage = HVM;
+       if (xen_hvm_domain() && xen_initial_domain())
+               usage = LOCAL;
+       if (xen_pv_domain() && !xen_start_info->store_evtchn)
+               usage = LOCAL;
+       if (xen_pv_domain() && xen_start_info->store_evtchn)
+               xenstored_ready = 1;
+
+       switch (usage) {
+       case LOCAL:
+               err = xenstored_local_init();
+               if (err)
+                       goto out_error;
+               xen_store_interface = mfn_to_virt(xen_store_mfn);
+               break;
+       case PV:
+               xen_store_evtchn = xen_start_info->store_evtchn;
+               xen_store_mfn = xen_start_info->store_mfn;
+               xen_store_interface = mfn_to_virt(xen_store_mfn);
+               break;
+       case HVM:
                err = hvm_get_parameter(HVM_PARAM_STORE_EVTCHN, &v);
                if (err)
                        goto out_error;
@@ -738,18 +768,12 @@ static int __init xenbus_init(void)
                if (err)
                        goto out_error;
                xen_store_mfn = (unsigned long)v;
-               xen_store_interface = ioremap(xen_store_mfn << PAGE_SHIFT, PAGE_SIZE);
-       } else {
-               xen_store_evtchn = xen_start_info->store_evtchn;
-               xen_store_mfn = xen_start_info->store_mfn;
-               if (xen_store_evtchn)
-                       xenstored_ready = 1;
-               else {
-                       err = xenstored_local_init();
-                       if (err)
-                               goto out_error;
-               }
-               xen_store_interface = mfn_to_virt(xen_store_mfn);
+               xen_store_interface =
+                       ioremap(xen_store_mfn << PAGE_SHIFT, PAGE_SIZE);
+               break;
+       default:
+               pr_warn("Xenstore state unknown\n");
+               break;
        }
 
        /* Initialize the interface to xenstore. */
index a31b54d488398675fc01eaa2878f0a21ec49fe46..3159a37d966d57755b6bd6d0d2a19379309c7e6e 100644 (file)
@@ -21,6 +21,7 @@
 #include <xen/xenbus.h>
 #include <xen/events.h>
 #include <xen/page.h>
+#include <xen/xen.h>
 
 #include <xen/platform_pci.h>
 
index bce15cf4a8df1708a5237a12e7223ca56b093e8f..131dec04794ee3ee1af70c2fd3f1dd2220774070 100644 (file)
@@ -44,6 +44,7 @@
 #include <linux/rwsem.h>
 #include <linux/module.h>
 #include <linux/mutex.h>
+#include <asm/xen/hypervisor.h>
 #include <xen/xenbus.h>
 #include <xen/xen.h>
 #include "xenbus_comms.h"
@@ -622,7 +623,7 @@ static void xs_reset_watches(void)
 {
        int err, supported = 0;
 
-       if (!xen_hvm_domain())
+       if (!xen_hvm_domain() || xen_initial_domain())
                return;
 
        err = xenbus_scanf(XBT_NIL, "control",
index e872526fdc5fbb371ca0e420a961aec4738fdfa2..8d08b3ed406db688c6fa8c1cfe10d921870d2e72 100644 (file)
@@ -25,6 +25,7 @@ extern int swiotlb_force;
 extern void swiotlb_init(int verbose);
 extern void swiotlb_init_with_tbl(char *tlb, unsigned long nslabs, int verbose);
 extern unsigned long swiotlb_nr_tbl(void);
+extern int swiotlb_late_init_with_tbl(char *tlb, unsigned long nslabs);
 
 /*
  * Enumeration for sync targets
index 04399b28e821bf694a58d706e0b6c9f66e9c7d9f..c6bfe01acf6b4f4952f42ea171b68947c87ff16f 100644 (file)
@@ -109,4 +109,6 @@ int xen_irq_from_gsi(unsigned gsi);
 /* Determine whether to ignore this IRQ if it is passed to a guest. */
 int xen_test_irq_shared(int irq);
 
+/* initialize Xen IRQ subsystem */
+void xen_init_IRQ(void);
 #endif /* _XEN_EVENTS_H */
index b6ca39a069d80c984962db4659e2f9bbe3256573..131a6ccdba25693e6899b7813d99a6934e846ce4 100644 (file)
@@ -50,6 +50,9 @@
 /* x86: pirq can be used by HVM guests */
 #define XENFEAT_hvm_pirqs           10
 
+/* operation as Dom0 is supported */
+#define XENFEAT_dom0                      11
+
 #define XENFEAT_NR_SUBMAPS 1
 
 #endif /* __XEN_PUBLIC_FEATURES_H__ */
index a17d84433e6a1ab54e660fc4f25493a180ce15f2..f9f8b975ae7448bfdae47100ad7da63a34fbe39b 100644 (file)
@@ -338,7 +338,7 @@ DEFINE_GUEST_HANDLE_STRUCT(gnttab_dump_table);
 #define GNTTABOP_transfer                4
 struct gnttab_transfer {
     /* IN parameters. */
-    unsigned long mfn;
+    xen_pfn_t mfn;
     domid_t       domid;
     grant_ref_t   ref;
     /* OUT parameters. */
@@ -375,7 +375,7 @@ struct gnttab_copy {
        struct {
                union {
                        grant_ref_t ref;
-                       unsigned long   gmfn;
+                       xen_pfn_t   gmfn;
                } u;
                domid_t  domid;
                uint16_t offset;
@@ -519,7 +519,9 @@ DEFINE_GUEST_HANDLE_STRUCT(gnttab_get_version);
 #define GNTST_no_device_space  (-7) /* Out of space in I/O MMU.              */
 #define GNTST_permission_denied (-8) /* Not enough privilege for operation.  */
 #define GNTST_bad_page         (-9) /* Specified page was invalid for op.    */
-#define GNTST_bad_copy_arg    (-10) /* copy arguments cross page boundary */
+#define GNTST_bad_copy_arg    (-10) /* copy arguments cross page boundary.   */
+#define GNTST_address_too_big (-11) /* transfer page address too large.      */
+#define GNTST_eagain          (-12) /* Operation not done; try again.        */
 
 #define GNTTABOP_error_msgs {                   \
     "okay",                                     \
@@ -532,7 +534,9 @@ DEFINE_GUEST_HANDLE_STRUCT(gnttab_get_version);
     "no spare translation slot in the I/O MMU", \
     "permission denied",                        \
     "bad page",                                 \
-    "copy arguments cross page boundary"        \
+    "copy arguments cross page boundary",       \
+    "page address size too large",              \
+    "operation not done; try again"             \
 }
 
 #endif /* __XEN_PUBLIC_GRANT_TABLE_H__ */
index 01fc8ae5f0b06f9d96ed76852152a5ef64cf5d63..0eafaf254fff0e282e4fe340ede1950a5d9e86cb 100644 (file)
@@ -5,6 +5,7 @@
 #define XEN_IO_PROTO_ABI_X86_64     "x86_64-abi"
 #define XEN_IO_PROTO_ABI_IA64       "ia64-abi"
 #define XEN_IO_PROTO_ABI_POWERPC64  "powerpc64-abi"
+#define XEN_IO_PROTO_ABI_ARM        "arm-abi"
 
 #if defined(__i386__)
 # define XEN_IO_PROTO_ABI_NATIVE XEN_IO_PROTO_ABI_X86_32
@@ -14,6 +15,8 @@
 # define XEN_IO_PROTO_ABI_NATIVE XEN_IO_PROTO_ABI_IA64
 #elif defined(__powerpc64__)
 # define XEN_IO_PROTO_ABI_NATIVE XEN_IO_PROTO_ABI_POWERPC64
+#elif defined(__arm__)
+# define XEN_IO_PROTO_ABI_NATIVE XEN_IO_PROTO_ABI_ARM
 #else
 # error arch fixup needed here
 #endif
index eac3ce1537190228ba8dc74f0398d8e6e4795572..b66d04ce6957549a1097c532bc483e5ee6ab38d8 100644 (file)
@@ -31,10 +31,10 @@ struct xen_memory_reservation {
      *   OUT: GMFN bases of extents that were allocated
      *   (NB. This command also updates the mach_to_phys translation table)
      */
-    GUEST_HANDLE(ulong) extent_start;
+    GUEST_HANDLE(xen_pfn_t) extent_start;
 
     /* Number of extents, and size/alignment of each (2^extent_order pages). */
-    unsigned long  nr_extents;
+    xen_ulong_t  nr_extents;
     unsigned int   extent_order;
 
     /*
@@ -92,7 +92,7 @@ struct xen_memory_exchange {
      *     command will be non-zero.
      *  5. THIS FIELD MUST BE INITIALISED TO ZERO BY THE CALLER!
      */
-    unsigned long nr_exchanged;
+    xen_ulong_t nr_exchanged;
 };
 
 DEFINE_GUEST_HANDLE_STRUCT(xen_memory_exchange);
@@ -130,7 +130,7 @@ struct xen_machphys_mfn_list {
      * any large discontiguities in the machine address space, 2MB gaps in
      * the machphys table will be represented by an MFN base of zero.
      */
-    GUEST_HANDLE(ulong) extent_start;
+    GUEST_HANDLE(xen_pfn_t) extent_start;
 
     /*
      * Number of extents written to the above array. This will be smaller
@@ -148,8 +148,8 @@ DEFINE_GUEST_HANDLE_STRUCT(xen_machphys_mfn_list);
  */
 #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. */
+    xen_ulong_t v_start, v_end; /* Start and end virtual addresses.   */
+    xen_ulong_t max_mfn;        /* Maximum MFN that can be looked up. */
 };
 DEFINE_GUEST_HANDLE_STRUCT(xen_machphys_mapping_t);
 
@@ -163,16 +163,19 @@ struct xen_add_to_physmap {
     /* Which domain to change the mapping for. */
     domid_t domid;
 
+    /* Number of pages to go through for gmfn_range */
+    uint16_t    size;
+
     /* Source mapping space. */
 #define XENMAPSPACE_shared_info 0 /* shared info page */
 #define XENMAPSPACE_grant_table 1 /* grant table page */
     unsigned int space;
 
     /* Index into source mapping space. */
-    unsigned long idx;
+    xen_ulong_t idx;
 
     /* GPFN where the source mapping page should appear. */
-    unsigned long gpfn;
+    xen_pfn_t gpfn;
 };
 DEFINE_GUEST_HANDLE_STRUCT(xen_add_to_physmap);
 
@@ -186,7 +189,7 @@ struct xen_translate_gpfn_list {
     domid_t domid;
 
     /* Length of list. */
-    unsigned long nr_gpfns;
+    xen_ulong_t nr_gpfns;
 
     /* List of GPFNs to translate. */
     GUEST_HANDLE(ulong) gpfn_list;
index bfa1d50fe15bed0c5d2b37d392454ce5e6d56d02..1844d31f45520fef57c93be90ba7e247e1a0b042 100644 (file)
@@ -56,7 +56,7 @@ struct physdev_eoi {
 #define PHYSDEVOP_pirq_eoi_gmfn_v2       28
 struct physdev_pirq_eoi_gmfn {
     /* IN */
-    unsigned long gmfn;
+    xen_ulong_t gmfn;
 };
 
 /*
index 61fa66160983882ff5c26eccb9b7fc01ce0c2130..54ad6f9e4725635fbaa7cdde363f2bf540a48141 100644 (file)
@@ -54,7 +54,7 @@ DEFINE_GUEST_HANDLE_STRUCT(xenpf_settime_t);
 #define XENPF_add_memtype         31
 struct xenpf_add_memtype {
        /* IN variables. */
-       unsigned long mfn;
+       xen_pfn_t mfn;
        uint64_t nr_mfns;
        uint32_t type;
        /* OUT variables. */
@@ -84,7 +84,7 @@ struct xenpf_read_memtype {
        /* IN variables. */
        uint32_t reg;
        /* OUT variables. */
-       unsigned long mfn;
+       xen_pfn_t mfn;
        uint64_t nr_mfns;
        uint32_t type;
 };
@@ -112,6 +112,7 @@ DEFINE_GUEST_HANDLE_STRUCT(xenpf_platform_quirk_t);
 #define XEN_FW_DISK_INFO          1 /* from int 13 AH=08/41/48 */
 #define XEN_FW_DISK_MBR_SIGNATURE 2 /* from MBR offset 0x1b8 */
 #define XEN_FW_VBEDDC_INFO        3 /* from int 10 AX=4f15 */
+#define XEN_FW_KBD_SHIFT_FLAGS    5 /* Int16, Fn02: Get keyboard shift flags. */
 struct xenpf_firmware_info {
        /* IN variables. */
        uint32_t type;
@@ -142,6 +143,8 @@ struct xenpf_firmware_info {
                        /* must refer to 128-byte buffer */
                        GUEST_HANDLE(uchar) edid;
                } vbeddc_info; /* XEN_FW_VBEDDC_INFO */
+
+               uint8_t kbd_shift_flags; /* XEN_FW_KBD_SHIFT_FLAGS */
        } u;
 };
 DEFINE_GUEST_HANDLE_STRUCT(xenpf_firmware_info_t);
index e8b6519d47e9df818ebbb6d19323f032b8dde988..3030c81c09cec133e467500db5f96fc973888ec2 100644 (file)
@@ -45,7 +45,7 @@ struct xen_changeset_info {
 
 #define XENVER_platform_parameters 5
 struct xen_platform_parameters {
-    unsigned long virt_start;
+    xen_ulong_t virt_start;
 };
 
 #define XENVER_get_features 6
@@ -60,4 +60,7 @@ struct xen_feature_info {
 /* arg == NULL; returns host memory page size. */
 #define XENVER_pagesize 7
 
+/* arg == xen_domain_handle_t. */
+#define XENVER_guest_handle 8
+
 #endif /* __XEN_PUBLIC_VERSION_H__ */
index 0801468f9abed879eb1b9b1d52363aaeb979a2ae..886a5d80a18fdcbaa572c8350a400d59ab4455ba 100644 (file)
@@ -10,7 +10,6 @@
 #define __XEN_PUBLIC_XEN_H__
 
 #include <asm/xen/interface.h>
-#include <asm/pvclock-abi.h>
 
 /*
  * XEN "SYSTEM CALLS" (a.k.a. HYPERCALLS).
@@ -190,7 +189,7 @@ struct mmuext_op {
        unsigned int cmd;
        union {
                /* [UN]PIN_TABLE, NEW_BASEPTR, NEW_USER_BASEPTR */
-               unsigned long mfn;
+               xen_pfn_t mfn;
                /* INVLPG_LOCAL, INVLPG_ALL, SET_LDT */
                unsigned long linear_addr;
        } arg1;
@@ -430,11 +429,11 @@ struct start_info {
        unsigned long nr_pages;     /* Total pages allocated to this domain.  */
        unsigned long shared_info;  /* MACHINE address of shared info struct. */
        uint32_t flags;             /* SIF_xxx flags.                         */
-       unsigned long store_mfn;    /* MACHINE page number of shared page.    */
+       xen_pfn_t store_mfn;        /* MACHINE page number of shared page.    */
        uint32_t store_evtchn;      /* Event channel for store communication. */
        union {
                struct {
-                       unsigned long mfn;  /* MACHINE page number of console page.   */
+                       xen_pfn_t mfn;      /* MACHINE page number of console page.   */
                        uint32_t  evtchn;   /* Event channel for console page.        */
                } domU;
                struct {
@@ -455,6 +454,7 @@ struct dom0_vga_console_info {
        uint8_t video_type;
 #define XEN_VGATYPE_TEXT_MODE_3 0x03
 #define XEN_VGATYPE_VESA_LFB    0x23
+#define XEN_VGATYPE_EFI_LFB     0x70
 
        union {
                struct {
index 17857fb4d5509b24a475609e2806af53c79d5317..a85316811d79ad43493d21c1e35d51ed10aa257c 100644 (file)
@@ -35,8 +35,7 @@
 
 #include <linux/types.h>
 #include <linux/compiler.h>
-
-typedef unsigned long xen_pfn_t;
+#include <xen/interface/xen.h>
 
 struct privcmd_hypercall {
        __u64 op;
@@ -59,13 +58,33 @@ struct privcmd_mmapbatch {
        int num;     /* number of pages to populate */
        domid_t dom; /* target domain */
        __u64 addr;  /* virtual address */
-       xen_pfn_t __user *arr; /* array of mfns - top nibble set on err */
+       xen_pfn_t __user *arr; /* array of mfns - or'd with
+                                 PRIVCMD_MMAPBATCH_*_ERROR on err */
+};
+
+#define PRIVCMD_MMAPBATCH_MFN_ERROR     0xf0000000U
+#define PRIVCMD_MMAPBATCH_PAGED_ERROR   0x80000000U
+
+struct privcmd_mmapbatch_v2 {
+       unsigned int num; /* number of pages to populate */
+       domid_t dom;      /* target domain */
+       __u64 addr;       /* virtual address */
+       const xen_pfn_t __user *arr; /* array of mfns */
+       int __user *err;  /* array of error codes */
 };
 
 /*
  * @cmd: IOCTL_PRIVCMD_HYPERCALL
  * @arg: &privcmd_hypercall_t
  * Return: Value returned from execution of the specified hypercall.
+ *
+ * @cmd: IOCTL_PRIVCMD_MMAPBATCH_V2
+ * @arg: &struct privcmd_mmapbatch_v2
+ * Return: 0 on success (i.e., arg->err contains valid error codes for
+ * each frame).  On an error other than a failed frame remap, -1 is
+ * returned and errno is set to EINVAL, EFAULT etc.  As an exception,
+ * if the operation was otherwise successful but any frame failed with
+ * -ENOENT, then -1 is returned and errno is set to ENOENT.
  */
 #define IOCTL_PRIVCMD_HYPERCALL                                        \
        _IOC(_IOC_NONE, 'P', 0, sizeof(struct privcmd_hypercall))
@@ -73,5 +92,7 @@ struct privcmd_mmapbatch {
        _IOC(_IOC_NONE, 'P', 2, sizeof(struct privcmd_mmap))
 #define IOCTL_PRIVCMD_MMAPBATCH                                        \
        _IOC(_IOC_NONE, 'P', 3, sizeof(struct privcmd_mmapbatch))
+#define IOCTL_PRIVCMD_MMAPBATCH_V2                             \
+       _IOC(_IOC_NONE, 'P', 4, sizeof(struct privcmd_mmapbatch_v2))
 
 #endif /* __LINUX_PUBLIC_PRIVCMD_H__ */
index 4f4d449f00f6b98644be40b85f108667c4cb1642..de8bcc641c49ae64c6971c11b792b696216cce0a 100644 (file)
@@ -3,7 +3,7 @@
 
 #include <linux/swiotlb.h>
 
-extern void xen_swiotlb_init(int verbose);
+extern int xen_swiotlb_init(int verbose, bool early);
 
 extern void
 *xen_swiotlb_alloc_coherent(struct device *hwdev, size_t size,
@@ -23,15 +23,6 @@ extern dma_addr_t xen_swiotlb_map_page(struct device *dev, struct page *page,
 extern void xen_swiotlb_unmap_page(struct device *hwdev, dma_addr_t dev_addr,
                                   size_t size, enum dma_data_direction dir,
                                   struct dma_attrs *attrs);
-/*
-extern int
-xen_swiotlb_map_sg(struct device *hwdev, struct scatterlist *sg, int nents,
-                  enum dma_data_direction dir);
-
-extern void
-xen_swiotlb_unmap_sg(struct device *hwdev, struct scatterlist *sg, int nents,
-                    enum dma_data_direction dir);
-*/
 extern int
 xen_swiotlb_map_sg_attrs(struct device *hwdev, struct scatterlist *sgl,
                         int nelems, enum dma_data_direction dir,
index a16402418d314710cf8281a28b5023cc06be94a1..2c0d3a56c749c6145e07ef6537355bebd45a4c89 100644 (file)
@@ -23,7 +23,7 @@ extern enum xen_domain_type xen_domain_type;
 #include <xen/interface/xen.h>
 #include <asm/xen/hypervisor.h>
 
-#define xen_initial_domain()   (xen_pv_domain() && \
+#define xen_initial_domain()   (xen_domain() && \
                                 xen_start_info->flags & SIF_INITDOMAIN)
 #else  /* !CONFIG_XEN_DOM0 */
 #define xen_initial_domain()   (0)
index 45bc1f83a5ada665297bc0b9dcd3a6ad72e2ec72..f114bf6a8e1363dc812cfa4fd8e6ae66a1411575 100644 (file)
@@ -170,7 +170,7 @@ void __init swiotlb_init_with_tbl(char *tlb, unsigned long nslabs, int verbose)
  * Statically reserve bounce buffer space and initialize bounce buffer data
  * structures for the software IO TLB used to implement the DMA API.
  */
-void __init
+static void __init
 swiotlb_init_with_default_size(size_t default_size, int verbose)
 {
        unsigned long bytes;
@@ -206,8 +206,9 @@ swiotlb_init(int verbose)
 int
 swiotlb_late_init_with_default_size(size_t default_size)
 {
-       unsigned long i, bytes, req_nslabs = io_tlb_nslabs;
+       unsigned long bytes, req_nslabs = io_tlb_nslabs;
        unsigned int order;
+       int rc = 0;
 
        if (!io_tlb_nslabs) {
                io_tlb_nslabs = (default_size >> IO_TLB_SHIFT);
@@ -229,16 +230,32 @@ swiotlb_late_init_with_default_size(size_t default_size)
                order--;
        }
 
-       if (!io_tlb_start)
-               goto cleanup1;
-
+       if (!io_tlb_start) {
+               io_tlb_nslabs = req_nslabs;
+               return -ENOMEM;
+       }
        if (order != get_order(bytes)) {
                printk(KERN_WARNING "Warning: only able to allocate %ld MB "
                       "for software IO TLB\n", (PAGE_SIZE << order) >> 20);
                io_tlb_nslabs = SLABS_PER_PAGE << order;
-               bytes = io_tlb_nslabs << IO_TLB_SHIFT;
        }
+       rc = swiotlb_late_init_with_tbl(io_tlb_start, io_tlb_nslabs);
+       if (rc)
+               free_pages((unsigned long)io_tlb_start, order);
+       return rc;
+}
+
+int
+swiotlb_late_init_with_tbl(char *tlb, unsigned long nslabs)
+{
+       unsigned long i, bytes;
+
+       bytes = nslabs << IO_TLB_SHIFT;
+
+       io_tlb_nslabs = nslabs;
+       io_tlb_start = tlb;
        io_tlb_end = io_tlb_start + bytes;
+
        memset(io_tlb_start, 0, bytes);
 
        /*
@@ -288,10 +305,8 @@ cleanup3:
        io_tlb_list = NULL;
 cleanup2:
        io_tlb_end = NULL;
-       free_pages((unsigned long)io_tlb_start, order);
        io_tlb_start = NULL;
-cleanup1:
-       io_tlb_nslabs = req_nslabs;
+       io_tlb_nslabs = 0;
        return -ENOMEM;
 }