ARM 中 TPIDR_EL0/TPIDR_EL1 等线程 ID 寄存器的用途是什么?

What is the purpose of Thread ID registers like TPIDR_EL0/TPIDR_EL1 in ARM?

根据ARM documentation,线程ID注册为TPIDR_EL0TPIDR_EL1

Provide locations to store the IDs of software threads and processes for OS management purposes. These registers have no effect on processor behavior.

为什么有人要将线程 ID 存储在一个特殊的寄存器中? ARM 处理器是否像 MMU 那样要求线程在内存中具有特殊结构?线程是否对 ARM 有特殊意义,是 ARM 希望在某处找到的东西?或者我可以在不使用这个寄存器的情况下(有效地)实现线程吗?

我问是因为我在 Fuchsia 的 Zircon Kernel 上找到了这段代码 OS:

static inline void arch_set_current_thread(Thread* t) {
  __arm_wsr64("tpidr_el1", (uint64_t)&t->arch_.thread_pointer_location);
  __isb(ARM_MB_SY);
}

在启动时它会创建一个线程并将其指针存储在 tpidr_el1

与用户空间中线程本地存储相关的所有内容都需要保存在每线程结构中。您需要将此结构的地址保存在某处。在 armv8 中,TPIDR_EL0 可以用于此目的。在 x86_64 中,通常 fs 段寄存器被重新用于此用途。

Fuchsia 的 ABI for Thread-Local Storage 记录在他们的网站上。

在 fuchsia 中,TPIDR_EL0 将为您提供 pthread structure. See __allocate_thread 以了解部分内存的分配方式。

一个用法示例(线程局部变量除外)是 SafeStack feature,它在 pthread 结构中存储第二个堆栈指针。

对于内核,在armv8中,出于类似的目的,使用TPIDR_EL1来保存内核的指针Thread structure

请注意,在 armv8 中,有一个用于 EL0(用户空间)和 EL1 (内核空间)的寄存器。在 x86-64 中,没有分离,处理起来有点尴尬:内核有一个内部位置来存储 gs 寄存器的“内核版本”,并使用 swapgs 指令在用户空间和内核空间 gs 寄存器。