Index: uspace/lib/c/arch/abs32le/include/libarch/tls.h
===================================================================
--- uspace/lib/c/arch/abs32le/include/libarch/tls.h	(revision 9b1baac695a63afb1850cd44050a52e06635cbd2)
+++ uspace/lib/c/arch/abs32le/include/libarch/tls.h	(revision 0b0508283ddd2f79e0dcee257b44867abb882bdf)
@@ -41,4 +41,7 @@
 #include <stddef.h>
 
+/* Some architectures store the value with an offset. Some do not. */
+#define ARCH_TP_OFFSET 0
+
 typedef struct {
 	void *self;
@@ -46,10 +49,12 @@
 } tcb_t;
 
-static inline void __tcb_set(tcb_t *tcb)
+static inline void __tcb_raw_set(void *tls)
 {
+	/* Usually a short assembly assigning to an ABI-defined register. */
 }
 
-static inline tcb_t *__tcb_get(void)
+static inline void *__tcb_raw_get(void)
 {
+	/* Usually a short assembly reading from an ABI-defined register. */
 	return NULL;
 }
Index: uspace/lib/c/arch/amd64/include/libarch/tls.h
===================================================================
--- uspace/lib/c/arch/amd64/include/libarch/tls.h	(revision 9b1baac695a63afb1850cd44050a52e06635cbd2)
+++ uspace/lib/c/arch/amd64/include/libarch/tls.h	(revision 0b0508283ddd2f79e0dcee257b44867abb882bdf)
@@ -38,4 +38,6 @@
 #define CONFIG_TLS_VARIANT_2
 
+#define ARCH_TP_OFFSET 0
+
 #include <libc.h>
 
@@ -45,13 +47,12 @@
 } tcb_t;
 
-static inline void __tcb_set(tcb_t *tcb)
+static inline void __tcb_raw_set(void *tls)
 {
-	asm volatile ("movq %0, %%fs:0" :: "r" (tcb));
+	asm volatile ("movq %0, %%fs:0" :: "r" (tls));
 }
 
-static inline tcb_t *__tcb_get(void)
+static inline void *__tcb_raw_get(void)
 {
-	tcb_t *retval;
-
+	void *retval;
 	asm volatile ("movq %%fs:0, %0" : "=r" (retval));
 	return retval;
Index: uspace/lib/c/arch/arm32/include/libarch/fibril.h
===================================================================
--- uspace/lib/c/arch/arm32/include/libarch/fibril.h	(revision 9b1baac695a63afb1850cd44050a52e06635cbd2)
+++ uspace/lib/c/arch/arm32/include/libarch/fibril.h	(revision 0b0508283ddd2f79e0dcee257b44867abb882bdf)
@@ -62,5 +62,5 @@
 		(c)->pc = (sysarg_t) (_pc); \
 		(c)->sp = ((sysarg_t) (stack)) + (size) - SP_DELTA; \
-		(c)->tls = ((sysarg_t)(ptls)) + sizeof(tcb_t) + ARM_TP_OFFSET; \
+		(c)->tls = ((sysarg_t)(ptls)) + ARCH_TP_OFFSET; \
 		(c)->fp = 0; \
 	} while (0)
Index: uspace/lib/c/arch/arm32/include/libarch/tls.h
===================================================================
--- uspace/lib/c/arch/arm32/include/libarch/tls.h	(revision 9b1baac695a63afb1850cd44050a52e06635cbd2)
+++ uspace/lib/c/arch/arm32/include/libarch/tls.h	(revision 0b0508283ddd2f79e0dcee257b44867abb882bdf)
@@ -42,5 +42,5 @@
 
 /** Offsets for accessing thread-local variables are shifted 8 bytes higher. */
