Commit 985e00fe authored by Mao Minkai's avatar Mao Minkai Committed by guzitao
Browse files

sw64: expand struct pt_regs

Sunway inclusion
category: feature
bugzilla: https://gitee.com/openeuler/kernel/issues/I8CCP8



--------------------------------

Add three new members to pt_regs
  - orig_r0: stores the r0 before syscall
  - orig_r19: stores the r19 before syscall

Since the syscall_nr is stored in r0, orig_r0 will be set to -1 in
non-syscall context or when syscall is complete.

Modify syscall process accordingly.

Signed-off-by: default avatarMao Minkai <maominkai@wxiat.com>
Reviewed-by: default avatarHe Sheng <hesheng@wxiat.com>
Signed-off-by: default avatarGu Zitao <guzitao@wxiat.com>
parent 1ecccb6a
Loading
Loading
Loading
Loading
+14 −3
Original line number Diff line number Diff line
@@ -6,6 +6,11 @@
#include <asm/hmcall.h>
#include <asm/page.h>

#define NO_SYSCALL	(-1)

#ifdef __KERNEL__
#ifndef __ASSEMBLY__

/*
 * This struct defines the way the registers are stored on the
 * kernel stack during a system call or other kernel entry
@@ -20,6 +25,8 @@ struct pt_regs {
			unsigned long ps;
		};
	};
	unsigned long orig_r0;
	unsigned long orig_r19;
	/* These are saved by HMcode: */
	unsigned long hm_ps;
	unsigned long hm_pc;
