Index: kernel/generic/include/cpu.h
===================================================================
--- kernel/generic/include/cpu.h	(revision 3b6854248cddcb5c644dde7380ebb48393b90942)
+++ kernel/generic/include/cpu.h	(revision 47607932cbd36ab7b6c155cdf94805b947d98d82)
@@ -44,5 +44,35 @@
 #include <arch.h>
 
-#define CPU                  CURRENT->cpu
+#define CPU                  (CURRENT->cpu)
+#define CPU_LOCAL            (&CPU->local)
+
+/**
+ * Contents of CPU_LOCAL. These are variables that are only ever accessed by
+ * the CPU they belong to, so they don't need any synchronization,
+ * just locally disabled interrupts.
+ */
+typedef struct cpu_local {
+	/**
+	 * When system clock loses a tick, it is
+	 * recorded here so that clock() can react.
+	 */
+	size_t missed_clock_ticks;
+
+	uint64_t current_clock_tick;
+	uint64_t preempt_deadline;  /* < when should the currently running thread be preempted */
+	uint64_t relink_deadline;
+
+	/**
+	 * Stack used by scheduler when there is no running thread.
+	 * This field is unchanged after initialization.
+	 */
+	uint8_t *stack;
+
+	/**
+	 * Processor cycle accounting.
+	 */
+	bool idle;
+	uint64_t last_cycle;
+} cpu_local_t;
 
 /** CPU structure.
@@ -63,22 +93,6 @@
 
 	/**
-	 * When system clock loses a tick, it is
-	 * recorded here so that clock() can react.
-	 * This variable is CPU-local and can be
-	 * only accessed when interrupts are
-	 * disabled.
-	 */
-	size_t missed_clock_ticks;
-
-	/** Can only be accessed by the CPU represented by this structure when interrupts are disabled. */
-	uint64_t current_clock_tick;
-	uint64_t preempt_deadline;  /* < when should the currently running thread be preempted */
-	uint64_t relink_deadline;
-
-	/**
 	 * Processor cycle accounting.
 	 */
-	bool idle;
-	uint64_t last_cycle;
 	atomic_time_stat_t idle_cycles;
 	atomic_time_stat_t busy_cycles;
@@ -103,8 +117,5 @@
 	_Atomic(struct thread *) fpu_owner;
 
-	/**
-	 * Stack used by scheduler when there is no running thread.
-	 */
-	uint8_t *stack;
+	cpu_local_t local;
 } cpu_t;
 
Index: kernel/generic/src/cpu/cpu.c
===================================================================
--- kernel/generic/src/cpu/cpu.c	(revision 3b6854248cddcb5c644dde7380ebb48393b90942)
+++ kernel/generic/src/cpu/cpu.c	(revision 47607932cbd36ab7b6c155cdf94805b947d98d82)
@@ -81,5 +81,5 @@
 				panic("Cannot allocate CPU stack.");
 
-			cpus[i].stack = (uint8_t *) PA2KA(stack_phys);
+			cpus[i].local.stack = (uint8_t *) PA2KA(stack_phys);
 			cpus[i].id = i;
 
@@ -104,6 +104,6 @@
 	CPU->tlb_active = true;
 
-	CPU->idle = false;
-	CPU->last_cycle = get_cycle();
+	CPU_LOCAL->idle = false;
+	CPU_LOCAL->last_cycle = get_cycle();
 	CPU->idle_cycles = ATOMIC_TIME_INITIALIZER();
 	CPU->busy_cycles = ATOMIC_TIME_INITIALIZER();
Index: kernel/generic/src/interrupt/interrupt.c
===================================================================
--- kernel/generic/src/interrupt/interrupt.c	(revision 3b6854248cddcb5c644dde7380ebb48393b90942)
+++ kernel/generic/src/interrupt/interrupt.c	(revision 47607932cbd36ab7b6c155cdf94805b947d98d82)
@@ -121,9 +121,9 @@
 
 	/* Account CPU usage if it woke up from sleep */
