xen: Xen implementation for paravirt_ops
Subsystems (9)
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-rc7 + your patches + the last batch of pv_ops patches I posted.
This patch generally restricts itself to Xen-specific parts of the tree, though it does make a few small changes elsewhere.
These patches include:
- some helper routines for allocating address space and walking pagetables
- Xen interface header files
- Core Xen implementation
- 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/25 xen: Add apply_to_page_range() which applies a function to a pte range.
Add a new mm function apply_to_page_range() which applies a given function to every pte in a given virtual address range in a given mm structure. This is a generic alternative to cut-and-pasting the Linux idiomatic pagetable walking code in every place that a sequence of PTEs must be accessed.
Although this interface is intended to be useful in a wide range of situations, it is currently used specifically by several Xen subsystems, for example: to ensure that pagetables have been allocated for a virtual address range, and to construct batched special pagetable update requests to map I/O memory (in ioremap()).
--- include/linux/mm.h | 5 ++ mm/memory.c | 94 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 99 insertions(+)
===================================================================
include/linux/mm.h +5 -0
@@ -1135,6 +1135,11 @@ struct page *follow_page(struct vm_area_#define FOLL_GET 0x04/* do get_page on page */ #define FOLL_ANON 0x08/* give ZERO_PAGE if no pgtable */ +typedef int (*pte_fn_t )(pte_t *pte,struct page *pmd_page,unsigned long addr, +void *data); +extern int apply_to_page_range (struct mm_struct *mm,unsigned long address, +unsigned long size,pte_fn_t fn,void *data); +#ifdef CONFIG_PROC_FS void vm_stat_account (struct mm_struct *,unsigned long ,struct file *,long );#else
===================================================================
mm/memory.c +94 -0
100 lines not on this page · raw message
PATCH 2/25 xen: Allocate and free vmalloc areas
In reply to Jeremy FitzhardingeAllocate/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 | 51 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+)
===================================================================
include/linux/vmalloc.h +4 -0
@@ -68,6 +68,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 +51 -0
54 lines not on this page · raw message
PATCH 3/25 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 | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+)
===================================================================
arch/i386/kernel/vsyscall-note.S +28 -0
@@ -23,3 +24,31 @@ 3: .balign 4; /* pad out section */ ASM_ELF_NOTE_BEGIN(".note.kernel-version", "a", UTS_SYSNAME, 0) .long LINUX_VERSION_CODE ASM_ELF_NOTE_END + +#ifdef CONFIG_XEN +/* + * Add a special note telling glibc's dynamic linker a fake hardware + * flavor that it will use to choose the search path for libraries in the + * same way it uses real hardware capabilities like "mmx". + * We supply "nosegneg" as the fake capability, to indicate that we + * do not like negative offsets in instructions using segment overrides, + * since we implement those inefficiently. This makes it possible to + * install libraries optimized to avoid those access patterns in someplace + * like /lib/i686/tls/nosegneg. Note that an /etc/ld.so.conf.d/file + * corresponding to the bits here is needed to make ldconfig work right. + * It should contain: + * hwcap 0 nosegneg + * to match the mapping of bit to name that we give here. + */ +#define NOTE_KERNELCAP_BEGIN(ncaps, mask) \ + ASM_ELF_NOTE_BEGIN(".note.kernelcap", "a", "GNU", 2) \ + .long ncaps, mask +#define NOTE_KERNELCAP(bit, name) \ + .byte bit; .asciz name +#define NOTE_KERNELCAP_END ASM_ELF_NOTE_END + +NOTE_KERNELCAP_BEGIN(1, 2) +NOTE_KERNELCAP(1, "nosegneg") +NOTE_KERNELCAP_END +#endif +
Re: [PATCH 03/25] 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 needs to be "hwcap 0 nosegneg" to match:
arch/i386/kernel/vsyscall-note.S 3: .balign 4; /* pad out section */ · line 52
Quoted 3 lines
arch/i386/kernel/vsyscall-note.S +3
-0+NOTE_KERNELCAP_BEGIN(1, 2) +NOTE_KERNELCAP(1, "nosegneg") +NOTE_KERNELCAP_END
The actual bits you are using should be fine. (You're intentionally skipping bit 0 to work around hold glibc bugs, which you might want to add to the comments. Also a comment or perhaps using 1<<1 syntax would make it more clear that "2" is the bit mask containing bit 1 and that's why it has to be 2, and not because of some other magical property of 2.) But if kernel packagers don't write the matching bit number in their ld.so.conf.d files, then ld.so.cache lookups won't work right.
Thanks,
Roland
Re: [PATCH 03/25] xen: Add nosegneg capability to the vsyscall page notes
Quoted 8 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 needs to be "hwcap 0 nosegneg" to match:
Quoted 12 lines
arch/i386/kernel/vsyscall-note.S 3: .balign 4; /* pad out section */ · line 52
Quoted 4 lines
arch/i386/kernel/vsyscall-note.S +3
-0+NOTE_KERNELCAP_BEGIN(1, 2) +NOTE_KERNELCAP(1, "nosegneg") +NOTE_KERNELCAP_ENDThe actual bits you are using should be fine. (You're intentionally skipping bit 0 to work around hold glibc bugs, which you might want to add to the comments. Also a comment or perhaps using 1<<1 syntax would make it more clear that "2" is the bit mask containing bit 1 and that's why it has to be 2, and not because of some other magical property of 2.) But if kernel packagers don't write the matching bit number in their ld.so.conf.d files, then ld.so.cache lookups won't work right.
I have to admit I still don't really understand all this. Is it documented somewhere?
What does "hwcap 0 nosegneg" actually mean? What does the "0" mean here?
In the ELF note, what does the "nosegneg" string mean? How is it used? Is it compared to the "nosegneg" in ld.so.conf? How does this relate to the bitfields?
Thanks,
J
Re: [PATCH 03/25] xen: Add nosegneg capability to the vsyscall page notes
Quoted 2 lines
I have to admit I still don't really understand all this. Is it documented somewhere?
I have explained it in public more than once, but I don't know off hand anywhere that was helpfully recorded.
Quoted 1 line
What does "hwcap 0 nosegneg" actually mean? What does the "0" mean here?
ldconfig is usually run at library install time. It reads ld.so.conf (and its include files, usually found in /etc/ld.so.conf.d/*.conf). ldconfig finds libraries on the disk and stores their names in ld.so.cache. For libraries in "hwcap directories", it records in ld.so.cache a bitmask of hwcap bits for each library, based on which hwcap names appeared in the library file name. The hard-wired hwcap names are things such as "mmx" and "sse2", a chosen subset of the AT_HWCAP bits the kernel provides.
When the dynamic linker is finding a library at runtime, it uses a match from ld.so.cache unless none was found or LD_LIBRARY_PATH was set. When there is no cache hit, it searches a directory path for the library's name. The subset of hwcap names whose AT_HWCAP bits are set yields a list of subdirectories to try under each directory in the path. To see the list:
$ LD_LIBRARY_PATH=/lib:/usr/lib LD_DEBUG=libs /bin/true
21491: find library=libc.so.6 [0]; searching
21491: search path=/lib/tls/i686/sse2:/lib/tls/i686:/lib/tls/sse2:/lib/tls:/lib/i686/sse2:/lib/i686:/lib/sse2:/lib:/usr/lib/tls/i686/sse2:/usr/lib/tls/i686:/usr/lib/tls/sse2:/usr/lib/tls:/usr/lib/i686/sse2:/usr/lib/i686:/usr/lib/sse2:/usr/lib (system search path)(Here you can notice that "tls" is used as a pseudo-hwcap; it is in fact hard-wired into the list if the dynamic linker supports ELF TLS, which all recent ones do. Also you'll notice "i686" is not a hwcap bit, but is the AT_PLATFORM string, which is treated similarly.)
The hwcap bitmasks in ld.so.cache are intended to make the single cache file equivalent to this varying search path depending on runtime hwcap bits set. A cache entry whose bitmask has bits not set at runtime is ignored. Running "ldconfig -p | grep hwcap" (read-only, need not be root) will show you any entries in your ld.so.cache that have an hwcap bitmask set.
The "hwcap" directive in ld.so.conf tells ldconfig to understand a new hwcap name that is not in the hard-wired set. There is some number of extra bits available; "hwcap 0" assigns the first extra bit, "hwcap 1" the second, and so on. The name is what to use as a subdirectory name, analogous to "sse2" et al.
On my system with an ld.so.conf.d file installed doing "hwcap 0 nosegneg":
$ ldconfig -p | grep libc.so.6
libc.so.6 (libc6, hwcap: 0x0018000000000000, OS ABI: Linux 2.6.9) => /lib/i686/nosegneg/libc.so.6
libc.so.6 (libc6, OS ABI: Linux 2.6.9) => /lib/libc.so.6(There are two bits set because the "tls" pseudo-bit is also set.)
With this in ld.so.cache, the libc.so.6 lookup will find /lib/i686/nosegneg/libc.so.6 first, but only if the hwcap bit set.
Quoted 3 lines
In the ELF note, what does the "nosegneg" string mean? How is it used? Is it compared to the "nosegneg" in ld.so.conf? How does this relate to the bitfields?
Each bit + string element in the note (there's just the one in what we have) establishes for the dynamic linker at runtime the association between the "extra" pseudo-hwcap bit number and the name. If that pseudo-hwcap is enabled, then that string will figure into the directory search path as "sse2" does in the example above. This string is never consulted when looking in ld.so.cache.
The mask field in NOTE_KERNELCAP_BEGIN says which "extra" bits are enabled. If the corresponding bit is not set here, then it's just like a hard-wired hwcap bit like "sse2" when that bit was not set in AT_HWCAP. That is, a cache lookup will ignore entries with that hwcap bit in their bitmask, and that hwcap name will not be used in constructing the directory search path. I put this bitmask in so that the kernel has the option of using a single vDSO image for multiple different runtime configurations. It can simply modify the bitmask in the image at setup time to disable some entries.
For example, a Xen-enabled kernel can use a single vDSO image (or a single pair of int80/sysenter images), containing the "nosegneg" hwcap note. When there is no need for it (native or hvm or 64-bit hv or whatever), it just clears the mask word. If you actually do this, you'll want to modify the NOTE_KERNELCAP_BEGIN macro to define a global label you can use with VDSO_SYM.
Thanks,
Roland
Re: [PATCH 03/25] xen: Add nosegneg capability to the vsyscall page notes
Quoted 7 lines · Roland McGrath
Quoted 3 lines
I have to admit I still don't really understand all this. Is it documented somewhere?
I have explained it in public more than once, but I don't know off hand anywhere that was helpfully recorded.
Thanks very much. I'd been poking about, but the closest I came to an actual description was various patches fixing bugs, so it was a little incomplete.
Quoted 6 lines
For example, a Xen-enabled kernel can use a single vDSO image (or a single pair of int80/sysenter images), containing the "nosegneg" hwcap note. When there is no need for it (native or hvm or 64-bit hv or whatever), it just clears the mask word. If you actually do this, you'll want to modify the
NOTE_KERNELCAP_BEGINmacro to define a global label you can use withVDSO_SYM.
Thanks for the pointer. I'd been getting a bit of heat for enabling the nonegseg flag unconditionally. If I can make Xen-specific then that will be one less source of complaints.
J
PATCH 4/25 xen: Add XEN config options
In reply to Jeremy FitzhardingeThe XEN config option enables the Xen paravirt_ops interface, which is installed when the kernel finds itself running under Xen.
Xen is no longer a sub-architecture, so the X86_XEN subarch config option has gone.
Xen is currently incompatible with PREEMPT, but this is fixed up later in the series.
--- arch/i386/Kconfig | 2 ++ arch/i386/xen/Kconfig | 10 ++++++++++ 2 files changed, 12 insertions(+)
===================================================================
arch/i386/Kconfig +2 -0
@@ -216,6 +216,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 +10 -0
@@ -0,0 +1,10 @@ +# +# This Kconfig describes xen options +# + +config XEN + bool "Enable support for Xen hypervisor" + depends on PARAVIRT && HZ_100 && !PREEMPT && !NO_HZ + default y + help + This is the Linux Xen port.
Re: [PATCH 04/25] xen: Add XEN config options
Quoted 8 lines · On Monday 23 April 2007 23:56:42 Jeremy Fitzhardinge wrote:
The XEN config option enables the Xen
paravirt_opsinterface, which is installed when the kernel finds itself running under Xen.Xen is no longer a sub-architecture, so the
X86_XENsubarch config option has gone.Xen is currently incompatible with PREEMPT, but this is fixed up later in the series.
Shouldn't this be after the change that adds arch/i386/xen/Kconfig?
Otherwise you break bisects
-Andi
Re: [PATCH 04/25] xen: Add XEN config options
Quoted 8 lines · Andi Kleen
Quoted 6 lines · On Monday 23 April 2007 23:56:42 Jeremy Fitzhardinge wrote:
The XEN config option enables the Xen
paravirt_opsinterface, which is installed when the kernel finds itself running under Xen.Xen is no longer a sub-architecture, so the
X86_XENsubarch config option has gone.
Quoted 8 lines
Quoted 3 lines
Xen is currently incompatible with PREEMPT, but this is fixed up later in the series.
Shouldn't this be after the change that adds
arch/i386/xen/Kconfig?Otherwise you break bisects
It should be OK. The series should build and run at each patch (though I have to admit I haven't tested this). In general I've been adding config options for each feature as the feature itself is added.
J
Re: [PATCH 04/25] xen: Add XEN config options
Quoted 9 lines
Quoted 5 lines
Shouldn't this be after the change that adds
arch/i386/xen/Kconfig?Otherwise you break bisects
It should be OK. The series should build and run at each patch (though I have to admit I haven't tested this). In general I've been adding config options for each feature as the feature itself is added.
But i don't see anything that creates arch/i386/xen before this?
-Andi
PATCH 5/25 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 | 61 ++++ 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, 2957 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 +61 -0
61 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
446 lines not on this page · raw message
PATCH 6/25 xen: Core Xen implementation
In reply to Jeremy FitzhardingeCore Xen Implementation
This patch is a rollup of all the core pieces of the Xen implementation, including booting, memory management, interrupts, time and so on.
This adds a second entry point to head.S, which is jumped to when booted by Xen. This allows startup under Xen to be easily detected.
Because Xen starts the kernel in a fairly sane state, very little setup is needed here; it just needs to jump into xen_start_kernel to init the paravirt_ops structure, and then jump into start_kernel proper.
This also makes a few small adjustments to the gdt tables to make them properly suited to Xen.
This patch also contains an initial set of paravirt ops for Xen, mostly ones which can just be implemented with the generic native_* version. At boot time, the global paravirt_ops structure is populated with the Xen pointers in xen_start_kernel, which then jumps to the standard start_kernel.
Also implements Xen 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.
Xen 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.
Context switches are optimised with the use of multicalls, so that the multiple hypercalls needed to perform the switch can be implemented with a single hypercall. In order to simplify the source changes, this is done via a generic multicall batching mechanism, which can be used to batch arbitrary series of hypercalls into a multicall.
Time 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/Makefile | 3 arch/i386/kernel/entry.S | 79 ++++ arch/i386/kernel/head.S | 5 arch/i386/kernel/paravirt.c | 3 arch/i386/kernel/vmlinux.lds.S | 1 arch/i386/xen/Kconfig | 2 arch/i386/xen/Makefile | 2 arch/i386/xen/enlighten.c | 727 ++++++++++++++++++++++++++++++++++++++ arch/i386/xen/events.c | 487 +++++++++++++++++++++++++ arch/i386/xen/features.c | 29 + arch/i386/xen/mmu.c | 377 +++++++++++++++++++ arch/i386/xen/mmu.h | 47 ++ arch/i386/xen/multicalls.c | 61 +++ arch/i386/xen/multicalls.h | 26 + arch/i386/xen/setup.c | 93 ++++ arch/i386/xen/time.c | 393 ++++++++++++++++++++ arch/i386/xen/xen-head.S | 34 + arch/i386/xen/xen-ops.h | 34 + include/asm-i386/irq.h | 1 include/asm-i386/xen/hypercall.h | 18 include/xen/events.h | 28 + include/xen/features.h | 26 + include/xen/page.h | 178 +++++++++ 23 files changed, 2650 insertions(+), 4 deletions(-)
===================================================================
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 +79 -0
85 lines not on this page · raw message
===================================================================
arch/i386/kernel/head.S +4 -1
@@ -533,6 +533,8 @@ unhandled_paravirt: ud2 #endif +#include "../xen/xen-head.S" + /* * Real beginning of normal "text" segment */
@@ -542,7 +544,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)
===================================================================
arch/i386/kernel/paravirt.c +1 -2
@@ -292,6 +292,7 @@ struct paravirt_ops paravirt_ops = { .apic_read = native_apic_read, .setup_boot_clock = setup_boot_APIC_clock, .setup_secondary_clock = setup_secondary_APIC_clock, + .startup_ipi_hook = paravirt_nop, #endif .set_lazy_mode = paravirt_nop,
@@ -342,8 +343,6 @@ struct paravirt_ops paravirt_ops = { .dup_mmap = paravirt_nop, .exit_mmap = paravirt_nop, .activate_mm = paravirt_nop, - - .startup_ipi_hook = paravirt_nop, };/*
===================================================================
arch/i386/kernel/vmlinux.lds.S +1 -0
@@ -94,6 +94,7 @@ SECTIONS . = ALIGN(4096); .data.page_aligned : AT(ADDR(.data.page_aligned) - LOAD_OFFSET) { + *(.data.page_aligned) *(.data.idt) }
===================================================================
arch/i386/xen/Kconfig +1 -1
@@ -4,7 +4,7 @@ config XEN bool "Enable support for Xen hypervisor" - depends on PARAVIRT && HZ_100 && !PREEMPT && !NO_HZ + depends on PARAVIRT && !PREEMPT default y help This is the Linux Xen port.
===================================================================
arch/i386/xen/Makefile new file +2 -0
@@ -0,0 +1,2 @@ +obj-y := enlighten.o setup.o events.o time.o \ + features.o mmu.o multicalls.o
===================================================================
arch/i386/xen/enlighten.c new file +727 -0
727 lines not on this page · raw message
===================================================================
arch/i386/xen/events.c new file +487 -0
487 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/mmu.c new file +377 -0
377 lines not on this page · raw message
===================================================================
arch/i386/xen/mmu.h new file +47 -0
47 lines not on this page · raw message
===================================================================
arch/i386/xen/multicalls.c new file +61 -0
61 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 +93 -0
93 lines not on this page · raw message
===================================================================
arch/i386/xen/time.c new file +393 -0
393 lines not on this page · raw message
===================================================================
arch/i386/xen/xen-head.S new file +34 -0
@@ -0,0 +1,34 @@ +/* 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 + jmp startup_paravirt + +.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/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 */
===================================================================
include/xen/features.h new file +26 -0
@@ -0,0 +1,26 @@ +/****************************************************************************** +* 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) +{ +switch (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
Re: [PATCH 06/25] xen: Core Xen implementation
Quoted 5 lines · On Monday 23 April 2007 23:56:44 Jeremy Fitzhardinge wrote:
Core Xen Implementation
This patch is a rollup of all the core pieces of the Xen implementation, including booting, memory management, interrupts, time and so on.
The patch is definitely too big.
arch/i386/kernel/entry.S ENTRY(kernel_thread_helper) · line 1034
Quoted 9 lines
arch/i386/kernel/entry.S +9
-0+#ifdef CONFIG_XEN +/* Xen only supports sysenter/sysexit in ring0 guests, + and only if it the guest asks for it. So for now, + this should never be used. */ +ENTRY(xen_sti_sysexit) + CFI_STARTPROC + ud2 + CFI_ENDPROC +ENDPROC(xen_sti_sysexit)
Put that elsewhere? It doesn't need to be here.
Review
Quoted 2 lines
+++
b/arch/i386/xen/enlighten.c(quoted diff) +0
-0@@ -0,0 +1,727 @@
Comments describing what all the files do?
arch/i386/xen/enlighten.c line 63
Quoted 5 lines
arch/i386/xen/enlighten.c new file +5
-0+unsigned maskedx = ~0 ; +if (*eax ==1 ) + maskedx = ~((1 <<X86_FEATURE_APIC ) | + (1 <<X86_FEATURE_ACPI ) | + (1 <<X86_FEATURE_ACC ));
Why ACC?
And why doesn't Xen mask those by itself?
And you got apic functions later which would be never called? Why are the hooks needed then?
arch/i386/xen/enlighten.c line 93
Quoted 11 lines
arch/i386/xen/enlighten.c new file +11
-0+ +static unsigned long xen_save_fl (void ) +{ +struct vcpu_info *vcpu; +unsigned long flags; + +preempt_disable (); + vcpu =x86_read_percpu (xen_vcpu); +/* flag has opposite sense of mask */ + flags = !vcpu->evtchn_upcall_mask; +preempt_enable ();
If you use get_cpu/put_cpu it will be optimized away on PREEMPT && !SMP (more occurrences)
arch/i386/xen/enlighten.c line 113
Quoted 12 lines
arch/i386/xen/enlighten.c new file +12
-0+static void xen_restore_fl (unsigned long flags) +{ +struct vcpu_info *vcpu; + +preempt_disable (); + +/* convert from IF type flag */ + flags = !(flags &X86_EFLAGS_IF ); + vcpu =x86_read_percpu (xen_vcpu); + vcpu->evtchn_upcall_mask = flags; +if (flags ==0 ) { +barrier ();/* unmask then check (avoid races) */
Don't you need a rmb() here then? The CPU could speculate reads (more occurrences)
Quoted 4 lines
arch/i386/xen/enlighten.c new file +4
-0+if (unlikely (vcpu->evtchn_upcall_pending)) +force_evtchn_callback (); +preempt_enable (); + }else
arch/i386/xen/enlighten.c line 127
Quoted 10 lines
arch/i386/xen/enlighten.c new file +10
-0+preempt_enable_no_resched (); +} + +static void xen_irq_disable (void ) +{ +struct vcpu_info *vcpu; +preempt_disable (); + vcpu =x86_read_percpu (xen_vcpu); + vcpu->evtchn_upcall_mask =1 ; +preempt_enable_no_resched ();
First with the new per cpu the preempt disable shouldn't be needed anymore because the thing is atomic. In the worst case you do the change on the previous CPU, but that can happen anyways after preempt_enable
And then when you have enabled who transfers the irq off state to the new CPU?
arch/i386/xen/enlighten.c line 156
Quoted 7 lines
arch/i386/xen/enlighten.c new file +7
-0+static void xen_halt (void ) +{ +#if 0 +if (irqs_disabled ()) +HYPERVISOR_vcpu_op (VCPUOP_down,smp_processor_id (),NULL ); +#endif +}
Who halts then?
arch/i386/xen/enlighten.c line 204
Quoted 9 lines
arch/i386/xen/enlighten.c new file +9
-0+static void xen_load_gdt (const struct Xgt_desc_struct *dtr) +{ +unsigned long *frames; +unsigned long va = dtr->address; +unsigned int size = dtr->size +1 ; +int f; +struct multicall_space mcs; + +BUG_ON (size >16 *PAGE_SIZE );
Why 16?
arch/i386/xen/enlighten.c line 313
Quoted 2 lines
arch/i386/xen/enlighten.c new file +2
-0+ count = desc->size /8 ; +BUG_ON (count >256 );
should be >= ?
arch/i386/xen/enlighten.c line 373
Quoted 9 lines
arch/i386/xen/enlighten.c new file +9
-0+static void xen_set_iopl_mask (unsigned mask) +{ +#if 0 +struct physdev_set_iopl set_iopl; + +/* Force the change at ring 0. */ + set_iopl.iopl = (mask ==0 ) ?1 : (mask >>12 ) &3 ; +HYPERVISOR_physdev_op (PHYSDEVOP_set_iopl, &set_iopl); +#endif
And who does iopl then?
arch/i386/xen/enlighten.c line 423
Quoted 6 lines
arch/i386/xen/enlighten.c new file +6
-0+* 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. +*/ +#define xen_pfn_to_cr3 (pfn) (((unsigned)(pfn) << 12) | ((unsigned)(pfn) >> 20)) +#define xen_cr3_to_pfn (cr3) (((unsigned)(cr3) >> 12) | ((unsigned)(cr3) << 20))
Don't you lose bits >4GB here due to the casts before shift?
arch/i386/xen/enlighten.c line 684
Quoted 1 line
arch/i386/xen/enlighten.c new file +1
-0+BUG_ON (memcmp (xen_start_info->magic,"xen-3.0" ,7 ) !=0 );
Hopefully Xen 4.0 can handle this then.
arch/i386/xen/enlighten.c line 719
Quoted 3 lines
arch/i386/xen/enlighten.c new file +3
-0+ +/* Poke various useful things into boot_params */ +LOADER_TYPE = (9 <<4 ) |0 ;
| 0 ? Probably should be something symbolic
arch/i386/xen/mmu.c line 215
Quoted 5 lines
arch/i386/xen/mmu.c new file +5
-0+unsigned long xen_pmd_val (pmd_t pmd) +{ +BUG (); +return 0 ; +}
Why do we have pmd_val hooks then?
arch/i386/xen/mmu.c line 237
Quoted 5 lines
arch/i386/xen/mmu.c new file +5
-0+pmd_t xen_make_pmd (unsigned long pmd) +{ +BUG (); +return __pmd (0 ); +}
and make_pmd hooks?
arch/i386/xen/time.c
Quoted 2 lines
arch/i386/xen/time.c new file +0
-0
... will review the rest later.
Can you please split it up a bit?
-Andi
Re: [PATCH 06/25] xen: Core Xen implementation
Quoted 11 lines · Andi Kleen
Quoted 6 lines · On Monday 23 April 2007 23:56:44 Jeremy Fitzhardinge wrote:
Core Xen Implementation
This patch is a rollup of all the core pieces of the Xen implementation, including booting, memory management, interrupts, time and so on.
The patch is definitely too big.
Yes. It was originally smaller patches, which I tried to keep in a state where everything was incrementally buildable, but it got too hard to keep it all together.
I guess I can break it down into functional groups, and put the config stuff at the end.
Quoted 4 lines
Quoted 4 lines
arch/i386/kernel/entry.S +4
-0+#ifdef CONFIG_XEN +/* Xen only supports sysenter/sysexit in ring0 guests, + and only if it the guest asks for it. So for now, + this should never be used. */
Quoted 9 lines
arch/i386/kernel/entry.S ENTRY(kernel_thread_helper) · line 1034
Quoted 6 lines
arch/i386/kernel/entry.S +5
-0+ENTRY(xen_sti_sysexit) + CFI_STARTPROC + ud2 + CFI_ENDPROC +ENDPROC(xen_sti_sysexit)Put that elsewhere? It doesn't need to be here.
Yes, I can drop it. It's not needed in this kernel.
Quoted 6 lines
Review
Quoted 3 lines
+++
b/arch/i386/xen/enlighten.c(quoted diff) +0
-0@@ -0,0 +1,727 @@Comments describing what all the files do?
OK.
Quoted 11 lines
arch/i386/xen/enlighten.c line 63
Quoted 6 lines
arch/i386/xen/enlighten.c new file +5
-0+unsigned maskedx = ~0 ; +if (*eax ==1 ) + maskedx = ~((1 <<X86_FEATURE_APIC ) | + (1 <<X86_FEATURE_ACPI ) | + (1 <<X86_FEATURE_ACC ));Why ACC?
And why doesn't Xen mask those by itself?
Because it doesn't care whether they're set or not. I'm suppressing them here to prevent the kernel from trying to use these features. I suppress ACC in particular to stop the P4 thermal interrupt code from trying to do anything.
I'll comment it.
Quoted 3 lines
And you got apic functions later which would be never called? Why are the hooks needed then?
They aren't. They're only for VMI. I've only got them to make sure that there are no stray APIC usages.
Quoted 7 lines
Quoted 7 lines
arch/i386/xen/enlighten.c new file +7
-0+ +static unsigned long xen_save_fl (void ) +{ +struct vcpu_info *vcpu; +unsigned long flags; + +preempt_disable ();
Quoted 9 lines
arch/i386/xen/enlighten.c line 93
Quoted 5 lines
arch/i386/xen/enlighten.c new file +4
-0+ vcpu =x86_read_percpu (xen_vcpu); +/* flag has opposite sense of mask */ + flags = !vcpu->evtchn_upcall_mask; +preempt_enable ();If you use get_cpu/put_cpu it will be optimized away on PREEMPT && !SMP (more occurrences)
Won't preempt_disable disappear as well? I don't need the CPU number.
Quoted 8 lines
Quoted 8 lines
arch/i386/xen/enlighten.c new file +8
-0+static void xen_restore_fl (unsigned long flags) +{ +struct vcpu_info *vcpu; + +preempt_disable (); + +/* convert from IF type flag */ + flags = !(flags &X86_EFLAGS_IF );
Quoted 9 lines
arch/i386/xen/enlighten.c line 113
Quoted 5 lines
arch/i386/xen/enlighten.c new file +4
-0+ vcpu =x86_read_percpu (xen_vcpu); + vcpu->evtchn_upcall_mask = flags; +if (flags ==0 ) { +barrier ();/* unmask then check (avoid races) */ Don't you need a
rmb()here then? The CPU could speculate reads (more occurrences)
OK.
Quoted 12 lines
Quoted 12 lines
arch/i386/xen/enlighten.c new file +12
-0+if (unlikely (vcpu->evtchn_upcall_pending)) +force_evtchn_callback (); +preempt_enable (); + }else +preempt_enable_no_resched (); +} + +static void xen_irq_disable (void ) +{ +struct vcpu_info *vcpu; +preempt_disable (); + vcpu =x86_read_percpu (xen_vcpu);
Quoted 9 lines
arch/i386/xen/enlighten.c line 127
Quoted 3 lines
arch/i386/xen/enlighten.c new file +2
-0+ vcpu->evtchn_upcall_mask =1 ; +preempt_enable_no_resched ();First with the new per cpu the preempt disable shouldn't be needed anymore because the thing is atomic. In the worst case you do the change on the previous CPU, but that can happen anyways after
preempt_enable
No, there's a one instruction preempt window there. If I do:
mov %fs:xen_vcpu, %eax
movb $1,1(%eax)
and a preempt happens in between, then the interrupt will be disabled on the wrong cpu.
Once we can put the vcpu structure into the percpu area directly, then I can do:
movb $1,%fs:xen_vcpu+1
which is preempt-safe, of course.
Quoted 3 lines
And then when you have enabled who transfers the irq off state to the new CPU?
I don't follow you.
Quoted 11 lines
arch/i386/xen/enlighten.c line 156
Quoted 8 lines
arch/i386/xen/enlighten.c new file +7
-0+static void xen_halt (void ) +{ +#if 0 +if (irqs_disabled ()) +HYPERVISOR_vcpu_op (VCPUOP_down,smp_processor_id (),NULL ); +#endif +}Who halts then?
I fix this up in the xen-machine-ops.patch.
Quoted 4 lines
Quoted 4 lines
arch/i386/xen/enlighten.c new file +4
-0+static void xen_load_gdt (const struct Xgt_desc_struct *dtr) +{ +unsigned long *frames; +unsigned long va = dtr->address;
Quoted 9 lines
arch/i386/xen/enlighten.c line 204
Quoted 6 lines
arch/i386/xen/enlighten.c new file +5
-0+unsigned int size = dtr->size +1 ; +int f; +struct multicall_space mcs; + +BUG_ON (size >16 *PAGE_SIZE );Why 16?
I'll make it more explicit. It's 64k of GDT entries == 16 pages.
Quoted 6 lines
arch/i386/xen/enlighten.c line 313
Quoted 3 lines
arch/i386/xen/enlighten.c new file +2
-0+ count = desc->size /8 ; +BUG_ON (count >256 );should be >= ?
I think 256 idt entries is OK, but it should be (desc->size+1) / 8.
Quoted 4 lines
Quoted 4 lines
arch/i386/xen/enlighten.c new file +4
-0+static void xen_set_iopl_mask (unsigned mask) +{ +#if 0 +struct physdev_set_iopl set_iopl;
Quoted 9 lines
arch/i386/xen/enlighten.c line 373
Quoted 6 lines
arch/i386/xen/enlighten.c new file +5
-0+ +/* Force the change at ring 0. */ + set_iopl.iopl = (mask ==0 ) ?1 : (mask >>12 ) &3 ; +HYPERVISOR_physdev_op (PHYSDEVOP_set_iopl, &set_iopl); +#endif And who does iopl then?
Nobody at the moment. I don't think there's much need for it in an unprivileged Xen domU. I could just nop it out for now.
Quoted 10 lines
arch/i386/xen/enlighten.c line 423
Quoted 7 lines
arch/i386/xen/enlighten.c new file +6
-0+* 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. +*/ +#define xen_pfn_to_cr3 (pfn) (((unsigned)(pfn) << 12) | ((unsigned)(pfn) >> 20)) +#define xen_cr3_to_pfn (cr3) (((unsigned)(cr3) >> 12) | ((unsigned)(cr3) << 20))Don't you lose bits >4GB here due to the casts before shift?
Erm, good point.
Quoted 5 lines
arch/i386/xen/enlighten.c line 684
Quoted 2 lines
arch/i386/xen/enlighten.c new file +1
-0+BUG_ON (memcmp (xen_start_info->magic,"xen-3.0" ,7 ) !=0 );Hopefully Xen 4.0 can handle this then.
It would probably present xen-3 guests a xen-3 signature.
Quoted 7 lines
arch/i386/xen/enlighten.c line 719
Quoted 4 lines
arch/i386/xen/enlighten.c new file +3
-0+ +/* Poke various useful things into boot_params */ +LOADER_TYPE = (9 <<4 ) |0 ;| 0 ? Probably should be something symbolic
0 is the version number. I don't think there are symbols for the bootloader types.
Quoted 10 lines
arch/i386/xen/mmu.c line 215
Quoted 6 lines
arch/i386/xen/mmu.c new file +5
-0+unsigned long xen_pmd_val (pmd_t pmd) +{ +BUG (); +return 0 ; +}Why do we have
pmd_valhooks then?
Quoted 9 lines
arch/i386/xen/mmu.c line 237
Quoted 6 lines
arch/i386/xen/mmu.c new file +5
-0+pmd_t xen_make_pmd (unsigned long pmd) +{ +BUG (); +return __pmd (0 ); +}and
make_pmdhooks?
That's the !PAE case, so we expect to never have any PMD calls. The hooks exist for !PAE because I didn't want to have more ifdefs.
Quoted 8 lines
arch/i386/xen/time.c
Quoted 3 lines
arch/i386/xen/time.c new file +0
-0... will review the rest later.
Can you please split it up a bit?
OK.
J
Re: [PATCH 06/25] xen: Core Xen implementation
In reply to Andi KleenQuoted 2 lines
... will review the rest later.
Rest is ok
-Andi
Re: [PATCH 06/25] xen: Core Xen implementation
Quoted 5 lines · Andi Kleen
Quoted 2 lines
... will review the rest later.
Rest is ok
Thanks for looking at it. I'll try to separate xen-core into more digestable pieces.
J
Re: [PATCH 06/25] xen: Core Xen implementation
Quoted 9 lines · On Wednesday 25 April 2007 21:41:23 Jeremy Fitzhardinge wrote:
Quoted 5 lines · Andi Kleen
Quoted 2 lines
... will review the rest later.
Rest is ok
Thanks for looking at it. I'll try to separate xen-core into more digestable pieces.
For me you don't need anymore, but possibly for others.
To summarize the outstanding issues are:
- fixing sched_clock first
- hopefully more review of the core pieces by others
- what i commented (minor stuff mostly)
- review of xenbus and drivers
[i did upto the grant table code, but not more]
-Andi
Re: [PATCH 06/25] xen: Core Xen implementation II
Quoted 7 lines
To summarize the outstanding issues are:
- fixingsched_clockfirst
- hopefully more review of the core pieces by others
- what i commented (minor stuff mostly)
- review of xenbus and drivers
[i did upto the grant table code, but not more]
- and more testing by other people (forgot that earlier)
-Andi
Re: [PATCH 06/25] xen: Core Xen implementation
In reply to Andi KleenQuoted 2 lines · Andi Kleen
For me you don't need anymore, but possibly for others.
Hm. I'm not a fan of the great big monolithic patch myself, but on the other hand I don't like the idea of patches which are not self-contained steps from working->working state. Xen-core.patch is currently the (more or less) minimal set of stuff which needs to be in place to get working Xen guest up, and so from that perspective I don't think there's a good way of splitting it up.
Quoted 3 lines
To summarize the outstanding issues are:
- fixingsched_clockfirst
What was the sched_clock problem? I don't remember and outstanding issues with it. I noticed you didn't take paravirt-sched_clock.
Quoted 3 lines
- hopefully more review of the core pieces by others
- what i commented (minor stuff mostly)
I just rebased onto your newest patches, so I'll address your comments and repost.
Quoted 1 line
- review of xenbus and drivers
Yes, not much response there.
J
Re: [PATCH 06/25] xen: Core Xen implementation
Quoted 7 lines
Quoted 4 lines
To summarize the outstanding issues are:
- fixingsched_clockfirstWhat was the
sched_clockproblem? I don't remember and outstanding issues with it. I noticed you didn't take paravirt-sched_clock.
The major problem was that it didn't compile on x86-64. And a few uglities in there so I was not too unhappy to drop.
-Andi
Re: [PATCH 06/25] xen: Core Xen implementation
Quoted 2 lines · Andi Kleen
The major problem was that it didn't compile on x86-64.
Ah, OK. I don't think you mentioned that. I'll fix that up.
Quoted 2 lines
And a few uglities in there
Such as?
J
Re: [PATCH 06/25] xen: Core Xen implementation
In reply to Andi KleenQuoted 11 lines · Andi Kleen
arch/i386/xen/enlighten.c line 113
Quoted 7 lines
arch/i386/xen/enlighten.c new file +6
-0+/* convert from IF type flag */ + flags = !(flags &X86_EFLAGS_IF ); + vcpu =x86_read_percpu (xen_vcpu); + vcpu->evtchn_upcall_mask = flags; +if (flags ==0 ) { +barrier ();/* unmask then check (avoid races) */ Don't you need a
rmb()here then? The CPU could speculate reads (more occurrences)
Is rmb() sufficient? It will stop a speculative read on the pending flag, but will it make sure the write has happened by then? Ie, is it a write-vs-read barrier, or just a read-vs-read? Documentation/memory-barriers.txt suggests not.
J
Re: [PATCH 06/25] xen: Core Xen implementation
Quoted 8 lines · Jeremy Fitzhardinge
Quoted 3 lines
Don't you need a
rmb()here then? The CPU could speculate reads (more occurrences)Is
rmb()sufficient? It will stop a speculative read on the pending flag, but will it make sure the write has happened by then? Ie, is it a write-vs-read barrier, or just a read-vs-read?Documentation/memory-barriers.txtsuggests not.
The barrier() is sufficient. We are racing against Xen checking evtchn_upcall_mask *on the local cpu*. Which means an interrupt has to occur, which squashes speculative stuff.
Yeah, I know, it needs a better comment. :-)
-- Keir
PATCH 7/25 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 | 280 +++++++++++++++++++++++++++---------------- 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(+), 140 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_none (*pmd)) {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 -102
379 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 8/25 xen: 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
@@ -160,13 +160,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 )
@@ -193,7 +208,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)
@@ -217,7 +232,7 @@ static void xen_load_gdt(const struct XgMULTI_set_gdt (mcs.mc, frames, size/8 ); -xen_mc_issue (); +xen_mc_issue (PARAVIRT_LAZY_CPU ); } static void load_TLS_descriptor(struct thread_struct *t,
@@ -225,18 +240,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)
@@ -356,13 +373,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)
@@ -452,7 +465,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
@@ -344,7 +344,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 ;
@@ -364,10 +364,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
@@ -378,7 +380,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
@@ -402,7 +404,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),
@@ -416,7 +418,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 ;
@@ -426,7 +432,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
@@ -14,11 +14,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;
@@ -34,11 +40,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 9/25 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 | 101 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 100 insertions(+), 1 deletion(-)
===================================================================
arch/i386/xen/time.c +100 -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,99 @@ 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); + +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 +433,8 @@ static irqreturn_t xen_timer_interrupt(i ret =IRQ_HANDLED ; } +do_stolen_accounting (); +return ret; }
@@ -363,6 +460,8 @@ static void xen_setup_timer(int cpu) evt->irq = irq;clockevents_register_device (evt); +setup_runstate_info (); +put_cpu_var (xen_clock_events); }
@@ -375,7 +474,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;
Re: [PATCH 09/25] xen: Account for time stolen by Xen
arch/i386/xen/time.c struct shadow_time_info { · line 55
Quoted 5 lines
arch/i386/xen/time.c +4
-0+ + do { + state_time = state->state_entry_time; + barrier();
Should be likely rmb
-Andi
Re: [PATCH 09/25] xen: Account for time stolen by Xen
Quoted 7 lines · Andi Kleen
arch/i386/xen/time.c struct shadow_time_info { · line 55
Quoted 5 lines
arch/i386/xen/time.c +4
-0+ + do { + state_time = state->state_entry_time; + barrier();Should be likely rmb
We discussed this, and decided that it wasn't necessary. The state is always updated by the current CPU, so if it changes under our feet it will be because we were preempted, and so that should shoot down any speculated reads.
J
Re: [PATCH 09/25] xen: Account for time stolen by Xen
Quoted 9 lines · On Wednesday 25 April 2007 20:13:34 Jeremy Fitzhardinge wrote:
Quoted 7 lines · Andi Kleen
arch/i386/xen/time.c struct shadow_time_info { · line 55
Quoted 5 lines
arch/i386/xen/time.c +4
-0+ + do { + state_time = state->state_entry_time; + barrier();Should be likely rmb
Quoted 4 lines
We discussed this, and decided that it wasn't necessary. The state is always updated by the current CPU, so if it changes under our feet it will be because we were preempted, and so that should shoot down any speculated reads.
Then the barrier shouldn't be needed at all?
Anyways needs comments
-Andi
Re: [PATCH 09/25] xen: Account for time stolen by Xen
Quoted 2 lines · Andi Kleen
Then the barrier shouldn't be needed at all?
We still need to prevent compiler reordering.
Quoted 2 lines
Anyways needs comments
Yep.
J
PATCH 10/25 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 the running state (vs blocked, 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 11/25 xen: Xen SMP guest support
In reply to Jeremy FitzhardingeThis is a fairly straightforward Xen implementation of smp_ops. One thing this must to is carefully set up all the various sibling and core maps so that the smp scheduler setup works properly (the setup is very simple, since vcpus don't have any siblings or multiple cores).
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 | 16 arch/i386/kernel/smpboot.c | 4 arch/i386/xen/Makefile | 6 arch/i386/xen/enlighten.c | 118 ++++- arch/i386/xen/events.c | 78 +++ arch/i386/xen/mmu.c | 66 ++- arch/i386/xen/mmu.h | 9 arch/i386/xen/setup.c | 9 arch/i386/xen/smp.c | 419 ++++++++++++++++++++ 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 | 17 include/asm-i386/processor.h | 1 include/asm-i386/smp.h | 2 include/xen/events.h | 27 + 16 files changed, 730 insertions(+), 78 deletions(-)
===================================================================
arch/i386/kernel/smp.c +1 -15
@@ -23,6 +23,7 @@#include <asm/mtrr.h> #include <asm/tlbflush.h> +#include <asm/mmu_context.h> #include <mach_apic.h> /*
@@ -256,21 +257,6 @@ static struct mm_struct * flush_mm;static struct mm_struct * flush_mm;static unsigned long flush_va;static DEFINE_SPINLOCK (tlbstate_lock); - -/* -* 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) -{ -if (per_cpu (cpu_tlbstate, cpu).state ==TLBSTATE_OK ) -BUG (); -cpu_clear (cpu,per_cpu (cpu_tlbstate, cpu).active_mm->cpu_vm_mask); -load_cr3 (swapper_pg_dir); -}/* *
===================================================================
arch/i386/kernel/smpboot.c +2 -2
@@ -151,7 +151,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;
@@ -785,7 +785,7 @@ static inline struct task_struct * alloc/* Initialize the CPU's GDT. This is either the boot CPU doing itself (still using the master per-cpu area), or a CPU doing it for a secondary which will soon come up. */ -static __cpuinit void init_gdt (int cpu) +__cpuinit void init_gdt (int cpu) {struct desc_struct *gdt =get_cpu_gdt_table (cpu);
===================================================================
arch/i386/xen/Makefile +4 -2
@@ -1,2 +1,4 @@ obj-y := enlighten.o setup.o events.o t -obj-y := enlighten.o setup.o events.o time.o \ - features.o mmu.o multicalls.o +obj-y := enlighten.o setup.o events.o time.o \ + features.o mmu.o multicalls.o + +obj-$(CONFIG_SMP) += smp.o
===================================================================
arch/i386/xen/enlighten.c +93 -25
204 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 +46 -20
81 lines not on this page · raw message
===================================================================
arch/i386/xen/mmu.h +9 -0
@@ -2,6 +2,15 @@#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. +*/ +#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 -4
@@ -15,10 +15,6 @@#include <xen/features.h> #include "xen-ops.h" - -/* 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;
@@ -90,4 +86,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 +419 -0
419 lines not on this page · raw message
===================================================================
arch/i386/xen/time.c +5 -4
@@ -452,8 +452,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;
@@ -502,5 +503,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 +17 -0
@@ -30,6 +30,23 @@ static inline void enter_lazy_tlb(structif (per_cpu (cpu_tlbstate, cpu).state ==TLBSTATE_OK )per_cpu (cpu_tlbstate, cpu).state =TLBSTATE_LAZY ;#endif +} + +/* +* 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) +{ +#ifdef CONFIG_SMP +if (per_cpu (cpu_tlbstate, cpu).state ==TLBSTATE_OK ) +BUG (); +cpu_clear (cpu,per_cpu (cpu_tlbstate, cpu).active_mm->cpu_vm_mask); +#endif +load_cr3 (swapper_pg_dir); } static inline void switch_mm(struct mm_struct *prev,
===================================================================
include/asm-i386/processor.h +1 -0
@@ -752,6 +752,7 @@ extern void cpu_set_gdt(int);extern void cpu_set_gdt (int );extern void switch_to_new_gdt (void );extern void cpu_init (void ); +extern void init_gdt (int cpu);extern int force_mwait;
===================================================================
include/asm-i386/smp.h +2 -0
@@ -143,6 +143,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) {
Re: [PATCH 11/25] xen: Xen SMP guest support
Quoted 4 lines
#ifdef
CONFIG_X86_LOCAL_APIC
static unsigned longxen_apic_read(unsigned long reg)
Can't you just make them all NULL? Crashing here should be correct.
arch/i386/xen/enlighten.c static const struct paravirt_ops xen_par · line 790
Quoted 2 lines
arch/i386/xen/enlighten.c +2
-0+#ifdef CONFIG_SMP +static const struct smp_ops xen_smp_ops __initdata = {
Why __initdata?
arch/i386/xen/smp.c line 55
Quoted 2 lines
arch/i386/xen/smp.c new file +2
-0+/* VCPUs are single-cored, and have no siblings */ +static void set_cpu_sibling_map (int cpu)
Can you put this somewhere generic and use it everywhere? Don't want duplication of this code.
arch/i386/xen/smp.c line 65
Quoted 10 lines
arch/i386/xen/smp.c new file +10
-0+{ +struct cpuinfo_x86 *c = &cpu_data[cpu]; + +cpu_set (cpu, cpu_sibling_map[cpu]); +cpu_set (cpu, c->llc_shared_map); + cpu_core_map[cpu] = cpu_sibling_map[cpu]; + c->booted_cores =1 ; +} + +static void remove_siblinginfo (int cpu)
Similar.
arch/i386/xen/smp.c line 138
Quoted 7 lines
arch/i386/xen/smp.c new file +7
-0+void __init xen_fill_possible_map (void ) +{ +int i, rc; + +for_each_possible_cpu (i) +if (i !=smp_processor_id ()) +return ;
Strange check?
include/asm-i386/mmu_context.h static inline void enter_lazy_tlb(struct · line 50
Quoted 13 lines
include/asm-i386/mmu_context.h +12
-0+ +* We need to reload %cr3 since the page tables may be going +* away from under us.. +*/ +static inline void leave_mm (unsigned long cpu) +{ +#ifdef CONFIG_SMP +if (per_cpu (cpu_tlbstate, cpu).state ==TLBSTATE_OK ) +BUG (); +cpu_clear (cpu,per_cpu (cpu_tlbstate, cpu).active_mm->cpu_vm_mask); +#endif +load_cr3 (swapper_pg_dir); }
Should be out of line
-Andi
Re: [PATCH 11/25] xen: Xen SMP guest support
Quoted 7 lines · Andi Kleen
Quoted 4 lines
#ifdef
CONFIG_X86_LOCAL_APIC
static unsigned longxen_apic_read(unsigned long reg)Can't you just make them all NULL? Crashing here should be correct.
No. The APIC setup code does at least one unconditional read to get the APIC version before deciding the APIC is disabled/not present. In my testing that's the only access to the APIC which happens under Xen, but it wouldn't surprise me if there were other stray accesses with different configurations (like the P4_THERMAL stuff).
Quoted 6 lines
arch/i386/xen/enlighten.c static const struct paravirt_ops xen_par · line 790
Quoted 3 lines
arch/i386/xen/enlighten.c +2
-0+#ifdef CONFIG_SMP +static const struct smp_ops xen_smp_ops __initdata = {Why
__initdata?
It gets copied into the real smp_ops early on, so it isn't needed after that.
Quoted 7 lines
arch/i386/xen/smp.c line 55
Quoted 3 lines
arch/i386/xen/smp.c new file +2
-0+/* VCPUs are single-cored, and have no siblings */ +static void set_cpu_sibling_map (int cpu)Can you put this somewhere generic and use it everywhere? Don't want duplication of this code.
OK.
Quoted 2 lines
Strange check?
Er, yes, that does look odd.
Quoted 8 lines
Quoted 8 lines
include/asm-i386/mmu_context.h +8
-0+ +* We need to reload %cr3 since the page tables may be going +* away from under us.. +*/ +static inline void leave_mm (unsigned long cpu) +{ +#ifdef CONFIG_SMP +if (per_cpu (cpu_tlbstate, cpu).state ==TLBSTATE_OK )
Quoted 9 lines
include/asm-i386/mmu_context.h static inline void enter_lazy_tlb(struct · line 50
Quoted 6 lines
include/asm-i386/mmu_context.h +4
-0+BUG (); +cpu_clear (cpu,per_cpu (cpu_tlbstate, cpu).active_mm->cpu_vm_mask); +#endif +load_cr3 (swapper_pg_dir); }Should be out of line
OK.
J
Re: [PATCH 11/25] xen: Xen SMP guest support
In reply to Andi KleenQuoted 7 lines · Andi Kleen
arch/i386/xen/smp.c line 55
Quoted 3 lines
arch/i386/xen/smp.c new file +2
-0+/* VCPUs are single-cored, and have no siblings */ +static void set_cpu_sibling_map (int cpu)Can you put this somewhere generic and use it everywhere? Don't want duplication of this code.
Are there any other users? This is a very cutdown version of the code in kernel/smpboot.c; under Xen all CPUs are considered to be single-cored and single-threaded, so there's not a lot to do here.
J
Re: [PATCH 11/25] xen: Xen SMP guest support
Quoted 9 lines · On Friday 27 April 2007 08:46:19 Jeremy Fitzhardinge wrote:
Quoted 7 lines · Andi Kleen
arch/i386/xen/smp.c line 55
Quoted 3 lines
arch/i386/xen/smp.c new file +2
-0+/* VCPUs are single-cored, and have no siblings */ +static void set_cpu_sibling_map (int cpu)Can you put this somewhere generic and use it everywhere? Don't want duplication of this code.
Quoted 3 lines
Are there any other users? This is a very cutdown version of the code in
kernel/smpboot.c; under Xen all CPUs are considered to be single-cored and single-threaded, so there's not a lot to do here.
I would like to have a single place to set that up, with xen calling it with single arguments and the normal code with complex ones
-Andi
PATCH 12/25 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 | 93 ++++++++++++++++++++++++++++---------------- arch/i386/xen/mmu.c | 4 + arch/i386/xen/multicalls.c | 11 ++--- arch/i386/xen/time.c | 22 ++++++++-- 5 files changed, 88 insertions(+), 44 deletions(-)
===================================================================
arch/i386/xen/Kconfig +1 -1
@@ -4,7 +4,7 @@ config XEN bool "Enable support for Xen hypervisor" - depends on PARAVIRT && !PREEMPT + depends on PARAVIRT default y help This is the Linux Xen port.
===================================================================
arch/i386/xen/enlighten.c +61 -32
198 lines not on this page · raw message
===================================================================
arch/i386/xen/mmu.c +3 -1
@@ -481,5 +481,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
@@ -1,4 +1,5 @@#include <linux/percpu.h> +#include <linux/hardirq.h> #include <asm/xen/hypercall.h>
@@ -18,9 +19,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 */
@@ -39,7 +42,6 @@ void xen_mc_flush(void) }else BUG_ON (b->argidx !=0 ); -put_cpu_var (mc_buffer);local_irq_restore (flags);BUG_ON (ret);
@@ -47,10 +49,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 ||
@@ -62,7 +65,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
@@ -48,7 +48,7 @@ static void get_runstate_snapshot(structu64 state_time;struct vcpu_runstate_info *state; -preempt_disable (); +BUG_ON (preemptible ()); state = &__get_cpu_var (runstate);
@@ -58,8 +58,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 )
@@ -128,15 +126,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 13/25 xen: 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 14/25 xen: 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/time.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-)
===================================================================
arch/i386/xen/time.c +16 -3
@@ -77,7 +77,7 @@ static void do_stolen_accounting(void) {struct vcpu_runstate_info state;struct vcpu_runstate_info *snap; -u64 blocked, runnable, offline, stolen; +s64 blocked, runnable, offline, stolen;cputime_t ticks;get_runstate_snapshot (&state);
@@ -97,6 +97,10 @@ static void do_stolen_accounting(void)including any left-overs from last time. Passing NULL to account_steal_time accounts the time as stolen. */ stolen = runnable + offline +__get_cpu_var (residual_stolen); + +if (stolen <0 ) + stolen =0 ; + ticks =0 ;while (stolen >=NS_PER_TICK ) { ticks++;
@@ -109,6 +113,10 @@ static void do_stolen_accounting(void)including any left-overs from last time. Passing idle to account_steal_time accounts the time as idle/wait. */ blocked +=__get_cpu_var (residual_blocked); + +if (blocked <0 ) + blocked =0 ; + ticks =0 ;while (blocked >=NS_PER_TICK ) { ticks++;
@@ -127,7 +135,8 @@ unsigned long long xen_sched_clock(void) {struct vcpu_runstate_info state;cycle_t now; -unsigned long long ret; +u64 ret; +s64 offset;/* * Ideally sched_clock should be called on a per-cpu basis
@@ -142,9 +151,13 @@ unsigned long long xen_sched_clock(void)WARN_ON (state.state != RUNSTATE_running); + offset = now - state.state_entry_time; +if (offset <0 ) + offset =0 ; + ret = state.time[RUNSTATE_blocked] + state.time[RUNSTATE_running] + - (now - state.state_entry_time); + offset;preempt_enable ();
PATCH 15/25 xen: xen time fixups
In reply to Jeremy Fitzhardinge1. make sure timer state is set up before bringing up CPU
2. make sure snapshot of 64-bit time values is atomic
Be sure, however, that the clockevent source is registered on its home CPU.
--- arch/i386/xen/smp.c | 4 +- arch/i386/xen/time.c | 93 +++++++++++++++++++++++++++++++---------------- arch/i386/xen/xen-ops.h | 3 + 3 files changed, 67 insertions(+), 33 deletions(-)
===================================================================
arch/i386/xen/smp.c +3 -1
@@ -78,10 +78,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 ();
@@ -275,6 +276,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 +62 -31
165 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 16/25 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/Kconfig | 1 arch/i386/xen/events.c | 3 - drivers/Makefile | 3 + drivers/xen/Makefile | 1 drivers/xen/hvc-console.c | 134 +++++++++++++++++++++++++++++++++++++++++++++ include/xen/events.h | 1 6 files changed, 142 insertions(+), 1 deletion(-)
===================================================================
arch/i386/xen/Kconfig +1 -0
@@ -5,6 +5,7 @@ config XEN config XEN bool "Enable support for Xen hypervisor" depends on PARAVIRT + select HVC_DRIVER default y help This is the Linux Xen port.
===================================================================
arch/i386/xen/events.c +2 -1
@@ -219,7 +219,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;
@@ -244,6 +244,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/xen/Makefile new file +1 -0
@@ -0,0 +1,1 @@ +obj-y += hvc-console.o
===================================================================
drivers/xen/hvc-console.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,
Re: [PATCH 16/25] xen: Use the hvc console infrastructure for Xen console
Quoted 5 lines · Jeremy Fitzhardinge
Implement a Xen back-end for hvc console.
From: Gerd Hoffmann <[email protected]>
Signed-off-by Jeremy Fitzhardinge <[email protected]>
Quoted 8 lines
--- arch/i386/xen/Kconfig | 1 arch/i386/xen/events.c | 3 - drivers/Makefile | 3 + drivers/xen/Makefile | 1 drivers/xen/hvc-console.c | 134 +++++++++++++++++++++++++++++++++++++++++++++ include/xen/events.h | 1 6 files changed, 142 insertions(+), 1 deletion(-)
If you move the driver to drivers/char/hvc_xen.c instead, you won't have to do...
Quoted 1 line
+#include "
../char/hvc_console.h"
...this.
Other single-platform backend hvc drivers are under drivers/char already.
-Olof
Re: [PATCH 16/25] xen: Use the hvc console infrastructure for Xen console
Quoted 20 lines · Olof Johansson
Quoted 5 lines · Jeremy Fitzhardinge
Implement a Xen back-end for hvc console.
From: Gerd Hoffmann <[email protected]>
Signed-off-by Jeremy Fitzhardinge <[email protected]>Quoted 9 lines
--- arch/i386/xen/Kconfig | 1 arch/i386/xen/events.c | 3 - drivers/Makefile | 3 + drivers/xen/Makefile | 1 drivers/xen/hvc-console.c | 134 +++++++++++++++++++++++++++++++++++++++++++++ include/xen/events.h | 1 6 files changed, 142 insertions(+), 1 deletion(-)If you move the driver to
drivers/char/hvc_xen.cinstead, you won't have to do...
Quoted 6 lines
Quoted 2 lines
+#include "
../char/hvc_console.h"...this.
Other single-platform backend hvc drivers are under
drivers/charalready.
Good point.
J
PATCH 17/25 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/xen/hvc-console.c | 25 +++++++++++++++++++++++++ include/xen/hvc-console.h | 6 ++++++ 3 files changed, 36 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 */
@@ -243,6 +244,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/xen/hvc-console.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 "../char/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 , +};
===================================================================
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 */
PATCH 18/25 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 19/25 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 | 9 drivers/xen/xenbus/xenbus_client.c | 563 +++++++++++++++++ drivers/xen/xenbus/xenbus_comms.c | 233 +++++++ drivers/xen/xenbus/xenbus_comms.h | 46 + drivers/xen/xenbus/xenbus_probe.c | 919 +++++++++++++++++++++++++++++ drivers/xen/xenbus/xenbus_probe.h | 72 ++ drivers/xen/xenbus/xenbus_probe_backend.c | 265 ++++++++ drivers/xen/xenbus/xenbus_xs.c | 861 +++++++++++++++++++++++++++ include/asm-i386/xen/hypervisor.h | 1 include/xen/xenbus.h | 211 ++++++ 11 files changed, 3181 insertions(+)
===================================================================
drivers/xen/Makefile +1 -0
@@ -1,2 +1,3 @@ obj-y += grant-table.o obj-y += grant-table.o obj-y += hvc-console.o +obj-y += xenbus/
===================================================================
drivers/xen/xenbus/Makefile new file +9 -0
@@ -0,0 +1,9 @@ +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 + +obj-$(CONFIG_XEN_BACKEND) += xenbus_probe_backend.o
===================================================================
drivers/xen/xenbus/xenbus_client.c new file +563 -0
563 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 +919 -0
919 lines not on this page · raw message
===================================================================
drivers/xen/xenbus/xenbus_probe.h new file +72 -0
72 lines not on this page · raw message
===================================================================
drivers/xen/xenbus/xenbus_probe_backend.c new file +265 -0
265 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 +211 -0
22 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 20/25 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 | 1 drivers/block/Makefile | 1 drivers/block/xen/Kconfig | 14 drivers/block/xen/Makefile | 5 drivers/block/xen/blkfront.c | 844 ++++++++++++++++++++++++++++++++++++++++++ drivers/block/xen/block.h | 135 ++++++ drivers/block/xen/vbd.c | 229 +++++++++++ include/linux/major.h | 2 8 files changed, 1231 insertions(+)
===================================================================
drivers/block/Kconfig +1 -0
@@ -445,6 +445,7 @@ config CDROM_PKTCDVD_WCACHE don't do deferred write error handling yet. source "drivers/s390/block/Kconfig" +source "drivers/block/xen/Kconfig" config ATA_OVER_ETH tristate "ATA over Ethernet support"
===================================================================
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) += xen/
===================================================================
drivers/block/xen/Kconfig new file +14 -0
@@ -0,0 +1,14 @@ +menu "Xen block device drivers" + depends on XEN + +config XEN_BLKDEV_FRONTEND + tristate "Block device frontend driver" + depends on XEN + default y + help + The block device frontend driver allows the kernel to access block + devices exported from a device driver virtual machine. Unless you + are building a dedicated device driver virtual machine, then you + almost certainly want to say Y here. + +endmenu
===================================================================
drivers/block/xen/Makefile new file +5 -0
@@ -0,0 +1,5 @@ + +obj-$(CONFIG_XEN_BLKDEV_FRONTEND) := xenblk.o + +xenblk-objs := blkfront.o vbd.o +
===================================================================
drivers/block/xen/blkfront.c new file +844 -0
844 lines not on this page · raw message
===================================================================
drivers/block/xen/block.h new file +135 -0
135 lines not on this page · raw message
===================================================================
drivers/block/xen/vbd.c new file +229 -0
229 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
PATCH 21/25 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 | 1957 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 1971 insertions(+)
===================================================================
drivers/net/Kconfig +12 -0
@@ -2508,6 +2508,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 +1957 -0
1,957 lines not on this page · raw message
PATCH 22/25 xen: xen-netfront: use skb.cb for storing private data
In reply to Jeremy FitzhardingeNetfront's use of nh.raw and h.raw for storing page+offset is a bit hinky, and it breaks with upcoming network stack updates which reduce these fields to sub-pointer sizes. Fortunately, skb offers the "cb" field specifically for stashing this kind of info, so use it.
--- drivers/net/xen-netfront.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-)
===================================================================
drivers/net/xen-netfront.c +13 -5
@@ -52,6 +52,13 @@#include <xen/page.h> #include <xen/grant_table.h> +struct netfront_cb { +struct page *page; +unsigned offset; +}; + +#define NETFRONT_SKB_CB (skb) ((struct netfront_cb *)((skb)->cb)) +/* * Mutually-exclusive module options to select receive data path: * rx_copy : Packets are copied by network backend into local memory
@@ -944,10 +951,11 @@ static void handle_incoming_queue(structstruct sk_buff *skb;while ((skb =__skb_dequeue (rxq)) !=NULL ) { -struct page *page = (struct page *)skb->nh.raw; +struct page *page =NETFRONT_SKB_CB (skb)->page;void *vaddr =page_address (page); - -memcpy (skb->data, vaddr + (skb->h.raw - skb->nh.raw), +unsigned offset =NETFRONT_SKB_CB (skb)->offset; + +memcpy (skb->data, vaddr + offset,skb_headlen (skb));if (page !=skb_shinfo (skb)->frags[0 ].page)
@@ -1251,8 +1259,8 @@ err: } } - skb->nh.raw = (void *)skb_shinfo (skb)->frags[0 ].page; - skb->h.raw = skb->nh.raw + rx->offset; +NETFRONT_SKB_CB (skb)->page =skb_shinfo (skb)->frags[0 ].page; +NETFRONT_SKB_CB (skb)->offset = rx->offset; len = rx->status;if (len >RX_COPY_THRESHOLD )
Re: [PATCH 22/25] xen: xen-netfront: use skb.cb for storing private data
Quoted 9 lines · Jeremy Fitzhardinge
Netfront's use of nh.raw and h.raw for storing page+offset is a bit hinky, and it breaks with upcoming network stack updates which reduce these fields to sub-pointer sizes. Fortunately, skb offers the "cb" field specifically for stashing this kind of info, so use it.
Signed-off-by Jeremy Fitzhardinge <[email protected]>Cc Herbert Xu <[email protected]>Cc Chris Wright <[email protected]>Cc Christian Limpach <[email protected]>
Thanks Jeremy. The patch looks good.
Cheers,
Signature · 4 lines
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <[email protected]>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txtRe: [PATCH 22/25] xen: xen-netfront: use skb.cb for storing private data
Quoted 1 line · Herbert Xu
Thanks Jeremy. The patch looks good.
Could you give netfront an overall review as well? I know you're already pretty familiar with it, but if you could cast a fresh eye over it, that would be helpful.
Thanks,
J
Re: [PATCH 22/25] xen: xen-netfront: use skb.cb for storing private data
Quoted 4 lines · Jeremy Fitzhardinge
Could you give netfront an overall review as well? I know you're already pretty familiar with it, but if you could cast a fresh eye over it, that would be helpful.
Sure thing. I'll look over it soon.
Actually there is one thing I'd like to see changed first up: I noticed that you've stripped out the checksum hack which is in the main Xen tree. We actually have the code in net-2.6.22 (which is also in mm) that lets you use CHECKSUM_PARTIAL on received packets without having to do that hack.
Here's the patch that I've been testing so far. It's against the Xen source, but should be easy to adapt to your version as well.
I just thought about this again, and in fact we need this change for correctness as well as performance. Because not setting ip_summed to CHECKSUM_PARTIAL in netfront is not going to stop netback from sending CHECKSUM_PARTIAL packets to us. If these packets are then routed/bridged back to netback, they'll have the wrong checksum.
Cheers,
Signature · 411 lines
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <[email protected]>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
--
diff -ur linux-2.6.20.noarch/drivers/xen/core/skbuff.c linux-2.6.20.i686/drivers/xen/core/skbuff.c
--- linux-2.6.20.noarch/drivers/xen/core/skbuff.c 2007-04-03 15:26:15.000000000 +1000
+++ linux-2.6.20.i686/drivers/xen/core/skbuff.c 2007-03-30 21:06:20.000000000 +1000
@@ -9,6 +9,10 @@
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/init.h>
+#include <linux/if_ether.h>
+#include <linux/tcp.h>
+#include <linux/udp.h>
+#include <net/ip.h>
#include <asm/io.h>
#include <asm/page.h>
#include <asm/hypervisor.h>
@@ -78,6 +82,37 @@
return skb;
}
+int skb_checksum_setup(struct sk_buff *skb)
+{
+ if (skb->protocol != htons(ETH_P_IP))
+ goto out;
+ skb->h.raw = (unsigned char *)skb->nh.iph + 4*skb->nh.iph->ihl;
+ if (skb->h.raw >= skb->tail)
+ goto out;
+ switch (skb->nh.iph->protocol) {
+ case IPPROTO_TCP:
+ skb->csum_offset = offsetof(struct tcphdr, check);
+ break;
+ case IPPROTO_UDP:
+ skb->csum_offset = offsetof(struct udphdr, check);
+ break;
+ default:
+ if (net_ratelimit())
+ printk(KERN_ERR "Attempting to checksum a non-"
+ "TCP/UDP packet, dropping a protocol"
+ " %d packet", skb->nh.iph->protocol);
+ goto out;
+ }
+ if ((skb->h.raw + skb->csum_offset + 2) > skb->tail)
+ goto out;
+ skb->ip_summed = CHECKSUM_PARTIAL;
+
+ return 0;
+out:
+ return -EPROTO;
+}
+EXPORT_SYMBOL(skb_checksum_setup);
+
static void skbuff_ctor(void *buf, struct kmem_cache *cachep, unsigned long unused)
{
int order = 0;
diff -ur linux-2.6.20.noarch/drivers/xen/netback/loopback.c linux-2.6.20.i686/drivers/xen/netback/loopback.c
--- linux-2.6.20.noarch/drivers/xen/netback/loopback.c 2007-04-03 15:26:15.000000000 +1000
+++ linux-2.6.20.i686/drivers/xen/netback/loopback.c 2007-03-30 21:01:02.000000000 +1000
@@ -149,16 +149,6 @@
np->stats.rx_bytes += skb->len;
np->stats.rx_packets++;
- if (skb->ip_summed == CHECKSUM_PARTIAL) {
- /* Defer checksum calculation. */
- skb->proto_csum_blank = 1;
- /* Must be a local packet: assert its integrity. */
- skb->proto_data_valid = 1;
- }
-
- skb->ip_summed = skb->proto_data_valid ?
- CHECKSUM_UNNECESSARY : CHECKSUM_NONE;
-
skb->pkt_type = PACKET_HOST; /* overridden by eth_type_trans() */
skb->protocol = eth_type_trans(skb, dev);
skb->dev = dev;
diff -ur linux-2.6.20.noarch/drivers/xen/netback/netback.c linux-2.6.20.i686/drivers/xen/netback/netback.c
--- linux-2.6.20.noarch/drivers/xen/netback/netback.c 2007-04-03 15:26:15.000000000 +1000
+++ linux-2.6.20.i686/drivers/xen/netback/netback.c 2007-03-31 21:07:48.000000000 +1000
@@ -293,7 +293,6 @@
/* Copy only the header fields we use in this driver. */
nskb->dev = skb->dev;
nskb->ip_summed = skb->ip_summed;
- nskb->proto_data_valid = skb->proto_data_valid;
dev_kfree_skb(skb);
skb = nskb;
}
@@ -666,9 +665,11 @@
id = meta[npo.meta_cons].id;
flags = nr_frags ? NETRXF_more_data : 0;
- if (skb->ip_summed == CHECKSUM_PARTIAL) /* local packet? */
+ if (skb->ip_summed == CHECKSUM_PARTIAL)
+ /* local packet? */
flags |= NETRXF_csum_blank | NETRXF_data_validated;
- else if (skb->proto_data_valid) /* remote but checksummed? */
+ else if (skb->ip_summed == CHECKSUM_UNNECESSARY)
+ /* remote but checksummed? */
flags |= NETRXF_data_validated;
if (meta[npo.meta_cons].copy)
@@ -1303,23 +1304,19 @@
netif_idx_release(pending_idx);
}
- /*
- * Old frontends do not assert data_validated but we
- * can infer it from csum_blank so test both flags.
- */
- if (txp->flags & (NETTXF_data_validated|NETTXF_csum_blank)) {
- skb->ip_summed = CHECKSUM_UNNECESSARY;
- skb->proto_data_valid = 1;
- } else {
- skb->ip_summed = CHECKSUM_NONE;
- skb->proto_data_valid = 0;
- }
- skb->proto_csum_blank = !!(txp->flags & NETTXF_csum_blank);
-
netbk_fill_frags(skb);
skb->dev = netif->dev;
skb->protocol = eth_type_trans(skb, skb->dev);
+ skb->nh.raw = skb->data;
+
+ if (txp->flags & NETTXF_csum_blank) {
+ if (skb_checksum_setup(skb)) {
+ kfree_skb(skb);
+ continue;
+ }
+ } else if (txp->flags & NETTXF_data_validated)
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
netif->stats.rx_bytes += skb->len;
netif->stats.rx_packets++;
diff -ur linux-2.6.20.noarch/drivers/xen/netfront/netfront.c linux-2.6.20.i686/drivers/xen/netfront/netfront.c
--- linux-2.6.20.noarch/drivers/xen/netfront/netfront.c 2007-04-03 15:26:15.000000000 +1000
+++ linux-2.6.20.i686/drivers/xen/netfront/netfront.c 2007-03-31 21:07:43.000000000 +1000
@@ -925,12 +925,12 @@
tx->flags = 0;
extra = NULL;
- if (skb->ip_summed == CHECKSUM_PARTIAL) /* local packet? */
+ if (skb->ip_summed == CHECKSUM_PARTIAL)
+ /* local packet? */
tx->flags |= NETTXF_csum_blank | NETTXF_data_validated;
-#ifdef CONFIG_XEN
- if (skb->proto_data_valid) /* remote but checksummed? */
+ else if (skb->ip_summed == CHECKSUM_UNNECESSARY)
+ /* remote but checksummed? */
tx->flags |= NETTXF_data_validated;
-#endif
#ifdef HAVE_TSO
if (skb_is_gso(skb)) {
@@ -1351,20 +1351,10 @@
skb->truesize += skb->data_len - (RX_COPY_THRESHOLD - len);
skb->len += skb->data_len;
- /*
- * Old backends do not assert data_validated but we
- * can infer it from csum_blank so test both flags.
- */
- if (rx->flags & (NETRXF_data_validated|NETRXF_csum_blank))
+ if (rx->flags & NETRXF_csum_blank)
+ skb->ip_summed = CHECKSUM_PARTIAL;
+ else if (rx->flags & NETRXF_data_validated)
skb->ip_summed = CHECKSUM_UNNECESSARY;
- else
- skb->ip_summed = CHECKSUM_NONE;
-#ifdef CONFIG_XEN
- skb->proto_data_valid = (skb->ip_summed != CHECKSUM_NONE);
- skb->proto_csum_blank = !!(rx->flags & NETRXF_csum_blank);
-#endif
- np->stats.rx_packets++;
- np->stats.rx_bytes += skb->len;
__skb_queue_tail(&rxq, skb);
@@ -1404,6 +1394,19 @@
/* Ethernet work: Delayed to here as it peeks the header. */
skb->protocol = eth_type_trans(skb, dev);
+ skb->nh.raw = skb->data;
+
+ if (skb->ip_summed == CHECKSUM_PARTIAL) {
+ if (skb_checksum_setup(skb)) {
+ work_done--;
+ kfree_skb(skb);
+ np->stats.rx_errors++;
+ continue;
+ }
+ }
+
+ np->stats.rx_packets++;
+ np->stats.rx_bytes += skb->len;
/* Pass it up. */
netif_receive_skb(skb);
diff -ur linux-2.6.20.noarch/include/linux/skbuff.h linux-2.6.20.i686/include/linux/skbuff.h
--- linux-2.6.20.noarch/include/linux/skbuff.h 2007-04-03 15:26:15.000000000 +1000
+++ linux-2.6.20.i686/include/linux/skbuff.h 2007-03-30 21:01:02.000000000 +1000
@@ -202,8 +202,6 @@
* @local_df: allow local fragmentation
* @cloned: Head may be cloned (check refcnt to be sure)
* @nohdr: Payload reference only, must not modify header
- * @proto_data_valid: Protocol data validated since arriving at localhost
- * @proto_csum_blank: Protocol csum must be added before leaving localhost
* @pkt_type: Packet class
* @fclone: skbuff clone status
* @ip_summed: Driver fed us an IP checksum
@@ -286,13 +284,7 @@
nfctinfo:3;
__u8 pkt_type:3,
fclone:2,
-#ifndef CONFIG_XEN
ipvs_property:1;
-#else
- ipvs_property:1,
- proto_data_valid:1,
- proto_csum_blank:1;
-#endif
__be16 protocol;
void (*destructor)(struct sk_buff *skb);
@@ -1345,6 +1337,8 @@
extern struct sk_buff *skb_segment(struct sk_buff *skb, int features);
+extern int skb_checksum_setup(struct sk_buff *skb);
+
static inline void *skb_header_pointer(const struct sk_buff *skb, int offset,
int len, void *buffer)
{
diff -ur linux-2.6.20.noarch/net/core/dev.c linux-2.6.20.i686/net/core/dev.c
--- linux-2.6.20.noarch/net/core/dev.c 2007-04-03 15:26:15.000000000 +1000
+++ linux-2.6.20.i686/net/core/dev.c 2007-04-03 15:26:04.000000000 +1000
@@ -117,12 +117,6 @@
#include <linux/err.h>
#include <linux/ctype.h>
-#ifdef CONFIG_XEN
-#include <net/ip.h>
-#include <linux/tcp.h>
-#include <linux/udp.h>
-#endif
-
/*
* The list of packet types we will receive (as opposed to discard)
* and the routines to invoke.
@@ -1398,43 +1392,6 @@
} \
}
-#ifdef CONFIG_XEN
-inline int skb_checksum_setup(struct sk_buff *skb)
-{
- if (skb->proto_csum_blank) {
- if (skb->protocol != htons(ETH_P_IP))
- goto out;
- skb->h.raw = (unsigned char *)skb->nh.iph + 4*skb->nh.iph->ihl;
- if (skb->h.raw >= skb->tail)
- goto out;
- switch (skb->nh.iph->protocol) {
- case IPPROTO_TCP:
- skb->csum = offsetof(struct tcphdr, check);
- break;
- case IPPROTO_UDP:
- skb->csum = offsetof(struct udphdr, check);
- break;
- default:
- if (net_ratelimit())
- printk(KERN_ERR "Attempting to checksum a non-"
- "TCP/UDP packet, dropping a protocol"
- " %d packet", skb->nh.iph->protocol);
- goto out;
- }
- if ((skb->h.raw + skb->csum + 2) > skb->tail)
- goto out;
- skb->ip_summed = CHECKSUM_PARTIAL;
- skb->proto_csum_blank = 0;
- }
- return 0;
-out:
- return -EPROTO;
-}
-#else
-inline int skb_checksum_setup(struct sk_buff *skb) { return 0; }
-#endif
-
-
/**
* dev_queue_xmit - transmit a buffer
* @skb: buffer to transmit
@@ -1467,12 +1424,6 @@
struct Qdisc *q;
int rc = -ENOMEM;
- /* If a checksum-deferred packet is forwarded to a device that needs a
- * checksum, correct the pointers and force checksumming.
- */
- if (skb_checksum_setup(skb))
- goto out_kfree_skb;
-
/* GSO will handle the following emulations directly. */
if (netif_needs_gso(dev, skb))
goto gso;
@@ -1848,19 +1799,6 @@
}
#endif
-#ifdef CONFIG_XEN
- switch (skb->ip_summed) {
- case CHECKSUM_UNNECESSARY:
- skb->proto_data_valid = 1;
- break;
- case CHECKSUM_PARTIAL:
- /* XXX Implement me. */
- default:
- skb->proto_data_valid = 0;
- break;
- }
-#endif
-
list_for_each_entry_rcu(ptype, &ptype_all, list) {
if (!ptype->dev || ptype->dev == skb->dev) {
if (pt_prev)
@@ -3625,7 +3563,6 @@
EXPORT_SYMBOL(net_enable_timestamp);
EXPORT_SYMBOL(net_disable_timestamp);
EXPORT_SYMBOL(dev_get_flags);
-EXPORT_SYMBOL(skb_checksum_setup);
#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
EXPORT_SYMBOL(br_handle_frame_hook);
diff -ur linux-2.6.20.noarch/net/core/skbuff.c linux-2.6.20.i686/net/core/skbuff.c
--- linux-2.6.20.noarch/net/core/skbuff.c 2007-04-03 15:26:15.000000000 +1000
+++ linux-2.6.20.i686/net/core/skbuff.c 2007-03-30 21:01:02.000000000 +1000
@@ -484,10 +484,6 @@
C(local_df);
n->cloned = 1;
n->nohdr = 0;
-#ifdef CONFIG_XEN
- C(proto_data_valid);
- C(proto_csum_blank);
-#endif
C(pkt_type);
C(ip_summed);
C(priority);
diff -ur linux-2.6.20.noarch/net/ipv4/netfilter/ip_nat_proto_tcp.c linux-2.6.20.i686/net/ipv4/netfilter/ip_nat_proto_tcp.c
--- linux-2.6.20.noarch/net/ipv4/netfilter/ip_nat_proto_tcp.c 2007-04-03 15:26:15.000000000 +1000
+++ linux-2.6.20.i686/net/ipv4/netfilter/ip_nat_proto_tcp.c 2007-03-30 21:01:02.000000000 +1000
@@ -129,15 +129,8 @@
if (hdrsize < sizeof(*hdr))
return 1;
-#ifdef CONFIG_XEN
- if ((*pskb)->proto_csum_blank)
- nf_csum_replace4(&hdr->check, oldip, newip);
- else
-#endif
- {
nf_proto_csum_replace4(&hdr->check, *pskb, oldip, newip, 1);
nf_proto_csum_replace2(&hdr->check, *pskb, oldport, newport, 0);
- }
return 1;
}
diff -ur linux-2.6.20.noarch/net/ipv4/netfilter/ip_nat_proto_udp.c linux-2.6.20.i686/net/ipv4/netfilter/ip_nat_proto_udp.c
--- linux-2.6.20.noarch/net/ipv4/netfilter/ip_nat_proto_udp.c 2007-04-03 15:26:15.000000000 +1000
+++ linux-2.6.20.i686/net/ipv4/netfilter/ip_nat_proto_udp.c 2007-03-30 21:01:02.000000000 +1000
@@ -115,16 +115,8 @@
}
if (hdr->check || (*pskb)->ip_summed == CHECKSUM_PARTIAL) {
-#ifdef CONFIG_XEN
- if ((*pskb)->proto_csum_blank)
- nf_csum_replace4(&hdr->check, oldip, newip);
- else
-#endif
- {
nf_proto_csum_replace4(&hdr->check, *pskb, oldip, newip, 1);
nf_proto_csum_replace2(&hdr->check, *pskb, *portptr, newport, 0);
- }
-
if (!hdr->check)
hdr->check = CSUM_MANGLED_0;
}
diff -ur linux-2.6.20.noarch/net/ipv4/xfrm4_output.c linux-2.6.20.i686/net/ipv4/xfrm4_output.c
--- linux-2.6.20.noarch/net/ipv4/xfrm4_output.c 2007-04-03 15:26:15.000000000 +1000
+++ linux-2.6.20.i686/net/ipv4/xfrm4_output.c 2007-03-30 21:01:02.000000000 +1000
@@ -18,8 +18,6 @@
#include <net/xfrm.h>
#include <net/icmp.h>
-extern int skb_checksum_setup(struct sk_buff *skb);
-
static int xfrm4_tunnel_check_size(struct sk_buff *skb)
{
int mtu, ret = 0;
@@ -49,10 +47,6 @@
struct dst_entry *dst = skb->dst;
struct xfrm_state *x = dst->xfrm;
int err;
-
- err = skb_checksum_setup(skb);
- if (err)
- goto error_nolock;
if (skb->ip_summed == CHECKSUM_PARTIAL) {
err = skb_checksum_help(skb);Re: [PATCH 22/25] xen: xen-netfront: use skb.cb for storing private data
Quoted 8 lines · Herbert Xu
Sure thing. I'll look over it soon.
Actually there is one thing I'd like to see changed first up: I noticed that you've stripped out the checksum hack which is in the main Xen tree. We actually have the code in net-2.6.22 (which is also in mm) that lets you use
CHECKSUM_PARTIALon received packets without having to do that hack.
Quoted 9 lines
Here's the patch that I've been testing so far. It's against the Xen source, but should be easy to adapt to your version as well.
I just thought about this again, and in fact we need this change for correctness as well as performance. Because not setting
ip_summedtoCHECKSUM_PARTIALin netfront is not going to stop netback from sendingCHECKSUM_PARTIALpackets to us. If these packets are then routed/bridged back to netback, they'll have the wrong checksum.
OK, I've been sitting on this in the hope that I'll suddenly see the light and work out what you're talking about - but apparently that's not going to happen. So, some questions:
1. Does this patch change the dom0 <-> domU interface? or does it fix something that's currently broken?
2. Can just apply the netfront part to the pv_ops kernel, or does it require the corresponding dom0 patch to be applied as well?
Thanks,
J
Re: [PATCH 22/25] xen: xen-netfront: use skb.cb for storing private data
Quoted 7 lines · Jeremy Fitzhardinge
OK, I've been sitting on this in the hope that I'll suddenly see the light and work out what you're talking about - but apparently that's not going to happen. So, some questions:
1. Does this patch change the dom0 <-> domU interface? or does it fix something that's currently broken?
No it doesn't change the interface at all.
Quoted 2 lines
2. Can just apply the netfront part to the
pv_opskernel, or does it require the corresponding dom0 patch to be applied as well?
They can be applied separately so you don't need the dom0 part for your tree.
Cheers,
Signature · 4 lines
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <[email protected]>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txtRe: [PATCH 22/25] xen: xen-netfront: use skb.cb for storing private data
Quoted 2 lines · Herbert Xu
They can be applied separately so you don't need the dom0 part for your tree.
Great, thanks.
J
Re: [PATCH 22/25] xen: xen-netfront: use skb.cb for storing private data
Quoted 5 lines · Jeremy Fitzhardinge
Quoted 2 lines · Herbert Xu
They can be applied separately so you don't need the dom0 part for your tree.
Great, thanks.
BTW, the version I posted to you is missing the following line.
Cheers,
Signature · 15 lines
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <[email protected]>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
--
--- linux-2.6.20.i386/drivers/xen/core/skbuff.c 2007-04-28 15:30:16.000000000 +1000
+++ build-2.6.20.i386/drivers/xen/core/skbuff.c 2007-04-28 15:30:52.000000000 +1000
@@ -89,6 +89,7 @@
skb->h.raw = (unsigned char *)skb->nh.iph + 4*skb->nh.iph->ihl;
if (skb->h.raw >= skb->tail)
goto out;
+ skb->csum_start = skb->h.raw - skb->head;
switch (skb->nh.iph->protocol) {
case IPPROTO_TCP:
skb->csum_offset = offsetof(struct tcphdr, check);Re: [PATCH 22/25] xen: xen-netfront: use skb.cb for storing private data
drivers/xen/core/skbuff.c line 95
Quoted 13 lines · Herbert Xu
BTW, the version I posted to you is missing the following line.
drivers/xen/core/skbuff.c +1
-0@@ -89,6 +89,7 @@ skb->h.raw = (unsigned char *)skb->nh.iph +4 *skb->nh.iph->ihl;if (skb->h.raw >= skb->tail) goto out; + skb->csum_start = skb->h.raw - skb->head;switch (skb->nh.iph->protocol) {case IPPROTO_TCP : skb->csum_offset = offsetof(struct tcphdr , check);
drivers/xen/core/skbuff.c? What's that?
J
Re: [PATCH 22/25] xen: xen-netfront: use skb.cb for storing private data
Quoted 16 lines · Jeremy Fitzhardinge
drivers/xen/core/skbuff.c line 95
Quoted 13 lines · Herbert Xu
BTW, the version I posted to you is missing the following line.
drivers/xen/core/skbuff.c +1
-0@@ -89,6 +89,7 @@ skb->h.raw = (unsigned char *)skb->nh.iph +4 *skb->nh.iph->ihl;if (skb->h.raw >= skb->tail) goto out; + skb->csum_start = skb->h.raw - skb->head;switch (skb->nh.iph->protocol) {case IPPROTO_TCP : skb->csum_offset = offsetof(struct tcphdr , check);
drivers/xen/core/skbuff.c? What's that?
It's part of the skb_checksum_setup function which we still need for this because the current netback protocol doesn't pass the csum_start and csum_offset values along.
Cheers,
Signature · 4 lines
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <[email protected]>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txtPATCH 23/25 xen: Lockdep fixes for xen-netfront
In reply to Jeremy Fitzhardingenetfront contains two locking problems found by lockdep:
1. rx_lock is a normal spinlock, and tx_lock is an irq spinlock. This means that in normal use, tx_lock may be taken by an interrupt routine while rx_lock is held. However, netif_disconnect_backend takes them in the order tx_lock->rx_lock, which could lead to a deadlock. Reverse them
2. rx_lock can also be taken in softirq context, so it should be taken/released with spin_(un)lock_bh.
--- drivers/net/xen-netfront.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-)
===================================================================
drivers/net/xen-netfront.c +15 -15
@@ -515,14 +515,14 @@ static int network_open(struct net_devicmemset (&np->stats,0 ,sizeof (np->stats)); -spin_lock (&np->rx_lock); +spin_lock_bh (&np->rx_lock);if (netfront_carrier_ok (np)) {network_alloc_rx_buffers (dev); np->rx.sring->rsp_event = np->rx.rsp_cons +1 ;if (RING_HAS_UNCONSUMED_RESPONSES (&np->rx))netif_rx_schedule (dev); } -spin_unlock (&np->rx_lock); +spin_unlock_bh (&np->rx_lock);network_maybe_wake_tx (dev);
@@ -1212,10 +1212,10 @@ static int netif_poll(struct net_deviceint pages_flipped =0 ;int err; -spin_lock (&np->rx_lock); +spin_lock_bh (&np->rx_lock);if (unlikely (!netfront_carrier_ok (np))) { -spin_unlock (&np->rx_lock); +spin_unlock_bh (&np->rx_lock);return 0 ; }
@@ -1356,7 +1356,7 @@ err:local_irq_restore (flags); } -spin_unlock (&np->rx_lock); +spin_unlock_bh (&np->rx_lock);return more_to_do; }
@@ -1399,7 +1399,7 @@ static void netif_release_rx_bufs(structskb_queue_head_init (&free_list); -spin_lock (&np->rx_lock); +spin_lock_bh (&np->rx_lock);for (id =0 ; id <NET_RX_RING_SIZE ; id++) {if ((ref = np->grant_rx_ref[id]) ==GRANT_INVALID_REF ) {
@@ -1469,7 +1469,7 @@ static void netif_release_rx_bufs(structwhile ((skb =__skb_dequeue (&free_list)) !=NULL )dev_kfree_skb (skb); -spin_unlock (&np->rx_lock); +spin_unlock_bh (&np->rx_lock); }static int network_close (struct net_device *dev)
@@ -1579,8 +1579,8 @@ static int network_connect(struct net_dedev_info (&dev->dev,"has %sing receive path.\n" , np->copying_receiver ?"copy" :"flipp" ); +spin_lock_bh (&np->rx_lock);spin_lock_irq (&np->tx_lock); -spin_lock (&np->rx_lock);/* * Recovery procedure:
@@ -1632,8 +1632,8 @@ static int network_connect(struct net_denetwork_tx_buf_gc (dev);network_alloc_rx_buffers (dev); -spin_unlock (&np->rx_lock);spin_unlock_irq (&np->tx_lock); +spin_unlock_bh (&np->rx_lock);return 0 ; }
@@ -1689,7 +1689,7 @@ static ssize_t store_rxbuf_min(struct deif (target >RX_MAX_TARGET ) target =RX_MAX_TARGET ; -spin_lock (&np->rx_lock); +spin_lock_bh (&np->rx_lock);if (target > np->rx_max_target) np->rx_max_target = target; np->rx_min_target = target;
@@ -1698,7 +1698,7 @@ static ssize_t store_rxbuf_min(struct denetwork_alloc_rx_buffers (netdev); -spin_unlock (&np->rx_lock); +spin_unlock_bh (&np->rx_lock);return len; }
@@ -1732,7 +1732,7 @@ static ssize_t store_rxbuf_max(struct deif (target >RX_MAX_TARGET ) target =RX_MAX_TARGET ; -spin_lock (&np->rx_lock); +spin_lock_bh (&np->rx_lock);if (target < np->rx_min_target) np->rx_min_target = target; np->rx_max_target = target;
@@ -1741,7 +1741,7 @@ static ssize_t store_rxbuf_max(struct denetwork_alloc_rx_buffers (netdev); -spin_unlock (&np->rx_lock); +spin_unlock_bh (&np->rx_lock);return len; }
@@ -1885,11 +1885,11 @@ static void netif_disconnect_backend(strstatic void netif_disconnect_backend (struct netfront_info *info) {/* Stop old i/f to prevent errors whilst we rebuild the state. */ +spin_lock_bh (&info->rx_lock);spin_lock_irq (&info->tx_lock); -spin_lock (&info->rx_lock);netfront_carrier_off (info); -spin_unlock (&info->rx_lock);spin_unlock_irq (&info->tx_lock); +spin_unlock_bh (&info->rx_lock);if (info->irq)unbind_from_irqhandler (info->irq, info->netdev);
Re: [PATCH 23/25] xen: Lockdep fixes for xen-netfront
drivers/net/xen-netfront.c static int netif_poll(struct net_device · line 1218
Quoted 11 lines · Jeremy Fitzhardinge
drivers/net/xen-netfront.c +2
-2@@ -1212,10 +1212,10 @@ static int netif_poll(struct net_deviceint pages_flipped =0 ;int err; -spin_lock (&np->rx_lock); +spin_lock_bh (&np->rx_lock);if (unlikely (!netfront_carrier_ok (np))) { -spin_unlock (&np->rx_lock); +spin_unlock_bh (&np->rx_lock);
You don't need to disable BH in netif_poll since it's always called with BH disabled.
Cheers,
Signature · 4 lines
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <[email protected]>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txtRe: [PATCH 23/25] xen: Lockdep fixes for xen-netfront
Quoted 3 lines · Herbert Xu
You don't need to disable BH in
netif_pollsince it's always called with BH disabled.
Ah, yes, you mentioned that before. I'll fix it up.
J
PATCH 24/25 xen: xen: diddle netfront
In reply to Jeremy FitzhardingeMove things around a bit to match xen-unstable netfront.
--- drivers/net/xen-netfront.c | 36 +++++++++++++++++------------------- 1 file changed, 17 insertions(+), 19 deletions(-)
===================================================================
drivers/net/xen-netfront.c +17 -19
@@ -750,19 +750,6 @@ no_skb:notify_remote_via_irq (np->irq); } -static void xennet_move_rx_slot (struct netfront_info *np,struct sk_buff *skb, -grant_ref_t ref) -{ -int new =xennet_rxidx (np->rx.req_prod_pvt); - -BUG_ON (np->rx_skbs[new]); - np->rx_skbs[new] = skb; - np->grant_rx_ref[new] = ref; -RING_GET_REQUEST (&np->rx, np->rx.req_prod_pvt)->id = new; -RING_GET_REQUEST (&np->rx, np->rx.req_prod_pvt)->gref = ref; - np->rx.req_prod_pvt++; -} -static void xennet_make_frags (struct sk_buff *skb,struct net_device *dev,struct netif_tx_request *tx) {
@@ -944,6 +931,19 @@ static irqreturn_t netif_int(int irq, vospin_unlock_irqrestore (&np->tx_lock, flags);return IRQ_HANDLED ; +} + +static void xennet_move_rx_slot (struct netfront_info *np,struct sk_buff *skb, +grant_ref_t ref) +{ +int new =xennet_rxidx (np->rx.req_prod_pvt); + +BUG_ON (np->rx_skbs[new]); + np->rx_skbs[new] = skb; + np->grant_rx_ref[new] = ref; +RING_GET_REQUEST (&np->rx, np->rx.req_prod_pvt)->id = new; +RING_GET_REQUEST (&np->rx, np->rx.req_prod_pvt)->gref = ref; + np->rx.req_prod_pvt++; }static void handle_incoming_queue (struct net_device *dev,struct sk_buff_head *rxq)
@@ -1169,7 +1169,8 @@ static RING_IDX xennet_fill_frags(structreturn cons; } -static int xennet_set_skb_gso (struct sk_buff *skb,struct netif_extra_info *gso) +static int xennet_set_skb_gso (struct sk_buff *skb, +struct netif_extra_info *gso) {if (!gso->u.gso.size) {if (net_ratelimit ())
@@ -1456,11 +1457,8 @@ static void netif_release_rx_bufs(structif (!xen_feature (XENFEAT_auto_translated_physmap)) {/* Do all the remapping work and M2P updates. */ - mcl->op = __HYPERVISOR_mmu_update; - mcl->args[0 ] = (unsigned long )np->rx_mmu; - mcl->args[1 ] = mmu - np->rx_mmu; - mcl->args[2 ] =0 ; - mcl->args[3 ] =DOMID_SELF ; +MULTI_mmu_update (mcl, np->rx_mmu, mmu - np->rx_mmu, +0 ,DOMID_SELF ); mcl++;HYPERVISOR_multicall (np->rx_mcl, mcl - np->rx_mcl); }
PATCH 25/25 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)
Quoted 4 lines · On Monday 23 April 2007 23:56:38 Jeremy Fitzhardinge wrote:
Hi Andi,
It applies to 2.6.21-rc7 + your patches + the last batch of
pv_opspatches
I got most of those except for the broken sched_clock change.
Quoted 1 line
I posted.
How much testing outside Jeremylabs has it gotten? Some beta testing before merging would be good, otherwise we'll just have a flood of fixes shortly when it is exposed to users.
Quoted 2 lines
This patch generally restricts itself to Xen-specific parts of the tree, though it does make a few small changes elsewhere.
The general problem is that it is much more than just an architecture update.
Quoted 2 lines
These patches include:
- some helper routines for allocating address space and walking pagetables
Needs review from mm people.
Quoted 3 lines
- Xen interface header files
- Core Xen implementation
- Efficient late-pinning/early-unpinning pagetable handling
The number of new paravirt hooks makes me thing of renaming it to everything_ops @|
Quoted 1 line
- Virtualized time, including stolen time
Can you let it be reviewed by the time people? (Thomas, Ingo, John, Roman etc.)
Quoted 6 lines
- SMP support
- Preemption support
- Batched pagetable updates- Xen console, based on hvc console
- Xenbus
That one would need to be reviewed first. It's so much code that I can't do it all myself.
Quoted 1 line
- Netfront, the paravirtualized network device
That one should go through the network device maintainer/netdev.
Quoted 1 line
- Blockfront, the paravirtualized block device
And that needs a block device review and whoever maintains that (Jens?)
-Andi
Quoted 10 lines · Andi Kleen
Quoted 5 lines · On Monday 23 April 2007 23:56:38 Jeremy Fitzhardinge wrote:
Hi Andi,
It applies to 2.6.21-rc7 + your patches + the last batch of
pv_opspatchesI got most of those except for the broken
sched_clockchange.
Er, we had a bit of back-and-forward with that. How did that end up?
Quoted 7 lines
Quoted 2 lines
I posted.
How much testing outside Jeremylabs has it gotten? Some beta testing before merging would be good, otherwise we'll just have a flood of fixes shortly when it is exposed to users.
Yes. I'm just prepping a tree for xen-devel, and I primed people at the Xen Summit last week.
Quoted 4 lines
Quoted 3 lines
This patch generally restricts itself to Xen-specific parts of the tree, though it does make a few small changes elsewhere.
Quoted 9 lines
The general problem is that it is much more than just an architecture update.
Quoted 3 lines
These patches include:
- some helper routines for allocating address space and walking pagetablesNeeds review from mm people.
These have been pretty well looked at already. They have been posted repeatedly, and I think all the comments have been sorted out. alloc_vm_area() will be a bit affected by Andrew's -mm patch to make vmalloc_sync_all a globally-visible arch export, but they merge nicely.
Quoted 8 lines
Quoted 4 lines
- Xen interface header files
- Core Xen implementation
- Efficient late-pinning/early-unpinning pagetable handlingThe number of new paravirt hooks makes me thing of renaming it to
everything_ops@|
There's only one new op in this series, and I couldn't work out a way to avoid it, other than putting a #ifdef CONFIG_XEN in kernel/setup.c. The last patch posting didn't add any new hooks. Which ones are you referring to?
Quoted 5 lines
Quoted 2 lines
- Virtualized time, including stolen time
Can you let it be reviewed by the time people? (Thomas, Ingo, John, Roman etc.)
Thomas has looked at and generally approves of the Xen clocksource/event code. The stolen time code is really only used to generate a few numbers in /proc, and so has very little direct impact on the rest of the kernel, and hasn't really attracted much interest as a result. I've posted the patch to implement sched_clock in terms of unstolen time to the various time people repeatedly, and nobody has responded, so I guess it doesn't irritate anyone too much; it would be nice to have some definite feedback though.
Quoted 7 lines
Quoted 3 lines
- Xen console, based on hvc console
- XenbusThat one would need to be reviewed first. It's so much code that I can't do it all myself.
I put a specific plea for GregKH to look at this.
Quoted 5 lines
Quoted 2 lines
- Netfront, the paravirtualized network device
That one should go through the network device maintainer/netdev.
Stephen Hemminger has looked at this in the past and we've addressed all his comments so far. But it would be nice to get some more net developers to review this; it was cc:d to netdev.
Quoted 5 lines
Quoted 2 lines
- Blockfront, the paravirtualized block device
And that needs a block device review and whoever maintains that (Jens?)
He was cc:d. I'll ask him specifically.
J