-#define ARM_TP_OFFSET  (-8)
+#define ARCH_TP_OFFSET  (sizeof(tcb_t) - 8)
 
 /** TCB (Thread Control Block) struct.
@@ -53,36 +53,15 @@
 } tcb_t;
 
-
-/** Sets TLS address to the r9 register.
- *
- *  @param tcb		TCB (TLS starts behind)
- */
-static inline void __tcb_set(tcb_t *tcb)
+static inline void *__tcb_raw_get(void)
 {
-	uint8_t *tls = (uint8_t *) tcb;
-	tls += sizeof(tcb_t) + ARM_TP_OFFSET;
-	asm volatile (
-	    "mov r9, %0"
-	    :
-	    : "r" (tls)
-	);
+	uint8_t *ret;
+	asm volatile ("mov %0, r9" : "=r" (ret));
+	return ret;
 }
 
-
-/** Returns TCB address.
- *
- * @return		TCB address (starts before TLS which address is stored
- * 			in r9 register).
- */
-static inline tcb_t *__tcb_get(void)
+static inline void __tcb_raw_set(void *tls)
 {
-	uint8_t *ret;
-	asm volatile (
-	    "mov %0, r9"
-	    : "=r" (ret)
-	);
-	return (tcb_t *) (ret - ARM_TP_OFFSET - sizeof(tcb_t));
+	asm volatile ("mov r9, %0" :: "r" (tls));
 }
-
 
 /** Returns TLS address stored.
Index: uspace/lib/c/arch/ia32/include/libarch/tls.h
===================================================================
--- uspace/lib/c/arch/ia32/include/libarch/tls.h	(revision 9b1baac695a63afb1850cd44050a52e06635cbd2)
+++ uspace/lib/c/arch/ia32/include/libarch/tls.h	(revision 0b0508283ddd2f79e0dcee257b44867abb882bdf)
@@ -38,4 +38,6 @@
 #define CONFIG_TLS_VARIANT_2
 
+#define ARCH_TP_OFFSET 0
+
 #include <libc.h>
 
@@ -46,15 +48,13 @@
 } tcb_t;
 
-static inline void __tcb_set(tcb_t *tcb)
+static inline void __tcb_raw_set(void *tls)
 {
-	asm volatile ("movl %0, %%gs:0" :: "r" (tcb));
+	asm volatile ("movl %0, %%gs:0" :: "r" (tls));
 }
 
-static inline tcb_t *__tcb_get(void)
+static inline void *__tcb_raw_get(void)
 {
-	tcb_t *retval;
-
+	void *retval;
 	asm volatile ("movl %%gs:0, %0" : "=r" (retval));
-
 	return retval;
 }
Index: uspace/lib/c/arch/ia64/include/libarch/tls.h
===================================================================
--- uspace/lib/c/arch/ia64/include/libarch/tls.h	(revision 9b1baac695a63afb1850cd44050a52e06635cbd2)
+++ uspace/lib/c/arch/ia64/include/libarch/tls.h	(revision 0b0508283ddd2f79e0dcee257b44867abb882bdf)
@@ -38,4 +38,6 @@
 #define CONFIG_TLS_VARIANT_1
 
+#define ARCH_TP_OFFSET 0
+
 /* This structure must be exactly 16 bytes long */
 typedef struct {
@@ -44,15 +46,13 @@
 } tcb_t;
 
-static inline void __tcb_set(tcb_t *tcb)
+static inline void __tcb_raw_set(void *tcb)
 {
 	asm volatile ("mov r13 = %0\n" : : "r" (tcb) : "r13");
 }
 
-static inline tcb_t *__tcb_get(void)
+static inline void *__tcb_raw_get(void)
 {
-	tcb_t *retval;
-
+	void *retval;
 	asm volatile ("mov %0 = r13\n" : "=r" (retval));
-
 	return retval;
 }
Index: uspace/lib/c/arch/mips32/include/libarch/tls.h
===================================================================
--- uspace/lib/c/arch/mips32/include/libarch/tls.h	(revision 9b1baac695a63afb1850cd44050a52e06635cbd2)
+++ uspace/lib/c/arch/mips32/include/libarch/tls.h	(revision 0b0508283ddd2f79e0dcee257b44867abb882bdf)
@@ -61,5 +61,5 @@
  * - No assumption about DTV etc., but it will not have a fixed address
  */
