]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/amd64/amd64/support.S
amd64: macroify copyin/copyout and provide erms variants
[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 .macro SMAP_DISABLE smap
285 .if     \smap
286         stac
287 .endif
288 .endmacro
289
290
291 .macro SMAP_ENABLE smap
292 .if     \smap
293         clac
294 .endif
295 .endmacro
296
297 /*
298  * copyout(from_kernel, to_user, len)
299  *         %rdi,        %rsi,    %rdx
300  */
301 .macro  COPYOUT smap erms
302         PUSH_FRAME_POINTER
303         movq    PCPU(CURPCB),%rax
304         /* Trap entry clears PSL.AC */
305         movq    $copyout_fault,PCB_ONFAULT(%rax)
306         testq   %rdx,%rdx                       /* anything to do? */
307         jz      2f
308
309         /*
310          * Check explicitly for non-user addresses.  If 486 write protection
311          * is being used, this check is essential because we are in kernel
312          * mode so the h/w does not provide any protection against writing
313          * kernel addresses.
314          */
315
316         /*
317          * First, prevent address wrapping.
318          */
319         movq    %rsi,%rax
320         addq    %rdx,%rax
321         jc      copyout_fault
322 /*
323  * XXX STOP USING VM_MAXUSER_ADDRESS.
324  * It is an end address, not a max, so every time it is used correctly it
325  * looks like there is an off by one error, and of course it caused an off
326  * by one error in several places.
327  */
328         movq    $VM_MAXUSER_ADDRESS,%rcx
329         cmpq    %rcx,%rax
330         ja      copyout_fault
331
332         xchgq   %rdi,%rsi
333         /* bcopy(%rsi, %rdi, %rdx) */
334         movq    %rdx,%rcx
335
336         SMAP_DISABLE \smap
337 .if     \erms == 0
338         shrq    $3,%rcx
339         rep
340         movsq
341         movb    %dl,%cl
342         andb    $7,%cl
343         je      1f
344 .endif
345         rep
346         movsb
347 1:
348         SMAP_ENABLE \smap
349 2:
350         xorl    %eax,%eax
351         movq    PCPU(CURPCB),%rdx
352         movq    %rax,PCB_ONFAULT(%rdx)
353         POP_FRAME_POINTER
354         ret
355 .endmacro
356
357 ENTRY(copyout_nosmap_std)
358         COPYOUT smap=0 erms=0
359 END(copyout_nosmap_std)
360
361 ENTRY(copyout_smap_std)
362         COPYOUT smap=1 erms=0
363 END(copyout_smap_std)
364
365 ENTRY(copyout_nosmap_erms)
366         COPYOUT smap=0 erms=1
367 END(copyout_nosmap_erms)
368
369 ENTRY(copyout_smap_erms)
370         COPYOUT smap=1 erms=1
371 END(copyout_smap_erms)
372
373         ALIGN_TEXT
374 copyout_fault:
375         movq    PCPU(CURPCB),%rdx
376         movq    $0,PCB_ONFAULT(%rdx)
377         movq    $EFAULT,%rax
378         POP_FRAME_POINTER
379         ret
380
381 /*
382  * copyin(from_user, to_kernel, len)
383  *        %rdi,      %rsi,      %rdx
384  */
385 .macro  COPYIN smap erms
386         PUSH_FRAME_POINTER
387         movq    PCPU(CURPCB),%rax
388         movq    $copyin_fault,PCB_ONFAULT(%rax)
389         testq   %rdx,%rdx                       /* anything to do? */
390         jz      2f
391
392         /*
393          * make sure address is valid
394          */
395         movq    %rdi,%rax
396         addq    %rdx,%rax
397         jc      copyin_fault
398         movq    $VM_MAXUSER_ADDRESS,%rcx
399         cmpq    %rcx,%rax
400         ja      copyin_fault
401
402         xchgq   %rdi,%rsi
403         movq    %rdx,%rcx
404         movb    %cl,%al
405
406         SMAP_DISABLE \smap
407 .if \erms == 0
408         shrq    $3,%rcx                         /* copy longword-wise */
409         rep
410         movsq
411         movb    %al,%cl
412         andb    $7,%cl                          /* copy remaining bytes */
413         je      1
414 .endif
415         rep
416         movsb
417
418 1:
419         SMAP_ENABLE \smap
420 2:
421         xorl    %eax,%eax
422         movq    PCPU(CURPCB),%rdx
423         movq    %rax,PCB_ONFAULT(%rdx)
424         POP_FRAME_POINTER
425         ret
426 .endmacro
427
428 ENTRY(copyin_nosmap_std)
429         COPYIN smap=0 erms=0
430 END(copyin_nosmap_std)
431
432 ENTRY(copyin_smap_std)
433         COPYIN smap=1 erms=0
434 END(copyin_smap_std)
435
436 ENTRY(copyin_nosmap_erms)
437         COPYIN smap=0 erms=1
438 END(copyin_nosmap_erms)
439
440 ENTRY(copyin_smap_erms)
441         COPYIN smap=1 erms=1
442 END(copyin_smap_erms)
443
444         ALIGN_TEXT
445 copyin_fault:
446         movq    PCPU(CURPCB),%rdx
447         movq    $0,PCB_ONFAULT(%rdx)
448         movq    $EFAULT,%rax
449         POP_FRAME_POINTER
450         ret
451
452 /*
453  * casueword32.  Compare and set user integer.  Returns -1 on fault,
454  *        0 if access was successful.  Old value is written to *oldp.
455  *        dst = %rdi, old = %esi, oldp = %rdx, new = %ecx
456  */
457 ENTRY(casueword32_nosmap)
458         PUSH_FRAME_POINTER
459         movq    PCPU(CURPCB),%r8
460         movq    $fusufault,PCB_ONFAULT(%r8)
461
462         movq    $VM_MAXUSER_ADDRESS-4,%rax
463         cmpq    %rax,%rdi                       /* verify address is valid */
464         ja      fusufault
465
466         movl    %esi,%eax                       /* old */
467 #ifdef SMP
468         lock
469 #endif
470         cmpxchgl %ecx,(%rdi)                    /* new = %ecx */
471
472         /*
473          * The old value is in %eax.  If the store succeeded it will be the
474          * value we expected (old) from before the store, otherwise it will
475          * be the current value.  Save %eax into %esi to prepare the return
476          * value.
477          */
478         movl    %eax,%esi
479         xorl    %eax,%eax
480         movq    %rax,PCB_ONFAULT(%r8)
481
482         /*
483          * Access the oldp after the pcb_onfault is cleared, to correctly
484          * catch corrupted pointer.
485          */
486         movl    %esi,(%rdx)                     /* oldp = %rdx */
487         POP_FRAME_POINTER
488         ret
489 END(casueword32_nosmap)
490
491 ENTRY(casueword32_smap)
492         PUSH_FRAME_POINTER
493         movq    PCPU(CURPCB),%r8
494         movq    $fusufault,PCB_ONFAULT(%r8)
495
496         movq    $VM_MAXUSER_ADDRESS-4,%rax
497         cmpq    %rax,%rdi                       /* verify address is valid */
498         ja      fusufault
499
500         movl    %esi,%eax                       /* old */
501         stac
502 #ifdef SMP
503         lock
504 #endif
505         cmpxchgl %ecx,(%rdi)                    /* new = %ecx */
506         clac
507
508         /*
509          * The old value is in %eax.  If the store succeeded it will be the
510          * value we expected (old) from before the store, otherwise it will
511          * be the current value.  Save %eax into %esi to prepare the return
512          * value.
513          */
514         movl    %eax,%esi
515         xorl    %eax,%eax
516         movq    %rax,PCB_ONFAULT(%r8)
517
518         /*
519          * Access the oldp after the pcb_onfault is cleared, to correctly
520          * catch corrupted pointer.
521          */
522         movl    %esi,(%rdx)                     /* oldp = %rdx */
523         POP_FRAME_POINTER
524         ret
525 END(casueword32_smap)
526
527 /*
528  * casueword.  Compare and set user long.  Returns -1 on fault,
529  *        0 if access was successful.  Old value is written to *oldp.
530  *        dst = %rdi, old = %rsi, oldp = %rdx, new = %rcx
531  */
532 ENTRY(casueword_nosmap)
533         PUSH_FRAME_POINTER
534         movq    PCPU(CURPCB),%r8
535         movq    $fusufault,PCB_ONFAULT(%r8)
536
537         movq    $VM_MAXUSER_ADDRESS-4,%rax
538         cmpq    %rax,%rdi                       /* verify address is valid */
539         ja      fusufault
540
541         movq    %rsi,%rax                       /* old */
542 #ifdef SMP
543         lock
544 #endif
545         cmpxchgq %rcx,(%rdi)                    /* new = %rcx */
546
547         /*
548          * The old value is in %rax.  If the store succeeded it will be the
549          * value we expected (old) from before the store, otherwise it will
550          * be the current value.
551          */
552         movq    %rax,%rsi
553         xorl    %eax,%eax
554         movq    %rax,PCB_ONFAULT(%r8)
555         movq    %rsi,(%rdx)
556         POP_FRAME_POINTER
557         ret
558 END(casueword_nosmap)
559
560 ENTRY(casueword_smap)
561         PUSH_FRAME_POINTER
562         movq    PCPU(CURPCB),%r8
563         movq    $fusufault,PCB_ONFAULT(%r8)
564
565         movq    $VM_MAXUSER_ADDRESS-4,%rax
566         cmpq    %rax,%rdi                       /* verify address is valid */
567         ja      fusufault
568
569         movq    %rsi,%rax                       /* old */
570         stac
571 #ifdef SMP
572         lock
573 #endif
574         cmpxchgq %rcx,(%rdi)                    /* new = %rcx */
575         clac
576
577         /*
578          * The old value is in %rax.  If the store succeeded it will be the
579          * value we expected (old) from before the store, otherwise it will
580          * be the current value.
581          */
582         movq    %rax,%rsi
583         xorl    %eax,%eax
584         movq    %rax,PCB_ONFAULT(%r8)
585         movq    %rsi,(%rdx)
586         POP_FRAME_POINTER
587         ret
588 END(casueword_smap)
589
590 /*
591  * Fetch (load) a 64-bit word, a 32-bit word, a 16-bit word, or an 8-bit
592  * byte from user memory.
593  * addr = %rdi, valp = %rsi
594  */
595
596 ENTRY(fueword_nosmap)
597         PUSH_FRAME_POINTER
598         movq    PCPU(CURPCB),%rcx
599         movq    $fusufault,PCB_ONFAULT(%rcx)
600
601         movq    $VM_MAXUSER_ADDRESS-8,%rax
602         cmpq    %rax,%rdi                       /* verify address is valid */
603         ja      fusufault
604
605         xorl    %eax,%eax
606         movq    (%rdi),%r11
607         movq    %rax,PCB_ONFAULT(%rcx)
608         movq    %r11,(%rsi)
609         POP_FRAME_POINTER
610         ret
611 END(fueword_nosmap)
612
613 ENTRY(fueword_smap)
614         PUSH_FRAME_POINTER
615         movq    PCPU(CURPCB),%rcx
616         movq    $fusufault,PCB_ONFAULT(%rcx)
617
618         movq    $VM_MAXUSER_ADDRESS-8,%rax
619         cmpq    %rax,%rdi                       /* verify address is valid */
620         ja      fusufault
621
622         xorl    %eax,%eax
623         stac
624         movq    (%rdi),%r11
625         clac
626         movq    %rax,PCB_ONFAULT(%rcx)
627         movq    %r11,(%rsi)
628         POP_FRAME_POINTER
629         ret
630 END(fueword_smap)
631
632 ENTRY(fueword32_nosmap)
633         PUSH_FRAME_POINTER
634         movq    PCPU(CURPCB),%rcx
635         movq    $fusufault,PCB_ONFAULT(%rcx)
636
637         movq    $VM_MAXUSER_ADDRESS-4,%rax
638         cmpq    %rax,%rdi                       /* verify address is valid */
639         ja      fusufault
640
641         xorl    %eax,%eax
642         movl    (%rdi),%r11d
643         movq    %rax,PCB_ONFAULT(%rcx)
644         movl    %r11d,(%rsi)
645         POP_FRAME_POINTER
646         ret
647 END(fueword32_nosmap)
648
649 ENTRY(fueword32_smap)
650         PUSH_FRAME_POINTER
651         movq    PCPU(CURPCB),%rcx
652         movq    $fusufault,PCB_ONFAULT(%rcx)
653
654         movq    $VM_MAXUSER_ADDRESS-4,%rax
655         cmpq    %rax,%rdi                       /* verify address is valid */
656         ja      fusufault
657
658         xorl    %eax,%eax
659         stac
660         movl    (%rdi),%r11d
661         clac
662         movq    %rax,PCB_ONFAULT(%rcx)
663         movl    %r11d,(%rsi)
664         POP_FRAME_POINTER
665         ret
666 END(fueword32_smap)
667
668 ENTRY(fuword16_nosmap)
669         PUSH_FRAME_POINTER
670         movq    PCPU(CURPCB),%rcx
671         movq    $fusufault,PCB_ONFAULT(%rcx)
672
673         movq    $VM_MAXUSER_ADDRESS-2,%rax
674         cmpq    %rax,%rdi
675         ja      fusufault
676
677         movzwl  (%rdi),%eax
678         movq    $0,PCB_ONFAULT(%rcx)
679         POP_FRAME_POINTER
680         ret
681 END(fuword16_nosmap)
682
683 ENTRY(fuword16_smap)
684         PUSH_FRAME_POINTER
685         movq    PCPU(CURPCB),%rcx
686         movq    $fusufault,PCB_ONFAULT(%rcx)
687
688         movq    $VM_MAXUSER_ADDRESS-2,%rax
689         cmpq    %rax,%rdi
690         ja      fusufault
691
692         stac
693         movzwl  (%rdi),%eax
694         clac
695         movq    $0,PCB_ONFAULT(%rcx)
696         POP_FRAME_POINTER
697         ret
698 END(fuword16_smap)
699
700 ENTRY(fubyte_nosmap)
701         PUSH_FRAME_POINTER
702         movq    PCPU(CURPCB),%rcx
703         movq    $fusufault,PCB_ONFAULT(%rcx)
704
705         movq    $VM_MAXUSER_ADDRESS-1,%rax
706         cmpq    %rax,%rdi
707         ja      fusufault
708
709         movzbl  (%rdi),%eax
710         movq    $0,PCB_ONFAULT(%rcx)
711         POP_FRAME_POINTER
712         ret
713 END(fubyte_nosmap)
714
715 ENTRY(fubyte_smap)
716         PUSH_FRAME_POINTER
717         movq    PCPU(CURPCB),%rcx
718         movq    $fusufault,PCB_ONFAULT(%rcx)
719
720         movq    $VM_MAXUSER_ADDRESS-1,%rax
721         cmpq    %rax,%rdi
722         ja      fusufault
723
724         stac
725         movzbl  (%rdi),%eax
726         clac
727         movq    $0,PCB_ONFAULT(%rcx)
728         POP_FRAME_POINTER
729         ret
730 END(fubyte_smap)
731
732 /*
733  * Store a 64-bit word, a 32-bit word, a 16-bit word, or an 8-bit byte to
734  * user memory.
735  * addr = %rdi, value = %rsi
736  */
737 ENTRY(suword_nosmap)
738         PUSH_FRAME_POINTER
739         movq    PCPU(CURPCB),%rcx
740         movq    $fusufault,PCB_ONFAULT(%rcx)
741
742         movq    $VM_MAXUSER_ADDRESS-8,%rax
743         cmpq    %rax,%rdi                       /* verify address validity */
744         ja      fusufault
745
746         movq    %rsi,(%rdi)
747         xorl    %eax,%eax
748         movq    PCPU(CURPCB),%rcx
749         movq    %rax,PCB_ONFAULT(%rcx)
750         POP_FRAME_POINTER
751         ret
752 END(suword_nosmap)
753
754 ENTRY(suword_smap)
755         PUSH_FRAME_POINTER
756         movq    PCPU(CURPCB),%rcx
757         movq    $fusufault,PCB_ONFAULT(%rcx)
758
759         movq    $VM_MAXUSER_ADDRESS-8,%rax
760         cmpq    %rax,%rdi                       /* verify address validity */
761         ja      fusufault
762
763         stac
764         movq    %rsi,(%rdi)
765         clac
766         xorl    %eax,%eax
767         movq    PCPU(CURPCB),%rcx
768         movq    %rax,PCB_ONFAULT(%rcx)
769         POP_FRAME_POINTER
770         ret
771 END(suword_smap)
772
773 ENTRY(suword32_nosmap)
774         PUSH_FRAME_POINTER
775         movq    PCPU(CURPCB),%rcx
776         movq    $fusufault,PCB_ONFAULT(%rcx)
777
778         movq    $VM_MAXUSER_ADDRESS-4,%rax
779         cmpq    %rax,%rdi                       /* verify address validity */
780         ja      fusufault
781
782         movl    %esi,(%rdi)
783         xorl    %eax,%eax
784         movq    PCPU(CURPCB),%rcx
785         movq    %rax,PCB_ONFAULT(%rcx)
786         POP_FRAME_POINTER
787         ret
788 END(suword32_nosmap)
789
790 ENTRY(suword32_smap)
791         PUSH_FRAME_POINTER
792         movq    PCPU(CURPCB),%rcx
793         movq    $fusufault,PCB_ONFAULT(%rcx)
794
795         movq    $VM_MAXUSER_ADDRESS-4,%rax
796         cmpq    %rax,%rdi                       /* verify address validity */
797         ja      fusufault
798
799         stac
800         movl    %esi,(%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(suword32_smap)
808
809 ENTRY(suword16_nosmap)
810         PUSH_FRAME_POINTER
811         movq    PCPU(CURPCB),%rcx
812         movq    $fusufault,PCB_ONFAULT(%rcx)
813
814         movq    $VM_MAXUSER_ADDRESS-2,%rax
815         cmpq    %rax,%rdi                       /* verify address validity */
816         ja      fusufault
817
818         movw    %si,(%rdi)
819         xorl    %eax,%eax
820         movq    PCPU(CURPCB),%rcx               /* restore trashed register */
821         movq    %rax,PCB_ONFAULT(%rcx)
822         POP_FRAME_POINTER
823         ret
824 END(suword16_nosmap)
825
826 ENTRY(suword16_smap)
827         PUSH_FRAME_POINTER
828         movq    PCPU(CURPCB),%rcx
829         movq    $fusufault,PCB_ONFAULT(%rcx)
830
831         movq    $VM_MAXUSER_ADDRESS-2,%rax
832         cmpq    %rax,%rdi                       /* verify address validity */
833         ja      fusufault
834
835         stac
836         movw    %si,(%rdi)
837         clac
838         xorl    %eax,%eax
839         movq    PCPU(CURPCB),%rcx               /* restore trashed register */
840         movq    %rax,PCB_ONFAULT(%rcx)
841         POP_FRAME_POINTER
842         ret
843 END(suword16_smap)
844
845 ENTRY(subyte_nosmap)
846         PUSH_FRAME_POINTER
847         movq    PCPU(CURPCB),%rcx
848         movq    $fusufault,PCB_ONFAULT(%rcx)
849
850         movq    $VM_MAXUSER_ADDRESS-1,%rax
851         cmpq    %rax,%rdi                       /* verify address validity */
852         ja      fusufault
853
854         movl    %esi,%eax
855         movb    %al,(%rdi)
856         xorl    %eax,%eax
857         movq    PCPU(CURPCB),%rcx               /* restore trashed register */
858         movq    %rax,PCB_ONFAULT(%rcx)
859         POP_FRAME_POINTER
860         ret
861 END(subyte_nosmap)
862
863 ENTRY(subyte_smap)
864         PUSH_FRAME_POINTER
865         movq    PCPU(CURPCB),%rcx
866         movq    $fusufault,PCB_ONFAULT(%rcx)
867
868         movq    $VM_MAXUSER_ADDRESS-1,%rax
869         cmpq    %rax,%rdi                       /* verify address validity */
870         ja      fusufault
871
872         movl    %esi,%eax
873         stac
874         movb    %al,(%rdi)
875         clac
876         xorl    %eax,%eax
877         movq    PCPU(CURPCB),%rcx               /* restore trashed register */
878         movq    %rax,PCB_ONFAULT(%rcx)
879         POP_FRAME_POINTER
880         ret
881 END(subyte_smap)
882
883         ALIGN_TEXT
884         /* Fault entry clears PSL.AC */
885 fusufault:
886         movq    PCPU(CURPCB),%rcx
887         xorl    %eax,%eax
888         movq    %rax,PCB_ONFAULT(%rcx)
889         decq    %rax
890         POP_FRAME_POINTER
891         ret
892
893 /*
894  * copyinstr(from, to, maxlen, int *lencopied)
895  *           %rdi, %rsi, %rdx, %rcx
896  *
897  *      copy a string from 'from' to 'to', stop when a 0 character is reached.
898  *      return ENAMETOOLONG if string is longer than maxlen, and
899  *      EFAULT on protection violations. If lencopied is non-zero,
900  *      return the actual length in *lencopied.
901  */
902 ENTRY(copyinstr_nosmap)
903         PUSH_FRAME_POINTER
904         movq    %rdx,%r8                        /* %r8 = maxlen */
905         movq    %rcx,%r9                        /* %r9 = *len */
906         xchgq   %rdi,%rsi                       /* %rdi = from, %rsi = to */
907         movq    PCPU(CURPCB),%rcx
908         movq    $cpystrflt,PCB_ONFAULT(%rcx)
909
910         movq    $VM_MAXUSER_ADDRESS,%rax
911
912         /* make sure 'from' is within bounds */
913         subq    %rsi,%rax
914         jbe     cpystrflt
915
916         /* restrict maxlen to <= VM_MAXUSER_ADDRESS-from */
917         cmpq    %rdx,%rax
918         jae     1f
919         movq    %rax,%rdx
920         movq    %rax,%r8
921 1:
922         incq    %rdx
923
924 2:
925         decq    %rdx
926         jz      copyinstr_toolong
927
928         lodsb
929         stosb
930         orb     %al,%al
931         jnz     2b
932
933         jmp     copyinstr_succ
934 END(copyinstr_nosmap)
935
936 ENTRY(copyinstr_smap)
937         PUSH_FRAME_POINTER
938         movq    %rdx,%r8                        /* %r8 = maxlen */
939         movq    %rcx,%r9                        /* %r9 = *len */
940         xchgq   %rdi,%rsi                       /* %rdi = from, %rsi = to */
941         movq    PCPU(CURPCB),%rcx
942         movq    $cpystrflt,PCB_ONFAULT(%rcx)
943
944         movq    $VM_MAXUSER_ADDRESS,%rax
945
946         /* make sure 'from' is within bounds */
947         subq    %rsi,%rax
948         jbe     cpystrflt
949
950         stac
951
952         /* restrict maxlen to <= VM_MAXUSER_ADDRESS-from */
953         cmpq    %rdx,%rax
954         jae     1f
955         movq    %rax,%rdx
956         movq    %rax,%r8
957 1:
958         incq    %rdx
959
960 2:
961         decq    %rdx
962         jz      copyinstr_toolong_smap
963
964         lodsb
965         stosb
966         orb     %al,%al
967         jnz     2b
968
969         clac
970
971 copyinstr_succ:
972         /* Success -- 0 byte reached */
973         decq    %rdx
974         xorl    %eax,%eax
975
976 cpystrflt_x:
977         /* set *lencopied and return %eax */
978         movq    PCPU(CURPCB),%rcx
979         movq    $0,PCB_ONFAULT(%rcx)
980
981         testq   %r9,%r9
982         jz      1f
983         subq    %rdx,%r8
984         movq    %r8,(%r9)
985 1:
986         POP_FRAME_POINTER
987         ret
988         /* Fault entry clears PSL.AC */
989 cpystrflt:
990         movq    $EFAULT,%rax
991         jmp     cpystrflt_x
992
993 copyinstr_toolong_smap:
994         clac
995 copyinstr_toolong:
996         /* rdx is zero - return ENAMETOOLONG or EFAULT */
997         movq    $VM_MAXUSER_ADDRESS,%rax
998         cmpq    %rax,%rsi
999         jae     cpystrflt
1000         movq    $ENAMETOOLONG,%rax
1001         jmp     cpystrflt_x
1002
1003 END(copyinstr_smap)
1004
1005 /*
1006  * copystr(from, to, maxlen, int *lencopied)
1007  *         %rdi, %rsi, %rdx, %rcx
1008  */
1009 ENTRY(copystr)
1010         PUSH_FRAME_POINTER
1011         movq    %rdx,%r8                        /* %r8 = maxlen */
1012
1013         xchgq   %rdi,%rsi
1014         incq    %rdx
1015 1:
1016         decq    %rdx
1017         jz      4f
1018         lodsb
1019         stosb
1020         orb     %al,%al
1021         jnz     1b
1022
1023         /* Success -- 0 byte reached */
1024         decq    %rdx
1025         xorl    %eax,%eax
1026         jmp     6f
1027 4:
1028         /* rdx is zero -- return ENAMETOOLONG */
1029         movq    $ENAMETOOLONG,%rax
1030
1031 6:
1032
1033         testq   %rcx,%rcx
1034         jz      7f
1035         /* set *lencopied and return %rax */
1036         subq    %rdx,%r8
1037         movq    %r8,(%rcx)
1038 7:
1039         POP_FRAME_POINTER
1040         ret
1041 END(copystr)
1042
1043 /*
1044  * Handling of special amd64 registers and descriptor tables etc
1045  */
1046 /* void lgdt(struct region_descriptor *rdp); */
1047 ENTRY(lgdt)
1048         /* reload the descriptor table */
1049         lgdt    (%rdi)
1050
1051         /* flush the prefetch q */
1052         jmp     1f
1053         nop
1054 1:
1055         movl    $KDSEL,%eax
1056         movl    %eax,%ds
1057         movl    %eax,%es
1058         movl    %eax,%fs        /* Beware, use wrmsr to set 64 bit base */
1059         movl    %eax,%gs
1060         movl    %eax,%ss
1061
1062         /* reload code selector by turning return into intersegmental return */
1063         popq    %rax
1064         pushq   $KCSEL
1065         pushq   %rax
1066         MEXITCOUNT
1067         lretq
1068 END(lgdt)
1069
1070 /*****************************************************************************/
1071 /* setjump, longjump                                                         */
1072 /*****************************************************************************/
1073
1074 ENTRY(setjmp)
1075         movq    %rbx,0(%rdi)                    /* save rbx */
1076         movq    %rsp,8(%rdi)                    /* save rsp */
1077         movq    %rbp,16(%rdi)                   /* save rbp */
1078         movq    %r12,24(%rdi)                   /* save r12 */
1079         movq    %r13,32(%rdi)                   /* save r13 */
1080         movq    %r14,40(%rdi)                   /* save r14 */
1081         movq    %r15,48(%rdi)                   /* save r15 */
1082         movq    0(%rsp),%rdx                    /* get rta */
1083         movq    %rdx,56(%rdi)                   /* save rip */
1084         xorl    %eax,%eax                       /* return(0); */
1085         ret
1086 END(setjmp)
1087
1088 ENTRY(longjmp)
1089         movq    0(%rdi),%rbx                    /* restore rbx */
1090         movq    8(%rdi),%rsp                    /* restore rsp */
1091         movq    16(%rdi),%rbp                   /* restore rbp */
1092         movq    24(%rdi),%r12                   /* restore r12 */
1093         movq    32(%rdi),%r13                   /* restore r13 */
1094         movq    40(%rdi),%r14                   /* restore r14 */
1095         movq    48(%rdi),%r15                   /* restore r15 */
1096         movq    56(%rdi),%rdx                   /* get rta */
1097         movq    %rdx,0(%rsp)                    /* put in return frame */
1098         xorl    %eax,%eax                       /* return(1); */
1099         incl    %eax
1100         ret
1101 END(longjmp)
1102
1103 /*
1104  * Support for reading MSRs in the safe manner.  (Instead of panic on #gp,
1105  * return an error.)
1106  */
1107 ENTRY(rdmsr_safe)
1108 /* int rdmsr_safe(u_int msr, uint64_t *data) */
1109         PUSH_FRAME_POINTER
1110         movq    PCPU(CURPCB),%r8
1111         movq    $msr_onfault,PCB_ONFAULT(%r8)
1112         movl    %edi,%ecx
1113         rdmsr                   /* Read MSR pointed by %ecx. Returns
1114                                    hi byte in edx, lo in %eax */
1115         salq    $32,%rdx        /* sign-shift %rdx left */
1116         movl    %eax,%eax       /* zero-extend %eax -> %rax */
1117         orq     %rdx,%rax
1118         movq    %rax,(%rsi)
1119         xorq    %rax,%rax
1120         movq    %rax,PCB_ONFAULT(%r8)
1121         POP_FRAME_POINTER
1122         ret
1123
1124 /*
1125  * Support for writing MSRs in the safe manner.  (Instead of panic on #gp,
1126  * return an error.)
1127  */
1128 ENTRY(wrmsr_safe)
1129 /* int wrmsr_safe(u_int msr, uint64_t data) */
1130         PUSH_FRAME_POINTER
1131         movq    PCPU(CURPCB),%r8
1132         movq    $msr_onfault,PCB_ONFAULT(%r8)
1133         movl    %edi,%ecx
1134         movl    %esi,%eax
1135         sarq    $32,%rsi
1136         movl    %esi,%edx
1137         wrmsr                   /* Write MSR pointed by %ecx. Accepts
1138                                    hi byte in edx, lo in %eax. */
1139         xorq    %rax,%rax
1140         movq    %rax,PCB_ONFAULT(%r8)
1141         POP_FRAME_POINTER
1142         ret
1143
1144 /*
1145  * MSR operations fault handler
1146  */
1147         ALIGN_TEXT
1148 msr_onfault:
1149         movq    $0,PCB_ONFAULT(%r8)
1150         movl    $EFAULT,%eax
1151         POP_FRAME_POINTER
1152         ret
1153
1154 /*
1155  * void pmap_pti_pcid_invalidate(uint64_t ucr3, uint64_t kcr3);
1156  * Invalidates address space addressed by ucr3, then returns to kcr3.
1157  * Done in assembler to ensure no other memory accesses happen while
1158  * on ucr3.
1159  */
1160         ALIGN_TEXT
1161 ENTRY(pmap_pti_pcid_invalidate)
1162         pushfq
1163         cli
1164         movq    %rdi,%cr3       /* to user page table */
1165         movq    %rsi,%cr3       /* back to kernel */
1166         popfq
1167         retq
1168
1169 /*
1170  * void pmap_pti_pcid_invlpg(uint64_t ucr3, uint64_t kcr3, vm_offset_t va);
1171  * Invalidates virtual address va in address space ucr3, then returns to kcr3.
1172  */
1173         ALIGN_TEXT
1174 ENTRY(pmap_pti_pcid_invlpg)
1175         pushfq
1176         cli
1177         movq    %rdi,%cr3       /* to user page table */
1178         invlpg  (%rdx)
1179         movq    %rsi,%cr3       /* back to kernel */
1180         popfq
1181         retq
1182
1183 /*
1184  * void pmap_pti_pcid_invlrng(uint64_t ucr3, uint64_t kcr3, vm_offset_t sva,
1185  *     vm_offset_t eva);
1186  * Invalidates virtual addresses between sva and eva in address space ucr3,
1187  * then returns to kcr3.
1188  */
1189         ALIGN_TEXT
1190 ENTRY(pmap_pti_pcid_invlrng)
1191         pushfq
1192         cli
1193         movq    %rdi,%cr3       /* to user page table */
1194 1:      invlpg  (%rdx)
1195         addq    $PAGE_SIZE,%rdx
1196         cmpq    %rdx,%rcx
1197         ja      1b
1198         movq    %rsi,%cr3       /* back to kernel */
1199         popfq
1200         retq
1201
1202         .altmacro
1203         .macro  ibrs_seq_label l
1204 handle_ibrs_\l:
1205         .endm
1206         .macro  ibrs_call_label l
1207         call    handle_ibrs_\l
1208         .endm
1209         .macro  ibrs_seq count
1210         ll=1
1211         .rept   \count
1212         ibrs_call_label %(ll)
1213         nop
1214         ibrs_seq_label %(ll)
1215         addq    $8,%rsp
1216         ll=ll+1
1217         .endr
1218         .endm
1219
1220 /* all callers already saved %rax, %rdx, and %rcx */
1221 ENTRY(handle_ibrs_entry)
1222         cmpb    $0,hw_ibrs_active(%rip)
1223         je      1f
1224         movl    $MSR_IA32_SPEC_CTRL,%ecx
1225         rdmsr
1226         orl     $(IA32_SPEC_CTRL_IBRS|IA32_SPEC_CTRL_STIBP),%eax
1227         orl     $(IA32_SPEC_CTRL_IBRS|IA32_SPEC_CTRL_STIBP)>>32,%edx
1228         wrmsr
1229         movb    $1,PCPU(IBPB_SET)
1230         testl   $CPUID_STDEXT_SMEP,cpu_stdext_feature(%rip)
1231         jne     1f
1232         ibrs_seq 32
1233 1:      ret
1234 END(handle_ibrs_entry)
1235
1236 ENTRY(handle_ibrs_exit)
1237         cmpb    $0,PCPU(IBPB_SET)
1238         je      1f
1239         movl    $MSR_IA32_SPEC_CTRL,%ecx
1240         rdmsr
1241         andl    $~(IA32_SPEC_CTRL_IBRS|IA32_SPEC_CTRL_STIBP),%eax
1242         andl    $~((IA32_SPEC_CTRL_IBRS|IA32_SPEC_CTRL_STIBP)>>32),%edx
1243         wrmsr
1244         movb    $0,PCPU(IBPB_SET)
1245 1:      ret
1246 END(handle_ibrs_exit)
1247
1248 /* registers-neutral version, but needs stack */
1249 ENTRY(handle_ibrs_exit_rs)
1250         cmpb    $0,PCPU(IBPB_SET)
1251         je      1f
1252         pushq   %rax
1253         pushq   %rdx
1254         pushq   %rcx
1255         movl    $MSR_IA32_SPEC_CTRL,%ecx
1256         rdmsr
1257         andl    $~(IA32_SPEC_CTRL_IBRS|IA32_SPEC_CTRL_STIBP),%eax
1258         andl    $~((IA32_SPEC_CTRL_IBRS|IA32_SPEC_CTRL_STIBP)>>32),%edx
1259         wrmsr
1260         popq    %rcx
1261         popq    %rdx
1262         popq    %rax
1263         movb    $0,PCPU(IBPB_SET)
1264 1:      ret
1265 END(handle_ibrs_exit_rs)
1266
1267         .noaltmacro
1268
1269 /*
1270  * Flush L1D cache.  Load enough of the data from the kernel text
1271  * to flush existing L1D content.
1272  *
1273  * N.B. The function does not follow ABI calling conventions, it corrupts %rbx.
1274  * The vmm.ko caller expects that only %rax, %rdx, %rbx, %rcx, %r9, and %rflags
1275  * registers are clobbered.  The NMI handler caller only needs %r13 preserved.
1276  */
1277 ENTRY(flush_l1d_sw)
1278 #define L1D_FLUSH_SIZE  (64 * 1024)
1279         movq    $KERNBASE, %r9
1280         movq    $-L1D_FLUSH_SIZE, %rcx
1281         /*
1282          * pass 1: Preload TLB.
1283          * Kernel text is mapped using superpages.  TLB preload is
1284          * done for the benefit of older CPUs which split 2M page
1285          * into 4k TLB entries.
1286          */
1287 1:      movb    L1D_FLUSH_SIZE(%r9, %rcx), %al
1288         addq    $PAGE_SIZE, %rcx
1289         jne     1b
1290         xorl    %eax, %eax
1291         cpuid
1292         movq    $-L1D_FLUSH_SIZE, %rcx
1293         /* pass 2: Read each cache line. */
1294 2:      movb    L1D_FLUSH_SIZE(%r9, %rcx), %al
1295         addq    $64, %rcx
1296         jne     2b
1297         lfence
1298         ret
1299 #undef  L1D_FLUSH_SIZE
1300 END(flush_l1d_sw)