521ea19d1c
sintrcnt/sintrnames which are symbols containing the size of the 2 tables. - For amd64/i386 remove the storage of intr* stuff from assembly files. This area can be widely improved by applying the same to other architectures and likely finding an unified approach among them and move the whole code to be MI. More work in this area is expected to happen fairly soon. No MFC is previewed for this patch. Tested by: pluknet Reviewed by: jhb Approved by: re (kib)
733 lines
15 KiB
ArmAsm
733 lines
15 KiB
ArmAsm
/*-
|
|
* Copyright (c) 2003 Peter Wemm.
|
|
* Copyright (c) 1993 The Regents of the University of California.
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
* 4. Neither the name of the University nor the names of its contributors
|
|
* may be used to endorse or promote products derived from this software
|
|
* without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
* SUCH DAMAGE.
|
|
*
|
|
* $FreeBSD$
|
|
*/
|
|
|
|
#include "opt_ddb.h"
|
|
|
|
#include <machine/asmacros.h>
|
|
#include <machine/intr_machdep.h>
|
|
#include <machine/pmap.h>
|
|
|
|
#include "assym.s"
|
|
|
|
.text
|
|
|
|
/*
|
|
* bcopy family
|
|
* void bzero(void *buf, u_int len)
|
|
*/
|
|
|
|
/* done */
|
|
ENTRY(bzero)
|
|
movq %rsi,%rcx
|
|
xorl %eax,%eax
|
|
shrq $3,%rcx
|
|
cld
|
|
rep
|
|
stosq
|
|
movq %rsi,%rcx
|
|
andq $7,%rcx
|
|
rep
|
|
stosb
|
|
ret
|
|
END(bzero)
|
|
|
|
/* Address: %rdi */
|
|
ENTRY(pagezero)
|
|
movq $-PAGE_SIZE,%rdx
|
|
subq %rdx,%rdi
|
|
xorl %eax,%eax
|
|
1:
|
|
movnti %rax,(%rdi,%rdx)
|
|
movnti %rax,8(%rdi,%rdx)
|
|
movnti %rax,16(%rdi,%rdx)
|
|
movnti %rax,24(%rdi,%rdx)
|
|
addq $32,%rdx
|
|
jne 1b
|
|
sfence
|
|
ret
|
|
END(pagezero)
|
|
|
|
ENTRY(bcmp)
|
|
movq %rdx,%rcx
|
|
shrq $3,%rcx
|
|
cld /* compare forwards */
|
|
repe
|
|
cmpsq
|
|
jne 1f
|
|
|
|
movq %rdx,%rcx
|
|
andq $7,%rcx
|
|
repe
|
|
cmpsb
|
|
1:
|
|
setne %al
|
|
movsbl %al,%eax
|
|
ret
|
|
END(bcmp)
|
|
|
|
/*
|
|
* bcopy(src, dst, cnt)
|
|
* rdi, rsi, rdx
|
|
* ws@tools.de (Wolfgang Solfrank, TooLs GmbH) +49-228-985800
|
|
*/
|
|
ENTRY(bcopy)
|
|
xchgq %rsi,%rdi
|
|
movq %rdx,%rcx
|
|
|
|
movq %rdi,%rax
|
|
subq %rsi,%rax
|
|
cmpq %rcx,%rax /* overlapping && src < dst? */
|
|
jb 1f
|
|
|
|
shrq $3,%rcx /* copy by 64-bit words */
|
|
cld /* nope, copy forwards */
|
|
rep
|
|
movsq
|
|
movq %rdx,%rcx
|
|
andq $7,%rcx /* any bytes left? */
|
|
rep
|
|
movsb
|
|
ret
|
|
|
|
/* ALIGN_TEXT */
|
|
1:
|
|
addq %rcx,%rdi /* copy backwards */
|
|
addq %rcx,%rsi
|
|
decq %rdi
|
|
decq %rsi
|
|
andq $7,%rcx /* any fractional bytes? */
|
|
std
|
|
rep
|
|
movsb
|
|
movq %rdx,%rcx /* copy remainder by 32-bit words */
|
|
shrq $3,%rcx
|
|
subq $7,%rsi
|
|
subq $7,%rdi
|
|
rep
|
|
movsq
|
|
cld
|
|
ret
|
|
END(bcopy)
|
|
|
|
/*
|
|
* Note: memcpy does not support overlapping copies
|
|
*/
|
|
ENTRY(memcpy)
|
|
movq %rdx,%rcx
|
|
shrq $3,%rcx /* copy by 64-bit words */
|
|
cld /* copy forwards */
|
|
rep
|
|
movsq
|
|
movq %rdx,%rcx
|
|
andq $7,%rcx /* any bytes left? */
|
|
rep
|
|
movsb
|
|
ret
|
|
END(memcpy)
|
|
|
|
/*
|
|
* pagecopy(%rdi=from, %rsi=to)
|
|
*/
|
|
ENTRY(pagecopy)
|
|
movq $-PAGE_SIZE,%rax
|
|
movq %rax,%rdx
|
|
subq %rax,%rdi
|
|
subq %rax,%rsi
|
|
1:
|
|
prefetchnta (%rdi,%rax)
|
|
addq $64,%rax
|
|
jne 1b
|
|
2:
|
|
movq (%rdi,%rdx),%rax
|
|
movnti %rax,(%rsi,%rdx)
|
|
movq 8(%rdi,%rdx),%rax
|
|
movnti %rax,8(%rsi,%rdx)
|
|
movq 16(%rdi,%rdx),%rax
|
|
movnti %rax,16(%rsi,%rdx)
|
|
movq 24(%rdi,%rdx),%rax
|
|
movnti %rax,24(%rsi,%rdx)
|
|
addq $32,%rdx
|
|
jne 2b
|
|
sfence
|
|
ret
|
|
END(pagecopy)
|
|
|
|
/* fillw(pat, base, cnt) */
|
|
/* %rdi,%rsi, %rdx */
|
|
ENTRY(fillw)
|
|
movq %rdi,%rax
|
|
movq %rsi,%rdi
|
|
movq %rdx,%rcx
|
|
cld
|
|
rep
|
|
stosw
|
|
ret
|
|
END(fillw)
|
|
|
|
/*****************************************************************************/
|
|
/* copyout and fubyte family */
|
|
/*****************************************************************************/
|
|
/*
|
|
* Access user memory from inside the kernel. These routines should be
|
|
* the only places that do this.
|
|
*
|
|
* These routines set curpcb->onfault for the time they execute. When a
|
|
* protection violation occurs inside the functions, the trap handler
|
|
* returns to *curpcb->onfault instead of the function.
|
|
*/
|
|
|
|
/*
|
|
* copyout(from_kernel, to_user, len) - MP SAFE
|
|
* %rdi, %rsi, %rdx
|
|
*/
|
|
ENTRY(copyout)
|
|
movq PCPU(CURPCB),%rax
|
|
movq $copyout_fault,PCB_ONFAULT(%rax)
|
|
testq %rdx,%rdx /* anything to do? */
|
|
jz done_copyout
|
|
|
|
/*
|
|
* Check explicitly for non-user addresses. If 486 write protection
|
|
* is being used, this check is essential because we are in kernel
|
|
* mode so the h/w does not provide any protection against writing
|
|
* kernel addresses.
|
|
*/
|
|
|
|
/*
|
|
* First, prevent address wrapping.
|
|
*/
|
|
movq %rsi,%rax
|
|
addq %rdx,%rax
|
|
jc copyout_fault
|
|
/*
|
|
* XXX STOP USING VM_MAXUSER_ADDRESS.
|
|
* It is an end address, not a max, so every time it is used correctly it
|
|
* looks like there is an off by one error, and of course it caused an off
|
|
* by one error in several places.
|
|
*/
|
|
movq $VM_MAXUSER_ADDRESS,%rcx
|
|
cmpq %rcx,%rax
|
|
ja copyout_fault
|
|
|
|
xchgq %rdi,%rsi
|
|
/* bcopy(%rsi, %rdi, %rdx) */
|
|
movq %rdx,%rcx
|
|
|
|
shrq $3,%rcx
|
|
cld
|
|
rep
|
|
movsq
|
|
movb %dl,%cl
|
|
andb $7,%cl
|
|
rep
|
|
movsb
|
|
|
|
done_copyout:
|
|
xorl %eax,%eax
|
|
movq PCPU(CURPCB),%rdx
|
|
movq %rax,PCB_ONFAULT(%rdx)
|
|
ret
|
|
|
|
ALIGN_TEXT
|
|
copyout_fault:
|
|
movq PCPU(CURPCB),%rdx
|
|
movq $0,PCB_ONFAULT(%rdx)
|
|
movq $EFAULT,%rax
|
|
ret
|
|
END(copyout)
|
|
|
|
/*
|
|
* copyin(from_user, to_kernel, len) - MP SAFE
|
|
* %rdi, %rsi, %rdx
|
|
*/
|
|
ENTRY(copyin)
|
|
movq PCPU(CURPCB),%rax
|
|
movq $copyin_fault,PCB_ONFAULT(%rax)
|
|
testq %rdx,%rdx /* anything to do? */
|
|
jz done_copyin
|
|
|
|
/*
|
|
* make sure address is valid
|
|
*/
|
|
movq %rdi,%rax
|
|
addq %rdx,%rax
|
|
jc copyin_fault
|
|
movq $VM_MAXUSER_ADDRESS,%rcx
|
|
cmpq %rcx,%rax
|
|
ja copyin_fault
|
|
|
|
xchgq %rdi,%rsi
|
|
movq %rdx,%rcx
|
|
movb %cl,%al
|
|
shrq $3,%rcx /* copy longword-wise */
|
|
cld
|
|
rep
|
|
movsq
|
|
movb %al,%cl
|
|
andb $7,%cl /* copy remaining bytes */
|
|
rep
|
|
movsb
|
|
|
|
done_copyin:
|
|
xorl %eax,%eax
|
|
movq PCPU(CURPCB),%rdx
|
|
movq %rax,PCB_ONFAULT(%rdx)
|
|
ret
|
|
|
|
ALIGN_TEXT
|
|
copyin_fault:
|
|
movq PCPU(CURPCB),%rdx
|
|
movq $0,PCB_ONFAULT(%rdx)
|
|
movq $EFAULT,%rax
|
|
ret
|
|
END(copyin)
|
|
|
|
/*
|
|
* casuword32. Compare and set user integer. Returns -1 or the current value.
|
|
* dst = %rdi, old = %rsi, new = %rdx
|
|
*/
|
|
ENTRY(casuword32)
|
|
movq PCPU(CURPCB),%rcx
|
|
movq $fusufault,PCB_ONFAULT(%rcx)
|
|
|
|
movq $VM_MAXUSER_ADDRESS-4,%rax
|
|
cmpq %rax,%rdi /* verify address is valid */
|
|
ja fusufault
|
|
|
|
movl %esi,%eax /* old */
|
|
#ifdef SMP
|
|
lock
|
|
#endif
|
|
cmpxchgl %edx,(%rdi) /* new = %edx */
|
|
|
|
/*
|
|
* The old value is in %eax. If the store succeeded it will be the
|
|
* value we expected (old) from before the store, otherwise it will
|
|
* be the current value.
|
|
*/
|
|
|
|
movq PCPU(CURPCB),%rcx
|
|
movq $0,PCB_ONFAULT(%rcx)
|
|
ret
|
|
END(casuword32)
|
|
|
|
/*
|
|
* casuword. Compare and set user word. Returns -1 or the current value.
|
|
* dst = %rdi, old = %rsi, new = %rdx
|
|
*/
|
|
ENTRY(casuword)
|
|
movq PCPU(CURPCB),%rcx
|
|
movq $fusufault,PCB_ONFAULT(%rcx)
|
|
|
|
movq $VM_MAXUSER_ADDRESS-4,%rax
|
|
cmpq %rax,%rdi /* verify address is valid */
|
|
ja fusufault
|
|
|
|
movq %rsi,%rax /* old */
|
|
#ifdef SMP
|
|
lock
|
|
#endif
|
|
cmpxchgq %rdx,(%rdi) /* new = %rdx */
|
|
|
|
/*
|
|
* The old value is in %eax. If the store succeeded it will be the
|
|
* value we expected (old) from before the store, otherwise it will
|
|
* be the current value.
|
|
*/
|
|
|
|
movq PCPU(CURPCB),%rcx
|
|
movq $fusufault,PCB_ONFAULT(%rcx)
|
|
movq $0,PCB_ONFAULT(%rcx)
|
|
ret
|
|
END(casuword)
|
|
|
|
/*
|
|
* Fetch (load) a 64-bit word, a 32-bit word, a 16-bit word, or an 8-bit
|
|
* byte from user memory. All these functions are MPSAFE.
|
|
* addr = %rdi
|
|
*/
|
|
|
|
ALTENTRY(fuword64)
|
|
ENTRY(fuword)
|
|
movq PCPU(CURPCB),%rcx
|
|
movq $fusufault,PCB_ONFAULT(%rcx)
|
|
|
|
movq $VM_MAXUSER_ADDRESS-8,%rax
|
|
cmpq %rax,%rdi /* verify address is valid */
|
|
ja fusufault
|
|
|
|
movq (%rdi),%rax
|
|
movq $0,PCB_ONFAULT(%rcx)
|
|
ret
|
|
END(fuword64)
|
|
END(fuword)
|
|
|
|
ENTRY(fuword32)
|
|
movq PCPU(CURPCB),%rcx
|
|
movq $fusufault,PCB_ONFAULT(%rcx)
|
|
|
|
movq $VM_MAXUSER_ADDRESS-4,%rax
|
|
cmpq %rax,%rdi /* verify address is valid */
|
|
ja fusufault
|
|
|
|
movl (%rdi),%eax
|
|
movq $0,PCB_ONFAULT(%rcx)
|
|
ret
|
|
END(fuword32)
|
|
|
|
/*
|
|
* fuswintr() and suswintr() are specialized variants of fuword16() and
|
|
* suword16(), respectively. They are called from the profiling code,
|
|
* potentially at interrupt time. If they fail, that's okay; good things
|
|
* will happen later. They always fail for now, until the trap code is
|
|
* able to deal with this.
|
|
*/
|
|
ALTENTRY(suswintr)
|
|
ENTRY(fuswintr)
|
|
movq $-1,%rax
|
|
ret
|
|
END(suswintr)
|
|
END(fuswintr)
|
|
|
|
ENTRY(fuword16)
|
|
movq PCPU(CURPCB),%rcx
|
|
movq $fusufault,PCB_ONFAULT(%rcx)
|
|
|
|
movq $VM_MAXUSER_ADDRESS-2,%rax
|
|
cmpq %rax,%rdi
|
|
ja fusufault
|
|
|
|
movzwl (%rdi),%eax
|
|
movq $0,PCB_ONFAULT(%rcx)
|
|
ret
|
|
END(fuword16)
|
|
|
|
ENTRY(fubyte)
|
|
movq PCPU(CURPCB),%rcx
|
|
movq $fusufault,PCB_ONFAULT(%rcx)
|
|
|
|
movq $VM_MAXUSER_ADDRESS-1,%rax
|
|
cmpq %rax,%rdi
|
|
ja fusufault
|
|
|
|
movzbl (%rdi),%eax
|
|
movq $0,PCB_ONFAULT(%rcx)
|
|
ret
|
|
END(fubyte)
|
|
|
|
ALIGN_TEXT
|
|
fusufault:
|
|
movq PCPU(CURPCB),%rcx
|
|
xorl %eax,%eax
|
|
movq %rax,PCB_ONFAULT(%rcx)
|
|
decq %rax
|
|
ret
|
|
|
|
/*
|
|
* Store a 64-bit word, a 32-bit word, a 16-bit word, or an 8-bit byte to
|
|
* user memory. All these functions are MPSAFE.
|
|
* addr = %rdi, value = %rsi
|
|
*/
|
|
ALTENTRY(suword64)
|
|
ENTRY(suword)
|
|
movq PCPU(CURPCB),%rcx
|
|
movq $fusufault,PCB_ONFAULT(%rcx)
|
|
|
|
movq $VM_MAXUSER_ADDRESS-8,%rax
|
|
cmpq %rax,%rdi /* verify address validity */
|
|
ja fusufault
|
|
|
|
movq %rsi,(%rdi)
|
|
xorl %eax,%eax
|
|
movq PCPU(CURPCB),%rcx
|
|
movq %rax,PCB_ONFAULT(%rcx)
|
|
ret
|
|
END(suword64)
|
|
END(suword)
|
|
|
|
ENTRY(suword32)
|
|
movq PCPU(CURPCB),%rcx
|
|
movq $fusufault,PCB_ONFAULT(%rcx)
|
|
|
|
movq $VM_MAXUSER_ADDRESS-4,%rax
|
|
cmpq %rax,%rdi /* verify address validity */
|
|
ja fusufault
|
|
|
|
movl %esi,(%rdi)
|
|
xorl %eax,%eax
|
|
movq PCPU(CURPCB),%rcx
|
|
movq %rax,PCB_ONFAULT(%rcx)
|
|
ret
|
|
END(suword32)
|
|
|
|
ENTRY(suword16)
|
|
movq PCPU(CURPCB),%rcx
|
|
movq $fusufault,PCB_ONFAULT(%rcx)
|
|
|
|
movq $VM_MAXUSER_ADDRESS-2,%rax
|
|
cmpq %rax,%rdi /* verify address validity */
|
|
ja fusufault
|
|
|
|
movw %si,(%rdi)
|
|
xorl %eax,%eax
|
|
movq PCPU(CURPCB),%rcx /* restore trashed register */
|
|
movq %rax,PCB_ONFAULT(%rcx)
|
|
ret
|
|
END(suword16)
|
|
|
|
ENTRY(subyte)
|
|
movq PCPU(CURPCB),%rcx
|
|
movq $fusufault,PCB_ONFAULT(%rcx)
|
|
|
|
movq $VM_MAXUSER_ADDRESS-1,%rax
|
|
cmpq %rax,%rdi /* verify address validity */
|
|
ja fusufault
|
|
|
|
movl %esi,%eax
|
|
movb %al,(%rdi)
|
|
xorl %eax,%eax
|
|
movq PCPU(CURPCB),%rcx /* restore trashed register */
|
|
movq %rax,PCB_ONFAULT(%rcx)
|
|
ret
|
|
END(subyte)
|
|
|
|
/*
|
|
* copyinstr(from, to, maxlen, int *lencopied) - MP SAFE
|
|
* %rdi, %rsi, %rdx, %rcx
|
|
*
|
|
* copy a string from from to to, stop when a 0 character is reached.
|
|
* return ENAMETOOLONG if string is longer than maxlen, and
|
|
* EFAULT on protection violations. If lencopied is non-zero,
|
|
* return the actual length in *lencopied.
|
|
*/
|
|
ENTRY(copyinstr)
|
|
movq %rdx,%r8 /* %r8 = maxlen */
|
|
movq %rcx,%r9 /* %r9 = *len */
|
|
xchgq %rdi,%rsi /* %rdi = from, %rsi = to */
|
|
movq PCPU(CURPCB),%rcx
|
|
movq $cpystrflt,PCB_ONFAULT(%rcx)
|
|
|
|
movq $VM_MAXUSER_ADDRESS,%rax
|
|
|
|
/* make sure 'from' is within bounds */
|
|
subq %rsi,%rax
|
|
jbe cpystrflt
|
|
|
|
/* restrict maxlen to <= VM_MAXUSER_ADDRESS-from */
|
|
cmpq %rdx,%rax
|
|
jae 1f
|
|
movq %rax,%rdx
|
|
movq %rax,%r8
|
|
1:
|
|
incq %rdx
|
|
cld
|
|
|
|
2:
|
|
decq %rdx
|
|
jz 3f
|
|
|
|
lodsb
|
|
stosb
|
|
orb %al,%al
|
|
jnz 2b
|
|
|
|
/* Success -- 0 byte reached */
|
|
decq %rdx
|
|
xorl %eax,%eax
|
|
jmp cpystrflt_x
|
|
3:
|
|
/* rdx is zero - return ENAMETOOLONG or EFAULT */
|
|
movq $VM_MAXUSER_ADDRESS,%rax
|
|
cmpq %rax,%rsi
|
|
jae cpystrflt
|
|
4:
|
|
movq $ENAMETOOLONG,%rax
|
|
jmp cpystrflt_x
|
|
|
|
cpystrflt:
|
|
movq $EFAULT,%rax
|
|
|
|
cpystrflt_x:
|
|
/* set *lencopied and return %eax */
|
|
movq PCPU(CURPCB),%rcx
|
|
movq $0,PCB_ONFAULT(%rcx)
|
|
|
|
testq %r9,%r9
|
|
jz 1f
|
|
subq %rdx,%r8
|
|
movq %r8,(%r9)
|
|
1:
|
|
ret
|
|
END(copyinstr)
|
|
|
|
/*
|
|
* copystr(from, to, maxlen, int *lencopied) - MP SAFE
|
|
* %rdi, %rsi, %rdx, %rcx
|
|
*/
|
|
ENTRY(copystr)
|
|
movq %rdx,%r8 /* %r8 = maxlen */
|
|
|
|
xchgq %rdi,%rsi
|
|
incq %rdx
|
|
cld
|
|
1:
|
|
decq %rdx
|
|
jz 4f
|
|
lodsb
|
|
stosb
|
|
orb %al,%al
|
|
jnz 1b
|
|
|
|
/* Success -- 0 byte reached */
|
|
decq %rdx
|
|
xorl %eax,%eax
|
|
jmp 6f
|
|
4:
|
|
/* rdx is zero -- return ENAMETOOLONG */
|
|
movq $ENAMETOOLONG,%rax
|
|
|
|
6:
|
|
|
|
testq %rcx,%rcx
|
|
jz 7f
|
|
/* set *lencopied and return %rax */
|
|
subq %rdx,%r8
|
|
movq %r8,(%rcx)
|
|
7:
|
|
ret
|
|
END(copystr)
|
|
|
|
/*
|
|
* Handling of special amd64 registers and descriptor tables etc
|
|
* %rdi
|
|
*/
|
|
/* void lgdt(struct region_descriptor *rdp); */
|
|
ENTRY(lgdt)
|
|
/* reload the descriptor table */
|
|
lgdt (%rdi)
|
|
|
|
/* flush the prefetch q */
|
|
jmp 1f
|
|
nop
|
|
1:
|
|
movl $KDSEL,%eax
|
|
movl %eax,%ds
|
|
movl %eax,%es
|
|
movl %eax,%fs /* Beware, use wrmsr to set 64 bit base */
|
|
movl %eax,%gs
|
|
movl %eax,%ss
|
|
|
|
/* reload code selector by turning return into intersegmental return */
|
|
popq %rax
|
|
pushq $KCSEL
|
|
pushq %rax
|
|
MEXITCOUNT
|
|
lretq
|
|
END(lgdt)
|
|
|
|
/*****************************************************************************/
|
|
/* setjump, longjump */
|
|
/*****************************************************************************/
|
|
|
|
ENTRY(setjmp)
|
|
movq %rbx,0(%rdi) /* save rbx */
|
|
movq %rsp,8(%rdi) /* save rsp */
|
|
movq %rbp,16(%rdi) /* save rbp */
|
|
movq %r12,24(%rdi) /* save r12 */
|
|
movq %r13,32(%rdi) /* save r13 */
|
|
movq %r14,40(%rdi) /* save r14 */
|
|
movq %r15,48(%rdi) /* save r15 */
|
|
movq 0(%rsp),%rdx /* get rta */
|
|
movq %rdx,56(%rdi) /* save rip */
|
|
xorl %eax,%eax /* return(0); */
|
|
ret
|
|
END(setjmp)
|
|
|
|
ENTRY(longjmp)
|
|
movq 0(%rdi),%rbx /* restore rbx */
|
|
movq 8(%rdi),%rsp /* restore rsp */
|
|
movq 16(%rdi),%rbp /* restore rbp */
|
|
movq 24(%rdi),%r12 /* restore r12 */
|
|
movq 32(%rdi),%r13 /* restore r13 */
|
|
movq 40(%rdi),%r14 /* restore r14 */
|
|
movq 48(%rdi),%r15 /* restore r15 */
|
|
movq 56(%rdi),%rdx /* get rta */
|
|
movq %rdx,0(%rsp) /* put in return frame */
|
|
xorl %eax,%eax /* return(1); */
|
|
incl %eax
|
|
ret
|
|
END(longjmp)
|
|
|
|
/*
|
|
* Support for reading MSRs in the safe manner.
|
|
*/
|
|
ENTRY(rdmsr_safe)
|
|
/* int rdmsr_safe(u_int msr, uint64_t *data) */
|
|
movq PCPU(CURPCB),%r8
|
|
movq $msr_onfault,PCB_ONFAULT(%r8)
|
|
movl %edi,%ecx
|
|
rdmsr /* Read MSR pointed by %ecx. Returns
|
|
hi byte in edx, lo in %eax */
|
|
salq $32,%rdx /* sign-shift %rdx left */
|
|
movl %eax,%eax /* zero-extend %eax -> %rax */
|
|
orq %rdx,%rax
|
|
movq %rax,(%rsi)
|
|
xorq %rax,%rax
|
|
movq %rax,PCB_ONFAULT(%r8)
|
|
ret
|
|
|
|
/*
|
|
* Support for writing MSRs in the safe manner.
|
|
*/
|
|
ENTRY(wrmsr_safe)
|
|
/* int wrmsr_safe(u_int msr, uint64_t data) */
|
|
movq PCPU(CURPCB),%r8
|
|
movq $msr_onfault,PCB_ONFAULT(%r8)
|
|
movl %edi,%ecx
|
|
movl %esi,%eax
|
|
sarq $32,%rsi
|
|
movl %esi,%edx
|
|
wrmsr /* Write MSR pointed by %ecx. Accepts
|
|
hi byte in edx, lo in %eax. */
|
|
xorq %rax,%rax
|
|
movq %rax,PCB_ONFAULT(%r8)
|
|
ret
|
|
|
|
/*
|
|
* MSR operations fault handler
|
|
*/
|
|
ALIGN_TEXT
|
|
msr_onfault:
|
|
movq $0,PCB_ONFAULT(%r8)
|
|
movl $EFAULT,%eax
|
|
ret
|