-#define MIPS_TP_OFFSET 0x7000
+#define ARCH_TP_OFFSET (0x7000 + sizeof(tcb_t))
 
 typedef struct {
@@ -67,19 +67,15 @@
 } tcb_t;
 
-static inline void __tcb_set(tcb_t *tcb)
+static inline void __tcb_raw_set(void *tls)
 {
-	uint8_t *tp = (uint8_t *) tcb;
-	tp += MIPS_TP_OFFSET + sizeof(tcb_t);
-
-	asm volatile ("add $27, %0, $0" : : "r" (tp)); /* Move tls to K1 */
+	/* Move tls to K1 */
+	asm volatile ("add $27, %0, $0" :: "r" (tls));
 }
 
-static inline tcb_t *__tcb_get(void)
+static inline void *__tcb_raw_get(void)
 {
-	uint8_t *retval;
-
+	void *retval;
 	asm volatile ("add %0, $27, $0" : "=r" (retval));
-
-	return (tcb_t *)(retval - MIPS_TP_OFFSET - sizeof(tcb_t));
+	return retval;
 }
 
Index: uspace/lib/c/arch/ppc32/include/libarch/tls.h
===================================================================
--- uspace/lib/c/arch/ppc32/include/libarch/tls.h	(revision 9b1baac695a63afb1850cd44050a52e06635cbd2)
+++ uspace/lib/c/arch/ppc32/include/libarch/tls.h	(revision 0b0508283ddd2f79e0dcee257b44867abb882bdf)
@@ -40,5 +40,5 @@
 #include <libc.h>
 
-#define PPC_TP_OFFSET 0x7000
+#define ARCH_TP_OFFSET (0x7000 + sizeof(tcb_t))
 
 typedef struct {
@@ -46,26 +46,14 @@
 } tcb_t;
 
-static inline void __tcb_set(tcb_t *tcb)
+static inline void __tcb_raw_set(void *tls)
 {
-	uint8_t *tp = (uint8_t *) tcb;
-	tp += PPC_TP_OFFSET + sizeof(tcb_t);
-
-	asm volatile (
-	    "mr %%r2, %0\n"
-	    :
-	    : "r" (tp)
-	);
+	asm volatile ("mr %%r2, %0\n" :: "r" (tls));
 }
 
-static inline tcb_t *__tcb_get(void)
+static inline void *__tcb_raw_get(void)
 {
-	uint8_t *retval;
-
-	asm volatile (
-	    "mr %0, %%r2\n"
-	    : "=r" (retval)
-	);
-
-	return (tcb_t *) (retval - PPC_TP_OFFSET - sizeof(tcb_t));
+	void *retval;
+	asm volatile ("mr %0, %%r2\n" : "=r" (retval));
+	return retval;
 }
 
Index: uspace/lib/c/arch/riscv64/include/libarch/tls.h
===================================================================
--- uspace/lib/c/arch/riscv64/include/libarch/tls.h	(revision 9b1baac695a63afb1850cd44050a52e06635cbd2)
+++ uspace/lib/c/arch/riscv64/include/libarch/tls.h	(revision 0b0508283ddd2f79e0dcee257b44867abb882bdf)
@@ -40,4 +40,7 @@
 #include <libc.h>
 
+/* Some architectures store the value with an offset. Some do not. */
+#define ARCH_TP_OFFSET 0
+
 typedef struct {
 	void *self;
@@ -45,11 +48,13 @@
 } tcb_t;
 
-static inline void __tcb_set(tcb_t *tcb)
+static inline void __tcb_raw_set(void *tls)
 {
+	// TODO
 }
 
-static inline tcb_t *__tcb_get(void)
+static inline void *__tcb_raw_get(void)
 {
-	return (tcb_t *) 0;
+	// TODO
+	return 0;
 }
 
