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