Skip to contentSkip to conversation

xen: Xen paravirt_ops implementation

PATCH In review Jeremy Fitzhardinge 5 participants 62 messages May 22, 2007 – Jun 6, 2007

Subsystems (10)
lore
Share & tools
lore
#0 lore raw

cover xen: Xen paravirt_ops implementation

Hi,

This is the Xen implementation for the paravirt_ops interface. The series is based on 2.6.22-rc1-mm1, and I think its ready to be cooked in -mm with a view to being merged in 2.6.23.

The first part of the series is some small changes to the core kernel. Apart from the new code added in "Allocate and free vmalloc areas" (posted many times before), they are simply a few one-liners around the place.

paravirt: add an "mm" argument to alloc_pt
paravirt: add a hook for once the allocator is ready
paravirt: increase IRQ limit
paravirt: unstatic leave_mm
paravirt: unstatic smp_store_cpu_info
paravirt: make siblingmap functions visible
paravirt: export __supported_pte_mask
xen: Allocate and free vmalloc areas

 arch/i386/kernel/setup.c                           |    2 
 arch/i386/kernel/smp.c                             |    5 -
 arch/i386/kernel/smpboot.c                         |    8 -
 arch/i386/kernel/vsyscall-note.S                   |   28 +++++
 arch/i386/mm/init.c                                |    1 
 include/asm-i386/mach-default/irq_vectors_limits.h |    2 
 include/asm-i386/mmu_context.h                     |    2 
 include/asm-i386/paravirt.h                        |    8 +
 include/asm-i386/setup.h                           |    4 
 include/asm-i386/smp.h                             |    5 +
 include/linux/vmalloc.h                            |    4 
 mm/vmalloc.c                                       |   53 +++++++++++
 12 files changed, 114 insertions(+), 8 deletions(-)

The rest of the series is the Xen implementation itself. This includes the core of Xen itself, plus the Xenbus virtual bus, and virtual console, disk and net drivers. The vast majority of it is new code, with a few changes to non-Xen files to:

1. Makefile/Kconfig build stuff
2. add a new ELF note to the VDSO to select a Xen-optimised libc
3. a chunk of new code in entry.S, to handle upcalls from Xen, which in turn need to jump into other entry.S labels
4. Define a proper label for PG_owner_priv_1
5. Define a major for the Xen virtual block device
6. Increate NR_IRQ to 224 when CONFIG_PARAVIRT is enabled, even if there's no IO APIC.

xen: Add nosegneg capability to the vsyscall page notes
xen: Add Xen interface header files
xen: Core Xen implementation
xen: Xen virtual mmu
xen: xen event channels
xen: xen time implementation
xen: xen configuration
xen: add pinned page flag
xen: Complete pagetable pinning for Xen
xen: ignore RW mapping of RO pages in pagetable_init
xen: Account for time stolen by Xen
xen: Implement xen_sched_clock
xen: Xen SMP guest support
xen: Add support for preemption
xen: lazy-mmu operations
xen: hack to prevent bad segment register reload
xen: Use the hvc console infrastructure for Xen console
xen: Add Xen grant table support
xen: Add the Xenbus sysfs and virtual device hotplug driver.
xen: Add Xen virtual block device driver.
xen: Add the Xen virtual network device driver.
xen: Xen machine operations
xen: handle external requests for shutdown, reboot and sysrq
xen: Place vcpu_info structure into per-cpu memory, if possible
xen: Attempt to patch inline versions of common operations

 arch/i386/Kconfig                     |    2 
 arch/i386/Makefile                    |    3 
 arch/i386/kernel/asm-offsets.c        |    7 
 arch/i386/kernel/entry.S              |   71 
 arch/i386/kernel/head.S               |    5 
 arch/i386/kernel/vmlinux.lds.S        |    1 
 arch/i386/xen/Kconfig                 |   11 
 arch/i386/xen/Makefile                |    4 
 arch/i386/xen/enlighten.c             | 1134 +++++++++++++
 arch/i386/xen/events.c                |  588 +++++++
 arch/i386/xen/features.c              |   29 
 arch/i386/xen/manage.c                |  143 +
 arch/i386/xen/mmu.c                   |  599 +++++++
 arch/i386/xen/mmu.h                   |   60 
 arch/i386/xen/multicalls.c            |  115 +
 arch/i386/xen/multicalls.h            |   45 
 arch/i386/xen/setup.c                 |   93 +
 arch/i386/xen/smp.c                   |  405 ++++
 arch/i386/xen/time.c                  |  585 +++++++
 arch/i386/xen/xen-asm.S               |  114 +
 arch/i386/xen/xen-head.S              |   36 
 arch/i386/xen/xen-ops.h               |   70 
 arch/x86_64/kernel/early_printk.c     |    5 
 drivers/Makefile                      |    2 
 drivers/block/Kconfig                 |    8 
 drivers/block/Makefile                |    1 
 drivers/block/xen-blkfront.c          |  988 +++++++++++
 drivers/char/Kconfig                  |    8 
 drivers/char/Makefile                 |    1 
 drivers/char/hvc_xen.c                |  159 +
 drivers/net/Kconfig                   |   12 
 drivers/net/Makefile                  |    1 
 drivers/net/xen-netfront.c            | 1995 ++++++++++++++++++++++++
 drivers/xen/Makefile                  |    2 
 drivers/xen/grant-table.c             |  582 +++++++
 drivers/xen/xenbus/Makefile           |    7 
 drivers/xen/xenbus/xenbus_client.c    |  569 ++++++
 drivers/xen/xenbus/xenbus_comms.c     |  233 ++
 drivers/xen/xenbus/xenbus_comms.h     |   46 
 drivers/xen/xenbus/xenbus_probe.c     |  935 +++++++++++
 drivers/xen/xenbus/xenbus_probe.h     |   74 
 drivers/xen/xenbus/xenbus_xs.c        |  861 ++++++++++
 include/asm-i386/irq.h                |    1 
 include/asm-i386/xen/hypercall.h      |  431 +++++
 include/asm-i386/xen/hypervisor.h     |   73 
 include/asm-i386/xen/interface.h      |  187 ++
 include/linux/major.h                 |    2 
 include/linux/page-flags.h            |    5 
 include/xen/events.h                  |   48 
 include/xen/features.h                |   23 
 include/xen/grant_table.h             |  107 +
 include/xen/hvc-console.h             |    6 
 include/xen/interface/elfnote.h       |  133 +
 include/xen/interface/event_channel.h |  195 ++
 include/xen/interface/features.h      |   43 
 include/xen/interface/grant_table.h   |  375 ++++
 include/xen/interface/io/blkif.h      |   94 +
 include/xen/interface/io/console.h    |   23 
 include/xen/interface/io/netif.h      |  156 +
 include/xen/interface/io/ring.h       |  260 +++
 include/xen/interface/io/xenbus.h     |   42 
 include/xen/interface/io/xs_wire.h    |   87 +
 include/xen/interface/memory.h        |  145 +
 include/xen/interface/physdev.h       |  145 +
 include/xen/interface/sched.h         |   77 
 include/xen/interface/vcpu.h          |  177 ++
 include/xen/interface/version.h       |   60 
 include/xen/interface/xen.h           |  446 +++++
 include/xen/page.h                    |  178 ++
 include/xen/xenbus.h                  |  234 ++
 70 files changed, 14361 insertions(+), 1 deletion(-)
#1 lore raw

PATCH 1/33 xen: paravirt: add an "mm" argument to alloc_pt

It's useful to know which mm is allocating a pagetable. Xen uses this to determine whether the pagetable being added to is pinned or not.

---
 arch/i386/kernel/vmi.c      |    2 +-
 arch/i386/mm/init.c         |    2 +-
 arch/i386/mm/pageattr.c     |    2 +-
 include/asm-i386/paravirt.h |    8 ++++----
 include/asm-i386/pgalloc.h  |    6 +++---
 5 files changed, 10 insertions(+), 10 deletions(-)

===================================================================

arch/i386/kernel/vmi.c +1 -1
@@ -361,7 +361,7 @@ static void *vmi_kmap_atomic_pte(struct 
 }
 #endif
 
-static void vmi_allocate_pt(u32 pfn)
+static void vmi_allocate_pt(struct mm_struct *mm, u32 pfn)
 {
 	vmi_set_page_type(pfn, VMI_PAGE_L1);
 	vmi_ops.allocate_page(pfn, VMI_PAGE_L1, 0, 0, 0);

===================================================================

arch/i386/mm/init.c +1 -1
@@ -87,7 +87,7 @@ static pte_t * __init one_page_table_ini
 	if (!(pmd_val(*pmd) & _PAGE_PRESENT)) {
 		pte_t *page_table = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE);
 
-		paravirt_alloc_pt(__pa(page_table) >> PAGE_SHIFT);
+		paravirt_alloc_pt(&init_mm, __pa(page_table) >> PAGE_SHIFT);
 		set_pmd(pmd, __pmd(__pa(page_table) | _PAGE_TABLE));
 		BUG_ON(page_table != pte_offset_kernel(pmd, 0));
 	}

===================================================================

