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