35. 在使用者空間應用程式中使用 XSTATE 特性

x86 架構支援透過 CPUID 列舉的浮點擴充套件。 應用程式查詢 CPUID 並使用 XGETBV 來評估核心 XCR0 啟用了哪些特性。

對於 AVX-512 和 PKRU 狀態,如果可用,核心會自動啟用這些特性。 像 AMX TILE_DATA(XSTATE 元件 18)這樣的特性也由 XCR0 啟用,但第一次使用相關指令會被核心捕獲,因為預設情況下不會自動分配所需的大型 XSTATE 緩衝區。

35.1. 動態特性的目的

傳統的使用者空間庫通常對備用訊號堆疊具有硬編碼的靜態大小,通常使用 MINSIGSTKSZ,它通常是 2KB。 該堆疊必須能夠儲存至少核心在跳轉到訊號處理程式之前設定的訊號幀。 該訊號幀必須包含由 CPU 定義的 XSAVE 緩衝區。

然而,這意味著訊號堆疊的大小是動態的,而不是靜態的,因為不同的 CPU 具有不同大小的 XSAVE 緩衝區。 對於像 AMX 這樣的新 CPU 特性,現有應用程式的 2KB 編譯大小太小了。 核心不需要普遍要求更大的堆疊,而是透過動態啟用,核心可以強制使用者空間應用程式擁有適當大小的備用堆疊。

35.2. 在使用者空間應用程式中使用動態啟用的 XSTATE 特性

核心提供了一個基於 arch_prctl(2) 的機制,供應用程式請求使用此類特性。 與此相關的 arch_prctl(2) 選項是

-ARCH_GET_XCOMP_SUPP

arch_prctl(ARCH_GET_XCOMP_SUPP, &features);

ARCH_GET_XCOMP_SUPP 將支援的特性儲存在型別為 uint64_t 的使用者空間儲存中。 第二個引數是指向該儲存的指標。

-ARCH_GET_XCOMP_PERM

arch_prctl(ARCH_GET_XCOMP_PERM, &features);

ARCH_GET_XCOMP_PERM 將使用者空間程序具有許可權的特性儲存在型別為 uint64_t 的使用者空間儲存中。 第二個引數是指向該儲存的指標。

-ARCH_REQ_XCOMP_PERM

arch_prctl(ARCH_REQ_XCOMP_PERM, feature_nr);

ARCH_REQ_XCOMP_PERM 允許請求動態啟用的特性或特性集的許可權。 特性集可以對映到一個設施,例如 AMX,並且可能需要啟用一個或多個 XSTATE 元件。

特性引數是設施工作所需的最高 XSTATE 元件的編號。

當請求一個特性的許可權時,核心會檢查可用性。 核心確保程序任務中的 sigaltstacks 足夠大,以容納生成的大的訊號幀。 它在 ARCH_REQ_XCOMP_SUPP 和任何後續 sigaltstack(2) 呼叫期間強制執行這一點。 如果已安裝的 sigaltstack 小於生成的訊號幀大小,則 ARCH_REQ_XCOMP_SUPP 會導致 -ENOSUPP。 此外,如果請求的 altstack 對於允許的特性來說太小,sigaltstack(2) 會導致 -ENOMEM。

授予的許可權對每個程序都有效。 許可權在 fork(2) 上繼承,並在 exec(3) 上清除。

第一次使用與動態啟用特性相關的指令會被核心捕獲。 陷阱處理程式檢查該程序是否具有使用該特性的許可權。 如果程序沒有許可權,則核心會將 SIGILL 傳送到應用程式。 如果程序有許可權,則處理程式會為任務分配更大的 xstate 緩衝區,以便可以上下文切換大狀態。 在不太可能發生的分配失敗的情況下,核心會發送 SIGSEGV。

35.2.1. AMX TILE_DATA 啟用示例

以下是使用者空間應用程式如何動態啟用 TILE_DATA 的示例

  1. 應用程式首先需要向核心查詢 AMX 支援

    #include <asm/prctl.h>
    #include <sys/syscall.h>
    #include <stdio.h>
    #include <unistd.h>
    
    #ifndef ARCH_GET_XCOMP_SUPP
    #define ARCH_GET_XCOMP_SUPP  0x1021
    #endif
    
    #ifndef ARCH_XCOMP_TILECFG
    #define ARCH_XCOMP_TILECFG   17
    #endif
    
    #ifndef ARCH_XCOMP_TILEDATA
    #define ARCH_XCOMP_TILEDATA  18
    #endif
    
    #define MASK_XCOMP_TILE      ((1 << ARCH_XCOMP_TILECFG) | \
                                  (1 << ARCH_XCOMP_TILEDATA))
    
    unsigned long features;
    long rc;
    
    ...
    
    rc = syscall(SYS_arch_prctl, ARCH_GET_XCOMP_SUPP, &features);
    
    if (!rc && (features & MASK_XCOMP_TILE) == MASK_XCOMP_TILE)
        printf("AMX is available.\n");
    
  2. 之後,在確定對 AMX 的支援後,應用程式必須明確請求使用它的許可權

    #ifndef ARCH_REQ_XCOMP_PERM
    #define ARCH_REQ_XCOMP_PERM  0x1023
    #endif
    
    ...
    
    rc = syscall(SYS_arch_prctl, ARCH_REQ_XCOMP_PERM, ARCH_XCOMP_TILEDATA);
    
    if (!rc)
        printf("AMX is ready for use.\n");
    

請注意,此示例不包括 sigaltstack 準備。

35.3. 訊號幀中的動態特性

如果動態啟用的特性處於其初始配置中,則在訊號進入時不會將其寫入訊號幀。 這與非動態特性不同,無論其配置如何,它們總是被寫入。 訊號處理程式可以檢查 XSAVE 緩衝區的 XSTATE_BV 欄位以確定是否寫入了特性。

35.4. 虛擬機器上的動態特性

訪客狀態元件的許可權需要與主機分開管理,因為它們彼此排斥。 擴充套件了一對選項來控制訪客許可權

-ARCH_GET_XCOMP_GUEST_PERM

arch_prctl(ARCH_GET_XCOMP_GUEST_PERM, &features);

ARCH_GET_XCOMP_GUEST_PERM 是 ARCH_GET_XCOMP_PERM 的變體。 因此,它為訪客元件提供相同的語義和功能。

-ARCH_REQ_XCOMP_GUEST_PERM

arch_prctl(ARCH_REQ_XCOMP_GUEST_PERM, feature_nr);

ARCH_REQ_XCOMP_GUEST_PERM 是 ARCH_REQ_XCOMP_PERM 的變體。 它對訪客許可權具有相同的語義。 雖然提供類似的功能,但這帶有一個約束。 當建立第一個 VCPU 時,許可權會被凍結。 在那之後,任何更改許可權的嘗試都將被拒絕。 因此,必須在建立第一個 VCPU 之前請求許可權。

請注意,一些 VMM 可能已經建立了一組受支援的狀態元件。 這些選項不假定支援任何特定的 VMM。