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