xref: /dragonfly/sys/platform/pc64/x86_64/support.s (revision 19380330)
1/*-
2 * Copyright (c) 1993 The Regents of the University of California.
3 * Copyright (c) 2003 Peter Wemm.
4 * Copyright (c) 2008 The DragonFly Project.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 4. Neither the name of the University nor the names of its contributors
16 *    may be used to endorse or promote products derived from this software
17 *    without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 *
31 * $FreeBSD: src/sys/amd64/amd64/support.S,v 1.127 2007/05/23 08:33:04 kib Exp $
32 */
33
34#include <machine/asmacros.h>
35#include <machine/pmap.h>
36
37#include "assym.s"
38
39	ALIGN_DATA
40
41	.text
42
43/*
44 * bcopy family
45 * void bzero(void *buf, size_t len)
46 */
47
48/* done */
49ENTRY(bzero)
50	movq	%rsi,%rcx
51	xorl	%eax,%eax
52	shrq	$3,%rcx
53	cld
54	rep
55	stosq
56	movq	%rsi,%rcx
57	andq	$7,%rcx
58	rep
59	stosb
60	ret
61
62/* Address: %rdi */
63ENTRY(pagezero)
64	movq	$-PAGE_SIZE,%rdx
65	subq	%rdx,%rdi
66	xorl	%eax,%eax
671:
68	movq	%rax,(%rdi,%rdx)	/* movnti */
69	movq	%rax,8(%rdi,%rdx)	/* movnti */
70	movq	%rax,16(%rdi,%rdx)	/* movnti */
71	movq	%rax,24(%rdi,%rdx)	/* movnti */
72	addq	$32,%rdx
73	jne	1b
74	/*sfence*/
75	ret
76
77ENTRY(bcmp)
78	movq	%rdx,%rcx
79	shrq	$3,%rcx
80	cld					/* compare forwards */
81	repe
82	cmpsq
83	jne	1f
84
85	movq	%rdx,%rcx
86	andq	$7,%rcx
87	repe
88	cmpsb
891:
90	setne	%al
91	movsbl	%al,%eax
92	ret
93
94/*
95 * bcopy(src, dst, cnt)
96 *       rdi, rsi, rdx
97 *  ws@tools.de     (Wolfgang Solfrank, TooLs GmbH) +49-228-985800
98 */
99ENTRY(generic_bcopy)	/* generic_bcopy is bcopy without FPU */
100ENTRY(ovbcopy) /* our bcopy doesn't use the FPU, so ovbcopy is the same */
101ENTRY(bcopy)
102	xchgq	%rsi,%rdi
103	movq	%rdx,%rcx
104
105	movq	%rdi,%rax
106	subq	%rsi,%rax
107	cmpq	%rcx,%rax			/* overlapping && src < dst? */
108	jb	1f
109
110	shrq	$3,%rcx				/* copy by 64-bit words */
111	cld					/* nope, copy forwards */
112	rep
113	movsq
114	movq	%rdx,%rcx
115	andq	$7,%rcx				/* any bytes left? */
116	rep
117	movsb
118	ret
119
120	/* ALIGN_TEXT */
1211:
122	addq	%rcx,%rdi			/* copy backwards */
123	addq	%rcx,%rsi
124	decq	%rdi
125	decq	%rsi
126	andq	$7,%rcx				/* any fractional bytes? */
127	std
128	rep
129	movsb
130	movq	%rdx,%rcx			/* copy remainder by 32-bit words */
131	shrq	$3,%rcx
132	subq	$7,%rsi
133	subq	$7,%rdi
134	rep
135	movsq
136	cld
137	ret
138ENTRY(reset_dbregs)
139	movq	$0x200,%rax   /* the manual says that bit 10 must be set to 1 */
140	movq    %rax,%dr7     /* disable all breapoints first */
141	movq    $0,%rax
142	movq    %rax,%dr0
143	movq    %rax,%dr1
144	movq    %rax,%dr2
145	movq    %rax,%dr3
146	movq    %rax,%dr6
147	ret
148
149/*
150 * Note: memcpy does not support overlapping copies
151 */
152ENTRY(memcpy)
153	movq	%rdx,%rcx
154	shrq	$3,%rcx				/* copy by 64-bit words */
155	cld					/* copy forwards */
156	rep
157	movsq
158	movq	%rdx,%rcx
159	andq	$7,%rcx				/* any bytes left? */
160	rep
161	movsb
162	ret
163
164/*
165 * pagecopy(%rdi=from, %rsi=to)
166 */
167ENTRY(pagecopy)
168	movq	$-PAGE_SIZE,%rax
169	movq	%rax,%rdx
170	subq	%rax,%rdi
171	subq	%rax,%rsi
1721:
173	/*prefetchnta (%rdi,%rax)*/
174	/*addq	$64,%rax*/
175	/*jne	1b*/
1762:
177	movq	(%rdi,%rdx),%rax
178	movq	%rax,(%rsi,%rdx)	/* movnti */
179	movq	8(%rdi,%rdx),%rax
180	movq	%rax,8(%rsi,%rdx)	/* movnti */
181	movq	16(%rdi,%rdx),%rax
182	movq	%rax,16(%rsi,%rdx)	/* movnti */
183	movq	24(%rdi,%rdx),%rax
184	movq	%rax,24(%rsi,%rdx)	/* movnti */
185	addq	$32,%rdx
186	jne	2b
187	/*sfence*/
188	ret
189
190/* fillw(pat, base, cnt) */
191/*       %rdi,%rsi, %rdx */
192ENTRY(fillw)
193	movq	%rdi,%rax
194	movq	%rsi,%rdi
195	movq	%rdx,%rcx
196	cld
197	rep
198	stosw
199	ret
200
201/*****************************************************************************/
202/* copyout and fubyte family                                                 */
203/*****************************************************************************/
204/*
205 * Access user memory from inside the kernel. These routines should be
206 * the only places that do this.
207 *
208 * These routines set curpcb->onfault for the time they execute. When a
209 * protection violation occurs inside the functions, the trap handler
210 * returns to *curpcb->onfault instead of the function.
211 */
212
213/*
214 * copyout(from_kernel, to_user, len)  - MP SAFE
215 *         %rdi,        %rsi,    %rdx
216 */
217ENTRY(copyout)
218	movq	PCPU(curthread),%rax
219	movq	TD_PCB(%rax), %rax
220	movq	$copyout_fault,PCB_ONFAULT(%rax)
221	movq	%rsp,PCB_ONFAULT_SP(%rax)
222	testq	%rdx,%rdx			/* anything to do? */
223	jz	done_copyout
224
225	/*
226	 * Check explicitly for non-user addresses.  If 486 write protection
227	 * is being used, this check is essential because we are in kernel
228	 * mode so the h/w does not provide any protection against writing
229	 * kernel addresses.
230	 */
231
232	/*
233	 * First, prevent address wrapping.
234	 */
235	movq	%rsi,%rax
236	addq	%rdx,%rax
237	jc	copyout_fault
238/*
239 * XXX STOP USING VM_MAX_USER_ADDRESS.
240 * It is an end address, not a max, so every time it is used correctly it
241 * looks like there is an off by one error, and of course it caused an off
242 * by one error in several places.
243 */
244	movq	$VM_MAX_USER_ADDRESS,%rcx
245	cmpq	%rcx,%rax
246	ja	copyout_fault
247
248	xchgq	%rdi,%rsi
249	/* bcopy(%rsi, %rdi, %rdx) */
250	movq	%rdx,%rcx
251
252	shrq	$3,%rcx
253	cld
254	rep
255	movsq
256	movb	%dl,%cl
257	andb	$7,%cl
258	rep
259	movsb
260
261done_copyout:
262	xorl	%eax,%eax
263	movq	PCPU(curthread),%rdx
264	movq	TD_PCB(%rdx), %rdx
265	movq	%rax,PCB_ONFAULT(%rdx)
266	ret
267
268	ALIGN_TEXT
269copyout_fault:
270	movq	PCPU(curthread),%rdx
271	movq	TD_PCB(%rdx), %rdx
272	movq	$0,PCB_ONFAULT(%rdx)
273	movq	$EFAULT,%rax
274	ret
275
276/*
277 * copyin(from_user, to_kernel, len) - MP SAFE
278 *        %rdi,      %rsi,      %rdx
279 */
280ENTRY(copyin)
281	movq	PCPU(curthread),%rax
282	movq	TD_PCB(%rax), %rax
283	movq	$copyin_fault,PCB_ONFAULT(%rax)
284	movq	%rsp,PCB_ONFAULT_SP(%rax)
285	testq	%rdx,%rdx			/* anything to do? */
286	jz	done_copyin
287
288	/*
289	 * make sure address is valid
290	 */
291	movq	%rdi,%rax
292	addq	%rdx,%rax
293	jc	copyin_fault
294	movq	$VM_MAX_USER_ADDRESS,%rcx
295	cmpq	%rcx,%rax
296	ja	copyin_fault
297
298	xchgq	%rdi,%rsi
299	movq	%rdx,%rcx
300	movb	%cl,%al
301	shrq	$3,%rcx				/* copy longword-wise */
302	cld
303	rep
304	movsq
305	movb	%al,%cl
306	andb	$7,%cl				/* copy remaining bytes */
307	rep
308	movsb
309
310done_copyin:
311	xorl	%eax,%eax
312	movq	PCPU(curthread),%rdx
313	movq	TD_PCB(%rdx), %rdx
314	movq	%rax,PCB_ONFAULT(%rdx)
315	ret
316
317	ALIGN_TEXT
318copyin_fault:
319	movq	PCPU(curthread),%rdx
320	movq	TD_PCB(%rdx), %rdx
321	movq	$0,PCB_ONFAULT(%rdx)
322	movq	$EFAULT,%rax
323	ret
324
325/*
326 * casuword32.  Compare and set user integer.  Returns -1 or the current value.
327 *        dst = %rdi, old = %rsi, new = %rdx
328 */
329ENTRY(casuword32)
330	movq	PCPU(curthread),%rcx
331	movq	TD_PCB(%rcx), %rcx
332	movq	$fusufault,PCB_ONFAULT(%rcx)
333	movq	%rsp,PCB_ONFAULT_SP(%rcx)
334
335	movq	$VM_MAX_USER_ADDRESS-4,%rax
336	cmpq	%rax,%rdi			/* verify address is valid */
337	ja	fusufault
338
339	movl	%esi,%eax			/* old */
340#ifdef SMP
341	lock
342#endif
343	cmpxchgl %edx,(%rdi)			/* new = %edx */
344
345	/*
346	 * The old value is in %eax.  If the store succeeded it will be the
347	 * value we expected (old) from before the store, otherwise it will
348	 * be the current value.
349	 */
350
351	movq	PCPU(curthread),%rcx
352	movq	TD_PCB(%rcx), %rcx
353	movq	$0,PCB_ONFAULT(%rcx)
354	ret
355
356/*
357 * casuword.  Compare and set user word.  Returns -1 or the current value.
358 *        dst = %rdi, old = %rsi, new = %rdx
359 */
360ENTRY(casuword)
361	movq	PCPU(curthread),%rcx
362	movq	TD_PCB(%rcx), %rcx
363	movq	$fusufault,PCB_ONFAULT(%rcx)
364	movq	%rsp,PCB_ONFAULT_SP(%rcx)
365
366	movq	$VM_MAX_USER_ADDRESS-4,%rax
367	cmpq	%rax,%rdi			/* verify address is valid */
368	ja	fusufault
369
370	movq	%rsi,%rax			/* old */
371#ifdef SMP
372	lock
373#endif
374	cmpxchgq %rdx,(%rdi)			/* new = %rdx */
375
376	/*
377	 * The old value is in %eax.  If the store succeeded it will be the
378	 * value we expected (old) from before the store, otherwise it will
379	 * be the current value.
380	 */
381
382	movq	PCPU(curthread),%rcx
383	movq	TD_PCB(%rcx), %rcx
384	movq	$0,PCB_ONFAULT(%rcx)
385	ret
386
387/*
388 * Fetch (load) a 64-bit word, a 32-bit word, a 16-bit word, or an 8-bit
389 * byte from user memory.  All these functions are MPSAFE.
390 * addr = %rdi
391 */
392
393ALTENTRY(fuword64)
394ENTRY(fuword)
395	movq	PCPU(curthread),%rcx
396	movq	TD_PCB(%rcx), %rcx
397	movq	$fusufault,PCB_ONFAULT(%rcx)
398	movq	%rsp,PCB_ONFAULT_SP(%rcx)
399
400	movq	$VM_MAX_USER_ADDRESS-8,%rax
401	cmpq	%rax,%rdi			/* verify address is valid */
402	ja	fusufault
403
404	movq	(%rdi),%rax
405	movq	$0,PCB_ONFAULT(%rcx)
406	ret
407
408ENTRY(fuword32)
409	movq	PCPU(curthread),%rcx
410	movq	TD_PCB(%rcx), %rcx
411	movq	$fusufault,PCB_ONFAULT(%rcx)
412	movq	%rsp,PCB_ONFAULT_SP(%rcx)
413
414	movq	$VM_MAX_USER_ADDRESS-4,%rax
415	cmpq	%rax,%rdi			/* verify address is valid */
416	ja	fusufault
417
418	movl	(%rdi),%eax
419	movq	$0,PCB_ONFAULT(%rcx)
420	ret
421
422/*
423 * fuswintr() and suswintr() are specialized variants of fuword16() and
424 * suword16(), respectively.  They are called from the profiling code,
425 * potentially at interrupt time.  If they fail, that's okay; good things
426 * will happen later.  They always fail for now, until the trap code is
427 * able to deal with this.
428 */
429ALTENTRY(suswintr)
430ENTRY(fuswintr)
431	movq	$-1,%rax
432	ret
433
434ENTRY(fuword16)
435	movq	PCPU(curthread),%rcx
436	movq	TD_PCB(%rcx), %rcx
437	movq	$fusufault,PCB_ONFAULT(%rcx)
438	movq	%rsp,PCB_ONFAULT_SP(%rcx)
439
440	movq	$VM_MAX_USER_ADDRESS-2,%rax
441	cmpq	%rax,%rdi
442	ja	fusufault
443
444	movzwl	(%rdi),%eax
445	movq	$0,PCB_ONFAULT(%rcx)
446	ret
447
448ENTRY(fubyte)
449	movq	PCPU(curthread),%rcx
450	movq	TD_PCB(%rcx), %rcx
451	movq	$fusufault,PCB_ONFAULT(%rcx)
452	movq	%rsp,PCB_ONFAULT_SP(%rcx)
453
454	movq	$VM_MAX_USER_ADDRESS-1,%rax
455	cmpq	%rax,%rdi
456	ja	fusufault
457
458	movzbl	(%rdi),%eax
459	movq	$0,PCB_ONFAULT(%rcx)
460	ret
461
462	ALIGN_TEXT
463fusufault:
464	movq	PCPU(curthread),%rcx
465	xorl	%eax,%eax
466	movq	TD_PCB(%rcx), %rcx
467	movq	%rax,PCB_ONFAULT(%rcx)
468	decq	%rax
469	ret
470
471/*
472 * Store a 64-bit word, a 32-bit word, a 16-bit word, or an 8-bit byte to
473 * user memory.  All these functions are MPSAFE.
474 *
475 * addr = %rdi, value = %rsi
476 *
477 * Write a long
478 */
479ALTENTRY(suword64)
480ENTRY(suword)
481	movq	PCPU(curthread),%rcx
482	movq	TD_PCB(%rcx), %rcx
483	movq	$fusufault,PCB_ONFAULT(%rcx)
484	movq	%rsp,PCB_ONFAULT_SP(%rcx)
485
486	movq	$VM_MAX_USER_ADDRESS-8,%rax
487	cmpq	%rax,%rdi			/* verify address validity */
488	ja	fusufault
489
490	movq	%rsi,(%rdi)
491	xorl	%eax,%eax
492	movq	PCPU(curthread),%rcx
493	movq	TD_PCB(%rcx), %rcx
494	movq	%rax,PCB_ONFAULT(%rcx)
495	ret
496
497/*
498 * Write an int
499 */
500ENTRY(suword32)
501	movq	PCPU(curthread),%rcx
502	movq	TD_PCB(%rcx), %rcx
503	movq	$fusufault,PCB_ONFAULT(%rcx)
504	movq	%rsp,PCB_ONFAULT_SP(%rcx)
505
506	movq	$VM_MAX_USER_ADDRESS-4,%rax
507	cmpq	%rax,%rdi			/* verify address validity */
508	ja	fusufault
509
510	movl	%esi,(%rdi)
511	xorl	%eax,%eax
512	movq	PCPU(curthread),%rcx
513	movq	TD_PCB(%rcx), %rcx
514	movq	%rax,PCB_ONFAULT(%rcx)
515	ret
516
517ENTRY(suword16)
518	movq	PCPU(curthread),%rcx
519	movq	TD_PCB(%rcx), %rcx
520	movq	$fusufault,PCB_ONFAULT(%rcx)
521	movq	%rsp,PCB_ONFAULT_SP(%rcx)
522
523	movq	$VM_MAX_USER_ADDRESS-2,%rax
524	cmpq	%rax,%rdi			/* verify address validity */
525	ja	fusufault
526
527	movw	%si,(%rdi)
528	xorl	%eax,%eax
529	movq	PCPU(curthread),%rcx		/* restore trashed register */
530	movq	TD_PCB(%rcx), %rcx
531	movq	%rax,PCB_ONFAULT(%rcx)
532	ret
533
534ENTRY(subyte)
535	movq	PCPU(curthread),%rcx
536	movq	TD_PCB(%rcx), %rcx
537	movq	$fusufault,PCB_ONFAULT(%rcx)
538	movq	%rsp,PCB_ONFAULT_SP(%rcx)
539
540	movq	$VM_MAX_USER_ADDRESS-1,%rax
541	cmpq	%rax,%rdi			/* verify address validity */
542	ja	fusufault
543
544	movl	%esi,%eax
545	movb	%al,(%rdi)
546	xorl	%eax,%eax
547	movq	PCPU(curthread),%rcx		/* restore trashed register */
548	movq	TD_PCB(%rcx), %rcx
549	movq	%rax,PCB_ONFAULT(%rcx)
550	ret
551
552/*
553 * copyinstr(from, to, maxlen, int *lencopied) - MP SAFE
554 *           %rdi, %rsi, %rdx, %rcx
555 *
556 *	copy a string from from to to, stop when a 0 character is reached.
557 *	return ENAMETOOLONG if string is longer than maxlen, and
558 *	EFAULT on protection violations. If lencopied is non-zero,
559 *	return the actual length in *lencopied.
560 */
561ENTRY(copyinstr)
562	movq	%rdx,%r8			/* %r8 = maxlen */
563	movq	%rcx,%r9			/* %r9 = *len */
564	xchgq	%rdi,%rsi			/* %rdi = from, %rsi = to */
565	movq	PCPU(curthread),%rcx
566	movq	TD_PCB(%rcx), %rcx
567	movq	$cpystrflt,PCB_ONFAULT(%rcx)
568	movq	%rsp,PCB_ONFAULT_SP(%rcx)
569
570	movq	$VM_MAX_USER_ADDRESS,%rax
571
572	/* make sure 'from' is within bounds */
573	subq	%rsi,%rax
574	jbe	cpystrflt
575
576	/* restrict maxlen to <= VM_MAX_USER_ADDRESS-from */
577	cmpq	%rdx,%rax
578	jae	1f
579	movq	%rax,%rdx
580	movq	%rax,%r8
5811:
582	incq	%rdx
583	cld
584
5852:
586	decq	%rdx
587	jz	3f
588
589	lodsb
590	stosb
591	orb	%al,%al
592	jnz	2b
593
594	/* Success -- 0 byte reached */
595	decq	%rdx
596	xorl	%eax,%eax
597	jmp	cpystrflt_x
5983:
599	/* rdx is zero - return ENAMETOOLONG or EFAULT */
600	movq	$VM_MAX_USER_ADDRESS,%rax
601	cmpq	%rax,%rsi
602	jae	cpystrflt
6034:
604	movq	$ENAMETOOLONG,%rax
605	jmp	cpystrflt_x
606
607cpystrflt:
608	movq	$EFAULT,%rax
609
610cpystrflt_x:
611	/* set *lencopied and return %eax */
612	movq	PCPU(curthread),%rcx
613	movq	TD_PCB(%rcx), %rcx
614	movq	$0,PCB_ONFAULT(%rcx)
615
616	testq	%r9,%r9
617	jz	1f
618	subq	%rdx,%r8
619	movq	%r8,(%r9)
6201:
621	ret
622
623
624/*
625 * copystr(from, to, maxlen, int *lencopied) - MP SAFE
626 *         %rdi, %rsi, %rdx, %rcx
627 */
628ENTRY(copystr)
629	movq	%rdx,%r8			/* %r8 = maxlen */
630
631	xchgq	%rdi,%rsi
632	incq	%rdx
633	cld
6341:
635	decq	%rdx
636	jz	4f
637	lodsb
638	stosb
639	orb	%al,%al
640	jnz	1b
641
642	/* Success -- 0 byte reached */
643	decq	%rdx
644	xorl	%eax,%eax
645	jmp	6f
6464:
647	/* rdx is zero -- return ENAMETOOLONG */
648	movq	$ENAMETOOLONG,%rax
649
6506:
651
652	testq	%rcx,%rcx
653	jz	7f
654	/* set *lencopied and return %rax */
655	subq	%rdx,%r8
656	movq	%r8,(%rcx)
6577:
658	ret
659
660/*
661 * Handling of special x86_64 registers and descriptor tables etc
662 * %rdi
663 */
664/* void lgdt(struct region_descriptor *rdp); */
665ENTRY(lgdt)
666	/* reload the descriptor table */
667	lgdt	(%rdi)
668
669	/* flush the prefetch q */
670	jmp	1f
671	nop
6721:
673	movl	$KDSEL,%eax
674	movl	%eax,%ds
675	movl	%eax,%es
676	movl	%eax,%fs	/* Beware, use wrmsr to set 64 bit base */
677	movl	%eax,%gs	/* Beware, use wrmsr to set 64 bit base */
678	movl	%eax,%ss
679
680	/* reload code selector by turning return into intersegmental return */
681	popq	%rax
682	pushq	$KCSEL
683	pushq	%rax
684	MEXITCOUNT
685	lretq
686
687/*****************************************************************************/
688/* setjump, longjump                                                         */
689/*****************************************************************************/
690
691ENTRY(setjmp)
692	movq	%rbx,0(%rdi)			/* save rbx */
693	movq	%rsp,8(%rdi)			/* save rsp */
694	movq	%rbp,16(%rdi)			/* save rbp */
695	movq	%r12,24(%rdi)			/* save r12 */
696	movq	%r13,32(%rdi)			/* save r13 */
697	movq	%r14,40(%rdi)			/* save r14 */
698	movq	%r15,48(%rdi)			/* save r15 */
699	movq	0(%rsp),%rdx			/* get rta */
700	movq	%rdx,56(%rdi)			/* save rip */
701	xorl	%eax,%eax			/* return(0); */
702	ret
703
704ENTRY(longjmp)
705	movq	0(%rdi),%rbx			/* restore rbx */
706	movq	8(%rdi),%rsp			/* restore rsp */
707	movq	16(%rdi),%rbp			/* restore rbp */
708	movq	24(%rdi),%r12			/* restore r12 */
709	movq	32(%rdi),%r13			/* restore r13 */
710	movq	40(%rdi),%r14			/* restore r14 */
711	movq	48(%rdi),%r15			/* restore r15 */
712	movq	56(%rdi),%rdx			/* get rta */
713	movq	%rdx,0(%rsp)			/* put in return frame */
714	xorl	%eax,%eax			/* return(1); */
715	incl	%eax
716	ret
717
718/*
719 * Support for reading MSRs in the safe manner.
720 */
721ENTRY(rdmsr_safe)
722/* int rdmsr_safe(u_int msr, uint64_t *data) */
723	movq	PCPU(curthread),%r8
724	movq	TD_PCB(%r8), %r8
725	movq	$msr_onfault,PCB_ONFAULT(%r8)
726	movq	%rsp,PCB_ONFAULT_SP(%r8)
727	movl	%edi,%ecx
728	rdmsr			/* Read MSR pointed by %ecx. Returns
729				   hi byte in edx, lo in %eax */
730	salq	$32,%rdx	/* sign-shift %rdx left */
731	movl	%eax,%eax	/* zero-extend %eax -> %rax */
732	orq	%rdx,%rax
733	movq	%rax,(%rsi)
734	xorq	%rax,%rax
735	movq	%rax,PCB_ONFAULT(%r8)
736	ret
737
738/*
739 * MSR operations fault handler
740 */
741	ALIGN_TEXT
742msr_onfault:
743	movq	PCPU(curthread),%r8
744	movq	TD_PCB(%r8), %r8
745	movq	$0,PCB_ONFAULT(%r8)
746	movl	$EFAULT,%eax
747	ret
748
749/*
750 * Support for BB-profiling (gcc -a).  The kernbb program will extract
751 * the data from the kernel.
752 */
753
754	.data
755	ALIGN_DATA
756	.globl bbhead
757bbhead:
758	.quad 0
759
760	.text
761NON_GPROF_ENTRY(__bb_init_func)
762	movq	$1,(%rdi)
763	movq	bbhead,%rax
764	movq	%rax,32(%rdi)
765	movq	%rdi,bbhead
766	NON_GPROF_RET
767