📄 bcopy.s
字号:
fildq 48(%esi)
fildq 56(%esi)
fistpq 56(%edi)
fistpq 48(%edi)
fistpq 40(%edi)
fistpq 32(%edi)
fistpq 24(%edi)
fistpq 16(%edi)
fistpq 8(%edi)
fistpq 0(%edi)
addl $64,%esi
addl $64,%edi
subl $64,%ecx
cmpl $64,%ecx
jae large_i586_bcopy_loop
popl %eax
addl %eax,%ecx
cmpl $64,%ecx
jae 4b
cmpl $0,_npxproc
je i586_bc2
frstor 0(%esp)
addl $108,%esp
i586_bc2:
lmsw %dx
movb $0xfe,kernel_fpu_lock
/*
* This is a duplicate of the main part of generic_bcopy. See the comments
* there. Jumping into generic_bcopy would cost a whole 0-1 cycles and
* would mess up high resolution profiling.
*/
ALIGN_TEXT
small_i586_bcopy:
shrl $2,%ecx
cld
rep
movsl
movl 20(%esp),%ecx
andl $3,%ecx
rep
movsb
popl %edi
popl %esi
ret
ALIGN_TEXT
1:
addl %ecx,%edi
addl %ecx,%esi
decl %edi
decl %esi
andl $3,%ecx
std
rep
movsb
movl 20(%esp),%ecx
shrl $2,%ecx
subl $3,%esi
subl $3,%edi
rep
movsl
popl %edi
popl %esi
cld
ret
#endif /* I586_CPU && NNPX > 0 */
/*
* Note: memcpy does not support overlapping copies
*/
ENTRY(memcpy)
pushl %edi
pushl %esi
movl 12(%esp),%edi
movl 16(%esp),%esi
movl 20(%esp),%ecx
movl %edi,%eax
shrl $2,%ecx /* copy by 32-bit words */
cld /* nope, copy forwards */
rep
movsl
movl 20(%esp),%ecx
andl $3,%ecx /* any bytes left? */
rep
movsb
popl %esi
popl %edi
ret
/*****************************************************************************/
/* copyout and fubyte family */
/*****************************************************************************/
/*
* Access user memory from inside the kernel. These routines and possibly
* the math- and DOS emulators should be the only places that do this.
*
* We have to access the memory with user's permissions, so use a segment
* selector with RPL 3. For writes to user space we have to additionally
* check the PTE for write permission, because the 386 does not check
* write permissions when we are executing with EPL 0. The 486 does check
* this if the WP bit is set in CR0, so we can use a simpler version here.
*
* 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) */
ENTRY(copyout)
MEXITCOUNT
jmp *_copyout_vector
ENTRY(generic_copyout)
movl _curpcb,%eax
movl $copyout_fault,PCB_ONFAULT(%eax)
pushl %esi
pushl %edi
pushl %ebx
movl 16(%esp),%esi
movl 20(%esp),%edi
movl 24(%esp),%ebx
testl %ebx,%ebx /* 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.
*/
movl %edi,%eax
addl %ebx,%eax
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.
*/
cmpl $VM_MAXUSER_ADDRESS,%eax
ja copyout_fault
#if defined(I386_CPU)
#if defined(I486_CPU) || defined(I586_CPU) || defined(I686_CPU)
cmpl $CPUCLASS_386,_cpu_class
jne 3f
#endif
/*
* We have to check each PTE for user write permission.
* The checking may cause a page fault, so it is important to set
* up everything for return via copyout_fault before here.
*/
/* compute number of pages */
movl %edi,%ecx
andl $PAGE_MASK,%ecx
addl %ebx,%ecx
decl %ecx
shrl $IDXSHIFT+2,%ecx
incl %ecx
/* compute PTE offset for start address */
movl %edi,%edx
shrl $IDXSHIFT,%edx
andb $0xfc,%dl
1:
/* check PTE for each page */
leal _PTmap(%edx),%eax
shrl $IDXSHIFT,%eax
andb $0xfc,%al
testb $PG_V,_PTmap(%eax) /* PTE page must be valid */
je 4f
movb _PTmap(%edx),%al
andb $PG_V|PG_RW|PG_U,%al /* page must be valid and user writable */
cmpb $PG_V|PG_RW|PG_U,%al
je 2f
4:
/* simulate a trap */
pushl %edx
pushl %ecx
shll $IDXSHIFT,%edx
pushl %edx
call _trapwrite /* trapwrite(addr) */
popl %edx
popl %ecx
popl %edx
testl %eax,%eax /* if not ok, return EFAULT */
jnz copyout_fault
2:
addl $4,%edx
decl %ecx
jnz 1b /* check next page */
#endif /* I386_CPU */
/* bcopy(%esi, %edi, %ebx) */
3:
movl %ebx,%ecx
#if defined(I586_CPU) && NNPX > 0
ALIGN_TEXT
slow_copyout:
#endif
shrl $2,%ecx
cld
rep
movsl
movb %bl,%cl
andb $3,%cl
rep
movsb
done_copyout:
popl %ebx
popl %edi
popl %esi
xorl %eax,%eax
movl _curpcb,%edx
movl %eax,PCB_ONFAULT(%edx)
ret
ALIGN_TEXT
copyout_fault:
popl %ebx
popl %edi
popl %esi
movl _curpcb,%edx
movl $0,PCB_ONFAULT(%edx)
movl $EFAULT,%eax
ret
#if defined(I586_CPU) && NNPX > 0
ENTRY(i586_copyout)
/*
* Duplicated from generic_copyout. Could be done a bit better.
*/
movl _curpcb,%eax
movl $copyout_fault,PCB_ONFAULT(%eax)
pushl %esi
pushl %edi
pushl %ebx
movl 16(%esp),%esi
movl 20(%esp),%edi
movl 24(%esp),%ebx
testl %ebx,%ebx /* 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.
*/
movl %edi,%eax
addl %ebx,%eax
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.
*/
cmpl $VM_MAXUSER_ADDRESS,%eax
ja copyout_fault
/* bcopy(%esi, %edi, %ebx) */
3:
movl %ebx,%ecx
/*
* End of duplicated code.
*/
cmpl $1024,%ecx
jb slow_copyout
pushl %ecx
call _fastmove
addl $4,%esp
jmp done_copyout
#endif /* I586_CPU && NNPX > 0 */
/* copyin(from_user, to_kernel, len) */
ENTRY(copyin)
MEXITCOUNT
jmp *_copyin_vector
ENTRY(generic_copyin)
movl _curpcb,%eax
movl $copyin_fault,PCB_ONFAULT(%eax)
pushl %esi
pushl %edi
movl 12(%esp),%esi /* caddr_t from */
movl 16(%esp),%edi /* caddr_t to */
movl 20(%esp),%ecx /* size_t len */
/*
* make sure address is valid
*/
movl %esi,%edx
addl %ecx,%edx
jc copyin_fault
cmpl $VM_MAXUSER_ADDRESS,%edx
ja copyin_fault
#if defined(I586_CPU) && NNPX > 0
ALIGN_TEXT
slow_copyin:
#endif
movb %cl,%al
shrl $2,%ecx /* copy longword-wise */
cld
rep
movsl
movb %al,%cl
andb $3,%cl /* copy remaining bytes */
rep
movsb
#if defined(I586_CPU) && NNPX > 0
ALIGN_TEXT
done_copyin:
#endif
popl %edi
popl %esi
xorl %eax,%eax
movl _curpcb,%edx
movl %eax,PCB_ONFAULT(%edx)
ret
ALIGN_TEXT
copyin_fault:
popl %edi
popl %esi
movl _curpcb,%edx
movl $0,PCB_ONFAULT(%edx)
movl $EFAULT,%eax
ret
#if defined(I586_CPU) && NNPX > 0
ENTRY(i586_copyin)
/*
* Duplicated from generic_copyin. Could be done a bit better.
*/
movl _curpcb,%eax
movl $copyin_fault,PCB_ONFAULT(%eax)
pushl %esi
pushl %edi
movl 12(%esp),%esi /* caddr_t from */
movl 16(%esp),%edi /* caddr_t to */
movl 20(%esp),%ecx /* size_t len */
/*
* make sure address is valid
*/
movl %esi,%edx
addl %ecx,%edx
jc copyin_fault
cmpl $VM_MAXUSER_ADDRESS,%edx
ja copyin_fault
/*
* End of duplicated code.
*/
cmpl $1024,%ecx
jb slow_copyin
pushl %ebx /* XXX prepare for fastmove_fault */
pushl %ecx
call _fastmove
addl $8,%esp
jmp done_copyin
#endif /* I586_CPU && NNPX > 0 */
#if defined(I586_CPU) && NNPX > 0
/* fastmove(src, dst, len)
src in %esi
dst in %edi
len in %ecx XXX changed to on stack for profiling
uses %eax and %edx for tmp. storage
*/
/* XXX use ENTRY() to get profiling. fastmove() is actually a non-entry. */
ENTRY(fastmove)
pushl %ebp
movl %esp,%ebp
subl $PCB_SAVEFPU_SIZE+3*4,%esp
movl 8(%ebp),%ecx
cmpl $63,%ecx
jbe fastmove_tail
testl $7,%esi /* check if src addr is multiple of 8 */
jnz fastmove_tail
testl $7,%edi /* check if dst addr is multiple of 8 */
jnz fastmove_tail
/* if (npxproc != NULL) { */
cmpl $0,_npxproc
je 6f
/* fnsave(&curpcb->pcb_savefpu); */
movl _curpcb,%eax
fnsave PCB_SAVEFPU(%eax)
/* npxproc = NULL; */
movl $0,_npxproc
/* } */
6:
/* now we own the FPU. */
/*
* The process' FP state is saved in the pcb, but if we get
* switched, the cpu_switch() will store our FP state in the
* pcb. It should be possible to avoid all the copying for
* this, e.g., by setting a flag to tell cpu_switch() to
* save the state somewhere else.
*/
/* tmp = curpcb->pcb_savefpu; */
movl %ecx,-12(%ebp)
movl %esi,-8(%ebp)
movl %edi,-4(%ebp)
movl %esp,%edi
movl _curpcb,%esi
addl $PCB_SAVEFPU,%esi
cld
movl $PCB_SAVEFPU_SIZE>>2,%ecx
rep
movsl
movl -12(%ebp),%ecx
movl -8(%ebp),%esi
movl -4(%ebp),%edi
/* stop_emulating(); */
clts
/* npxproc = curproc; */
movl _curproc,%eax
movl %eax,_npxproc
movl _curpcb,%eax
movl $fastmove_fault,PCB_ONFAULT(%eax)
4:
movl %ecx,-12(%ebp)
cmpl $1792,%ecx
jbe 2f
movl $1792,%ecx
2:
subl %ecx,-12(%ebp)
cmpl $256,%ecx
jb 5f
movl %ecx,-8(%ebp)
movl %esi,-4(%ebp)
ALIGN_TEXT
3:
movl 0(%esi),%eax
movl 32(%esi),%eax
movl 64(%esi),%eax
movl 96(%esi),%eax
movl 128(%esi),%eax
movl 160(%esi),%eax
movl 192(%esi),%eax
movl 224(%esi),%eax
addl $256,%esi
subl $256,%ecx
cmpl $256,%ecx
jae 3b
movl -8(%ebp),%ecx
movl -4(%ebp),%esi
5:
ALIGN_TEXT
fastmove_loop:
fildq 0(%esi)
fildq 8(%esi)
fildq 16(%esi)
fildq 24(%esi)
fildq 32(%esi)
fildq 40(%esi)
fildq 48(%esi)
fildq 56(%esi)
fistpq 56(%edi)
fistpq 48(%edi)
fistpq 40(%edi)
fistpq 32(%edi)
fistpq 24(%edi)
fistpq 16(%edi)
fistpq 8(%edi)
fistpq 0(%edi)
addl $-64,%ecx
addl $64,%esi
addl $64,%edi
cmpl $63,%ecx
ja fastmove_loop
movl -12(%ebp),%eax
addl %eax,%ecx
cmpl $64,%ecx
jae 4b
/* curpcb->pcb_savefpu = tmp; */
movl %ecx,-12(%ebp)
movl %esi,-8(%ebp)
movl %edi,-4(%ebp)
movl _curpcb,%edi
addl $PCB_SAVEFPU,%edi
movl %esp,%esi
cld
movl $PCB_SAVEFPU_SIZE>>2,%ecx
rep
movsl
movl -12(%ebp),%ecx
movl -8(%ebp),%esi
movl -4(%ebp),%edi
/* start_emulating(); */
smsw %ax
orb $CR0_TS,%al
lmsw %ax
/* npxproc = NULL; */
movl $0,_npxproc
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -