xref: /illumos-gate/usr/src/uts/i86xpv/sys/machprivregs.h (revision 27954b0d964ffcb749cf19296906e7fecdf3da1b)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #ifndef	_SYS_MACHPRIVREGS_H
28 #define	_SYS_MACHPRIVREGS_H
29 
30 #include <sys/hypervisor.h>
31 
32 /*
33  * Platform dependent instruction sequences for manipulating
34  * privileged state
35  */
36 
37 #ifdef __cplusplus
38 extern "C" {
39 #endif
40 
41 /*
42  * CLI and STI are quite complex to virtualize!
43  */
44 
45 #if defined(__amd64)
46 
47 #define	CURVCPU(r)					\
48 	movq	%gs:CPU_VCPU_INFO, r
49 
50 #define	CURTHREAD(r)					\
51 	movq	%gs:CPU_THREAD, r
52 
53 #elif defined(__i386)
54 
55 #define	CURVCPU(r)					\
56 	movl	%gs:CPU_VCPU_INFO, r
57 
58 #define	CURTHREAD(r)					\
59 	movl	%gs:CPU_THREAD, r
60 
61 #endif	/* __i386 */
62 
63 #define	XEN_TEST_EVENT_PENDING(r)			\
64 	testb	$0xff, VCPU_INFO_EVTCHN_UPCALL_PENDING(r)
65 
66 #define	XEN_SET_UPCALL_MASK(r)				\
67 	movb	$1, VCPU_INFO_EVTCHN_UPCALL_MASK(r)
68 
69 #define	XEN_GET_UPCALL_MASK(r, mask)			\
70 	movb	VCPU_INFO_EVTCHN_UPCALL_MASK(r), mask
71 
72 #define	XEN_TEST_UPCALL_MASK(r)				\
73 	testb	$1, VCPU_INFO_EVTCHN_UPCALL_MASK(r)
74 
75 #define	XEN_CLEAR_UPCALL_MASK(r)			\
76 	ASSERT_UPCALL_MASK_IS_SET;			\
77 	movb	$0, VCPU_INFO_EVTCHN_UPCALL_MASK(r)
78 
79 #ifdef DEBUG
80 
81 /*
82  * Much logic depends on the upcall mask being set at
83  * various points in the code; use this macro to validate.
84  *
85  * Need to use CURVCPU(r) to establish the vcpu pointer.
86  */
87 #if defined(__amd64)
88 
89 #define	ASSERT_UPCALL_MASK_IS_SET			\
90 	pushq	%r11;					\
91 	CURVCPU(%r11);					\
92 	XEN_TEST_UPCALL_MASK(%r11);			\
93 	jne	6f;					\
94 	cmpl	$0, stistipanic(%rip);			\
95 	jle	6f;					\
96 	movl	$-1, stistipanic(%rip);			\
97 	movq	stistimsg(%rip), %rdi;			\
98 	xorl	%eax, %eax;				\
99 	call	panic;					\
100 6:	pushq	%rax;					\
101 	pushq	%rbx;					\
102 	movl	%gs:CPU_ID, %eax;			\
103 	leaq	.+0(%rip), %r11;			\
104 	leaq	laststi(%rip), %rbx;			\
105 	movq	%r11, (%rbx, %rax, 8);			\
106 	popq	%rbx;					\
107 	popq	%rax;					\
108 	popq	%r11
109 
110 #define	SAVE_CLI_LOCATION				\
111 	pushq	%rax;					\
112 	pushq	%rbx;					\
113 	pushq	%rcx;					\
114 	movl	%gs:CPU_ID, %eax;			\
115 	leaq	.+0(%rip), %rcx;			\
116 	leaq	lastcli, %rbx;				\
117 	movq	%rcx, (%rbx, %rax, 8);			\
118 	popq	%rcx;					\
119 	popq	%rbx;					\
120 	popq	%rax;					\
121 
122 #elif defined(__i386)
123 
124 #define	ASSERT_UPCALL_MASK_IS_SET			\
125 	pushl	%ecx;					\
126 	CURVCPU(%ecx);					\
127 	XEN_TEST_UPCALL_MASK(%ecx);			\
128 	jne	6f;					\
129 	cmpl	$0, stistipanic;			\
130 	jle	6f;					\
131 	movl	$-1, stistipanic;			\
132 	movl	stistimsg, %ecx;			\
133 	pushl	%ecx;					\
134 	call	panic;					\
135 6:	pushl	%eax;					\
136 	pushl	%ebx;					\
137 	movl	%gs:CPU_ID, %eax;			\
138 	leal	.+0, %ecx;				\
139 	leal	laststi, %ebx;				\
140 	movl	%ecx, (%ebx, %eax, 4);			\
141 	popl	%ebx;					\
142 	popl	%eax;					\
143 	popl	%ecx
144 
145 #define	SAVE_CLI_LOCATION				\
146 	pushl	%eax;					\
147 	pushl	%ebx;					\
148 	pushl	%ecx;					\
149 	movl	%gs:CPU_ID, %eax;			\
150 	leal	.+0, %ecx;				\
151 	leal	lastcli, %ebx;				\
152 	movl	%ecx, (%ebx, %eax, 4);			\
153 	popl	%ecx;					\
154 	popl	%ebx;					\
155 	popl	%eax;					\
156 
157 #endif	/* __i386 */
158 
159 #else	/* DEBUG */
160 
161 #define	ASSERT_UPCALL_MASK_IS_SET	/* empty */
162 #define	SAVE_CLI_LOCATION		/* empty */
163 
164 #endif	/* DEBUG */
165 
166 #define	KPREEMPT_DISABLE(t)				\
167 	addb	$1, T_PREEMPT(t)
168 
169 #define	KPREEMPT_ENABLE_NOKP(t)				\
170 	subb	$1, T_PREEMPT(t)
171 
172 #define	CLI(r)						\
173 	CURTHREAD(r);					\
174 	KPREEMPT_DISABLE(r);				\
175 	CURVCPU(r);					\
176 	XEN_SET_UPCALL_MASK(r);				\
177 	SAVE_CLI_LOCATION;				\
178 	CURTHREAD(r);					\
179 	KPREEMPT_ENABLE_NOKP(r)
180 
181 #define	CLIRET(r, ret)					\
182 	CURTHREAD(r);					\
183 	KPREEMPT_DISABLE(r);				\
184 	CURVCPU(r);					\
185 	XEN_GET_UPCALL_MASK(r, ret);			\
186 	XEN_SET_UPCALL_MASK(r);				\
187 	SAVE_CLI_LOCATION;				\
188 	CURTHREAD(r);					\
189 	KPREEMPT_ENABLE_NOKP(r)
190 
191 /*
192  * We use the fact that HYPERVISOR_block will clear the upcall mask
193  * for us and then give us an upcall if there is a pending event
194  * to achieve getting a callback on this cpu without the danger of
195  * being preempted and migrating to another cpu between the upcall
196  * enable and the callback delivery.
197  */
198 #if defined(__amd64)
199 
200 #define	STI_CLOBBER		/* clobbers %rax, %rdi, %r11 */		\
201 	CURVCPU(%r11);							\
202 	ASSERT_UPCALL_MASK_IS_SET;					\
203 	movw	$0x100, %ax;	/* assume mask set, pending clear */	\
204 	movw	$0, %di;	/* clear mask and pending */		\
205 	lock;								\
206 	cmpxchgw %di, VCPU_INFO_EVTCHN_UPCALL_PENDING(%r11);		\
207 	jz	7f;		/* xchg worked, we're done */		\
208 	movl	$__HYPERVISOR_sched_op, %eax; /* have pending upcall */	\
209 	movl	$SCHEDOP_block, %edi;					\
210 	pushq	%rsi;	/* hypercall clobbers C param regs plus r10 */	\
211 	pushq	%rcx;							\
212 	pushq	%rdx;							\
213 	pushq	%r8;							\
214 	pushq	%r9;							\
215 	pushq	%r10;							\
216 	TRAP_INSTR;	/* clear upcall mask, force upcall */ 		\
217 	popq	%r10;							\
218 	popq	%r9;							\
219 	popq	%r8;							\
220 	popq	%rdx;							\
221 	popq	%rcx;							\
222 	popq	%rsi;							\
223 7:
224 
225 #define	STI								\
226 	pushq	%r11;							\
227 	pushq	%rdi;							\
228 	pushq	%rax;							\
229 	STI_CLOBBER;	/* clobbers %r11, %rax, %rdi */			\
230 	popq	%rax;							\
231 	popq	%rdi;							\
232 	popq	%r11
233 
234 #elif defined(__i386)
235 
236 #define	STI_CLOBBER		/* clobbers %eax, %ebx, %ecx */		\
237 	CURVCPU(%ecx);							\
238 	ASSERT_UPCALL_MASK_IS_SET;					\
239 	movw	$0x100, %ax;	/* assume mask set, pending clear */	\
240 	movw	$0, %bx;	/* clear mask and pending */		\
241 	lock;								\
242 	cmpxchgw %bx, VCPU_INFO_EVTCHN_UPCALL_PENDING(%ecx);		\
243 	jz	7f;		/* xchg worked, we're done */		\
244 	movl	$__HYPERVISOR_sched_op, %eax; /* have pending upcall */	\
245 	movl	$SCHEDOP_block, %ebx;					\
246 	TRAP_INSTR;		/* clear upcall mask, force upcall */	\
247 7:
248 
249 #define	STI						\
250 	pushl	%eax;					\
251 	pushl	%ebx;					\
252 	pushl	%ecx;					\
253 	STI_CLOBBER;	/* clobbers %eax, %ebx, %ecx */	\
254 	popl	%ecx;					\
255 	popl	%ebx;					\
256 	popl	%eax
257 
258 #endif	/* __i386 */
259 
260 /*
261  * Map the PS_IE bit to the hypervisor's event mask bit
262  * To -set- the event mask, we have to do a CLI
263  * To -clear- the event mask, we have to do a STI
264  * (with all the accompanying pre-emption and callbacks, ick)
265  *
266  * And vice versa.
267  */
268 
269 #if defined(__amd64)
270 
271 #define	IE_TO_EVENT_MASK(rtmp, rfl)		\
272 	testq	$PS_IE, rfl;			\
273 	jnz	4f;				\
274 	CLI(rtmp);				\
275 	jmp	5f;				\
276 4:	STI;					\
277 5:
278 
279 #define	EVENT_MASK_TO_IE(rtmp, rfl)		\
280 	andq	$_BITNOT(PS_IE), rfl;		\
281 	CURVCPU(rtmp);				\
282 	XEN_TEST_UPCALL_MASK(rtmp);		\
283 	jnz	1f;				\
284 	orq	$PS_IE, rfl;			\
285 1:
286 
287 #elif defined(__i386)
288 
289 #define	IE_TO_EVENT_MASK(rtmp, rfl)		\
290 	testl	$PS_IE, rfl;			\
291 	jnz	4f;				\
292 	CLI(rtmp);				\
293 	jmp	5f;				\
294 4:	STI;					\
295 5:
296 
297 #define	EVENT_MASK_TO_IE(rtmp, rfl)		\
298 	andl	$_BITNOT(PS_IE), rfl;		\
299 	CURVCPU(rtmp);				\
300 	XEN_TEST_UPCALL_MASK(rtmp);		\
301 	jnz	1f;				\
302 	orl	$PS_IE, rfl;			\
303 1:
304 
305 #endif	/* __i386 */
306 
307 /*
308  * Used to re-enable interrupts in the body of exception handlers
309  */
310 
311 #if defined(__amd64)
312 
313 #define	ENABLE_INTR_FLAGS		\
314 	pushq	$F_ON;			\
315 	popfq;				\
316 	STI
317 
318 #elif defined(__i386)
319 
320 #define	ENABLE_INTR_FLAGS		\
321 	pushl	$F_ON;			\
322 	popfl;				\
323 	STI
324 
325 #endif	/* __i386 */
326 
327 /*
328  * Virtualize IRET and SYSRET
329  */
330 
331 #if defined(__amd64)
332 
333 #if defined(DEBUG)
334 
335 /*
336  * Die nastily with a #ud trap if we are about to switch to user
337  * mode in HYPERVISOR_IRET and RUPDATE_PENDING is set.
338  */
339 #define	__ASSERT_NO_RUPDATE_PENDING			\
340 	pushq	%r15;					\
341 	cmpw	$KCS_SEL, 0x10(%rsp);			\
342 	je	1f;					\
343 	movq	%gs:CPU_THREAD, %r15;			\
344 	movq	T_LWP(%r15), %r15;			\
345 	testb	$0x1, PCB_RUPDATE(%r15);		\
346 	je	1f;					\
347 	ud2;						\
348 1:	popq	%r15
349 
350 #else	/* DEBUG */
351 
352 #define	__ASSERT_NO_RUPDATE_PENDING
353 
354 #endif	/* DEBUG */
355 
356 /*
357  * Switching from guest kernel to user mode.
358  * flag == VGCF_IN_SYSCALL => return via sysret
359  * flag == 0 => return via iretq
360  *
361  * See definition in public/arch-x86_64.h. Stack going in must be:
362  * rax, r11, rcx, flags, rip, cs, rflags, rsp, ss.
363  */
364 #define	HYPERVISOR_IRET(flag)			\
365 	__ASSERT_NO_RUPDATE_PENDING;		\
366 	pushq	$flag;				\
367 	pushq	%rcx;				\
368 	pushq	%r11;				\
369 	pushq	%rax;				\
370 	movl	$__HYPERVISOR_iret, %eax;	\
371 	syscall;				\
372 	ud2	/* die nastily if we return! */
373 
374 #define	IRET	HYPERVISOR_IRET(0)
375 
376 /*
377  * XXPV: Normally we would expect to use sysret to return from kernel to
378  *       user mode when using the syscall instruction. The iret hypercall
379  *       does support both iret and sysret semantics. For us to use sysret
380  *	 style would require that we use the hypervisor's private descriptors
381  *	 that obey syscall instruction's imposed segment selector ordering.
382  *	 With iret we can use whatever %cs value we choose. We should fix
383  *	 this to use sysret one day.
384  */
385 #define	SYSRETQ	HYPERVISOR_IRET(0)
386 #define	SYSRETL	ud2		/* 32-bit syscall/sysret not supported */
387 #define	SWAPGS	/* empty - handled in hypervisor */
388 
389 #elif defined(__i386)
390 
391 /*
392  * Switching from guest kernel to user mode.
393  * See definition in public/arch-x86_32.h. Stack going in must be:
394  * eax, flags, eip, cs, eflags, esp, ss.
395  */
396 #define	HYPERVISOR_IRET				\
397 	pushl	%eax;				\
398 	movl	$__HYPERVISOR_iret, %eax;	\
399 	int	$0x82;				\
400 	ud2	/* die nastily if we return! */
401 
402 #define	IRET	HYPERVISOR_IRET
403 #define	SYSRET	ud2		/* 32-bit syscall/sysret not supported */
404 
405 #endif	/* __i386 */
406 
407 
408 /*
409  * Xen 3.x wedges the current value of upcall_mask into unused byte of
410  * saved %cs on stack at the time of passing through a trap or interrupt
411  * gate.  Since Xen also updates PS_IE in %[e,r]lags as well, we always
412  * mask off the saved upcall mask so the kernel and/or tools like debuggers
413  * will not be confused about bits set in reserved portions of %cs slot.
414  *
415  * See xen/include/public/arch-x86_[32,64].h:cpu_user_regs_t for details.
416  */
417 #if defined(__amd64)
418 
419 #define	CLEAN_CS	movb	$0, REGOFF_CS+4(%rsp)
420 
421 #elif defined(__i386)
422 
423 #define	CLEAN_CS	movb	$0, REGOFF_CS+2(%esp)
424 
425 #endif	/* __i386 */
426 
427 /*
428  * All exceptions for amd64 have %r11 and %rcx on the stack.
429  * Just pop them back into their appropriate registers and
430  * let it get saved as is running native.
431  */
432 #if defined(__amd64)
433 
434 #define	XPV_TRAP_POP	\
435 	popq	%rcx;	\
436 	popq	%r11
437 
438 #define	XPV_TRAP_PUSH	\
439 	pushq	%r11;	\
440 	pushq	%rcx
441 
442 #endif	/* __amd64 */
443 
444 
445 /*
446  * Macros for saving the original segment registers and restoring them
447  * for fast traps.
448  */
449 #if defined(__amd64)
450 
451 /*
452  * Smaller versions of INTR_PUSH and INTR_POP for fast traps.
453  * The following registers have been pushed onto the stack by
454  * hardware at this point:
455  *
456  *	greg_t	r_rip;
457  *	greg_t	r_cs;
458  *	greg_t	r_rfl;
459  *	greg_t	r_rsp;
460  *	greg_t	r_ss;
461  *
462  * This handler is executed both by 32-bit and 64-bit applications.
463  * 64-bit applications allow us to treat the set (%rdi, %rsi, %rdx,
464  * %rcx, %r8, %r9, %r10, %r11, %rax) as volatile across function calls.
465  * However, 32-bit applications only expect (%eax, %edx, %ecx) to be volatile
466  * across a function call -- in particular, %esi and %edi MUST be saved!
467  *
468  * We could do this differently by making a FAST_INTR_PUSH32 for 32-bit
469  * programs, and FAST_INTR_PUSH for 64-bit programs, but it doesn't seem
470  * particularly worth it.
471  *
472  */
473 #define	FAST_INTR_PUSH			\
474 	INTGATE_INIT_KERNEL_FLAGS;	\
475 	popq	%rcx;			\
476 	popq	%r11;			\
477 	subq    $REGOFF_RIP, %rsp;	\
478 	movq    %rsi, REGOFF_RSI(%rsp);	\
479 	movq    %rdi, REGOFF_RDI(%rsp);	\
480 	CLEAN_CS
481 
482 #define	FAST_INTR_POP			\
483 	movq    REGOFF_RSI(%rsp), %rsi;	\
484 	movq    REGOFF_RDI(%rsp), %rdi;	\
485 	addq    $REGOFF_RIP, %rsp
486 
487 #define	FAST_INTR_RETURN		\
488 	ASSERT_UPCALL_MASK_IS_SET;	\
489 	HYPERVISOR_IRET(0)
490 
491 #elif defined(__i386)
492 
493 #define	FAST_INTR_PUSH			\
494 	cld;				\
495 	__SEGREGS_PUSH			\
496 	__SEGREGS_LOAD_KERNEL		\
497 
498 #define	FAST_INTR_POP			\
499 	__SEGREGS_POP
500 
501 #define	FAST_INTR_RETURN		\
502 	IRET
503 
504 #endif	/* __i386 */
505 
506 /*
507  * Handling the CR0.TS bit for floating point handling.
508  *
509  * When the TS bit is *set*, attempts to touch the floating
510  * point hardware will result in a #nm trap.
511  */
512 #if defined(__amd64)
513 
514 #define	STTS(rtmp)				\
515 	pushq	%rdi;				\
516 	movl	$1, %edi;			\
517 	call	HYPERVISOR_fpu_taskswitch;	\
518 	popq	%rdi
519 
520 #define	CLTS					\
521 	pushq	%rdi;				\
522 	xorl	%edi, %edi;			\
523 	call	HYPERVISOR_fpu_taskswitch;	\
524 	popq	%rdi
525 
526 #elif defined(__i386)
527 
528 #define	STTS(r)					\
529 	pushl	$1;				\
530 	call	HYPERVISOR_fpu_taskswitch;	\
531 	addl	$4, %esp
532 
533 #define	CLTS					\
534 	pushl	$0;				\
535 	call	HYPERVISOR_fpu_taskswitch;	\
536 	addl	$4, %esp
537 
538 #endif	/* __i386 */
539 
540 #ifdef __cplusplus
541 }
542 #endif
543 
544 #endif	/* _SYS_MACHPRIVREGS_H */
545