Changeset View
Changeset View
Standalone View
Standalone View
sys/i386/i386/support.s
Show First 20 Lines • Show All 245 Lines • ▼ Show 20 Lines | ENTRY(memcpy) | ||||
andl $3,%ecx /* any bytes left? */ | andl $3,%ecx /* any bytes left? */ | ||||
rep | rep | ||||
movsb | movsb | ||||
popl %esi | popl %esi | ||||
popl %edi | popl %edi | ||||
ret | ret | ||||
END(memcpy) | END(memcpy) | ||||
/*****************************************************************************/ | |||||
/* 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->pcb_onfault for the time they execute. When a | |||||
* protection violation occurs inside the functions, the trap handler | |||||
* returns to *curpcb->pcb_onfault instead of the function. | |||||
*/ | |||||
/* | |||||
* copyout(from_kernel, to_user, len) - MP SAFE | |||||
*/ | |||||
ENTRY(copyout) | |||||
movl PCPU(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. This check is essential | |||||
* because it prevents usermode from writing into the kernel. We do | |||||
* not verify anywhere else that the user did not specify a rogue | |||||
* address. | |||||
*/ | |||||
/* | |||||
* 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) */ | |||||
movl %ebx,%ecx | |||||
shrl $2,%ecx | |||||
rep | |||||
movsl | |||||
movb %bl,%cl | |||||
andb $3,%cl | |||||
rep | |||||
movsb | |||||
done_copyout: | |||||
popl %ebx | |||||
popl %edi | |||||
popl %esi | |||||
xorl %eax,%eax | |||||
movl PCPU(CURPCB),%edx | |||||
movl %eax,PCB_ONFAULT(%edx) | |||||
ret | |||||
END(copyout) | |||||
ALIGN_TEXT | |||||
copyout_fault: | |||||
popl %ebx | |||||
popl %edi | |||||
popl %esi | |||||
movl PCPU(CURPCB),%edx | |||||
movl $0,PCB_ONFAULT(%edx) | |||||
movl $EFAULT,%eax | |||||
ret | |||||
/* | |||||
* copyin(from_user, to_kernel, len) - MP SAFE | |||||
*/ | |||||
ENTRY(copyin) | |||||
movl PCPU(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 | |||||
movb %cl,%al | |||||
shrl $2,%ecx /* copy longword-wise */ | |||||
rep | |||||
movsl | |||||
movb %al,%cl | |||||
andb $3,%cl /* copy remaining bytes */ | |||||
rep | |||||
movsb | |||||
popl %edi | |||||
popl %esi | |||||
xorl %eax,%eax | |||||
movl PCPU(CURPCB),%edx | |||||
movl %eax,PCB_ONFAULT(%edx) | |||||
ret | |||||
END(copyin) | |||||
ALIGN_TEXT | |||||
copyin_fault: | |||||
popl %edi | |||||
popl %esi | |||||
movl PCPU(CURPCB),%edx | |||||
movl $0,PCB_ONFAULT(%edx) | |||||
movl $EFAULT,%eax | |||||
ret | |||||
/* | |||||
* casueword. Compare and set user word. Returns -1 on fault, | |||||
* 0 on non-faulting access. The current value is in *oldp. | |||||
*/ | |||||
ALTENTRY(casueword32) | |||||
ENTRY(casueword) | |||||
movl PCPU(CURPCB),%ecx | |||||
movl $fusufault,PCB_ONFAULT(%ecx) | |||||
movl 4(%esp),%edx /* dst */ | |||||
movl 8(%esp),%eax /* old */ | |||||
movl 16(%esp),%ecx /* new */ | |||||
cmpl $VM_MAXUSER_ADDRESS-4,%edx /* verify address is valid */ | |||||
ja fusufault | |||||
#ifdef SMP | |||||
lock | |||||
#endif | |||||
cmpxchgl %ecx,(%edx) /* Compare and set. */ | |||||
/* | |||||
* 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. | |||||
*/ | |||||
movl PCPU(CURPCB),%ecx | |||||
movl $0,PCB_ONFAULT(%ecx) | |||||
movl 12(%esp),%edx /* oldp */ | |||||
movl %eax,(%edx) | |||||
xorl %eax,%eax | |||||
ret | |||||
END(casueword32) | |||||
END(casueword) | |||||
/* | |||||
* Fetch (load) a 32-bit word, a 16-bit word, or an 8-bit byte from user | |||||
* memory. | |||||
*/ | |||||
ALTENTRY(fueword32) | |||||
ENTRY(fueword) | |||||
movl PCPU(CURPCB),%ecx | |||||
movl $fusufault,PCB_ONFAULT(%ecx) | |||||
movl 4(%esp),%edx /* from */ | |||||
cmpl $VM_MAXUSER_ADDRESS-4,%edx /* verify address is valid */ | |||||
ja fusufault | |||||
movl (%edx),%eax | |||||
movl $0,PCB_ONFAULT(%ecx) | |||||
movl 8(%esp),%edx | |||||
movl %eax,(%edx) | |||||
xorl %eax,%eax | |||||
ret | |||||
END(fueword32) | |||||
END(fueword) | |||||
/* | |||||
* fuswintr() and suswintr() are specialized variants of fuword16() and | * fuswintr() and suswintr() are specialized variants of fuword16() and | ||||
* suword16(), respectively. They are called from the profiling code, | * suword16(), respectively. They are called from the profiling code, | ||||
* potentially at interrupt time. If they fail, that's okay; good things | * 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 | * will happen later. They always fail for now, until the trap code is | ||||
* able to deal with this. | * able to deal with this. | ||||
*/ | */ | ||||
ALTENTRY(suswintr) | ALTENTRY(suswintr) | ||||
ENTRY(fuswintr) | ENTRY(fuswintr) | ||||
movl $-1,%eax | movl $-1,%eax | ||||
ret | ret | ||||
END(suswintr) | END(suswintr) | ||||
END(fuswintr) | END(fuswintr) | ||||
ENTRY(fuword16) | |||||
movl PCPU(CURPCB),%ecx | |||||
movl $fusufault,PCB_ONFAULT(%ecx) | |||||
movl 4(%esp),%edx | |||||
cmpl $VM_MAXUSER_ADDRESS-2,%edx | |||||
ja fusufault | |||||
movzwl (%edx),%eax | |||||
movl $0,PCB_ONFAULT(%ecx) | |||||
ret | |||||
END(fuword16) | |||||
ENTRY(fubyte) | |||||
movl PCPU(CURPCB),%ecx | |||||
movl $fusufault,PCB_ONFAULT(%ecx) | |||||
movl 4(%esp),%edx | |||||
cmpl $VM_MAXUSER_ADDRESS-1,%edx | |||||
ja fusufault | |||||
movzbl (%edx),%eax | |||||
movl $0,PCB_ONFAULT(%ecx) | |||||
ret | |||||
END(fubyte) | |||||
ALIGN_TEXT | |||||
fusufault: | |||||
movl PCPU(CURPCB),%ecx | |||||
xorl %eax,%eax | |||||
movl %eax,PCB_ONFAULT(%ecx) | |||||
decl %eax | |||||
ret | |||||
/* | |||||
* Store a 32-bit word, a 16-bit word, or an 8-bit byte to user memory. | |||||
* All these functions are MPSAFE. | |||||
*/ | |||||
ALTENTRY(suword32) | |||||
ENTRY(suword) | |||||
movl PCPU(CURPCB),%ecx | |||||
movl $fusufault,PCB_ONFAULT(%ecx) | |||||
movl 4(%esp),%edx | |||||
cmpl $VM_MAXUSER_ADDRESS-4,%edx /* verify address validity */ | |||||
ja fusufault | |||||
movl 8(%esp),%eax | |||||
movl %eax,(%edx) | |||||
xorl %eax,%eax | |||||
movl PCPU(CURPCB),%ecx | |||||
movl %eax,PCB_ONFAULT(%ecx) | |||||
ret | |||||
END(suword32) | |||||
END(suword) | |||||
ENTRY(suword16) | |||||
movl PCPU(CURPCB),%ecx | |||||
movl $fusufault,PCB_ONFAULT(%ecx) | |||||
movl 4(%esp),%edx | |||||
cmpl $VM_MAXUSER_ADDRESS-2,%edx /* verify address validity */ | |||||
ja fusufault | |||||
movw 8(%esp),%ax | |||||
movw %ax,(%edx) | |||||
xorl %eax,%eax | |||||
movl PCPU(CURPCB),%ecx /* restore trashed register */ | |||||
movl %eax,PCB_ONFAULT(%ecx) | |||||
ret | |||||
END(suword16) | |||||
ENTRY(subyte) | |||||
movl PCPU(CURPCB),%ecx | |||||
movl $fusufault,PCB_ONFAULT(%ecx) | |||||
movl 4(%esp),%edx | |||||
cmpl $VM_MAXUSER_ADDRESS-1,%edx /* verify address validity */ | |||||
ja fusufault | |||||
movb 8(%esp),%al | |||||
movb %al,(%edx) | |||||
xorl %eax,%eax | |||||
movl PCPU(CURPCB),%ecx /* restore trashed register */ | |||||
movl %eax,PCB_ONFAULT(%ecx) | |||||
ret | |||||
END(subyte) | |||||
/* | |||||
* copyinstr(from, to, maxlen, int *lencopied) - MP SAFE | |||||
* | |||||
* 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) | |||||
pushl %esi | |||||
pushl %edi | |||||
movl PCPU(CURPCB),%ecx | |||||
movl $cpystrflt,PCB_ONFAULT(%ecx) | |||||
movl 12(%esp),%esi /* %esi = from */ | |||||
movl 16(%esp),%edi /* %edi = to */ | |||||
movl 20(%esp),%edx /* %edx = maxlen */ | |||||
movl $VM_MAXUSER_ADDRESS,%eax | |||||
/* make sure 'from' is within bounds */ | |||||
subl %esi,%eax | |||||
jbe cpystrflt | |||||
/* restrict maxlen to <= VM_MAXUSER_ADDRESS-from */ | |||||
cmpl %edx,%eax | |||||
jae 1f | |||||
movl %eax,%edx | |||||
movl %eax,20(%esp) | |||||
1: | |||||
incl %edx | |||||
2: | |||||
decl %edx | |||||
jz 3f | |||||
lodsb | |||||
stosb | |||||
orb %al,%al | |||||
jnz 2b | |||||
/* Success -- 0 byte reached */ | |||||
decl %edx | |||||
xorl %eax,%eax | |||||
jmp cpystrflt_x | |||||
3: | |||||
/* edx is zero - return ENAMETOOLONG or EFAULT */ | |||||
cmpl $VM_MAXUSER_ADDRESS,%esi | |||||
jae cpystrflt | |||||
4: | |||||
movl $ENAMETOOLONG,%eax | |||||
jmp cpystrflt_x | |||||
cpystrflt: | |||||
movl $EFAULT,%eax | |||||
cpystrflt_x: | |||||
/* set *lencopied and return %eax */ | |||||
movl PCPU(CURPCB),%ecx | |||||
movl $0,PCB_ONFAULT(%ecx) | |||||
movl 20(%esp),%ecx | |||||
subl %edx,%ecx | |||||
movl 24(%esp),%edx | |||||
testl %edx,%edx | |||||
jz 1f | |||||
movl %ecx,(%edx) | |||||
1: | |||||
popl %edi | |||||
popl %esi | |||||
ret | |||||
END(copyinstr) | |||||
/* | /* | ||||
* copystr(from, to, maxlen, int *lencopied) - MP SAFE | * copystr(from, to, maxlen, int *lencopied) - MP SAFE | ||||
*/ | */ | ||||
ENTRY(copystr) | ENTRY(copystr) | ||||
pushl %esi | pushl %esi | ||||
pushl %edi | pushl %edi | ||||
▲ Show 20 Lines • Show All 212 Lines • Show Last 20 Lines |