]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/amd64/amd64/support.S
amd64: depessimize copyinstr_smap
[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         je      1f
316         rep
317         movsb
318 1:      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_smap)
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         rep
362         movsq
363         movb    %al,%cl
364         andb    $7,%cl                          /* copy remaining bytes */
365         je      done_copyin
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      1f
399         rep
400         movsb
401 1:      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(fueword_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(fueword_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
891 2:
892         decq    %rdx
893         jz      copyinstr_toolong
894
895         lodsb
896         stosb
897         orb     %al,%al
898         jnz     2b
899
900         jmp     copyinstr_succ
901 END(copyinstr_nosmap)
902
903 ENTRY(copyinstr_smap)
904         PUSH_FRAME_POINTER
905         movq    %rdx,%r8                        /* %r8 = maxlen */
906         movq    %rcx,%r9                        /* %r9 = *len */
907         xchgq   %rdi,%rsi                       /* %rdi = from, %rsi = to */
908         movq    PCPU(CURPCB),%rcx
909         movq    $cpystrflt,PCB_ONFAULT(%rcx)
910
911         movq    $VM_MAXUSER_ADDRESS,%rax
912
913         /* make sure 'from' is within bounds */
914         subq    %rsi,%rax
915         jbe     cpystrflt
916
917         stac
918
919         /* restrict maxlen to <= VM_MAXUSER_ADDRESS-from */
920         cmpq    %rdx,%rax
921         jae     1f
922         movq    %rax,%rdx
923         movq    %rax,%r8
924 1:
925         incq    %rdx
926
927 2:
928         decq    %rdx
929         jz      copyinstr_toolong_smap
930
931         lodsb
932         stosb
933         orb     %al,%al
934         jnz     2b
935
936         clac
937
938 copyinstr_succ:
939         /* Success -- 0 byte reached */
940         decq    %rdx
941         xorl    %eax,%eax
942
943 cpystrflt_x:
944         /* set *lencopied and return %eax */
945         movq    PCPU(CURPCB),%rcx
946         movq    $0,PCB_ONFAULT(%rcx)
947
948         testq   %r9,%r9
949         jz      1f
950         subq    %rdx,%r8
951         movq    %r8,(%r9)
952 1:
953         POP_FRAME_POINTER
954         ret
955         /* Fault entry clears PSL.AC */
956 cpystrflt:
957         movq    $EFAULT,%rax
958         jmp     cpystrflt_x
959
960 copyinstr_toolong_smap:
961         clac
962 copyinstr_toolong:
963         /* rdx is zero - return ENAMETOOLONG or EFAULT */
964         movq    $VM_MAXUSER_ADDRESS,%rax
965         cmpq    %rax,%rsi
966         jae     cpystrflt
967         movq    $ENAMETOOLONG,%rax
968         jmp     cpystrflt_x
969
970 END(copyinstr_smap)
971
972 /*
973  * copystr(from, to, maxlen, int *lencopied)
974  *         %rdi, %rsi, %rdx, %rcx
975  */
976 ENTRY(copystr)
977         PUSH_FRAME_POINTER
978         movq    %rdx,%r8                        /* %r8 = maxlen */
979
980         xchgq   %rdi,%rsi
981         incq    %rdx
982 1:
983         decq    %rdx
984         jz      4f
985         lodsb
986         stosb
987         orb     %al,%al
988         jnz     1b
989
990         /* Success -- 0 byte reached */
991         decq    %rdx
992         xorl    %eax,%eax
993         jmp     6f
994 4:
995         /* rdx is zero -- return ENAMETOOLONG */
996         movq    $ENAMETOOLONG,%rax
997
998 6:
999
1000         testq   %rcx,%rcx
1001         jz      7f
1002         /* set *lencopied and return %rax */
1003         subq    %rdx,%r8
1004         movq    %r8,(%rcx)
1005 7:
1006         POP_FRAME_POINTER
1007         ret
1008 END(copystr)
1009
1010 /*
1011  * Handling of special amd64 registers and descriptor tables etc
1012  */
1013 /* void lgdt(struct region_descriptor *rdp); */
1014 ENTRY(lgdt)
1015         /* reload the descriptor table */
1016         lgdt    (%rdi)
1017
1018         /* flush the prefetch q */
1019         jmp     1f
1020         nop
1021 1:
1022         movl    $KDSEL,%eax
1023         movl    %eax,%ds
1024         movl    %eax,%es
1025         movl    %eax,%fs        /* Beware, use wrmsr to set 64 bit base */
1026         movl    %eax,%gs
1027         movl    %eax,%ss
1028
1029         /* reload code selector by turning return into intersegmental return */
1030         popq    %rax
1031         pushq   $KCSEL
1032         pushq   %rax
1033         MEXITCOUNT
1034         lretq
1035 END(lgdt)
1036
1037 /*****************************************************************************/
1038 /* setjump, longjump                                                         */
1039 /*****************************************************************************/
1040
1041 ENTRY(setjmp)
1042         movq    %rbx,0(%rdi)                    /* save rbx */
1043         movq    %rsp,8(%rdi)                    /* save rsp */
1044         movq    %rbp,16(%rdi)                   /* save rbp */
1045         movq    %r12,24(%rdi)                   /* save r12 */
1046         movq    %r13,32(%rdi)                   /* save r13 */
1047         movq    %r14,40(%rdi)                   /* save r14 */
1048         movq    %r15,48(%rdi)                   /* save r15 */
1049         movq    0(%rsp),%rdx                    /* get rta */
1050         movq    %rdx,56(%rdi)                   /* save rip */
1051         xorl    %eax,%eax                       /* return(0); */
1052         ret
1053 END(setjmp)
1054
1055 ENTRY(longjmp)
1056         movq    0(%rdi),%rbx                    /* restore rbx */
1057         movq    8(%rdi),%rsp                    /* restore rsp */
1058         movq    16(%rdi),%rbp                   /* restore rbp */
1059         movq    24(%rdi),%r12                   /* restore r12 */
1060         movq    32(%rdi),%r13                   /* restore r13 */
1061         movq    40(%rdi),%r14                   /* restore r14 */
1062         movq    48(%rdi),%r15                   /* restore r15 */
1063         movq    56(%rdi),%rdx                   /* get rta */
1064         movq    %rdx,0(%rsp)                    /* put in return frame */
1065         xorl    %eax,%eax                       /* return(1); */
1066         incl    %eax
1067         ret
1068 END(longjmp)
1069
1070 /*
1071  * Support for reading MSRs in the safe manner.  (Instead of panic on #gp,
1072  * return an error.)
1073  */
1074 ENTRY(rdmsr_safe)
1075 /* int rdmsr_safe(u_int msr, uint64_t *data) */
1076         PUSH_FRAME_POINTER
1077         movq    PCPU(CURPCB),%r8
1078         movq    $msr_onfault,PCB_ONFAULT(%r8)
1079         movl    %edi,%ecx
1080         rdmsr                   /* Read MSR pointed by %ecx. Returns
1081                                    hi byte in edx, lo in %eax */
1082         salq    $32,%rdx        /* sign-shift %rdx left */
1083         movl    %eax,%eax       /* zero-extend %eax -> %rax */
1084         orq     %rdx,%rax
1085         movq    %rax,(%rsi)
1086         xorq    %rax,%rax
1087         movq    %rax,PCB_ONFAULT(%r8)
1088         POP_FRAME_POINTER
1089         ret
1090
1091 /*
1092  * Support for writing MSRs in the safe manner.  (Instead of panic on #gp,
1093  * return an error.)
1094  */
1095 ENTRY(wrmsr_safe)
1096 /* int wrmsr_safe(u_int msr, uint64_t data) */
1097         PUSH_FRAME_POINTER
1098         movq    PCPU(CURPCB),%r8
1099         movq    $msr_onfault,PCB_ONFAULT(%r8)
1100         movl    %edi,%ecx
1101         movl    %esi,%eax
1102         sarq    $32,%rsi
1103         movl    %esi,%edx
1104         wrmsr                   /* Write MSR pointed by %ecx. Accepts
1105                                    hi byte in edx, lo in %eax. */
1106         xorq    %rax,%rax
1107         movq    %rax,PCB_ONFAULT(%r8)
1108         POP_FRAME_POINTER
1109         ret
1110
1111 /*
1112  * MSR operations fault handler
1113  */
1114         ALIGN_TEXT
1115 msr_onfault:
1116         movq    $0,PCB_ONFAULT(%r8)
1117         movl    $EFAULT,%eax
1118         POP_FRAME_POINTER
1119         ret
1120
1121 /*
1122  * void pmap_pti_pcid_invalidate(uint64_t ucr3, uint64_t kcr3);
1123  * Invalidates address space addressed by ucr3, then returns to kcr3.
1124  * Done in assembler to ensure no other memory accesses happen while
1125  * on ucr3.
1126  */
1127         ALIGN_TEXT
1128 ENTRY(pmap_pti_pcid_invalidate)
1129         pushfq
1130         cli
1131         movq    %rdi,%cr3       /* to user page table */
1132         movq    %rsi,%cr3       /* back to kernel */
1133         popfq
1134         retq
1135
1136 /*
1137  * void pmap_pti_pcid_invlpg(uint64_t ucr3, uint64_t kcr3, vm_offset_t va);
1138  * Invalidates virtual address va in address space ucr3, then returns to kcr3.
1139  */
1140         ALIGN_TEXT
1141 ENTRY(pmap_pti_pcid_invlpg)
1142         pushfq
1143         cli
1144         movq    %rdi,%cr3       /* to user page table */
1145         invlpg  (%rdx)
1146         movq    %rsi,%cr3       /* back to kernel */
1147         popfq
1148         retq
1149
1150 /*
1151  * void pmap_pti_pcid_invlrng(uint64_t ucr3, uint64_t kcr3, vm_offset_t sva,
1152  *     vm_offset_t eva);
1153  * Invalidates virtual addresses between sva and eva in address space ucr3,
1154  * then returns to kcr3.
1155  */
1156         ALIGN_TEXT
1157 ENTRY(pmap_pti_pcid_invlrng)
1158         pushfq
1159         cli
1160         movq    %rdi,%cr3       /* to user page table */
1161 1:      invlpg  (%rdx)
1162         addq    $PAGE_SIZE,%rdx
1163         cmpq    %rdx,%rcx
1164         ja      1b
1165         movq    %rsi,%cr3       /* back to kernel */
1166         popfq
1167         retq
1168
1169         .altmacro
1170         .macro  ibrs_seq_label l
1171 handle_ibrs_\l:
1172         .endm
1173         .macro  ibrs_call_label l
1174         call    handle_ibrs_\l
1175         .endm
1176         .macro  ibrs_seq count
1177         ll=1
1178         .rept   \count
1179         ibrs_call_label %(ll)
1180         nop
1181         ibrs_seq_label %(ll)
1182         addq    $8,%rsp
1183         ll=ll+1
1184         .endr
1185         .endm
1186
1187 /* all callers already saved %rax, %rdx, and %rcx */
1188 ENTRY(handle_ibrs_entry)
1189         cmpb    $0,hw_ibrs_active(%rip)
1190         je      1f
1191         movl    $MSR_IA32_SPEC_CTRL,%ecx
1192         rdmsr
1193         orl     $(IA32_SPEC_CTRL_IBRS|IA32_SPEC_CTRL_STIBP),%eax
1194         orl     $(IA32_SPEC_CTRL_IBRS|IA32_SPEC_CTRL_STIBP)>>32,%edx
1195         wrmsr
1196         movb    $1,PCPU(IBPB_SET)
1197         testl   $CPUID_STDEXT_SMEP,cpu_stdext_feature(%rip)
1198         jne     1f
1199         ibrs_seq 32
1200 1:      ret
1201 END(handle_ibrs_entry)
1202
1203 ENTRY(handle_ibrs_exit)
1204         cmpb    $0,PCPU(IBPB_SET)
1205         je      1f
1206         movl    $MSR_IA32_SPEC_CTRL,%ecx
1207         rdmsr
1208         andl    $~(IA32_SPEC_CTRL_IBRS|IA32_SPEC_CTRL_STIBP),%eax
1209         andl    $~((IA32_SPEC_CTRL_IBRS|IA32_SPEC_CTRL_STIBP)>>32),%edx
1210         wrmsr
1211         movb    $0,PCPU(IBPB_SET)
1212 1:      ret
1213 END(handle_ibrs_exit)
1214
1215 /* registers-neutral version, but needs stack */
1216 ENTRY(handle_ibrs_exit_rs)
1217         cmpb    $0,PCPU(IBPB_SET)
1218         je      1f
1219         pushq   %rax
1220         pushq   %rdx
1221         pushq   %rcx
1222         movl    $MSR_IA32_SPEC_CTRL,%ecx
1223         rdmsr
1224         andl    $~(IA32_SPEC_CTRL_IBRS|IA32_SPEC_CTRL_STIBP),%eax
1225         andl    $~((IA32_SPEC_CTRL_IBRS|IA32_SPEC_CTRL_STIBP)>>32),%edx
1226         wrmsr
1227         popq    %rcx
1228         popq    %rdx
1229         popq    %rax
1230         movb    $0,PCPU(IBPB_SET)
1231 1:      ret
1232 END(handle_ibrs_exit_rs)
1233
1234         .noaltmacro
1235
1236 /*
1237  * Flush L1D cache.  Load enough of the data from the kernel text
1238  * to flush existing L1D content.
1239  *
1240  * N.B. The function does not follow ABI calling conventions, it corrupts %rbx.
1241  * The vmm.ko caller expects that only %rax, %rdx, %rbx, %rcx, %r9, and %rflags
1242  * registers are clobbered.  The NMI handler caller only needs %r13 preserved.
1243  */
1244 ENTRY(flush_l1d_sw)
1245 #define L1D_FLUSH_SIZE  (64 * 1024)
1246         movq    $KERNBASE, %r9
1247         movq    $-L1D_FLUSH_SIZE, %rcx
1248         /*
1249          * pass 1: Preload TLB.
1250          * Kernel text is mapped using superpages.  TLB preload is
1251          * done for the benefit of older CPUs which split 2M page
1252          * into 4k TLB entries.
1253          */
1254 1:      movb    L1D_FLUSH_SIZE(%r9, %rcx), %al
1255         addq    $PAGE_SIZE, %rcx
1256         jne     1b
1257         xorl    %eax, %eax
1258         cpuid
1259         movq    $-L1D_FLUSH_SIZE, %rcx
1260         /* pass 2: Read each cache line. */
1261 2:      movb    L1D_FLUSH_SIZE(%r9, %rcx), %al
1262         addq    $64, %rcx
1263         jne     2b
1264         lfence
1265         ret
1266 #undef  L1D_FLUSH_SIZE
1267 END(flush_l1d_sw)