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