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