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