Stop calling set_syscall_retval() from linux_set_syscall_retval().
The former clobbers some registers that shouldn't be touched. Reviewed by: kib (earlier version) MFC after: 2 weeks Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D26406
This commit is contained in:
parent
54669eb779
commit
6221ec6064
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=366810
@ -206,24 +206,45 @@ linux_fetch_syscall_args(struct thread *td)
|
||||
static void
|
||||
linux_set_syscall_retval(struct thread *td, int error)
|
||||
{
|
||||
struct trapframe *frame = td->td_frame;
|
||||
struct trapframe *frame;
|
||||
|
||||
/*
|
||||
* On Linux only %rcx and %r11 values are not preserved across
|
||||
* the syscall. So, do not clobber %rdx and %r10.
|
||||
*/
|
||||
td->td_retval[1] = frame->tf_rdx;
|
||||
if (error != EJUSTRETURN)
|
||||
frame = td->td_frame;
|
||||
|
||||
switch (error) {
|
||||
case 0:
|
||||
frame->tf_rax = td->td_retval[0];
|
||||
frame->tf_r10 = frame->tf_rcx;
|
||||
break;
|
||||
|
||||
case ERESTART:
|
||||
/*
|
||||
* Reconstruct pc, we know that 'syscall' is 2 bytes,
|
||||
* lcall $X,y is 7 bytes, int 0x80 is 2 bytes.
|
||||
* We saved this in tf_err.
|
||||
*
|
||||
*/
|
||||
frame->tf_rip -= frame->tf_err;
|
||||
frame->tf_r10 = frame->tf_rcx;
|
||||
break;
|
||||
|
||||
case EJUSTRETURN:
|
||||
break;
|
||||
|
||||
cpu_set_syscall_retval(td, error);
|
||||
|
||||
if (__predict_false(error != 0)) {
|
||||
if (error != ERESTART && error != EJUSTRETURN)
|
||||
frame->tf_rax = linux_to_bsd_errno(error);
|
||||
default:
|
||||
frame->tf_rax = linux_to_bsd_errno(error);
|
||||
frame->tf_r10 = frame->tf_rcx;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Restore all registers. */
|
||||
/*
|
||||
* Differently from FreeBSD native ABI, on Linux only %rcx
|
||||
* and %r11 values are not preserved across the syscall.
|
||||
* Require full context restore to get all registers except
|
||||
* those two restored at return to usermode.
|
||||
*
|
||||
* XXX: Would be great to be able to avoid PCB_FULL_IRET
|
||||
* for the error == 0 case.
|
||||
*/
|
||||
set_pcb_flags(td->td_pcb, PCB_FULL_IRET);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user