xen: Xen implementation for paravirt_ops
Subsystems (10)
cover xen: Xen implementation for paravirt_ops
Hi Andi,
This series of patches implements the Xen paravirt-ops interface. It applies to 2.6.21-git13 + patches-2.6.21-git7-070507-1.tar.gz (I think "unwinder" is the only patch which doesn't apply to git13, and the sched-clock patches are the only ones which this series actually needs).
Changes since the last posting:
- More netfront review and cleanup
- Added ability to cleanly halt/reboot guests from outside the domain.
- Folded bugfix patches into their main patch
- Lots of little style and other cleanups
These patches are now moderately well tested, with several successful runs through XenSource's regression test suite, and some amount of non-me testing. While I wouldn't go into production with a xen/paravirt_ops kernel right now, it does seem pretty functional.
This series generally restricts itself to Xen-specific parts of the tree, though it does make a few small changes elsewhere.
It includes:
- some helper routines for allocating address space and walking pagetables
- Xen interface header files
- Core Xen implementation (boot, mmu, events, time)
- Efficient late-pinning/early-unpinning pagetable handling
- Virtualized time, including stolen time
- SMP support
- Preemption support
- Batched pagetable updates
- Xen console, based on hvc console
- Xenbus
- Netfront, the paravirtualized network device
- Blockfront, the paravirtualized block device
Thanks,
J
PATCH 1/28 xen: Allocate and free vmalloc areas
Allocate/destroy a 'vmalloc' VM area: alloc_vm_area and free_vm_area The alloc function ensures that page tables are constructed for the region of kernel virtual address space and mapped into init_mm.
--- 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 (unsigned long 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
PATCH 2/28 xen: Add nosegneg capability to the vsyscall page notes
In reply to Jeremy FitzhardingeAdd 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 | 23 +++++++++++++++++++++++ include/asm-i386/elf.h | 14 ++++++++++---- 2 files changed, 33 insertions(+), 4 deletions(-)
===================================================================
arch/i386/kernel/vsyscall-note.S +23 -0
@@ -12,3 +12,26 @@ ELFNOTE_START(Linux, 0, "a") ELFNOTE_START(Linux, 0, "a") .long LINUX_VERSION_CODE ELFNOTE_END + +#ifdef CONFIG_XEN +#include <asm/elf.h> + +/* + * 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 0 nosegneg + * to match the mapping of bit to name that we give here. + */ +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
===================================================================
include/asm-i386/elf.h +10 -4
@@ -1,10 +1,12 @@#ifndef __ASMi386_ELF_H#define __ASMi386_ELF_H -/* -* ELF register definitions.. -*/ +/* 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. */ +#define VDSO_NOTE_NONEGSEG_BIT 1 +#ifndef __ASSEMBLY__#include <asm/ptrace.h> #include <asm/user.h> #include <asm/auxvec.h>
@@ -24,6 +26,9 @@#define R_386_GOTPC 10#define R_386_NUM 11 +/* +* ELF register definitions.. +*/ typedef unsigned long elf_greg_t ;#define ELF_NGREG (sizeof (struct user_regs_struct) / sizeof(elf_greg_t))
@@ -160,6 +165,7 @@ do if (vdso_enabled) { \NEW_AUX_ENT (AT_SYSINFO_EHDR ,VDSO_CURRENT_BASE ); \ } while (0) -#endif +#endif /* ARCH_DLINFO */ +#endif /* __ASSEMBLY__ */ #endif
Re: [patch 02/28]xen: Add nosegneg capability to the vsyscall page notes
Quoted 3 lines
+ * It should contain:
+ * hwcap 0 nosegneg
+ * to match the mapping of bit to name that we give here.
This comment still needs s/0/1/ to match the code. Given that the actual bit is now defined in the macro in another file, perhaps the comment should say more about it than just a magic 1.
Thanks,
Roland
Re: [patch 02/28]xen: Add nosegneg capability to the vsyscall page notes
Quoted 9 lines · Roland McGrath
Quoted 4 lines
+ * It should contain:
+ * hwcap 0 nosegneg
+ * to match the mapping of bit to name that we give here.This comment still needs s/0/1/ to match the code. Given that the actual bit is now defined in the macro in another file, perhaps the comment should say more about it than just a magic 1.
Crap, I thought I had 1) understood it, and 2) fixed it. I guess I skipped 1 and therefore overlooked 2.
J
PATCH 3/28 xen: Add Xen interface header files
In reply to Jeremy FitzhardingeAdd 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 | 96 +++++++ include/xen/interface/io/console.h | 23 + include/xen/interface/io/netif.h | 152 +++++++++++ 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, 3041 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 +96 -0
96 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 +152 -0
152 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
405 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.
PATCH 4/28 xen: Core Xen implementation
In reply to Jeremy FitzhardingeThis patch is a rollup of all the core pieces of the Xen implementation, including:
- booting and setup
- pagetable setup
- privileged instructions
- segmentation
- multicall batching
--- 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 | 731 ++++++++++++++++++++++++++++++++++++++ arch/i386/xen/features.c | 29 + arch/i386/xen/multicalls.c | 82 ++++ arch/i386/xen/multicalls.h | 26 + arch/i386/xen/setup.c | 96 ++++ arch/i386/xen/xen-head.S | 36 + arch/i386/xen/xen-ops.h | 34 + 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, 1334 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
@@ -516,7 +516,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)
@@ -541,6 +542,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
@@ -88,6 +88,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 +731 -0
731 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 +82 -0
82 lines not on this page · raw message
===================================================================
arch/i386/xen/multicalls.h new file +26 -0
@@ -0,0 +1,26 @@ +#ifndef _XEN_MULTICALLS_H +#define _XEN_MULTICALLS_H + +#include "xen-ops.h" + +/* Multicalls */ +struct multicall_space +{ +struct multicall_entry *mc; +void *args; +}; + +/* Allocate room for a multicall and its args */ +struct multicall_space xen_mc_entry (size_t args); + +/* Flush all pending multicalls */ +void xen_mc_flush (void ); + +/* Issue a multicall if we're not in lazy mode */ +static inline void xen_mc_issue (void ) +{ +if (xen_get_lazy_mode () ==PARAVIRT_LAZY_NONE ) +xen_mc_flush (); +} + +#endif /* _XEN_MULTICALLS_H */
===================================================================
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 +34 -0
@@ -0,0 +1,34 @@ +#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 ) +{ +unsigned ret =get_cpu_var (xen_lazy_mode); +put_cpu_var (xen_lazy_mode); + +return ret; +} + + +#endif /* XEN_OPS_H */
===================================================================
include/asm-i386/irq.h +1 -0
@@ -41,6 +41,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
PATCH 5/28 xen: Xen virtual mmu
In reply to Jeremy FitzhardingeXen pagetable handling, including the machinery to implement direct pagetables. This means that pte update operations are intercepted so that pseudo-physical addresses can be converted to machine addresses. It also implements late pinning/early unpinning so that pagetables are initialized while they're normal read-write memory as much as possible, yet pinned to make cr3 reloads as efficient as possible.
--- 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);
@@ -565,11 +566,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 );
@@ -578,9 +577,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 ()); }
@@ -682,6 +679,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
PATCH 6/28 xen: xen event channels
In reply to Jeremy FitzhardingeXen implements interrupts in terms of event channels. This patch maps an event through an event channel to an irq, and then feeds it through the normal interrupt path, via a Xen irq_chip implementation.
--- 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 */
PATCH 7/28 xen: xen time implementation
In reply to Jeremy FitzhardingeTime is implemented by using a clocksource which is driven from the hypervisor's nanosecond timebase. Xen implements time by extrapolating from known timestamps using the tsc; the hypervisor is responsible for making sure that the tsc is constant rate and synchronized between vcpus.
--- 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
PATCH 8/28 xen: xen configuration
In reply to Jeremy FitzhardingePut 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.
PATCH 9/28 xen: Complete pagetable pinning for Xen
In reply to Jeremy FitzhardingeXen has a notion of pinned pagetables, which are pagetables that remain read-only to the guest and are validated by the hypervisor. This makes context switches much cheaper, because the hypervisor doesn't need to revalidate the pagetable each time.
This patch adds a PG_pinned flag for pagetable pages so we can tell if it has been pinned or not. This allows various pagetable update optimisations.
This also adds a mm parameter to the alloc_pt pv_op, so that Xen can see if we're adding a page to a pinned pagetable. This is not necessary for alloc_pd or release_p[dt], which is fortunate because it isn't available at all callsites.
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), principly by implementing xen_kmap_atomic_pte.
--- arch/i386/kernel/setup.c | 3 arch/i386/kernel/vmi.c | 2 arch/i386/mm/init.c | 2 arch/i386/mm/pageattr.c | 2 arch/i386/xen/enlighten.c | 105 +++++++++++---- arch/i386/xen/mmu.c | 283 +++++++++++++++++++++++++++---------------- arch/i386/xen/mmu.h | 2 arch/i386/xen/xen-ops.h | 2 include/asm-i386/paravirt.h | 16 +- include/asm-i386/pgalloc.h | 6 include/asm-i386/setup.h | 4 include/linux/page-flags.h | 5 12 files changed, 289 insertions(+), 143 deletions(-)
===================================================================
arch/i386/kernel/setup.c +3 -0
@@ -607,9 +607,12 @@ void __init setup_arch(char **cmdline_p)sparse_init ();zone_sizes_init (); +/* * NOTE: at this point the bootmem allocator is fully available. */ + +paravirt_post_allocator_init ();dmi_scan_machine ();
===================================================================
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_iniif (!(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));
===================================================================
arch/i386/xen/enlighten.c +78 -27
153 lines not on this page · raw message
===================================================================
arch/i386/xen/mmu.c +178 -105
384 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 timeint 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 )
===================================================================
include/asm-i386/paravirt.h +12 -4
@@ -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 );
@@ -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);
@@ -682,6 +684,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)
@@ -738,9 +746,9 @@ static inline void flush_tlb_others(cpumPVOP_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))); \
===================================================================
include/asm-i386/setup.h +4 -0
@@ -79,6 +79,10 @@ void __init add_memory_region(unsigned lextern unsigned long init_pg_tables_end; +#ifndef CONFIG_PARAVIRT +#define paravirt_post_allocator_init () do {} while(0) +#endif +#endif /* __ASSEMBLY__ */ #endif /* __KERNEL__ */
===================================================================
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)
PATCH 10/28 xen: ignore RW mapping of RO pages in pagetable_init
In reply to Jeremy FitzhardingeWhen 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
@@ -635,7 +635,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)));
@@ -687,9 +687,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;/*
@@ -737,6 +759,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)) {/*
@@ -919,7 +942,7 @@ static const struct paravirt_ops xen_par .dup_mmap = xen_dup_mmap, .exit_mmap = xen_exit_mmap, - .set_pte = xen_set_pte, + .set_pte = NULL, /* see xen_pagetable_setup_* */ .set_pte_at = xen_set_pte_at, .set_pmd = xen_set_pmd,
PATCH 11/28 xen: fix multicall batching
In reply to Jeremy FitzhardingeDisable interrupts between allocating a multicall entry and actually issuing it, to prevent an interrupt from coming in, allocating and initializing further multicall entries, and then issuing them all, including the partially completed one.
--- arch/i386/xen/enlighten.c | 44 +++++++++++++++++++++++++++----------------- arch/i386/xen/mmu.c | 18 ++++++++++++------ arch/i386/xen/multicalls.c | 9 ++++++++- arch/i386/xen/multicalls.h | 27 +++++++++++++++++++++++---- arch/i386/xen/xen-ops.h | 5 +---- 5 files changed, 71 insertions(+), 32 deletions(-)
===================================================================
arch/i386/xen/enlighten.c +27 -17
@@ -187,13 +187,25 @@ static void xen_halt(void)static void xen_set_lazy_mode (enum paravirt_lazy_mode mode) { -enum paravirt_lazy_mode *lazy = &get_cpu_var (xen_lazy_mode); +switch (mode) { +case PARAVIRT_LAZY_NONE : +BUG_ON (x86_read_percpu (xen_lazy_mode) ==PARAVIRT_LAZY_NONE ); +break ; + +case PARAVIRT_LAZY_MMU : +case PARAVIRT_LAZY_CPU : +BUG_ON (x86_read_percpu (xen_lazy_mode) !=PARAVIRT_LAZY_NONE ); +break ; + +case PARAVIRT_LAZY_FLUSH : +/* flush if necessary, but don't change state */ +if (x86_read_percpu (xen_lazy_mode) !=PARAVIRT_LAZY_NONE ) +xen_mc_flush (); +return ; + }xen_mc_flush (); - - *lazy = mode; - -put_cpu_var (xen_lazy_mode); +x86_write_percpu (xen_lazy_mode, mode); }static unsigned long xen_store_tr (void )
@@ -220,7 +232,7 @@ static void xen_set_ldt(const void *addrMULTI_mmuext_op (mcs.mc, op,1 ,NULL ,DOMID_SELF ); -xen_mc_issue (); +xen_mc_issue (PARAVIRT_LAZY_CPU ); }static void xen_load_gdt (const struct Xgt_desc_struct *dtr)
@@ -248,7 +260,7 @@ static void xen_load_gdt(const struct XgMULTI_set_gdt (mcs.mc, frames, size /sizeof (struct desc_struct )); -xen_mc_issue (); +xen_mc_issue (PARAVIRT_LAZY_CPU ); } static void load_TLS_descriptor(struct thread_struct *t,
@@ -256,18 +268,20 @@ static void load_TLS_descriptor(struct t {struct desc_struct *gdt =get_cpu_gdt_table (cpu);xmaddr_t maddr =virt_to_machine (&gdt[GDT_ENTRY_TLS_MIN +i]); -struct multicall_space mc =xen_mc_entry (0 ); +struct multicall_space mc =__xen_mc_entry (0 );MULTI_update_descriptor (mc.mc, maddr.maddr, t->tls_array[i]); }static void xen_load_tls (struct thread_struct *t,unsigned int cpu) { +xen_mc_batch (); +load_TLS_descriptor (t, cpu,0 );load_TLS_descriptor (t, cpu,1 );load_TLS_descriptor (t, cpu,2 ); -xen_mc_issue (); +xen_mc_issue (PARAVIRT_LAZY_CPU ); }static void xen_write_ldt_entry (struct desc_struct *dt,int entrynum,u32 low,u32 high)
@@ -387,13 +401,9 @@ static void xen_load_esp0(struct tss_strstatic void xen_load_esp0 (struct tss_struct *tss,struct thread_struct *thread) { -if (xen_get_lazy_mode () !=PARAVIRT_LAZY_CPU ) { -if (HYPERVISOR_stack_switch (__KERNEL_DS, thread->esp0)) -BUG (); - }else { -struct multicall_space mcs =xen_mc_entry (0 ); -MULTI_stack_switch (mcs.mc, __KERNEL_DS, thread->esp0); - } +struct multicall_space mcs =xen_mc_entry (0 ); +MULTI_stack_switch (mcs.mc, __KERNEL_DS, thread->esp0); +xen_mc_issue (PARAVIRT_LAZY_CPU ); }static void xen_set_iopl_mask (unsigned mask)
@@ -485,7 +495,7 @@ static void xen_write_cr3(unsigned longMULTI_mmuext_op (mcs.mc, op,1 ,NULL ,DOMID_SELF ); -xen_mc_issue (); +xen_mc_issue (PARAVIRT_LAZY_CPU ); } }
===================================================================
arch/i386/xen/mmu.c +12 -6
@@ -366,7 +366,7 @@ static int pin_page(struct page *page, uelse {void *pt =lowmem_page_address (page);unsigned long pfn =page_to_pfn (page); -struct multicall_space mcs =xen_mc_entry (0 ); +struct multicall_space mcs =__xen_mc_entry (0 ); flush =0 ;
@@ -386,10 +386,12 @@ void xen_pgd_pin(pgd_t *pgd)struct multicall_space mcs;struct mmuext_op *op; +xen_mc_batch (); +if (pgd_walk (pgd, pin_page,TASK_SIZE ))kmap_flush_unused (); - mcs =xen_mc_entry (sizeof (*op)); + mcs =__xen_mc_entry (sizeof (*op)); op = mcs.args;#ifdef CONFIG_X86_PAE
@@ -400,7 +402,7 @@ void xen_pgd_pin(pgd_t *pgd) op->arg1.mfn =pfn_to_mfn (PFN_DOWN (__pa (pgd)));MULTI_mmuext_op (mcs.mc, op,1 ,NULL ,DOMID_SELF ); -xen_mc_flush (); +xen_mc_issue (0 ); }/* The init_mm pagetable is really pinned as soon as its created, but
@@ -424,7 +426,7 @@ static int unpin_page(struct page *page,if (pgfl && !PageHighMem (page)) {void *pt =lowmem_page_address (page);unsigned long pfn =page_to_pfn (page); -struct multicall_space mcs =xen_mc_entry (0 ); +struct multicall_space mcs =__xen_mc_entry (0 ); MULTI_update_va_mapping(mcs.mc, (unsigned long)pt, pfn_pte(pfn, PAGE_KERNEL),
@@ -438,7 +440,11 @@ static void xen_pgd_unpin(pgd_t *pgd)static void xen_pgd_unpin (pgd_t *pgd) {struct mmuext_op *op; -struct multicall_space mcs =xen_mc_entry (sizeof (*op)); +struct multicall_space mcs; + +xen_mc_batch (); + + mcs =__xen_mc_entry (sizeof (*op)); op = mcs.args; op->cmd =MMUEXT_UNPIN_TABLE ;
@@ -448,7 +454,7 @@ static void xen_pgd_unpin(pgd_t *pgd)pgd_walk (pgd, unpin_page,TASK_SIZE ); -xen_mc_flush (); +xen_mc_issue (0 ); }
===================================================================
arch/i386/xen/multicalls.c +8 -1
@@ -35,11 +35,17 @@ struct mc_buffer { }; static DEFINE_PER_CPU(struct mc_buffer, mc_buffer); +DEFINE_PER_CPU (unsigned long , xen_mc_irq_flags);void xen_mc_flush (void ) {struct mc_buffer *b = &get_cpu_var (mc_buffer);int ret =0 ; +unsigned long flags; + +/* Disable interrupts in case someone comes in and queues +something in the middle */ +local_irq_save (flags);if (b->mcidx) {int i;
@@ -55,11 +61,12 @@ void xen_mc_flush(void)BUG_ON (b->argidx !=0 );put_cpu_var (mc_buffer); +local_irq_restore (flags);BUG_ON (ret); } -struct multicall_space xen_mc_entry (size_t args) +struct multicall_space __xen_mc_entry (size_t args) {struct mc_buffer *b = &get_cpu_var (mc_buffer);struct multicall_space ret;
===================================================================
arch/i386/xen/multicalls.h +23 -4
@@ -11,16 +11,35 @@ struct multicall_space };/* Allocate room for a multicall and its args */ -struct multicall_space xen_mc_entry (size_t args); +struct multicall_space __xen_mc_entry (size_t args); + +DECLARE_PER_CPU(unsigned long, xen_mc_irq_flags); + +/* Call to start a batch of multiple __xen_mc_entry()s. Must be +paired with xen_mc_issue() */ +static inline void xen_mc_batch (void ) +{ +/* need to disable interrupts until this entry is complete */ +local_irq_save (__get_cpu_var (xen_mc_irq_flags)); +} + +static inline struct multicall_space xen_mc_entry (size_t args) +{ +xen_mc_batch (); +return __xen_mc_entry (args); +}/* Flush all pending multicalls */ void xen_mc_flush (void ); -/* Issue a multicall if we're not in lazy mode */ -static inline void xen_mc_issue (void ) +/* Issue a multicall if we're not in a lazy mode */ +static inline void xen_mc_issue (unsigned mode) { -if (xen_get_lazy_mode () ==PARAVIRT_LAZY_NONE ) +if ((xen_get_lazy_mode () & mode) ==0 )xen_mc_flush (); + +/* restore flags saved in xen_mc_batch */ +local_irq_restore (x86_read_percpu (xen_mc_irq_flags)); }#endif /* _XEN_MULTICALLS_H */
===================================================================
arch/i386/xen/xen-ops.h +1 -4
@@ -26,10 +26,7 @@ DECLARE_PER_CPU(enum paravirt_lazy_mode,static inline unsigned xen_get_lazy_mode (void ) { -unsigned ret =get_cpu_var (xen_lazy_mode); -put_cpu_var (xen_lazy_mode); - -return ret; +return x86_read_percpu (xen_lazy_mode); }
PATCH 12/28 xen: Account for time stolen by Xen
In reply to Jeremy FitzhardingeThis accounts for the time Xen steals from our VCPUs. 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 | 106 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 105 insertions(+), 1 deletion(-)
===================================================================
arch/i386/xen/time.c +105 -1
@@ -2,6 +2,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>
@@ -14,6 +15,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 {
@@ -26,6 +28,104 @@ 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); + +/* +* 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 = state->state_entry_time; +barrier (); + *res = *state; +barrier (); + }while (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; +u64 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); + 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); + 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 ;
@@ -338,6 +438,8 @@ static irqreturn_t xen_timer_interrupt(i ret =IRQ_HANDLED ; } +do_stolen_accounting (); +return ret; }
@@ -364,6 +466,8 @@ static void xen_setup_timer(int cpu) evt->irq = irq;clockevents_register_device (evt); +setup_runstate_info (); +put_cpu_var (xen_clock_events); }
@@ -376,7 +480,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;
PATCH 13/28 xen: Implement xen_sched_clock
In reply to Jeremy FitzhardingeImplement 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 | 22 +++++++++++++++++++++- arch/i386/xen/xen-ops.h | 3 +-- 3 files changed, 23 insertions(+), 4 deletions(-)
===================================================================
arch/i386/xen/enlighten.c +1 -1
@@ -676,7 +676,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, #ifdef CONFIG_X86_LOCAL_APIC .apic_write = paravirt_nop,
===================================================================
arch/i386/xen/time.c +21 -1
@@ -16,6 +16,8 @@#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) + +static cycle_t xen_clocksource_read (void );/* These are perodically updated in shared_info, and then copied here. */ struct shadow_time_info {
@@ -118,6 +120,24 @@ 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 (); + +get_runstate_snapshot (&state); + +WARN_ON (state.state != RUNSTATE_running); + +return state.time[RUNSTATE_blocked] + + state.time[RUNSTATE_running] + + (now - state.state_entry_time); +}/* Get the CPU speed from Xen */
@@ -209,7 +229,7 @@ static u64 get_nsec_offset(struct shadowreturn 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 );
PATCH 14/28 xen: Xen SMP guest support
In reply to Jeremy FitzhardingeThis 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/kernel/smp.c | 5 arch/i386/kernel/smpboot.c | 8 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 | 405 ++++++++++++++++++++ arch/i386/xen/time.c | 9 arch/i386/xen/xen-ops.h | 25 + include/asm-i386/mach-default/irq_vectors_limits.h | 2 include/asm-i386/mmu_context.h | 2 include/asm-i386/smp.h | 5 include/xen/events.h | 27 + 16 files changed, 715 insertions(+), 65 deletions(-)
===================================================================
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 ();
===================================================================
arch/i386/kernel/smpboot.c +3 -5
@@ -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;
@@ -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;
===================================================================
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 +405 -0
405 lines not on this page · raw message
===================================================================
arch/i386/xen/time.c +5 -4
@@ -472,8 +472,9 @@ static irqreturn_t xen_timer_interrupt(ireturn ret; } -static void xen_setup_timer (int cpu) -{ +void xen_setup_timer (void ) +{ +int cpu =smp_processor_id ();const char *name;struct clock_event_device *evt;int irq;
@@ -522,5 +523,5 @@ __init void xen_time_init(void) tsc_disable =0 ; -xen_setup_timer (cpu); -} +xen_setup_timer (); +}
===================================================================
arch/i386/xen/xen-ops.h +25 -0
@@ -2,6 +2,13 @@#define XEN_OPS_H #include <linux/init.h> +#include <linux/percpu.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);
@@ -18,6 +25,7 @@ unsigned long xen_get_wallclock(void);unsigned long xen_get_wallclock (void );int xen_set_wallclock (unsigned long time);unsigned long long xen_sched_clock (void ); +void xen_setup_timer (void );void xen_mark_init_mm_pinned (void );
@@ -28,5 +36,22 @@ static inline unsigned xen_get_lazy_modereturn 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/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
===================================================================
include/asm-i386/mmu_context.h +2 -0
@@ -31,6 +31,8 @@ static inline void enter_lazy_tlb(structper_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,
===================================================================
include/asm-i386/smp.h +5 -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
@@ -143,6 +146,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 */
===================================================================
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) {
PATCH 15/28 xen: Add support for preemption
In reply to Jeremy FitzhardingeAdd 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,6 +4,6 @@ config XEN bool "Enable support for Xen hypervisor" - depends on PARAVIRT && !PREEMPT + depends on PARAVIRT help This is the Linux Xen port.
===================================================================
arch/i386/xen/enlighten.c +62 -43
209 lines not on this page · raw message
===================================================================
arch/i386/xen/mmu.c +3 -1
@@ -520,5 +520,7 @@ void xen_exit_mmap(struct mm_struct *mm)preempt_enable (); +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_irqvoid 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
@@ -57,7 +57,7 @@ static void get_runstate_snapshot(structu64 state_time;struct vcpu_runstate_info *state; -preempt_disable (); +BUG_ON (preemptible ()); state = &__get_cpu_var (runstate);
@@ -72,8 +72,6 @@ static void get_runstate_snapshot(struct *res = *state;barrier (); }while (state->state_entry_time != state_time); - -preempt_enable (); }static void setup_runstate_info (void )
@@ -142,15 +140,29 @@ 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; +unsigned long long ret; + +/* +* 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);WARN_ON (state.state != RUNSTATE_running); -return state.time[RUNSTATE_blocked] + + ret = state.time[RUNSTATE_blocked] + state.time[RUNSTATE_running] + (now - state.state_entry_time); + +preempt_enable (); + +return ret; }
PATCH 16/28 xen: lazy-mmu operations
In reply to Jeremy FitzhardingeThis 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 longstatic 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 cif (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 ];
PATCH 17/28 xen: deal with negative stolen time
In reply to Jeremy FitzhardingeStolen time should never be negative; if it ever is, it probably indicates some other bug. However, if it does happen, then its better to just clamp it at zero, rather than trying to account for it as a huge positive number.
--- arch/i386/xen/smp.c | 4 + arch/i386/xen/time.c | 112 ++++++++++++++++++++++++++++++++--------------- arch/i386/xen/xen-ops.h | 3 - 3 files changed, 83 insertions(+), 36 deletions(-)
===================================================================
arch/i386/xen/smp.c +3 -1
@@ -72,10 +72,11 @@ static __cpuinit void cpu_bringup_and_idint cpu =smp_processor_id ();cpu_init (); -xen_setup_timer ();preempt_disable ();per_cpu (cpu_state, cpu) =CPU_ONLINE ; + +xen_setup_cpu_clockevents ();/* We can take interrupts now: we're officially "up". */ local_irq_enable ();
@@ -263,6 +264,7 @@ int __cpuinit xen_cpu_up(unsigned int cpper_cpu (current_task, cpu) = idle;xen_vcpu_setup (cpu);irq_ctx_init (cpu); +xen_setup_timer (cpu);/* make sure interrupts start blocked */ per_cpu (xen_vcpu, cpu)->evtchn_upcall_mask =1 ;
===================================================================
arch/i386/xen/time.c +78 -34
216 lines not on this page · raw message
===================================================================
arch/i386/xen/xen-ops.h +2 -1
@@ -25,7 +25,8 @@ unsigned long xen_get_wallclock(void);unsigned long xen_get_wallclock (void );int xen_set_wallclock (unsigned long time);unsigned long long xen_sched_clock (void ); -void xen_setup_timer (void ); +void xen_setup_timer (int cpu); +void xen_setup_cpu_clockevents (void );void xen_mark_init_mm_pinned (void );
PATCH 18/28 xen: Use the hvc console infrastructure for Xen console
In reply to Jeremy FitzhardingeImplement a Xen back-end for hvc console.
From: Gerd Hoffmann <[email protected]>
--- arch/i386/xen/events.c | 3 - drivers/Makefile | 3 + drivers/char/Kconfig | 8 ++ drivers/char/Makefile | 1 drivers/char/hvc_xen.c | 134 ++++++++++++++++++++++++++++++++++++++++++++++++ include/xen/events.h | 1 6 files changed, 149 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 ireturn irq; } +EXPORT_SYMBOL_GPL (bind_evtchn_to_irq);static int bind_ipi_to_irq (unsigned int ipi,unsigned int cpu) {
===================================================================
drivers/Makefile +3 -0
@@ -14,6 +14,9 @@ obj-$(CONFIG_ACPI) += acpi/ # was used and do nothing if so obj-$(CONFIG_PNP) += pnp/ obj-$(CONFIG_ARM_AMBA) += amba/ + +# Xen is the default console when running as a guest +obj-$(CONFIG_XEN) += xen/ # char/ comes before serial/ etc so that the VT console is the boot-time # default.
===================================================================
drivers/char/Kconfig +8 -0
@@ -650,6 +650,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
@@ -43,6 +43,7 @@ obj-$(CONFIG_SX) += sx.o generic_serial obj-$(CONFIG_SX) += sx.o generic_serial.o obj-$(CONFIG_RIO) += rio/ generic_serial.o obj-$(CONFIG_HVC_CONSOLE) += hvc_vio.o hvsi.o +obj-$(CONFIG_HVC_XEN) += hvc_xen.o obj-$(CONFIG_HVC_ISERIES) += hvc_iseries.o obj-$(CONFIG_HVC_RTAS) += hvc_rtas.o obj-$(CONFIG_HVC_BEAT) += hvc_beat.o
===================================================================
drivers/char/hvc_xen.c new file +134 -0
134 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,
PATCH 19/28 xen: Add early printk support via hvc console
In reply to Jeremy FitzhardingeAdd early printk support via hvc console, enable using "earlyprintk=xen" on the kernel command line.
From: Gerd Hoffmann <[email protected]>
--- arch/x86_64/kernel/early_printk.c | 5 +++++ drivers/char/hvc_xen.c | 25 +++++++++++++++++++++++++ drivers/xen/Makefile | 1 + include/xen/hvc-console.h | 6 ++++++ 4 files changed, 37 insertions(+)
===================================================================
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(chasimnow_init (buf +6 ); early_console = &simnow_console; keep_early =1 ; +#ifdef CONFIG_XEN + }else if (!strncmp (buf,"xen" ,3 )) { + early_console = &xenboot_console; +#endif }register_console (early_console);return 0 ;
===================================================================
drivers/char/hvc_xen.c +25 -0
@@ -28,6 +28,7 @@#include <xen/page.h> #include <xen/events.h> #include <xen/interface/io/console.h> +#include <xen/hvc-console.h> #include "hvc_console.h"
@@ -132,3 +133,27 @@ module_init(xen_init);module_init (xen_init);module_exit (xen_fini);console_initcall (xen_cons_init); + +static void xenboot_write_console (struct console *console,const char *string, +unsigned len) +{ +unsigned int linelen, off =0 ; +const char *pos; + +while (off < len &&NULL != (pos =strchr (string+off,'\n' ))) { + linelen = pos-string+off; +if (off + linelen > len) +break ; +write_console (0 , string+off, linelen); +write_console (0 ,"\r\n" ,2 ); + off += linelen +1 ; + } +if (off < len) +write_console (0 , string+off, len-off); +} + +struct console xenboot_console = { + .name ="xenboot" , + .write = xenboot_write_console, + .flags =CON_PRINTBUFFER |CON_BOOT , +};
===================================================================
drivers/xen/Makefile new file +1 -0
@@ -0,0 +1,1 @@ +obj-y += grant-table.o
===================================================================
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 */
Re: [Xen-devel] [patch 19/28]xen: Add early printk support via hvc console
Quoted 1 line · Jeremy Fitzhardinge
+#ifdef
CONFIG_XEN
xenboot_console is only available with CONFIG_HVC_XEN.
Quoted 3 lines
arch/x86_64/kernel/early_printk.c +3
-0+ } else if (!strncmp(buf, "xen", 3)) { + early_console = &xenboot_console; +#endif
Re: [Xen-devel] [patch 19/28]xen: Add early printk support via hvc console
Quoted 7 lines · Bastian Blank
Quoted 2 lines · Jeremy Fitzhardinge
+#ifdef
CONFIG_XEN
xenboot_consoleis only available withCONFIG_HVC_XEN.
Good point. I added CONFIG_HVC_XEN, but forgot to update this.
J
PATCH 20/28 xen: Add Xen grant table support
In reply to Jeremy FitzhardingeAdd 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/xen/Makefile | 1 drivers/xen/grant-table.c | 576 +++++++++++++++++++++++++++++++++++ include/xen/grant_table.h | 107 ++++++ include/xen/interface/grant_table.h | 112 +++++- 4 files changed, 777 insertions(+), 19 deletions(-)
===================================================================
drivers/xen/Makefile +1 -0
@@ -1,1 +1,2 @@ obj-y += hvc-console.o +obj-y += grant-table.o obj-y += hvc-console.o
===================================================================
drivers/xen/grant-table.c new file +576 -0
576 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 +93 -19
201 lines not on this page · raw message
PATCH 21/28 xen: Add the Xenbus sysfs and virtual device hotplug driver.
In reply to Jeremy FitzhardingeThis 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,2 +1,3 @@ obj-y += grant-table.o 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
PATCH 22/28 xen: Add Xen virtual block device driver.
In reply to Jeremy FitzhardingeThe 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 include/xen/interface/io/blkif.h | 6 5 files changed, 1001 insertions(+), 4 deletions(-)
===================================================================
drivers/block/Kconfig +8 -0
@@ -453,6 +453,14 @@ config ATA_OVER_ETH This driver provides Support for ATA over Ethernet block devices like the Coraid EtherDrive (R) Storage Blade. +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. + endmenu endif
===================================================================
drivers/block/Makefile +1 -0
@@ -29,3 +29,4 @@ obj-$(CONFIG_BLK_DEV_SX8) += sx8.o obj-$(CONFIG_BLK_DEV_SX8) += sx8.o obj-$(CONFIG_BLK_DEV_UB) += ub.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
@@ -156,6 +156,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
===================================================================
include/xen/interface/io/blkif.h +2 -4
@@ -24,10 +24,8 @@* rsp_event appropriately (e.g., using RING_FINAL_CHECK_FOR_RESPONSES()). */ -#ifndef blkif_vdev_t -#define blkif_vdev_t uint16_t -#endif -#define blkif_sector_t uint64_t +typedef uint16_t blkif_vdev_t ; +typedef uint64_t blkif_sector_t ;/* * REQUEST CODES.
PATCH 23/28 xen: rename xen netif_ structures to xen_netif_
In reply to Jeremy FitzhardingeThe "netif_" prefix is used in the Linux network stack, so rename the Xen structures to xen_netif_ to avoid confusion (and potential collision).
--- include/xen/interface/io/netif.h | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-)
===================================================================
include/xen/interface/io/netif.h +11 -7
@@ -47,7 +47,7 @@#define _NETTXF_extra_info (3)#define NETTXF_extra_info (1U<<_NETTXF_extra_info) -struct netif_tx_request { +struct xen_netif_tx_request {grant_ref_t gref;/* Reference to buffer page */ uint16_t offset;/* Offset within buffer page */ uint16_t flags;/* NETTXF_* */
@@ -71,7 +71,7 @@ struct netif_tx_request {* This structure needs to fit within both netif_tx_request and * netif_rx_response for compatibility. */ -struct netif_extra_info { +struct xen_netif_extra_info {uint8_t type;/* XEN_NETIF_EXTRA_TYPE_* */ uint8_t flags;/* XEN_NETIF_EXTRA_FLAG_* */
@@ -103,12 +103,12 @@ struct netif_extra_info { } u; }; -struct netif_tx_response { +struct xen_netif_tx_response {uint16_t id;int16_t status;/* NETIF_RSP_* */ }; -struct netif_rx_request { +struct xen_netif_rx_request {uint16_t id;/* Echoed in response message. */ grant_ref_t gref;/* Reference to incoming granted frame */ };
@@ -129,7 +129,7 @@ struct netif_rx_request {#define _NETRXF_extra_info (3)#define NETRXF_extra_info (1U<<_NETRXF_extra_info) -struct netif_rx_response { +struct xen_netif_rx_response {uint16_t id;uint16_t offset;/* Offset in page of start of received packet */ uint16_t flags;/* NETRXF_* */
@@ -140,8 +140,12 @@ struct netif_rx_response {* Generate netif ring structures and types. */ -DEFINE_RING_TYPES(netif_tx, struct netif_tx_request, struct netif_tx_response); -DEFINE_RING_TYPES(netif_rx, struct netif_rx_request, struct netif_rx_response); +DEFINE_RING_TYPES (xen_netif_tx, + struct xen_netif_tx_request, + struct xen_netif_tx_response); +DEFINE_RING_TYPES (xen_netif_rx, + struct xen_netif_rx_request, + struct xen_netif_rx_response);#define NETIF_RSP_DROPPED -2#define NETIF_RSP_ERROR -1
PATCH 24/28 xen: Add the Xen virtual network device driver.
In reply to Jeremy FitzhardingeThe network device frontend driver allows the kernel to access network devices exported exported by a virtual machine containing a physical network device driver.
--- drivers/net/Kconfig | 12 drivers/net/Makefile | 2 drivers/net/xen-netfront.c | 1995 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 2009 insertions(+)
===================================================================
drivers/net/Kconfig +12 -0
@@ -2507,6 +2507,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 +2 -0
@@ -218,3 +218,5 @@ obj-$(CONFIG_FS_ENET) += fs_enet/ obj-$(CONFIG_FS_ENET) += fs_enet/ obj-$(CONFIG_NETXEN_NIC) += netxen/ + +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
PATCH 25/28 xen: Xen machine operations
In reply to Jeremy FitzhardingeMake 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)
PATCH 26/28 xen: handle external requests for shutdown, reboot and sysrq
In reply to Jeremy FitzhardingeThe 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
PATCH 27/28 xen: Place vcpu_info structure into per-cpu memory, if possible
In reply to Jeremy FitzhardingeAn 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 cxen_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__ */ /*
PATCH 28/28 xen: Attempt to patch inline versions of common operations
In reply to Jeremy FitzhardingeThis 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>
@@ -135,4 +136,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_tint 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 */