@@ -37,9 +44,9 @@ struct pt_regs {
#define kernel_stack_pointer(regs) ((unsigned long)((regs) + 1))
#define instruction_pointer_set(regs, val) ((regs)->pc = val)

#define force_successful_syscall_return() (current_pt_regs()->regs[0] = 0)
#define force_successful_syscall_return() (current_pt_regs()->orig_r0 = NO_SYSCALL)

#define MAX_REG_OFFSET (offsetof(struct pt_regs, ps))
#define MAX_REG_OFFSET (offsetof(struct pt_regs, orig_r0))

extern short regoffsets[];

@@ -70,9 +77,13 @@ static inline int is_syscall_success(struct pt_regs *regs)

static inline long regs_return_value(struct pt_regs *regs)
{
	if (is_syscall_success(regs) || !user_mode(regs))
	if ((regs->orig_r0 == NO_SYSCALL) || is_syscall_success(regs))
		return regs->regs[0];
	else
		return -regs->regs[0];
}

#endif /* !__ASSEMBLY__ */
#endif /* __KERNEL__ */

#endif /* _ASM_SW64_PTRACE_H */
+3 −3
Original line number Diff line number Diff line
@@ -29,18 +29,18 @@ static inline void syscall_set_return_value(struct task_struct *task,
{
	if (error) {
		regs->regs[0]  = -error;
		regs->regs[19] = -1;
		regs->regs[19] = 1;
	} else {
		regs->regs[0] = val;
		regs->regs[19] = 0;
	}
}


static inline void syscall_rollback(struct task_struct *task,
				    struct pt_regs *regs)
{
	/* Do nothing */
	regs->regs[0] = regs->orig_r0;
	regs->regs[19] = regs->orig_r19;
}

static inline void syscall_get_arguments(struct task_struct *task,
+2 −0
Original line number Diff line number Diff line
@@ -101,6 +101,8 @@ void foo(void)
	DEFINE(PT_REGS_SP, offsetof(struct pt_regs, regs[30]));
	DEFINE(PT_REGS_PC, offsetof(struct pt_regs, pc));
	DEFINE(PT_REGS_PS, offsetof(struct pt_regs, ps));
	DEFINE(PT_REGS_ORIG_R0, offsetof(struct pt_regs, orig_r0));
	DEFINE(PT_REGS_ORIG_R19, offsetof(struct pt_regs, orig_r19));
	DEFINE(PT_REGS_HM_PS, offsetof(struct pt_regs, hm_ps));
	DEFINE(PT_REGS_HM_PC, offsetof(struct pt_regs, hm_pc));
	DEFINE(PT_REGS_HM_GP, offsetof(struct pt_regs, hm_gp));
+24 −71
Original line number Diff line number Diff line
@@ -8,6 +8,7 @@
#include <asm/hmcall.h>
#include <asm/errno.h>
#include <asm/unistd.h>
#include <asm/ptrace.h>

	.text
	.set noat
@@ -63,9 +64,11 @@
	and	$6, 0x8, $7
	beq	$7, 1f
	sys_call HMC_rdusp
	br	$31, 2f
	br	2f
1:	ldi	$0, PT_REGS_SIZE($sp)
2:	stl	$0, PT_REGS_SP($sp)
	ldi	$1, NO_SYSCALL
	stl	$1, PT_REGS_ORIG_R0($sp)
	sys_call HMC_rdktp
	.endm

@@ -202,6 +205,8 @@ entSys:

	SAVE_ALL
	ldl	$0, PT_REGS_R0($sp)
	stl	$0, PT_REGS_ORIG_R0($sp)
	stl	$19, PT_REGS_ORIG_R19($sp)
	ldi	$4, NR_SYSCALLS($31)
	stl	$16, PT_REGS_R16($sp)
	ldi	$5, sys_call_table
@@ -220,6 +225,10 @@ entSys:
1:	call	$26, ($27), ni_syscall
	ldgp	$gp, 0($26)
	blt	$0, $syscall_error	/* the call failed */

	ldi	$1, NO_SYSCALL
	stl	$1, PT_REGS_ORIG_R0($sp)
$syscall_success:
	stl	$0, PT_REGS_R0($sp)
	stl	$31, PT_REGS_R19($sp)	/* a3=0 => no error */

@@ -231,7 +240,6 @@ ret_from_sys_call:
#endif
	br	$27, 1f
1:	ldgp	$29, 0($27)
	selne	$26, 0, $18, $18		/* $18 = 0 => non-restartable */
	ldl	$0, PT_REGS_PS($sp)
	and	$0, 8, $0
	beq	$0, ret_to_kernel
@@ -246,7 +254,9 @@ ret_to_user:
	sys_call HMC_swpipl
	ldw	$17, TI_FLAGS($8)
	and	$17, _TIF_WORK_MASK, $2
	bne	$2, work_pending
	beq	$2, restore_all
	mov	$sp, $16
	call	$26, do_notify_resume
restore_all:
	RESTORE_ALL
	sys_call HMC_rti
@@ -256,7 +266,6 @@ ret_to_kernel:
	sys_call HMC_swpipl
	br restore_all


	.align 3
$syscall_error:
	/*
@@ -266,59 +275,16 @@ $syscall_error:
	 * frame to indicate that a negative return value wasn't an
	 * error number..
	 */
	ldl	$18, PT_REGS_R0($sp)	/* old syscall nr (zero if success) */
	beq	$18, $ret_success
	ldl	$1, PT_REGS_ORIG_R0($sp)	/* old syscall nr (-1 if success) */
	blt	$1, $syscall_success

	ldl	$19, PT_REGS_R19($sp)	/* .. and this a3 */
	subl	$31, $0, $0	/* with error in v0 */
	addl	$31, 1, $1	/* set a3 for errno return */
	stl	$0, PT_REGS_R0($sp)
	mov	$31, $26	/* tell "ret_from_sys_call" we can restart */
	stl	$1, PT_REGS_R19($sp)	/* a3 for return */
	br	ret_from_sys_call


$ret_success:
	stl	$0, PT_REGS_R0($sp)
	stl	$31, PT_REGS_R19($sp)	/* a3=0 => no error */
	br	ret_from_sys_call
	.end entSys

/*
 * Do all cleanup when returning from all interrupts and system calls.
 *
 * Arguments:
 *	$8: current.
 *	$17: TI_FLAGS.
 *	$18: The old syscall number, or zero if this is not a return
 *		from a syscall that errored and is possibly restartable.
 *	$19: The old a3 value
 */

	.align 4
	.ent work_pending
work_pending:
	and	$17, _TIF_NOTIFY_RESUME | _TIF_SIGPENDING | _TIF_UPROBE | _TIF_PATCH_PENDING, $2
	bne	$2, $work_notifysig

$work_resched:
	/*
	 * We can get here only if we returned from syscall without SIGPENDING
	 * or got through work_notifysig already.  Either case means no syscall
	 * restarts for us, so let $18 and $19 burn.
	 */
	call	$26, schedule
	mov	0, $18
	br	ret_to_user

$work_notifysig:
	mov	$sp, $16
	call	$26, do_work_pending
	br	restore_all
	.end work_pending



/*
 * PTRACE syscall handler
 */
@@ -327,12 +293,11 @@ $work_notifysig:
	.ent strace
strace:
	/* set up signal stack, call syscall_trace */
	mov	$0, $9
	mov	$19, $10
	call	$26, syscall_trace_enter
	blt	$0, $syscall_trace_failed

	/* get the system call number and the arguments back.. */
	stl	$0, PT_REGS_ORIG_R0($sp)
	ldl	$16, PT_REGS_R16($sp)
	ldl	$17, PT_REGS_R17($sp)
	ldl	$18, PT_REGS_R18($sp)
@@ -355,38 +320,27 @@ ret_from_straced:

	/* check return.. */
	blt	$0, $strace_error	/* the call failed */
	stl	$31, PT_REGS_R19($sp)	/* a3=0 => no error */

	ldi	$1, NO_SYSCALL
	stl	$1, PT_REGS_ORIG_R0($sp)
$strace_success:
	stl	$0, PT_REGS_R0($sp)	/* save return value */
	stl	$31, PT_REGS_R19($sp)	/* a3=0 => no error */
	call	$26, syscall_trace_leave
	br	$31, ret_from_sys_call
	br	ret_from_sys_call

	.align 3
$strace_error:
	ldl	$18, PT_REGS_R0($sp)	/* old syscall nr (zero if success) */

	beq	$18, $strace_success
	ldl	$19, PT_REGS_R19($sp)	/* .. and this a3 */
	ldl	$1, PT_REGS_ORIG_R0($sp)	/* old syscall nr (-1 if success) */
	blt	$1, $strace_success

	subl	$31, $0, $0	/* with error in v0 */
	addl	$31, 1, $1	/* set a3 for errno return */
	stl	$0, PT_REGS_R0($sp)
	stl	$1, PT_REGS_R19($sp)	/* a3 for return */

	mov	$18, $9		/* save old syscall number */
	mov	$19, $10	/* save old a3 */
	call	$26, syscall_trace_leave
	mov	$9, $18
	mov	$10, $19

	mov	$31, $26	/* tell "ret_from_sys_call" we can restart */
	br	ret_from_sys_call

$syscall_trace_failed:
	call	$26, syscall_trace_leave
	mov	$9, $18
	mov	$10, $19
	mov	$31, $26	/* tell "ret_from_sys_call" we can restart */
	br	ret_from_sys_call
	.end strace

@@ -454,8 +408,7 @@ ret_from_kernel_thread:
	mov	$9, $27
	mov	$10, $16
	call	$26, ($9)
	mov	$31, $19		/* to disable syscall restarts */
	br	$31, ret_to_user
	br	ret_to_user
	.end ret_from_kernel_thread

	.align 4
+6 −6
Original line number Diff line number Diff line
@@ -374,19 +374,19 @@ asmlinkage unsigned long syscall_trace_enter(void)
	struct pt_regs *regs = current_pt_regs();

	if (test_thread_flag(TIF_SYSCALL_TRACE) &&
		tracehook_report_syscall_entry(current_pt_regs()))
		ret = -1UL;
		tracehook_report_syscall_entry(regs))
		return NO_SYSCALL;

#ifdef CONFIG_SECCOMP
	/* Do seccomp after ptrace, to catch any tracer changes. */
	if (secure_computing() == -1)
		return -1;
		return NO_SYSCALL;
#endif

	if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))
		trace_sys_enter(regs, regs->regs[0]);
	audit_syscall_entry(regs->regs[0], regs->regs[16], regs->regs[17], regs->regs[18], regs->regs[19]);
	return ret ?: current_pt_regs()->regs[0];
	return ret ?: regs->regs[0];
}

asmlinkage void
@@ -394,9 +394,9 @@ syscall_trace_leave(void)
{
	struct pt_regs *regs = current_pt_regs();

	audit_syscall_exit(current_pt_regs());
	audit_syscall_exit(regs);
	if (test_thread_flag(TIF_SYSCALL_TRACE))
		tracehook_report_syscall_exit(current_pt_regs(), 0);
		tracehook_report_syscall_exit(regs, 0);
	if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))
		trace_sys_exit(regs, regs_return_value(regs));
}
Loading