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