| Chinese translated version of Documentation/arch/arm/kernel_user_helpers.rst |
| |
| If you have any comment or update to the content, please contact the |
| original document maintainer directly. However, if you have a problem |
| communicating in English you can also ask the Chinese maintainer for |
| help. Contact the Chinese maintainer if this translation is outdated |
| or if there is a problem with the translation. |
| |
| Maintainer: Nicolas Pitre <nicolas.pitre@linaro.org> |
| Dave Martin <dave.martin@linaro.org> |
| Chinese maintainer: Fu Wei <tekkamanninja@gmail.com> |
| --------------------------------------------------------------------- |
| Documentation/arch/arm/kernel_user_helpers.rst 的中文翻譯 |
| |
| 如果想評論或更新本文的內容,請直接聯繫原文檔的維護者。如果你使用英文 |
| 交流有困難的話,也可以向中文版維護者求助。如果本翻譯更新不及時或者翻 |
| 譯存在問題,請聯繫中文版維護者。 |
| 英文版維護者: Nicolas Pitre <nicolas.pitre@linaro.org> |
| Dave Martin <dave.martin@linaro.org> |
| 中文版維護者: 傅煒 Fu Wei <tekkamanninja@gmail.com> |
| 中文版翻譯者: 傅煒 Fu Wei <tekkamanninja@gmail.com> |
| 中文版校譯者: 宋冬生 Dongsheng Song <dongshneg.song@gmail.com> |
| 傅煒 Fu Wei <tekkamanninja@gmail.com> |
| |
| |
| 以下爲正文 |
| --------------------------------------------------------------------- |
| 內核提供的用戶空間輔助代碼 |
| ========================= |
| |
| 在內核內存空間的固定地址處,有一個由內核提供並可從用戶空間訪問的代碼 |
| 段。它用於向用戶空間提供因在許多 ARM CPU 中未實現的特性和/或指令而需 |
| 內核提供幫助的某些操作。這些代碼直接在用戶模式下執行的想法是爲了獲得 |
| 最佳效率,但那些與內核計數器聯繫過於緊密的部分,則被留給了用戶庫實現。 |
| 事實上,此代碼甚至可能因不同的 CPU 而異,這取決於其可用的指令集或它 |
| 是否爲 SMP 系統。換句話說,內核保留在不作出警告的情況下根據需要更改 |
| 這些代碼的權利。只有本文檔描述的入口及其結果是保證穩定的。 |
| |
| 這與完全成熟的 VDSO 實現不同(但兩者並不衝突),儘管如此,VDSO 可阻止 |
| 某些通過常量高效跳轉到那些代碼段的彙編技巧。且由於那些代碼段在返回用戶 |
| 代碼前僅使用少量的代碼週期,則一個 VDSO 間接遠程調用將會在這些簡單的 |
| 操作上增加一個可測量的開銷。 |
| |
| 在對那些擁有原生支持的新型處理器進行代碼優化時,僅在已爲其他操作使用 |
| 了類似的新增指令,而導致二進制結果已與早期 ARM 處理器不兼容的情況下, |
| 用戶空間才應繞過這些輔助代碼,並在內聯函數中實現這些操作(無論是通過 |
| 編譯器在代碼中直接放置,還是作爲庫函數調用實現的一部分)。也就是說, |
| 如果你編譯的代碼不會爲了其他目的使用新指令,則不要僅爲了避免使用這些 |
| 內核輔助代碼,導致二進制程序無法在早期處理器上運行。 |
| |
| 新的輔助代碼可能隨着時間的推移而增加,所以新內核中的某些輔助代碼在舊 |
| 內核中可能不存在。因此,程序必須在對任何輔助代碼調用假設是安全之前, |
| 檢測 __kuser_helper_version 的值(見下文)。理想情況下,這種檢測應該 |
| 只在進程啓動時執行一次;如果內核版本不支持所需輔助代碼,則該進程可儘早 |
| 中止執行。 |
| |
| kuser_helper_version |
| -------------------- |
| |
| 位置: 0xffff0ffc |
| |
| 參考聲明: |
| |
| extern int32_t __kuser_helper_version; |
| |
| 定義: |
| |
| 這個區域包含了當前運行內核實現的輔助代碼版本號。用戶空間可以通過讀 |
| 取此版本號以確定特定的輔助代碼是否存在。 |
| |
| 使用範例: |
| |
| #define __kuser_helper_version (*(int32_t *)0xffff0ffc) |
| |
| void check_kuser_version(void) |
| { |
| if (__kuser_helper_version < 2) { |
| fprintf(stderr, "can't do atomic operations, kernel too old\n"); |
| abort(); |
| } |
| } |
| |
| 注意: |
| |
| 用戶空間可以假設這個域的值不會在任何單個進程的生存期內改變。也就 |
| 是說,這個域可以僅在庫的初始化階段或進程啓動階段讀取一次。 |
| |
| kuser_get_tls |
| ------------- |
| |
| 位置: 0xffff0fe0 |
| |
| 參考原型: |
| |
| void * __kuser_get_tls(void); |
| |
| 輸入: |
| |
| lr = 返回地址 |
| |
| 輸出: |
| |
| r0 = TLS 值 |
| |
| 被篡改的寄存器: |
| |
| 無 |
| |
| 定義: |
| |
| 獲取之前通過 __ARM_NR_set_tls 系統調用設置的 TLS 值。 |
| |
| 使用範例: |
| |
| typedef void * (__kuser_get_tls_t)(void); |
| #define __kuser_get_tls (*(__kuser_get_tls_t *)0xffff0fe0) |
| |
| void foo() |
| { |
| void *tls = __kuser_get_tls(); |
| printf("TLS = %p\n", tls); |
| } |
| |
| 注意: |
| |
| - 僅在 __kuser_helper_version >= 1 時,此輔助代碼存在 |
| (從內核版本 2.6.12 開始)。 |
| |
| kuser_cmpxchg |
| ------------- |
| |
| 位置: 0xffff0fc0 |
| |
| 參考原型: |
| |
| int __kuser_cmpxchg(int32_t oldval, int32_t newval, volatile int32_t *ptr); |
| |
| 輸入: |
| |
| r0 = oldval |
| r1 = newval |
| r2 = ptr |
| lr = 返回地址 |
| |
| 輸出: |
| |
| r0 = 成功代碼 (零或非零) |
| C flag = 如果 r0 == 0 則置 1,如果 r0 != 0 則清零。 |
| |
| 被篡改的寄存器: |
| |
| r3, ip, flags |
| |
| 定義: |
| |
| 僅在 *ptr 爲 oldval 時原子保存 newval 於 *ptr 中。 |
| 如果 *ptr 被改變,則返回值爲零,否則爲非零值。 |
| 如果 *ptr 被改變,則 C flag 也會被置 1,以實現調用代碼中的彙編 |
| 優化。 |
| |
| 使用範例: |
| |
| typedef int (__kuser_cmpxchg_t)(int oldval, int newval, volatile int *ptr); |
| #define __kuser_cmpxchg (*(__kuser_cmpxchg_t *)0xffff0fc0) |
| |
| int atomic_add(volatile int *ptr, int val) |
| { |
| int old, new; |
| |
| do { |
| old = *ptr; |
| new = old + val; |
| } while(__kuser_cmpxchg(old, new, ptr)); |
| |
| return new; |
| } |
| |
| 注意: |
| |
| - 這個例程已根據需要包含了內存屏障。 |
| |
| - 僅在 __kuser_helper_version >= 2 時,此輔助代碼存在 |
| (從內核版本 2.6.12 開始)。 |
| |
| kuser_memory_barrier |
| -------------------- |
| |
| 位置: 0xffff0fa0 |
| |
| 參考原型: |
| |
| void __kuser_memory_barrier(void); |
| |
| 輸入: |
| |
| lr = 返回地址 |
| |
| 輸出: |
| |
| 無 |
| |
| 被篡改的寄存器: |
| |
| 無 |
| |
| 定義: |
| |
| 應用於任何需要內存屏障以防止手動數據修改帶來的一致性問題,以及 |
| __kuser_cmpxchg 中。 |
| |
| 使用範例: |
| |
| typedef void (__kuser_dmb_t)(void); |
| #define __kuser_dmb (*(__kuser_dmb_t *)0xffff0fa0) |
| |
| 注意: |
| |
| - 僅在 __kuser_helper_version >= 3 時,此輔助代碼存在 |
| (從內核版本 2.6.15 開始)。 |
| |
| kuser_cmpxchg64 |
| --------------- |
| |
| 位置: 0xffff0f60 |
| |
| 參考原型: |
| |
| int __kuser_cmpxchg64(const int64_t *oldval, |
| const int64_t *newval, |
| volatile int64_t *ptr); |
| |
| 輸入: |
| |
| r0 = 指向 oldval |
| r1 = 指向 newval |
| r2 = 指向目標值 |
| lr = 返回地址 |
| |
| 輸出: |
| |
| r0 = 成功代碼 (零或非零) |
| C flag = 如果 r0 == 0 則置 1,如果 r0 != 0 則清零。 |
| |
| 被篡改的寄存器: |
| |
| r3, lr, flags |
| |
| 定義: |
| |
| 僅在 *ptr 等於 *oldval 指向的 64 位值時,原子保存 *newval |
| 指向的 64 位值於 *ptr 中。如果 *ptr 被改變,則返回值爲零, |
| 否則爲非零值。 |
| |
| 如果 *ptr 被改變,則 C flag 也會被置 1,以實現調用代碼中的彙編 |
| 優化。 |
| |
| 使用範例: |
| |
| typedef int (__kuser_cmpxchg64_t)(const int64_t *oldval, |
| const int64_t *newval, |
| volatile int64_t *ptr); |
| #define __kuser_cmpxchg64 (*(__kuser_cmpxchg64_t *)0xffff0f60) |
| |
| int64_t atomic_add64(volatile int64_t *ptr, int64_t val) |
| { |
| int64_t old, new; |
| |
| do { |
| old = *ptr; |
| new = old + val; |
| } while(__kuser_cmpxchg64(&old, &new, ptr)); |
| |
| return new; |
| } |
| |
| 注意: |
| |
| - 這個例程已根據需要包含了內存屏障。 |
| |
| - 由於這個過程的代碼長度(此輔助代碼跨越 2 個常規的 kuser “槽”), |
| 因此 0xffff0f80 不被作爲有效的入口點。 |
| |
| - 僅在 __kuser_helper_version >= 5 時,此輔助代碼存在 |
| (從內核版本 3.1 開始)。 |
| |