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