x86 paravirt_ops: create no_paravirt.h for native ops
Subsystems (2)
PATCH 1/4 x86 paravirt_ops: create no_paravirt.h for native ops
(Andrew, please sit these in the -mm tree for cooking)
Create a paravirt.h header for (almost) all the critical operations which need to be replaced with hypervisor calls.
For the moment, this simply includes no_paravirt.h, where all the native implementations now live.
===================================================================
arch/i386/kernel/entry.S +1 -7
@@ -49,6 +49,7 @@ #include <asm/page.h> #include <asm/desc.h> #include <asm/dwarf2.h> +#include <asm/paravirt.h> #include "irq_vectors.h" #define nr_syscalls ((syscall_table_size)/4)
@@ -75,13 +76,6 @@ DF_MASK = 0x00000400 DF_MASK = 0x00000400 NT_MASK = 0x00004000 VM_MASK = 0x00020000 - -/* These are replaces for paravirtualization */ -#define DISABLE_INTERRUPTS cli -#define ENABLE_INTERRUPTS sti -#define ENABLE_INTERRUPTS_SYSEXIT sti; sysexit -#define INTERRUPT_RETURN iret -#define GET_CR0_INTO_EAX movl %cr0, %eax #ifdef CONFIG_PREEMPT #define preempt_stop DISABLE_INTERRUPTS; TRACE_IRQS_OFF
===================================================================
include/asm-i386/irqflags.h +1 -63
81 lines not on this page · raw message
===================================================================
include/asm-i386/processor.h +1 -46
71 lines not on this page · raw message
===================================================================
include/asm-i386/segment.h +0 -1
@@ -121,5 +121,4 @@/* Bottom three bits of xcs give the ring privilege level */ #define SEGMENT_RPL_MASK 0x3 -#define get_kernel_rpl () 0#endif
===================================================================
include/asm-i386/spinlock.h +1 -3
@@ -5,6 +5,7 @@#include <asm/rwlock.h> #include <asm/page.h> #include <linux/compiler.h> +#include <asm/paravirt.h> /* * Your basic SMP spinlocks, allowing only a single CPU anywhere
@@ -16,9 +17,6 @@* * (the type definitions are in asm/spinlock_types.h) */ - -#define CLI_STRING "cli" -#define STI_STRING "sti"#define __raw_spin_is_locked (x) \ (*(volatile signed char *)(&(x)->slock) <= 0)
===================================================================
include/asm-i386/system.h +2 -58
75 lines not on this page · raw message
===================================================================
include/asm-i386/no_paravirt.h new file +189 -0
189 lines not on this page · raw message
===================================================================
include/asm-i386/paravirt.h new file +7 -0
@@ -0,0 +1,7 @@ +#ifndef __ASM_PARAVIRT_H +#define __ASM_PARAVIRT_H +/* Various instructions on x86 need to be replaced for +* para-virtualization: those hooks are defined here. */ +#include <asm/no_paravirt.h> + +#endif /* __ASM_PARAVIRT_H */
Signature · 1 line
Help! Save Australia from the worst of the DMCA: http://linux.org.au/law
PATCH 2/4 x86 paravirt_ops: paravirt_desc.h for native descriptor ops.
Unfortunately, due to include cycles, we can't put these in paravirt.h: we use a separate header for these.
The implementation comes from Zach's [RFC, PATCH 10/24] i386 Vmi descriptor changes:
Descriptor and trap table cleanups. Add cleanly written accessors for IDT and GDT gates so the subarch may override them. Note that this allows the hypervisor to transparently tweak the DPL of the descriptors as well as the RPL of segments in those descriptors, with no unnecessary kernel code modification. It also allows the hypervisor implementation of the VMI to tweak the gates, allowing for custom exception frames or extra layers of indirection above the guest fault / IRQ handlers.
===================================================================
arch/i386/kernel/traps.c +5 -19
@@ -1107,20 +1107,6 @@ void __init trap_init_f00f_bug(void) }#endif -#define _set_gate (gate_addr,type,dpl,addr,seg) \ -do { \ - int __d0, __d1; \ - __asm__ __volatile__ ("movw %%dx,%%ax\n\t" \ - "movw %4,%%dx\n\t" \ - "movl %%eax,%0\n\t" \ - "movl %%edx,%1" \ - :"=m" (*((long *) (gate_addr))), \ - "=m" (*(1+(long *) (gate_addr))), "=&a" (__d0), "=&d" (__d1) \ - :"i" ((short) (0x8000+(dpl<<13)+(type<<8))), \ - "3" ((char *) (addr)),"2" ((seg) << 16)); \ -} while (0) - -/* * This needs to use 'idt_table' rather than 'idt', and * thus use the _nonmapped_ version of the IDT, as the
@@ -1129,7 +1115,7 @@ do { \*/ void set_intr_gate (unsigned int n,void *addr) { -_set_gate (idt_table+n,14 ,0 ,addr,__KERNEL_CS); +_set_gate (n,DESCTYPE_INT , addr, __KERNEL_CS); }/*
@@ -1137,22 +1123,22 @@ void set_intr_gate(unsigned int n, void*/ static inline void set_system_intr_gate (unsigned int n,void *addr) { -_set_gate (idt_table+n,14 ,3 , addr, __KERNEL_CS); +_set_gate (n,DESCTYPE_INT |DESCTYPE_DPL3 , addr, __KERNEL_CS); }static void __init set_trap_gate (unsigned int n,void *addr) { -_set_gate (idt_table+n,15 ,0 ,addr,__KERNEL_CS); +_set_gate (n,DESCTYPE_TRAP , addr, __KERNEL_CS); }static void __init set_system_gate (unsigned int n,void *addr) { -_set_gate (idt_table+n,15 ,3 ,addr,__KERNEL_CS); +_set_gate (n,DESCTYPE_TRAP |DESCTYPE_DPL3 , addr, __KERNEL_CS); }static void __init set_task_gate (unsigned int n,unsigned int gdt_entry) { -_set_gate (idt_table+n,5 ,0 ,0 ,(gdt_entry<<3 )); +_set_gate (n,DESCTYPE_TASK , (void *)0 , (gdt_entry<<3 )); }
===================================================================
include/asm-i386/desc.h +45 -47
119 lines not on this page · raw message
===================================================================
include/asm-i386/no_paravirt_desc.h new file +41 -0
41 lines not on this page · raw message
===================================================================
include/asm-i386/paravirt_desc.h new file +6 -0
@@ -0,0 +1,6 @@ +#ifndef __ASM_PARAVIRT_DESC_H +#define __ASM_PARAVIRT_DESC_H +/* A separate header because they need processor.h, which needs paravirt.h */ +#include <asm/no_paravirt_desc.h> + +#endif /* __ASM_PARAVIRT_DESC_H */
Signature · 1 line
Help! Save Australia from the worst of the DMCA: http://linux.org.au/law
PATCH 3/4 x86 paravirt_ops: implementation of paravirt_ops
This patch does the dumbest possible replacement of paravirtualized
instructions: calls through a "paravirt_ops" structure. Currently these are function implementations of native hardware: hypervisors will override the ops structure with their own variants.
All the pv-ops functions are declared "fastcall" so that a specific register-based ABI is used, to make inlining assember easier.
--- arch/i386/Kconfig | 11 + arch/i386/kernel/Makefile | 1 arch/i386/kernel/asm-offsets.c | 8 arch/i386/kernel/entry.S | 9 arch/i386/kernel/paravirt.c | 392 ++++++++++++++++++++++++++++++++++++++ include/asm-i386/msr.h | 5 include/asm-i386/paravirt.h | 226 +++++++++++++++++++++ include/asm-i386/paravirt_desc.h | 5 8 files changed, 657 insertions(+)
===================================================================
arch/i386/Kconfig +11 -0
@@ -180,6 +180,17 @@ config X86_ES7000 should say N here. endchoice + +config PARAVIRT + bool "Paravirtualization support (EXPERIMENTAL)" + depends on EXPERIMENTAL + help + Paravirtualization is a way of running multiple instances of + Linux on the same machine, under a hypervisor. This option + changes the kernel so it can modify itself when it is run + under a hypervisor, improving performance significantly. + However, when run without a hypervisor the kernel is + theoretically slower. If in doubt, say N. config ACPI_SRAT bool
===================================================================
arch/i386/kernel/Makefile +1 -0
@@ -40,6 +40,7 @@ obj-$(CONFIG_HPET_TIMER) += hpet.o obj-$(CONFIG_HPET_TIMER) += hpet.o obj-$(CONFIG_K8_NB) += k8.o obj-$(CONFIG_AUDIT) += audit.o +obj-$(CONFIG_PARAVIRT) += paravirt.o EXTRA_AFLAGS := -traditional
===================================================================
arch/i386/kernel/asm-offsets.c +8 -0
@@ -15,6 +15,7 @@#include <asm/processor.h> #include <asm/thread_info.h> #include <asm/elf.h> +#include <asm/paravirt.h> #define DEFINE (sym, val) \ asm volatile("\n->" #sym " %0 " #val : : "i" (val))
@@ -74,4 +75,11 @@ void foo(void)DEFINE (VDSO_PRELINK ,VDSO_PRELINK );OFFSET (crypto_tfm_ctx_offset, crypto_tfm, __crt_ctx); +#ifdef CONFIG_PARAVIRT +OFFSET (PARAVIRT_irq_disable, paravirt_ops, irq_disable); +OFFSET (PARAVIRT_irq_enable, paravirt_ops, irq_enable); +OFFSET (PARAVIRT_irq_enable_sysexit, paravirt_ops, irq_enable_sysexit); +OFFSET (PARAVIRT_iret, paravirt_ops, iret); +OFFSET (PARAVIRT_read_cr0, paravirt_ops, read_cr0); +#endif }
===================================================================
arch/i386/kernel/entry.S +9 -0
@@ -803,6 +803,15 @@ 1: INTERRUPT_RETURN .long 1b,iret_exc .previous +#ifdef CONFIG_PARAVIRT +ENTRY(nopara_iret) + iret + +ENTRY(nopara_irq_enable_sysexit) + sti + sysexit +#endif + KPROBE_ENTRY(int3) RING0_INT_FRAME pushl $-1 # mark this as an int
===================================================================
include/asm-i386/msr.h +5 -0
@@ -1,5 +1,9 @@#ifndef __ASM_MSR_H#define __ASM_MSR_H + +#ifdef CONFIG_PARAVIRT +#include <asm/paravirt.h> +#else /* * Access to machine-specific registers (available on 586 and better only)
@@ -77,6 +81,7 @@ static inline void wrmsrl (unsigned long __asm__ __volatile__("rdpmc" \ :"=a" (low),"=d" (high) \ : "c" (counter)) +#endif /* !CONFIG_PARAVIRT */ /* symbolic names for some interesting MSRs */ /* Intel defined MSRs. */
===================================================================
include/asm-i386/paravirt.h +226 -0
232 lines not on this page · raw message
===================================================================
include/asm-i386/paravirt_desc.h +4 -0
@@ -1,6 +1,10 @@#ifndef __ASM_PARAVIRT_DESC_H#define __ASM_PARAVIRT_DESC_H/* A separate header because they need processor.h, which needs paravirt.h */ +#ifndef CONFIG_PARAVIRT #include <asm/no_paravirt_desc.h> +#else +#include <asm/paravirt.h> +#endif #endif /* __ASM_PARAVIRT_DESC_H */
===================================================================
arch/i386/kernel/paravirt.c new file +382 -0
382 lines not on this page · raw message
Signature · 1 line
Help! Save Australia from the worst of the DMCA: http://linux.org.au/law
PATCH 4/4 x86 paravirt_ops: binary patching infrastructure
It turns out that the most called ops, by several orders of magnitude, are the interrupt manipulation ops. These are obvious candidates for patching, so mark them up and create infrastructure for it.
The method used is that the ops structure has a patch function, which is called for each place which needs to be patched: this returns a number of instructions (the rest are NOP-padded).
===================================================================
arch/i386/kernel/alternative.c +36 -1
@@ -3,6 +3,7 @@#include <linux/list.h> #include <asm/alternative.h> #include <asm/sections.h> +#include <asm/paravirt.h> static int no_replacement =0 ;static int smp_alt_once =0 ;
@@ -342,6 +343,38 @@ void alternatives_smp_switch(int smp)#endif +#ifdef CONFIG_PARAVIRT +void apply_paravirt (struct paravirt_patch *start,struct paravirt_patch *end) +{ +unsigned char **noptable =find_nop_table (); +struct paravirt_patch *p; +int diff, i, k; + +local_irq_disable (); +for (p = start; p < end; p++) { +unsigned int used; + used = paravirt_ops.patch (p->instrtype, p->instr, p->len); +/* Pad the rest with nops */ + diff = p->len - used; +for (i = used; diff >0 ; diff -= k, i += k) { + k = diff; +if (k >ASM_NOP_MAX ) + k =ASM_NOP_MAX ; +memcpy (p->instr + i, noptable[k], k); + } + } +sync_core (); +local_irq_enable (); +} +extern struct paravirt_patch __start_parainstructions[], + __stop_parainstructions[]; +#else +void apply_paravirt (struct paravirt_patch *start,struct paravirt_patch *end) +{ +} +extern char __start_parainstructions[], __stop_parainstructions[]; +#endif /* CONFIG_PARAVIRT */ +void __init alternative_instructions (void ) {if (no_replacement) {
@@ -386,4 +419,6 @@ void __init alternative_instructions(voi alternatives_smp_switch(0); }#endif -} + +apply_paravirt (__start_parainstructions, __stop_parainstructions); +}
===================================================================
arch/i386/kernel/module.c +8 -1
@@ -108,7 +108,8 @@ int module_finalize(const Elf_Ehdr *hdr,const Elf_Shdr *sechdrs, struct module *me) { - const Elf_Shdr *s, *text = NULL, *alt = NULL, *locks = NULL; + const Elf_Shdr *s, *text = NULL, *alt = NULL, *locks = NULL, + *para =NULL ;char *secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;for (s = sechdrs; s < sechdrs + hdr->e_shnum; s++) {
@@ -118,6 +119,8 @@ int module_finalize(const Elf_Ehdr *hdr, alt = s;if (!strcmp (".smp_locks" , secstrings + s->sh_name)) locks= s; +if (!strcmp (".parainstructions" , secstrings + s->sh_name)) + para = s; }if (alt) {
@@ -132,6 +135,10 @@ int module_finalize(const Elf_Ehdr *hdr, lseg, lseg + locks->sh_size, tseg, tseg + text->sh_size); } +if (para) { +void *aseg = (void *)alt->sh_addr; +apply_paravirt (aseg, aseg + alt->sh_size); + }return 0 ; }
===================================================================
arch/i386/kernel/paravirt.c +45 -0
53 lines not on this page · raw message
===================================================================
arch/i386/kernel/vmlinux.lds.S +6 -0
@@ -150,6 +150,12 @@ SECTIONS .altinstr_replacement : AT(ADDR(.altinstr_replacement) - LOAD_OFFSET) { *(.altinstr_replacement) } + . = ALIGN(4); + __start_parainstructions = .; + .parainstructions : AT(ADDR(.parainstructions) - LOAD_OFFSET) { + *(.parainstructions) + } + __stop_parainstructions = .; /* .exit.text is discard at runtime, not link time, to deal with references from .altinstructions and .eh_frame */ .exit.text : AT(ADDR(.exit.text) - LOAD_OFFSET) { *(.exit.text) }
===================================================================
include/asm-i386/alternative.h +3 -0
@@ -138,4 +138,7 @@ static inline void alternatives_smp_swit#define LOCK_PREFIX ""#endif +struct paravirt_patch ; +void apply_paravirt (struct paravirt_patch *start,struct paravirt_patch *end); +#endif /* _I386_ALTERNATIVE_H */
===================================================================
include/asm-i386/paravirt.h +90 -29
150 lines not on this page · raw message
Signature · 1 line
Help! Save Australia from the worst of the DMCA: http://linux.org.au/law
Re: [PATCH 4/4] x86 paravirt_ops: binary patching infrastructure
And a trivial warning fix on that last one when !CONFIG_PARAVIRT.
struct paravirt_patch is only defined for CONFIG_PARAVIRT, so we declare the (unused) __start and __stop section markers as char, which causes a warning when we pass them to the dummy apply_paravirt.
arch/i386/kernel/alternative.c renamed from arch/i386/kernel/alternative.c.~1~ +1 -1
@@ -369,7 +369,7 @@extern struct paravirt_patch __start_parainstructions[], __stop_parainstructions[];#else -void apply_paravirt (struct paravirt_patch *start,struct paravirt_patch *end) +void apply_paravirt (void *start,void *end) { }extern char __start_parainstructions[], __stop_parainstructions[];
Signature · 1 line
Help! Save Australia from the worst of the DMCA: http://linux.org.au/law
Re: [PATCH 4/4] x86 paravirt_ops: binary patching infrastructure
In reply to Rusty RussellReview
Quoted 3 lines · Rusty Russell
(quoted diff) +2
-0+#ifdef CONFIG_PARAVIRT +void apply_paravirt(struct paravirt_patch *start, struct paravirt_patch *end)
It would be better to merge this with the existing LOCK prefix patching or perhaps the normal alternative() patcher (is there any particular reason you can't use it?)
Three alternative patching mechanisms just seems to be too many
-Andi
Re: [PATCH 4/4] x86 paravirt_ops: binary patching infrastructure
Quoted 10 lines · Andi Kleen
Review
Quoted 4 lines
(quoted diff) +2
-0+#ifdef CONFIG_PARAVIRT +void apply_paravirt(struct paravirt_patch *start, struct paravirt_patch *end)It would be better to merge this with the existing LOCK prefix patching or perhaps the normal
alternative()patcher (is there any particular reason you can't use it?)Three alternative patching mechanisms just seems to be too many
The difference is that every hypervisor wants its own patched instruction sequence, which may require a specialized patching mechanism. If you're simply patching in calls, then it isn't a big deal, but you may also want to patch in real inlined code for some operations (like sti/cli equivalents). The alternatives are to allow each backend to deal with its own patching (perhaps with common functions abstracted out as they appear), or have a common set of patching machinery which can deal with all users. The former seems simpler.
J
Re: [PATCH 3/4] x86 paravirt_ops: implementation of paravirt_ops
In reply to Rusty RussellQuoted 4 lines · Rusty Russell
This patch does the dumbest possible replacement of paravirtualized
instructions: calls through a "paravirt_ops" structure. Currently these are function implementations of native hardware: hypervisors will override the ops structure with their own variants.
You should call it HAL - that would make it clearer what it is.
I think I would prefer to patch always. Is there a particular reason you can't do that?
-Andi
Re: [PATCH 3/4] x86 paravirt_ops: implementation of paravirt_ops
Quoted 10 lines · Andi Kleen
Quoted 5 lines · Rusty Russell
This patch does the dumbest possible replacement of paravirtualized
instructions: calls through a "paravirt_ops" structure. Currently these are function implementations of native hardware: hypervisors will override the ops structure with their own variants.You should call it HAL - that would make it clearer what it is.
I've always found the term "HAL" to be vague to the point of meaningless. What would it mean in this case: "hypervisor abstraction layer"? It certainly doesn't attempt abstract all hardware.
Quoted 3 lines
I think I would prefer to patch always. Is there a particular reason you can't do that?
Some calls just don't need patching; an indirect call is fast enough, and simple. But I can't think of a good reason to not patch patchable calls, other than for debugging perhaps (easier to place one breakpoint than one per inline site).
J
Re: [PATCH 3/4] x86 paravirt_ops: implementation of paravirt_ops
In reply to Andi KleenQuoted 7 lines · Andi Kleen
Quoted 4 lines · Rusty Russell
This patch does the dumbest possible replacement of paravirtualized
instructions: calls through a "paravirt_ops" structure. Currently these are function implementations of native hardware: hypervisors will override the ops structure with their own variants.You should call it HAL - that would make it clearer what it is.
People get visions of grandeur when HAL is mentioned: they think it'll abstract everything. I really only want to do the minimum needed for the hypervisors we have on the table today.
Maybe one day it will abstract everything, then we can call it a HAL. But I won't be doing that work 8)
Quoted 2 lines
I think I would prefer to patch always. Is there a particular reason you can't do that?
We could patch all the indirect calls into direct calls, but I don't think it's worth bothering: most simply don't matter.
The implementation ensures that someone can get boot on a new hypervisor by populating the ops struct. Later they can go back and implement the patching stuff.
Quoted 5 lines
It would be better to merge this with the existing LOCK prefix patching or perhaps the normal
alternative()patcher (is there any particular reason you can't use it?)Three alternative patching mechanisms just seems to be too many
Each backend wants a different patch, so alternative() doesn't cut it. We could look at generalizing alternative() I guess, but it works fine so I didn't want to touch it.
Rusty.
Signature · 1 line
Help! Save Australia from the worst of the DMCA: http://linux.org.au/law
Re: [PATCH 3/4] x86 paravirt_ops: implementation of paravirt_ops
Quoted 6 lines
Quoted 3 lines
I think I would prefer to patch always. Is there a particular reason you can't do that?
We could patch all the indirect calls into direct calls, but I don't think it's worth bothering: most simply don't matter.
I still think it would be better to patch always.
Quoted 3 lines
Each backend wants a different patch, so
alternative()doesn't cut it. We could look at generalizingalternative()I guess, but it works fine so I didn't want to touch it.
You could at least use a common function (with the replacement passed in as argument) for lock prefixes and your stuff
-Andi
Re: [PATCH 3/4] x86 paravirt_ops: implementation of paravirt_ops
Quoted 7 lines · Andi Kleen
Quoted 5 lines
Quoted 2 lines
I think I would prefer to patch always. Is there a particular reason you can't do that?
We could patch all the indirect calls into direct calls, but I don't think it's worth bothering: most simply don't matter.
I still think it would be better to patch always.
Actually, I just figured out a neat way to do this without having to handle all the cases by hand. I'll try it and get back to you...
Quoted 6 lines
Quoted 3 lines
Each backend wants a different patch, so
alternative()doesn't cut it. We could look at generalizingalternative()I guess, but it works fine so I didn't want to touch it.You could at least use a common function (with the replacement passed in as argument) for lock prefixes and your stuff
I don't want to rule out patching based on location (reg lifetime etc), but there's definitely room for combining these two. Good point.
Thanks!
Rusty.
Signature · 1 line
Help! Save Australia from the worst of the DMCA: http://linux.org.au/law
Re: [PATCH 2/4] x86 paravirt_ops: paravirt_desc.h for native descriptor ops.
In reply to Rusty RussellQuoted 5 lines · Rusty Russell
Unfortunately, due to include cycles, we can't put these in
paravirt.h: we use a separate header for these.The implementation comes from Zach's [RFC, PATCH 10/24] i386 Vmi descriptor changes:
Quoted 7 lines
Descriptor and trap table cleanups. Add cleanly written accessors for IDT and GDT gates so the subarch may override them. Note that this allows the hypervisor to transparently tweak the DPL of the descriptors as well as the RPL of segments in those descriptors, with no unnecessary kernel code modification. It also allows the hypervisor implementation of the VMI to tweak the gates, allowing for custom exception frames or extra layers of indirection above the guest fault / IRQ handlers.
Nice cleanup. The old assembly mess was ripe to be killed for a long time.
-Andi
Re: [PATCH 2/4] x86 paravirt_ops: paravirt_desc.h for native descriptor ops.
Quoted 14 lines · Andi Kleen
Quoted 5 lines · Rusty Russell
Unfortunately, due to include cycles, we can't put these in
paravirt.h: we use a separate header for these.The implementation comes from Zach's [RFC, PATCH 10/24] i386 Vmi descriptor changes:
Quoted 7 lines
Descriptor and trap table cleanups. Add cleanly written accessors for IDT and GDT gates so the subarch may override them. Note that this allows the hypervisor to transparently tweak the DPL of the descriptors as well as the RPL of segments in those descriptors, with no unnecessary kernel code modification. It also allows the hypervisor implementation of the VMI to tweak the gates, allowing for custom exception frames or extra layers of indirection above the guest fault / IRQ handlers.
Quoted 1 line
Nice cleanup. The old assembly mess was ripe to be killed for a long time.
OK, here's that patch extracted out.
Thanks!
Rusty.
Subject: Descriptor and trap table cleanups.
The implementation comes from Zach's [RFC, PATCH 10/24] i386 Vmi descriptor changes:
Descriptor and trap table cleanups. Add cleanly written accessors for IDT and GDT gates so the subarch may override them. Note that this allows the hypervisor to transparently tweak the DPL of the descriptors as well as the RPL of segments in those descriptors, with no unnecessary kernel code modification. It also allows the hypervisor implementation of the VMI to tweak the gates, allowing for custom exception frames or extra layers of indirection above the guest fault / IRQ handlers.
===================================================================
arch/i386/kernel/traps.c +5 -19
@@ -1112,20 +1112,6 @@ void __init trap_init_f00f_bug(void) }#endif -#define _set_gate (gate_addr,type,dpl,addr,seg) \ -do { \ - int __d0, __d1; \ - __asm__ __volatile__ ("movw %%dx,%%ax\n\t" \ - "movw %4,%%dx\n\t" \ - "movl %%eax,%0\n\t" \ - "movl %%edx,%1" \ - :"=m" (*((long *) (gate_addr))), \ - "=m" (*(1+(long *) (gate_addr))), "=&a" (__d0), "=&d" (__d1) \ - :"i" ((short) (0x8000+(dpl<<13)+(type<<8))), \ - "3" ((char *) (addr)),"2" ((seg) << 16)); \ -} while (0) - -/* * This needs to use 'idt_table' rather than 'idt', and * thus use the _nonmapped_ version of the IDT, as the
@@ -1134,7 +1120,7 @@ do { \*/ void set_intr_gate (unsigned int n,void *addr) { -_set_gate (idt_table+n,14 ,0 ,addr,__KERNEL_CS); +_set_gate (n,DESCTYPE_INT , addr, __KERNEL_CS); }/*
@@ -1142,22 +1128,22 @@ void set_intr_gate(unsigned int n, void*/ static inline void set_system_intr_gate (unsigned int n,void *addr) { -_set_gate (idt_table+n,14 ,3 , addr, __KERNEL_CS); +_set_gate (n,DESCTYPE_INT |DESCTYPE_DPL3 , addr, __KERNEL_CS); }static void __init set_trap_gate (unsigned int n,void *addr) { -_set_gate (idt_table+n,15 ,0 ,addr,__KERNEL_CS); +_set_gate (n,DESCTYPE_TRAP , addr, __KERNEL_CS); }static void __init set_system_gate (unsigned int n,void *addr) { -_set_gate (idt_table+n,15 ,3 ,addr,__KERNEL_CS); +_set_gate (n,DESCTYPE_TRAP |DESCTYPE_DPL3 , addr, __KERNEL_CS); }static void __init set_task_gate (unsigned int n,unsigned int gdt_entry) { -_set_gate (idt_table+n,5 ,0 ,0 ,(gdt_entry<<3 )); +_set_gate (n,DESCTYPE_TASK , (void *)0 , (gdt_entry<<3 )); }
===================================================================
include/asm-i386/desc.h +82 -51
155 lines not on this page · raw message
Signature · 1 line
Help! Save Australia from the worst of the DMCA: http://linux.org.au/law
Re: [PATCH 2/4] x86 paravirt_ops: paravirt_desc.h for native descriptor ops.
Quoted 15 lines · Rusty Russell
Quoted 14 lines · Andi Kleen
Quoted 12 lines · Rusty Russell
Unfortunately, due to include cycles, we can't put these in
paravirt.h: we use a separate header for these.The implementation comes from Zach's [RFC, PATCH 10/24] i386 Vmi descriptor changes:
Descriptor and trap table cleanups. Add cleanly written accessors for IDT and GDT gates so the subarch may override them. Note that this allows the hypervisor to transparently tweak the DPL of the descriptors as well as the RPL of segments in those descriptors, with no unnecessary kernel code modification. It also allows the hypervisor implementation of the VMI to tweak the gates, allowing for custom exception frames or extra layers of indirection above the guest fault / IRQ handlers.
Quoted 3 lines
Quoted 1 line
Nice cleanup. The old assembly mess was ripe to be killed for a long time.
OK, here's that patch extracted out.
Is there something wrong with your mailer? This one doesn't apply either:
Applying patch patches/paravirt_desc.h-for-native patching file arch/i386/kernel/traps.c
Hunk #1 FAILED at 1112.
1 out of 1 hunk FAILED -- rejects in file arch/i386/kernel/traps.c missing header for unified diff at line 78 of patch can't find file to patch at input line 78
Perhaps you used the wrong -p or --strip option?
The text leading up to this was:
--------------------------
| * thus use the _nonmapped_ version of the IDT, as the
--------------------------
No file to patch. Skipping patch.
1 out of 1 hunk ignored
missing header for unified diff at line 88 of patch can't find file to patch at input line 88
Perhaps you used the wrong -p or --strip option?
The text leading up to this was:
--------------------------
| /*
--------------------------
-Andi
Re: [PATCH 2/4] x86 paravirt_ops: paravirt_desc.h for native descriptor ops.
Quoted 16 lines · Andi Kleen
Quoted 15 lines · Rusty Russell
Quoted 14 lines · Andi Kleen
Quoted 12 lines · Rusty Russell
Unfortunately, due to include cycles, we can't put these in
paravirt.h: we use a separate header for these.The implementation comes from Zach's [RFC, PATCH 10/24] i386 Vmi descriptor changes:
Descriptor and trap table cleanups. Add cleanly written accessors for IDT and GDT gates so the subarch may override them. Note that this allows the hypervisor to transparently tweak the DPL of the descriptors as well as the RPL of segments in those descriptors, with no unnecessary kernel code modification. It also allows the hypervisor implementation of the VMI to tweak the gates, allowing for custom exception frames or extra layers of indirection above the guest fault / IRQ handlers.
Quoted 5 lines
Quoted 3 lines
Quoted 1 line
Nice cleanup. The old assembly mess was ripe to be killed for a long time.
OK, here's that patch extracted out.
Is there something wrong with your mailer? This one doesn't apply either:
Looks like it's against Linus' tree, not whatever you were trying against...
(13:19:10:davej@nwo:linux-2.6)$ cat ~/rusty | patch -p1 --dry-run patching file arch/i386/kernel/traps.c Hunk #1 succeeded at 1116 (offset 4 lines). Hunk #3 succeeded at 1132 (offset 4 lines). patching file include/asm-i386/desc.h (13:19:15:davej@nwo:linux-2.6)$
Dave
Signature · 1 line
http://www.codemonkey.org.uk
Quoted 8 lines · Rusty Russell
(Andrew, please sit these in the -mm tree for cooking)
Create a
paravirt.hheader for (almost) all the critical operations which need to be replaced with hypervisor calls.For the moment, this simply includes
no_paravirt.h, where all the native implementations now live.
Sorry, but I have to say these are not yet ready for -mm. While they're better than before (I can successfully boot), the machine locks up when I start X, and I wouldn't have any confidence in running with this stuff enabled. I'd prefer these weren't in -mm until we somewhat confident one could run with CONFIG_PARAVIRT on all the time (ie, think it could be default on, even if it isn't).
J
include/asm-i386/no_paravirt.h
Quoted 4 lines
===================================================================
include/asm-i386/no_paravirt.h new file +0
-0
I can't say I like the name. After all that should be the normal case for a long time now ... native? normal? bareiron?
Also I would prefer if you split this file up a bit - the old processor/system/irqflags split wasn't too bad.
include/asm-i386/no_paravirt.h line 34
Quoted 5 lines
include/asm-i386/no_paravirt.h new file +5
-0+ +/* +* Set IOPL bits in EFLAGS from given mask +*/ +static inline void set_iopl_mask (unsigned mask)
This function can be completely written in C using local_save_flags()/local_restore_flags() Please do that. I guess it's still a good idea to keep it separated
though because it might allow other optimizations.
e.g. i've been thinking about special casing IF changes in save/restore flags to optimize CPUs which have slow pushf/popf. If you already make sure all non IF manipulations of flags are separated that would help.
include/asm-i386/no_paravirt.h line 52
Quoted 6 lines
include/asm-i386/no_paravirt.h new file +6
-0+/* Stop speculative execution */ +static inline void sync_core (void ) +{ +unsigned int eax =1 , ebx, ecx, edx; +__cpuid (&eax, &ebx, &ecx, &edx); +}
Actually I don't think this one should be para virtualized at all. I don't see any reason at all why a hypervisor should trap it and it is very time critical. I would recommend you move it back into the normal files without hooks.
include/asm-i386/no_paravirt.h line 56
Quoted 4 lines
include/asm-i386/no_paravirt.h new file +4
-0+ +/* +* Clear and set 'TS' bit respectively +*/
The comment seems out of date (no set TS)
include/asm-i386/no_paravirt.h line 60
Quoted 4 lines
include/asm-i386/no_paravirt.h new file +4
-0+#define clts () __asm__ __volatile__ ("clts") +#define read_cr0 () ({ \ + unsigned int __dummy; \ + __asm__ __volatile__( \
Maybe it's just me, but can't you just drop all these __s around asm and volatile? They are completely useless as far I know.
Also the assembly will be easier readable if you just keep it on a single line for the simple ones.
-Andi
Quoted 12 lines · Andi Kleen
include/asm-i386/no_paravirt.h line 52
Quoted 7 lines
include/asm-i386/no_paravirt.h new file +6
-0+/* Stop speculative execution */ +static inline void sync_core (void ) +{ +unsigned int eax =1 , ebx, ecx, edx; +__cpuid (&eax, &ebx, &ecx, &edx); +}Actually I don't think this one should be para virtualized at all.
I don't see any reason at all why a hypervisor should trap it and it
is very time critical. I would recommend you move it back into the normal files without hooks.
When VT/AMDV is enabled, cpuid could cause a vm exit, so it would be nice to use one of the other serializing instructions in this case. For the default implementation, it should probably be an explicit asm("cpuid") to make it clear that we don't want any paravirtualized cpuid.
J
Quoted 15 lines · Jeremy Fitzhardinge
Quoted 4 lines · Andi Kleen
Quoted 4 lines
include/asm-i386/no_paravirt.h new file +4
-0+/* Stop speculative execution */ +static inline void sync_core (void ) +{ +unsigned int eax =1 , ebx, ecx, edx;Quoted 9 lines
include/asm-i386/no_paravirt.h line 52
Quoted 3 lines
include/asm-i386/no_paravirt.h new file +2
-0+__cpuid (&eax, &ebx, &ecx, &edx); +}Actually I don't think this one should be para virtualized at all. I don't see any reason at all why a hypervisor should trap it and it is very time critical. I would recommend you move it back into the normal files without hooks.
Quoted 1 line
When VT/AMDV is enabled, cpuid could cause a vm exit,
They will learn to add a filter at some point I guess (at least on SVM because it's not patched out on AMD)
Quoted 2 lines
so it would be
nice to use one of the other serializing instructions in this case.
You would first need to find one that works in ring 3. On x86-64 it is used in the gettimeoday vsyscall in ring 3 to synchronize the TSC and afaik John was about to implement that for i386 too.
BTW another issue that I haven't checked but we will need to make this also an alternative() for another case - it is faily important to patch it out on Intel systems with a synchronized TSC where it is fairly expensive. That is also not done yet on i386, but will be likely once vsyscall gettimeofday is implemented.
So basically you would need double patching. Ugly.
I would recommend to keep it out of para ops.
-Andi
Quoted 5 lines · Andi Kleen
Quoted 2 lines
so it would be nice to use one of the other serializing instructions in this case.
You would first need to find one that works in ring 3. On x86-64 it is used in the gettimeoday vsyscall in ring 3 to synchronize the TSC and afaik John was about to implement that for i386 too.
Well, that's really usermode code, so I don't think we'd necessarily touch it at all. It's not the same problem as the (single, at the moment) ring 0 use.
Quoted 7 lines
BTW another issue that I haven't checked but we will need to make
this also analternative()for another case - it is faily important
to patch it out on Intel systems with a synchronized TSC where it is
fairly expensive. That is also not done yet on i386, but will be likely once vsyscall gettimeofday is implemented.So basically you would need double patching. Ugly.
Yeah. I guess the cleanest way to do that is do the paravirt substitution, and then nop it out later if it isn't needed in the vsyscall.
Quoted 1 line
I would recommend to keep it out of para ops.
It's hardly a big deal either way. There's only one in-kernel use of it.
J
Quoted 13 lines · Jeremy Fitzhardinge
Quoted 4 lines · Andi Kleen
Quoted 4 lines
include/asm-i386/no_paravirt.h new file +4
-0+/* Stop speculative execution */ +static inline void sync_core (void ) +{ +unsigned int eax =1 , ebx, ecx, edx;Quoted 8 lines
include/asm-i386/no_paravirt.h line 52
Quoted 3 lines
include/asm-i386/no_paravirt.h new file +2
-0+__cpuid (&eax, &ebx, &ecx, &edx); +}Actually I don't think this one should be para virtualized at all. I don't see any reason at all why a hypervisor should trap it and it is very time critical. I would recommend you move it back into the normal files without hooks.
I don't see where it's time-critical...
Rusty.
Signature · 1 line
Help! Save Australia from the worst of the DMCA: http://linux.org.au/law
Quoted 15 lines · Rusty Russell
Quoted 13 lines · Jeremy Fitzhardinge
Quoted 4 lines · Andi Kleen
Quoted 4 lines
include/asm-i386/no_paravirt.h new file +4
-0+/* Stop speculative execution */ +static inline void sync_core (void ) +{ +unsigned int eax =1 , ebx, ecx, edx;Quoted 8 lines
include/asm-i386/no_paravirt.h line 52
Quoted 3 lines
include/asm-i386/no_paravirt.h new file +2
-0+__cpuid (&eax, &ebx, &ecx, &edx); +}Actually I don't think this one should be para virtualized at all. I don't see any reason at all why a hypervisor should trap it and it is very time critical. I would recommend you move it back into the normal files without hooks.
Quoted 1 line
I don't see where it's time-critical...
See explanation in my other email. Also in general we want this one fast.
-Andi
Quoted 6 lines · Andi Kleen
include/asm-i386/no_paravirt.h
Quoted 3 lines
===================================================================
include/asm-i386/no_paravirt.h new file +0
-0I can't say I like the name. After all that should be the normal case for a long time now ... native? normal? bareiron?
Yeah, I don't like it much either. native.h doesn't say what the alternative is. native_paravirt.h is kind of contradictory.
Quoted 2 lines
Also I would prefer if you split this file up a bit - the old processor/system/irqflags split wasn't too bad.
In the paravirt case, they all come into one ops structure, which has to be declared in one place.
Of course, those headers can do:
#ifdef CONFIG_PARAVIRT
#include <asm/paravirt.h>
#else
...
#endif
I'll try this and see what happens. Playing with the x86 headers can be extremely hairy 8(
Quoted 13 lines
include/asm-i386/no_paravirt.h line 34
Quoted 5 lines
include/asm-i386/no_paravirt.h new file +5
-0+ +/* +* Set IOPL bits in EFLAGS from given mask +*/ +static inline void set_iopl_mask (unsigned mask)This function can be completely written in C using local_save_flags()/local_restore_flags() Please do that. I guess it's still a good idea to keep it separated
though because it might allow other optimizations.e.g. i've been thinking about special casing IF changes in save/restore flags to optimize CPUs which have slow pushf/popf. If you already make sure all non IF manipulations of flags are separated that would help.
...
Quoted 16 lines
include/asm-i386/no_paravirt.h line 56
Quoted 4 lines
include/asm-i386/no_paravirt.h new file +4
-0+ +/* +* Clear and set 'TS' bit respectively +*/ The comment seems out of date (no set TS)
include/asm-i386/no_paravirt.h line 60
Quoted 4 lines
include/asm-i386/no_paravirt.h new file +4
-0+#define clts () __asm__ __volatile__ ("clts") +#define read_cr0 () ({ \ + unsigned int __dummy; \ + __asm__ __volatile__( \Maybe it's just me, but can't you just drop all these
__saround asm and volatile? They are completely useless as far I know.
Quoted 2 lines
Also the assembly will be easier readable if you just keep it on a single line for the simple ones.
I'm just shuffling code here, and if the other approach works, I won't even be doing that.
But I'm happy to submit a separate patch which cleans these...
Thanks!
Rusty.
Signature · 1 line
Help! Save Australia from the worst of the DMCA: http://linux.org.au/law
Quoted 10 lines · Rusty Russell
Quoted 6 lines · Andi Kleen
include/asm-i386/no_paravirt.h
Quoted 3 lines
===================================================================
include/asm-i386/no_paravirt.h new file +0
-0I can't say I like the name. After all that should be the normal case for a long time now ... native? normal? bareiron?
Yeah, I don't like it much either.
native.hdoesn't say what the alternative is.native_paravirt.his kind of contradictory.
You could create a subdirectory?
Quoted 2 lines
I'm just shuffling code here, and if the other approach works, I won't even be doing that.
If you move it you can as well clean it up. The result would be likely at least 50% shorter.
-Andi
Quoted 11 lines · Rusty Russell
Quoted 10 lines · Andi Kleen
Quoted 6 lines
include/asm-i386/no_paravirt.h
Quoted 3 lines
===================================================================
include/asm-i386/no_paravirt.h new file +0
-0I can't say I like the name. After all that should be the normal case for a long time now ... native? normal? bareiron?
Yeah, I don't like it much either.
native.hdoesn't say what the alternative is.native_paravirt.his kind of contradictory.
baremetal.h seems appropriate.
Cheers,
Muli
Quoted 2 lines
baremetal.hseems appropriate.
<vanilla.h>, in hommage to "vanilla kernel".
Jan Engelhardt
Quoted 4 lines · Jan Engelhardt
Quoted 2 lines
baremetal.hseems appropriate.<
vanilla.h>, in hommage to "vanilla kernel".
I think most people use 'vanilla' to mean 'mainline', as in Linus's kernel, so I find 'baremetal' (as opposed to 'virtualized') more appropriate but... since this thread has all of the characteristics of your favorite bike-shed, I'll bow out of it now :-)
Cheers,
Muli
Quoted 5 lines
Quoted 3 lines
Quoted 1 line
baremetal.hseems appropriate.<
vanilla.h>, in hommage to "vanilla kernel".I think most people use 'vanilla' to mean 'mainline', as in Linus's
Vanilla is also used outside Linux. One example that comes to mind is "vanilla Doom" (Doom as in: the game by id software), and actually someone took on it and created www.chocolate-doom.org.
Oh well, OT.
Jan Engelhardt
Quoted 10 lines · Rusty Russell
Quoted 10 lines
include/asm-i386/no_paravirt.h line 34
Quoted 6 lines
include/asm-i386/no_paravirt.h new file +5
-0+ +/* +* Set IOPL bits in EFLAGS from given mask +*/ +static inline void set_iopl_mask (unsigned mask)This function can be completely written in C using local_save_flags()/local_restore_flags() Please do that. I guess it's still a good idea to keep it separated
though because it might allow other optimizations.
Quoted 4 lines
Quoted 4 lines
e.g. i've been thinking about special casing IF changes in save/restore flags to optimize CPUs which have slow pushf/popf. If you already make sure all non IF manipulations of flags are separated that would help.
Actually, that is not quite true. Local_save_flags / raw_local_irq_restore today is used only for operating on IF flag, and raw_local_restore_flags does not exist. Our implementation of these in VMI assumes that only the IF flag is being changed, and this is the default assumption under which Xen runs as well. Using local_restore to switch IOPL as well causes the extremely performance critical common case of pure IRQ restore to do potentially a lot more work in a hypervisor.
So if you do want us to go with the C approach, I would propose using raw_local_iopl_restore, which can make a different hypercall (actually, in our case, this is not even a hypercall, merely a VMI call).
Zach
Quoted 17 lines · Zachary Amsden
Quoted 10 lines · Rusty Russell
Quoted 10 lines
include/asm-i386/no_paravirt.h line 34
Quoted 6 lines
include/asm-i386/no_paravirt.h new file +5
-0+ +/* +* Set IOPL bits in EFLAGS from given mask +*/ +static inline void set_iopl_mask (unsigned mask)This function can be completely written in C using local_save_flags()/local_restore_flags() Please do that. I guess it's still a good idea to keep it separated
though because it might allow other optimizations.Quoted 4 lines
Quoted 4 lines
e.g. i've been thinking about special casing IF changes in save/restore flags to optimize CPUs which have slow pushf/popf. If you already make sure all non IF manipulations of flags are separated that would help.
Quoted 3 lines
Actually, that is not quite true.
Local_save_flags/raw_local_irq_restoretoday is used only for operating on IF flag, andraw_local_restore_flagsdoes not exist.
Yes, sorry for the typo.
Quoted 9 lines
Our implementation of these in
VMI assumes that only the IF flag is being changed, and this is the default assumption under which Xen runs as well. Usinglocal_restoreto switch IOPL as well causes the extremely performance critical common case of pure IRQ restore to do potentially a lot more work in a hypervisor.So if you do want us to go with the C approach, I would propose using
raw_local_iopl_restore, which can make a different hypercall (actually, in our case, this is not even a hypercall, merely a VMI call).
I meant Rusty can use local restore in his native implementation. The higher level interface can be different.
-Andi