xref: /dragonfly/sys/platform/pc64/x86_64/support.s (revision cae2835b)
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 * 3. 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 * bzero(ptr:%rdi, bytes:%rsi)
45 *
46 * Using rep stosq is 70% faster than a %rax loop and almost as fast as
47 * a %xmm0 loop on a modern intel cpu.
48 *
49 * Do not use non-termportal instructions here as we do not know the caller's
50 * intent.
51 */
52ENTRY(bzero)
53	movq	%rsi,%rcx
54	xorl	%eax,%eax
55	shrq	$3,%rcx
56	cld
57	rep
58	stosq
59	movq	%rsi,%rcx
60	andq	$7,%rcx
61	rep
62	stosb
63	ret
64
65/*
66 * pagezero(ptr:%rdi)
67 *
68 * Using rep stosq is nearly as fast as using %xmm0 on a modern intel cpu,
69 * and about 70% faster than a %rax loop.
70 *
71 * Do not use non-termportal instructions here as we do not know the caller's
72 * intent.
73 */
74ENTRY(pagezero)
75	movq	$PAGE_SIZE>>3,%rcx
76	xorl	%eax,%eax
77	cld
78	rep
79	stosq
80	ret
81
82/*
83 * bcmp(ptr:%rdi, ptr:%rsi, bytes:%rdx)
84 */
85ENTRY(bcmp)
86	movq	%rdx,%rcx
87	shrq	$3,%rcx
88	cld					/* compare forwards */
89	repe
90	cmpsq
91	jne	1f
92
93	movq	%rdx,%rcx
94	andq	$7,%rcx
95	repe
96	cmpsb
971:
98	setne	%al
99	movsbl	%al,%eax
100	ret
101
102/*
103 * bcopy(src:%rdi, dst:%rsi, cnt:%rdx)
104 *
105 * ws@tools.de (Wolfgang Solfrank, TooLs GmbH) +49-228-985800
106 */
107ENTRY(bcopy)
108	xchgq	%rsi,%rdi
109	movq	%rdx,%rcx
110
111	movq	%rdi,%rax
112	subq	%rsi,%rax
113	cmpq	%rcx,%rax			/* overlapping && src < dst? */
114	jb	1f
115
116	shrq	$3,%rcx				/* copy by 64-bit words */
117	cld					/* nope, copy forwards */
118	rep
119	movsq
120	movq	%rdx,%rcx
121	andq	$7,%rcx				/* any bytes left? */
122	rep
123	movsb
124	ret
125
126	ALIGN_TEXT
1271:
128	addq	%rcx,%rdi			/* copy backwards */
129	addq	%rcx,%rsi
130	decq	%rdi
131	decq	%rsi
132	andq	$7,%rcx				/* any fractional bytes? */
133	std
134	rep
135	movsb
136	movq	%rdx,%rcx			/* copy by 32-bit words */
137	shrq	$3,%rcx
138	subq	$7,%rsi
139	subq	$7,%rdi
140	rep
141	movsq
142	cld
143	ret
144
145ENTRY(reset_dbregs)
146	movq	$0x200,%rax   /* the manual says that bit 10 must be set to 1 */
147	movq    %rax,%dr7     /* disable all breapoints first */
148	movq    $0,%rax
149	movq    %rax,%dr0
150	movq    %rax,%dr1
151	movq    %rax,%dr2
152	movq    %rax,%dr3
153	movq    %rax,%dr6
154	ret
155
156/*
157 * memcpy(dst:%rdi, src:%rsi, bytes:%rdx)
158 *
159 * Note: memcpy does not support overlapping copies
160 */
161ENTRY(memcpy)
162	movq	%rdi,%r8
163	movq	%rdx,%rcx
164	shrq	$3,%rcx				/* copy by 64-bit words */
165	cld					/* copy forwards */
166	rep
167	movsq
168	movq	%rdx,%rcx
169	andq	$7,%rcx				/* any bytes left? */
170	rep
171	movsb
172	movq	%r8,%rax
173	ret
174
175/* fillw(pat, base, cnt) */
176/*       %rdi,%rsi, %rdx */
177ENTRY(fillw)
178	movq	%rdi,%rax
179	movq	%rsi,%rdi
180	movq	%rdx,%rcx
181	cld
182	rep
183	stosw
184	ret
185
186/*****************************************************************************/
187/* copyout and fubyte family                                                 */
188/*****************************************************************************/
189/*
190 * Access user memory from inside the kernel. These routines should be
191 * the only places that do this.
192 *
193 * These routines set curpcb->onfault for the time they execute. When a
194 * protection violation occurs inside the functions, the trap handler
195 * returns to *curpcb->onfault instead of the function.
196 */
197
198/*
199 * std_copyout(from_kernel, to_user, len)  - MP SAFE
200 *         %rdi,        %rsi,    %rdx
201 */
202ENTRY(std_copyout)
203	movq	PCPU(curthread),%rax
204	movq	TD_PCB(%rax), %rax
205	movq	$copyout_fault,PCB_ONFAULT(%rax)
206	movq	%rsp,PCB_ONFAULT_SP(%rax)
207	testq	%rdx,%rdx			/* anything to do? */
208	jz	done_copyout
209
210	/*
211	 * Check explicitly for non-user addresses.  If 486 write protection
212	 * is being used, this check is essential because we are in kernel
213	 * mode so the h/w does not provide any protection against writing
214	 * kernel addresses.
215	 */
216
217	/*
218	 * First, prevent address wrapping.
219	 */
220	movq	%rsi,%rax
221	addq	%rdx,%rax
222	jc	copyout_fault
223/*
224 * XXX STOP USING VM_MAX_USER_ADDRESS.
225 * It is an end address, not a max, so every time it is used correctly it
226 * looks like there is an off by one error, and of course it caused an off
227 * by one error in several places.
228 */
229	movq	$VM_MAX_USER_ADDRESS,%rcx
230	cmpq	%rcx,%rax
231	ja	copyout_fault
232
233	xchgq	%rdi,%rsi
234	/* bcopy(%rsi, %rdi, %rdx) */
235	movq	%rdx,%rcx
236
237	shrq	$3,%rcx
238	cld
239	rep
240	movsq
241	movb	%dl,%cl
242	andb	$7,%cl
243	rep
244	movsb
245
246done_copyout:
247	xorl	%eax,%eax
248	movq	PCPU(curthread),%rdx
249	movq	TD_PCB(%rdx), %rdx
250	movq	%rax,PCB_ONFAULT(%rdx)
251	ret
252
253	ALIGN_TEXT
254copyout_fault:
255	movq	PCPU(curthread),%rdx
256	movq	TD_PCB(%rdx), %rdx
257	movq	$0,PCB_ONFAULT(%rdx)
258	movq	$EFAULT,%rax
259	ret
260
261/*
262 * std_copyin(from_user, to_kernel, len) - MP SAFE
263 *        %rdi,      %rsi,      %rdx
264 */
265ENTRY(std_copyin)
266	movq	PCPU(curthread),%rax
267	movq	TD_PCB(%rax), %rax
268	movq	$copyin_fault,PCB_ONFAULT(%rax)
269	movq	%rsp,PCB_ONFAULT_SP(%rax)
270	testq	%rdx,%rdx			/* anything to do? */
271	jz	done_copyin
272
273	/*
274	 * make sure address is valid
275	 */
276	movq	%rdi,%rax
277	addq	%rdx,%rax
278	jc	copyin_fault
279	movq	$VM_MAX_USER_ADDRESS,%rcx
280	cmpq	%rcx,%rax
281	ja	copyin_fault
282
283	xchgq	%rdi,%rsi
284	movq	%rdx,%rcx
285	movb	%cl,%al
286	shrq	$3,%rcx				/* copy longword-wise */
287	cld
288	rep
289	movsq
290	movb	%al,%cl
291	andb	$7,%cl				/* copy remaining bytes */
292	rep
293	movsb
294
295done_copyin:
296	xorl	%eax,%eax
297	movq	PCPU(curthread),%rdx
298	movq	TD_PCB(%rdx), %rdx
299	movq	%rax,PCB_ONFAULT(%rdx)
300	ret
301
302	ALIGN_TEXT
303copyin_fault:
304	movq	PCPU(curthread),%rdx
305	movq	TD_PCB(%rdx), %rdx
306	movq	$0,PCB_ONFAULT(%rdx)
307	movq	$EFAULT,%rax
308	ret
309
310/*
311 * casuword32.  Compare and set user integer.  Returns -1 or the current value.
312 *        dst = %rdi, old = %rsi, new = %rdx
313 */
314ENTRY(casuword32)
315	movq	PCPU(curthread),%rcx
316	movq	TD_PCB(%rcx), %rcx
317	movq	$fusufault,PCB_ONFAULT(%rcx)
318	movq	%rsp,PCB_ONFAULT_SP(%rcx)
319
320	movq	$VM_MAX_USER_ADDRESS-4,%rax
321	cmpq	%rax,%rdi			/* verify address is valid */
322	ja	fusufault
323
324	movl	%esi,%eax			/* old */
325	lock
326	cmpxchgl %edx,(%rdi)			/* new = %edx */
327
328	/*
329	 * The old value is in %eax.  If the store succeeded it will be the
330	 * value we expected (old) from before the store, otherwise it will
331	 * be the current value.
332	 */
333
334	movq	PCPU(curthread),%rcx
335	movq	TD_PCB(%rcx), %rcx
336	movq	$0,PCB_ONFAULT(%rcx)
337	ret
338
339/*
340 * casuword.  Compare and set user word.  Returns -1 or the current value.
341 *        dst = %rdi, old = %rsi, new = %rdx
342 */
343ENTRY(casuword)
344	movq	PCPU(curthread),%rcx
345	movq	TD_PCB(%rcx), %rcx
346	movq	$fusufault,PCB_ONFAULT(%rcx)
347	movq	%rsp,PCB_ONFAULT_SP(%rcx)
348
349	movq	$VM_MAX_USER_ADDRESS-8,%rax
350	cmpq	%rax,%rdi			/* verify address is valid */
351	ja	fusufault
352
353	movq	%rsi,%rax			/* old */
354	lock
355	cmpxchgq %rdx,(%rdi)			/* new = %rdx */
356
357	/*
358	 * The old value is in %rax.  If the store succeeded it will be the
359	 * value we expected (old) from before the store, otherwise it will
360	 * be the current value.
361	 */
362
363	movq	PCPU(curthread),%rcx
364	movq	TD_PCB(%rcx), %rcx
365	movq	$0,PCB_ONFAULT(%rcx)
366	ret
367
368/*
369 * Fetch (load) a 64-bit word, a 32-bit word, a 16-bit word, or an 8-bit
370 * byte from user memory.  All these functions are MPSAFE.
371 * addr = %rdi
372 */
373
374ALTENTRY(fuword64)
375ENTRY(std_fuword)
376	movq	PCPU(curthread),%rcx
377	movq	TD_PCB(%rcx), %rcx
378	movq	$fusufault,PCB_ONFAULT(%rcx)
379	movq	%rsp,PCB_ONFAULT_SP(%rcx)
380
381	movq	$VM_MAX_USER_ADDRESS-8,%rax
382	cmpq	%rax,%rdi			/* verify address is valid */
383	ja	fusufault
384
385	movq	(%rdi),%rax
386	movq	$0,PCB_ONFAULT(%rcx)
387	ret
388
389ENTRY(fuword32)
390	movq	PCPU(curthread),%rcx
391	movq	TD_PCB(%rcx), %rcx
392	movq	$fusufault,PCB_ONFAULT(%rcx)
393	movq	%rsp,PCB_ONFAULT_SP(%rcx)
394
395	movq	$VM_MAX_USER_ADDRESS-4,%rax
396	cmpq	%rax,%rdi			/* verify address is valid */
397	ja	fusufault
398
399	movl	(%rdi),%eax
400	movq	$0,PCB_ONFAULT(%rcx)
401	ret
402
403/*
404 * fuswintr() and suswintr() are specialized variants of fuword16() and
405 * suword16(), respectively.  They are called from the profiling code,
406 * potentially at interrupt time.  If they fail, that's okay; good things
407 * will happen later.  They always fail for now, until the trap code is
408 * able to deal with this.
409 */
410ALTENTRY(suswintr)
411ENTRY(fuswintr)
412	movq	$-1,%rax
413	ret
414
415ENTRY(fuword16)
416	movq	PCPU(curthread),%rcx
417	movq	TD_PCB(%rcx), %rcx
418	movq	$fusufault,PCB_ONFAULT(%rcx)
419	movq	%rsp,PCB_ONFAULT_SP(%rcx)
420
421	movq	$VM_MAX_USER_ADDRESS-2,%rax
422	cmpq	%rax,%rdi
423	ja	fusufault
424
425	movzwl	(%rdi),%eax
426	movq	$0,PCB_ONFAULT(%rcx)
427	ret
428
429ENTRY(std_fubyte)
430	movq	PCPU(curthread),%rcx
431	movq	TD_PCB(%rcx), %rcx
432	movq	$fusufault,PCB_ONFAULT(%rcx)
433	movq	%rsp,PCB_ONFAULT_SP(%rcx)
434
435	movq	$VM_MAX_USER_ADDRESS-1,%rax
436	cmpq	%rax,%rdi
437	ja	fusufault
438
439	movzbl	(%rdi),%eax
440	movq	$0,PCB_ONFAULT(%rcx)
441	ret
442
443	ALIGN_TEXT
444fusufault:
445	movq	PCPU(curthread),%rcx
446	xorl	%eax,%eax
447	movq	TD_PCB(%rcx), %rcx
448	movq	%rax,PCB_ONFAULT(%rcx)
449	decq	%rax
450	ret
451
452/*
453 * Store a 64-bit word, a 32-bit word, a 16-bit word, or an 8-bit byte to
454 * user memory.  All these functions are MPSAFE.
455 *
456 * addr = %rdi, value = %rsi
457 *
458 * Write a long
459 */
460ALTENTRY(suword64)
461ENTRY(std_suword)
462	movq	PCPU(curthread),%rcx
463	movq	TD_PCB(%rcx), %rcx
464	movq	$fusufault,PCB_ONFAULT(%rcx)
465	movq	%rsp,PCB_ONFAULT_SP(%rcx)
466
467	movq	$VM_MAX_USER_ADDRESS-8,%rax
468	cmpq	%rax,%rdi			/* verify address validity */
469	ja	fusufault
470
471	movq	%rsi,(%rdi)
472	xorl	%eax,%eax
473	movq	PCPU(curthread),%rcx
474	movq	TD_PCB(%rcx), %rcx
475	movq	%rax,PCB_ONFAULT(%rcx)
476	ret
477
478/*
479 * Write an int
480 */
481ENTRY(std_suword32)
482	movq	PCPU(curthread),%rcx
483	movq	TD_PCB(%rcx), %rcx
484	movq	$fusufault,PCB_ONFAULT(%rcx)
485	movq	%rsp,PCB_ONFAULT_SP(%rcx)
486
487	movq	$VM_MAX_USER_ADDRESS-4,%rax
488	cmpq	%rax,%rdi			/* verify address validity */
489	ja	fusufault
490
491	movl	%esi,(%rdi)
492	xorl	%eax,%eax
493	movq	PCPU(curthread),%rcx
494	movq	TD_PCB(%rcx), %rcx
495	movq	%rax,PCB_ONFAULT(%rcx)
496	ret
497
498ENTRY(suword16)
499	movq	PCPU(curthread),%rcx
500	movq	TD_PCB(%rcx), %rcx
501	movq	$fusufault,PCB_ONFAULT(%rcx)
502	movq	%rsp,PCB_ONFAULT_SP(%rcx)
503
504	movq	$VM_MAX_USER_ADDRESS-2,%rax
505	cmpq	%rax,%rdi			/* verify address validity */
506	ja	fusufault
507
508	movw	%si,(%rdi)
509	xorl	%eax,%eax
510	movq	PCPU(curthread),%rcx		/* restore trashed register */
511	movq	TD_PCB(%rcx), %rcx
512	movq	%rax,PCB_ONFAULT(%rcx)
513	ret
514
515ENTRY(std_subyte)
516	movq	PCPU(curthread),%rcx
517	movq	TD_PCB(%rcx), %rcx
518	movq	$fusufault,PCB_ONFAULT(%rcx)
519	movq	%rsp,PCB_ONFAULT_SP(%rcx)
520
521	movq	$VM_MAX_USER_ADDRESS-1,%rax
522	cmpq	%rax,%rdi			/* verify address validity */
523	ja	fusufault
524
525	movl	%esi,%eax
526	movb	%al,(%rdi)
527	xorl	%eax,%eax
528	movq	PCPU(curthread),%rcx		/* restore trashed register */
529	movq	TD_PCB(%rcx), %rcx
530	movq	%rax,PCB_ONFAULT(%rcx)
531	ret
532
533/*
534 * std_copyinstr(from, to, maxlen, int *lencopied) - MP SAFE
535 *           %rdi, %rsi, %rdx, %rcx
536 *
537 *	copy a string from from to to, stop when a 0 character is reached.
538 *	return ENAMETOOLONG if string is longer than maxlen, and
539 *	EFAULT on protection violations. If lencopied is non-zero,
540 *	return the actual length in *lencopied.
541 */
542ENTRY(std_copyinstr)
543	movq	%rdx,%r8			/* %r8 = maxlen */
544	movq	%rcx,%r9			/* %r9 = *len */
545	xchgq	%rdi,%rsi			/* %rdi = from, %rsi = to */
546	movq	PCPU(curthread),%rcx
547	movq	TD_PCB(%rcx), %rcx
548	movq	$cpystrflt,PCB_ONFAULT(%rcx)
549	movq	%rsp,PCB_ONFAULT_SP(%rcx)
550
551	movq	$VM_MAX_USER_ADDRESS,%rax
552
553	/* make sure 'from' is within bounds */
554	subq	%rsi,%rax
555	jbe	cpystrflt
556
557	/* restrict maxlen to <= VM_MAX_USER_ADDRESS-from */
558	cmpq	%rdx,%rax
559	jae	1f
560	movq	%rax,%rdx
561	movq	%rax,%r8
5621:
563	incq	%rdx
564	cld
565
5662:
567	decq	%rdx
568	jz	3f
569
570	lodsb
571	stosb
572	orb	%al,%al
573	jnz	2b
574
575	/* Success -- 0 byte reached */
576	decq	%rdx
577	xorl	%eax,%eax
578	jmp	cpystrflt_x
5793:
580	/* rdx is zero - return ENAMETOOLONG or EFAULT */
581	movq	$VM_MAX_USER_ADDRESS,%rax
582	cmpq	%rax,%rsi
583	jae	cpystrflt
5844:
585	movq	$ENAMETOOLONG,%rax
586	jmp	cpystrflt_x
587
588cpystrflt:
589	movq	$EFAULT,%rax
590
591cpystrflt_x:
592	/* set *lencopied and return %eax */
593	movq	PCPU(curthread),%rcx
594	movq	TD_PCB(%rcx), %rcx
595	movq	$0,PCB_ONFAULT(%rcx)
596
597	testq	%r9,%r9
598	jz	1f
599	subq	%rdx,%r8
600	movq	%r8,(%r9)
6011:
602	ret
603
604
605/*
606 * copystr(from, to, maxlen, int *lencopied) - MP SAFE
607 *         %rdi, %rsi, %rdx, %rcx
608 */
609ENTRY(copystr)
610	movq	%rdx,%r8			/* %r8 = maxlen */
611
612	xchgq	%rdi,%rsi
613	incq	%rdx
614	cld
6151:
616	decq	%rdx
617	jz	4f
618	lodsb
619	stosb
620	orb	%al,%al
621	jnz	1b
622
623	/* Success -- 0 byte reached */
624	decq	%rdx
625	xorl	%eax,%eax
626	jmp	6f
6274:
628	/* rdx is zero -- return ENAMETOOLONG */
629	movq	$ENAMETOOLONG,%rax
630
6316:
632
633	testq	%rcx,%rcx
634	jz	7f
635	/* set *lencopied and return %rax */
636	subq	%rdx,%r8
637	movq	%r8,(%rcx)
6387:
639	ret
640
641/*
642 * Handling of special x86_64 registers and descriptor tables etc
643 * %rdi
644 */
645/* void lgdt(struct region_descriptor *rdp); */
646ENTRY(lgdt)
647	/* reload the descriptor table */
648	lgdt	(%rdi)
649
650	/* flush the prefetch q */
651	jmp	1f
652	nop
6531:
654	movl	$KDSEL,%eax
655	movl	%eax,%ds
656	movl	%eax,%es
657	movl	%eax,%fs	/* Beware, use wrmsr to set 64 bit base */
658	movl	%eax,%gs	/* Beware, use wrmsr to set 64 bit base */
659	movl	%eax,%ss
660
661	/* reload code selector by turning return into intersegmental return */
662	popq	%rax
663	pushq	$KCSEL
664	pushq	%rax
665	MEXITCOUNT
666	lretq
667
668/*****************************************************************************/
669/* setjmp, longjmp                                                           */
670/*****************************************************************************/
671
672ENTRY(setjmp)
673	movq	%rbx,0(%rdi)			/* save rbx */
674	movq	%rsp,8(%rdi)			/* save rsp */
675	movq	%rbp,16(%rdi)			/* save rbp */
676	movq	%r12,24(%rdi)			/* save r12 */
677	movq	%r13,32(%rdi)			/* save r13 */
678	movq	%r14,40(%rdi)			/* save r14 */
679	movq	%r15,48(%rdi)			/* save r15 */
680	movq	0(%rsp),%rdx			/* get rta */
681	movq	%rdx,56(%rdi)			/* save rip */
682	xorl	%eax,%eax			/* return(0); */
683	ret
684
685ENTRY(longjmp)
686	movq	0(%rdi),%rbx			/* restore rbx */
687	movq	8(%rdi),%rsp			/* restore rsp */
688	movq	16(%rdi),%rbp			/* restore rbp */
689	movq	24(%rdi),%r12			/* restore r12 */
690	movq	32(%rdi),%r13			/* restore r13 */
691	movq	40(%rdi),%r14			/* restore r14 */
692	movq	48(%rdi),%r15			/* restore r15 */
693	movq	56(%rdi),%rdx			/* get rta */
694	movq	%rdx,0(%rsp)			/* put in return frame */
695	xorl	%eax,%eax			/* return(1); */
696	incl	%eax
697	ret
698
699/*
700 * Support for reading MSRs in the safe manner.
701 */
702ENTRY(rdmsr_safe)
703/* int rdmsr_safe(u_int msr, uint64_t *data) */
704	movq	PCPU(curthread),%r8
705	movq	TD_PCB(%r8), %r8
706	movq	$msr_onfault,PCB_ONFAULT(%r8)
707	movq	%rsp,PCB_ONFAULT_SP(%r8)
708	movl	%edi,%ecx
709	rdmsr			/* Read MSR pointed by %ecx. Returns
710				   hi byte in edx, lo in %eax */
711	salq	$32,%rdx	/* sign-shift %rdx left */
712	movl	%eax,%eax	/* zero-extend %eax -> %rax */
713	orq	%rdx,%rax
714	movq	%rax,(%rsi)
715	xorq	%rax,%rax
716	movq	%rax,PCB_ONFAULT(%r8)
717	ret
718
719/*
720 * Support for writing MSRs in the safe manner.
721 */
722ENTRY(wrmsr_safe)
723/* int wrmsr_safe(u_int msr, uint64_t data) */
724	movq	PCPU(curthread),%r8
725	movq	TD_PCB(%r8), %r8
726	movq	$msr_onfault,PCB_ONFAULT(%r8)
727	movq    %rsp,PCB_ONFAULT_SP(%rcx)
728	movl	%edi,%ecx
729	movl	%esi,%eax
730	sarq	$32,%rsi
731	movl	%esi,%edx
732	wrmsr			/* Write MSR pointed by %ecx. Accepts
733				   hi byte in edx, lo in %eax. */
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