]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/amd64/amd64/support.S
Import mandoc 1.14.4
[FreeBSD/FreeBSD.git] / sys / amd64 / amd64 / support.S
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  * 3. 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/specialreg.h>
37 #include <machine/pmap.h>
38
39 #include "assym.inc"
40
41         .text
42
43 /* Address: %rdi */
44 ENTRY(pagezero_std)
45         PUSH_FRAME_POINTER
46         movq    $PAGE_SIZE/8,%rcx
47         xorl    %eax,%eax
48         rep
49         stosq
50         POP_FRAME_POINTER
51         ret
52 END(pagezero_std)
53
54 ENTRY(pagezero_erms)
55         PUSH_FRAME_POINTER
56         movq    $PAGE_SIZE,%rcx
57         xorl    %eax,%eax
58         rep
59         stosb
60         POP_FRAME_POINTER
61         ret
62 END(pagezero_erms)
63
64 /*
65  * pagecopy(%rdi=from, %rsi=to)
66  */
67 ENTRY(pagecopy)
68         PUSH_FRAME_POINTER
69         movq    $PAGE_SIZE/8,%rcx
70         movq    %rdi,%r9
71         movq    %rsi,%rdi
72         movq    %r9,%rsi
73         rep
74         movsq
75         POP_FRAME_POINTER
76         ret
77 END(pagecopy)
78
79 /* Address: %rdi */
80 ENTRY(sse2_pagezero)
81         PUSH_FRAME_POINTER
82         movq    $-PAGE_SIZE,%rdx
83         subq    %rdx,%rdi
84         xorl    %eax,%eax
85         jmp     1f
86         /*
87          * The loop takes 29 bytes.  Ensure that it doesn't cross a 32-byte
88          * cache line.
89          */
90         .p2align 5,0x90
91 1:
92         movnti  %rax,(%rdi,%rdx)
93         movnti  %rax,8(%rdi,%rdx)
94         movnti  %rax,16(%rdi,%rdx)
95         movnti  %rax,24(%rdi,%rdx)
96         addq    $32,%rdx
97         jne     1b
98         sfence
99         POP_FRAME_POINTER
100         ret
101 END(sse2_pagezero)
102
103 /*
104  * memmove(dst, src, cnt)
105  *         rdi, rsi, rdx
106  * Adapted from bcopy written by:
107  *  ws@tools.de     (Wolfgang Solfrank, TooLs GmbH) +49-228-985800
108  */
109 ENTRY(memmove_std)
110         PUSH_FRAME_POINTER
111         movq    %rdi,%rax
112         movq    %rdx,%rcx
113
114         movq    %rdi,%r8
115         subq    %rsi,%r8
116         cmpq    %rcx,%r8                        /* overlapping && src < dst? */
117         jb      2f
118
119         shrq    $3,%rcx                         /* copy by 64-bit words */
120         rep
121         movsq
122         movq    %rdx,%rcx
123         andq    $7,%rcx                         /* any bytes left? */
124         jne     1f
125         POP_FRAME_POINTER
126         ret
127 1:
128         rep
129         movsb
130         POP_FRAME_POINTER
131         ret
132
133         /* ALIGN_TEXT */
134 2:
135         addq    %rcx,%rdi                       /* copy backwards */
136         addq    %rcx,%rsi
137         decq    %rdi
138         decq    %rsi
139         std
140         andq    $7,%rcx                         /* any fractional bytes? */
141         je      3f
142         rep
143         movsb
144 3:
145         movq    %rdx,%rcx                       /* copy remainder by 32-bit words */
146         shrq    $3,%rcx
147         subq    $7,%rsi
148         subq    $7,%rdi
149         rep
150         movsq
151         cld
152         POP_FRAME_POINTER
153         ret
154 END(memmove_std)
155
156 ENTRY(memmove_erms)
157         PUSH_FRAME_POINTER
158         movq    %rdi,%rax
159         movq    %rdx,%rcx
160
161         movq    %rdi,%r8
162         subq    %rsi,%r8
163         cmpq    %rcx,%r8                        /* overlapping && src < dst? */
164         jb      1f
165
166         rep
167         movsb
168         POP_FRAME_POINTER
169         ret
170
171 1:
172         addq    %rcx,%rdi                       /* copy backwards */
173         addq    %rcx,%rsi
174         decq    %rdi
175         decq    %rsi
176         std
177         rep
178         movsb
179         cld
180         POP_FRAME_POINTER
181         ret
182 END(memmove_erms)
183
184 /*
185  * memcpy(dst, src, len)
186  *        rdi, rsi, rdx
187  *
188  * Note: memcpy does not support overlapping copies
189  */
190 ENTRY(memcpy_std)
191         PUSH_FRAME_POINTER
192         movq    %rdi,%rax
193         movq    %rdx,%rcx
194         shrq    $3,%rcx                         /* copy by 64-bit words */
195         rep
196         movsq
197         movq    %rdx,%rcx
198         andq    $7,%rcx                         /* any bytes left? */
199         jne     1f
200         POP_FRAME_POINTER
201         ret
202 1:
203         rep
204         movsb
205         POP_FRAME_POINTER
206         ret
207 END(memcpy_std)
208
209 ENTRY(memcpy_erms)
210         PUSH_FRAME_POINTER
211         movq    %rdi,%rax
212         movq    %rdx,%rcx
213         rep
214         movsb
215         POP_FRAME_POINTER
216         ret
217 END(memcpy_erms)
218
219 /*
220  * memset(dst, c,   len)
221  *        rdi, rsi, rdx
222  */
223 ENTRY(memset_std)
224         PUSH_FRAME_POINTER
225         movq    %rdi,%r9
226         movq    %rdx,%rcx
227         movzbq  %sil,%r8
228         movabs  $0x0101010101010101,%rax
229         imulq   %r8,%rax
230         shrq    $3,%rcx
231         rep
232         stosq
233         movq    %rdx,%rcx
234         andq    $7,%rcx
235         jne     1f
236         movq    %r9,%rax
237         POP_FRAME_POINTER
238         ret
239 1:
240         rep
241         stosb
242         movq    %r9,%rax
243         POP_FRAME_POINTER
244         ret
245 END(memset_std)
246
247 ENTRY(memset_erms)
248         PUSH_FRAME_POINTER
249         movq    %rdi,%r9
250         movq    %rdx,%rcx
251         movb    %sil,%al
252         rep
253         stosb
254         movq    %r9,%rax
255         POP_FRAME_POINTER
256         ret
257 END(memset_erms)
258
259 /* fillw(pat, base, cnt) */
260 /*       %rdi,%rsi, %rdx */
261 ENTRY(fillw)
262         PUSH_FRAME_POINTER
263         movq    %rdi,%rax
264         movq    %rsi,%rdi
265         movq    %rdx,%rcx
266         rep
267         stosw
268         POP_FRAME_POINTER
269         ret
270 END(fillw)
271
272 /*****************************************************************************/
273 /* copyout and fubyte family                                                 */
274 /*****************************************************************************/
275 /*
276  * Access user memory from inside the kernel. These routines should be
277  * the only places that do this.
278  *
279  * These routines set curpcb->pcb_onfault for the time they execute. When a
280  * protection violation occurs inside the functions, the trap handler
281  * returns to *curpcb->pcb_onfault instead of the function.
282  */
283
284 /*
285  * copyout(from_kernel, to_user, len)
286  *         %rdi,        %rsi,    %rdx
287  */
288 ENTRY(copyout_nosmap)
289         PUSH_FRAME_POINTER
290         movq    PCPU(CURPCB),%rax
291         movq    $copyout_fault,PCB_ONFAULT(%rax)
292         testq   %rdx,%rdx                       /* anything to do? */
293         jz      done_copyout
294
295         /*
296          * Check explicitly for non-user addresses.  This check is essential
297          * because it prevents usermode from writing into the kernel.  We do
298          * not verify anywhere else that the user did not specify a rogue
299          * address.
300          */
301         /*
302          * First, prevent address wrapping.
303          */
304         movq    %rsi,%rax
305         addq    %rdx,%rax
306         jc      copyout_fault
307 /*
308  * XXX STOP USING VM_MAXUSER_ADDRESS.
309  * It is an end address, not a max, so every time it is used correctly it
310  * looks like there is an off by one error, and of course it caused an off
311  * by one error in several places.
312  */
313         movq    $VM_MAXUSER_ADDRESS,%rcx
314         cmpq    %rcx,%rax
315         ja      copyout_fault
316
317         xchgq   %rdi,%rsi
318         /* bcopy(%rsi, %rdi, %rdx) */
319         movq    %rdx,%rcx
320
321         shrq    $3,%rcx
322         rep
323         movsq
324         movb    %dl,%cl
325         andb    $7,%cl
326         je      done_copyout
327         rep
328         movsb
329
330         jmp     done_copyout
331 END(copyout_nosmap)
332
333 ENTRY(copyout_smap)
334         PUSH_FRAME_POINTER
335         movq    PCPU(CURPCB),%rax
336         /* Trap entry clears PSL.AC */
337         movq    $copyout_fault,PCB_ONFAULT(%rax)
338         testq   %rdx,%rdx                       /* anything to do? */
339         jz      done_copyout
340
341         /*
342          * Check explicitly for non-user addresses.  If 486 write protection
343          * is being used, this check is essential because we are in kernel
344          * mode so the h/w does not provide any protection against writing
345          * kernel addresses.
346          */
347
348         /*
349          * First, prevent address wrapping.
350          */
351         movq    %rsi,%rax
352         addq    %rdx,%rax
353         jc      copyout_fault
354 /*
355  * XXX STOP USING VM_MAXUSER_ADDRESS.
356  * It is an end address, not a max, so every time it is used correctly it
357  * looks like there is an off by one error, and of course it caused an off
358  * by one error in several places.
359  */
360         movq    $VM_MAXUSER_ADDRESS,%rcx
361         cmpq    %rcx,%rax
362         ja      copyout_fault
363
364         xchgq   %rdi,%rsi
365         /* bcopy(%rsi, %rdi, %rdx) */
366         movq    %rdx,%rcx
367
368         shrq    $3,%rcx
369         stac
370         rep
371         movsq
372         movb    %dl,%cl
373         andb    $7,%cl
374         je      1f
375         rep
376         movsb
377 1:      clac
378
379 done_copyout:
380         xorl    %eax,%eax
381         movq    PCPU(CURPCB),%rdx
382         movq    %rax,PCB_ONFAULT(%rdx)
383         POP_FRAME_POINTER
384         ret
385
386         ALIGN_TEXT
387 copyout_fault:
388         movq    PCPU(CURPCB),%rdx
389         movq    $0,PCB_ONFAULT(%rdx)
390         movq    $EFAULT,%rax
391         POP_FRAME_POINTER
392         ret
393 END(copyout_smap)
394
395 /*
396  * copyin(from_user, to_kernel, len)
397  *        %rdi,      %rsi,      %rdx
398  */
399 ENTRY(copyin_nosmap)
400         PUSH_FRAME_POINTER
401         movq    PCPU(CURPCB),%rax
402         movq    $copyin_fault,PCB_ONFAULT(%rax)
403         testq   %rdx,%rdx                       /* anything to do? */
404         jz      done_copyin
405
406         /*
407          * make sure address is valid
408          */
409         movq    %rdi,%rax
410         addq    %rdx,%rax
411         jc      copyin_fault
412         movq    $VM_MAXUSER_ADDRESS,%rcx
413         cmpq    %rcx,%rax
414         ja      copyin_fault
415
416         xchgq   %rdi,%rsi
417         movq    %rdx,%rcx
418         movb    %cl,%al
419         shrq    $3,%rcx                         /* copy longword-wise */
420         rep
421         movsq
422         movb    %al,%cl
423         andb    $7,%cl                          /* copy remaining bytes */
424         je      done_copyin
425         rep
426         movsb
427
428         jmp     done_copyin
429 END(copyin_nosmap)
430
431 ENTRY(copyin_smap)
432         PUSH_FRAME_POINTER
433         movq    PCPU(CURPCB),%rax
434         movq    $copyin_fault,PCB_ONFAULT(%rax)
435         testq   %rdx,%rdx                       /* anything to do? */
436         jz      done_copyin
437
438         /*
439          * make sure address is valid
440          */
441         movq    %rdi,%rax
442         addq    %rdx,%rax
443         jc      copyin_fault
444         movq    $VM_MAXUSER_ADDRESS,%rcx
445         cmpq    %rcx,%rax
446         ja      copyin_fault
447
448         xchgq   %rdi,%rsi
449         movq    %rdx,%rcx
450         movb    %cl,%al
451         shrq    $3,%rcx                         /* copy longword-wise */
452         stac
453         rep
454         movsq
455         movb    %al,%cl
456         andb    $7,%cl                          /* copy remaining bytes */
457         je      1f
458         rep
459         movsb
460 1:      clac
461
462 done_copyin:
463         xorl    %eax,%eax
464         movq    PCPU(CURPCB),%rdx
465         movq    %rax,PCB_ONFAULT(%rdx)
466         POP_FRAME_POINTER
467         ret
468 END(copyin_smap)
469
470         ALIGN_TEXT
471 copyin_fault:
472         movq    PCPU(CURPCB),%rdx
473         movq    $0,PCB_ONFAULT(%rdx)
474         movq    $EFAULT,%rax
475         POP_FRAME_POINTER
476         ret
477
478 /*
479  * casueword32.  Compare and set user integer.  Returns -1 on fault,
480  *        0 if access was successful.  Old value is written to *oldp.
481  *        dst = %rdi, old = %esi, oldp = %rdx, new = %ecx
482  */
483 ENTRY(casueword32_nosmap)
484         PUSH_FRAME_POINTER
485         movq    PCPU(CURPCB),%r8
486         movq    $fusufault,PCB_ONFAULT(%r8)
487
488         movq    $VM_MAXUSER_ADDRESS-4,%rax
489         cmpq    %rax,%rdi                       /* verify address is valid */
490         ja      fusufault
491
492         movl    %esi,%eax                       /* old */
493 #ifdef SMP
494         lock
495 #endif
496         cmpxchgl %ecx,(%rdi)                    /* new = %ecx */
497
498         /*
499          * The old value is in %eax.  If the store succeeded it will be the
500          * value we expected (old) from before the store, otherwise it will
501          * be the current value.  Save %eax into %esi to prepare the return
502          * value.
503          */
504         movl    %eax,%esi
505         xorl    %eax,%eax
506         movq    %rax,PCB_ONFAULT(%r8)
507
508         /*
509          * Access the oldp after the pcb_onfault is cleared, to correctly
510          * catch corrupted pointer.
511          */
512         movl    %esi,(%rdx)                     /* oldp = %rdx */
513         POP_FRAME_POINTER
514         ret
515 END(casueword32_nosmap)
516
517 ENTRY(casueword32_smap)
518         PUSH_FRAME_POINTER
519         movq    PCPU(CURPCB),%r8
520         movq    $fusufault,PCB_ONFAULT(%r8)
521
522         movq    $VM_MAXUSER_ADDRESS-4,%rax
523         cmpq    %rax,%rdi                       /* verify address is valid */
524         ja      fusufault
525
526         movl    %esi,%eax                       /* old */
527         stac
528 #ifdef SMP
529         lock
530 #endif
531         cmpxchgl %ecx,(%rdi)                    /* new = %ecx */
532         clac
533
534         /*
535          * The old value is in %eax.  If the store succeeded it will be the
536          * value we expected (old) from before the store, otherwise it will
537          * be the current value.  Save %eax into %esi to prepare the return
538          * value.
539          */
540         movl    %eax,%esi
541         xorl    %eax,%eax
542         movq    %rax,PCB_ONFAULT(%r8)
543
544         /*
545          * Access the oldp after the pcb_onfault is cleared, to correctly
546          * catch corrupted pointer.
547          */
548         movl    %esi,(%rdx)                     /* oldp = %rdx */
549         POP_FRAME_POINTER
550         ret
551 END(casueword32_smap)
552
553 /*
554  * casueword.  Compare and set user long.  Returns -1 on fault,
555  *        0 if access was successful.  Old value is written to *oldp.
556  *        dst = %rdi, old = %rsi, oldp = %rdx, new = %rcx
557  */
558 ENTRY(casueword_nosmap)
559         PUSH_FRAME_POINTER
560         movq    PCPU(CURPCB),%r8
561         movq    $fusufault,PCB_ONFAULT(%r8)
562
563         movq    $VM_MAXUSER_ADDRESS-4,%rax
564         cmpq    %rax,%rdi                       /* verify address is valid */
565         ja      fusufault
566
567         movq    %rsi,%rax                       /* old */
568 #ifdef SMP
569         lock
570 #endif
571         cmpxchgq %rcx,(%rdi)                    /* new = %rcx */
572
573         /*
574          * The old value is in %rax.  If the store succeeded it will be the
575          * value we expected (old) from before the store, otherwise it will
576          * be the current value.
577          */
578         movq    %rax,%rsi
579         xorl    %eax,%eax
580         movq    %rax,PCB_ONFAULT(%r8)
581         movq    %rsi,(%rdx)
582         POP_FRAME_POINTER
583         ret
584 END(casueword_nosmap)
585
586 ENTRY(casueword_smap)
587         PUSH_FRAME_POINTER
588         movq    PCPU(CURPCB),%r8
589         movq    $fusufault,PCB_ONFAULT(%r8)
590
591         movq    $VM_MAXUSER_ADDRESS-4,%rax
592         cmpq    %rax,%rdi                       /* verify address is valid */
593         ja      fusufault
594
595         movq    %rsi,%rax                       /* old */
596         stac
597 #ifdef SMP
598         lock
599 #endif
600         cmpxchgq %rcx,(%rdi)                    /* new = %rcx */
601         clac
602
603         /*
604          * The old value is in %rax.  If the store succeeded it will be the
605          * value we expected (old) from before the store, otherwise it will
606          * be the current value.
607          */
608         movq    %rax,%rsi
609         xorl    %eax,%eax
610         movq    %rax,PCB_ONFAULT(%r8)
611         movq    %rsi,(%rdx)
612         POP_FRAME_POINTER
613         ret
614 END(casueword_smap)
615
616 /*
617  * Fetch (load) a 64-bit word, a 32-bit word, a 16-bit word, or an 8-bit
618  * byte from user memory.
619  * addr = %rdi, valp = %rsi
620  */
621
622 ENTRY(fueword_nosmap)
623         PUSH_FRAME_POINTER
624         movq    PCPU(CURPCB),%rcx
625         movq    $fusufault,PCB_ONFAULT(%rcx)
626
627         movq    $VM_MAXUSER_ADDRESS-8,%rax
628         cmpq    %rax,%rdi                       /* verify address is valid */
629         ja      fusufault
630
631         xorl    %eax,%eax
632         movq    (%rdi),%r11
633         movq    %rax,PCB_ONFAULT(%rcx)
634         movq    %r11,(%rsi)
635         POP_FRAME_POINTER
636         ret
637 END(fueword_nosmap)
638
639 ENTRY(fueword_smap)
640         PUSH_FRAME_POINTER
641         movq    PCPU(CURPCB),%rcx
642         movq    $fusufault,PCB_ONFAULT(%rcx)
643
644         movq    $VM_MAXUSER_ADDRESS-8,%rax
645         cmpq    %rax,%rdi                       /* verify address is valid */
646         ja      fusufault
647
648         xorl    %eax,%eax
649         stac
650         movq    (%rdi),%r11
651         clac
652         movq    %rax,PCB_ONFAULT(%rcx)
653         movq    %r11,(%rsi)
654         POP_FRAME_POINTER
655         ret
656 END(fueword_smap)
657
658 ENTRY(fueword32_nosmap)
659         PUSH_FRAME_POINTER
660         movq    PCPU(CURPCB),%rcx
661         movq    $fusufault,PCB_ONFAULT(%rcx)
662
663         movq    $VM_MAXUSER_ADDRESS-4,%rax
664         cmpq    %rax,%rdi                       /* verify address is valid */
665         ja      fusufault
666
667         xorl    %eax,%eax
668         movl    (%rdi),%r11d
669         movq    %rax,PCB_ONFAULT(%rcx)
670         movl    %r11d,(%rsi)
671         POP_FRAME_POINTER
672         ret
673 END(fueword32_nosmap)
674
675 ENTRY(fueword32_smap)
676         PUSH_FRAME_POINTER
677         movq    PCPU(CURPCB),%rcx
678         movq    $fusufault,PCB_ONFAULT(%rcx)
679
680         movq    $VM_MAXUSER_ADDRESS-4,%rax
681         cmpq    %rax,%rdi                       /* verify address is valid */
682         ja      fusufault
683
684         xorl    %eax,%eax
685         stac
686         movl    (%rdi),%r11d
687         clac
688         movq    %rax,PCB_ONFAULT(%rcx)
689         movl    %r11d,(%rsi)
690         POP_FRAME_POINTER
691         ret
692 END(fueword32_smap)
693
694 ENTRY(fuword16_nosmap)
695         PUSH_FRAME_POINTER
696         movq    PCPU(CURPCB),%rcx
697         movq    $fusufault,PCB_ONFAULT(%rcx)
698
699         movq    $VM_MAXUSER_ADDRESS-2,%rax
700         cmpq    %rax,%rdi
701         ja      fusufault
702
703         movzwl  (%rdi),%eax
704         movq    $0,PCB_ONFAULT(%rcx)
705         POP_FRAME_POINTER
706         ret
707 END(fuword16_nosmap)
708
709 ENTRY(fuword16_smap)
710         PUSH_FRAME_POINTER
711         movq    PCPU(CURPCB),%rcx
712         movq    $fusufault,PCB_ONFAULT(%rcx)
713
714         movq    $VM_MAXUSER_ADDRESS-2,%rax
715         cmpq    %rax,%rdi
716         ja      fusufault
717
718         stac
719         movzwl  (%rdi),%eax
720         clac
721         movq    $0,PCB_ONFAULT(%rcx)
722         POP_FRAME_POINTER
723         ret
724 END(fuword16_smap)
725
726 ENTRY(fubyte_nosmap)
727         PUSH_FRAME_POINTER
728         movq    PCPU(CURPCB),%rcx
729         movq    $fusufault,PCB_ONFAULT(%rcx)
730
731         movq    $VM_MAXUSER_ADDRESS-1,%rax
732         cmpq    %rax,%rdi
733         ja      fusufault
734
735         movzbl  (%rdi),%eax
736         movq    $0,PCB_ONFAULT(%rcx)
737         POP_FRAME_POINTER
738         ret
739 END(fubyte_nosmap)
740
741 ENTRY(fubyte_smap)
742         PUSH_FRAME_POINTER
743         movq    PCPU(CURPCB),%rcx
744         movq    $fusufault,PCB_ONFAULT(%rcx)
745
746         movq    $VM_MAXUSER_ADDRESS-1,%rax
747         cmpq    %rax,%rdi
748         ja      fusufault
749
750         stac
751         movzbl  (%rdi),%eax
752         clac
753         movq    $0,PCB_ONFAULT(%rcx)
754         POP_FRAME_POINTER
755         ret
756 END(fubyte_smap)
757
758         ALIGN_TEXT
759         /* Fault entry clears PSL.AC */
760 fusufault:
761         movq    PCPU(CURPCB),%rcx
762         xorl    %eax,%eax
763         movq    %rax,PCB_ONFAULT(%rcx)
764         decq    %rax
765         POP_FRAME_POINTER
766         ret
767
768 /*
769  * Store a 64-bit word, a 32-bit word, a 16-bit word, or an 8-bit byte to
770  * user memory.
771  * addr = %rdi, value = %rsi
772  */
773 ENTRY(suword_nosmap)
774         PUSH_FRAME_POINTER
775         movq    PCPU(CURPCB),%rcx
776         movq    $fusufault,PCB_ONFAULT(%rcx)
777
778         movq    $VM_MAXUSER_ADDRESS-8,%rax
779         cmpq    %rax,%rdi                       /* verify address validity */
780         ja      fusufault
781
782         movq    %rsi,(%rdi)
783         xorl    %eax,%eax
784         movq    PCPU(CURPCB),%rcx
785         movq    %rax,PCB_ONFAULT(%rcx)
786         POP_FRAME_POINTER
787         ret
788 END(suword_nosmap)
789
790 ENTRY(suword_smap)
791         PUSH_FRAME_POINTER
792         movq    PCPU(CURPCB),%rcx
793         movq    $fusufault,PCB_ONFAULT(%rcx)
794
795         movq    $VM_MAXUSER_ADDRESS-8,%rax
796         cmpq    %rax,%rdi                       /* verify address validity */
797         ja      fusufault
798
799         stac
800         movq    %rsi,(%rdi)
801         clac
802         xorl    %eax,%eax
803         movq    PCPU(CURPCB),%rcx
804         movq    %rax,PCB_ONFAULT(%rcx)
805         POP_FRAME_POINTER
806         ret
807 END(suword_smap)
808
809 ENTRY(suword32_nosmap)
810         PUSH_FRAME_POINTER
811         movq    PCPU(CURPCB),%rcx
812         movq    $fusufault,PCB_ONFAULT(%rcx)
813
814         movq    $VM_MAXUSER_ADDRESS-4,%rax
815         cmpq    %rax,%rdi                       /* verify address validity */
816         ja      fusufault
817
818         movl    %esi,(%rdi)
819         xorl    %eax,%eax
820         movq    PCPU(CURPCB),%rcx
821         movq    %rax,PCB_ONFAULT(%rcx)
822         POP_FRAME_POINTER
823         ret
824 END(suword32_nosmap)
825
826 ENTRY(suword32_smap)
827         PUSH_FRAME_POINTER
828         movq    PCPU(CURPCB),%rcx
829         movq    $fusufault,PCB_ONFAULT(%rcx)
830
831         movq    $VM_MAXUSER_ADDRESS-4,%rax
832         cmpq    %rax,%rdi                       /* verify address validity */
833         ja      fusufault
834
835         stac
836         movl    %esi,(%rdi)
837         clac
838         xorl    %eax,%eax
839         movq    PCPU(CURPCB),%rcx
840         movq    %rax,PCB_ONFAULT(%rcx)
841         POP_FRAME_POINTER
842         ret
843 END(suword32_smap)
844
845 ENTRY(suword16_nosmap)
846         PUSH_FRAME_POINTER
847         movq    PCPU(CURPCB),%rcx
848         movq    $fusufault,PCB_ONFAULT(%rcx)
849
850         movq    $VM_MAXUSER_ADDRESS-2,%rax
851         cmpq    %rax,%rdi                       /* verify address validity */
852         ja      fusufault
853
854         movw    %si,(%rdi)
855         xorl    %eax,%eax
856         movq    PCPU(CURPCB),%rcx               /* restore trashed register */
857         movq    %rax,PCB_ONFAULT(%rcx)
858         POP_FRAME_POINTER
859         ret
860 END(suword16_nosmap)
861
862 ENTRY(suword16_smap)
863         PUSH_FRAME_POINTER
864         movq    PCPU(CURPCB),%rcx
865         movq    $fusufault,PCB_ONFAULT(%rcx)
866
867         movq    $VM_MAXUSER_ADDRESS-2,%rax
868         cmpq    %rax,%rdi                       /* verify address validity */
869         ja      fusufault
870
871         stac
872         movw    %si,(%rdi)
873         clac
874         xorl    %eax,%eax
875         movq    PCPU(CURPCB),%rcx               /* restore trashed register */
876         movq    %rax,PCB_ONFAULT(%rcx)
877         POP_FRAME_POINTER
878         ret
879 END(suword16_smap)
880
881 ENTRY(subyte_nosmap)
882         PUSH_FRAME_POINTER
883         movq    PCPU(CURPCB),%rcx
884         movq    $fusufault,PCB_ONFAULT(%rcx)
885
886         movq    $VM_MAXUSER_ADDRESS-1,%rax
887         cmpq    %rax,%rdi                       /* verify address validity */
888         ja      fusufault
889
890         movl    %esi,%eax
891         movb    %al,(%rdi)
892         xorl    %eax,%eax
893         movq    PCPU(CURPCB),%rcx               /* restore trashed register */
894         movq    %rax,PCB_ONFAULT(%rcx)
895         POP_FRAME_POINTER
896         ret
897 END(subyte_nosmap)
898
899 ENTRY(subyte_smap)
900         PUSH_FRAME_POINTER
901         movq    PCPU(CURPCB),%rcx
902         movq    $fusufault,PCB_ONFAULT(%rcx)
903
904         movq    $VM_MAXUSER_ADDRESS-1,%rax
905         cmpq    %rax,%rdi                       /* verify address validity */
906         ja      fusufault
907
908         movl    %esi,%eax
909         stac
910         movb    %al,(%rdi)
911         clac
912         xorl    %eax,%eax
913         movq    PCPU(CURPCB),%rcx               /* restore trashed register */
914         movq    %rax,PCB_ONFAULT(%rcx)
915         POP_FRAME_POINTER
916         ret
917 END(subyte_smap)
918
919 /*
920  * copyinstr(from, to, maxlen, int *lencopied)
921  *           %rdi, %rsi, %rdx, %rcx
922  *
923  *      copy a string from 'from' to 'to', stop when a 0 character is reached.
924  *      return ENAMETOOLONG if string is longer than maxlen, and
925  *      EFAULT on protection violations. If lencopied is non-zero,
926  *      return the actual length in *lencopied.
927  */
928 ENTRY(copyinstr_nosmap)
929         PUSH_FRAME_POINTER
930         movq    %rdx,%r8                        /* %r8 = maxlen */
931         movq    %rcx,%r9                        /* %r9 = *len */
932         xchgq   %rdi,%rsi                       /* %rdi = from, %rsi = to */
933         movq    PCPU(CURPCB),%rcx
934         movq    $cpystrflt,PCB_ONFAULT(%rcx)
935
936         movq    $VM_MAXUSER_ADDRESS,%rax
937
938         /* make sure 'from' is within bounds */
939         subq    %rsi,%rax
940         jbe     cpystrflt
941
942         /* restrict maxlen to <= VM_MAXUSER_ADDRESS-from */
943         cmpq    %rdx,%rax
944         jae     1f
945         movq    %rax,%rdx
946         movq    %rax,%r8
947 1:
948         incq    %rdx
949
950 2:
951         decq    %rdx
952         jz      copyinstr_toolong
953
954         lodsb
955         stosb
956         orb     %al,%al
957         jnz     2b
958
959         jmp     copyinstr_succ
960 END(copyinstr_nosmap)
961
962 ENTRY(copyinstr_smap)
963         PUSH_FRAME_POINTER
964         movq    %rdx,%r8                        /* %r8 = maxlen */
965         movq    %rcx,%r9                        /* %r9 = *len */
966         xchgq   %rdi,%rsi                       /* %rdi = from, %rsi = to */
967         movq    PCPU(CURPCB),%rcx
968         movq    $cpystrflt,PCB_ONFAULT(%rcx)
969
970         movq    $VM_MAXUSER_ADDRESS,%rax
971
972         /* make sure 'from' is within bounds */
973         subq    %rsi,%rax
974         jbe     cpystrflt
975
976         stac
977
978         /* restrict maxlen to <= VM_MAXUSER_ADDRESS-from */
979         cmpq    %rdx,%rax
980         jae     1f
981         movq    %rax,%rdx
982         movq    %rax,%r8
983 1:
984         incq    %rdx
985
986 2:
987         decq    %rdx
988         jz      copyinstr_toolong_smap
989
990         lodsb
991         stosb
992         orb     %al,%al
993         jnz     2b
994
995         clac
996
997 copyinstr_succ:
998         /* Success -- 0 byte reached */
999         decq    %rdx
1000         xorl    %eax,%eax
1001
1002 cpystrflt_x:
1003         /* set *lencopied and return %eax */
1004         movq    PCPU(CURPCB),%rcx
1005         movq    $0,PCB_ONFAULT(%rcx)
1006
1007         testq   %r9,%r9
1008         jz      1f
1009         subq    %rdx,%r8
1010         movq    %r8,(%r9)
1011 1:
1012         POP_FRAME_POINTER
1013         ret
1014         /* Fault entry clears PSL.AC */
1015 cpystrflt:
1016         movq    $EFAULT,%rax
1017         jmp     cpystrflt_x
1018
1019 copyinstr_toolong_smap:
1020         clac
1021 copyinstr_toolong:
1022         /* rdx is zero - return ENAMETOOLONG or EFAULT */
1023         movq    $VM_MAXUSER_ADDRESS,%rax
1024         cmpq    %rax,%rsi
1025         jae     cpystrflt
1026         movq    $ENAMETOOLONG,%rax
1027         jmp     cpystrflt_x
1028
1029 END(copyinstr_smap)
1030
1031 /*
1032  * copystr(from, to, maxlen, int *lencopied)
1033  *         %rdi, %rsi, %rdx, %rcx
1034  */
1035 ENTRY(copystr)
1036         PUSH_FRAME_POINTER
1037         movq    %rdx,%r8                        /* %r8 = maxlen */
1038
1039         xchgq   %rdi,%rsi
1040         incq    %rdx
1041 1:
1042         decq    %rdx
1043         jz      4f
1044         lodsb
1045         stosb
1046         orb     %al,%al
1047         jnz     1b
1048
1049         /* Success -- 0 byte reached */
1050         decq    %rdx
1051         xorl    %eax,%eax
1052         jmp     6f
1053 4:
1054         /* rdx is zero -- return ENAMETOOLONG */
1055         movq    $ENAMETOOLONG,%rax
1056
1057 6:
1058
1059         testq   %rcx,%rcx
1060         jz      7f
1061         /* set *lencopied and return %rax */
1062         subq    %rdx,%r8
1063         movq    %r8,(%rcx)
1064 7:
1065         POP_FRAME_POINTER
1066         ret
1067 END(copystr)
1068
1069 /*
1070  * Handling of special amd64 registers and descriptor tables etc
1071  */
1072 /* void lgdt(struct region_descriptor *rdp); */
1073 ENTRY(lgdt)
1074         /* reload the descriptor table */
1075         lgdt    (%rdi)
1076
1077         /* flush the prefetch q */
1078         jmp     1f
1079         nop
1080 1:
1081         movl    $KDSEL,%eax
1082         movl    %eax,%ds
1083         movl    %eax,%es
1084         movl    %eax,%fs        /* Beware, use wrmsr to set 64 bit base */
1085         movl    %eax,%gs
1086         movl    %eax,%ss
1087
1088         /* reload code selector by turning return into intersegmental return */
1089         popq    %rax
1090         pushq   $KCSEL
1091         pushq   %rax
1092         MEXITCOUNT
1093         lretq
1094 END(lgdt)
1095
1096 /*****************************************************************************/
1097 /* setjump, longjump                                                         */
1098 /*****************************************************************************/
1099
1100 ENTRY(setjmp)
1101         movq    %rbx,0(%rdi)                    /* save rbx */
1102         movq    %rsp,8(%rdi)                    /* save rsp */
1103         movq    %rbp,16(%rdi)                   /* save rbp */
1104         movq    %r12,24(%rdi)                   /* save r12 */
1105         movq    %r13,32(%rdi)                   /* save r13 */
1106         movq    %r14,40(%rdi)                   /* save r14 */
1107         movq    %r15,48(%rdi)                   /* save r15 */
1108         movq    0(%rsp),%rdx                    /* get rta */
1109         movq    %rdx,56(%rdi)                   /* save rip */
1110         xorl    %eax,%eax                       /* return(0); */
1111         ret
1112 END(setjmp)
1113
1114 ENTRY(longjmp)
1115         movq    0(%rdi),%rbx                    /* restore rbx */
1116         movq    8(%rdi),%rsp                    /* restore rsp */
1117         movq    16(%rdi),%rbp                   /* restore rbp */
1118         movq    24(%rdi),%r12                   /* restore r12 */
1119         movq    32(%rdi),%r13                   /* restore r13 */
1120         movq    40(%rdi),%r14                   /* restore r14 */
1121         movq    48(%rdi),%r15                   /* restore r15 */
1122         movq    56(%rdi),%rdx                   /* get rta */
1123         movq    %rdx,0(%rsp)                    /* put in return frame */
1124         xorl    %eax,%eax                       /* return(1); */
1125         incl    %eax
1126         ret
1127 END(longjmp)
1128
1129 /*
1130  * Support for reading MSRs in the safe manner.  (Instead of panic on #gp,
1131  * return an error.)
1132  */
1133 ENTRY(rdmsr_safe)
1134 /* int rdmsr_safe(u_int msr, uint64_t *data) */
1135         PUSH_FRAME_POINTER
1136         movq    PCPU(CURPCB),%r8
1137         movq    $msr_onfault,PCB_ONFAULT(%r8)
1138         movl    %edi,%ecx
1139         rdmsr                   /* Read MSR pointed by %ecx. Returns
1140                                    hi byte in edx, lo in %eax */
1141         salq    $32,%rdx        /* sign-shift %rdx left */
1142         movl    %eax,%eax       /* zero-extend %eax -> %rax */
1143         orq     %rdx,%rax
1144         movq    %rax,(%rsi)
1145         xorq    %rax,%rax
1146         movq    %rax,PCB_ONFAULT(%r8)
1147         POP_FRAME_POINTER
1148         ret
1149
1150 /*
1151  * Support for writing MSRs in the safe manner.  (Instead of panic on #gp,
1152  * return an error.)
1153  */
1154 ENTRY(wrmsr_safe)
1155 /* int wrmsr_safe(u_int msr, uint64_t data) */
1156         PUSH_FRAME_POINTER
1157         movq    PCPU(CURPCB),%r8
1158         movq    $msr_onfault,PCB_ONFAULT(%r8)
1159         movl    %edi,%ecx
1160         movl    %esi,%eax
1161         sarq    $32,%rsi
1162         movl    %esi,%edx
1163         wrmsr                   /* Write MSR pointed by %ecx. Accepts
1164                                    hi byte in edx, lo in %eax. */
1165         xorq    %rax,%rax
1166         movq    %rax,PCB_ONFAULT(%r8)
1167         POP_FRAME_POINTER
1168         ret
1169
1170 /*
1171  * MSR operations fault handler
1172  */
1173         ALIGN_TEXT
1174 msr_onfault:
1175         movq    $0,PCB_ONFAULT(%r8)
1176         movl    $EFAULT,%eax
1177         POP_FRAME_POINTER
1178         ret
1179
1180 /*
1181  * void pmap_pti_pcid_invalidate(uint64_t ucr3, uint64_t kcr3);
1182  * Invalidates address space addressed by ucr3, then returns to kcr3.
1183  * Done in assembler to ensure no other memory accesses happen while
1184  * on ucr3.
1185  */
1186         ALIGN_TEXT
1187 ENTRY(pmap_pti_pcid_invalidate)
1188         pushfq
1189         cli
1190         movq    %rdi,%cr3       /* to user page table */
1191         movq    %rsi,%cr3       /* back to kernel */
1192         popfq
1193         retq
1194
1195 /*
1196  * void pmap_pti_pcid_invlpg(uint64_t ucr3, uint64_t kcr3, vm_offset_t va);
1197  * Invalidates virtual address va in address space ucr3, then returns to kcr3.
1198  */
1199         ALIGN_TEXT
1200 ENTRY(pmap_pti_pcid_invlpg)
1201         pushfq
1202         cli
1203         movq    %rdi,%cr3       /* to user page table */
1204         invlpg  (%rdx)
1205         movq    %rsi,%cr3       /* back to kernel */
1206         popfq
1207         retq
1208
1209 /*
1210  * void pmap_pti_pcid_invlrng(uint64_t ucr3, uint64_t kcr3, vm_offset_t sva,
1211  *     vm_offset_t eva);
1212  * Invalidates virtual addresses between sva and eva in address space ucr3,
1213  * then returns to kcr3.
1214  */
1215         ALIGN_TEXT
1216 ENTRY(pmap_pti_pcid_invlrng)
1217         pushfq
1218         cli
1219         movq    %rdi,%cr3       /* to user page table */
1220 1:      invlpg  (%rdx)
1221         addq    $PAGE_SIZE,%rdx
1222         cmpq    %rdx,%rcx
1223         ja      1b
1224         movq    %rsi,%cr3       /* back to kernel */
1225         popfq
1226         retq
1227
1228         .altmacro
1229         .macro  ibrs_seq_label l
1230 handle_ibrs_\l:
1231         .endm
1232         .macro  ibrs_call_label l
1233         call    handle_ibrs_\l
1234         .endm
1235         .macro  ibrs_seq count
1236         ll=1
1237         .rept   \count
1238         ibrs_call_label %(ll)
1239         nop
1240         ibrs_seq_label %(ll)
1241         addq    $8,%rsp
1242         ll=ll+1
1243         .endr
1244         .endm
1245
1246 /* all callers already saved %rax, %rdx, and %rcx */
1247 ENTRY(handle_ibrs_entry)
1248         cmpb    $0,hw_ibrs_active(%rip)
1249         je      1f
1250         movl    $MSR_IA32_SPEC_CTRL,%ecx
1251         rdmsr
1252         orl     $(IA32_SPEC_CTRL_IBRS|IA32_SPEC_CTRL_STIBP),%eax
1253         orl     $(IA32_SPEC_CTRL_IBRS|IA32_SPEC_CTRL_STIBP)>>32,%edx
1254         wrmsr
1255         movb    $1,PCPU(IBPB_SET)
1256         testl   $CPUID_STDEXT_SMEP,cpu_stdext_feature(%rip)
1257         jne     1f
1258         ibrs_seq 32
1259 1:      ret
1260 END(handle_ibrs_entry)
1261
1262 ENTRY(handle_ibrs_exit)
1263         cmpb    $0,PCPU(IBPB_SET)
1264         je      1f
1265         movl    $MSR_IA32_SPEC_CTRL,%ecx
1266         rdmsr
1267         andl    $~(IA32_SPEC_CTRL_IBRS|IA32_SPEC_CTRL_STIBP),%eax
1268         andl    $~((IA32_SPEC_CTRL_IBRS|IA32_SPEC_CTRL_STIBP)>>32),%edx
1269         wrmsr
1270         movb    $0,PCPU(IBPB_SET)
1271 1:      ret
1272 END(handle_ibrs_exit)
1273
1274 /* registers-neutral version, but needs stack */
1275 ENTRY(handle_ibrs_exit_rs)
1276         cmpb    $0,PCPU(IBPB_SET)
1277         je      1f
1278         pushq   %rax
1279         pushq   %rdx
1280         pushq   %rcx
1281         movl    $MSR_IA32_SPEC_CTRL,%ecx
1282         rdmsr
1283         andl    $~(IA32_SPEC_CTRL_IBRS|IA32_SPEC_CTRL_STIBP),%eax
1284         andl    $~((IA32_SPEC_CTRL_IBRS|IA32_SPEC_CTRL_STIBP)>>32),%edx
1285         wrmsr
1286         popq    %rcx
1287         popq    %rdx
1288         popq    %rax
1289         movb    $0,PCPU(IBPB_SET)
1290 1:      ret
1291 END(handle_ibrs_exit_rs)
1292
1293         .noaltmacro
1294
1295 /*
1296  * Flush L1D cache.  Load enough of the data from the kernel text
1297  * to flush existing L1D content.
1298  *
1299  * N.B. The function does not follow ABI calling conventions, it corrupts %rbx.
1300  * The vmm.ko caller expects that only %rax, %rdx, %rbx, %rcx, %r9, and %rflags
1301  * registers are clobbered.  The NMI handler caller only needs %r13 preserved.
1302  */
1303 ENTRY(flush_l1d_sw)
1304 #define L1D_FLUSH_SIZE  (64 * 1024)
1305         movq    $KERNBASE, %r9
1306         movq    $-L1D_FLUSH_SIZE, %rcx
1307         /*
1308          * pass 1: Preload TLB.
1309          * Kernel text is mapped using superpages.  TLB preload is
1310          * done for the benefit of older CPUs which split 2M page
1311          * into 4k TLB entries.
1312          */
1313 1:      movb    L1D_FLUSH_SIZE(%r9, %rcx), %al
1314         addq    $PAGE_SIZE, %rcx
1315         jne     1b
1316         xorl    %eax, %eax
1317         cpuid
1318         movq    $-L1D_FLUSH_SIZE, %rcx
1319         /* pass 2: Read each cache line. */
1320 2:      movb    L1D_FLUSH_SIZE(%r9, %rcx), %al
1321         addq    $64, %rcx
1322         jne     2b
1323         lfence
1324         ret
1325 #undef  L1D_FLUSH_SIZE
1326 END(flush_l1d_sw)