aboutsummaryrefslogtreecommitdiffstats
path: root/include/asm-i386/paravirt.h
diff options
context:
space:
mode:
authorRusty Russell <rusty@rustcorp.com.au>2006-12-06 20:14:07 -0500
committerAndi Kleen <andi@basil.nowhere.org>2006-12-06 20:14:07 -0500
commitd3561b7fa0fb0fc583bab0eeda32bec9e4c4056d (patch)
tree39d835965878622d052ef3b3c7b759d83b6bc327 /include/asm-i386/paravirt.h
parentdb91b882aabd0b3b55a87cbfb344f2798bb740b4 (diff)
[PATCH] paravirt: header and stubs for paravirtualisation
Create a paravirt.h header for all the critical operations which need to be replaced with hypervisor calls, and include that instead of defining native operations, when CONFIG_PARAVIRT. 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. And: +From: Andy Whitcroft <apw@shadowen.org> The paravirt ops introduce a 'weak' attribute onto memory_setup(). Code ordering leads to the following warnings on x86: arch/i386/kernel/setup.c:651: warning: weak declaration of `memory_setup' after first use results in unspecified behavior Move memory_setup() to avoid this. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> Signed-off-by: Chris Wright <chrisw@sous-sol.org> Signed-off-by: Andi Kleen <ak@suse.de> Cc: Jeremy Fitzhardinge <jeremy@goop.org> Cc: Zachary Amsden <zach@vmware.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Andy Whitcroft <apw@shadowen.org>
Diffstat (limited to 'include/asm-i386/paravirt.h')
-rw-r--r--include/asm-i386/paravirt.h281
1 files changed, 281 insertions, 0 deletions
diff --git a/include/asm-i386/paravirt.h b/include/asm-i386/paravirt.h
new file mode 100644
index 000000000000..a7551a44686f
--- /dev/null
+++ b/include/asm-i386/paravirt.h
@@ -0,0 +1,281 @@
1#ifndef __ASM_PARAVIRT_H
2#define __ASM_PARAVIRT_H
3/* Various instructions on x86 need to be replaced for
4 * para-virtualization: those hooks are defined here. */
5#include <linux/linkage.h>
6
7#ifdef CONFIG_PARAVIRT
8#ifndef __ASSEMBLY__
9struct thread_struct;
10struct Xgt_desc_struct;
11struct tss_struct;
12struct paravirt_ops
13{
14 unsigned int kernel_rpl;
15 int paravirt_enabled;
16 const char *name;
17
18 void (*arch_setup)(void);
19 char *(*memory_setup)(void);
20 void (*init_IRQ)(void);
21
22 void (*banner)(void);
23
24 unsigned long (*get_wallclock)(void);
25 int (*set_wallclock)(unsigned long);
26 void (*time_init)(void);
27
28 /* All the function pointers here are declared as "fastcall"
29 so that we get a specific register-based calling
30 convention. This makes it easier to implement inline
31 assembler replacements. */
32
33 void (fastcall *cpuid)(unsigned int *eax, unsigned int *ebx,
34 unsigned int *ecx, unsigned int *edx);
35
36 unsigned long (fastcall *get_debugreg)(int regno);
37 void (fastcall *set_debugreg)(int regno, unsigned long value);
38
39 void (fastcall *clts)(void);
40
41 unsigned long (fastcall *read_cr0)(void);
42 void (fastcall *write_cr0)(unsigned long);
43
44 unsigned long (fastcall *read_cr2)(void);
45 void (fastcall *write_cr2)(unsigned long);
46
47 unsigned long (fastcall *read_cr3)(void);
48 void (fastcall *write_cr3)(unsigned long);
49
50 unsigned long (fastcall *read_cr4_safe)(void);
51 unsigned long (fastcall *read_cr4)(void);
52 void (fastcall *write_cr4)(unsigned long);
53
54 unsigned long (fastcall *save_fl)(void);
55 void (fastcall *restore_fl)(unsigned long);
56 void (fastcall *irq_disable)(void);
57 void (fastcall *irq_enable)(void);
58 void (fastcall *safe_halt)(void);
59 void (fastcall *halt)(void);
60 void (fastcall *wbinvd)(void);
61
62 /* err = 0/-EFAULT. wrmsr returns 0/-EFAULT. */
63 u64 (fastcall *read_msr)(unsigned int msr, int *err);
64 int (fastcall *write_msr)(unsigned int msr, u64 val);
65
66 u64 (fastcall *read_tsc)(void);
67 u64 (fastcall *read_pmc)(void);
68
69 void (fastcall *load_tr_desc)(void);
70 void (fastcall *load_gdt)(const struct Xgt_desc_struct *);
71 void (fastcall *load_idt)(const struct Xgt_desc_struct *);
72 void (fastcall *store_gdt)(struct Xgt_desc_struct *);
73 void (fastcall *store_idt)(struct Xgt_desc_struct *);
74 void (fastcall *set_ldt)(const void *desc, unsigned entries);
75 unsigned long (fastcall *store_tr)(void);
76 void (fastcall *load_tls)(struct thread_struct *t, unsigned int cpu);
77 void (fastcall *write_ldt_entry)(void *dt, int entrynum,
78 u32 low, u32 high);
79 void (fastcall *write_gdt_entry)(void *dt, int entrynum,
80 u32 low, u32 high);
81 void (fastcall *write_idt_entry)(void *dt, int entrynum,
82 u32 low, u32 high);
83 void (fastcall *load_esp0)(struct tss_struct *tss,
84 struct thread_struct *thread);
85
86 void (fastcall *set_iopl_mask)(unsigned mask);
87
88 void (fastcall *io_delay)(void);
89 void (*const_udelay)(unsigned long loops);
90
91 /* These two are jmp to, not actually called. */
92 void (fastcall *irq_enable_sysexit)(void);
93 void (fastcall *iret)(void);
94};
95
96extern struct paravirt_ops paravirt_ops;
97
98#define paravirt_enabled() (paravirt_ops.paravirt_enabled)
99
100static inline void load_esp0(struct tss_struct *tss,
101 struct thread_struct *thread)
102{
103 paravirt_ops.load_esp0(tss, thread);
104}
105
106#define ARCH_SETUP paravirt_ops.arch_setup();
107static inline unsigned long get_wallclock(void)
108{
109 return paravirt_ops.get_wallclock();
110}
111
112static inline int set_wallclock(unsigned long nowtime)
113{
114 return paravirt_ops.set_wallclock(nowtime);
115}
116
117static inline void do_time_init(void)
118{
119 return paravirt_ops.time_init();
120}
121
122/* The paravirtualized CPUID instruction. */
123static inline void __cpuid(unsigned int *eax, unsigned int *ebx,
124 unsigned int *ecx, unsigned int *edx)
125{
126 paravirt_ops.cpuid(eax, ebx, ecx, edx);
127}
128
129/*
130 * These special macros can be used to get or set a debugging register
131 */
132#define get_debugreg(var, reg) var = paravirt_ops.get_debugreg(reg)
133#define set_debugreg(val, reg) paravirt_ops.set_debugreg(reg, val)
134
135#define clts() paravirt_ops.clts()
136
137#define read_cr0() paravirt_ops.read_cr0()
138#define write_cr0(x) paravirt_ops.write_cr0(x)
139
140#define read_cr2() paravirt_ops.read_cr2()
141#define write_cr2(x) paravirt_ops.write_cr2(x)
142
143#define read_cr3() paravirt_ops.read_cr3()
144#define write_cr3(x) paravirt_ops.write_cr3(x)
145
146#define read_cr4() paravirt_ops.read_cr4()
147#define read_cr4_safe(x) paravirt_ops.read_cr4_safe()
148#define write_cr4(x) paravirt_ops.write_cr4(x)
149
150static inline unsigned long __raw_local_save_flags(void)
151{
152 return paravirt_ops.save_fl();
153}
154
155static inline void raw_local_irq_restore(unsigned long flags)
156{
157 return paravirt_ops.restore_fl(flags);
158}
159
160static inline void raw_local_irq_disable(void)
161{
162 paravirt_ops.irq_disable();
163}
164
165static inline void raw_local_irq_enable(void)
166{
167 paravirt_ops.irq_enable();
168}
169
170static inline unsigned long __raw_local_irq_save(void)
171{
172 unsigned long flags = paravirt_ops.save_fl();
173
174 paravirt_ops.irq_disable();
175
176 return flags;
177}
178
179static inline void raw_safe_halt(void)
180{
181 paravirt_ops.safe_halt();
182}
183
184static inline void halt(void)
185{
186 paravirt_ops.safe_halt();
187}
188#define wbinvd() paravirt_ops.wbinvd()
189
190#define get_kernel_rpl() (paravirt_ops.kernel_rpl)
191
192#define rdmsr(msr,val1,val2) do { \
193 int _err; \
194 u64 _l = paravirt_ops.read_msr(msr,&_err); \
195 val1 = (u32)_l; \
196 val2 = _l >> 32; \
197} while(0)
198
199#define wrmsr(msr,val1,val2) do { \
200 u64 _l = ((u64)(val2) << 32) | (val1); \
201 paravirt_ops.write_msr((msr), _l); \
202} while(0)
203
204#define rdmsrl(msr,val) do { \
205 int _err; \
206 val = paravirt_ops.read_msr((msr),&_err); \
207} while(0)
208
209#define wrmsrl(msr,val) (paravirt_ops.write_msr((msr),(val)))
210#define wrmsr_safe(msr,a,b) ({ \
211 u64 _l = ((u64)(b) << 32) | (a); \
212 paravirt_ops.write_msr((msr),_l); \
213})
214
215/* rdmsr with exception handling */
216#define rdmsr_safe(msr,a,b) ({ \
217 int _err; \
218 u64 _l = paravirt_ops.read_msr(msr,&_err); \
219 (*a) = (u32)_l; \
220 (*b) = _l >> 32; \
221 _err; })
222
223#define rdtsc(low,high) do { \
224 u64 _l = paravirt_ops.read_tsc(); \
225 low = (u32)_l; \
226 high = _l >> 32; \
227} while(0)
228
229#define rdtscl(low) do { \
230 u64 _l = paravirt_ops.read_tsc(); \
231 low = (int)_l; \
232} while(0)
233
234#define rdtscll(val) (val = paravirt_ops.read_tsc())
235
236#define write_tsc(val1,val2) wrmsr(0x10, val1, val2)
237
238#define rdpmc(counter,low,high) do { \
239 u64 _l = paravirt_ops.read_pmc(); \
240 low = (u32)_l; \
241 high = _l >> 32; \
242} while(0)
243
244#define load_TR_desc() (paravirt_ops.load_tr_desc())
245#define load_gdt(dtr) (paravirt_ops.load_gdt(dtr))
246#define load_idt(dtr) (paravirt_ops.load_idt(dtr))
247#define set_ldt(addr, entries) (paravirt_ops.set_ldt((addr), (entries)))
248#define store_gdt(dtr) (paravirt_ops.store_gdt(dtr))
249#define store_idt(dtr) (paravirt_ops.store_idt(dtr))
250#define store_tr(tr) ((tr) = paravirt_ops.store_tr())
251#define load_TLS(t,cpu) (paravirt_ops.load_tls((t),(cpu)))
252#define write_ldt_entry(dt, entry, low, high) \
253 (paravirt_ops.write_ldt_entry((dt), (entry), (low), (high)))
254#define write_gdt_entry(dt, entry, low, high) \
255 (paravirt_ops.write_gdt_entry((dt), (entry), (low), (high)))
256#define write_idt_entry(dt, entry, low, high) \
257 (paravirt_ops.write_idt_entry((dt), (entry), (low), (high)))
258#define set_iopl_mask(mask) (paravirt_ops.set_iopl_mask(mask))
259
260/* The paravirtualized I/O functions */
261static inline void slow_down_io(void) {
262 paravirt_ops.io_delay();
263#ifdef REALLY_SLOW_IO
264 paravirt_ops.io_delay();
265 paravirt_ops.io_delay();
266 paravirt_ops.io_delay();
267#endif
268}
269
270#define CLI_STRING "pushl %eax; pushl %ecx; pushl %edx; call *paravirt_ops+PARAVIRT_irq_disable; popl %edx; popl %ecx; popl %eax"
271#define STI_STRING "pushl %eax; pushl %ecx; pushl %edx; call *paravirt_ops+PARAVIRT_irq_enable; popl %edx; popl %ecx; popl %eax"
272#else /* __ASSEMBLY__ */
273
274#define INTERRUPT_RETURN jmp *%cs:paravirt_ops+PARAVIRT_iret
275#define DISABLE_INTERRUPTS pushl %eax; pushl %ecx; pushl %edx; call *paravirt_ops+PARAVIRT_irq_disable; popl %edx; popl %ecx; popl %eax
276#define ENABLE_INTERRUPTS pushl %eax; pushl %ecx; pushl %edx; call *%cs:paravirt_ops+PARAVIRT_irq_enable; popl %edx; popl %ecx; popl %eax
277#define ENABLE_INTERRUPTS_SYSEXIT jmp *%cs:paravirt_ops+PARAVIRT_irq_enable_sysexit
278#define GET_CR0_INTO_EAX call *paravirt_ops+PARAVIRT_read_cr0
279#endif /* __ASSEMBLY__ */
280#endif /* CONFIG_PARAVIRT */
281#endif /* __ASM_PARAVIRT_H */