Index: uspace/lib/c/arch/sparc64/include/libarch/tls.h
===================================================================
--- uspace/lib/c/arch/sparc64/include/libarch/tls.h	(revision 9b1baac695a63afb1850cd44050a52e06635cbd2)
+++ uspace/lib/c/arch/sparc64/include/libarch/tls.h	(revision 0b0508283ddd2f79e0dcee257b44867abb882bdf)
@@ -41,4 +41,6 @@
 #define CONFIG_TLS_VARIANT_2
 
+#define ARCH_TP_OFFSET 0
+
 typedef struct {
 	void *self;
@@ -46,15 +48,13 @@
 } tcb_t;
 
-static inline void __tcb_set(tcb_t *tcb)
+static inline void __tcb_raw_set(void *tcb)
 {
 	asm volatile ("mov %0, %%g7\n" : : "r" (tcb) : "g7");
 }
 
-static inline tcb_t *__tcb_get(void)
+static inline void *__tcb_raw_get(void)
 {
-	tcb_t *retval;
-
+	void *retval;
 	asm volatile ("mov %%g7, %0\n" : "=r" (retval));
-
 	return retval;
 }
Index: uspace/lib/c/generic/context.c
===================================================================
--- uspace/lib/c/generic/context.c	(revision 9b1baac695a63afb1850cd44050a52e06635cbd2)
+++ uspace/lib/c/generic/context.c	(revision 0b0508283ddd2f79e0dcee257b44867abb882bdf)
@@ -29,5 +29,5 @@
 #include <context.h>
 #include <setjmp.h>
-#include <libarch/tls.h>
+#include <tls.h>
 #include <libarch/fibril.h>
 #include <libarch/faddr.h>
Index: uspace/lib/c/generic/private/fibril.h
===================================================================
--- uspace/lib/c/generic/private/fibril.h	(revision 9b1baac695a63afb1850cd44050a52e06635cbd2)
+++ uspace/lib/c/generic/private/fibril.h	(revision 0b0508283ddd2f79e0dcee257b44867abb882bdf)
@@ -32,5 +32,5 @@
 #include <adt/list.h>
 #include <context.h>
-#include <libarch/tls.h>
+#include <tls.h>
 #include <abi/proc/uarg.h>
 #include <atomic.h>
Index: uspace/lib/c/include/fibril_synch.h
===================================================================
--- uspace/lib/c/include/fibril_synch.h	(revision 9b1baac695a63afb1850cd44050a52e06635cbd2)
+++ uspace/lib/c/include/fibril_synch.h	(revision 0b0508283ddd2f79e0dcee257b44867abb882bdf)
@@ -38,5 +38,5 @@
 #include <fibril.h>
 #include <adt/list.h>
-#include <libarch/tls.h>
+#include <tls.h>
 #include <sys/time.h>
 #include <stdbool.h>
Index: uspace/lib/c/include/tls.h
===================================================================
--- uspace/lib/c/include/tls.h	(revision 9b1baac695a63afb1850cd44050a52e06635cbd2)
+++ uspace/lib/c/include/tls.h	(revision 0b0508283ddd2f79e0dcee257b44867abb882bdf)
@@ -37,6 +37,32 @@
 
 #include <libarch/tls.h>
+#include <stdbool.h>
 #include <stddef.h>
 #include <stdint.h>
+
+static inline void __tcb_reset(void)
+{
+	__tcb_raw_set(NULL);
+}
+
+static inline void __tcb_set(tcb_t *tcb)
+{
+	__tcb_raw_set((uint8_t *)tcb + ARCH_TP_OFFSET);
+}
+
+
+static inline tcb_t *__tcb_get(void)
+{
+	return (tcb_t *)((uint8_t *)__tcb_raw_get() - ARCH_TP_OFFSET);
+}
+
+/*
+ * The TP register is supposed to be zero when the thread is first created
+ * by the kernel. We use this for some debugging assertions.
+ */
+static inline bool __tcb_is_set(void)
+{
+	return __tcb_raw_get() != NULL;
+}
 
 /** DTV Generation number - equals vector length */
