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