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

Gue*_*OCs 6 cpu kernel arm armv8 fuchsia

根据ARM 文档,线程 ID 寄存器类似于TPIDR_EL0TPIDR_EL1

提供存储软件线程和进程 ID 的位置,以用于操作系统管理目的。这些寄存器对处理器行为没有影响。

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

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

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

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

Mar*_*rco 7

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

Fuchsia 的线程本地存储 ABI记录在其网站中。

在紫红色中,TPIDR_EL0将为您提供pthread 结构。查看__allocate_thread其中一些内存是如何分配的。

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

对于内核,在armv8中,TPIDR_EL1出于类似的目的,用于保存内核Thread结构的指针。

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