浮點 API

核心程式碼通常禁止使用浮點 (FP) 暫存器或指令,包括 C 語言的 float 和 double 資料型別。此規則減少了系統呼叫開銷,因為核心無需儲存和恢復使用者空間的浮點暫存器狀態。

然而,偶爾驅動程式或庫函式可能需要包含浮點程式碼。透過將包含浮點程式碼的函式隔離到單獨的翻譯單元(單獨的原始檔),並在呼叫這些函式時儲存/恢復浮點暫存器狀態來支援此功能。這建立了浮點使用的“臨界區”。

進行這種隔離的原因是為了防止編譯器在這些臨界區之外生成涉及浮點暫存器的程式碼。編譯器有時會使用浮點暫存器來最佳化內聯的 memcpy 或變數賦值,因為浮點暫存器可能比通用暫存器更寬。

浮點程式碼在核心中的可用性是架構特定的。此外,由於單個核心可能被配置為同時支援帶有和不帶有浮點單元的平臺,因此必須在構建時和執行時都檢查 FPU 的可用性。

如以下所述,有幾種架構實現了 linux/fpu.h 中的通用核心浮點 API。其他一些架構實現了自己獨特的 API,這些 API 已單獨文件化。

構建時 API

如果選項 ARCH_HAS_KERNEL_FPU_SUPPORT 被啟用,則可以構建浮點程式碼。對於 C 程式碼,此類程式碼必須放在單獨的檔案中,並且該檔案必須使用以下模式調整其編譯標誌

CFLAGS_foo.o += $(CC_FLAGS_FPU)
CFLAGS_REMOVE_foo.o += $(CC_FLAGS_NO_FPU)

架構應根據需要在其頂層 Makefile 中定義這些變數中的一個或兩個。例如

CC_FLAGS_FPU := -mhard-float

CC_FLAGS_NO_FPU := -msoft-float

常規核心程式碼假定使用與 CC_FLAGS_NO_FPU 等效的標誌。

執行時 API

執行時 API 在 linux/fpu.h 中提供。此標頭檔案不能從實現浮點程式碼的檔案(那些編譯標誌已如上調整的檔案)中包含。相反,它必須在定義浮點臨界區時包含。

bool kernel_fpu_available(void)

此函式報告浮點程式碼是否可在當前 CPU 或平臺上使用。此函式返回的值在執行時不應改變,因此只需呼叫一次,而不是在每個臨界區之前呼叫。

void kernel_fpu_begin(void)
void kernel_fpu_end(void)

這些函式建立了一個浮點臨界區。只有在先前呼叫 kernel_fpu_available() 返回 true 後,呼叫 kernel_fpu_begin() 才有效。這些函式只保證可從(可搶佔或不可搶佔的)程序上下文呼叫。

在臨界區內部,搶佔可能會被停用,因此它們的尺寸應儘量減小。它們要求是可重入的。如果呼叫方期望巢狀臨界區,則必須實現自己的引用計數。