support.s revision 282274
1/*-
2 * Copyright (c) 1993 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 4. Neither the name of the University nor the names of its contributors
14 *    may be used to endorse or promote products derived from this software
15 *    without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 * $FreeBSD: head/sys/i386/i386/support.s 282274 2015-04-30 15:48:48Z jhb $
30 */
31
32#include "opt_npx.h"
33
34#include <machine/asmacros.h>
35#include <machine/cputypes.h>
36#include <machine/intr_machdep.h>
37#include <machine/pmap.h>
38#include <machine/specialreg.h>
39
40#include "assym.s"
41
42#define IDXSHIFT	10
43
44	.text
45
46/*
47 * bcopy family
48 * void bzero(void *buf, u_int len)
49 */
50ENTRY(bzero)
51	pushl	%edi
52	movl	8(%esp),%edi
53	movl	12(%esp),%ecx
54	xorl	%eax,%eax
55	shrl	$2,%ecx
56	cld
57	rep
58	stosl
59	movl	12(%esp),%ecx
60	andl	$3,%ecx
61	rep
62	stosb
63	popl	%edi
64	ret
65END(bzero)
66
67ENTRY(sse2_pagezero)
68	pushl	%ebx
69	movl	8(%esp),%ecx
70	movl	%ecx,%eax
71	addl	$4096,%eax
72	xor	%ebx,%ebx
731:
74	movnti	%ebx,(%ecx)
75	addl	$4,%ecx
76	cmpl	%ecx,%eax
77	jne	1b
78	sfence
79	popl	%ebx
80	ret
81END(sse2_pagezero)
82
83ENTRY(i686_pagezero)
84	pushl	%edi
85	pushl	%ebx
86
87	movl	12(%esp),%edi
88	movl	$1024,%ecx
89	cld
90
91	ALIGN_TEXT
921:
93	xorl	%eax,%eax
94	repe
95	scasl
96	jnz	2f
97
98	popl	%ebx
99	popl	%edi
100	ret
101
102	ALIGN_TEXT
103
1042:
105	incl	%ecx
106	subl	$4,%edi
107
108	movl	%ecx,%edx
109	cmpl	$16,%ecx
110
111	jge	3f
112
113	movl	%edi,%ebx
114	andl	$0x3f,%ebx
115	shrl	%ebx
116	shrl	%ebx
117	movl	$16,%ecx
118	subl	%ebx,%ecx
119
1203:
121	subl	%ecx,%edx
122	rep
123	stosl
124
125	movl	%edx,%ecx
126	testl	%edx,%edx
127	jnz	1b
128
129	popl	%ebx
130	popl	%edi
131	ret
132END(i686_pagezero)
133
134/* fillw(pat, base, cnt) */
135ENTRY(fillw)
136	pushl	%edi
137	movl	8(%esp),%eax
138	movl	12(%esp),%edi
139	movl	16(%esp),%ecx
140	cld
141	rep
142	stosw
143	popl	%edi
144	ret
145END(fillw)
146
147ENTRY(bcopyb)
148	pushl	%esi
149	pushl	%edi
150	movl	12(%esp),%esi
151	movl	16(%esp),%edi
152	movl	20(%esp),%ecx
153	movl	%edi,%eax
154	subl	%esi,%eax
155	cmpl	%ecx,%eax			/* overlapping && src < dst? */
156	jb	1f
157	cld					/* nope, copy forwards */
158	rep
159	movsb
160	popl	%edi
161	popl	%esi
162	ret
163
164	ALIGN_TEXT
1651:
166	addl	%ecx,%edi			/* copy backwards. */
167	addl	%ecx,%esi
168	decl	%edi
169	decl	%esi
170	std
171	rep
172	movsb
173	popl	%edi
174	popl	%esi
175	cld
176	ret
177END(bcopyb)
178
179/*
180 * bcopy(src, dst, cnt)
181 *  ws@tools.de     (Wolfgang Solfrank, TooLs GmbH) +49-228-985800
182 */
183ENTRY(bcopy)
184	pushl	%ebp
185	movl	%esp,%ebp
186	pushl	%esi
187	pushl	%edi
188	movl	8(%ebp),%esi
189	movl	12(%ebp),%edi
190	movl	16(%ebp),%ecx
191
192	movl	%edi,%eax
193	subl	%esi,%eax
194	cmpl	%ecx,%eax			/* overlapping && src < dst? */
195	jb	1f
196
197	shrl	$2,%ecx				/* copy by 32-bit words */
198	cld					/* nope, copy forwards */
199	rep
200	movsl
201	movl	16(%ebp),%ecx
202	andl	$3,%ecx				/* any bytes left? */
203	rep
204	movsb
205	popl	%edi
206	popl	%esi
207	popl	%ebp
208	ret
209
210	ALIGN_TEXT
2111:
212	addl	%ecx,%edi			/* copy backwards */
213	addl	%ecx,%esi
214	decl	%edi
215	decl	%esi
216	andl	$3,%ecx				/* any fractional bytes? */
217	std
218	rep
219	movsb
220	movl	16(%ebp),%ecx			/* copy remainder by 32-bit words */
221	shrl	$2,%ecx
222	subl	$3,%esi
223	subl	$3,%edi
224	rep
225	movsl
226	popl	%edi
227	popl	%esi
228	cld
229	popl	%ebp
230	ret
231END(bcopy)
232
233/*
234 * Note: memcpy does not support overlapping copies
235 */
236ENTRY(memcpy)
237	pushl	%edi
238	pushl	%esi
239	movl	12(%esp),%edi
240	movl	16(%esp),%esi
241	movl	20(%esp),%ecx
242	movl	%edi,%eax
243	shrl	$2,%ecx				/* copy by 32-bit words */
244	cld					/* nope, copy forwards */
245	rep
246	movsl
247	movl	20(%esp),%ecx
248	andl	$3,%ecx				/* any bytes left? */
249	rep
250	movsb
251	popl	%esi
252	popl	%edi
253	ret
254END(memcpy)
255
256/*****************************************************************************/
257/* copyout and fubyte family                                                 */
258/*****************************************************************************/
259/*
260 * Access user memory from inside the kernel. These routines and possibly
261 * the math- and DOS emulators should be the only places that do this.
262 *
263 * We have to access the memory with user's permissions, so use a segment
264 * selector with RPL 3. For writes to user space we have to additionally
265 * check the PTE for write permission, because the 386 does not check
266 * write permissions when we are executing with EPL 0. The 486 does check
267 * this if the WP bit is set in CR0, so we can use a simpler version here.
268 *
269 * These routines set curpcb->pcb_onfault for the time they execute. When a
270 * protection violation occurs inside the functions, the trap handler
271 * returns to *curpcb->pcb_onfault instead of the function.
272 */
273
274/*
275 * copyout(from_kernel, to_user, len)  - MP SAFE
276 */
277ENTRY(copyout)
278	movl	PCPU(CURPCB),%eax
279	movl	$copyout_fault,PCB_ONFAULT(%eax)
280	pushl	%esi
281	pushl	%edi
282	pushl	%ebx
283	movl	16(%esp),%esi
284	movl	20(%esp),%edi
285	movl	24(%esp),%ebx
286	testl	%ebx,%ebx			/* anything to do? */
287	jz	done_copyout
288
289	/*
290	 * Check explicitly for non-user addresses.  If 486 write protection
291	 * is being used, this check is essential because we are in kernel
292	 * mode so the h/w does not provide any protection against writing
293	 * kernel addresses.
294	 */
295
296	/*
297	 * First, prevent address wrapping.
298	 */
299	movl	%edi,%eax
300	addl	%ebx,%eax
301	jc	copyout_fault
302/*
303 * XXX STOP USING VM_MAXUSER_ADDRESS.
304 * It is an end address, not a max, so every time it is used correctly it
305 * looks like there is an off by one error, and of course it caused an off
306 * by one error in several places.
307 */
308	cmpl	$VM_MAXUSER_ADDRESS,%eax
309	ja	copyout_fault
310
311	/* bcopy(%esi, %edi, %ebx) */
312	movl	%ebx,%ecx
313
314	shrl	$2,%ecx
315	cld
316	rep
317	movsl
318	movb	%bl,%cl
319	andb	$3,%cl
320	rep
321	movsb
322
323done_copyout:
324	popl	%ebx
325	popl	%edi
326	popl	%esi
327	xorl	%eax,%eax
328	movl	PCPU(CURPCB),%edx
329	movl	%eax,PCB_ONFAULT(%edx)
330	ret
331END(copyout)
332
333	ALIGN_TEXT
334copyout_fault:
335	popl	%ebx
336	popl	%edi
337	popl	%esi
338	movl	PCPU(CURPCB),%edx
339	movl	$0,PCB_ONFAULT(%edx)
340	movl	$EFAULT,%eax
341	ret
342
343/*
344 * copyin(from_user, to_kernel, len) - MP SAFE
345 */
346ENTRY(copyin)
347	movl	PCPU(CURPCB),%eax
348	movl	$copyin_fault,PCB_ONFAULT(%eax)
349	pushl	%esi
350	pushl	%edi
351	movl	12(%esp),%esi			/* caddr_t from */
352	movl	16(%esp),%edi			/* caddr_t to */
353	movl	20(%esp),%ecx			/* size_t  len */
354
355	/*
356	 * make sure address is valid
357	 */
358	movl	%esi,%edx
359	addl	%ecx,%edx
360	jc	copyin_fault
361	cmpl	$VM_MAXUSER_ADDRESS,%edx
362	ja	copyin_fault
363
364	movb	%cl,%al
365	shrl	$2,%ecx				/* copy longword-wise */
366	cld
367	rep
368	movsl
369	movb	%al,%cl
370	andb	$3,%cl				/* copy remaining bytes */
371	rep
372	movsb
373
374	popl	%edi
375	popl	%esi
376	xorl	%eax,%eax
377	movl	PCPU(CURPCB),%edx
378	movl	%eax,PCB_ONFAULT(%edx)
379	ret
380END(copyin)
381
382	ALIGN_TEXT
383copyin_fault:
384	popl	%edi
385	popl	%esi
386	movl	PCPU(CURPCB),%edx
387	movl	$0,PCB_ONFAULT(%edx)
388	movl	$EFAULT,%eax
389	ret
390
391/*
392 * casueword.  Compare and set user word.  Returns -1 on fault,
393 * 0 on non-faulting access.  The current value is in *oldp.
394 */
395ALTENTRY(casueword32)
396ENTRY(casueword)
397	movl	PCPU(CURPCB),%ecx
398	movl	$fusufault,PCB_ONFAULT(%ecx)
399	movl	4(%esp),%edx			/* dst */
400	movl	8(%esp),%eax			/* old */
401	movl	16(%esp),%ecx			/* new */
402
403	cmpl	$VM_MAXUSER_ADDRESS-4,%edx	/* verify address is valid */
404	ja	fusufault
405
406#ifdef SMP
407	lock
408#endif
409	cmpxchgl %ecx,(%edx)			/* Compare and set. */
410
411	/*
412	 * The old value is in %eax.  If the store succeeded it will be the
413	 * value we expected (old) from before the store, otherwise it will
414	 * be the current value.
415	 */
416
417	movl	PCPU(CURPCB),%ecx
418	movl	$0,PCB_ONFAULT(%ecx)
419	movl	12(%esp),%edx			/* oldp */
420	movl	%eax,(%edx)
421	xorl	%eax,%eax
422	ret
423END(casueword32)
424END(casueword)
425
426/*
427 * Fetch (load) a 32-bit word, a 16-bit word, or an 8-bit byte from user
428 * memory.
429 */
430
431ALTENTRY(fueword32)
432ENTRY(fueword)
433	movl	PCPU(CURPCB),%ecx
434	movl	$fusufault,PCB_ONFAULT(%ecx)
435	movl	4(%esp),%edx			/* from */
436
437	cmpl	$VM_MAXUSER_ADDRESS-4,%edx	/* verify address is valid */
438	ja	fusufault
439
440	movl	(%edx),%eax
441	movl	$0,PCB_ONFAULT(%ecx)
442	movl	8(%esp),%edx
443	movl	%eax,(%edx)
444	xorl	%eax,%eax
445	ret
446END(fueword32)
447END(fueword)
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	movl	$-1,%eax
459	ret
460END(suswintr)
461END(fuswintr)
462
463ENTRY(fuword16)
464	movl	PCPU(CURPCB),%ecx
465	movl	$fusufault,PCB_ONFAULT(%ecx)
466	movl	4(%esp),%edx
467
468	cmpl	$VM_MAXUSER_ADDRESS-2,%edx
469	ja	fusufault
470
471	movzwl	(%edx),%eax
472	movl	$0,PCB_ONFAULT(%ecx)
473	ret
474END(fuword16)
475
476ENTRY(fubyte)
477	movl	PCPU(CURPCB),%ecx
478	movl	$fusufault,PCB_ONFAULT(%ecx)
479	movl	4(%esp),%edx
480
481	cmpl	$VM_MAXUSER_ADDRESS-1,%edx
482	ja	fusufault
483
484	movzbl	(%edx),%eax
485	movl	$0,PCB_ONFAULT(%ecx)
486	ret
487END(fubyte)
488
489	ALIGN_TEXT
490fusufault:
491	movl	PCPU(CURPCB),%ecx
492	xorl	%eax,%eax
493	movl	%eax,PCB_ONFAULT(%ecx)
494	decl	%eax
495	ret
496
497/*
498 * Store a 32-bit word, a 16-bit word, or an 8-bit byte to user memory.
499 * All these functions are MPSAFE.
500 */
501
502ALTENTRY(suword32)
503ENTRY(suword)
504	movl	PCPU(CURPCB),%ecx
505	movl	$fusufault,PCB_ONFAULT(%ecx)
506	movl	4(%esp),%edx
507
508	cmpl	$VM_MAXUSER_ADDRESS-4,%edx	/* verify address validity */
509	ja	fusufault
510
511	movl	8(%esp),%eax
512	movl	%eax,(%edx)
513	xorl	%eax,%eax
514	movl	PCPU(CURPCB),%ecx
515	movl	%eax,PCB_ONFAULT(%ecx)
516	ret
517END(suword32)
518END(suword)
519
520ENTRY(suword16)
521	movl	PCPU(CURPCB),%ecx
522	movl	$fusufault,PCB_ONFAULT(%ecx)
523	movl	4(%esp),%edx
524
525	cmpl	$VM_MAXUSER_ADDRESS-2,%edx	/* verify address validity */
526	ja	fusufault
527
528	movw	8(%esp),%ax
529	movw	%ax,(%edx)
530	xorl	%eax,%eax
531	movl	PCPU(CURPCB),%ecx		/* restore trashed register */
532	movl	%eax,PCB_ONFAULT(%ecx)
533	ret
534END(suword16)
535
536ENTRY(subyte)
537	movl	PCPU(CURPCB),%ecx
538	movl	$fusufault,PCB_ONFAULT(%ecx)
539	movl	4(%esp),%edx
540
541	cmpl	$VM_MAXUSER_ADDRESS-1,%edx	/* verify address validity */
542	ja	fusufault
543
544	movb	8(%esp),%al
545	movb	%al,(%edx)
546	xorl	%eax,%eax
547	movl	PCPU(CURPCB),%ecx		/* restore trashed register */
548	movl	%eax,PCB_ONFAULT(%ecx)
549	ret
550END(subyte)
551
552/*
553 * copyinstr(from, to, maxlen, int *lencopied) - MP SAFE
554 *
555 *	copy a string from from to to, stop when a 0 character is reached.
556 *	return ENAMETOOLONG if string is longer than maxlen, and
557 *	EFAULT on protection violations. If lencopied is non-zero,
558 *	return the actual length in *lencopied.
559 */
560ENTRY(copyinstr)
561	pushl	%esi
562	pushl	%edi
563	movl	PCPU(CURPCB),%ecx
564	movl	$cpystrflt,PCB_ONFAULT(%ecx)
565
566	movl	12(%esp),%esi			/* %esi = from */
567	movl	16(%esp),%edi			/* %edi = to */
568	movl	20(%esp),%edx			/* %edx = maxlen */
569
570	movl	$VM_MAXUSER_ADDRESS,%eax
571
572	/* make sure 'from' is within bounds */
573	subl	%esi,%eax
574	jbe	cpystrflt
575
576	/* restrict maxlen to <= VM_MAXUSER_ADDRESS-from */
577	cmpl	%edx,%eax
578	jae	1f
579	movl	%eax,%edx
580	movl	%eax,20(%esp)
5811:
582	incl	%edx
583	cld
584
5852:
586	decl	%edx
587	jz	3f
588
589	lodsb
590	stosb
591	orb	%al,%al
592	jnz	2b
593
594	/* Success -- 0 byte reached */
595	decl	%edx
596	xorl	%eax,%eax
597	jmp	cpystrflt_x
5983:
599	/* edx is zero - return ENAMETOOLONG or EFAULT */
600	cmpl	$VM_MAXUSER_ADDRESS,%esi
601	jae	cpystrflt
6024:
603	movl	$ENAMETOOLONG,%eax
604	jmp	cpystrflt_x
605
606cpystrflt:
607	movl	$EFAULT,%eax
608
609cpystrflt_x:
610	/* set *lencopied and return %eax */
611	movl	PCPU(CURPCB),%ecx
612	movl	$0,PCB_ONFAULT(%ecx)
613	movl	20(%esp),%ecx
614	subl	%edx,%ecx
615	movl	24(%esp),%edx
616	testl	%edx,%edx
617	jz	1f
618	movl	%ecx,(%edx)
6191:
620	popl	%edi
621	popl	%esi
622	ret
623END(copyinstr)
624
625/*
626 * copystr(from, to, maxlen, int *lencopied) - MP SAFE
627 */
628ENTRY(copystr)
629	pushl	%esi
630	pushl	%edi
631
632	movl	12(%esp),%esi			/* %esi = from */
633	movl	16(%esp),%edi			/* %edi = to */
634	movl	20(%esp),%edx			/* %edx = maxlen */
635	incl	%edx
636	cld
6371:
638	decl	%edx
639	jz	4f
640	lodsb
641	stosb
642	orb	%al,%al
643	jnz	1b
644
645	/* Success -- 0 byte reached */
646	decl	%edx
647	xorl	%eax,%eax
648	jmp	6f
6494:
650	/* edx is zero -- return ENAMETOOLONG */
651	movl	$ENAMETOOLONG,%eax
652
6536:
654	/* set *lencopied and return %eax */
655	movl	20(%esp),%ecx
656	subl	%edx,%ecx
657	movl	24(%esp),%edx
658	testl	%edx,%edx
659	jz	7f
660	movl	%ecx,(%edx)
6617:
662	popl	%edi
663	popl	%esi
664	ret
665END(copystr)
666
667ENTRY(bcmp)
668	pushl	%edi
669	pushl	%esi
670	movl	12(%esp),%edi
671	movl	16(%esp),%esi
672	movl	20(%esp),%edx
673
674	movl	%edx,%ecx
675	shrl	$2,%ecx
676	cld					/* compare forwards */
677	repe
678	cmpsl
679	jne	1f
680
681	movl	%edx,%ecx
682	andl	$3,%ecx
683	repe
684	cmpsb
6851:
686	setne	%al
687	movsbl	%al,%eax
688	popl	%esi
689	popl	%edi
690	ret
691END(bcmp)
692
693/*
694 * Handling of special 386 registers and descriptor tables etc
695 */
696/* void lgdt(struct region_descriptor *rdp); */
697ENTRY(lgdt)
698	/* reload the descriptor table */
699	movl	4(%esp),%eax
700	lgdt	(%eax)
701
702	/* flush the prefetch q */
703	jmp	1f
704	nop
7051:
706	/* reload "stale" selectors */
707	movl	$KDSEL,%eax
708	movl	%eax,%ds
709	movl	%eax,%es
710	movl	%eax,%gs
711	movl	%eax,%ss
712	movl	$KPSEL,%eax
713	movl	%eax,%fs
714
715	/* reload code selector by turning return into intersegmental return */
716	movl	(%esp),%eax
717	pushl	%eax
718	movl	$KCSEL,4(%esp)
719	MEXITCOUNT
720	lret
721END(lgdt)
722
723/* ssdtosd(*ssdp,*sdp) */
724ENTRY(ssdtosd)
725	pushl	%ebx
726	movl	8(%esp),%ecx
727	movl	8(%ecx),%ebx
728	shll	$16,%ebx
729	movl	(%ecx),%edx
730	roll	$16,%edx
731	movb	%dh,%bl
732	movb	%dl,%bh
733	rorl	$8,%ebx
734	movl	4(%ecx),%eax
735	movw	%ax,%dx
736	andl	$0xf0000,%eax
737	orl	%eax,%ebx
738	movl	12(%esp),%ecx
739	movl	%edx,(%ecx)
740	movl	%ebx,4(%ecx)
741	popl	%ebx
742	ret
743END(ssdtosd)
744
745/* void reset_dbregs() */
746ENTRY(reset_dbregs)
747	movl	$0,%eax
748	movl	%eax,%dr7	/* disable all breakpoints first */
749	movl	%eax,%dr0
750	movl	%eax,%dr1
751	movl	%eax,%dr2
752	movl	%eax,%dr3
753	movl	%eax,%dr6
754	ret
755END(reset_dbregs)
756
757/*****************************************************************************/
758/* setjump, longjump                                                         */
759/*****************************************************************************/
760
761ENTRY(setjmp)
762	movl	4(%esp),%eax
763	movl	%ebx,(%eax)			/* save ebx */
764	movl	%esp,4(%eax)			/* save esp */
765	movl	%ebp,8(%eax)			/* save ebp */
766	movl	%esi,12(%eax)			/* save esi */
767	movl	%edi,16(%eax)			/* save edi */
768	movl	(%esp),%edx			/* get rta */
769	movl	%edx,20(%eax)			/* save eip */
770	xorl	%eax,%eax			/* return(0); */
771	ret
772END(setjmp)
773
774ENTRY(longjmp)
775	movl	4(%esp),%eax
776	movl	(%eax),%ebx			/* restore ebx */
777	movl	4(%eax),%esp			/* restore esp */
778	movl	8(%eax),%ebp			/* restore ebp */
779	movl	12(%eax),%esi			/* restore esi */
780	movl	16(%eax),%edi			/* restore edi */
781	movl	20(%eax),%edx			/* get rta */
782	movl	%edx,(%esp)			/* put in return frame */
783	xorl	%eax,%eax			/* return(1); */
784	incl	%eax
785	ret
786END(longjmp)
787
788/*
789 * Support for reading MSRs in the safe manner.
790 */
791ENTRY(rdmsr_safe)
792/* int rdmsr_safe(u_int msr, uint64_t *data) */
793	movl	PCPU(CURPCB),%ecx
794	movl	$msr_onfault,PCB_ONFAULT(%ecx)
795
796	movl	4(%esp),%ecx
797	rdmsr
798	movl	8(%esp),%ecx
799	movl	%eax,(%ecx)
800	movl	%edx,4(%ecx)
801	xorl	%eax,%eax
802
803	movl	PCPU(CURPCB),%ecx
804	movl	%eax,PCB_ONFAULT(%ecx)
805
806	ret
807
808/*
809 * Support for writing MSRs in the safe manner.
810 */
811ENTRY(wrmsr_safe)
812/* int wrmsr_safe(u_int msr, uint64_t data) */
813	movl	PCPU(CURPCB),%ecx
814	movl	$msr_onfault,PCB_ONFAULT(%ecx)
815
816	movl	4(%esp),%ecx
817	movl	8(%esp),%eax
818	movl	12(%esp),%edx
819	wrmsr
820	xorl	%eax,%eax
821
822	movl	PCPU(CURPCB),%ecx
823	movl	%eax,PCB_ONFAULT(%ecx)
824
825	ret
826
827/*
828 * MSR operations fault handler
829 */
830	ALIGN_TEXT
831msr_onfault:
832	movl	PCPU(CURPCB),%ecx
833	movl	$0,PCB_ONFAULT(%ecx)
834	movl	$EFAULT,%eax
835	ret
836