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