blob: 6026ee5c2d352659d7f15e0fa486cfbb0d297997 [file] [log] [blame]
// Copyright 2016 The Fuchsia Authors
//
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT
#ifndef ZIRCON_KERNEL_ARCH_ARM64_INCLUDE_ARCH_CURRENT_THREAD_H_
#define ZIRCON_KERNEL_ARCH_ARM64_INCLUDE_ARCH_CURRENT_THREAD_H_
#include <lib/arch/intrin.h>
// Routines to directly access the current thread pointer out of the current
// cpu structure pointed the TPIDR_EL1 register.
// NOTE: must be included after the definition of Thread due to the offsetof
// applied in the following routines.
// Use the cpu local thread context pointer to store current_thread.
static inline Thread* arch_get_current_thread() {
#ifdef __clang__
// Clang with --target=aarch64-fuchsia -mtp=el1 reads
// TPIDR_EL1 for __builtin_thread_pointer (instead of the usual
// TPIDR_EL0 for user mode). Using the intrinsic instead of asm
// lets the compiler understand what it's doing a little better,
// which conceivably could let it optimize better.
char* tp = (char*)__builtin_thread_pointer();
#else
char* tp = (char*)__arm_rsr64("tpidr_el1");
#endif
// The Thread structure isn't standard layout, but it's "POD enough"
// for us to rely on computing this member offset via offsetof.
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Winvalid-offsetof"
tp -= offsetof(Thread, arch_.thread_pointer_location);
#pragma GCC diagnostic pop
return (Thread*)tp;
}
static inline void arch_set_current_thread(Thread* t) {
__arm_wsr64("tpidr_el1", (uint64_t)&t->arch().thread_pointer_location);
}
#endif // ZIRCON_KERNEL_ARCH_ARM64_INCLUDE_ARCH_CURRENT_THREAD_H_