xref: /freebsd/sys/amd64/amd64/support.S (revision acc1a9ef)
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	%rdi,%rax
155	movq	%rdx,%rcx
156	shrq	$3,%rcx				/* copy by 64-bit words */
157	cld					/* copy forwards */
158	rep
159	movsq
160	movq	%rdx,%rcx
161	andq	$7,%rcx				/* any bytes left? */
162	rep
163	movsb
164	POP_FRAME_POINTER
165	ret
166END(memcpy)
167
168/*
169 * pagecopy(%rdi=from, %rsi=to)
170 */
171ENTRY(pagecopy)
172	PUSH_FRAME_POINTER
173	movq	$-PAGE_SIZE,%rax
174	movq	%rax,%rdx
175	subq	%rax,%rdi
176	subq	%rax,%rsi
1771:
178	prefetchnta (%rdi,%rax)
179	addq	$64,%rax
180	jne	1b
1812:
182	movq	(%rdi,%rdx),%rax
183	movnti	%rax,(%rsi,%rdx)
184	movq	8(%rdi,%rdx),%rax
185	movnti	%rax,8(%rsi,%rdx)
186	movq	16(%rdi,%rdx),%rax
187	movnti	%rax,16(%rsi,%rdx)
188	movq	24(%rdi,%rdx),%rax
189	movnti	%rax,24(%rsi,%rdx)
190	addq	$32,%rdx
191	jne	2b
192	sfence
193	POP_FRAME_POINTER
194	ret
195END(pagecopy)
196
197/* fillw(pat, base, cnt) */
198/*       %rdi,%rsi, %rdx */
199ENTRY(fillw)
200	PUSH_FRAME_POINTER
201	movq	%rdi,%rax
202	movq	%rsi,%rdi
203	movq	%rdx,%rcx
204	cld
205	rep
206	stosw
207	POP_FRAME_POINTER
208	ret
209END(fillw)
210
211/*****************************************************************************/
212/* copyout and fubyte family                                                 */
213/*****************************************************************************/
214/*
215 * Access user memory from inside the kernel. These routines should be
216 * the only places that do this.
217 *
218 * These routines set curpcb->pcb_onfault for the time they execute. When a
219 * protection violation occurs inside the functions, the trap handler
220 * returns to *curpcb->pcb_onfault instead of the function.
221 */
222
223/*
224 * copyout(from_kernel, to_user, len)  - MP SAFE
225 *         %rdi,        %rsi,    %rdx
226 */
227ENTRY(copyout)
228	PUSH_FRAME_POINTER
229	movq	PCPU(CURPCB),%rax
230	movq	$copyout_fault,PCB_ONFAULT(%rax)
231	testq	%rdx,%rdx			/* anything to do? */
232	jz	done_copyout
233
234	/*
235	 * Check explicitly for non-user addresses.  If 486 write protection
236	 * is being used, this check is essential because we are in kernel
237	 * mode so the h/w does not provide any protection against writing
238	 * kernel addresses.
239	 */
240
241	/*
242	 * First, prevent address wrapping.
243	 */
244	movq	%rsi,%rax
245	addq	%rdx,%rax
246	jc	copyout_fault
247/*
248 * XXX STOP USING VM_MAXUSER_ADDRESS.
249 * It is an end address, not a max, so every time it is used correctly it
250 * looks like there is an off by one error, and of course it caused an off
251 * by one error in several places.
252 */
253	movq	$VM_MAXUSER_ADDRESS,%rcx
254	cmpq	%rcx,%rax
255	ja	copyout_fault
256
257	xchgq	%rdi,%rsi
258	/* bcopy(%rsi, %rdi, %rdx) */
259	movq	%rdx,%rcx
260
261	shrq	$3,%rcx
262	cld
263	rep
264	movsq
265	movb	%dl,%cl
266	andb	$7,%cl
267	rep
268	movsb
269
270done_copyout:
271	xorl	%eax,%eax
272	movq	PCPU(CURPCB),%rdx
273	movq	%rax,PCB_ONFAULT(%rdx)
274	POP_FRAME_POINTER
275	ret
276
277	ALIGN_TEXT
278copyout_fault:
279	movq	PCPU(CURPCB),%rdx
280	movq	$0,PCB_ONFAULT(%rdx)
281	movq	$EFAULT,%rax
282	POP_FRAME_POINTER
283	ret
284END(copyout)
285
286/*
287 * copyin(from_user, to_kernel, len) - MP SAFE
288 *        %rdi,      %rsi,      %rdx
289 */
290ENTRY(copyin)
291	PUSH_FRAME_POINTER
292	movq	PCPU(CURPCB),%rax
293	movq	$copyin_fault,PCB_ONFAULT(%rax)
294	testq	%rdx,%rdx			/* anything to do? */
295	jz	done_copyin
296
297	/*
298	 * make sure address is valid
299	 */
300	movq	%rdi,%rax
301	addq	%rdx,%rax
302	jc	copyin_fault
303	movq	$VM_MAXUSER_ADDRESS,%rcx
304	cmpq	%rcx,%rax
305	ja	copyin_fault
306
307	xchgq	%rdi,%rsi
308	movq	%rdx,%rcx
309	movb	%cl,%al
310	shrq	$3,%rcx				/* copy longword-wise */
311	cld
312	rep
313	movsq
314	movb	%al,%cl
315	andb	$7,%cl				/* copy remaining bytes */
316	rep
317	movsb
318
319done_copyin:
320	xorl	%eax,%eax
321	movq	PCPU(CURPCB),%rdx
322	movq	%rax,PCB_ONFAULT(%rdx)
323	POP_FRAME_POINTER
324	ret
325
326	ALIGN_TEXT
327copyin_fault:
328	movq	PCPU(CURPCB),%rdx
329	movq	$0,PCB_ONFAULT(%rdx)
330	movq	$EFAULT,%rax
331	POP_FRAME_POINTER
332	ret
333END(copyin)
334
335/*
336 * casueword32.  Compare and set user integer.  Returns -1 on fault,
337 *        0 if access was successful.  Old value is written to *oldp.
338 *        dst = %rdi, old = %esi, oldp = %rdx, new = %ecx
339 */
340ENTRY(casueword32)
341	PUSH_FRAME_POINTER
342	movq	PCPU(CURPCB),%r8
343	movq	$fusufault,PCB_ONFAULT(%r8)
344
345	movq	$VM_MAXUSER_ADDRESS-4,%rax
346	cmpq	%rax,%rdi			/* verify address is valid */
347	ja	fusufault
348
349	movl	%esi,%eax			/* old */
350#ifdef SMP
351	lock
352#endif
353	cmpxchgl %ecx,(%rdi)			/* new = %ecx */
354
355	/*
356	 * The old value is in %eax.  If the store succeeded it will be the
357	 * value we expected (old) from before the store, otherwise it will
358	 * be the current value.  Save %eax into %esi to prepare the return
359	 * value.
360	 */
361	movl	%eax,%esi
362	xorl	%eax,%eax
363	movq	%rax,PCB_ONFAULT(%r8)
364
365	/*
366	 * Access the oldp after the pcb_onfault is cleared, to correctly
367	 * catch corrupted pointer.
368	 */
369	movl	%esi,(%rdx)			/* oldp = %rdx */
370	POP_FRAME_POINTER
371	ret
372END(casueword32)
373
374/*
375 * casueword.  Compare and set user long.  Returns -1 on fault,
376 *        0 if access was successful.  Old value is written to *oldp.
377 *        dst = %rdi, old = %rsi, oldp = %rdx, new = %rcx
378 */
379ENTRY(casueword)
380	PUSH_FRAME_POINTER
381	movq	PCPU(CURPCB),%r8
382	movq	$fusufault,PCB_ONFAULT(%r8)
383
384	movq	$VM_MAXUSER_ADDRESS-4,%rax
385	cmpq	%rax,%rdi			/* verify address is valid */
386	ja	fusufault
387
388	movq	%rsi,%rax			/* old */
389#ifdef SMP
390	lock
391#endif
392	cmpxchgq %rcx,(%rdi)			/* new = %rcx */
393
394	/*
395	 * The old value is in %rax.  If the store succeeded it will be the
396	 * value we expected (old) from before the store, otherwise it will
397	 * be the current value.
398	 */
399	movq	%rax,%rsi
400	xorl	%eax,%eax
401	movq	%rax,PCB_ONFAULT(%r8)
402	movq	%rsi,(%rdx)
403	POP_FRAME_POINTER
404	ret
405END(casueword)
406
407/*
408 * Fetch (load) a 64-bit word, a 32-bit word, a 16-bit word, or an 8-bit
409 * byte from user memory.
410 * addr = %rdi, valp = %rsi
411 */
412
413ALTENTRY(fueword64)
414ENTRY(fueword)
415	PUSH_FRAME_POINTER
416	movq	PCPU(CURPCB),%rcx
417	movq	$fusufault,PCB_ONFAULT(%rcx)
418
419	movq	$VM_MAXUSER_ADDRESS-8,%rax
420	cmpq	%rax,%rdi			/* verify address is valid */
421	ja	fusufault
422
423	xorl	%eax,%eax
424	movq	(%rdi),%r11
425	movq	%rax,PCB_ONFAULT(%rcx)
426	movq	%r11,(%rsi)
427	POP_FRAME_POINTER
428	ret
429END(fueword64)
430END(fueword)
431
432ENTRY(fueword32)
433	PUSH_FRAME_POINTER
434	movq	PCPU(CURPCB),%rcx
435	movq	$fusufault,PCB_ONFAULT(%rcx)
436
437	movq	$VM_MAXUSER_ADDRESS-4,%rax
438	cmpq	%rax,%rdi			/* verify address is valid */
439	ja	fusufault
440
441	xorl	%eax,%eax
442	movl	(%rdi),%r11d
443	movq	%rax,PCB_ONFAULT(%rcx)
444	movl	%r11d,(%rsi)
445	POP_FRAME_POINTER
446	ret
447END(fueword32)
448
449/*
450 * fuswintr() and suswintr() are specialized variants of fuword16() and
451 * suword16(), respectively.  They are called from the profiling code,
452 * potentially at interrupt time.  If they fail, that's okay; good things
453 * will happen later.  They always fail for now, until the trap code is
454 * able to deal with this.
455 */
456ALTENTRY(suswintr)
457ENTRY(fuswintr)
458	movq	$-1,%rax
459	ret
460END(suswintr)
461END(fuswintr)
462
463ENTRY(fuword16)
464	PUSH_FRAME_POINTER
465	movq	PCPU(CURPCB),%rcx
466	movq	$fusufault,PCB_ONFAULT(%rcx)
467
468	movq	$VM_MAXUSER_ADDRESS-2,%rax
469	cmpq	%rax,%rdi
470	ja	fusufault
471
472	movzwl	(%rdi),%eax
473	movq	$0,PCB_ONFAULT(%rcx)
474	POP_FRAME_POINTER
475	ret
476END(fuword16)
477
478ENTRY(fubyte)
479	PUSH_FRAME_POINTER
480	movq	PCPU(CURPCB),%rcx
481	movq	$fusufault,PCB_ONFAULT(%rcx)
482
483	movq	$VM_MAXUSER_ADDRESS-1,%rax
484	cmpq	%rax,%rdi
485	ja	fusufault
486
487	movzbl	(%rdi),%eax
488	movq	$0,PCB_ONFAULT(%rcx)
489	POP_FRAME_POINTER
490	ret
491END(fubyte)
492
493	ALIGN_TEXT
494fusufault:
495	movq	PCPU(CURPCB),%rcx
496	xorl	%eax,%eax
497	movq	%rax,PCB_ONFAULT(%rcx)
498	decq	%rax
499	POP_FRAME_POINTER
500	ret
501
502/*
503 * Store a 64-bit word, a 32-bit word, a 16-bit word, or an 8-bit byte to
504 * user memory.  All these functions are MPSAFE.
505 * addr = %rdi, value = %rsi
506 */
507ALTENTRY(suword64)
508ENTRY(suword)
509	PUSH_FRAME_POINTER
510	movq	PCPU(CURPCB),%rcx
511	movq	$fusufault,PCB_ONFAULT(%rcx)
512
513	movq	$VM_MAXUSER_ADDRESS-8,%rax
514	cmpq	%rax,%rdi			/* verify address validity */
515	ja	fusufault
516
517	movq	%rsi,(%rdi)
518	xorl	%eax,%eax
519	movq	PCPU(CURPCB),%rcx
520	movq	%rax,PCB_ONFAULT(%rcx)
521	POP_FRAME_POINTER
522	ret
523END(suword64)
524END(suword)
525
526ENTRY(suword32)
527	PUSH_FRAME_POINTER
528	movq	PCPU(CURPCB),%rcx
529	movq	$fusufault,PCB_ONFAULT(%rcx)
530
531	movq	$VM_MAXUSER_ADDRESS-4,%rax
532	cmpq	%rax,%rdi			/* verify address validity */
533	ja	fusufault
534
535	movl	%esi,(%rdi)
536	xorl	%eax,%eax
537	movq	PCPU(CURPCB),%rcx
538	movq	%rax,PCB_ONFAULT(%rcx)
539	POP_FRAME_POINTER
540	ret
541END(suword32)
542
543ENTRY(suword16)
544	PUSH_FRAME_POINTER
545	movq	PCPU(CURPCB),%rcx
546	movq	$fusufault,PCB_ONFAULT(%rcx)
547
548	movq	$VM_MAXUSER_ADDRESS-2,%rax
549	cmpq	%rax,%rdi			/* verify address validity */
550	ja	fusufault
551
552	movw	%si,(%rdi)
553	xorl	%eax,%eax
554	movq	PCPU(CURPCB),%rcx		/* restore trashed register */
555	movq	%rax,PCB_ONFAULT(%rcx)
556	POP_FRAME_POINTER
557	ret
558END(suword16)
559
560ENTRY(subyte)
561	PUSH_FRAME_POINTER
562	movq	PCPU(CURPCB),%rcx
563	movq	$fusufault,PCB_ONFAULT(%rcx)
564
565	movq	$VM_MAXUSER_ADDRESS-1,%rax
566	cmpq	%rax,%rdi			/* verify address validity */
567	ja	fusufault
568
569	movl	%esi,%eax
570	movb	%al,(%rdi)
571	xorl	%eax,%eax
572	movq	PCPU(CURPCB),%rcx		/* restore trashed register */
573	movq	%rax,PCB_ONFAULT(%rcx)
574	POP_FRAME_POINTER
575	ret
576END(subyte)
577
578/*
579 * copyinstr(from, to, maxlen, int *lencopied) - MP SAFE
580 *           %rdi, %rsi, %rdx, %rcx
581 *
582 *	copy a string from from to to, stop when a 0 character is reached.
583 *	return ENAMETOOLONG if string is longer than maxlen, and
584 *	EFAULT on protection violations. If lencopied is non-zero,
585 *	return the actual length in *lencopied.
586 */
587ENTRY(copyinstr)
588	PUSH_FRAME_POINTER
589	movq	%rdx,%r8			/* %r8 = maxlen */
590	movq	%rcx,%r9			/* %r9 = *len */
591	xchgq	%rdi,%rsi			/* %rdi = from, %rsi = to */
592	movq	PCPU(CURPCB),%rcx
593	movq	$cpystrflt,PCB_ONFAULT(%rcx)
594
595	movq	$VM_MAXUSER_ADDRESS,%rax
596
597	/* make sure 'from' is within bounds */
598	subq	%rsi,%rax
599	jbe	cpystrflt
600
601	/* restrict maxlen to <= VM_MAXUSER_ADDRESS-from */
602	cmpq	%rdx,%rax
603	jae	1f
604	movq	%rax,%rdx
605	movq	%rax,%r8
6061:
607	incq	%rdx
608	cld
609
6102:
611	decq	%rdx
612	jz	3f
613
614	lodsb
615	stosb
616	orb	%al,%al
617	jnz	2b
618
619	/* Success -- 0 byte reached */
620	decq	%rdx
621	xorl	%eax,%eax
622	jmp	cpystrflt_x
6233:
624	/* rdx is zero - return ENAMETOOLONG or EFAULT */
625	movq	$VM_MAXUSER_ADDRESS,%rax
626	cmpq	%rax,%rsi
627	jae	cpystrflt
6284:
629	movq	$ENAMETOOLONG,%rax
630	jmp	cpystrflt_x
631
632cpystrflt:
633	movq	$EFAULT,%rax
634
635cpystrflt_x:
636	/* set *lencopied and return %eax */
637	movq	PCPU(CURPCB),%rcx
638	movq	$0,PCB_ONFAULT(%rcx)
639
640	testq	%r9,%r9
641	jz	1f
642	subq	%rdx,%r8
643	movq	%r8,(%r9)
6441:
645	POP_FRAME_POINTER
646	ret
647END(copyinstr)
648
649/*
650 * copystr(from, to, maxlen, int *lencopied) - MP SAFE
651 *         %rdi, %rsi, %rdx, %rcx
652 */
653ENTRY(copystr)
654	PUSH_FRAME_POINTER
655	movq	%rdx,%r8			/* %r8 = maxlen */
656
657	xchgq	%rdi,%rsi
658	incq	%rdx
659	cld
6601:
661	decq	%rdx
662	jz	4f
663	lodsb
664	stosb
665	orb	%al,%al
666	jnz	1b
667
668	/* Success -- 0 byte reached */
669	decq	%rdx
670	xorl	%eax,%eax
671	jmp	6f
6724:
673	/* rdx is zero -- return ENAMETOOLONG */
674	movq	$ENAMETOOLONG,%rax
675
6766:
677
678	testq	%rcx,%rcx
679	jz	7f
680	/* set *lencopied and return %rax */
681	subq	%rdx,%r8
682	movq	%r8,(%rcx)
6837:
684	POP_FRAME_POINTER
685	ret
686END(copystr)
687
688/*
689 * Handling of special amd64 registers and descriptor tables etc
690 * %rdi
691 */
692/* void lgdt(struct region_descriptor *rdp); */
693ENTRY(lgdt)
694	/* reload the descriptor table */
695	lgdt	(%rdi)
696
697	/* flush the prefetch q */
698	jmp	1f
699	nop
7001:
701	movl	$KDSEL,%eax
702	movl	%eax,%ds
703	movl	%eax,%es
704	movl	%eax,%fs	/* Beware, use wrmsr to set 64 bit base */
705	movl	%eax,%gs
706	movl	%eax,%ss
707
708	/* reload code selector by turning return into intersegmental return */
709	popq	%rax
710	pushq	$KCSEL
711	pushq	%rax
712	MEXITCOUNT
713	lretq
714END(lgdt)
715
716/*****************************************************************************/
717/* setjump, longjump                                                         */
718/*****************************************************************************/
719
720ENTRY(setjmp)
721	movq	%rbx,0(%rdi)			/* save rbx */
722	movq	%rsp,8(%rdi)			/* save rsp */
723	movq	%rbp,16(%rdi)			/* save rbp */
724	movq	%r12,24(%rdi)			/* save r12 */
725	movq	%r13,32(%rdi)			/* save r13 */
726	movq	%r14,40(%rdi)			/* save r14 */
727	movq	%r15,48(%rdi)			/* save r15 */
728	movq	0(%rsp),%rdx			/* get rta */
729	movq	%rdx,56(%rdi)			/* save rip */
730	xorl	%eax,%eax			/* return(0); */
731	ret
732END(setjmp)
733
734ENTRY(longjmp)
735	movq	0(%rdi),%rbx			/* restore rbx */
736	movq	8(%rdi),%rsp			/* restore rsp */
737	movq	16(%rdi),%rbp			/* restore rbp */
738	movq	24(%rdi),%r12			/* restore r12 */
739	movq	32(%rdi),%r13			/* restore r13 */
740	movq	40(%rdi),%r14			/* restore r14 */
741	movq	48(%rdi),%r15			/* restore r15 */
742	movq	56(%rdi),%rdx			/* get rta */
743	movq	%rdx,0(%rsp)			/* put in return frame */
744	xorl	%eax,%eax			/* return(1); */
745	incl	%eax
746	ret
747END(longjmp)
748
749/*
750 * Support for reading MSRs in the safe manner.
751 */
752ENTRY(rdmsr_safe)
753/* int rdmsr_safe(u_int msr, uint64_t *data) */
754	PUSH_FRAME_POINTER
755	movq	PCPU(CURPCB),%r8
756	movq	$msr_onfault,PCB_ONFAULT(%r8)
757	movl	%edi,%ecx
758	rdmsr			/* Read MSR pointed by %ecx. Returns
759				   hi byte in edx, lo in %eax */
760	salq	$32,%rdx	/* sign-shift %rdx left */
761	movl	%eax,%eax	/* zero-extend %eax -> %rax */
762	orq	%rdx,%rax
763	movq	%rax,(%rsi)
764	xorq	%rax,%rax
765	movq	%rax,PCB_ONFAULT(%r8)
766	POP_FRAME_POINTER
767	ret
768
769/*
770 * Support for writing MSRs in the safe manner.
771 */
772ENTRY(wrmsr_safe)
773/* int wrmsr_safe(u_int msr, uint64_t data) */
774	PUSH_FRAME_POINTER
775	movq	PCPU(CURPCB),%r8
776	movq	$msr_onfault,PCB_ONFAULT(%r8)
777	movl	%edi,%ecx
778	movl	%esi,%eax
779	sarq	$32,%rsi
780	movl	%esi,%edx
781	wrmsr			/* Write MSR pointed by %ecx. Accepts
782				   hi byte in edx, lo in %eax. */
783	xorq	%rax,%rax
784	movq	%rax,PCB_ONFAULT(%r8)
785	POP_FRAME_POINTER
786	ret
787
788/*
789 * MSR operations fault handler
790 */
791	ALIGN_TEXT
792msr_onfault:
793	movq	$0,PCB_ONFAULT(%r8)
794	movl	$EFAULT,%eax
795	POP_FRAME_POINTER
796	ret
797