arch/i386/mm/pageattr.c +1 -1
@@ -60,7 +60,7 @@ static struct page *split_large_page(uns
 	address = __pa(address);
 	addr = address & LARGE_PAGE_MASK; 
 	pbase = (pte_t *)page_address(base);
-	paravirt_alloc_pt(page_to_pfn(base));
+	paravirt_alloc_pt(&init_mm, page_to_pfn(base));
 	for (i = 0; i < PTRS_PER_PTE; i++, addr += PAGE_SIZE) {
                set_pte(&pbase[i], pfn_pte(addr >> PAGE_SHIFT,
                                           addr == address ? prot : ref_prot));

===================================================================

include/asm-i386/paravirt.h +4 -4
@@ -173,7 +175,7 @@ struct paravirt_ops
 				 unsigned long va);
 
 	/* Hooks for allocating/releasing pagetable pages */
-	void (*alloc_pt)(u32 pfn);
+	void (*alloc_pt)(struct mm_struct *mm, u32 pfn);
 	void (*alloc_pd)(u32 pfn);
 	void (*alloc_pd_clone)(u32 pfn, u32 clonepfn, u32 start, u32 count);
 	void (*release_pt)(u32 pfn);
@@ -738,9 +746,9 @@ static inline void flush_tlb_others(cpum
 	PVOP_VCALL3(flush_tlb_others, &cpumask, mm, va);
 }
 
-static inline void paravirt_alloc_pt(unsigned pfn)
-{
-	PVOP_VCALL1(alloc_pt, pfn);
+static inline void paravirt_alloc_pt(struct mm_struct *mm, unsigned pfn)
+{
+	PVOP_VCALL2(alloc_pt, mm, pfn);
 }
 static inline void paravirt_release_pt(unsigned pfn)
 {

===================================================================

include/asm-i386/pgalloc.h +3 -3
@@ -7,7 +7,7 @@
 #ifdef CONFIG_PARAVIRT
 #include <asm/paravirt.h>
 #else
-#define paravirt_alloc_pt(pfn) do { } while (0)
+#define paravirt_alloc_pt(mm, pfn) do { } while (0)
 #define paravirt_alloc_pd(pfn) do { } while (0)
 #define paravirt_alloc_pd(pfn) do { } while (0)
 #define paravirt_alloc_pd_clone(pfn, clonepfn, start, count) do { } while (0)
@@ -17,13 +17,13 @@
 
 #define pmd_populate_kernel(mm, pmd, pte)			\
 do {								\
-	paravirt_alloc_pt(__pa(pte) >> PAGE_SHIFT);		\
+	paravirt_alloc_pt(mm, __pa(pte) >> PAGE_SHIFT);		\
 	set_pmd(pmd, __pmd(_PAGE_TABLE + __pa(pte)));		\
 } while (0)
 
 #define pmd_populate(mm, pmd, pte) 				\
 do {								\
-	paravirt_alloc_pt(page_to_pfn(pte));			\
+	paravirt_alloc_pt(mm, page_to_pfn(pte));		\
 	set_pmd(pmd, __pmd(_PAGE_TABLE +			\
 		((unsigned long long)page_to_pfn(pte) <<	\
 			(unsigned long long) PAGE_SHIFT)));	\
#2 lore raw

PATCH 2/33 xen: paravirt: add a hook for once the allocator is ready

In reply to Jeremy Fitzhardinge

Add a hook so that the paravirt backend knows when the allocator is ready. This is useful for the obvious reason that the allocator is available, but the other side-effect of having the bootmem allocator available is that each page now has an associated "struct page".

---
 arch/i386/kernel/setup.c    |    2 ++
 include/asm-i386/paravirt.h |    8 ++++++++
 include/asm-i386/setup.h    |    4 ++++
 3 files changed, 14 insertions(+)

===================================================================

arch/i386/kernel/setup.c +2 -0
@@ -611,6 +611,8 @@ void __init setup_arch(char **cmdline_p)
 	 * NOTE: at this point the bootmem allocator is fully available.
 	 */
 
+	paravirt_post_allocator_init();
+
 	dmi_scan_machine();
 
 #ifdef CONFIG_X86_GENERICARCH

===================================================================

include/asm-i386/paravirt.h +8 -0
@@ -52,6 +52,8 @@ struct paravirt_ops
 	/* Basic arch-specific setup */
 	void (*arch_setup)(void);
 	char *(*memory_setup)(void);
+	void (*post_allocator_init)(void);
+
 	void (*init_IRQ)(void);
 	void (*time_init)(void);
 
@@ -669,6 +671,12 @@ static inline void setup_secondary_clock
 }
 #endif
 
+static inline void paravirt_post_allocator_init(void)
+{
+	if (paravirt_ops.post_allocator_init)
+		(*paravirt_ops.post_allocator_init)();
+}
+
 static inline void paravirt_pagetable_setup_start(pgd_t *base)
 {
 	if (paravirt_ops.pagetable_setup_start)

===================================================================

include/asm-i386/setup.h +4 -0
@@ -79,6 +79,10 @@ void __init add_memory_region(unsigned l
 
 extern unsigned long init_pg_tables_end;
 
+#ifndef CONFIG_PARAVIRT
+#define paravirt_post_allocator_init()	do {} while(0)
+#endif
+
 #endif /* __ASSEMBLY__ */
 
 #endif  /*  __KERNEL__  */
#3 lore raw

PATCH 3/33 xen: paravirt: increase IRQ limit

In reply to Jeremy Fitzhardinge

When running with CONFIG_PARAVIRT, we may want lots of IRQs even if there's no IO APIC.

Cc "Eric W. Biederman" <[email protected]>
---
 include/asm-i386/mach-default/irq_vectors_limits.h |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

===================================================================

include/asm-i386/mach-default/irq_vectors_limits.h +1 -1
@@ -1,7 +1,7 @@
 #ifndef _ASM_IRQ_VECTORS_LIMITS_H
 #define _ASM_IRQ_VECTORS_LIMITS_H
 
-#ifdef CONFIG_X86_IO_APIC
+#if defined(CONFIG_X86_IO_APIC) || defined(CONFIG_PARAVIRT)
 #define NR_IRQS 224
 # if (224 >= 32 * NR_CPUS)
 # define NR_IRQ_VECTORS NR_IRQS
#4 lore raw

PATCH 4/33 xen: paravirt: unstatic leave_mm

In reply to Jeremy Fitzhardinge

Make globally leave_mm visible, specifically so that Xen can use it to shoot-down lazy uses of cr3.

---
 arch/i386/kernel/smp.c         |    5 +++--
 include/asm-i386/mmu_context.h |    2 ++
 2 files changed, 5 insertions(+), 2 deletions(-)

===================================================================

include/asm-i386/mmu_context.h +2 -0
@@ -31,6 +31,8 @@ static inline void enter_lazy_tlb(struct
 		per_cpu(cpu_tlbstate, cpu).state = TLBSTATE_LAZY;
 #endif
 }
+
+void leave_mm (unsigned long cpu);
 
 static inline void switch_mm(struct mm_struct *prev,
 			     struct mm_struct *next,

===================================================================

arch/i386/kernel/smp.c +3 -2
@@ -22,6 +22,7 @@
 
 #include <asm/mtrr.h>
 #include <asm/tlbflush.h>
+#include <asm/mmu_context.h>
 #include <mach_apic.h>
 
 /*
@@ -249,13 +250,13 @@ static DEFINE_SPINLOCK(tlbstate_lock);
 static DEFINE_SPINLOCK(tlbstate_lock);
 
 /*
- * We cannot call mmdrop() because we are in interrupt context, 
+ * We cannot call mmdrop() because we are in interrupt context,
  * instead update mm->cpu_vm_mask.
  *
  * We need to reload %cr3 since the page tables may be going
  * away from under us..
  */
-static inline void leave_mm (unsigned long cpu)
+void leave_mm (unsigned long cpu)
 {
 	if (per_cpu(cpu_tlbstate, cpu).state == TLBSTATE_OK)
 		BUG();
#5 lore raw

PATCH 5/33 xen: paravirt: unstatic smp_store_cpu_info

In reply to Jeremy Fitzhardinge

Paravirt implementations need to store cpu info when bringing up cpus.

---
 arch/i386/kernel/smpboot.c |    2 +-
 include/asm-i386/smp.h     |    2 ++
 2 files changed, 3 insertions(+), 1 deletion(-)

===================================================================

include/asm-i386/smp.h +2 -0
@@ -129,6 +132,8 @@ extern void __cpu_die(unsigned int cpu);
 extern void __cpu_die(unsigned int cpu);
 extern unsigned int num_processors;
 
+void __cpuinit smp_store_cpu_info(int id);
+
 #endif /* !__ASSEMBLY__ */
 
 #else /* CONFIG_SMP */

===================================================================

arch/i386/kernel/smpboot.c +1 -1
@@ -148,7 +148,7 @@ void __init smp_alloc_memory(void)
  * a given CPU
  */
 
-static void __cpuinit smp_store_cpu_info(int id)
+void __cpuinit smp_store_cpu_info(int id)
 {
 	struct cpuinfo_x86 *c = cpu_data + id;
 
#6 lore raw

PATCH 6/33 xen: paravirt: make siblingmap functions visible

In reply to Jeremy Fitzhardinge

Paravirt implementations need to set the sibling map on new cpus.

---
 arch/i386/kernel/smpboot.c |    6 ++----
 include/asm-i386/smp.h     |    3 +++
 2 files changed, 5 insertions(+), 4 deletions(-)

===================================================================

include/asm-i386/smp.h +3 -0
@@ -43,9 +43,12 @@ extern u8 x86_cpu_to_apicid[];
 
 #define cpu_physical_id(cpu)	x86_cpu_to_apicid[cpu]
 
+extern void set_cpu_sibling_map(int cpu);
+
 #ifdef CONFIG_HOTPLUG_CPU
 extern void cpu_exit_clear(void);
 extern void cpu_uninit(void);
+extern void remove_siblinginfo(int cpu);
 #endif
 
 struct smp_ops

===================================================================

arch/i386/kernel/smpboot.c +2 -4
@@ -308,8 +308,7 @@ cpumask_t cpu_coregroup_map(int cpu)
 /* representing cpus for which sibling maps can be computed */
 static cpumask_t cpu_sibling_setup_map;
 
-static inline void
-set_cpu_sibling_map(int cpu)
+void set_cpu_sibling_map(int cpu)
 {
 	int i;
 	struct cpuinfo_x86 *c = cpu_data;
@@ -1157,8 +1156,7 @@ void __init native_smp_prepare_boot_cpu(
 }
 
 #ifdef CONFIG_HOTPLUG_CPU
-static void
-remove_siblinginfo(int cpu)
+void remove_siblinginfo(int cpu)
 {
 	int sibling;
 	struct cpuinfo_x86 *c = cpu_data;
#7 lore raw

PATCH 7/33 xen: paravirt: export __supported_pte_mask

In reply to Jeremy Fitzhardinge

__supported_pte_mask is needed when constructing pte values. Xen device drivers need to do this to make mappings of foreign pages (ie, pages granted to us by other domains).

---
 arch/i386/mm/init.c |    1 +
 1 file changed, 1 insertion(+)

===================================================================

arch/i386/mm/init.c +1 -0
@@ -473,6 +473,7 @@ void zap_low_mappings (void)
 
 static int disable_nx __initdata = 0;
 u64 __supported_pte_mask __read_mostly = ~_PAGE_NX;
+EXPORT_SYMBOL_GPL(__supported_pte_mask);
 
 /*
  * noexec = on|off
#8 lore raw

PATCH 8/33 xen: Allocate and free vmalloc areas

In reply to Jeremy Fitzhardinge

Allocate/release a chunk of vmalloc address space:
alloc_vm_area reserves a chunk of address space, and makes sure all the pagetables are constructed for that address range - but no pages.

free_vm_area releases the address space range.

---
 include/linux/vmalloc.h |    4 +++
 mm/vmalloc.c            |   53 +++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 57 insertions(+)

===================================================================

include/linux/vmalloc.h +4 -0
@@ -69,6 +69,10 @@ extern int map_vm_area(struct vm_struct 
 			struct page ***pages);
 extern void unmap_vm_area(struct vm_struct *area);
 
+/* Allocate/destroy a 'vmalloc' VM area. */
+extern struct vm_struct *alloc_vm_area(size_t size);
+extern void free_vm_area(struct vm_struct *area);
+
 /*
  *	Internals.  Dont't use..
  */

===================================================================

mm/vmalloc.c +53 -0

56 lines not on this page · raw message

#9 lore raw

PATCH 9/33 xen: Add nosegneg capability to the vsyscall page notes

In reply to Jeremy Fitzhardinge

Add the "nosegneg" fake capabilty to the vsyscall page notes. This is used by the runtime linker to select a glibc version which then disables negative-offset accesses to the thread-local segment via %gs. These accesses require emulation in Xen (because segments are truncated to protect the hypervisor address space) and avoiding them provides a measurable performance boost.

---
 arch/i386/kernel/vsyscall-note.S |   28 ++++++++++++++++++++++++++++
 1 file changed, 28 insertions(+)

===================================================================

arch/i386/kernel/vsyscall-note.S +28 -0
@@ -12,3 +12,31 @@ ELFNOTE_START(Linux, 0, "a")
 ELFNOTE_START(Linux, 0, "a")
 	.long LINUX_VERSION_CODE
 ELFNOTE_END
+
+#ifdef CONFIG_XEN
+
+/*
+ * Add a special note telling glibc's dynamic linker a fake hardware
+ * flavor that it will use to choose the search path for libraries in the
+ * same way it uses real hardware capabilities like "mmx".
+ * We supply "nosegneg" as the fake capability, to indicate that we
+ * do not like negative offsets in instructions using segment overrides,
+ * since we implement those inefficiently.  This makes it possible to
+ * install libraries optimized to avoid those access patterns in someplace
+ * like /lib/i686/tls/nosegneg.  Note that an /etc/ld.so.conf.d/file
+ * corresponding to the bits here is needed to make ldconfig work right.
+ * It should contain:
+ *	hwcap 1 nosegneg
+ * to match the mapping of bit to name that we give here.
+ */
+
+/* Bit used for the pseudo-hwcap for non-negative segments.  We use
+   bit 1 to avoid bugs in some versions of glibc when bit 0 is
+   used; the choice is otherwise arbitrary. */
+#define VDSO_NOTE_NONEGSEG_BIT	1
+
+ELFNOTE_START(GNU, 2, "a")
+	.long 1, 1<<VDSO_NOTE_NONEGSEG_BIT		/* ncaps, mask */
+	.byte VDSO_NOTE_NONEGSEG_BIT; .asciz "nosegneg"	/* bit, name */
+ELFNOTE_END
+#endif
#10 lore raw

PATCH 10/33 xen: Add Xen interface header files

In reply to Jeremy Fitzhardinge

Add Xen interface header files. These are taken fairly directly from the Xen tree, but somewhat rearranged to suit the kernel's conventions.

Define macros and inline functions for doing hypercalls into the hypervisor.

---
 include/asm-i386/xen/hypercall.h      |  413 ++++++++++++++++++++++++++++++
 include/asm-i386/xen/hypervisor.h     |   72 +++++
 include/asm-i386/xen/interface.h      |  187 +++++++++++++
 include/xen/interface/elfnote.h       |  133 +++++++++
 include/xen/interface/event_channel.h |  195 ++++++++++++++
 include/xen/interface/features.h      |   43 +++
 include/xen/interface/grant_table.h   |  301 ++++++++++++++++++++++
 include/xen/interface/io/blkif.h      |   94 ++++++
 include/xen/interface/io/console.h    |   23 +
 include/xen/interface/io/netif.h      |  156 +++++++++++
 include/xen/interface/io/ring.h       |  260 +++++++++++++++++++
 include/xen/interface/io/xenbus.h     |   42 +++
 include/xen/interface/io/xs_wire.h    |   87 ++++++
 include/xen/interface/memory.h        |  145 ++++++++++
 include/xen/interface/physdev.h       |  145 ++++++++++
 include/xen/interface/sched.h         |   77 +++++
 include/xen/interface/vcpu.h          |  164 ++++++++++++
 include/xen/interface/version.h       |   60 ++++
 include/xen/interface/xen.h           |  446 +++++++++++++++++++++++++++++++++
 19 files changed, 3043 insertions(+)

===================================================================

include/asm-i386/xen/hypercall.h new file +413 -0
@@ -0,0 +1,413 @@
+/******************************************************************************
+ * hypercall.h
+ *
+ * Linux-specific hypervisor handling.
+ *
+ * Copyright (c) 2002-2004, K A Fraser
+ *
+ * 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 __HYPERCALL_H__
+#define __HYPERCALL_H__
+
+#include <linux/errno.h>
+#include <linux/string.h>
+
+#include <xen/interface/xen.h>
+#include <xen/interface/sched.h>
+#include <xen/interface/physdev.h>
+
+extern struct { char _entry[32]; } hypercall_page[];
+
+#define _hypercall0(type, name)						\
+({									\
+	long __res;							\
+	asm volatile (							\
+		"call %[call]"						\
+		: "=a" (__res)						\
+		: [call] "m" (hypercall_page[__HYPERVISOR_##name])	\
+		: "memory" );						\
+	(type)__res;							\
+})
+
+#define _hypercall1(type, name, a1)					\
+({									\
+	long __res, __ign1;						\
+	asm volatile (							\
+		"call %[call]"						\
+		: "=a" (__res), "=b" (__ign1)				\
+		: "1" ((long)(a1)),					\
+		  [call] "m" (hypercall_page[__HYPERVISOR_##name])	\
+		: "memory" );						\
+	(type)__res;							\
+})
+
+#define _hypercall2(type, name, a1, a2)					\
+({									\
+	long __res, __ign1, __ign2;					\
+	asm volatile (							\
+		"call %[call]"						\
+		: "=a" (__res), "=b" (__ign1), "=c" (__ign2)		\
+		: "1" ((long)(a1)), "2" ((long)(a2)),			\
+		  [call] "m" (hypercall_page[__HYPERVISOR_##name])	\
+		: "memory" );						\
+	(type)__res;							\
+})
+
+#define _hypercall3(type, name, a1, a2, a3)				\
+({									\
+	long __res, __ign1, __ign2, __ign3;				\
+	asm volatile (							\
+		"call %[call]"						\
+		: "=a" (__res), "=b" (__ign1), "=c" (__ign2),		\
+		"=d" (__ign3)						\
+		: "1" ((long)(a1)), "2" ((long)(a2)),			\
+		  "3" ((long)(a3)),					\
+		  [call] "m" (hypercall_page[__HYPERVISOR_##name])	\
+		: "memory" );						\
+	(type)__res;							\
+})
+
+#define _hypercall4(type, name, a1, a2, a3, a4)				\
+({									\
+	long __res, __ign1, __ign2, __ign3, __ign4;			\
+	asm volatile (							\
+		"call %[call]"						\
+		: "=a" (__res), "=b" (__ign1), "=c" (__ign2),		\
+		"=d" (__ign3), "=S" (__ign4)				\
+		: "1" ((long)(a1)), "2" ((long)(a2)),			\
+		  "3" ((long)(a3)), "4" ((long)(a4)),			\
+		  [call] "m" (hypercall_page[__HYPERVISOR_##name])	\
+		: "memory" );						\
+	(type)__res;							\
+})
+
+#define _hypercall5(type, name, a1, a2, a3, a4, a5)			\
+({									\
+	long __res, __ign1, __ign2, __ign3, __ign4, __ign5;		\
+	asm volatile (							\
+		"call %[call]"						\
+		: "=a" (__res), "=b" (__ign1), "=c" (__ign2),		\
+		"=d" (__ign3), "=S" (__ign4), "=D" (__ign5)		\
+		: "1" ((long)(a1)), "2" ((long)(a2)),			\
+		  "3" ((long)(a3)), "4" ((long)(a4)),			\
+		  "5" ((long)(a5)),					\
+		  [call] "m" (hypercall_page[__HYPERVISOR_##name])	\
+		: "memory" );						\
+	(type)__res;							\
+})
+
+static inline int
+HYPERVISOR_set_trap_table(
+	struct trap_info *table)
+{
+	return _hypercall1(int, set_trap_table, table);
+}
+
+static inline int
+HYPERVISOR_mmu_update(
+	struct mmu_update *req, int count, int *success_count, domid_t domid)
+{
+	return _hypercall4(int, mmu_update, req, count, success_count, domid);
+}
+
+static inline int
+HYPERVISOR_mmuext_op(
+	struct mmuext_op *op, int count, int *success_count, domid_t domid)
+{
+	return _hypercall4(int, mmuext_op, op, count, success_count, domid);
+}
+
+static inline int
+HYPERVISOR_set_gdt(
+	unsigned long *frame_list, int entries)
+{
+	return _hypercall2(int, set_gdt, frame_list, entries);
+}
+
+static inline int
+HYPERVISOR_stack_switch(
+	unsigned long ss, unsigned long esp)
+{
+	return _hypercall2(int, stack_switch, ss, esp);
+}
+
+static inline int
+HYPERVISOR_set_callbacks(
+	unsigned long event_selector, unsigned long event_address,
+	unsigned long failsafe_selector, unsigned long failsafe_address)
+{
+	return _hypercall4(int, set_callbacks,
+			   event_selector, event_address,
+			   failsafe_selector, failsafe_address);
+}
+
+static inline int
+HYPERVISOR_fpu_taskswitch(
+	int set)
+{
+	return _hypercall1(int, fpu_taskswitch, set);
+}
+
+static inline int
+HYPERVISOR_sched_op(
+	int cmd, unsigned long arg)
+{
+	return _hypercall2(int, sched_op, cmd, arg);
+}
+
+static inline long
+HYPERVISOR_set_timer_op(
+	u64 timeout)
+{
+	unsigned long timeout_hi = (unsigned long)(timeout>>32);
+	unsigned long timeout_lo = (unsigned long)timeout;
+	return _hypercall2(long, set_timer_op, timeout_lo, timeout_hi);
+}
+
+static inline int
+HYPERVISOR_set_debugreg(
+	int reg, unsigned long value)
+{
+	return _hypercall2(int, set_debugreg, reg, value);
+}
+
+static inline unsigned long
+HYPERVISOR_get_debugreg(
+	int reg)
+{
+	return _hypercall1(unsigned long, get_debugreg, reg);
+}
+
+static inline int
+HYPERVISOR_update_descriptor(
+	u64 ma, u64 desc)
+{
+	return _hypercall4(int, update_descriptor, ma, ma>>32, desc, desc>>32);
+}
+
+static inline int
+HYPERVISOR_memory_op(
+	unsigned int cmd, void *arg)
+{
+	return _hypercall2(int, memory_op, cmd, arg);
+}
+
+static inline int
+HYPERVISOR_multicall(
+	void *call_list, int nr_calls)
+{
+	return _hypercall2(int, multicall, call_list, nr_calls);
+}
+
+static inline int
+HYPERVISOR_update_va_mapping(
+	unsigned long va, pte_t new_val, unsigned long flags)
+{
+	unsigned long pte_hi = 0;
+#ifdef CONFIG_X86_PAE
+	pte_hi = new_val.pte_high;
+#endif
+	return _hypercall4(int, update_va_mapping, va,
+			   new_val.pte_low, pte_hi, flags);
+}
+
+static inline int
+HYPERVISOR_event_channel_op(
+        int cmd, void *arg)
+{
+        int rc = _hypercall2(int, event_channel_op, cmd, arg);
+        if (unlikely(rc == -ENOSYS)) {
+                struct evtchn_op op;
+                op.cmd = cmd;
+                memcpy(&op.u, arg, sizeof(op.u));
+                rc = _hypercall1(int, event_channel_op_compat, &op);
+                memcpy(arg, &op.u, sizeof(op.u));
+        }
+        return rc;
+}
+
+static inline int
+HYPERVISOR_xen_version(
+	int cmd, void *arg)
+{
+	return _hypercall2(int, xen_version, cmd, arg);
+}
+
+static inline int
+HYPERVISOR_console_io(
+	int cmd, int count, char *str)
+{
+	return _hypercall3(int, console_io, cmd, count, str);
+}
+
+static inline int
+HYPERVISOR_physdev_op(int cmd, void *arg)
+{
+	int rc = _hypercall2(int, physdev_op, cmd, arg);
+	if (unlikely(rc == -ENOSYS)) {
+		struct physdev_op op;
+		op.cmd = cmd;
+		memcpy(&op.u, arg, sizeof(op.u));
+		rc = _hypercall1(int, physdev_op_compat, &op);
+		memcpy(arg, &op.u, sizeof(op.u));
+	}
+	return rc;
+}
+
+static inline int
+HYPERVISOR_grant_table_op(
+	unsigned int cmd, void *uop, unsigned int count)
+{
+	return _hypercall3(int, grant_table_op, cmd, uop, count);
+}
+
+static inline int
+HYPERVISOR_update_va_mapping_otherdomain(
+	unsigned long va, pte_t new_val, unsigned long flags, domid_t domid)
+{
+	unsigned long pte_hi = 0;
+#ifdef CONFIG_X86_PAE
+	pte_hi = new_val.pte_high;
+#endif
+	return _hypercall5(int, update_va_mapping_otherdomain, va,
+			   new_val.pte_low, pte_hi, flags, domid);
+}
+
+static inline int
+HYPERVISOR_vm_assist(
+	unsigned int cmd, unsigned int type)
+{
+	return _hypercall2(int, vm_assist, cmd, type);
+}
+
+static inline int
+HYPERVISOR_vcpu_op(
+	int cmd, int vcpuid, void *extra_args)
+{
+	return _hypercall3(int, vcpu_op, cmd, vcpuid, extra_args);
+}
+
+static inline int
+HYPERVISOR_suspend(
+	unsigned long srec)
+{
+	return _hypercall3(int, sched_op, SCHEDOP_shutdown,
+			   SHUTDOWN_suspend, srec);
+}
+
+static inline int
+HYPERVISOR_nmi_op(
+	unsigned long op,
+	unsigned long arg)
+{
+	return _hypercall2(int, nmi_op, op, arg);
+}
+
+static inline void
+MULTI_update_va_mapping(struct multicall_entry *mcl, unsigned long va,
+			pte_t new_val, unsigned long flags)
+{
+	mcl->op = __HYPERVISOR_update_va_mapping;
+	mcl->args[0] = va;
+#ifdef CONFIG_X86_PAE
+	mcl->args[1] = new_val.pte_low;
+	mcl->args[2] = new_val.pte_high;
+#else
+	mcl->args[1] = new_val.pte_low;
+	mcl->args[2] = 0;
+#endif
+	mcl->args[3] = flags;
+}
+
+static inline void
+MULTI_grant_table_op(struct multicall_entry *mcl, unsigned int cmd,
+		     void *uop, unsigned int count)
+{
+	mcl->op = __HYPERVISOR_grant_table_op;
+	mcl->args[0] = cmd;
+	mcl->args[1] = (unsigned long)uop;
+	mcl->args[2] = count;
+}
+
+static inline void
+MULTI_update_va_mapping_otherdomain(struct multicall_entry *mcl, unsigned long va,
+				    pte_t new_val, unsigned long flags, domid_t domid)
+{
+	mcl->op = __HYPERVISOR_update_va_mapping_otherdomain;
+	mcl->args[0] = va;
+#ifdef CONFIG_X86_PAE
+	mcl->args[1] = new_val.pte_low;
+	mcl->args[2] = new_val.pte_high;
+#else
+	mcl->args[1] = new_val.pte_low;
+	mcl->args[2] = 0;
+#endif
+	mcl->args[3] = flags;
+	mcl->args[4] = domid;
+}
+
+static inline void
+MULTI_update_descriptor(struct multicall_entry *mcl, u64 maddr,
+			struct desc_struct desc)
+{
+	mcl->op = __HYPERVISOR_update_descriptor;
+	mcl->args[0] = maddr;
+	mcl->args[1] = maddr >> 32;
+	mcl->args[2] = desc.a;
+	mcl->args[3] = desc.b;
+}
+
+static inline void
+MULTI_memory_op(struct multicall_entry *mcl, unsigned int cmd, void *arg)
+{
+	mcl->op = __HYPERVISOR_memory_op;
+	mcl->args[0] = cmd;
+	mcl->args[1] = (unsigned long)arg;
+}
+
+static inline void
+MULTI_mmu_update(struct multicall_entry *mcl, struct mmu_update *req,
+		 int count, int *success_count, domid_t domid)
+{
+	mcl->op = __HYPERVISOR_mmu_update;
+	mcl->args[0] = (unsigned long)req;
+	mcl->args[1] = count;
+	mcl->args[2] = (unsigned long)success_count;
+	mcl->args[3] = domid;
+}
+
+static inline void
+MULTI_mmuext_op(struct multicall_entry *mcl, struct mmuext_op *op, int count,
+		int *success_count, domid_t domid)
+{
+	mcl->op = __HYPERVISOR_mmuext_op;
+	mcl->args[0] = (unsigned long)op;
+	mcl->args[1] = count;
+	mcl->args[2] = (unsigned long)success_count;
+	mcl->args[3] = domid;
+}
+#endif /* __HYPERCALL_H__ */

===================================================================

include/asm-i386/xen/hypervisor.h new file +72 -0

72 lines not on this page · raw message

===================================================================

include/asm-i386/xen/interface.h new file +187 -0

187 lines not on this page · raw message

===================================================================

include/xen/interface/elfnote.h new file +133 -0

133 lines not on this page · raw message

===================================================================

include/xen/interface/event_channel.h new file +195 -0

195 lines not on this page · raw message

===================================================================

include/xen/interface/features.h new file +43 -0

43 lines not on this page · raw message

===================================================================

include/xen/interface/grant_table.h new file +301 -0

301 lines not on this page · raw message

===================================================================

include/xen/interface/io/blkif.h new file +94 -0

94 lines not on this page · raw message

===================================================================

include/xen/interface/io/console.h new file +23 -0
@@ -0,0 +1,23 @@
+/******************************************************************************
+ * console.h
+ *
+ * Console I/O interface for Xen guest OSes.
+ *
+ * Copyright (c) 2005, Keir Fraser
+ */
+
+#ifndef __XEN_PUBLIC_IO_CONSOLE_H__
+#define __XEN_PUBLIC_IO_CONSOLE_H__
+
+typedef uint32_t XENCONS_RING_IDX;
+
+#define MASK_XENCONS_IDX(idx, ring) ((idx) & (sizeof(ring)-1))
+
+struct xencons_interface {
+    char in[1024];
+    char out[2048];
+    XENCONS_RING_IDX in_cons, in_prod;
+    XENCONS_RING_IDX out_cons, out_prod;
+};
+
+#endif /* __XEN_PUBLIC_IO_CONSOLE_H__ */

===================================================================

include/xen/interface/io/netif.h new file +156 -0

156 lines not on this page · raw message

===================================================================

include/xen/interface/io/ring.h new file +260 -0

260 lines not on this page · raw message

===================================================================

include/xen/interface/io/xenbus.h new file +42 -0

42 lines not on this page · raw message

===================================================================

include/xen/interface/io/xs_wire.h new file +87 -0

87 lines not on this page · raw message

===================================================================

include/xen/interface/memory.h new file +145 -0

145 lines not on this page · raw message

===================================================================

include/xen/interface/physdev.h new file +145 -0

145 lines not on this page · raw message

===================================================================

include/xen/interface/sched.h new file +77 -0

77 lines not on this page · raw message

===================================================================

include/xen/interface/vcpu.h new file +164 -0

164 lines not on this page · raw message

===================================================================

include/xen/interface/version.h new file +60 -0

60 lines not on this page · raw message

===================================================================

include/xen/interface/xen.h new file +446 -0

403 lines not on this page · raw message

The rest of this diff is not shown. View the raw message.

Part of the diff is not shown here. View the raw message.

#11 lore raw

PATCH 11/33 xen: Core Xen implementation

In reply to Jeremy Fitzhardinge

This patch is a rollup of all the core pieces of the Xen implementation, including:
- booting and setup
- pagetable setup
- privileged instructions
- segmentation
- interrupt flags
- upcalls
- multicall batching

BOOTING AND SETUP

The vmlinux image is decorated with ELF notes which tell the Xen domain builder what the kernel's requirements are; the domain builder then constructs the address space accordingly and starts the kernel.

Xen has its own entrypoint for the kernel (contained in an ELF note). The ELF notes are set up by xen-head.S, which is included into head.S. In principle it could be linked separately, but it seems to provoke lots of binutils bugs.

Because the domain builder starts the kernel in a fairly sane state (32-bit protected mode, paging enabled, flat segments set up), there's not a lot of setup needed before starting the kernel proper. The main steps are:
1. Install the Xen paravirt_ops, which is simply a matter of a structure assignment.
2. Set init_mm to use the Xen-supplied pagetables (analogous to the head.S generated pagetables in a native boot).
3. Reserve address space for Xen, since it takes a chunk at the top of the address space for its own use.
4. Call start_kernel()

PAGETABLE SETUP

Once we hit the main kernel boot sequence, it will end up calling back via paravirt_ops to set up various pieces of Xen specific state. One of the critical things which requires a bit of extra care is the construction of the initial init_mm pagetable. Because Xen places tight constraints on pagetables (an active pagetable must always be valid, and must always be mapped read-only to the guest domain), we need to be careful when constructing the new pagetable to keep these constraints in mind. It turns out that the easiest way to do this is use the initial Xen-provided pagetable as a template, and then just insert new mappings for memory where a mapping doesn't already exist.

This means that during pagetable setup, it uses a special version of xen_set_pte which ignores any attempt to remap a read-only page as read-write (since Xen will map its own initial pagetable as RO), but lets other changes to the ptes happen, so that things like NX are set properly.

PRIVILEGED INSTRUCTIONS AND SEGMENTATION

When the kernel runs under Xen, it runs in ring 1 rather than ring 0. This means that it is more privileged than user-mode in ring 3, but it still can't run privileged instructions directly. Non-performance critical instructions are dealt with by taking a privilege exception and trapping into the hypervisor and emulating the instruction, but more performance-critical instructions have their own specific paravirt_ops. In many cases we can avoid having to do any hypercalls for these instructions, or the Xen implementation is quite different from the normal native version.

The privileged instructions fall into the broad classes of:
Segmentation: setting up the GDT and the GDT entries, LDT,
TLS and so on. Xen doesn't allow the GDT to be directly modified; all GDT updates are done via hypercalls where the new entries can be validated. This is important because Xen uses segment limits to prevent the guest kernel from damaging the hypervisor itself.
Traps and exceptions: Xen uses a special format for trap entrypoints,
so when the kernel wants to set an IDT entry, it needs to be converted to the form Xen expects. Xen sets int 0x80 up specially so that the trap goes straight from userspace into the guest kernel without going via the hypervisor. sysenter isn't supported.
Kernel stack: The esp0 entry is extracted from the tss and provided to
Xen.
TLB operations: the various TLB calls are mapped into corresponding
Xen hypercalls.
Control registers: all the control registers are privileged. The most
important is cr3, which points to the base of the current pagetable, and we handle it specially.

Another instruction we treat specially is CPUID, even though its not privileged. We want to control what CPU features are visible to the rest of the kernel, and so CPUID ends up going into a paravirt_op. Xen implements this mainly to disable the ACPI and APIC subsystems.

INTERRUPT FLAGS

Xen maintains its own separate flag for masking events, which is contained within the per-cpu vcpu_info structure. Because the guest kernel runs in ring 1 and not 0, the IF flag in EFLAGS is completely ignored (and must be, because even if a guest domain disables interrupts for itself, it can't disable them overall).

(A note on terminology: "events" and interrupts are effectively synonymous. However, rather than using an "enable flag", Xen uses a "mask flag", which blocks event delivery when it is non-zero.)

There are paravirt_ops for each of cli/sti/save_fl/restore_fl, which are implemented to manage the Xen event mask state. The only thing worth noting is that when events are unmasked, we need to explicitly see if there's a pending event and call into the hypervisor to make sure it gets delivered.

UPCALLS

Xen needs a couple of upcall (or callback) functions to be implemented by each guest. One is the event upcalls, which is how events (interrupts, effectively) are delivered to the guests. The other is the failsafe callback, which is used to report errors in either reloading a segment register, or caused by iret. These are implemented in i386/kernel/entry.S so they can jump into the normal iret_exc path when necessary.

MULTICALL BATCHING

Xen provides a multicall mechanism, which allows multiple hypercalls to be issued at once in order to mitigate the cost of trapping into the hypervisor. This is particularly useful for context switches, since the 4-5 hypercalls they would normally need (reload cr3, update TLS, maybe update LDT) can be reduced to one. This patch implements a generic batching mechanism for hypercalls, which gets used in many places in the Xen code.

---
 arch/i386/Makefile               |    3 
 arch/i386/kernel/entry.S         |   71 +++
 arch/i386/kernel/head.S          |    5 
 arch/i386/kernel/vmlinux.lds.S   |    1 
 arch/i386/xen/Makefile           |    1 
 arch/i386/xen/enlighten.c        |  741 ++++++++++++++++++++++++++++++++++++++
 arch/i386/xen/features.c         |   29 +
 arch/i386/xen/multicalls.c       |   89 ++++
 arch/i386/xen/multicalls.h       |   45 ++
 arch/i386/xen/setup.c            |   96 ++++
 arch/i386/xen/xen-head.S         |   36 +
 arch/i386/xen/xen-ops.h          |   31 +
 include/asm-i386/irq.h           |    1 
 include/asm-i386/xen/hypercall.h |   18 
 include/xen/features.h           |   23 +
 include/xen/page.h               |  178 +++++++++
 16 files changed, 1367 insertions(+), 1 deletion(-)

===================================================================

arch/i386/Makefile +3 -0
@@ -93,6 +93,9 @@ mcore-$(CONFIG_X86_ES7000)	:= mach-defau
 mcore-$(CONFIG_X86_ES7000)	:= mach-default
 core-$(CONFIG_X86_ES7000)	:= arch/i386/mach-es7000/
 
+# Xen paravirtualization support
+core-$(CONFIG_XEN)		+= arch/i386/xen/
+
 # default subarch .h files
 mflags-y += -Iinclude/asm-i386/mach-default
 

===================================================================

arch/i386/kernel/entry.S +71 -0

77 lines not on this page · raw message

===================================================================

arch/i386/kernel/head.S +4 -1
@@ -504,7 +504,8 @@ ENTRY(_stext)
 /*
  * BSS section
  */
-.section ".bss.page_aligned","w"
+.section ".bss.page_aligned","wa"
+	.align PAGE_SIZE_asm
 ENTRY(swapper_pg_dir)
 	.fill 1024,4,0
 ENTRY(empty_zero_page)
@@ -529,6 +530,8 @@ fault_msg:
 fault_msg:
 	.ascii "Int %d: CR2 %p  err %p  EIP %p  CS %p  flags %p\n"
 	.asciz "Stack: %p %p %p %p %p %p %p %p\n"
+
+#include "../xen/xen-head.S"
 
 /*
  * The IDT and GDT 'descriptors' are a strange 48-bit object

===================================================================

arch/i386/kernel/vmlinux.lds.S +1 -0
@@ -90,6 +90,7 @@ SECTIONS
 
   . = ALIGN(4096);
   .data.page_aligned : AT(ADDR(.data.page_aligned) - LOAD_OFFSET) {
+	*(.data.page_aligned)
 	*(.data.idt)
   }
 

===================================================================

arch/i386/xen/Makefile new file +1 -0
@@ -0,0 +1,1 @@
+obj-y		:= enlighten.o setup.o features.o multicalls.o

===================================================================

arch/i386/xen/enlighten.c new file +741 -0

741 lines not on this page · raw message

===================================================================

arch/i386/xen/features.c new file +29 -0
@@ -0,0 +1,29 @@
+/******************************************************************************
+ * features.c
+ *
+ * Xen feature flags.
+ *
+ * Copyright (c) 2006, Ian Campbell, XenSource Inc.
+ */
+#include <linux/types.h>
+#include <linux/cache.h>
+#include <linux/module.h>
+#include <asm/xen/hypervisor.h>
+#include <xen/features.h>
+
+u8 xen_features[XENFEAT_NR_SUBMAPS * 32] __read_mostly;
+EXPORT_SYMBOL_GPL(xen_features);
+
+void xen_setup_features(void)
+{
+	struct xen_feature_info fi;
+	int i, j;
+
+	for (i = 0; i < XENFEAT_NR_SUBMAPS; i++) {
+		fi.submap_idx = i;
+		if (HYPERVISOR_xen_version(XENVER_get_features, &fi) < 0)
+			break;
+		for (j=0; j<32; j++)
+			xen_features[i*32+j] = !!(fi.submap & 1<<j);
+	}
+}

===================================================================

arch/i386/xen/multicalls.c new file +89 -0

89 lines not on this page · raw message

===================================================================

arch/i386/xen/multicalls.h new file +45 -0

45 lines not on this page · raw message

===================================================================

arch/i386/xen/setup.c new file +96 -0

96 lines not on this page · raw message

===================================================================

arch/i386/xen/xen-head.S new file +36 -0
@@ -0,0 +1,36 @@
+/* Xen-specific pieces of head.S, intended to be included in the right
+	place in head.S */
+
+#ifdef CONFIG_XEN
+
+#include <linux/elfnote.h>
+#include <asm/boot.h>
+#include <xen/interface/elfnote.h>
+
+ENTRY(startup_xen)
+	movl %esi,xen_start_info
+	cld
+ 	movl $(init_thread_union+THREAD_SIZE),%esp
+	jmp xen_start_kernel
+
+.pushsection ".bss.page_aligned"
+	.align PAGE_SIZE_asm
+ENTRY(hypercall_page)
+	.skip 0x1000
+.popsection
+
+	ELFNOTE(Xen, XEN_ELFNOTE_GUEST_OS,       .asciz "linux")
+	ELFNOTE(Xen, XEN_ELFNOTE_GUEST_VERSION,  .asciz "2.6")
+	ELFNOTE(Xen, XEN_ELFNOTE_XEN_VERSION,    .asciz "xen-3.0")
+	ELFNOTE(Xen, XEN_ELFNOTE_VIRT_BASE,      .long  __PAGE_OFFSET)
+	ELFNOTE(Xen, XEN_ELFNOTE_ENTRY,          .long  startup_xen)
+	ELFNOTE(Xen, XEN_ELFNOTE_HYPERCALL_PAGE, .long  hypercall_page)
+	ELFNOTE(Xen, XEN_ELFNOTE_FEATURES,       .asciz "!writable_page_tables|pae_pgdir_above_4gb")
+#ifdef CONFIG_X86_PAE
+	ELFNOTE(Xen, XEN_ELFNOTE_PAE_MODE,       .asciz "yes")
+#else
+	ELFNOTE(Xen, XEN_ELFNOTE_PAE_MODE,       .asciz "no")
+#endif
+	ELFNOTE(Xen, XEN_ELFNOTE_LOADER,         .asciz "generic")
+
+#endif /*CONFIG_XEN */

===================================================================

arch/i386/xen/xen-ops.h new file +31 -0
@@ -0,0 +1,31 @@
+#ifndef XEN_OPS_H
+#define XEN_OPS_H
+
+#include <linux/init.h>
+#include <linux/clocksource.h>
+
+DECLARE_PER_CPU(struct vcpu_info *, xen_vcpu);
+DECLARE_PER_CPU(unsigned long, xen_cr3);
+
+extern struct start_info *xen_start_info;
+extern struct shared_info *HYPERVISOR_shared_info;
+
+char * __init xen_memory_setup(void);
+void __init xen_arch_setup(void);
+void __init xen_init_IRQ(void);
+
+unsigned long xen_cpu_khz(void);
+void __init xen_time_init(void);
+unsigned long xen_get_wallclock(void);
+int xen_set_wallclock(unsigned long time);
+cycle_t xen_clocksource_read(void);
+
+DECLARE_PER_CPU(enum paravirt_lazy_mode, xen_lazy_mode);
+
+static inline unsigned xen_get_lazy_mode(void)
+{
+	return x86_read_percpu(xen_lazy_mode);
+}
+
+
+#endif /* XEN_OPS_H */

===================================================================

include/asm-i386/irq.h +1 -0
@@ -36,6 +36,7 @@ extern void fixup_irqs(cpumask_t map);
 extern void fixup_irqs(cpumask_t map);
 #endif
 
+unsigned int do_IRQ(struct pt_regs *regs);
 void init_IRQ(void);
 void __init native_init_IRQ(void);
 

===================================================================

include/asm-i386/xen/hypercall.h +18 -0
@@ -410,4 +410,22 @@ MULTI_mmuext_op(struct multicall_entry *
 	mcl->args[2] = (unsigned long)success_count;
 	mcl->args[3] = domid;
 }
+
+static inline void
+MULTI_set_gdt(struct multicall_entry *mcl, unsigned long *frames, int entries)
+{
+	mcl->op = __HYPERVISOR_set_gdt;
+	mcl->args[0] = (unsigned long)frames;
+	mcl->args[1] = entries;
+}
+
+static inline void
+MULTI_stack_switch(struct multicall_entry *mcl,
+		   unsigned long ss, unsigned long esp)
+{
+	mcl->op = __HYPERVISOR_stack_switch;
+	mcl->args[0] = ss;
+	mcl->args[1] = esp;
+}
+
 #endif /* __HYPERCALL_H__ */

===================================================================

include/xen/features.h new file +23 -0
@@ -0,0 +1,23 @@
+/******************************************************************************
+ * features.h
+ *
+ * Query the features reported by Xen.
+ *
+ * Copyright (c) 2006, Ian Campbell
+ */
+
+#ifndef __XEN_FEATURES_H__
+#define __XEN_FEATURES_H__
+
+#include <xen/interface/features.h>
+
+void xen_setup_features(void);
+
+extern u8 xen_features[XENFEAT_NR_SUBMAPS * 32];
+
+static inline int xen_feature(int flag)
+{
+	return xen_features[flag];
+}
+
+#endif /* __ASM_XEN_FEATURES_H__ */

===================================================================

include/xen/page.h new file +178 -0

178 lines not on this page · raw message

#12 lore raw

PATCH 12/33 xen: Xen virtual mmu

In reply to Jeremy Fitzhardinge

Xen pagetable handling, including the machinery to implement direct pagetables.

Xen presents the real CPU's pagetables directly to guests, with no added shadowing or other layer of abstraction. Naturally this means the hypervisor must maintain close control over what the guest can put into the pagetable.

When the guest modifies the pte/pmd/pgd, it must convert its domain-specific notion of a "physical" pfn into a global machine frame number (mfn) before inserting the entry into the pagetable. Xen will check to make sure the domain is allowed to create a mapping of the given mfn.

Xen also requires that all mappings the guest has of its own active pagetable are read-only. This is relatively easy to implement in Linux because all pagetables share the same pte pages for kernel mappings, so updating the pte in one pagetable will implicitly update the mapping in all pagetables.

Normally a pagetable becomes active when you point to it with cr3 (or the Xen equivalent), but when you do so, Xen must check the whole pagetable for correctness, which is clearly a performance problem.

Xen solves this with pinning which keeps a pagetable effectively active even if its currently unused, which means that all the normal update rules are enforced. This means that it need not revalidate the pagetable when loading cr3.

This patch has a first-cut implementation of pinning, but it is more fully implemented in a later patch.

---
 arch/i386/xen/Makefile    |    2 
 arch/i386/xen/enlighten.c |   30 ++-
 arch/i386/xen/mmu.c       |  419 +++++++++++++++++++++++++++++++++++++++++++++
 arch/i386/xen/mmu.h       |   47 +++++
 4 files changed, 493 insertions(+), 5 deletions(-)

===================================================================

arch/i386/xen/Makefile +1 -1
@@ -1,1 +1,1 @@ obj-y		:= enlighten.o setup.o features.o
-obj-y		:= enlighten.o setup.o features.o multicalls.o
+obj-y		:= enlighten.o setup.o features.o multicalls.o mmu.o

===================================================================

arch/i386/xen/enlighten.c +26 -4
@@ -39,6 +39,7 @@
 #include <asm/pgtable.h>
 
 #include "xen-ops.h"
+#include "mmu.h"
 #include "multicalls.h"
 
 EXPORT_SYMBOL_GPL(hypercall_page);
@@ -575,11 +576,9 @@ static __init void xen_pagetable_setup_d
 		 * Should be set_fixmap(), but shared_info is a machine
 		 * address with no corresponding pseudo-phys address.
 		 */
-#if 0
 		set_pte_mfn(fix_to_virt(FIX_PARAVIRT_BOOTMAP),
 			    PFN_DOWN(xen_start_info->shared_info),
 			    PAGE_KERNEL);
-#endif
 
 		HYPERVISOR_shared_info =
 			(struct shared_info *)fix_to_virt(FIX_PARAVIRT_BOOTMAP);
@@ -588,9 +587,7 @@ static __init void xen_pagetable_setup_d
 		HYPERVISOR_shared_info =
 			(struct shared_info *)__va(xen_start_info->shared_info);
 
-#if 0
 	xen_pgd_pin(base);
-#endif
 
 	xen_vcpu_setup(smp_processor_id());
 }
@@ -686,6 +683,31 @@ static const struct paravirt_ops xen_par
 	.release_pd = xen_release_pd,
 	.release_pt = xen_release_pt,
 
+	.set_pte = xen_set_pte,
+	.set_pte_at = xen_set_pte_at,
+	.set_pmd = xen_set_pmd,
+
+	.pte_val = xen_pte_val,
+	.pgd_val = xen_pgd_val,
+
+	.make_pte = xen_make_pte,
+	.make_pgd = xen_make_pgd,
+
+#ifdef CONFIG_X86_PAE
+	.set_pte_atomic = xen_set_pte_atomic,
+	.set_pte_present = xen_set_pte_at,
+	.set_pud = xen_set_pud,
+	.pte_clear = xen_pte_clear,
+	.pmd_clear = xen_pmd_clear,
+
+	.make_pmd = xen_make_pmd,
+	.pmd_val = xen_pmd_val,
+#endif	/* PAE */
+
+	.activate_mm = xen_activate_mm,
+	.dup_mmap = xen_dup_mmap,
+	.exit_mmap = xen_exit_mmap,
+
 	.set_lazy_mode = xen_set_lazy_mode,
 };
 

===================================================================

arch/i386/xen/mmu.c new file +419 -0

419 lines not on this page · raw message

===================================================================

arch/i386/xen/mmu.h new file +47 -0

47 lines not on this page · raw message

#13 lore raw

PATCH 13/33 xen: xen event channels

In reply to Jeremy Fitzhardinge

Xen implements interrupts in terms of event channels. Each guest domain gets 1024 event channels which can be used for a variety of purposes, such as Xen timer events, inter-domain events, inter-processor events (IPI) or for real hardware IRQs.

Within the kernel, we map the event channels to IRQs, and implement the whole interrupt handling using a Xen irq_chip.

Rather than setting NR_IRQ to 1024 under PARAVIRT in order to accomodate Xen, we create a dynamic mapping between event channels and IRQs. Ideally, Linux will eventually move towards dynamically allocating per-irq structures, and we can use a 1:1 mapping between event channels and irqs.

---
 arch/i386/xen/Makefile    |    3 
 arch/i386/xen/enlighten.c |    1 
 arch/i386/xen/events.c    |  511 +++++++++++++++++++++++++++++++++++++++++++++
 include/xen/events.h      |   28 ++
 4 files changed, 542 insertions(+), 1 deletion(-)

===================================================================

arch/i386/xen/Makefile +2 -1
@@ -1,1 +1,2 @@ obj-y		:= enlighten.o setup.o features.o
-obj-y		:= enlighten.o setup.o features.o multicalls.o mmu.o
+obj-y		:= enlighten.o setup.o features.o multicalls.o mmu.o \
+			events.o

===================================================================

arch/i386/xen/enlighten.c +1 -0
@@ -593,6 +593,7 @@ static const struct paravirt_ops xen_par
 
 	.memory_setup = xen_memory_setup,
 	.arch_setup = xen_arch_setup,
+	.init_IRQ = xen_init_IRQ,
 
 	.cpuid = xen_cpuid,
 

===================================================================

arch/i386/xen/events.c new file +511 -0

511 lines not on this page · raw message

===================================================================

include/xen/events.h new file +28 -0
@@ -0,0 +1,28 @@
+#ifndef _XEN_EVENTS_H
+#define _XEN_EVENTS_H
+
+#include <linux/irq.h>
+
+int bind_evtchn_to_irqhandler(unsigned int evtchn,
+			      irqreturn_t (*handler)(int, void *),
+			      unsigned long irqflags, const char *devname,
+			      void *dev_id);
+int bind_virq_to_irqhandler(unsigned int virq, unsigned int cpu,
+			    irqreturn_t (*handler)(int, void *),
+			    unsigned long irqflags, const char *devname, void *dev_id);
+
+/*
+ * Common unbind function for all event sources. Takes IRQ to unbind from.
+ * Automatically closes the underlying event channel (even for bindings
+ * made with bind_evtchn_to_irqhandler()).
+ */
+void unbind_from_irqhandler(unsigned int irq, void *dev_id);
+
+static inline void notify_remote_via_evtchn(int port)
+{
+	struct evtchn_send send = { .port = port };
+	(void)HYPERVISOR_event_channel_op(EVTCHNOP_send, &send);
+}
+
+extern void notify_remote_via_irq(int irq);
+#endif	/* _XEN_EVENTS_H */
#14 lore raw

PATCH 14/33 xen: xen time implementation

In reply to Jeremy Fitzhardinge

Xen maintains a base clock which measures nanoseconds since system boot. This is provided to guests via a shared page which contains a base time in ns, a tsc timestamp at that point and tsc frequency parameters. Guests can compute the current time by reading the tsc and using it to extrapolate the current time from the basetime. The hypervisor makes sure that the frequency parameters are updated regularly, paricularly if the tsc changes rate or stops.

This is implemented as a clocksource, so the interface to the rest of the kernel is a simple clocksource which simply returns the current time directly in nanoseconds.

Xen also provides a simple timer mechanism, which allows a timeout to be set in the future. When that time arrives, a timer event is sent to the guest. There are two timer interfaces:
- An old one which also delivers a stream of (unused) ticks at 100Hz, and on the same event, the actual timer events. The 100Hz ticks cause a lot of spurious wakeups, but are basically harmless.
- The new timer interface doesn't have the 100Hz ticks, and can also fail if the specified time is in the past.

This code presents the Xen timer as a clockevent driver, and uses the new interface by preference.

---
 arch/i386/xen/Makefile    |    2 
 arch/i386/xen/enlighten.c |    6 
 arch/i386/xen/time.c      |  402 +++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 409 insertions(+), 1 deletion(-)

===================================================================

arch/i386/xen/Makefile +1 -1
@@ -1,2 +1,2 @@ obj-y		:= enlighten.o setup.o features.o
 obj-y		:= enlighten.o setup.o features.o multicalls.o mmu.o \
-			events.o
+			events.o time.o

===================================================================

arch/i386/xen/enlighten.c +6 -0
@@ -595,6 +595,12 @@ static const struct paravirt_ops xen_par
 	.arch_setup = xen_arch_setup,
 	.init_IRQ = xen_init_IRQ,
 
+	.time_init = xen_time_init,
+	.set_wallclock = xen_set_wallclock,
+	.get_wallclock = xen_get_wallclock,
+	.get_cpu_khz = xen_cpu_khz,
+	.sched_clock = xen_clocksource_read,
+
 	.cpuid = xen_cpuid,
 
 	.set_debugreg = xen_set_debugreg,

===================================================================

arch/i386/xen/time.c new file +402 -0

402 lines not on this page · raw message

#15 lore raw

Re: [Xen-devel] [patch 14/33] xen: xen time implementation

arch/i386/xen/time.c line 138

Quoted 13 lines
arch/i386/xen/time.c new file +13 -0
+cycle_t xen_clocksource_read(void)
+{
+	struct shadow_time_info *shadow = &get_cpu_var(shadow_time);
+	cycle_t ret;
+
+	get_time_values_from_xen();
+
+	ret = shadow->system_timestamp + get_nsec_offset(shadow);
+
+	put_cpu_var(shadow_time);
+
+	return ret;
+}

I'm afraid this mechanism is pretty unreliable on SMP: getnstimeofday() and do_gettimeofday() both use the difference between the last snapshot taken and the current value read from the clock source. Since I had added this clocksource code to our kernel, I had reproducible hangs on one of the systems I regularly work with (you may have seen the respective thread on xen-devel), which recently I finally found time to look into. The issue is that on that system, transition into ACPI mode takes over 600ms (SMM execution, and hence no interrupts delivered during that time), and with Xen using the PIT (PM timer support was added by Keir as a result of this, but that doesn't cure the problem here, it just reduces the likelihood it'll be encountered) platform time and local time got pretty much out of sync.

Xen itself knows to deal with this (by using an error correction factor to slow down the local [TSC-based] clock), but for the kernel such a situation may be fatal: If clocksource->cycle_last was most recently set on a CPU with shadow->tsc_to_nsec_mul sufficiently different from that where getnstimeofday() is being used, timekeeping.c's __get_nsec_offset() will calculate a huge nanosecond value (due to cyc2ns() doing unsigned operations), worth abut 4000s. This value may then be used to set a timeout that was intended to be a few milliseconds, effectively yielding a hung app (and perhaps system).

I'm sure the time keeping code can't deal with negative values returned from __get_nsec_offset() (timespec_add_ns() is an example, used in __get_realtime_clock_ts()), otherwise a potential solution might have been to set the clock source's multiplier and shift to one and zero respectively. But I think that a clock source can be expected to be monotonic anyway, which Xen's interpolation mechanism doesn't guarantee across multiple CPUs. (I'm actually beginning to think that this might also be the reason for certain test suites occasionally reporting timeouts to fire early.)

Unfortunately so far I haven't been able to think of a reasonable solution to this - a simplistic approach like making xen_clocksource_read() check the value it is about to return against the last value it returned doesn't seem to be a good idea (time might appear to have stopped over some period of time otherwise), nor does attempting to adjust the shadowed tsc_to_nsec_mul values (because the kernel can't know whether it should boost the lagging CPU or throttle the rushing one).

Jan

#16 lore raw

Re: [Xen-devel] [patch 14/33] xen: xen time implementation

Quoted 6 lines · Jan Beulich

The issue is
that on that system, transition into ACPI mode takes over 600ms (SMM execution, and hence no interrupts delivered during that time), and with Xen using the PIT (PM timer support was added by Keir as a result of this, but that doesn't cure the problem here, it just reduces the likelihood it'll be encountered) platform time and local time got pretty much out of sync.

If you have an ACPI PM timer in your system (and if you have SMM then your system is almost certainly modern enough to have one) then surely the problem is fixed for all practical purposes? The problem was overflow of a fixed-width platform counter. The PIT wraps every ~50ms, but the ACPI PM timer will wrap only every ~4s. It would be quite unreasonable for SMM to take the CPU away for multiple seconds, even as a one-time boot operation.

-- Keir

#17 lore raw

Re: [Xen-devel] [patch 14/33] xen: xen time implementation

Quoted 10 lines
Quoted 1 line
Quoted 1 line

Keir Fraser <[email protected]> 06.06.07 10:54 >>>

Quoted 6 lines · Jan Beulich

The issue is
that on that system, transition into ACPI mode takes over 600ms (SMM execution, and hence no interrupts delivered during that time), and with Xen using the PIT (PM timer support was added by Keir as a result of this, but that doesn't cure the problem here, it just reduces the likelihood it'll be encountered) platform time and local time got pretty much out of sync.

Quoted 6 lines

If you have an ACPI PM timer in your system (and if you have SMM then your system is almost certainly modern enough to have one) then surely the problem is fixed for all practical purposes? The problem was overflow of a fixed-width platform counter. The PIT wraps every ~50ms, but the ACPI PM timer will wrap only every ~4s. It would be quite unreasonable for SMM to take the CPU away for multiple seconds, even as a one-time boot operation.

No, I don't think the problem's gone with the PM timer - it is just much less likely. Since you depend on the TSC (which must generally be assumed be unsyncronized across CPUs) and on the error correction factor (which shows non-zero values every few seconds), getting the interpolated times on two CPUs out of sync is still possible, and given the way the time keeping code works even being off by just a single nanosecond may be fatal.

Jan

#18 lore raw

Re: [Xen-devel] [patch 14/33] xen: xen time implementation

Quoted 7 lines · Jan Beulich
Quoted 6 lines

If you have an ACPI PM timer in your system (and if you have SMM then your system is almost certainly modern enough to have one) then surely the problem is fixed for all practical purposes? The problem was overflow of a fixed-width platform counter. The PIT wraps every ~50ms, but the ACPI PM timer will wrap only every ~4s. It would be quite unreasonable for SMM to take the CPU away for multiple seconds, even as a one-time boot operation.

Quoted 6 lines

No, I don't think the problem's gone with the PM timer - it is just much less likely. Since you depend on the TSC (which must generally be assumed be unsyncronized across CPUs) and on the error correction factor (which shows non-zero values every few seconds), getting the interpolated times on two CPUs out of sync is still possible, and given the way the time keeping code works even being off by just a single nanosecond may be fatal.

If the error across CPUS is +/- just a few microseconds at worst then having the clocksource clamp to no less than the last timestamp returned seems a reasonable fix. Time won't 'stop' for longer than the cross-CPU error, and that should always be a tiny value.

-- Keir

#19 lore raw

Re: [Xen-devel] [patch 14/33] xen: xen time implementation

Quoted 17 lines
Quoted 1 line
Quoted 1 line

Keir Fraser <[email protected]> 06.06.07 11:56 >>>

Quoted 7 lines · Jan Beulich
Quoted 6 lines

If you have an ACPI PM timer in your system (and if you have SMM then your system is almost certainly modern enough to have one) then surely the problem is fixed for all practical purposes? The problem was overflow of a fixed-width platform counter. The PIT wraps every ~50ms, but the ACPI PM timer will wrap only every ~4s. It would be quite unreasonable for SMM to take the CPU away for multiple seconds, even as a one-time boot operation.

Quoted 6 lines

No, I don't think the problem's gone with the PM timer - it is just much less likely. Since you depend on the TSC (which must generally be assumed be unsyncronized across CPUs) and on the error correction factor (which shows non-zero values every few seconds), getting the interpolated times on two CPUs out of sync is still possible, and given the way the time keeping code works even being off by just a single nanosecond may be fatal.

Quoted 4 lines

If the error across CPUS is +/- just a few microseconds at worst then having the clocksource clamp to no less than the last timestamp returned seems a reasonable fix. Time won't 'stop' for longer than the cross-CPU error, and that should always be a tiny value.

Are you sure this is also true when e.g. a CPU gets throttled due to thermal conditions? It is my understanding that both the duty cycle adjustment and the frequency reduction would yield a reduced rate TSC, which would be accounted for only the next time the local clock gets calibrated. Otherwise, immediate calibration (and vcpu update) would need to be forced out of the thermal interrupt.

Jan

#20 lore raw

Re: [Xen-devel] [patch 14/33] xen: xen time implementation

Quoted 11 lines · Jan Beulich
Quoted 4 lines

If the error across CPUS is +/- just a few microseconds at worst then having the clocksource clamp to no less than the last timestamp returned seems a reasonable fix. Time won't 'stop' for longer than the cross-CPU error, and that should always be a tiny value.

Are you sure this is also true when e.g. a CPU gets throttled due to thermal conditions? It is my understanding that both the duty cycle adjustment and the frequency reduction would yield a reduced rate TSC, which would be accounted for only the next time the local clock gets calibrated. Otherwise, immediate calibration (and vcpu update) would need to be forced out of the thermal interrupt.

Yes, this could be an issue. Is there any way to get an interrupt or MCE when thermal throttling occurs?

-- Keir

#21 lore raw

RE: [patch 14/33] xen: xen time implementation

Quoted 33 lines

-----Original Message-----
From: [email protected] [mailto:[email protected]] On Behalf Of Keir Fraser
Sent: 06 June 2007 12:53
To: Jan Beulich
Cc: Jeremy Fitzhardinge; Xen-devel; lkml; Andi Kleen; Chris Wright; [email protected]; Thomas Gleixner; Andrew Morton; Linus Torvalds; Ingo Molnar
Subject: Re: [Xen-devel] [patch 14/33] xen: xen time implementation

Quoted 1 line · Jan Beulich
Quoted 1 line

If the error across CPUS is +/- just a few microseconds at

worst then having

Quoted 1 line
Quoted 1 line

the clocksource clamp to no less than the last timestamp

returned seems a

Quoted 1 line
Quoted 1 line

reasonable fix. Time won't 'stop' for longer than the

cross-CPU error, and

Quoted 3 lines
Quoted 1 line

that should always be a tiny value.

Are you sure this is also true when e.g. a CPU gets

throttled due to thermal

Quoted 1 line

conditions? It is my understanding that both the duty cycle

adjustment and

Quoted 1 line

the frequency reduction would yield a reduced rate TSC,

which would be

Quoted 1 line

accounted for only the next time the local clock gets

Quoted 8 lines

calibrated. Otherwise,

Quoted 1 line

immediate calibration (and vcpu update) would need to be

forced out of the

Quoted 1 line

thermal interrupt.

Yes, this could be an issue. Is there any way to get an interrupt or MCE
when thermal throttling occurs?

As far as I'm aware, no. The normal way to "throttle" a procoessor is a Pulse-Width-modulation on the STOPCLK pin, and the duration is in the order of microseconds, so an interrupt every few microseconds may not leave much room for the processor to actually do ANYTHING at that point.

Of course, it would be possible to design such hardware that does clock-throttling to indicate "Clock throttling started" and "clock throttling stopped" or some such, but as far as I'm aware, this is not how it works.

Some thermal sensors can give interrupts at certain levels of temperature, but that's not the same as start/stop clock throttling. [I reduced the distribution list a bit - I'm not sure if everyone needs to understand/know my thoughts on this subject]

--
Mats

Quoted 11 lines

-- Keir

_______________________________________________
Xen-devel mailing list
[email protected]
http://lists.xensource.com/xen-devel

#22 lore raw

RE: [patch 14/33] xen: xen time implementation

Quoted 10 lines
Quoted 3 lines

Yes, this could be an issue. Is there any way to get an interrupt or MCE
when thermal throttling occurs?

As far as I'm aware, no. The normal way to "throttle" a procoessor is a Pulse-Width-modulation on the STOPCLK pin, and the duration is in the order of microseconds, so an interrupt every few microseconds may not leave much room for the processor to actually do ANYTHING at that point.

Quoted 4 lines

Of course, it would be possible to design such hardware that does clock-throttling to indicate "Clock throttling started" and "clock throttling stopped" or some such, but as far as I'm aware, this is not how it works.

There already is such an interrupt being generated (and used) on newer Intel CPUs - see xen/arch/x86/cpu/mcheck/p4.c.

Jan

#23 lore raw

Re: [Xen-devel] [patch 14/33] xen: xen time implementation

In reply to Keir Fraser
Quoted 4 lines

Yes, this could be an issue. Is there any way to get an interrupt or MCE when thermal throttling occurs?

Yes you can get an thermal interrupt from the local APIC. See the Linux kernel source. Of course there would be still a race window.

On the other hand some timing issues on throttling are probably the smallest of the users' problems when it really happens.

Standard Linux just ignores it.

-Andi

#24 lore raw

Re: [Xen-devel] [patch 14/33] xen: xen time implementation

Quoted 11 lines
Quoted 5 lines
Quoted 1 line

Andi Kleen <[email protected]> 06.06.07 14:18 >>>

Yes, this could be an issue. Is there any way to get an interrupt or MCE when thermal throttling occurs?

Yes you can get an thermal interrupt from the local APIC. See the Linux kernel source. Of course there would be still a race window.

On the other hand some timing issues on throttling are probably the smallest of the users' problems when it really happens.

Not if this results in your box hanging - I think throttling is exactly intended to keep the box alive as long as possible (and I've seen throttling in action, with the box happily recovering from the situation - after having seen it a few times I checked and found the fan covered with dust).

Quoted 1 line

Standard Linux just ignores it.

Jan

#25 lore raw

Re: [Xen-devel] [patch 14/33] xen: xen time implementation

Quoted 6 lines · On Wednesday 06 June 2007 14:46:59 Jan Beulich wrote:
Quoted 6 lines
Quoted 5 lines
Quoted 1 line

Andi Kleen <[email protected]> 06.06.07 14:18 >>>

Yes, this could be an issue. Is there any way to get an interrupt or MCE when thermal throttling occurs?

Quoted 7 lines
Quoted 5 lines

Yes you can get an thermal interrupt from the local APIC. See the Linux kernel source. Of course there would be still a race window.

On the other hand some timing issues on throttling are probably the smallest of the users' problems when it really happens.

Not if this results in your box hanging

Yes it shouldn't hang. Just saying that some non monotonicity in the returned values under this abnormal condition is probably not the world's end.

-Andi

#26 lore raw

Re: [Xen-devel] [patch 14/33] xen: xen time implementation

In reply to Jan Beulich
Quoted 8 lines · Jan Beulich
Quoted 2 lines

On the other hand some timing issues on throttling are probably the smallest of the users' problems when it really happens.

Not if this results in your box hanging - I think throttling is exactly intended
to keep the box alive as long as possible (and I've seen throttling in action, with the box happily recovering from the situation - after having seen it a few times I checked and found the fan covered with dust).

Clamping to last returned timestamp value would be fine here. Time would go moderately haywire for a while (lurch forwards and then stop for a while), but wouldn't go backwards and should recover reasonably within the timescale of the thermal event itself. I don't see an issue with just implementing this clamping if it is needed.

-- Keir

#27 lore raw

Re: [Xen-devel] [patch 14/33] xen: xen time implementation

In reply to Jan Beulich
Quoted 8 lines · Jan Beulich
Quoted 2 lines

On the other hand some timing issues on throttling are probably the smallest of the users' problems when it really happens.

Not if this results in your box hanging - I think throttling is exactly intended
to keep the box alive as long as possible (and I've seen throttling in action, with the box happily recovering from the situation - after having seen it a few times I checked and found the fan covered with dust).

Clamping to last returned timestamp value would be fine here. Time would go moderately haywire for a while (lurch forwards and then stop for a while), but wouldn't go backwards and should recover reasonably within the timescale of the thermal event itself. I don't see an issue with just implementing this clamping if it is needed.

-- Keir

#28 lore raw

Re: [Xen-devel] [patch 14/33] xen: xen time implementation

In reply to Jan Beulich
Quoted 8 lines · Jan Beulich
Quoted 2 lines

On the other hand some timing issues on throttling are probably the smallest of the users' problems when it really happens.

Not if this results in your box hanging - I think throttling is exactly intended
to keep the box alive as long as possible (and I've seen throttling in action, with the box happily recovering from the situation - after having seen it a few times I checked and found the fan covered with dust).

Clamping to last returned timestamp value would be fine here. Time would go moderately haywire for a while (lurch forwards and then stop for a while), but wouldn't go backwards and should recover reasonably within the timescale of the thermal event itself. I don't see an issue with just implementing this clamping if it is needed.

-- Keir

#29 lore raw

Re: [Xen-devel] [patch 14/33] xen: xen time implementation

In reply to Jan Beulich
Quoted 11 lines · Jan Beulich
Quoted 4 lines

If the error across CPUS is +/- just a few microseconds at worst then having the clocksource clamp to no less than the last timestamp returned seems a reasonable fix. Time won't 'stop' for longer than the cross-CPU error, and that should always be a tiny value.

Are you sure this is also true when e.g. a CPU gets throttled due to thermal conditions? It is my understanding that both the duty cycle adjustment and the frequency reduction would yield a reduced rate TSC, which would be accounted for only the next time the local clock gets calibrated. Otherwise, immediate calibration (and vcpu update) would need to be forced out of the thermal interrupt.

Yes, this could be an issue. Is there any way to get an interrupt or MCE when thermal throttling occurs?

-- Keir

#30 lore raw

Re: [Xen-devel] [patch 14/33] xen: xen time implementation

In reply to Jan Beulich
Quoted 11 lines · Jan Beulich
Quoted 4 lines

If the error across CPUS is +/- just a few microseconds at worst then having the clocksource clamp to no less than the last timestamp returned seems a reasonable fix. Time won't 'stop' for longer than the cross-CPU error, and that should always be a tiny value.

Are you sure this is also true when e.g. a CPU gets throttled due to thermal conditions? It is my understanding that both the duty cycle adjustment and the frequency reduction would yield a reduced rate TSC, which would be accounted for only the next time the local clock gets calibrated. Otherwise, immediate calibration (and vcpu update) would need to be forced out of the thermal interrupt.

Yes, this could be an issue. Is there any way to get an interrupt or MCE when thermal throttling occurs?

-- Keir

#31 lore raw

Re: [Xen-devel] [patch 14/33] xen: xen time implementation

In reply to Jan Beulich
Quoted 7 lines · Jan Beulich
Quoted 6 lines

If you have an ACPI PM timer in your system (and if you have SMM then your system is almost certainly modern enough to have one) then surely the problem is fixed for all practical purposes? The problem was overflow of a fixed-width platform counter. The PIT wraps every ~50ms, but the ACPI PM timer will wrap only every ~4s. It would be quite unreasonable for SMM to take the CPU away for multiple seconds, even as a one-time boot operation.

Quoted 6 lines

No, I don't think the problem's gone with the PM timer - it is just much less likely. Since you depend on the TSC (which must generally be assumed be unsyncronized across CPUs) and on the error correction factor (which shows non-zero values every few seconds), getting the interpolated times on two CPUs out of sync is still possible, and given the way the time keeping code works even being off by just a single nanosecond may be fatal.

If the error across CPUS is +/- just a few microseconds at worst then having the clocksource clamp to no less than the last timestamp returned seems a reasonable fix. Time won't 'stop' for longer than the cross-CPU error, and that should always be a tiny value.

-- Keir

#32 lore raw

Re: [Xen-devel] [patch 14/33] xen: xen time implementation

In reply to Jan Beulich
Quoted 7 lines · Jan Beulich
Quoted 6 lines

If you have an ACPI PM timer in your system (and if you have SMM then your system is almost certainly modern enough to have one) then surely the problem is fixed for all practical purposes? The problem was overflow of a fixed-width platform counter. The PIT wraps every ~50ms, but the ACPI PM timer will wrap only every ~4s. It would be quite unreasonable for SMM to take the CPU away for multiple seconds, even as a one-time boot operation.

Quoted 6 lines

No, I don't think the problem's gone with the PM timer - it is just much less likely. Since you depend on the TSC (which must generally be assumed be unsyncronized across CPUs) and on the error correction factor (which shows non-zero values every few seconds), getting the interpolated times on two CPUs out of sync is still possible, and given the way the time keeping code works even being off by just a single nanosecond may be fatal.

If the error across CPUS is +/- just a few microseconds at worst then having the clocksource clamp to no less than the last timestamp returned seems a reasonable fix. Time won't 'stop' for longer than the cross-CPU error, and that should always be a tiny value.

-- Keir

#33 lore raw

Re: [Xen-devel] [patch 14/33] xen: xen time implementation

In reply to Jan Beulich
Quoted 6 lines · Jan Beulich

The issue is
that on that system, transition into ACPI mode takes over 600ms (SMM execution, and hence no interrupts delivered during that time), and with Xen using the PIT (PM timer support was added by Keir as a result of this, but that doesn't cure the problem here, it just reduces the likelihood it'll be encountered) platform time and local time got pretty much out of sync.

If you have an ACPI PM timer in your system (and if you have SMM then your system is almost certainly modern enough to have one) then surely the problem is fixed for all practical purposes? The problem was overflow of a fixed-width platform counter. The PIT wraps every ~50ms, but the ACPI PM timer will wrap only every ~4s. It would be quite unreasonable for SMM to take the CPU away for multiple seconds, even as a one-time boot operation.

-- Keir

#34 lore raw

Re: [Xen-devel] [patch 14/33] xen: xen time implementation

In reply to Jan Beulich
Quoted 6 lines · Jan Beulich

The issue is
that on that system, transition into ACPI mode takes over 600ms (SMM execution, and hence no interrupts delivered during that time), and with Xen using the PIT (PM timer support was added by Keir as a result of this, but that doesn't cure the problem here, it just reduces the likelihood it'll be encountered) platform time and local time got pretty much out of sync.

If you have an ACPI PM timer in your system (and if you have SMM then your system is almost certainly modern enough to have one) then surely the problem is fixed for all practical purposes? The problem was overflow of a fixed-width platform counter. The PIT wraps every ~50ms, but the ACPI PM timer will wrap only every ~4s. It would be quite unreasonable for SMM to take the CPU away for multiple seconds, even as a one-time boot operation.

-- Keir

#35 lore raw

Re: [Xen-devel] [patch 14/33] xen: xen time implementation

In reply to Jan Beulich
Quoted 10 lines · Jan Beulich

Xen itself knows to deal with this (by using an error correction factor to slow down the local [TSC-based] clock), but for the kernel such a situation may be fatal: If clocksource->cycle_last was most recently set on a CPU with shadow->tsc_to_nsec_mul sufficiently different from that where getnstimeofday() is being used, timekeeping.c's __get_nsec_offset() will calculate a huge nanosecond value (due to cyc2ns() doing unsigned operations), worth abut 4000s. This value may then be used to set a timeout that was intended to be a few milliseconds, effectively yielding a hung app (and perhaps system).

Hm. I had a similar situation in the stolen time code, and I ended up using signed values so I could clamp at zero. Though that might have been another bug; either way, the clamp is still there.

I wonder if cyc2ns might not be better using signed operations? Or perhaps better, the time code should endevour to do things on a completely per-cpu basis (haven't really given this any thought).

Quoted 5 lines

I'm sure the time keeping code can't deal with negative values returned from __get_nsec_offset() (timespec_add_ns() is an example, used in __get_realtime_clock_ts()), otherwise a potential solution might have been to set the clock source's multiplier and shift to one and zero respectively.

I don't quite follow you here, but wouldn't setting the multiplier/shift to 1/0 preclude being able to warp the clocksource with ntp?

Quoted 6 lines

But I think that a clock source can be expected to be
monotonic anyway, which Xen's interpolation mechanism doesn't guarantee across multiple CPUs. (I'm actually beginning to think that this might also be the reason for certain test suites occasionally reporting timeouts to fire early.)

Does the kernel expect the tsc clocksource to be completely monotonic across cpus? Any form of cpu-local clocksource is going to have this problem; I wonder if clocksources can really only be useful if they're always referring to a single system-wide time reference - seems like a bit of a limitation.

Quoted 7 lines

Unfortunately so far I haven't been able to think of a reasonable solution to this - a simplistic approach like making xen_clocksource_read() check the value it is about to return against the last value it returned doesn't seem to be a good idea (time might appear to have stopped over some period of time otherwise), nor does attempting to adjust the shadowed tsc_to_nsec_mul values (because the kernel can't know whether it should boost the lagging CPU or throttle the rushing one).

I once had some code in there to do that, implemented in very boneheaded way with a spinlock to protect the "last time returned" variable. I expect there's a better way to implement it.

J

#36 lore raw

Re: [Xen-devel] [patch 14/33] xen: xen time implementation

Quoted 7 lines
Quoted 6 lines

But I think that a clock source can be expected to be
monotonic anyway, which Xen's interpolation mechanism doesn't guarantee across multiple CPUs. (I'm actually beginning to think that this might also be the reason for certain test suites occasionally reporting timeouts to fire early.)

Quoted 5 lines

Does the kernel expect the tsc clocksource to be completely monotonic across cpus? Any form of cpu-local clocksource is going to have this problem; I wonder if clocksources can really only be useful if they're always referring to a single system-wide time reference - seems like a bit of a limitation.

I suppose so - the clock source's rating gets set to zero if it can be predicted that the TSCs aren't all synchronized, which should pretty much exclude the use of this clock source for any other than fallback if there's really nothing else available.

Jan

#37 lore raw

Re: [Xen-devel] [patch 14/33] xen: xen time implementation

In reply to Jeremy Fitzhardinge
Quoted 12 lines · On Wednesday 06 June 2007 12:05:22 Jeremy Fitzhardinge wrote:
Quoted 10 lines · Jan Beulich

Xen itself knows to deal with this (by using an error correction factor to slow down the local [TSC-based] clock), but for the kernel such a situation may be fatal: If clocksource->cycle_last was most recently set on a CPU with shadow->tsc_to_nsec_mul sufficiently different from that where getnstimeofday() is being used, timekeeping.c's __get_nsec_offset() will calculate a huge nanosecond value (due to cyc2ns() doing unsigned operations), worth abut 4000s. This value may then be used to set a timeout that was intended to be a few milliseconds, effectively yielding a hung app (and perhaps system).

Quoted 7 lines

Hm. I had a similar situation in the stolen time code, and I ended up using signed values so I could clamp at zero. Though that might have been another bug; either way, the clamp is still there.

I wonder if cyc2ns might not be better using signed operations? Or perhaps better, the time code should endevour to do things on a completely per-cpu basis (haven't really given this any thought).

This is being worked on.

Quoted 11 lines
Quoted 7 lines

Unfortunately so far I haven't been able to think of a reasonable solution to this - a simplistic approach like making xen_clocksource_read() check the value it is about to return against the last value it returned doesn't seem to be a good idea (time might appear to have stopped over some period of time otherwise), nor does attempting to adjust the shadowed tsc_to_nsec_mul values (because the kernel can't know whether it should boost the lagging CPU or throttle the rushing one).

I once had some code in there to do that, implemented in very boneheaded way with a spinlock to protect the "last time returned" variable. I expect there's a better way to implement it.

But any per CPU setup likely needs this to avoid non monotonicity

-Andi

#38 lore raw

Re: [Xen-devel] [patch 14/33] xen: xen time implementation

Quoted 6 lines · Andi Kleen
Quoted 4 lines

I once had some code in there to do that, implemented in very boneheaded way with a spinlock to protect the "last time returned" variable. I expect there's a better way to implement it.

But any per CPU setup likely needs this to avoid non monotonicity

Yeah. The point I didn't quite make was that this should be something that the clock core should handle rather than dealing with it in every clocksource.

J

#39 lore raw

PATCH 15/33 xen: xen configuration

In reply to Jeremy Fitzhardinge

Put config options for Xen after the core pieces are in place.

---
 arch/i386/Kconfig     |    2 ++
 arch/i386/xen/Kconfig |   11 +++++++++++
 2 files changed, 13 insertions(+)

===================================================================

arch/i386/Kconfig +2 -0
@@ -217,6 +217,8 @@ config PARAVIRT
 	  under a hypervisor, improving performance significantly.
 	  However, when run without a hypervisor the kernel is
 	  theoretically slower.  If in doubt, say N.
+
+source "arch/i386/xen/Kconfig"
 
 config VMI
 	bool "VMI Paravirt-ops support"

===================================================================

arch/i386/xen/Kconfig new file +11 -0
@@ -0,0 +1,11 @@
+#
+# This Kconfig describes xen options
+#
+
+config XEN
+	bool "Enable support for Xen hypervisor"
+	depends on PARAVIRT && !PREEMPT && !SMP
+	help
+	  This is the Linux Xen port.  Enabling this will allow the
+	  kernel to boot in a paravirtualized environment under the
+	  Xen hypervisor.
#40 lore raw

PATCH 16/33 xen: xen: add pinned page flag

In reply to Jeremy Fitzhardinge

Add a new definition for PG_owner_priv_1 to define PG_pinned on Xen pagetable pages.

---
 include/linux/page-flags.h |    5 +++++
 1 file changed, 5 insertions(+)

===================================================================

include/linux/page-flags.h +5 -0
@@ -93,6 +93,7 @@
 
 /* PG_owner_priv_1 users should have descriptive aliases */
 #define PG_checked		PG_owner_priv_1 /* Used by some filesystems */
+#define PG_pinned		PG_owner_priv_1	/* Xen pinned pagetable */
 
 #if (BITS_PER_LONG > 32)
 /*
@@ -170,6 +171,10 @@ static inline void SetPageUptodate(struc
 #define PageChecked(page)	test_bit(PG_checked, &(page)->flags)
 #define SetPageChecked(page)	set_bit(PG_checked, &(page)->flags)
 #define ClearPageChecked(page)	clear_bit(PG_checked, &(page)->flags)
+
+#define PagePinned(page)	test_bit(PG_pinned, &(page)->flags)
+#define SetPagePinned(page)	set_bit(PG_pinned, &(page)->flags)
+#define ClearPagePinned(page)	clear_bit(PG_pinned, &(page)->flags)
 
 #define PageReserved(page)	test_bit(PG_reserved, &(page)->flags)
 #define SetPageReserved(page)	set_bit(PG_reserved, &(page)->flags)
#41 lore raw

PATCH 17/33 xen: Complete pagetable pinning for Xen

In reply to Jeremy Fitzhardinge

Xen requires all active pagetables to be marked read-only. When the base of the pagetable is loaded into %cr3, the hypervisor validates the entire pagetable and only allows the load to proceed if it all checks out.

This is pretty slow, so to mitigate this cost Xen has a notion of pinned pagetables. Pinned pagetables are pagetables which are considered to be active even if no processor's cr3 is pointing to is. This means that it must remain read-only and all updates are validated by the hypervisor. This makes context switches much cheaper, because the hypervisor doesn't need to revalidate the pagetable each time.

This also adds a new paravirt hook which is called during setup once the zones and memory allocator have been initialized. When the init_mm pagetable is first built, the struct page array does not yet exist, and so there's nowhere to put he init_mm pagetable's PG_pinned flags. Once the zones are initialized and the struct page array exists, we can set the PG_pinned flags for those pages.

This patch also adds the Xen support for pte pages allocated out of highmem (highpte) by implementing xen_kmap_atomic_pte.

---
 arch/i386/xen/enlighten.c |  107 ++++++++++++----
 arch/i386/xen/mmu.c       |  289 ++++++++++++++++++++++++++++-----------------
 arch/i386/xen/mmu.h       |    2 
 arch/i386/xen/xen-ops.h   |    2 
 4 files changed, 266 insertions(+), 134 deletions(-)

===================================================================

arch/i386/xen/enlighten.c +79 -28
@@ -21,6 +21,9 @@
 #include <linux/sched.h>
 #include <linux/bootmem.h>
 #include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/page-flags.h>
+#include <linux/highmem.h>
 
 #include <xen/interface/xen.h>
 #include <xen/interface/physdev.h>
@@ -496,32 +499,59 @@ static void xen_write_cr3(unsigned long 
 	}
 }
 
+/* Early in boot, while setting up the initial pagetable, assume
+   everything is pinned. */
+static void xen_alloc_pt_init(struct mm_struct *mm, u32 pfn)
+{
+	BUG_ON(mem_map);	/* should only be used early */
+	make_lowmem_page_readonly(__va(PFN_PHYS(pfn)));
+}
+
+/* This needs to make sure the new pte page is pinned iff its being
+   attached to a pinned pagetable. */
 static void xen_alloc_pt(struct mm_struct *mm, u32 pfn)
 {
-	/* XXX pfn isn't necessarily a lowmem page */
-	make_lowmem_page_readonly(__va(PFN_PHYS(pfn)));
-}
-
-static void xen_alloc_pd(u32 pfn)
-{
-	make_lowmem_page_readonly(__va(PFN_PHYS(pfn)));
-}
-
-static void xen_release_pd(u32 pfn)
-{
-	make_lowmem_page_readwrite(__va(PFN_PHYS(pfn)));
-}
-
+	struct page *page = pfn_to_page(pfn);
+
+	if (PagePinned(virt_to_page(mm->pgd))) {
+		SetPagePinned(page);
+
+		if (!PageHighMem(page))
+			make_lowmem_page_readonly(__va(PFN_PHYS(pfn)));
+		else
+			/* make sure there are no stray mappings of
+			   this page */
+			kmap_flush_unused();
+	}
+}
+
+/* This should never happen until we're OK to use struct page */
 static void xen_release_pt(u32 pfn)
 {
-	make_lowmem_page_readwrite(__va(PFN_PHYS(pfn)));
-}
-
-static void xen_alloc_pd_clone(u32 pfn, u32 clonepfn,
-					u32 start, u32 count)
-{
-	xen_alloc_pd(pfn);
-}
+	struct page *page = pfn_to_page(pfn);
+
+	if (PagePinned(page)) {
+		if (!PageHighMem(page))
+			make_lowmem_page_readwrite(__va(PFN_PHYS(pfn)));
+	}
+}
+
+#ifdef CONFIG_HIGHPTE
+static void *xen_kmap_atomic_pte(struct page *page, enum km_type type)
+{
+	pgprot_t prot = PAGE_KERNEL;
+
+	if (PagePinned(page))
+		prot = PAGE_KERNEL_RO;
+
+	if (0 && PageHighMem(page))
+		printk("mapping highpte %lx type %d prot %s\n",
+		       page_to_pfn(page), type,
+		       (unsigned long)pgprot_val(prot) & _PAGE_RW ? "WRITE" : "READ");
+
+	return kmap_atomic_prot(page, type, prot);
+}
+#endif
 
 static __init void xen_pagetable_setup_start(pgd_t *base)
 {
@@ -549,7 +579,7 @@ static __init void xen_pagetable_setup_s
 				memcpy(pmd, (void *)pgd_page_vaddr(xen_pgd[i]),
 				       PAGE_SIZE);
 
-				xen_alloc_pd(PFN_DOWN(__pa(pmd)));
+				make_lowmem_page_readonly(pmd);
 
 				set_pgd(&base[i], __pgd(1 + __pa(pmd)));
 			} else
@@ -570,6 +600,10 @@ static __init void xen_pagetable_setup_s
 
 static __init void xen_pagetable_setup_done(pgd_t *base)
 {
+	/* This will work as long as patching hasn't happened yet
+	   (which it hasn't) */
+	paravirt_ops.alloc_pt = xen_alloc_pt;
+
 	if (!xen_feature(XENFEAT_auto_translated_physmap)) {
 		/*
 		 * Create a mapping for the shared info page.
@@ -587,7 +621,19 @@ static __init void xen_pagetable_setup_d
 		HYPERVISOR_shared_info =
 			(struct shared_info *)__va(xen_start_info->shared_info);
 
-	xen_pgd_pin(base);
+	/* Actually pin the pagetable down, but we can't set PG_pinned
+	   yet because the page structures don't exist yet. */
+	{
+		struct mmuext_op op;
+#ifdef CONFIG_X86_PAE
+		op.cmd = MMUEXT_PIN_L3_TABLE;
+#else
+		op.cmd = MMUEXT_PIN_L3_TABLE;
+#endif
+		op.arg1.mfn = pfn_to_mfn(PFN_DOWN(__pa(base)));
+		if (HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF))
+			BUG();
+	}
 
 	xen_vcpu_setup(smp_processor_id());
 }
@@ -604,6 +650,7 @@ static const struct paravirt_ops xen_par
 	.memory_setup = xen_memory_setup,
 	.arch_setup = xen_arch_setup,
 	.init_IRQ = xen_init_IRQ,
+	.post_allocator_init = xen_mark_init_mm_pinned,
 
 	.time_init = xen_time_init,
 	.set_wallclock = xen_set_wallclock,
@@ -684,11 +731,15 @@ static const struct paravirt_ops xen_par
 	.pagetable_setup_start = xen_pagetable_setup_start,
 	.pagetable_setup_done = xen_pagetable_setup_done,
 
-	.alloc_pt = xen_alloc_pt,
-	.alloc_pd = xen_alloc_pd,
-	.alloc_pd_clone = xen_alloc_pd_clone,
-	.release_pd = xen_release_pd,
+	.alloc_pt = xen_alloc_pt_init,
 	.release_pt = xen_release_pt,
+	.alloc_pd = paravirt_nop,
+	.alloc_pd_clone = paravirt_nop,
+	.release_pd = paravirt_nop,
+
+#ifdef CONFIG_HIGHPTE
+	.kmap_atomic_pte = xen_kmap_atomic_pte,
+#endif
 
 	.set_pte = xen_set_pte,
 	.set_pte_at = xen_set_pte_at,

===================================================================

arch/i386/xen/mmu.c +184 -105

390 lines not on this page · raw message

===================================================================

arch/i386/xen/mmu.h +1 -1
@@ -15,7 +15,7 @@ void xen_exit_mmap(struct mm_struct *mm)
 void xen_exit_mmap(struct mm_struct *mm);
 
 void xen_pgd_pin(pgd_t *pgd);
-void xen_pgd_unpin(pgd_t *pgd);
+//void xen_pgd_unpin(pgd_t *pgd);
 
 #ifdef CONFIG_X86_PAE
 unsigned long long xen_pte_val(pte_t);

===================================================================

arch/i386/xen/xen-ops.h +2 -0
@@ -20,6 +20,8 @@ int xen_set_wallclock(unsigned long time
 int xen_set_wallclock(unsigned long time);
 cycle_t xen_clocksource_read(void);
 
+void xen_mark_init_mm_pinned(void);
+
 DECLARE_PER_CPU(enum paravirt_lazy_mode, xen_lazy_mode);
 
 static inline unsigned xen_get_lazy_mode(void)
#42 lore raw

PATCH 18/33 xen: xen: ignore RW mapping of RO pages in pagetable_init

In reply to Jeremy Fitzhardinge

When setting up the initial pagetable, which includes mappings of all low physical memory, ignore a mapping which tries to set the RW bit on an RO pte. An RO pte indicates a page which is part of the current pagetable, and so it cannot be allowed to become RW.

Once xen_pagetable_setup_done is called, set_pte reverts to its normal behaviour.

---
 arch/i386/xen/enlighten.c |   27 +++++++++++++++++++++++++--
 1 file changed, 25 insertions(+), 2 deletions(-)

===================================================================

arch/i386/xen/enlighten.c +25 -2
@@ -501,7 +501,7 @@ static void xen_write_cr3(unsigned long 
 
 /* Early in boot, while setting up the initial pagetable, assume
    everything is pinned. */
-static void xen_alloc_pt_init(struct mm_struct *mm, u32 pfn)
+static __init void xen_alloc_pt_init(struct mm_struct *mm, u32 pfn)
 {
 	BUG_ON(mem_map);	/* should only be used early */
 	make_lowmem_page_readonly(__va(PFN_PHYS(pfn)));
@@ -553,9 +553,31 @@ static void *xen_kmap_atomic_pte(struct 
 }
 #endif
 
+static __init pte_t mask_rw_pte(pte_t *ptep, pte_t pte)
+{
+	/* If there's an existing pte, then don't allow _PAGE_RW to be set */
+	if (pte_val_ma(*ptep) & _PAGE_PRESENT)
+		pte = __pte_ma(((pte_val_ma(*ptep) & _PAGE_RW) | ~_PAGE_RW) &
+			       pte_val_ma(pte));
+
+	return pte;
+}
+
+/* Init-time set_pte while constructing initial pagetables, which
+   doesn't allow RO pagetable pages to be remapped RW */
+static __init void xen_set_pte_init(pte_t *ptep, pte_t pte)
+{
+	pte = mask_rw_pte(ptep, pte);
+
+	xen_set_pte(ptep, pte);
+}
+
 static __init void xen_pagetable_setup_start(pgd_t *base)
 {
 	pgd_t *xen_pgd = (pgd_t *)xen_start_info->pt_base;
+
+	/* special set_pte for pagetable initialization */
+	paravirt_ops.set_pte = xen_set_pte_init;
 
 	init_mm.pgd = base;
 	/*
@@ -603,6 +625,7 @@ static __init void xen_pagetable_setup_d
 	/* This will work as long as patching hasn't happened yet
 	   (which it hasn't) */
 	paravirt_ops.alloc_pt = xen_alloc_pt;
+	paravirt_ops.set_pte = xen_set_pte;
 
 	if (!xen_feature(XENFEAT_auto_translated_physmap)) {
 		/*
@@ -741,7 +764,7 @@ static const struct paravirt_ops xen_par
 	.kmap_atomic_pte = xen_kmap_atomic_pte,
 #endif
 
-	.set_pte = xen_set_pte,
+	.set_pte = NULL,	/* see xen_pagetable_setup_* */
 	.set_pte_at = xen_set_pte_at,
 	.set_pmd = xen_set_pmd,
 
#43 lore raw

PATCH 19/33 xen: Account for time stolen by Xen

In reply to Jeremy Fitzhardinge

This patch accounts for the time Xen steals from our VCPUs. Stolen time is time where a vcpu is runnable and could be running, but all available physical CPUs are being used for something else.

This accounting gets run on each timer interrupt, just as a way to get it run relatively often, and when interesting things are going on. Stolen time is not really used by much in the kernel; it is reported in /proc/stats, and that's about it.

---
 arch/i386/xen/time.c |  163 ++++++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 153 insertions(+), 10 deletions(-)

===================================================================

arch/i386/xen/time.c +153 -10
@@ -11,6 +11,7 @@
 #include <linux/interrupt.h>
 #include <linux/clocksource.h>
 #include <linux/clockchips.h>
+#include <linux/kernel_stat.h>
 
 #include <asm/xen/hypervisor.h>
 #include <asm/xen/hypercall.h>
@@ -23,6 +24,7 @@
 
 #define XEN_SHIFT 22
 #define TIMER_SLOP	100000	/* Xen may fire a timer up to this many ns early */
+#define NS_PER_TICK	(1000000000ll / HZ)
 
 /* These are perodically updated in shared_info, and then copied here. */
 struct shadow_time_info {
@@ -35,6 +37,141 @@ struct shadow_time_info {
 
 static DEFINE_PER_CPU(struct shadow_time_info, shadow_time);
 
+/* runstate info updated by Xen */
+static DEFINE_PER_CPU(struct vcpu_runstate_info, runstate);
+
+/* snapshots of runstate info */
+static DEFINE_PER_CPU(struct vcpu_runstate_info, runstate_snapshot);
+
+/* unused ns of stolen and blocked time */
+static DEFINE_PER_CPU(u64, residual_stolen);
+static DEFINE_PER_CPU(u64, residual_blocked);
+
+/* return an consistent snapshot of 64-bit time/counter value */
+static u64 get64(const u64 *p)
+{
+	u64 ret;
+
+	if (BITS_PER_LONG < 64) {
+		u32 *p32 = (u32 *)p;
+		u32 h, l;
+
+		/*
+		 * Read high then low, and then make sure high is
+		 * still the same; this will only loop if low wraps
+		 * and carries into high.
+		 * XXX some clean way to make this endian-proof?
+		 */
+		do {
+			h = p32[1];
+			barrier();
+			l = p32[0];
+			barrier();
+		} while (p32[1] != h);
+
+		ret = (((u64)h) << 32) | l;
+	} else
+		ret = *p;
+
+	return ret;
+}
+
+/*
+ * Runstate accounting
+ */
+static void get_runstate_snapshot(struct vcpu_runstate_info *res)
+{
+	u64 state_time;
+	struct vcpu_runstate_info *state;
+
+	preempt_disable();
+
+	state = &__get_cpu_var(runstate);
+
+	/*
+	 * The runstate info is always updated by the hypervisor on
+	 * the current CPU, so there's no need to use anything
+	 * stronger than a compiler barrier when fetching it.
+	 */
+	do {
+		state_time = get64(&state->state_entry_time);
+		barrier();
+		*res = *state;
+		barrier();
+	} while(get64(&state->state_entry_time) != state_time);
+
+	preempt_enable();
+}
+
+static void setup_runstate_info(void)
+{
+	struct vcpu_register_runstate_memory_area area;
+
+	area.addr.v = &__get_cpu_var(runstate);
+
+	if (HYPERVISOR_vcpu_op(VCPUOP_register_runstate_memory_area,
+			       smp_processor_id(), &area))
+		BUG();
+
+	get_runstate_snapshot(&__get_cpu_var(runstate_snapshot));
+}
+
+static void do_stolen_accounting(void)
+{
+	struct vcpu_runstate_info state;
+	struct vcpu_runstate_info *snap;
+	s64 blocked, runnable, offline, stolen;
+	cputime_t ticks;
+
+	get_runstate_snapshot(&state);
+
+	WARN_ON(state.state != RUNSTATE_running);
+
+	snap = &__get_cpu_var(runstate_snapshot);
+
+	/* work out how much time the VCPU has not been runn*ing*  */
+	blocked = state.time[RUNSTATE_blocked] - snap->time[RUNSTATE_blocked];
+	runnable = state.time[RUNSTATE_runnable] - snap->time[RUNSTATE_runnable];
+	offline = state.time[RUNSTATE_offline] - snap->time[RUNSTATE_offline];
+
+	*snap = state;
+
+	/* Add the appropriate number of ticks of stolen time,
+	   including any left-overs from last time.  Passing NULL to
+	   account_steal_time accounts the time as stolen. */
+	stolen = runnable + offline + __get_cpu_var(residual_stolen);
+
+	if (stolen < 0)
+		stolen = 0;
+
+	ticks = 0;
+	while(stolen >= NS_PER_TICK) {
+		ticks++;
+		stolen -= NS_PER_TICK;
+	}
+	__get_cpu_var(residual_stolen) = stolen;
+	account_steal_time(NULL, ticks);
+
+	/* Add the appropriate number of ticks of blocked time,
+	   including any left-overs from last time.  Passing idle to
+	   account_steal_time accounts the time as idle/wait. */
+	blocked += __get_cpu_var(residual_blocked);
+
+	if (blocked < 0)
+		blocked = 0;
+
+	ticks = 0;
+	while(blocked >= NS_PER_TICK) {
+		ticks++;
+		blocked -= NS_PER_TICK;
+	}
+	__get_cpu_var(residual_blocked) = blocked;
+	account_steal_time(idle_task(smp_processor_id()), ticks);
+}
+
+
+
+/* Get the CPU speed from Xen */
 unsigned long xen_cpu_khz(void)
 {
 	u64 cpu_khz = 1000000ULL << 32;
@@ -54,12 +191,10 @@ unsigned long xen_cpu_khz(void)
  * Reads a consistent set of time-base values from Xen, into a shadow data
  * area.
  */
-static void get_time_values_from_xen(void)
+static unsigned get_time_values_from_xen(void)
 {
 	struct vcpu_time_info   *src;
 	struct shadow_time_info *dst;
-
-	preempt_disable();
 
 	src = &__get_cpu_var(xen_vcpu)->time;
 	dst = &__get_cpu_var(shadow_time);
@@ -74,7 +209,7 @@ static void get_time_values_from_xen(voi
 		rmb();
 	} while ((src->version & 1) | (dst->version ^ src->version));
 
-	preempt_enable();
+	return dst->version;
 }
 
 /*
@@ -118,7 +253,7 @@ static u64 get_nsec_offset(struct shadow
 static u64 get_nsec_offset(struct shadow_time_info *shadow)
 {
 	u64 now, delta;
-	rdtscll(now);
+	now = native_read_tsc();
 	delta = now - shadow->tsc_timestamp;
 	return scale_delta(delta, shadow->tsc_to_nsec_mul, shadow->tsc_shift);
 }
@@ -127,10 +262,14 @@ cycle_t xen_clocksource_read(void)
 {
 	struct shadow_time_info *shadow = &get_cpu_var(shadow_time);
 	cycle_t ret;
-
-	get_time_values_from_xen();
-
-	ret = shadow->system_timestamp + get_nsec_offset(shadow);
+	unsigned version;
+
+	do {
+		version = get_time_values_from_xen();
+		barrier();
+		ret = shadow->system_timestamp + get_nsec_offset(shadow);
+		barrier();
+	} while(version != __get_cpu_var(xen_vcpu)->time.version);
 
 	put_cpu_var(shadow_time);
 
@@ -347,6 +486,8 @@ static irqreturn_t xen_timer_interrupt(i
 		ret = IRQ_HANDLED;
 	}
 
+	do_stolen_accounting();
+
 	return ret;
 }
 
@@ -373,6 +514,8 @@ static void xen_setup_timer(int cpu)
 	evt->irq = irq;
 	clockevents_register_device(evt);
 
+	setup_runstate_info();
+
 	put_cpu_var(xen_clock_events);
 }
 
@@ -385,7 +528,7 @@ __init void xen_time_init(void)
 	clocksource_register(&xen_clocksource);
 
 	if (HYPERVISOR_vcpu_op(VCPUOP_stop_periodic_timer, cpu, NULL) == 0) {
-		/* Successfully turned off 100hz tick, so we have the
+		/* Successfully turned off 100Hz tick, so we have the
 		   vcpuop-based timer interface */
 		printk(KERN_DEBUG "Xen: using vcpuop timer interface\n");
 		xen_clockevent = &xen_vcpuop_clockevent;
#44 lore raw

PATCH 20/33 xen: Implement xen_sched_clock

In reply to Jeremy Fitzhardinge

Implement xen_sched_clock, which returns the number of ns the current vcpu has been actually in an unstolen state (ie, running or blocked, vs runnable-but-not-running, or offline) since boot.

---
 arch/i386/xen/enlighten.c |    2 +-
 arch/i386/xen/time.c      |   27 ++++++++++++++++++++++++++-
 arch/i386/xen/xen-ops.h   |    3 +--
 3 files changed, 28 insertions(+), 4 deletions(-)

===================================================================

arch/i386/xen/enlighten.c +1 -1
@@ -679,7 +679,7 @@ static const struct paravirt_ops xen_par
 	.set_wallclock = xen_set_wallclock,
 	.get_wallclock = xen_get_wallclock,
 	.get_cpu_khz = xen_cpu_khz,
-	.sched_clock = xen_clocksource_read,
+	.sched_clock = xen_sched_clock,
 
 	.cpuid = xen_cpuid,
 

===================================================================

arch/i386/xen/time.c +26 -1
@@ -26,6 +26,8 @@
 #define TIMER_SLOP	100000	/* Xen may fire a timer up to this many ns early */
 #define NS_PER_TICK	(1000000000ll / HZ)
 
+static cycle_t xen_clocksource_read(void);
+
 /* These are perodically updated in shared_info, and then copied here. */
 struct shadow_time_info {
 	u64 tsc_timestamp;     /* TSC at last update of time vals.  */
@@ -169,6 +171,29 @@ static void do_stolen_accounting(void)
 	account_steal_time(idle_task(smp_processor_id()), ticks);
 }
 
+/*
+ * Xen sched_clock implementation.  Returns the number of unstolen
+ * nanoseconds, which is nanoseconds the VCPU spent in RUNNING+BLOCKED
+ * states.
+ */
+unsigned long long xen_sched_clock(void)
+{
+	struct vcpu_runstate_info state;
+	cycle_t now = xen_clocksource_read();
+	s64 offset;
+
+	get_runstate_snapshot(&state);
+
+	WARN_ON(state.state != RUNSTATE_running);
+
+	offset = now - state.state_entry_time;
+	if (offset < 0)
+		offset = 0;
+
+ 	return state.time[RUNSTATE_blocked] +
+ 		state.time[RUNSTATE_running] +
+		offset;
+}
 
 
 /* Get the CPU speed from Xen */
@@ -258,7 +283,7 @@ static u64 get_nsec_offset(struct shadow
 	return scale_delta(delta, shadow->tsc_to_nsec_mul, shadow->tsc_shift);
 }
 
-cycle_t xen_clocksource_read(void)
+static cycle_t xen_clocksource_read(void)
 {
 	struct shadow_time_info *shadow = &get_cpu_var(shadow_time);
 	cycle_t ret;

===================================================================

arch/i386/xen/xen-ops.h +1 -2
@@ -2,7 +2,6 @@
 #define XEN_OPS_H
 
 #include <linux/init.h>
-#include <linux/clocksource.h>
 
 DECLARE_PER_CPU(struct vcpu_info *, xen_vcpu);
 DECLARE_PER_CPU(unsigned long, xen_cr3);
@@ -18,7 +17,7 @@ void __init xen_time_init(void);
 void __init xen_time_init(void);
 unsigned long xen_get_wallclock(void);
 int xen_set_wallclock(unsigned long time);
-cycle_t xen_clocksource_read(void);
+unsigned long long xen_sched_clock(void);
 
 void xen_mark_init_mm_pinned(void);
 
#45 lore raw

PATCH 21/33 xen: Xen SMP guest support

In reply to Jeremy Fitzhardinge

This is a fairly straightforward Xen implementation of smp_ops.

Xen has its own IPI mechanisms, and has no dependency on any APIC-based IPI. The smp_ops hooks and the flush_tlb_others pv_op allow a Xen guest to avoid all APIC code in arch/i386 (the only apic operation is a single apic_read for the apic version number).

One subtle point which needs to be addressed is unpinning pagetables when another cpu may have a lazy tlb reference to the pagetable. Xen will not allow an in-use pagetable to be unpinned, so we must find any other cpus with a reference to the pagetable and get them to shoot down their references.

---
 arch/i386/xen/Kconfig     |    2 
 arch/i386/xen/Makefile    |    2 
 arch/i386/xen/enlighten.c |  117 +++++++++---
 arch/i386/xen/events.c    |   78 ++++++++
 arch/i386/xen/mmu.c       |   75 ++++++--
 arch/i386/xen/mmu.h       |   13 +
 arch/i386/xen/setup.c     |    5 
 arch/i386/xen/smp.c       |  407 +++++++++++++++++++++++++++++++++++++++++++++
 arch/i386/xen/time.c      |   27 +-
 arch/i386/xen/xen-ops.h   |   25 ++
 include/xen/events.h      |   27 ++
 11 files changed, 713 insertions(+), 65 deletions(-)

===================================================================

arch/i386/xen/Kconfig +1 -1
@@ -4,7 +4,7 @@
 
 config XEN
 	bool "Enable support for Xen hypervisor"
-	depends on PARAVIRT && !PREEMPT && !SMP
+	depends on PARAVIRT && !PREEMPT
 	help
 	  This is the Linux Xen port.  Enabling this will allow the
 	  kernel to boot in a paravirtualized environment under the

===================================================================

arch/i386/xen/Makefile +2 -0
@@ -1,2 +1,4 @@ obj-y		:= enlighten.o setup.o features.o
 obj-y		:= enlighten.o setup.o features.o multicalls.o mmu.o \
 			events.o time.o
+
+obj-$(CONFIG_SMP)	+= smp.o

===================================================================

arch/i386/xen/enlighten.c +90 -27

188 lines not on this page · raw message

===================================================================

arch/i386/xen/events.c +77 -1

108 lines not on this page · raw message

===================================================================

arch/i386/xen/mmu.c +55 -20

90 lines not on this page · raw message

===================================================================

arch/i386/xen/mmu.h +13 -0
@@ -2,6 +2,19 @@
 
 #include <linux/linkage.h>
 #include <asm/page.h>
+
+/*
+ * Page-directory addresses above 4GB do not fit into architectural %cr3.
+ * When accessing %cr3, or equivalent field in vcpu_guest_context, guests
+ * must use the following accessor macros to pack/unpack valid MFNs.
+ *
+ * Note that Xen is using the fact that the pagetable base is always
+ * page-aligned, and putting the 12 MSB of the address into the 12 LSB
+ * of cr3.
+ */
+#define xen_pfn_to_cr3(pfn) (((unsigned)(pfn) << 12) | ((unsigned)(pfn) >> 20))
+#define xen_cr3_to_pfn(cr3) (((unsigned)(cr3) >> 12) | ((unsigned)(cr3) << 20))
+
 
 void set_pte_mfn(unsigned long vaddr, unsigned long pfn, pgprot_t flags);
 

===================================================================

arch/i386/xen/setup.c +5 -0
@@ -93,4 +93,9 @@ void __init xen_arch_setup(void)
 	       COMMAND_LINE_SIZE : MAX_GUEST_CMDLINE);
 
 	pm_idle = xen_idle;
+
+#ifdef CONFIG_SMP
+	/* fill cpus_possible with all available cpus */
+	xen_fill_possible_map();
+#endif
 }

===================================================================

arch/i386/xen/smp.c new file +407 -0

407 lines not on this page · raw message

===================================================================

arch/i386/xen/time.c +15 -12
@@ -105,17 +105,15 @@ static void get_runstate_snapshot(struct
 	preempt_enable();
 }
 
-static void setup_runstate_info(void)
+static void setup_runstate_info(int cpu)
 {
 	struct vcpu_register_runstate_memory_area area;
 
-	area.addr.v = &__get_cpu_var(runstate);
+	area.addr.v = &per_cpu(runstate, cpu);
 
 	if (HYPERVISOR_vcpu_op(VCPUOP_register_runstate_memory_area,
 			       smp_processor_id(), &area))
 		BUG();
-
-	get_runstate_snapshot(&__get_cpu_var(runstate_snapshot));
 }
 
 static void do_stolen_accounting(void)
@@ -516,7 +514,7 @@ static irqreturn_t xen_timer_interrupt(i
 	return ret;
 }
 
-static void xen_setup_timer(int cpu)
+void xen_setup_timer(int cpu)
 {
 	const char *name;
 	struct clock_event_device *evt;
@@ -532,16 +530,20 @@ static void xen_setup_timer(int cpu)
 				      IRQF_DISABLED|IRQF_PERCPU|IRQF_NOBALANCING,
 				      name, NULL);
 
-	evt = &get_cpu_var(xen_clock_events);
+	evt = &per_cpu(xen_clock_events, cpu);
 	memcpy(evt, xen_clockevent, sizeof(*evt));
 
 	evt->cpumask = cpumask_of_cpu(cpu);
 	evt->irq = irq;
-	clockevents_register_device(evt);
-
-	setup_runstate_info();
-
-	put_cpu_var(xen_clock_events);
+
+	setup_runstate_info(cpu);
+}
+
+void xen_setup_cpu_clockevents(void)
+{
+	BUG_ON(preemptible());
+
+	clockevents_register_device(&__get_cpu_var(xen_clock_events));
 }
 
 __init void xen_time_init(void)
@@ -567,4 +569,5 @@ __init void xen_time_init(void)
 	tsc_disable = 0;
 
 	xen_setup_timer(cpu);
-}
+	xen_setup_cpu_clockevents();
+}

===================================================================

arch/i386/xen/xen-ops.h +25 -0
@@ -2,6 +2,12 @@
 #define XEN_OPS_H
 
 #include <linux/init.h>
+
+/* These are code, but not functions.  Defined in entry.S */
+extern const char xen_hypervisor_callback[];
+extern const char xen_failsafe_callback[];
+
+void xen_copy_trap_info(struct trap_info *traps);
 
 DECLARE_PER_CPU(struct vcpu_info *, xen_vcpu);
 DECLARE_PER_CPU(unsigned long, xen_cr3);
@@ -13,6 +19,8 @@ void __init xen_arch_setup(void);
 void __init xen_arch_setup(void);
 void __init xen_init_IRQ(void);
 
+void xen_setup_timer(int cpu);
+void xen_setup_cpu_clockevents(void);
 unsigned long xen_cpu_khz(void);
 void __init xen_time_init(void);
 unsigned long xen_get_wallclock(void);
@@ -28,5 +36,22 @@ static inline unsigned xen_get_lazy_mode
 	return x86_read_percpu(xen_lazy_mode);
 }
 
+void __init xen_fill_possible_map(void);
+
+void xen_vcpu_setup(int cpu);
+void xen_smp_prepare_boot_cpu(void);
+void xen_smp_prepare_cpus(unsigned int max_cpus);
+int xen_cpu_up(unsigned int cpu);
+void xen_smp_cpus_done(unsigned int max_cpus);
+
+void xen_smp_send_stop(void);
+void xen_smp_send_reschedule(int cpu);
+int xen_smp_call_function (void (*func) (void *info), void *info, int nonatomic,
+			   int wait);
+int xen_smp_call_function_single(int cpu, void (*func) (void *info), void *info,
+				 int nonatomic, int wait);
+
+int xen_smp_call_function_mask(cpumask_t mask, void (*func)(void *),
+			       void *info, int wait);
 
 #endif /* XEN_OPS_H */

===================================================================

include/xen/events.h +23 -4
@@ -1,15 +1,32 @@
 #ifndef _XEN_EVENTS_H
 #define _XEN_EVENTS_H
 
-#include <linux/irq.h>
+#include <linux/interrupt.h>
+
+#include <xen/interface/event_channel.h>
+#include <asm/xen/hypercall.h>
+
+enum ipi_vector {
+	XEN_RESCHEDULE_VECTOR,
+	XEN_CALL_FUNCTION_VECTOR,
+
+	XEN_NR_IPIS,
+};
 
 int bind_evtchn_to_irqhandler(unsigned int evtchn,
-			      irqreturn_t (*handler)(int, void *),
+			      irq_handler_t handler,
 			      unsigned long irqflags, const char *devname,
 			      void *dev_id);
 int bind_virq_to_irqhandler(unsigned int virq, unsigned int cpu,
-			    irqreturn_t (*handler)(int, void *),
-			    unsigned long irqflags, const char *devname, void *dev_id);
+			    irq_handler_t handler,
+			    unsigned long irqflags, const char *devname,
+			    void *dev_id);
+int bind_ipi_to_irqhandler(enum ipi_vector ipi,
+			   unsigned int cpu,
+			   irq_handler_t handler,
+			   unsigned long irqflags,
+			   const char *devname,
+			   void *dev_id);
 
 /*
  * Common unbind function for all event sources. Takes IRQ to unbind from.
@@ -17,6 +34,8 @@ int bind_virq_to_irqhandler(unsigned int
  * made with bind_evtchn_to_irqhandler()).
  */
 void unbind_from_irqhandler(unsigned int irq, void *dev_id);
+
+void xen_send_IPI_one(unsigned int cpu, enum ipi_vector vector);
 
 static inline void notify_remote_via_evtchn(int port)
 {
#46 lore raw

Re: [Xen-devel] [patch 21/33] xen: Xen SMP guest support

Quoted 6 lines
arch/i386/xen/time.c +0 -0
@@ -105,17 +105,15 @@ static void get_runstate_snapshot(struct
 	preempt_enable();
 }
 

arch/i386/xen/time.c static void get_runstate_snapshot(struct · line 115

Quoted 10 lines
arch/i386/xen/time.c +2 -2
-static void setup_runstate_info(void)
+static void setup_runstate_info(int cpu)
 {
 	struct vcpu_register_runstate_memory_area area;
 
-	area.addr.v = &__get_cpu_var(runstate);
+	area.addr.v = &per_cpu(runstate, cpu);
 
 	if (HYPERVISOR_vcpu_op(VCPUOP_register_runstate_memory_area,
 			       smp_processor_id(), &area))

Shouldn't this be 'cpu' rather than 'smp_processor_id()'?

arch/i386/xen/time.c static void get_runstate_snapshot(struct · line 119

Quoted 6 lines
arch/i386/xen/time.c +0 -2
 		BUG();
-
-	get_runstate_snapshot(&__get_cpu_var(runstate_snapshot));
 }
 
 static void do_stolen_accounting(void)

Jan

#47 lore raw

Re: [Xen-devel] [patch 21/33] xen: Xen SMP guest support

Quoted 11 lines · Jan Beulich
Quoted 11 lines
arch/i386/xen/time.c +1 -1
@@ -105,17 +105,15 @@ static void get_runstate_snapshot(struct
 	preempt_enable();
 }
 
-static void setup_runstate_info(void)
+static void setup_runstate_info(int cpu)
 {
 	struct vcpu_register_runstate_memory_area area;
 
Quoted 9 lines

arch/i386/xen/time.c static void get_runstate_snapshot(struct · line 118

Quoted 6 lines
arch/i386/xen/time.c +1 -1
-	area.addr.v = &__get_cpu_var(runstate);
+	area.addr.v = &per_cpu(runstate, cpu);
 
 	if (HYPERVISOR_vcpu_op(VCPUOP_register_runstate_memory_area,
 			       smp_processor_id(), &area))
 

Shouldn't this be 'cpu' rather than 'smp_processor_id()'?

Yes. I'd noticed that, thought it got fixed later in the series, and looks like I ultimately got confused. Not sure when this crept in; it has been correct in the past.

J

#48 lore raw

PATCH 22/33 xen: Add support for preemption

In reply to Jeremy Fitzhardinge

Add Xen support for preemption. This is mostly a cleanup of existing preempt_enable/disable calls, or just comments to explain the current usage.

---
 arch/i386/xen/Kconfig      |    2 
 arch/i386/xen/enlighten.c  |  105 +++++++++++++++++++++++++-------------------
 arch/i386/xen/mmu.c        |    4 +
 arch/i386/xen/multicalls.c |   11 ++--
 arch/i386/xen/time.c       |   22 +++++++--
 5 files changed, 89 insertions(+), 55 deletions(-)

===================================================================

arch/i386/xen/Kconfig +1 -1
@@ -4,7 +4,7 @@
 
 config XEN
 	bool "Enable support for Xen hypervisor"
-	depends on PARAVIRT && !PREEMPT
+	depends on PARAVIRT
 	help
 	  This is the Linux Xen port.  Enabling this will allow the
 	  kernel to boot in a paravirtualized environment under the

===================================================================

arch/i386/xen/enlighten.c +62 -43

209 lines not on this page · raw message

===================================================================

arch/i386/xen/mmu.c +3 -1
@@ -529,5 +529,7 @@ void xen_exit_mmap(struct mm_struct *mm)
 	drop_mm_ref(mm);
 	put_cpu();
 
+	spin_lock(&mm->page_table_lock);
 	xen_pgd_unpin(mm->pgd);
-}
+	spin_unlock(&mm->page_table_lock);
+}

===================================================================

arch/i386/xen/multicalls.c +6 -5
@@ -20,6 +20,7 @@
  * Jeremy Fitzhardinge <[email protected]>, XenSource Inc, 2007
  */
 #include <linux/percpu.h>
+#include <linux/hardirq.h>
 
 #include <asm/xen/hypercall.h>
 
@@ -39,9 +40,11 @@ DEFINE_PER_CPU(unsigned long, xen_mc_irq
 
 void xen_mc_flush(void)
 {
-	struct mc_buffer *b = &get_cpu_var(mc_buffer);
+	struct mc_buffer *b = &__get_cpu_var(mc_buffer);
 	int ret = 0;
 	unsigned long flags;
+
+	BUG_ON(preemptible());
 
 	/* Disable interrupts in case someone comes in and queues
 	   something in the middle */
@@ -60,7 +63,6 @@ void xen_mc_flush(void)
 	} else
 		BUG_ON(b->argidx != 0);
 
-	put_cpu_var(mc_buffer);
 	local_irq_restore(flags);
 
 	BUG_ON(ret);
@@ -68,10 +70,11 @@ void xen_mc_flush(void)
 
 struct multicall_space __xen_mc_entry(size_t args)
 {
-	struct mc_buffer *b = &get_cpu_var(mc_buffer);
+	struct mc_buffer *b = &__get_cpu_var(mc_buffer);
 	struct multicall_space ret;
 	unsigned argspace = (args + sizeof(u64) - 1) / sizeof(u64);
 
+	BUG_ON(preemptible());
 	BUG_ON(argspace > MC_ARGS);
 
 	if (b->mcidx == MC_BATCH ||
@@ -83,7 +86,5 @@ struct multicall_space __xen_mc_entry(si
 	ret.args = &b->args[b->argidx];
 	b->argidx += argspace;
 
-	put_cpu_var(mc_buffer);
-
 	return ret;
 }

===================================================================

arch/i386/xen/time.c +17 -5
@@ -86,7 +86,7 @@ static void get_runstate_snapshot(struct
 	u64 state_time;
 	struct vcpu_runstate_info *state;
 
-	preempt_disable();
+	BUG_ON(preemptible());
 
 	state = &__get_cpu_var(runstate);
 
@@ -101,8 +101,6 @@ static void get_runstate_snapshot(struct
 		*res = *state;
 		barrier();
 	} while(get64(&state->state_entry_time) != state_time);
-
-	preempt_enable();
 }
 
 static void setup_runstate_info(int cpu)
@@ -177,8 +175,18 @@ unsigned long long xen_sched_clock(void)
 unsigned long long xen_sched_clock(void)
 {
 	struct vcpu_runstate_info state;
-	cycle_t now = xen_clocksource_read();
+	cycle_t now;
+	u64 ret;
 	s64 offset;
+
+	/*
+	 * Ideally sched_clock should be called on a per-cpu basis
+	 * anyway, so preempt should already be disabled, but that's
+	 * not current practice at the moment.
+	 */
+	preempt_disable();
+
+	now = xen_clocksource_read();
 
 	get_runstate_snapshot(&state);
 
@@ -188,9 +196,13 @@ unsigned long long xen_sched_clock(void)
 	if (offset < 0)
 		offset = 0;
 
- 	return state.time[RUNSTATE_blocked] +
+	ret = state.time[RUNSTATE_blocked] +
  		state.time[RUNSTATE_running] +
 		offset;
+
+	preempt_enable();
+
+	return ret;
 }
 
 
#49 lore raw

PATCH 23/33 xen: xen: lazy-mmu operations

In reply to Jeremy Fitzhardinge

This patch uses the lazy-mmu hooks to batch mmu operations where possible. This is primarily useful for batching operations applied to active pagetables, which happens during mprotect, munmap, mremap and the like (mmap does not do bulk pagetable operations, so it isn't helped).

---
 arch/i386/xen/enlighten.c  |   56 +++++++++++++++++++++++++++-----------------
 arch/i386/xen/mmu.c        |   56 ++++++++++++++++++++++++++++++++------------
 arch/i386/xen/multicalls.c |    4 +--
 3 files changed, 78 insertions(+), 38 deletions(-)

===================================================================

arch/i386/xen/enlighten.c +35 -21
@@ -451,28 +451,38 @@ static void xen_apic_write(unsigned long
 
 static void xen_flush_tlb(void)
 {
-	struct mmuext_op op;
-
-	op.cmd = MMUEXT_TLB_FLUSH_LOCAL;
-	if (HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF))
-		BUG();
+	struct mmuext_op *op;
+	struct multicall_space mcs = xen_mc_entry(sizeof(*op));
+
+	op = mcs.args;
+	op->cmd = MMUEXT_TLB_FLUSH_LOCAL;
+	MULTI_mmuext_op(mcs.mc, op, 1, NULL, DOMID_SELF);
+
+	xen_mc_issue(PARAVIRT_LAZY_MMU);
 }
 
 static void xen_flush_tlb_single(unsigned long addr)
 {
-	struct mmuext_op op;
-
-	op.cmd = MMUEXT_INVLPG_LOCAL;
-	op.arg1.linear_addr = addr & PAGE_MASK;
-	if (HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF))
-		BUG();
+	struct mmuext_op *op;
+	struct multicall_space mcs = xen_mc_entry(sizeof(*op));
+
+	op = mcs.args;
+	op->cmd = MMUEXT_INVLPG_LOCAL;
+	op->arg1.linear_addr = addr & PAGE_MASK;
+	MULTI_mmuext_op(mcs.mc, op, 1, NULL, DOMID_SELF);
+
+	xen_mc_issue(PARAVIRT_LAZY_MMU);
 }
 
 static void xen_flush_tlb_others(const cpumask_t *cpus, struct mm_struct *mm,
 				 unsigned long va)
 {
-	struct mmuext_op op;
+	struct {
+		struct mmuext_op op;
+		cpumask_t mask;
+	} *args;
 	cpumask_t cpumask = *cpus;
+	struct multicall_space mcs;
 
 	/*
 	 * A couple of (to be removed) sanity checks:
@@ -489,17 +499,21 @@ static void xen_flush_tlb_others(const c
 	if (cpus_empty(cpumask))
 		return;
 
+	mcs = xen_mc_entry(sizeof(*args));
+	args = mcs.args;
+	args->mask = cpumask;
+	args->op.arg2.vcpumask = &args->mask;
+
 	if (va == TLB_FLUSH_ALL) {
-		op.cmd = MMUEXT_TLB_FLUSH_MULTI;
-		op.arg2.vcpumask = (void *)cpus;
+		args->op.cmd = MMUEXT_TLB_FLUSH_MULTI;
 	} else {
-		op.cmd = MMUEXT_INVLPG_MULTI;
-		op.arg1.linear_addr = va;
-		op.arg2.vcpumask = (void *)cpus;
-	}
-
-	if (HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF))
-		BUG();
+		args->op.cmd = MMUEXT_INVLPG_MULTI;
+		args->op.arg1.linear_addr = va;
+	}
+
+	MULTI_mmuext_op(mcs.mc, &args->op, 1, NULL, DOMID_SELF);
+
+	xen_mc_issue(PARAVIRT_LAZY_MMU);
 }
 
 static unsigned long xen_read_cr2(void)

===================================================================

arch/i386/xen/mmu.c +41 -15

73 lines not on this page · raw message

===================================================================

arch/i386/xen/multicalls.c +2 -2
@@ -5,8 +5,8 @@
 
 #include "multicalls.h"
 
-#define MC_BATCH	8
-#define MC_ARGS		(MC_BATCH * 32 / sizeof(u64))
+#define MC_BATCH	32
+#define MC_ARGS		(MC_BATCH * 16 / sizeof(u64))
 
 struct mc_buffer {
 	struct multicall_entry entries[MC_BATCH];
#50 lore raw

PATCH 24/33 xen: xen: hack to prevent bad segment register reload

In reply to Jeremy Fitzhardinge

The hypervisor saves and restores the segment registers as part of the state is saves while context switching. If, during a context switch, the next process doesn't use the TLS segments, it invalidates the GDT entry, causing the segment register reload to fault. This fault effectively doubles the cost of a context switch.

This patch is a band-aid workaround which clears the usermode %gs after it has been saved for the previous process, but before it gets reloaded for the next, and it avoids having the hypervisor attempt to erroneously reload it.

---
 arch/i386/xen/enlighten.c |   12 ++++++++++++
 1 file changed, 12 insertions(+)

===================================================================

arch/i386/xen/enlighten.c +12 -0
@@ -291,6 +291,18 @@ static void xen_load_tls(struct thread_s
 	load_TLS_descriptor(t, cpu, 2);
 
 	xen_mc_issue(PARAVIRT_LAZY_CPU);
+
+	/*
+	 * XXX sleazy hack: If we're being called in a lazy-cpu zone,
+	 * it means we're in a context switch, and %gs has just been
+	 * saved.  This means we can zero it out to prevent faults on
+	 * exit from the hypervisor if the next process has no %gs.
+	 * Either way, it has been saved, and the new value will get
+	 * loaded properly.  This will go away as soon as Xen has been
+	 * modified to not save/restore %gs for normal hypercalls.
+	 */
+	if (xen_get_lazy_mode() == PARAVIRT_LAZY_CPU)
+		loadsegment(gs, 0);
 }
 
 static void xen_write_ldt_entry(struct desc_struct *dt, int entrynum, u32 low, u32 high)
#51 lore raw

PATCH 25/33 xen: Use the hvc console infrastructure for Xen console

In reply to Jeremy Fitzhardinge

Implement a Xen back-end for hvc console.

* * *
Add early printk support via hvc console, enable using "earlyprintk=xen" on the kernel command line.

From: Gerd Hoffmann <[email protected]>

---
 arch/i386/xen/events.c            |    3 
 arch/x86_64/kernel/early_printk.c |    5 +
 drivers/char/Kconfig              |    8 +
 drivers/char/Makefile             |    1 
 drivers/char/hvc_xen.c            |  159 +++++++++++++++++++++++++++++++++++++
 include/xen/events.h              |    1 
 include/xen/hvc-console.h         |    6 +
 7 files changed, 182 insertions(+), 1 deletion(-)

===================================================================

arch/i386/xen/events.c +2 -1
@@ -244,7 +244,7 @@ static int find_unbound_irq(void)
 	return irq;
 }
 
-static int bind_evtchn_to_irq(unsigned int evtchn)
+int bind_evtchn_to_irq(unsigned int evtchn)
 {
 	int irq;
 
@@ -269,6 +269,7 @@ static int bind_evtchn_to_irq(unsigned i
 
 	return irq;
 }
+EXPORT_SYMBOL_GPL(bind_evtchn_to_irq);
 
 static int bind_ipi_to_irq(unsigned int ipi, unsigned int cpu)
 {

===================================================================

arch/x86_64/kernel/early_printk.c +5 -0
@@ -6,6 +6,7 @@
 #include <asm/io.h>
 #include <asm/processor.h>
 #include <asm/fcntl.h>
+#include <xen/hvc-console.h>
 
 /* Simple VGA output */
 
@@ -242,6 +243,10 @@ static int __init setup_early_printk(cha
  		simnow_init(buf + 6);
  		early_console = &simnow_console;
  		keep_early = 1;
+#ifdef CONFIG_HVC_XEN
+	} else if (!strncmp(buf, "xen", 3)) {
+ 		early_console = &xenboot_console;
+#endif
 	}
 
 	if (keep_early)

===================================================================

drivers/char/Kconfig +8 -0
@@ -663,6 +663,14 @@ config HVC_BEAT
 	help
 	  Toshiba's Cell Reference Set Beat Console device driver
 
+config HVC_XEN
+	bool "Xen Hypervisor Console support"
+	depends on XEN
+	select HVC_DRIVER
+	default y
+	help
+	  Xen virtual console device driver
+
 config HVCS
 	tristate "IBM Hypervisor Virtual Console Server support"
 	depends on PPC_PSERIES

===================================================================

drivers/char/Makefile +1 -0
@@ -49,6 +49,7 @@ obj-$(CONFIG_HVC_RTAS)		+= hvc_rtas.o
 obj-$(CONFIG_HVC_RTAS)		+= hvc_rtas.o
 obj-$(CONFIG_HVC_BEAT)		+= hvc_beat.o
 obj-$(CONFIG_HVC_DRIVER)	+= hvc_console.o
+obj-$(CONFIG_HVC_XEN)		+= hvc_xen.o
 obj-$(CONFIG_RAW_DRIVER)	+= raw.o
 obj-$(CONFIG_SGI_SNSC)		+= snsc.o snsc_event.o
 obj-$(CONFIG_MSPEC)		+= mspec.o

===================================================================

drivers/char/hvc_xen.c new file +159 -0

159 lines not on this page · raw message

===================================================================

include/xen/events.h +1 -0
@@ -13,6 +13,7 @@ enum ipi_vector {
 	XEN_NR_IPIS,
 };
 
+int bind_evtchn_to_irq(unsigned int evtchn);
 int bind_evtchn_to_irqhandler(unsigned int evtchn,
 			      irq_handler_t handler,
 			      unsigned long irqflags, const char *devname,

===================================================================

include/xen/hvc-console.h new file +6 -0
@@ -0,0 +1,6 @@
+#ifndef XEN_HVC_CONSOLE_H
+#define XEN_HVC_CONSOLE_H
+
+extern struct console xenboot_console;
+
+#endif	/* XEN_HVC_CONSOLE_H */
#52 lore raw

PATCH 26/33 xen: Add Xen grant table support

In reply to Jeremy Fitzhardinge

Add Xen 'grant table' driver which allows granting of access to selected local memory pages by other virtual machines and, symmetrically, the mapping of remote memory pages which other virtual machines have granted access to.

This driver is a prerequisite for many of the Xen virtual device drivers, which grant the 'device driver domain' restricted and temporary access to only those memory pages that are currently involved in I/O operations.

---
 drivers/Makefile                    |    2 
 drivers/xen/Makefile                |    1 
 drivers/xen/grant-table.c           |  582 +++++++++++++++++++++++++++++++++++
 include/xen/grant_table.h           |  107 ++++++
 include/xen/interface/grant_table.h |   96 +++++
 5 files changed, 777 insertions(+), 11 deletions(-)

===================================================================

drivers/Makefile +2 -0
@@ -14,6 +14,8 @@ obj-$(CONFIG_ACPI)		+= acpi/
 # was used and do nothing if so
 obj-$(CONFIG_PNP)		+= pnp/
 obj-$(CONFIG_ARM_AMBA)		+= amba/
+
+obj-$(CONFIG_XEN)		+= xen/
 
 # char/ comes before serial/ etc so that the VT console is the boot-time
 # default.

===================================================================

drivers/xen/Makefile new file +1 -0
@@ -0,0 +1,1 @@
+obj-y	+= grant-table.o

===================================================================

drivers/xen/grant-table.c new file +582 -0

582 lines not on this page · raw message

===================================================================

include/xen/grant_table.h new file +107 -0

107 lines not on this page · raw message

===================================================================

include/xen/interface/grant_table.h +85 -11

157 lines not on this page · raw message

#53 lore raw

PATCH 27/33 xen: Add the Xenbus sysfs and virtual device hotplug driver.

In reply to Jeremy Fitzhardinge

This communicates with the machine control software via a registry residing in a controlling virtual machine. This allows dynamic creation, destruction and modification of virtual device configurations (network devices, block devices and CPUS, to name some examples).

[ Greg, would you mind giving this a review? Thanks -J ]

---
 drivers/xen/Makefile               |    1 
 drivers/xen/xenbus/Makefile        |    7 
 drivers/xen/xenbus/xenbus_client.c |  569 +++++++++++++++++++++
 drivers/xen/xenbus/xenbus_comms.c  |  233 ++++++++
 drivers/xen/xenbus/xenbus_comms.h  |   46 +
 drivers/xen/xenbus/xenbus_probe.c  |  935 ++++++++++++++++++++++++++++++++++++
 drivers/xen/xenbus/xenbus_probe.h  |   74 ++
 drivers/xen/xenbus/xenbus_xs.c     |  861 +++++++++++++++++++++++++++++++++
 include/asm-i386/xen/hypervisor.h  |    1 
 include/xen/xenbus.h               |  234 +++++++++
 10 files changed, 2961 insertions(+)

===================================================================

drivers/xen/Makefile +1 -0
@@ -1,1 +1,2 @@ obj-y	+= grant-table.o
 obj-y	+= grant-table.o
+obj-y	+= xenbus/

===================================================================

drivers/xen/xenbus/Makefile new file +7 -0
@@ -0,0 +1,7 @@
+obj-y	+= xenbus.o
+
+xenbus-objs =
+xenbus-objs += xenbus_client.o
+xenbus-objs += xenbus_comms.o
+xenbus-objs += xenbus_xs.o
+xenbus-objs += xenbus_probe.o

===================================================================

drivers/xen/xenbus/xenbus_client.c new file +569 -0

569 lines not on this page · raw message

===================================================================

drivers/xen/xenbus/xenbus_comms.c new file +233 -0

233 lines not on this page · raw message

===================================================================

drivers/xen/xenbus/xenbus_comms.h new file +46 -0

46 lines not on this page · raw message

===================================================================

drivers/xen/xenbus/xenbus_probe.c new file +935 -0

935 lines not on this page · raw message

===================================================================

drivers/xen/xenbus/xenbus_probe.h new file +74 -0

74 lines not on this page · raw message

===================================================================

drivers/xen/xenbus/xenbus_xs.c new file +861 -0

861 lines not on this page · raw message

===================================================================

include/asm-i386/xen/hypervisor.h +1 -0
@@ -42,6 +42,7 @@
 
 #include <asm/ptrace.h>
 #include <asm/page.h>
+#include <asm/desc.h>
 #if defined(__i386__)
 #  ifdef CONFIG_X86_PAE
 #   include <asm-generic/pgtable-nopud.h>

===================================================================

include/xen/xenbus.h new file +234 -0

234 lines not on this page · raw message

#54 lore raw

PATCH 28/33 xen: Add Xen virtual block device driver.

In reply to Jeremy Fitzhardinge

The block device frontend driver allows the kernel to access block devices exported exported by a virtual machine containing a physical block device driver.

---
 drivers/block/Kconfig        |    8 
 drivers/block/Makefile       |    1 
 drivers/block/xen-blkfront.c |  988 ++++++++++++++++++++++++++++++++++++++++++
 include/linux/major.h        |    2 
 4 files changed, 999 insertions(+)

===================================================================

drivers/block/Kconfig +8 -0
@@ -462,4 +462,12 @@ config XILINX_SYSACE
 	help
 	  Include support for the Xilinx SystemACE CompactFlash interface
 
+config XEN_BLKDEV_FRONTEND
+	tristate "Xen virtual block device support"
+	depends on XEN
+	help
+	  This driver implements the front-end of the Xen virtual
+	  block device driver.  It communicates with a back-end driver
+	  in another domain which drives the actual block device.
+
 endif # BLK_DEV

===================================================================

drivers/block/Makefile +1 -0
@@ -30,3 +30,4 @@ obj-$(CONFIG_BLK_DEV_UB)	+= ub.o
 obj-$(CONFIG_BLK_DEV_UB)	+= ub.o
 obj-$(CONFIG_XILINX_SYSACE)	+= xsysace.o
 obj-$(CONFIG_LGUEST_GUEST)	+= lguest_blk.o
+obj-$(CONFIG_XEN_BLKDEV_FRONTEND)	:= xen-blkfront.o

===================================================================

drivers/block/xen-blkfront.c new file +988 -0

988 lines not on this page · raw message

===================================================================

include/linux/major.h +2 -0
@@ -158,6 +158,8 @@
 #define VXSPEC_MAJOR		200	/* VERITAS volume config driver */
 #define VXDMP_MAJOR		201	/* VERITAS volume multipath driver */
 
+#define XENVBD_MAJOR		202	/* Xen virtual block device */
+
 #define MSR_MAJOR		202
 #define CPUID_MAJOR		203
 
#55 lore raw

PATCH 29/33 xen: Add the Xen virtual network device driver.

In reply to Jeremy Fitzhardinge

The network device frontend driver allows the kernel to access network devices exported exported by a virtual machine containing a physical network device driver.

Cc Ian Pratt <[email protected]>
Cc Christian Limpach <[email protected]>
Cc Jeff Garzik <[email protected]>
Cc Stephen Hemminger <[email protected]>
Cc Christoph Hellwig <[email protected]>
Cc Rusty Russell <[email protected]>
Cc Herbert Xu <[email protected]>
Cc Keir Fraser <[email protected]>
---
 drivers/net/Kconfig        |   12 
 drivers/net/Makefile       |    1 
 drivers/net/xen-netfront.c | 1995 ++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 2008 insertions(+)

===================================================================

drivers/net/Kconfig +12 -0
@@ -2583,6 +2583,18 @@ source "drivers/atm/Kconfig"
 
 source "drivers/s390/net/Kconfig"
 
+config XEN_NETDEV_FRONTEND
+	tristate "Xen network device frontend driver"
+	depends on XEN
+	default y
+	help
+	  The network device frontend driver allows the kernel to
+	  access network devices exported exported by a virtual
+	  machine containing a physical network device driver. The
+	  frontend driver is intended for unprivileged guest domains;
+	  if you are compiling a kernel for a Xen guest, you almost
+	  certainly want to enable this.
+
 config ISERIES_VETH
 	tristate "iSeries Virtual Ethernet driver support"
 	depends on PPC_ISERIES

===================================================================

drivers/net/Makefile +1 -0
@@ -229,3 +229,4 @@ obj-$(CONFIG_FS_ENET) += fs_enet/
 
 obj-$(CONFIG_NETXEN_NIC) += netxen/
 obj-$(CONFIG_LGUEST_GUEST) += lguest_net.o
+obj-$(CONFIG_XEN_NETDEV_FRONTEND) += xen-netfront.o

===================================================================

drivers/net/xen-netfront.c new file +1995 -0

1,995 lines not on this page · raw message

#56 lore raw

PATCH 30/33 xen: Xen machine operations

In reply to Jeremy Fitzhardinge

Make the appropriate hypercalls to halt and reboot the virtual machine.

---
 arch/i386/xen/enlighten.c |   43 +++++++++++++++++++++++++++++++++++++++++++
 arch/i386/xen/smp.c       |    4 +---
 2 files changed, 44 insertions(+), 3 deletions(-)

===================================================================

arch/i386/xen/enlighten.c +43 -0
@@ -14,6 +14,7 @@
 
 #include <xen/interface/xen.h>
 #include <xen/interface/vcpu.h>
+#include <xen/interface/sched.h>
 #include <xen/features.h>
 #include <xen/page.h>
 
@@ -28,6 +29,7 @@
 #include <asm/pgtable.h>
 #include <asm/smp.h>
 #include <asm/tlbflush.h>
+#include <asm/reboot.h>
 
 #include "xen-ops.h"
 #include "mmu.h"
@@ -787,6 +789,45 @@ static const struct smp_ops xen_smp_ops 
 };
 #endif	/* CONFIG_SMP */
 
+static void xen_reboot(int reason)
+{
+#ifdef CONFIG_SMP
+	smp_send_stop();
+#endif
+
+	if (HYPERVISOR_sched_op(SCHEDOP_shutdown, reason))
+		BUG();
+}
+
+static void xen_restart(char *msg)
+{
+	xen_reboot(SHUTDOWN_reboot);
+}
+
+static void xen_emergency_restart(void)
+{
+	xen_reboot(SHUTDOWN_reboot);
+}
+
+static void xen_machine_halt(void)
+{
+	xen_reboot(SHUTDOWN_poweroff);
+}
+
+static void xen_crash_shutdown(struct pt_regs *regs)
+{
+	xen_reboot(SHUTDOWN_crash);
+}
+
+static const struct machine_ops __initdata xen_machine_ops = {
+	.restart = xen_restart,
+	.halt = xen_machine_halt,
+	.power_off = xen_machine_halt,
+	.shutdown = xen_machine_halt,
+	.crash_shutdown = xen_crash_shutdown,
+	.emergency_restart = xen_emergency_restart,
+};
+
 /* First C function to be called on Xen boot */
 static asmlinkage void __init xen_start_kernel(void)
 {
@@ -800,6 +841,8 @@ static asmlinkage void __init xen_start_
 
 	/* Install Xen paravirt ops */
 	paravirt_ops = xen_paravirt_ops;
+	machine_ops = xen_machine_ops;
+
 #ifdef CONFIG_SMP
 	smp_ops = xen_smp_ops;
 #endif

===================================================================

arch/i386/xen/smp.c +1 -3
@@ -303,9 +303,7 @@ static void stop_self(void *v)
 
 void xen_smp_send_stop(void)
 {
-	cpumask_t mask = cpu_online_map;
-	cpu_clear(smp_processor_id(), mask);
-	xen_smp_call_function_mask(mask, stop_self, NULL, 0);
+	smp_call_function(stop_self, NULL, 0, 0);
 }
 
 void xen_smp_send_reschedule(int cpu)
#57 lore raw

PATCH 31/33 xen: xen: handle external requests for shutdown, reboot and sysrq

In reply to Jeremy Fitzhardinge

The guest domain can be asked to shutdown or reboot itself, or have a sysrq key injected, via xenbus. This patch adds a watcher for those events, and does the appropriate action.

---
 arch/i386/xen/Makefile |    2 
 arch/i386/xen/manage.c |  143 ++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 144 insertions(+), 1 deletion(-)

===================================================================

arch/i386/xen/Makefile +1 -1
@@ -1,4 +1,4 @@ obj-y		:= enlighten.o setup.o features.o
 obj-y		:= enlighten.o setup.o features.o multicalls.o mmu.o \
-			events.o time.o
+			events.o time.o manage.o
 
 obj-$(CONFIG_SMP)	+= smp.o

===================================================================

arch/i386/xen/manage.c new file +143 -0

143 lines not on this page · raw message

#58 lore raw

PATCH 32/33 xen: Place vcpu_info structure into per-cpu memory, if possible

In reply to Jeremy Fitzhardinge

An experimental patch for Xen allows guests to place their vcpu_info structs anywhere. We try to use this to place the vcpu_info into the PDA, which allows direct access.

If this works, then switch to using direct access operations for irq_enable, disable, save_fl and restore_fl.

---
 arch/i386/xen/enlighten.c    |  121 +++++++++++++++++++++++++++++++++++++++++-
 arch/i386/xen/setup.c        |    8 --
 include/xen/interface/vcpu.h |   13 ++++
 3 files changed, 133 insertions(+), 9 deletions(-)

===================================================================

arch/i386/xen/enlighten.c +120 -1
@@ -61,9 +61,55 @@ struct start_info *xen_start_info;
 struct start_info *xen_start_info;
 EXPORT_SYMBOL_GPL(xen_start_info);
 
+static /* __initdata */ struct shared_info dummy_shared_info;
+
+/*
+ * Point at some empty memory to start with. We map the real shared_info
+ * page as soon as fixmap is up and running.
+ */
+struct shared_info *HYPERVISOR_shared_info = (void *)&dummy_shared_info;
+
+/* tristate - -1: not tested, 0: not available, 1: available */
+static int have_vcpu_info_placement = -1;
+
 void xen_vcpu_setup(int cpu)
 {
+	struct vcpu_register_vcpu_info info;
+	int err;
+	struct vcpu_info *vcpup;
+
 	per_cpu(xen_vcpu, cpu) = &HYPERVISOR_shared_info->vcpu_info[cpu];
+
+	if (!have_vcpu_info_placement)
+		return;		/* already tested, not available */
+
+	vcpup = &per_cpu(xen_vcpu_info, cpu);
+
+	printk("setting up vcpu for %d: xen_vcpu_info=%p\n",
+	       cpu, vcpup);
+
+	info.mfn = virt_to_mfn(vcpup);
+	info.offset = offset_in_page(vcpup);
+
+	printk("trying to map vcpu_info %d at %p, mfn %x, offset %d\n",
+	       cpu, vcpup, info.mfn, info.offset);
+
+	/* Check to see if the hypervisor will put the vcpu_info
+	   structure where we want it, which allows direct access via
+	   a percpu-variable. */
+	err = HYPERVISOR_vcpu_op(VCPUOP_register_vcpu_info, cpu, &info);
+
+	BUG_ON(err != 0 && err != -ENOSYS);
+	BUG_ON(err && have_vcpu_info_placement==1);  /* all or nothing */
+
+	have_vcpu_info_placement = 0;
+
+	if (err == 0) {
+		have_vcpu_info_placement = 1;
+		per_cpu(xen_vcpu, cpu) = vcpup;
+		printk("cpu %d using vcpu_info at %p\n",
+		       cpu, vcpup);
+	}
 }
 
 static void __init xen_banner(void)
@@ -123,6 +169,20 @@ static unsigned long xen_save_fl(void)
 	return (-flags) & X86_EFLAGS_IF;
 }
 
+static unsigned long xen_save_fl_direct(void)
+{
+	unsigned long flags;
+
+	/* flag has opposite sense of mask */
+	flags = !x86_read_percpu(xen_vcpu_info.evtchn_upcall_mask);
+
+	/* convert to IF type flag
+	   -0 -> 0x00000000
+	   -1 -> 0xffffffff
+	*/
+	return (-flags) & X86_EFLAGS_IF;
+}
+
 static void xen_restore_fl(unsigned long flags)
 {
 	struct vcpu_info *vcpu;
@@ -149,6 +209,25 @@ static void xen_restore_fl(unsigned long
 	}
 }
 
+static void xen_restore_fl_direct(unsigned long flags)
+{
+	/* convert from IF type flag */
+	flags = !(flags & X86_EFLAGS_IF);
+
+	/* This is an atomic update, so no need to worry about
+	   preemption. */
+	x86_write_percpu(xen_vcpu_info.evtchn_upcall_mask, flags);
+
+	/* If we get preempted here, then any pending event will be
+	   handled anyway. */
+
+	if (flags == 0) {
+		barrier(); /* unmask then check (avoid races) */
+		if (unlikely(x86_read_percpu(xen_vcpu_info.evtchn_upcall_pending)))
+			force_evtchn_callback();
+	}
+}
+
 static void xen_irq_disable(void)
 {
 	/* There's a one instruction preempt window here.  We need to
@@ -157,6 +236,12 @@ static void xen_irq_disable(void)
 	preempt_disable();
 	x86_read_percpu(xen_vcpu)->evtchn_upcall_mask = 1;
 	preempt_enable_no_resched();
+}
+
+static void xen_irq_disable_direct(void)
+{
+	/* Atomic update, so preemption not a concern. */
+	x86_write_percpu(xen_vcpu_info.evtchn_upcall_mask, 1);
 }
 
 static void xen_irq_enable(void)
@@ -176,6 +261,19 @@ static void xen_irq_enable(void)
 
 	barrier(); /* unmask then check (avoid races) */
 	if (unlikely(vcpu->evtchn_upcall_pending))
+		force_evtchn_callback();
+}
+
+static void xen_irq_enable_direct(void)
+{
+	/* Atomic update, so preemption not a concern. */
+	x86_write_percpu(xen_vcpu_info.evtchn_upcall_mask, 0);
+
+	/* Doesn't matter if we get preempted here, because any
+	   pending event will get dealt with anyway. */
+
+	barrier(); /* unmask then check (avoid races) */
+	if (unlikely(x86_read_percpu(xen_vcpu_info.evtchn_upcall_pending)))
 		force_evtchn_callback();
 }
 
@@ -538,9 +636,19 @@ static void xen_flush_tlb_others(const c
 	xen_mc_issue(PARAVIRT_LAZY_MMU);
 }
 
+static void xen_write_cr2(unsigned long cr2)
+{
+	x86_read_percpu(xen_vcpu)->arch.cr2 = cr2;
+}
+
 static unsigned long xen_read_cr2(void)
 {
 	return x86_read_percpu(xen_vcpu)->arch.cr2;
+}
+
+static unsigned long xen_read_cr2_direct(void)
+{
+	return x86_read_percpu(xen_vcpu_info.arch.cr2);
 }
 
 static void xen_write_cr4(unsigned long cr4)
@@ -775,7 +883,7 @@ static const struct paravirt_ops xen_par
 	.write_cr0 = native_write_cr0,
 
 	.read_cr2 = xen_read_cr2,
-	.write_cr2 = native_write_cr2,
+	.write_cr2 = xen_write_cr2,
 
 	.read_cr3 = xen_read_cr3,
 	.write_cr3 = xen_write_cr3,
@@ -963,6 +1071,17 @@ static asmlinkage void __init xen_start_
 	x86_write_percpu(xen_cr3, __pa(pgd));
 	xen_vcpu_setup(0);
 
+	/* xen_vcpu_setup managed to place the vcpu_info within the
+	   pda, so make use of it */
+	BUG_ON(have_vcpu_info_placement == -1);
+	if (have_vcpu_info_placement) {
+		paravirt_ops.save_fl = xen_save_fl_direct;
+		paravirt_ops.restore_fl = xen_restore_fl_direct;
+		paravirt_ops.irq_disable = xen_irq_disable_direct;
+		paravirt_ops.irq_enable = xen_irq_enable_direct;
+		paravirt_ops.read_cr2 = xen_read_cr2_direct;
+	}
+
 	paravirt_ops.kernel_rpl = 1;
 	if (xen_feature(XENFEAT_supervisor_mode_kernel))
 		paravirt_ops.kernel_rpl = 0;

===================================================================

arch/i386/xen/setup.c +0 -8
@@ -22,14 +22,6 @@
 /* These are code, but not functions.  Defined in entry.S */
 extern const char xen_hypervisor_callback[];
 extern const char xen_failsafe_callback[];
-
-static __initdata struct shared_info init_shared;
-
-/*
- * Point at some empty memory to start with. We map the real shared_info
- * page as soon as fixmap is up and running.
- */
-struct shared_info *HYPERVISOR_shared_info = &init_shared;
 
 unsigned long *phys_to_machine_mapping;
 EXPORT_SYMBOL(phys_to_machine_mapping);

===================================================================

include/xen/interface/vcpu.h +13 -0
@@ -151,6 +151,19 @@ struct vcpu_set_singleshot_timer {
 #define _VCPU_SSHOTTMR_future (0)
 #define VCPU_SSHOTTMR_future  (1U << _VCPU_SSHOTTMR_future)
 
+/*
+ * Register a memory location in the guest address space for the
+ * vcpu_info structure.  This allows the guest to place the vcpu_info
+ * structure in a convenient place, such as in a per-cpu data area.
+ * The pointer need not be page aligned, but the structure must not
+ * cross a page boundary.
+ */
+#define VCPUOP_register_vcpu_info   10  /* arg == struct vcpu_info */
+struct vcpu_register_vcpu_info {
+    uint32_t mfn;               /* mfn of page to place vcpu_info */
+    uint32_t offset;            /* offset within page */
+};
+
 #endif /* __XEN_PUBLIC_VCPU_H__ */
 
 /*
#59 lore raw

PATCH 33/33 xen: Attempt to patch inline versions of common operations

In reply to Jeremy Fitzhardinge

This patchs adds the mechanism to allow us to patch inline versions of common operations.

The implementations of the direct-access versions save_fl, restore_fl, irq_enable and irq_disable are now in assembler, and the same code is used for both out of line and inline uses.

---
 arch/i386/kernel/asm-offsets.c |    7 ++
 arch/i386/xen/Makefile         |    2 
 arch/i386/xen/enlighten.c      |  108 +++++++++++++++++++------------------
 arch/i386/xen/xen-asm.S        |  114 ++++++++++++++++++++++++++++++++++++++++
 arch/i386/xen/xen-ops.h        |   13 ++++
 5 files changed, 190 insertions(+), 54 deletions(-)

===================================================================

arch/i386/kernel/asm-offsets.c +7 -0
@@ -16,6 +16,7 @@
 #include <asm/processor.h>
 #include <asm/thread_info.h>
 #include <asm/elf.h>
+#include <xen/interface/xen.h>
 #ifdef CONFIG_LGUEST_GUEST
 #include <linux/lguest.h>
 #include "../../../drivers/lguest/lg.h"
@@ -134,4 +135,10 @@ void foo(void)
 	OFFSET(LGUEST_PAGES_regs_errcode, lguest_pages, regs.errcode);
 	OFFSET(LGUEST_PAGES_regs, lguest_pages, regs);
 #endif
+
+#ifdef CONFIG_XEN
+	BLANK();
+	OFFSET(XEN_vcpu_info_mask, vcpu_info, evtchn_upcall_mask);
+	OFFSET(XEN_vcpu_info_pending, vcpu_info, evtchn_upcall_pending);
+#endif
 }

===================================================================

arch/i386/xen/Makefile +1 -1
@@ -1,4 +1,4 @@ obj-y		:= enlighten.o setup.o features.o
 obj-y		:= enlighten.o setup.o features.o multicalls.o mmu.o \
-			events.o time.o manage.o
+			events.o time.o manage.o xen-asm.o
 
 obj-$(CONFIG_SMP)	+= smp.o

===================================================================

arch/i386/xen/enlighten.c +55 -53

159 lines not on this page · raw message

===================================================================

arch/i386/xen/xen-asm.S new file +114 -0

114 lines not on this page · raw message

===================================================================

arch/i386/xen/xen-ops.h +13 -0
@@ -55,4 +55,17 @@ int xen_smp_call_function_mask(cpumask_t
 int xen_smp_call_function_mask(cpumask_t mask, void (*func)(void *),
 			       void *info, int wait);
 
+
+/* Declare an asm function, along with symbols needed to make it
+   inlineable */
+#define DECL_ASM(ret, name, ...)		\
+	ret name(__VA_ARGS__);			\
+	extern char name##_end[];		\
+	extern char name##_reloc[]		\
+
+DECL_ASM(void, xen_irq_enable_direct, void);
+DECL_ASM(void, xen_irq_disable_direct, void);
+DECL_ASM(unsigned long, xen_save_fl_direct, void);
+DECL_ASM(void, xen_restore_fl_direct, unsigned long);
+
 #endif /* XEN_OPS_H */
#60 lore raw
In reply to Jeremy Fitzhardinge
Quoted 4 lines · Jeremy Fitzhardinge

This is the Xen implementation for the paravirt_ops interface. The series is based on 2.6.22-rc1-mm1, and I think its ready to be cooked in -mm with a view to being merged in 2.6.23.

I already got it in my tree now from your previous post. Does this version have changes over that one?

-Andi

#61 lore raw
Quoted 7 lines · Andi Kleen
Quoted 4 lines

This is the Xen implementation for the paravirt_ops interface. The series is based on 2.6.22-rc1-mm1, and I think its ready to be cooked in -mm with a view to being merged in 2.6.23.

I already got it in my tree now from your previous post. Does this version have changes over that one?

Yes, I've done a few passes of tidying up, and spent some effort on beefing up the patch descriptions/changelogs. There are no significant functional differences though.

J