Bring in the remainder of the post-SoC amd64 enchilada.
[dragonfly.git] / sys / platform / pc64 / amd64 / support.s
... / ...
CommitLineData
1/*-
2 * Copyright (c) 1993 The Regents of the University of California.
3 * Copyright (c) 2003 Peter Wemm.
4 * Copyright (c) 2008 The DragonFly Project.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 4. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 *
31 * $FreeBSD: src/sys/amd64/amd64/support.S,v 1.127 2007/05/23 08:33:04 kib Exp $
32 * $DragonFly: src/sys/platform/pc64/amd64/support.s,v 1.2 2008/08/29 17:07:10 dillon Exp $
33 */
34
35#include "opt_ddb.h"
36
37#include <machine/asmacros.h>
38#include <machine/intr_machdep.h>
39#include <machine/pmap.h>
40
41#include "assym.s"
42
43 ALIGN_DATA
44 .globl intrcnt, eintrcnt
45intrcnt:
46 .space INTRCNT_COUNT * 8
47eintrcnt:
48
49 .globl intrnames, eintrnames
50intrnames:
51 .space INTRCNT_COUNT * (MAXCOMLEN + 1)
52eintrnames:
53
54 .text
55
56/*
57 * bcopy family
58 * void bzero(void *buf, u_int len)
59 */
60
61/* done */
62ENTRY(bzero)
63 movq %rsi,%rcx
64 xorl %eax,%eax
65 shrq $3,%rcx
66 cld
67 rep
68 stosq
69 movq %rsi,%rcx
70 andq $7,%rcx
71 rep
72 stosb
73 ret
74
75/* Address: %rdi */
76ENTRY(pagezero)
77 movq $-PAGE_SIZE,%rdx
78 subq %rdx,%rdi
79 xorl %eax,%eax
801:
81 movnti %rax,(%rdi,%rdx)
82 movnti %rax,8(%rdi,%rdx)
83 movnti %rax,16(%rdi,%rdx)
84 movnti %rax,24(%rdi,%rdx)
85 addq $32,%rdx
86 jne 1b
87 sfence
88 ret
89
90ENTRY(bcmp)
91 movq %rdx,%rcx
92 shrq $3,%rcx
93 cld /* compare forwards */
94 repe
95 cmpsq
96 jne 1f
97
98 movq %rdx,%rcx
99 andq $7,%rcx
100 repe
101 cmpsb
1021:
103 setne %al
104 movsbl %al,%eax
105 ret
106
107/*
108 * bcopy(src, dst, cnt)
109 * rdi, rsi, rdx
110 * ws@tools.de (Wolfgang Solfrank, TooLs GmbH) +49-228-985800
111 */
112ENTRY(generic_bcopy) /* generic_bcopy is bcopy without FPU */
113ENTRY(ovbcopy) /* our bcopy doesn't use the FPU, so ovbcopy is the same */
114ENTRY(bcopy)
115 xchgq %rsi,%rdi
116 movq %rdx,%rcx
117
118 movq %rdi,%rax
119 subq %rsi,%rax
120 cmpq %rcx,%rax /* overlapping && src < dst? */
121 jb 1f
122
123 shrq $3,%rcx /* copy by 64-bit words */
124 cld /* nope, copy forwards */
125 rep
126 movsq
127 movq %rdx,%rcx
128 andq $7,%rcx /* any bytes left? */
129 rep
130 movsb
131 ret
132
133 /* ALIGN_TEXT */
1341:
135 addq %rcx,%rdi /* copy backwards */
136 addq %rcx,%rsi
137 decq %rdi
138 decq %rsi
139 andq $7,%rcx /* any fractional bytes? */
140 std
141 rep
142 movsb
143 movq %rdx,%rcx /* copy remainder by 32-bit words */
144 shrq $3,%rcx
145 subq $7,%rsi
146 subq $7,%rdi
147 rep
148 movsq
149 cld
150 ret
151ENTRY(reset_dbregs)
152 movq $0x200,%rax /* the manual says that bit 10 must be set to 1 */
153 movq %rax,%dr7 /* disable all breapoints first */
154 movq $0,%rax
155 movq %rax,%dr0
156 movq %rax,%dr1
157 movq %rax,%dr2
158 movq %rax,%dr3
159 movq %rax,%dr6
160 ret
161
162/*
163 * Note: memcpy does not support overlapping copies
164 */
165ENTRY(memcpy)
166 movq %rdx,%rcx
167 shrq $3,%rcx /* copy by 64-bit words */
168 cld /* copy forwards */
169 rep
170 movsq
171 movq %rdx,%rcx
172 andq $7,%rcx /* any bytes left? */
173 rep
174 movsb
175 ret
176
177/*
178 * pagecopy(%rdi=from, %rsi=to)
179 */
180ENTRY(pagecopy)
181 movq $-PAGE_SIZE,%rax
182 movq %rax,%rdx
183 subq %rax,%rdi
184 subq %rax,%rsi
1851:
186 prefetchnta (%rdi,%rax)
187 addq $64,%rax
188 jne 1b
1892:
190 movq (%rdi,%rdx),%rax
191 movnti %rax,(%rsi,%rdx)
192 movq 8(%rdi,%rdx),%rax
193 movnti %rax,8(%rsi,%rdx)
194 movq 16(%rdi,%rdx),%rax
195 movnti %rax,16(%rsi,%rdx)
196 movq 24(%rdi,%rdx),%rax
197 movnti %rax,24(%rsi,%rdx)
198 addq $32,%rdx
199 jne 2b
200 sfence
201 ret
202
203/* fillw(pat, base, cnt) */
204/* %rdi,%rsi, %rdx */
205ENTRY(fillw)
206 movq %rdi,%rax
207 movq %rsi,%rdi
208 movq %rdx,%rcx
209 cld
210 rep
211 stosw
212 ret
213
214/*****************************************************************************/
215/* copyout and fubyte family */
216/*****************************************************************************/
217/*
218 * Access user memory from inside the kernel. These routines should be
219 * the only places that do this.
220 *
221 * These routines set curpcb->onfault for the time they execute. When a
222 * protection violation occurs inside the functions, the trap handler
223 * returns to *curpcb->onfault instead of the function.
224 */
225
226/*
227 * copyout(from_kernel, to_user, len) - MP SAFE
228 * %rdi, %rsi, %rdx
229 */
230ENTRY(copyout)
231 movq PCPU(curthread),%rax
232 movq TD_PCB(%rax), %rax
233 movq $copyout_fault,PCB_ONFAULT(%rax)
234 testq %rdx,%rdx /* anything to do? */
235 jz done_copyout
236
237 /*
238 * Check explicitly for non-user addresses. If 486 write protection
239 * is being used, this check is essential because we are in kernel
240 * mode so the h/w does not provide any protection against writing
241 * kernel addresses.
242 */
243
244 /*
245 * First, prevent address wrapping.
246 */
247 movq %rsi,%rax
248 addq %rdx,%rax
249 jc copyout_fault
250/*
251 * XXX STOP USING VM_MAXUSER_ADDRESS.
252 * It is an end address, not a max, so every time it is used correctly it
253 * looks like there is an off by one error, and of course it caused an off
254 * by one error in several places.
255 */
256 movq $VM_MAXUSER_ADDRESS,%rcx
257 cmpq %rcx,%rax
258 ja copyout_fault
259
260 xchgq %rdi,%rsi
261 /* bcopy(%rsi, %rdi, %rdx) */
262 movq %rdx,%rcx
263
264 shrq $3,%rcx
265 cld
266 rep
267 movsq
268 movb %dl,%cl
269 andb $7,%cl
270 rep
271 movsb
272
273done_copyout:
274 xorl %eax,%eax
275 movq PCPU(curthread),%rdx
276 movq TD_PCB(%rdx), %rdx
277 movq %rax,PCB_ONFAULT(%rdx)
278 ret
279
280 ALIGN_TEXT
281copyout_fault:
282 movq PCPU(curthread),%rdx
283 movq TD_PCB(%rdx), %rdx
284 movq $0,PCB_ONFAULT(%rdx)
285 movq $EFAULT,%rax
286 ret
287
288/*
289 * copyin(from_user, to_kernel, len) - MP SAFE
290 * %rdi, %rsi, %rdx
291 */
292ENTRY(copyin)
293 movq PCPU(curthread),%rax
294 movq TD_PCB(%rax), %rax
295 movq $copyin_fault,PCB_ONFAULT(%rax)
296 testq %rdx,%rdx /* anything to do? */
297 jz done_copyin
298
299 /*
300 * make sure address is valid
301 */
302 movq %rdi,%rax
303 addq %rdx,%rax
304 jc copyin_fault
305 movq $VM_MAXUSER_ADDRESS,%rcx
306 cmpq %rcx,%rax
307 ja copyin_fault
308
309 xchgq %rdi,%rsi
310 movq %rdx,%rcx
311 movb %cl,%al
312 shrq $3,%rcx /* copy longword-wise */
313 cld
314 rep
315 movsq
316 movb %al,%cl
317 andb $7,%cl /* copy remaining bytes */
318 rep
319 movsb
320
321done_copyin:
322 xorl %eax,%eax
323 movq PCPU(curthread),%rdx
324 movq TD_PCB(%rdx), %rdx
325 movq %rax,PCB_ONFAULT(%rdx)
326 ret
327
328 ALIGN_TEXT
329copyin_fault:
330 movq PCPU(curthread),%rdx
331 movq TD_PCB(%rdx), %rdx
332 movq $0,PCB_ONFAULT(%rdx)
333 movq $EFAULT,%rax
334 ret
335
336/*
337 * casuword32. Compare and set user integer. Returns -1 or the current value.
338 * dst = %rdi, old = %rsi, new = %rdx
339 */
340ENTRY(casuword32)
341 movq PCPU(curthread),%rcx
342 movq TD_PCB(%rcx), %rcx
343 movq $fusufault,PCB_ONFAULT(%rcx)
344
345 movq $VM_MAXUSER_ADDRESS-4,%rax
346 cmpq %rax,%rdi /* verify address is valid */
347 ja fusufault
348
349 movl %esi,%eax /* old */
350#ifdef SMP
351 lock
352#endif
353 cmpxchgl %edx,(%rdi) /* new = %edx */
354
355 /*
356 * The old value is in %eax. If the store succeeded it will be the
357 * value we expected (old) from before the store, otherwise it will
358 * be the current value.
359 */
360
361 movq PCPU(curthread),%rcx
362 movq TD_PCB(%rcx), %rcx
363 movq $0,PCB_ONFAULT(%rcx)
364 ret
365
366/*
367 * casuword. Compare and set user word. Returns -1 or the current value.
368 * dst = %rdi, old = %rsi, new = %rdx
369 */
370ENTRY(casuword)
371 movq PCPU(curthread),%rcx
372 movq TD_PCB(%rcx), %rcx
373 movq $fusufault,PCB_ONFAULT(%rcx)
374
375 movq $VM_MAXUSER_ADDRESS-4,%rax
376 cmpq %rax,%rdi /* verify address is valid */
377 ja fusufault
378
379 movq %rsi,%rax /* old */
380#ifdef SMP
381 lock
382#endif
383 cmpxchgq %rdx,(%rdi) /* new = %rdx */
384
385 /*
386 * The old value is in %eax. If the store succeeded it will be the
387 * value we expected (old) from before the store, otherwise it will
388 * be the current value.
389 */
390
391 movq PCPU(curthread),%rcx
392 movq TD_PCB(%rcx), %rcx
393 movq $fusufault,PCB_ONFAULT(%rcx)
394 movq $0,PCB_ONFAULT(%rcx)
395 ret
396
397/*
398 * Fetch (load) a 64-bit word, a 32-bit word, a 16-bit word, or an 8-bit
399 * byte from user memory. All these functions are MPSAFE.
400 * addr = %rdi
401 */
402
403ALTENTRY(fuword64)
404ENTRY(fuword)
405 movq PCPU(curthread),%rcx
406 movq TD_PCB(%rcx), %rcx
407 movq $fusufault,PCB_ONFAULT(%rcx)
408
409 movq $VM_MAXUSER_ADDRESS-8,%rax
410 cmpq %rax,%rdi /* verify address is valid */
411 ja fusufault
412
413 movq (%rdi),%rax
414 movq $0,PCB_ONFAULT(%rcx)
415 ret
416
417ENTRY(fuword32)
418 movq PCPU(curthread),%rcx
419 movq TD_PCB(%rcx), %rcx
420 movq $fusufault,PCB_ONFAULT(%rcx)
421
422 movq $VM_MAXUSER_ADDRESS-4,%rax
423 cmpq %rax,%rdi /* verify address is valid */
424 ja fusufault
425
426 movl (%rdi),%eax
427 movq $0,PCB_ONFAULT(%rcx)
428 ret
429
430/*
431 * fuswintr() and suswintr() are specialized variants of fuword16() and
432 * suword16(), respectively. They are called from the profiling code,
433 * potentially at interrupt time. If they fail, that's okay; good things
434 * will happen later. They always fail for now, until the trap code is
435 * able to deal with this.
436 */
437ALTENTRY(suswintr)
438ENTRY(fuswintr)
439 movq $-1,%rax
440 ret
441
442ENTRY(fuword16)
443 movq PCPU(curthread),%rcx
444 movq TD_PCB(%rcx), %rcx
445 movq $fusufault,PCB_ONFAULT(%rcx)
446
447 movq $VM_MAXUSER_ADDRESS-2,%rax
448 cmpq %rax,%rdi
449 ja fusufault
450
451 movzwl (%rdi),%eax
452 movq $0,PCB_ONFAULT(%rcx)
453 ret
454
455ENTRY(fubyte)
456 movq PCPU(curthread),%rcx
457 movq TD_PCB(%rcx), %rcx
458 movq $fusufault,PCB_ONFAULT(%rcx)
459
460 movq $VM_MAXUSER_ADDRESS-1,%rax
461 cmpq %rax,%rdi
462 ja fusufault
463
464 movzbl (%rdi),%eax
465 movq $0,PCB_ONFAULT(%rcx)
466 ret
467
468 ALIGN_TEXT
469fusufault:
470 movq PCPU(curthread),%rcx
471 xorl %eax,%eax
472 movq TD_PCB(%rcx), %rcx
473 movq %rax,PCB_ONFAULT(%rcx)
474 decq %rax
475 ret
476
477/*
478 * Store a 64-bit word, a 32-bit word, a 16-bit word, or an 8-bit byte to
479 * user memory. All these functions are MPSAFE.
480 * addr = %rdi, value = %rsi
481 */
482ALTENTRY(suword64)
483ENTRY(suword)
484 movq PCPU(curthread),%rcx
485 movq TD_PCB(%rcx), %rcx
486 movq $fusufault,PCB_ONFAULT(%rcx)
487
488 movq $VM_MAXUSER_ADDRESS-8,%rax
489 cmpq %rax,%rdi /* verify address validity */
490 ja fusufault
491
492 movq %rsi,(%rdi)
493 xorl %eax,%eax
494 movq PCPU(curthread),%rcx
495 movq TD_PCB(%rcx), %rcx
496 movq %rax,PCB_ONFAULT(%rcx)
497 ret
498
499ENTRY(suword32)
500 movq PCPU(curthread),%rcx
501 movq TD_PCB(%rcx), %rcx
502 movq $fusufault,PCB_ONFAULT(%rcx)
503
504 movq $VM_MAXUSER_ADDRESS-4,%rax
505 cmpq %rax,%rdi /* verify address validity */
506 ja fusufault
507
508 movl %esi,(%rdi)
509 xorl %eax,%eax
510 movq PCPU(curthread),%rcx
511 movq TD_PCB(%rcx), %rcx
512 movq %rax,PCB_ONFAULT(%rcx)
513 ret
514
515ENTRY(suword16)
516 movq PCPU(curthread),%rcx
517 movq TD_PCB(%rcx), %rcx
518 movq $fusufault,PCB_ONFAULT(%rcx)
519
520 movq $VM_MAXUSER_ADDRESS-2,%rax
521 cmpq %rax,%rdi /* verify address validity */
522 ja fusufault
523
524 movw %si,(%rdi)
525 xorl %eax,%eax
526 movq PCPU(curthread),%rcx /* restore trashed register */
527 movq TD_PCB(%rcx), %rcx
528 movq %rax,PCB_ONFAULT(%rcx)
529 ret
530
531ENTRY(subyte)
532 movq PCPU(curthread),%rcx
533 movq TD_PCB(%rcx), %rcx
534 movq $fusufault,PCB_ONFAULT(%rcx)
535
536 movq $VM_MAXUSER_ADDRESS-1,%rax
537 cmpq %rax,%rdi /* verify address validity */
538 ja fusufault
539
540 movl %esi,%eax
541 movb %al,(%rdi)
542 xorl %eax,%eax
543 movq PCPU(curthread),%rcx /* restore trashed register */
544 movq TD_PCB(%rcx), %rcx
545 movq %rax,PCB_ONFAULT(%rcx)
546 ret
547
548/*
549 * copyinstr(from, to, maxlen, int *lencopied) - MP SAFE
550 * %rdi, %rsi, %rdx, %rcx
551 *
552 * copy a string from from to to, stop when a 0 character is reached.
553 * return ENAMETOOLONG if string is longer than maxlen, and
554 * EFAULT on protection violations. If lencopied is non-zero,
555 * return the actual length in *lencopied.
556 */
557ENTRY(copyinstr)
558 movq %rdx,%r8 /* %r8 = maxlen */
559 movq %rcx,%r9 /* %r9 = *len */
560 xchgq %rdi,%rsi /* %rdi = from, %rsi = to */
561 movq PCPU(curthread),%rcx
562 movq TD_PCB(%rcx), %rcx
563 movq $cpystrflt,PCB_ONFAULT(%rcx)
564
565 movq $VM_MAXUSER_ADDRESS,%rax
566
567 /* make sure 'from' is within bounds */
568 subq %rsi,%rax
569 jbe cpystrflt
570
571 /* restrict maxlen to <= VM_MAXUSER_ADDRESS-from */
572 cmpq %rdx,%rax
573 jae 1f
574 movq %rax,%rdx
575 movq %rax,%r8
5761:
577 incq %rdx
578 cld
579
5802:
581 decq %rdx
582 jz 3f
583
584 lodsb
585 stosb
586 orb %al,%al
587 jnz 2b
588
589 /* Success -- 0 byte reached */
590 decq %rdx
591 xorl %eax,%eax
592 jmp cpystrflt_x
5933:
594 /* rdx is zero - return ENAMETOOLONG or EFAULT */
595 movq $VM_MAXUSER_ADDRESS,%rax
596 cmpq %rax,%rsi
597 jae cpystrflt
5984:
599 movq $ENAMETOOLONG,%rax
600 jmp cpystrflt_x
601
602cpystrflt:
603 movq $EFAULT,%rax
604
605cpystrflt_x:
606 /* set *lencopied and return %eax */
607 movq PCPU(curthread),%rcx
608 movq TD_PCB(%rcx), %rcx
609 movq $0,PCB_ONFAULT(%rcx)
610
611 testq %r9,%r9
612 jz 1f
613 subq %rdx,%r8
614 movq %r8,(%r9)
6151:
616 ret
617
618
619/*
620 * copystr(from, to, maxlen, int *lencopied) - MP SAFE
621 * %rdi, %rsi, %rdx, %rcx
622 */
623ENTRY(copystr)
624 movq %rdx,%r8 /* %r8 = maxlen */
625
626 xchgq %rdi,%rsi
627 incq %rdx
628 cld
6291:
630 decq %rdx
631 jz 4f
632 lodsb
633 stosb
634 orb %al,%al
635 jnz 1b
636
637 /* Success -- 0 byte reached */
638 decq %rdx
639 xorl %eax,%eax
640 jmp 6f
6414:
642 /* rdx is zero -- return ENAMETOOLONG */
643 movq $ENAMETOOLONG,%rax
644
6456:
646
647 testq %rcx,%rcx
648 jz 7f
649 /* set *lencopied and return %rax */
650 subq %rdx,%r8
651 movq %r8,(%rcx)
6527:
653 ret
654
655/*
656 * Handling of special amd64 registers and descriptor tables etc
657 * %rdi
658 */
659/* void lgdt(struct region_descriptor *rdp); */
660ENTRY(lgdt)
661 /* reload the descriptor table */
662 lgdt (%rdi)
663
664 /* flush the prefetch q */
665 jmp 1f
666 nop
6671:
668 movl $KDSEL,%eax
669 movl %eax,%ds
670 movl %eax,%es
671 movl %eax,%fs /* Beware, use wrmsr to set 64 bit base */
672 movl %eax,%gs
673 movl %eax,%ss
674
675 /* reload code selector by turning return into intersegmental return */
676 popq %rax
677 pushq $KCSEL
678 pushq %rax
679 MEXITCOUNT
680 lretq
681
682/*****************************************************************************/
683/* setjump, longjump */
684/*****************************************************************************/
685
686ENTRY(setjmp)
687 movq %rbx,0(%rdi) /* save rbx */
688 movq %rsp,8(%rdi) /* save rsp */
689 movq %rbp,16(%rdi) /* save rbp */
690 movq %r12,24(%rdi) /* save r12 */
691 movq %r13,32(%rdi) /* save r13 */
692 movq %r14,40(%rdi) /* save r14 */
693 movq %r15,48(%rdi) /* save r15 */
694 movq 0(%rsp),%rdx /* get rta */
695 movq %rdx,56(%rdi) /* save rip */
696 xorl %eax,%eax /* return(0); */
697 ret
698
699ENTRY(longjmp)
700 movq 0(%rdi),%rbx /* restore rbx */
701 movq 8(%rdi),%rsp /* restore rsp */
702 movq 16(%rdi),%rbp /* restore rbp */
703 movq 24(%rdi),%r12 /* restore r12 */
704 movq 32(%rdi),%r13 /* restore r13 */
705 movq 40(%rdi),%r14 /* restore r14 */
706 movq 48(%rdi),%r15 /* restore r15 */
707 movq 56(%rdi),%rdx /* get rta */
708 movq %rdx,0(%rsp) /* put in return frame */
709 xorl %eax,%eax /* return(1); */
710 incl %eax
711 ret
712
713/*
714 * Support for BB-profiling (gcc -a). The kernbb program will extract
715 * the data from the kernel.
716 */
717
718 .data
719 ALIGN_DATA
720 .globl bbhead
721bbhead:
722 .quad 0
723
724 .text
725NON_GPROF_ENTRY(__bb_init_func)
726 movq $1,(%rdi)
727 movq bbhead,%rax
728 movq %rax,32(%rdi)
729 movq %rdi,bbhead
730 NON_GPROF_RET