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