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

Commit c50842df authored by Chris Zankel's avatar Chris Zankel
Browse files

xtensa: add support for TLS



The Xtensa architecture provides a global register called THREADPTR
for the purpose of Thread Local Storage (TLS) support. This allows us
to use a fairly simple implementation, keeping the thread pointer in
the regset and simply saving and restoring it upon entering/exiting
the from user space.

Signed-off-by: default avatarChris Zankel <chris@zankel.net>
parent b0c438e6
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -84,7 +84,8 @@ typedef struct {
	elf_greg_t sar;
	elf_greg_t windowstart;
	elf_greg_t windowbase;
	elf_greg_t reserved[8+48];
	elf_greg_t threadptr;
	elf_greg_t reserved[7+48];
	elf_greg_t a[64];
} xtensa_gregset_t;

+2 −1
Original line number Diff line number Diff line
@@ -38,6 +38,7 @@ struct pt_regs {
	unsigned long syscall;		/*  56 */
	unsigned long icountlevel;	/*  60 */
	unsigned long scompare1;	/*  64 */
	unsigned long threadptr;	/*  68 */

	/* Additional configurable registers that are used by the compiler. */
	xtregs_opt_t xtregs_opt;
@@ -48,7 +49,7 @@ struct pt_regs {
	/* current register frame.
	 * Note: The ESF for kernel exceptions ends after 16 registers!
	 */
	unsigned long areg[16];		/* 128 (64) */
	unsigned long areg[16];
};

#include <variant/core.h>
+1 −0
Original line number Diff line number Diff line
@@ -42,6 +42,7 @@ int main(void)
	DEFINE(PT_ICOUNTLEVEL, offsetof (struct pt_regs, icountlevel));
	DEFINE(PT_SYSCALL, offsetof (struct pt_regs, syscall));
	DEFINE(PT_SCOMPARE1, offsetof(struct pt_regs, scompare1));
	DEFINE(PT_THREADPTR, offsetof(struct pt_regs, threadptr));
	DEFINE(PT_AREG, offsetof (struct pt_regs, areg[0]));
	DEFINE(PT_AREG0, offsetof (struct pt_regs, areg[0]));
	DEFINE(PT_AREG1, offsetof (struct pt_regs, areg[1]));
+11 −1
Original line number Diff line number Diff line
@@ -130,6 +130,11 @@ _user_exception:
	s32i	a3, a1, PT_SAR
	s32i	a2, a1, PT_ICOUNTLEVEL

#if XCHAL_HAVE_THREADPTR
	rur	a2, threadptr
	s32i	a2, a1, PT_THREADPTR
#endif

	/* Rotate ws so that the current windowbase is at bit0. */
	/* Assume ws = xxwww1yyyy. Rotate ws right, so that a2 = yyyyxxwww1 */

@@ -510,6 +515,11 @@ user_exception_exit:
	 *	 (if we have restored WSBITS-1 frames).
	 */

#if XCHAL_HAVE_THREADPTR
	l32i	a3, a1, PT_THREADPTR
	wur	a3, threadptr
#endif

2:	j	common_exception_exit

	/* This is the kernel exception exit.
@@ -1955,7 +1965,7 @@ ENTRY(_switch_to)
	s32i	a6, a3, EXC_TABLE_FIXUP
	s32i	a7, a3, EXC_TABLE_KSTK

	/* restore context of the task that 'next' addresses */
	/* restore context of the task 'next' */

	l32i	a0, a13, THREAD_RA	# restore return address
	l32i	a1, a13, THREAD_SP	# restore stack pointer
+3 −2
Original line number Diff line number Diff line
@@ -259,9 +259,10 @@ int copy_thread(unsigned long clone_flags, unsigned long usp_thread_fn,
			memcpy(&childregs->areg[XCHAL_NUM_AREGS - len/4],
			       &regs->areg[XCHAL_NUM_AREGS - len/4], len);
		}
// FIXME: we need to set THREADPTR in thread_info...

		/* The thread pointer is passed in the '4th argument' (= a5) */
		if (clone_flags & CLONE_SETTLS)
			childregs->areg[2] = childregs->areg[6];
			childregs->threadptr = childregs->areg[5];
	} else {
		p->thread.ra = MAKE_RA_FOR_CALL(
				(unsigned long)ret_from_kernel_thread, 1);
Loading