-	if (CPU && CPU->idle) {
+	if (CPU && CPU_LOCAL->idle) {
 		uint64_t now = get_cycle();
-		atomic_time_increment(&CPU->idle_cycles, now - CPU->last_cycle);
-		CPU->last_cycle = now;
-		CPU->idle = false;
+		atomic_time_increment(&CPU->idle_cycles, now - CPU_LOCAL->last_cycle);
+		CPU_LOCAL->last_cycle = now;
+		CPU_LOCAL->idle = false;
 	}
 
Index: kernel/generic/src/main/main.c
===================================================================
--- kernel/generic/src/main/main.c	(revision 3b6854248cddcb5c644dde7380ebb48393b90942)
+++ kernel/generic/src/main/main.c	(revision 47607932cbd36ab7b6c155cdf94805b947d98d82)
@@ -328,5 +328,5 @@
 	ARCH_OP(post_cpu_init);
 
-	current_copy(CURRENT, (current_t *) CPU->stack);
+	current_copy(CURRENT, (current_t *) CPU_LOCAL->stack);
 
 	/*
@@ -338,5 +338,5 @@
 	context_save(&ctx);
 	context_set(&ctx, FADDR(main_ap_separated_stack),
-	    (uintptr_t) CPU->stack, STACK_SIZE);
+	    (uintptr_t) CPU_LOCAL->stack, STACK_SIZE);
 	context_restore(&ctx);
 	/* not reached */
Index: kernel/generic/src/proc/scheduler.c
===================================================================
--- kernel/generic/src/proc/scheduler.c	(revision 3b6854248cddcb5c644dde7380ebb48393b90942)
+++ kernel/generic/src/proc/scheduler.c	(revision 47607932cbd36ab7b6c155cdf94805b947d98d82)
@@ -216,5 +216,6 @@
 
 		/* This is safe because interrupts are disabled. */
-		CPU->preempt_deadline = CPU->current_clock_tick + us2ticks(time_to_run);
+		CPU_LOCAL->preempt_deadline =
+		    CPU_LOCAL->current_clock_tick + us2ticks(time_to_run);
 
 		/*
@@ -257,5 +258,5 @@
 		 * This improves energy saving and hyperthreading.
 		 */
-		CPU->idle = true;
+		CPU_LOCAL->idle = true;
 
 		/*
@@ -305,8 +306,8 @@
 static void relink_rq(int start)
 {
-	if (CPU->current_clock_tick < CPU->relink_deadline)
+	if (CPU_LOCAL->current_clock_tick < CPU_LOCAL->relink_deadline)
 		return;
 
-	CPU->relink_deadline = CPU->current_clock_tick + NEEDS_RELINK_MAX;
+	CPU_LOCAL->relink_deadline = CPU_LOCAL->current_clock_tick + NEEDS_RELINK_MAX;
 
 	/* Temporary cache for lists we are moving. */
@@ -401,5 +402,5 @@
 	 *
 	 */
-	current_copy(CURRENT, (current_t *) CPU->stack);
+	current_copy(CURRENT, (current_t *) CPU_LOCAL->stack);
 
 	/*
@@ -419,5 +420,5 @@
 	context_save(&ctx);
 	context_set(&ctx, FADDR(scheduler_separated_stack),
-	    (uintptr_t) CPU->stack, STACK_SIZE);
+	    (uintptr_t) CPU_LOCAL->stack, STACK_SIZE);
 	context_restore(&ctx);
 
Index: kernel/generic/src/time/clock.c
===================================================================
--- kernel/generic/src/time/clock.c	(revision 3b6854248cddcb5c644dde7380ebb48393b90942)
+++ kernel/generic/src/time/clock.c	(revision 47607932cbd36ab7b6c155cdf94805b947d98d82)
@@ -124,6 +124,6 @@
 {
 	uint64_t now = get_cycle();
-	atomic_time_increment(&CPU->busy_cycles, now - CPU->last_cycle);
-	CPU->last_cycle = now;
+	atomic_time_increment(&CPU->busy_cycles, now - CPU_LOCAL->last_cycle);
+	CPU_LOCAL->last_cycle = now;
 }
 
@@ -137,9 +137,9 @@
 void clock(void)
 {
-	size_t missed_clock_ticks = CPU->missed_clock_ticks;
-	CPU->missed_clock_ticks = 0;
-
-	CPU->current_clock_tick += missed_clock_ticks + 1;
-	uint64_t current_clock_tick = CPU->current_clock_tick;
+	size_t missed_clock_ticks = CPU_LOCAL->missed_clock_ticks;
+	CPU_LOCAL->missed_clock_ticks = 0;
+
+	CPU_LOCAL->current_clock_tick += missed_clock_ticks + 1;
+	uint64_t current_clock_tick = CPU_LOCAL->current_clock_tick;
 	clock_update_counters(current_clock_tick);
 
@@ -186,5 +186,5 @@
 
 	if (THREAD) {
-		if (current_clock_tick >= CPU->preempt_deadline && PREEMPTION_ENABLED) {
+		if (current_clock_tick >= CPU_LOCAL->preempt_deadline && PREEMPTION_ENABLED) {
 			scheduler();
 #ifdef CONFIG_UDEBUG
Index: kernel/generic/src/time/timeout.c
===================================================================
--- kernel/generic/src/time/timeout.c	(revision 3b6854248cddcb5c644dde7380ebb48393b90942)
+++ kernel/generic/src/time/timeout.c	(revision 47607932cbd36ab7b6c155cdf94805b947d98d82)
@@ -77,5 +77,5 @@
 		return 0;
 
-	return CPU->current_clock_tick + us2ticks(usec);
+	return CPU_LOCAL->current_clock_tick + us2ticks(usec);
 }
 
