Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 062b1c19 authored by Max Filippov's avatar Max Filippov
Browse files

xtensa: clean up access to spilled registers locations



Define macros SPILL_SLOT* that return a reference to the stack location
of the spill slot for specific register and use them instead of opencoded
address calculations.

Signed-off-by: default avatarMax Filippov <jcmvbkbc@gmail.com>
parent f984409a
Loading
Loading
Loading
Loading
+15 −0
Original line number Diff line number Diff line
@@ -113,6 +113,21 @@
 */
#define MAKE_PC_FROM_RA(ra,sp)    (((ra) & 0x3fffffff) | ((sp) & 0xc0000000))

/* Spill slot location for the register reg in the spill area under the stack
 * pointer sp. reg must be in the range [0..4).
 */
#define SPILL_SLOT(sp, reg) (*(((unsigned long *)(sp)) - 4 + (reg)))

/* Spill slot location for the register reg in the spill area under the stack
 * pointer sp for the call8. reg must be in the range [4..8).
 */
#define SPILL_SLOT_CALL8(sp, reg) (*(((unsigned long *)(sp)) - 12 + (reg)))

/* Spill slot location for the register reg in the spill area under the stack
 * pointer sp for the call12. reg must be in the range [4..12).
 */
#define SPILL_SLOT_CALL12(sp, reg) (*(((unsigned long *)(sp)) - 16 + (reg)))

typedef struct {
	unsigned long seg;
} mm_segment_t;
+4 −4
Original line number Diff line number Diff line
@@ -204,8 +204,8 @@ int copy_thread(unsigned long clone_flags, unsigned long usp_thread_fn,
#endif

	/* Create a call4 dummy-frame: a0 = 0, a1 = childregs. */
	*((int*)childregs - 3) = (unsigned long)childregs;
	*((int*)childregs - 4) = 0;
	SPILL_SLOT(childregs, 1) = (unsigned long)childregs;
	SPILL_SLOT(childregs, 0) = 0;

	p->thread.sp = (unsigned long)childregs;

@@ -266,8 +266,8 @@ int copy_thread(unsigned long clone_flags, unsigned long usp_thread_fn,
		/* pass parameters to ret_from_kernel_thread:
		 * a2 = thread_fn, a3 = thread_fn arg
		 */
		*((int *)childregs - 1) = thread_fn_arg;
		*((int *)childregs - 2) = usp_thread_fn;
		SPILL_SLOT(childregs, 3) = thread_fn_arg;
		SPILL_SLOT(childregs, 2) = usp_thread_fn;

		/* Childregs are only used when we're going to userspace
		 * in which case start_thread will set them up.
+5 −5
Original line number Diff line number Diff line
@@ -91,13 +91,13 @@ flush_window_regs_user(struct pt_regs *regs)
			inc = 1;

		} else if (m & 4) {		/* call8 */
			if (copy_to_user((void*)(sp - 32),
			if (copy_to_user(&SPILL_SLOT_CALL8(sp, 4),
					 &regs->areg[(base + 1) * 4], 16))
				goto errout;
			inc = 2;

		} else if (m & 8) {	/* call12 */
			if (copy_to_user((void*)(sp - 48),
			if (copy_to_user(&SPILL_SLOT_CALL12(sp, 4),
					 &regs->areg[(base + 1) * 4], 32))
				goto errout;
			inc = 3;
@@ -106,7 +106,7 @@ flush_window_regs_user(struct pt_regs *regs)
		/* Save current frame a0..a3 under next SP */

		sp = regs->areg[((base + inc) * 4 + 1) % XCHAL_NUM_AREGS];
		if (copy_to_user((void*)(sp - 16), &regs->areg[base * 4], 16))
		if (copy_to_user(&SPILL_SLOT(sp, 0), &regs->areg[base * 4], 16))
			goto errout;

		/* Get current stack pointer for next loop iteration. */
+8 −27
Original line number Diff line number Diff line
@@ -23,14 +23,6 @@
 */
extern int common_exception_return;

/* A struct that maps to the part of the frame containing the a0 and
 * a1 registers.
 */
struct frame_start {
	unsigned long a0;
	unsigned long a1;
};

void xtensa_backtrace_user(struct pt_regs *regs, unsigned int depth,
			   int (*ufn)(struct stackframe *frame, void *data),
			   void *data)
@@ -96,26 +88,16 @@ void xtensa_backtrace_user(struct pt_regs *regs, unsigned int depth,
	/* Start from the a1 register. */
	/* a1 = regs->areg[1]; */
	while (a0 != 0 && depth--) {
		struct frame_start frame_start;
		/* Get the location for a1, a0 for the
		 * previous frame from the current a1.
		 */
		unsigned long *psp = (unsigned long *)a1;

		psp -= 4;
		pc = MAKE_PC_FROM_RA(a0, pc);

		/* Check if the region is OK to access. */
		if (!access_ok(VERIFY_READ, psp, sizeof(frame_start)))
		if (!access_ok(VERIFY_READ, &SPILL_SLOT(a1, 0), 8))
			return;
		/* Copy a1, a0 from user space stack frame. */
		if (__copy_from_user_inatomic(&frame_start, psp,
					      sizeof(frame_start)))
		if (__get_user(a0, &SPILL_SLOT(a1, 0)) ||
		    __get_user(a1, &SPILL_SLOT(a1, 1)))
			return;

		pc = MAKE_PC_FROM_RA(a0, pc);
		a0 = frame_start.a0;
		a1 = frame_start.a1;

		frame.pc = pc;
		frame.sp = a1;

@@ -147,7 +129,6 @@ void xtensa_backtrace_kernel(struct pt_regs *regs, unsigned int depth,
	 */
	while (a1 > sp_start && a1 < sp_end && depth--) {
		struct stackframe frame;
		unsigned long *psp = (unsigned long *)a1;

		frame.pc = pc;
		frame.sp = a1;
@@ -171,8 +152,8 @@ void xtensa_backtrace_kernel(struct pt_regs *regs, unsigned int depth,
		sp_start = a1;

		pc = MAKE_PC_FROM_RA(a0, pc);
		a0 = *(psp - 4);
		a1 = *(psp - 3);
		a0 = SPILL_SLOT(a1, 0);
		a1 = SPILL_SLOT(a1, 1);
	}
}
EXPORT_SYMBOL(xtensa_backtrace_kernel);
@@ -196,8 +177,8 @@ void walk_stackframe(unsigned long *sp,

		sp = (unsigned long *)a1;

		a0 = *(sp - 4);
		a1 = *(sp - 3);
		a0 = SPILL_SLOT(a1, 0);
		a1 = SPILL_SLOT(a1, 1);

		if (a1 <= (unsigned long)sp)
			break;