docs: add traditional Chinese translation for kernel Documentation

Add traditional Chinese translation (zh_TW) for the Linux Kernel
documentation with a series of translated files.

Signed-off-by: Hu Haowen <src.res@email.cn>
Reviewed-by: Pan Yunwang <panyunwang849@gmail.com>
Link: https://lore.kernel.org/r/20210729155627.41744-1-src.res@email.cn
Signed-off-by: Jonathan Corbet <corbet@lwn.net>
This commit is contained in:
Hu Haowen 2021-07-29 23:56:25 +08:00 committed by Jonathan Corbet
parent 4a52225d61
commit 76f1fc266b
19 changed files with 4088 additions and 0 deletions

View File

@ -8,6 +8,7 @@ Translations
:maxdepth: 1
zh_CN/index
zh_TW/index
it_IT/index
ko_KR/index
ja_JP/index

View File

@ -0,0 +1,41 @@
Chinese translated version of Documentation/core-api/irq/index.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: Eric W. Biederman <ebiederman@xmission.com>
Traditional Chinese maintainer: Hu Haowen <src.res@email.cn>
---------------------------------------------------------------------
Documentation/core-api/irq/index.rst 的繁體中文翻譯
如果想評論或更新本文的內容,請直接聯繫原文檔的維護者。如果你使用英文
交流有困難的話,也可以向繁體中文版維護者求助。如果本翻譯更新不及時或
者翻譯存在問題,請聯繫繁體中文版維護者。
英文版維護者: Eric W. Biederman <ebiederman@xmission.com>
繁體中文版維護者: 胡皓文 Hu Haowen <src.res@email.cn>
繁體中文版翻譯者: 胡皓文 Hu Haowen <src.res@email.cn>
繁體中文版校譯者: 胡皓文 Hu Haowen <src.res@email.cn>
以下爲正文
---------------------------------------------------------------------
何爲 IRQ?
一個 IRQ 是來自某個設備的一個中斷請求。目前,它們可以來自一個硬體引腳,
或來自一個數據包。多個設備可能連接到同個硬體引腳,從而共享一個 IRQ。
一個 IRQ 編號是用於告知硬體中斷源的內核標識。通常情況下,這是一個
全局 irq_desc 數組的索引,但是除了在 linux/interrupt.h 中的實現,
具體的細節是體系結構特定的。
一個 IRQ 編號是設備上某個可能的中斷源的枚舉。通常情況下,枚舉的編號是
該引腳在系統內中斷控制器的所有輸入引腳中的編號。對於 ISA 總線中的情況,
枚舉的是在兩個 i8259 中斷控制器中 16 個輸入引腳。
架構可以對 IRQ 編號指定額外的含義,在硬體涉及任何手工配置的情況下,
是被提倡的。ISA 的 IRQ 是一個分配這類額外含義的典型例子。

View File

@ -0,0 +1,351 @@
.. SPDX-License-Identifier: GPL-2.0
.. include:: ../disclaimer-zh_TW.rst
:Original: Documentation/admin-guide/README.rst
:譯者:
吳想成 Wu XiangCheng <bobwxc@email.cn>
胡皓文 Hu Haowen <src.res@email.cn>
Linux內核5.x版本 <http://kernel.org/>
=========================================
以下是Linux版本5的發行註記。仔細閱讀它們
它們會告訴你這些都是什麼,解釋如何安裝內核,以及遇到問題時該如何做。
什麼是Linux
---------------
Linux是Unix作業系統的克隆版本由Linus Torvalds在一個鬆散的網絡黑客
Hacker無貶義團隊的幫助下從頭開始編寫。它旨在實現兼容POSIX和
單一UNIX規範。
它具有在現代成熟的Unix中應當具有的所有功能包括真正的多任務處理、虛擬內存、
共享庫、按需加載、共享的寫時拷貝COW可執行文件、恰當的內存管理以及包括
IPv4和IPv6在內的複合網絡棧。
Linux在GNU通用公共許可證版本2GNU GPLv2下分發詳見隨附的COPYING文件。
它能在什麼樣的硬體上運行?
-----------------------------
雖然Linux最初是爲32位的x86 PC機386或更高版本開發的但今天它也能運行在
至少Compaq Alpha AXP、Sun SPARC與UltraSPARC、Motorola 68000、PowerPC、
PowerPC64、ARM、Hitachi SuperH、Cell、IBM S/390、MIPS、HP PA-RISC、Intel
IA-64、DEC VAX、AMD x86-64 Xtensa和ARC架構上。
Linux很容易移植到大多數通用的32位或64位體系架構只要它們有一個分頁內存管理
單元PMMU和一個移植的GNU C編譯器gccGNU Compiler CollectionGCC的一
部分。Linux也被移植到許多沒有PMMU的體系架構中儘管功能顯然受到了一定的
限制。
Linux也被移植到了其自己上。現在可以將內核作爲用戶空間應用程式運行——這被
稱爲用戶模式LinuxUML
文檔
-----
網際網路上和書籍上都有大量的電子文檔既有Linux專屬文檔也有與一般UNIX問題相關
的文檔。我建議在任何Linux FTP站點上查找LDPLinux文檔項目書籍的文檔子目錄。
本自述文件並不是關於系統的文檔:有更好的可用資源。
- 網際網路上和書籍上都有大量的電子文檔既有Linux專屬文檔也有與普通
UNIX問題相關的文檔。我建議在任何有LDPLinux文檔項目書籍的Linux FTP
站點上查找文檔子目錄。本自述文件並不是關於系統的文檔:有更好的可用資源。
- 文檔/子目錄中有各種自述文件:例如,這些文件通常包含一些特定驅動程序的
內核安裝說明。請閱讀
:ref:`Documentation/process/changes.rst <changes>` 文件,它包含了升級內核
可能會導致的問題的相關信息。
安裝內核原始碼
---------------
- 如果您要安裝完整的原始碼請把內核tar檔案包放在您有權限的目錄中例如您
的主目錄)並將其解包::
xz -cd linux-5.x.tar.xz | tar xvf -
將「X」替換成最新內核的版本號。
【不要】使用 /usr/src/linux 目錄!這裡有一組庫頭文件使用的內核頭文件
(通常是不完整的)。它們應該與庫匹配,而不是被內核的變化搞得一團糟。
- 您還可以通過打補丁在5.x版本之間升級。補丁以xz格式分發。要通過打補丁進行
安裝請獲取所有較新的補丁文件進入內核原始碼linux-5.x的目錄並
執行::
xz -cd ../patch-5.x.xz | patch -p1
請【按順序】替換所有大於當前原始碼樹版本的「x」這樣就可以了。您可能想要
刪除備份文件文件名類似xxx~ 或 xxx.orig),並確保沒有失敗的補丁(文件名
類似xxx# 或 xxx.rej。如果有不是你就是我犯了錯誤。
與5.x內核的補丁不同5.x.y內核也稱爲穩定版內核的補丁不是增量的而是
直接應用於基本的5.x內核。例如如果您的基本內核是5.0並且希望應用5.0.3
補丁則不應先應用5.0.1和5.0.2的補丁。類似地如果您運行的是5.0.2內核,
並且希望跳轉到5.0.3那麼在應用5.0.3補丁之前必須首先撤銷5.0.2補丁
即patch -R。更多關於這方面的內容請閱讀
:ref:`Documentation/process/applying-patches.rst <applying_patches>`
或者,腳本 patch-kernel 可以用來自動化這個過程。它能確定當前內核版本並
應用找到的所有補丁::
linux/scripts/patch-kernel linux
上面命令中的第一個參數是內核原始碼的位置。補丁是在當前目錄應用的,但是
可以將另一個目錄指定爲第二個參數。
- 確保沒有過時的 .o 文件和依賴項::
cd linux
make mrproper
現在您應該已經正確安裝了原始碼。
軟體要求
---------
編譯和運行5.x內核需要各種軟體包的最新版本。請參考
:ref:`Documentation/process/changes.rst <changes>`
來了解最低版本要求以及如何升級軟體包。請注意,使用過舊版本的這些包可能會
導致很難追蹤的間接錯誤,因此不要以爲在生成或操作過程中出現明顯問題時可以
只更新包。
爲內核建立目錄
---------------
編譯內核時,默認情況下所有輸出文件都將與內核原始碼放在一起。使用
``make O=output/dir`` 選項可以爲輸出文件(包括 .config指定備用位置。
例如::
kernel source code: /usr/src/linux-5.x
build directory: /home/name/build/kernel
要配置和構建內核,請使用::
cd /usr/src/linux-5.x
make O=/home/name/build/kernel menuconfig
make O=/home/name/build/kernel
sudo make O=/home/name/build/kernel modules_install install
請注意:如果使用了 ``O=output/dir`` 選項那麼它必須用於make的所有調用。
配置內核
---------
即使只升級一個小版本,也不要跳過此步驟。每個版本中都會添加新的配置選項,
如果配置文件沒有按預定設置,就會出現奇怪的問題。如果您想以最少的工作量
將現有配置升級到新版本,請使用 ``makeoldconfig`` ,它只會詢問您新配置
選項的答案。
- 其他配置命令包括::
"make config" 純文本界面。
"make menuconfig" 基於文本的彩色菜單、選項列表和對話框。
"make nconfig" 增強的基於文本的彩色菜單。
"make xconfig" 基於Qt的配置工具。
"make gconfig" 基於GTK+的配置工具。
"make oldconfig" 基於現有的 ./.config 文件選擇所有選項,並詢問
新配置選項。
"make olddefconfig"
類似上一個,但不詢問直接將新選項設置爲默認值。
"make defconfig" 根據體系架構使用arch/$arch/defconfig或
arch/$arch/configs/${PLATFORM}_defconfig中的
默認選項值創建./.config文件。
"make ${PLATFORM}_defconfig"
使用arch/$arch/configs/${PLATFORM}_defconfig中
的默認選項值創建一個./.config文件。
用「makehelp」來獲取您體系架構中所有可用平台的列表。
"make allyesconfig"
通過儘可能將選項值設置爲「y」創建一個
./.config文件。
"make allmodconfig"
通過儘可能將選項值設置爲「m」創建一個
./.config文件。
"make allnoconfig" 通過儘可能將選項值設置爲「n」創建一個
./.config文件。
"make randconfig" 通過隨機設置選項值來創建./.config文件。
"make localmodconfig" 基於當前配置和加載的模塊lsmod創建配置。禁用
已加載的模塊不需要的任何模塊選項。
要爲另一台計算機創建localmodconfig請將該計算機
的lsmod存儲到一個文件中並將其作爲lsmod參數傳入。
此外通過在參數LMC_KEEP中指定模塊的路徑可以將
模塊保留在某些文件夾或kconfig文件中。
target$ lsmod > /tmp/mylsmod
target$ scp /tmp/mylsmod host:/tmp
host$ make LSMOD=/tmp/mylsmod \
LMC_KEEP="drivers/usb:drivers/gpu:fs" \
localmodconfig
上述方法在交叉編譯時也適用。
"make localyesconfig" 與localmodconfig類似只是它會將所有模塊選項轉換
爲內置(=y。你可以同時通過LMC_KEEP保留模塊。
"make kvmconfig" 爲kvm客體內核支持啓用其他選項。
"make xenconfig" 爲xen dom0客體內核支持啓用其他選項。
"make tinyconfig" 配置儘可能小的內核。
更多關於使用Linux內核配置工具的信息見文檔
Documentation/kbuild/kconfig.rst。
- ``make config`` 注意事項:
- 包含不必要的驅動程序會使內核變大,並且在某些情況下會導致問題:
探測不存在的控制器卡可能會混淆其他控制器。
- 如果存在協處理器,則編譯了數學仿真的內核仍將使用協處理器:在
這種情況下,數學仿真永遠不會被使用。內核會稍微大一點,但不管
是否有數學協處理器,都可以在不同的機器上工作。
- 「kernel hacking」配置細節通常會導致更大或更慢的內核或兩者
兼而有之),甚至可以通過配置一些例程來主動嘗試破壞壞代碼以發現
內核問題從而降低內核的穩定性kmalloc())。因此,您可能應該
用於研究「開發」、「實驗」或「調試」特性相關問題。
編譯內核
---------
- 確保您至少有gcc 4.9可用。
有關更多信息,請參閱 :ref:`Documentation/process/changes.rst <changes>`
請注意您仍然可以使用此內核運行a.out用戶程序。
- 執行 ``make`` 來創建壓縮內核映像。如果您安裝了lilo以適配內核makefile
那麼也可以進行 ``makeinstall`` 但是您可能需要先檢查特定的lilo設置。
實際安裝必須以root身份執行但任何正常構建都不需要。
無須徒然使用root身份。
- 如果您將內核的任何部分配置爲模塊,那麼還必須執行 ``make modules_install``
- 詳細的內核編譯/生成輸出:
通常,內核構建系統在相當安靜的模式下運行(但不是完全安靜)。但是有時您或
其他內核開發人員需要看到編譯、連結或其他命令的執行過程。爲此,可使用
「verbose詳細」構建模式。
``make`` 命令傳遞 ``V=1`` 來實現,例如::
make V=1 all
如需構建系統也給出內個目標重建的願意,請使用 ``V=2`` 。默認爲 ``V=0``
- 準備一個備份內核以防出錯。對於開發版本尤其如此,因爲每個新版本都包含
尚未調試的新代碼。也要確保保留與該內核對應的模塊的備份。如果要安裝
與工作內核版本號相同的新內核,請在進行 ``make modules_install`` 安裝
之前備份modules目錄。
或者在編譯之前使用內核配置選項「LOCALVERSION」向常規內核版本附加
一個唯一的後綴。LOCALVERSION可以在「General Setup」菜單中設置。
- 爲了引導新內核,您需要將內核映像(例如編譯後的
.../linux/arch/x86/boot/bzImage複製到常規可引導內核的位置。
- 不再支持在沒有LILO等啓動裝載程序幫助的情況下直接從軟盤引導內核。
如果從硬碟引導Linux很可能使用LILO它使用/etc/lilo.conf文件中
指定的內核映像文件。內核映像文件通常是/vmlinuz、/boot/vmlinuz、
/bzImage或/boot/bzImage。使用新內核前請保存舊映像的副本並複製
新映像覆蓋舊映像。然後您【必須重新運行LILO】來更新加載映射否則
將無法啓動新的內核映像。
重新安裝LILO通常需要運行/sbin/LILO。您可能希望編輯/etc/lilo.conf
文件爲舊內核映像指定一個條目(例如/vmlinux.old)防止新的不能正常
工作。有關更多信息請參閱LILO文檔。
重新安裝LILO之後您應該就已經準備好了。關閉系統重新啓動盡情
享受吧!
如果需要更改內核映像中的默認根設備、視頻模式等,請在適當的地方使用
啓動裝載程序的引導選項。無需重新編譯內核即可更改這些參數。
- 使用新內核重新啓動並享受它吧。
若遇到問題
-----------
- 如果您發現了一些可能由於內核缺陷所導致的問題請檢查MAINTAINERS維護者
文件看看是否有人與令您遇到麻煩的內核部分相關。如果無人在此列出,那麼第二
個最好的方案就是把它們發給我torvalds@linux-foundation.org也可能發送
到任何其他相關的郵件列表或新聞組。
- 在所有的缺陷報告中,【請】告訴我們您在說什麼內核,如何復現問題,以及您的
設置是什麼的(使用您的常識)。如果問題是新的,請告訴我;如果問題是舊的,
請嘗試告訴我您什麼時候首次注意到它。
- 如果缺陷導致如下消息::
unable to handle kernel paging request at address C0000010
Oops: 0002
EIP: 0010:XXXXXXXX
eax: xxxxxxxx ebx: xxxxxxxx ecx: xxxxxxxx edx: xxxxxxxx
esi: xxxxxxxx edi: xxxxxxxx ebp: xxxxxxxx
ds: xxxx es: xxxx fs: xxxx gs: xxxx
Pid: xx, process nr: xx
xx xx xx xx xx xx xx xx xx xx
或者類似的內核調試信息顯示在屏幕上或在系統日誌里,請【如實】複製它。
可能對你來說轉儲dump看起來不可理解但它確實包含可能有助於調試問題的
信息。轉儲上方的文本也很重要:它說明了內核轉儲代碼的原因(在上面的示例中,
是由於內核指針錯誤)。更多關於如何理解轉儲的信息,請參見
Documentation/admin-guide/bug-hunting.rst。
- 如果使用 CONFIG_KALLSYMS 編譯內核,則可以按原樣發送轉儲,否則必須使用
``ksymoops`` 程序來理解轉儲但通常首選使用CONFIG_KALLSYMS編譯
此實用程序可從
https://www.kernel.org/pub/linux/utils/kernel/ksymoops/ 下載。
或者,您可以手動執行轉儲查找:
- 在調試像上面這樣的轉儲時如果您可以查找EIP值的含義這將非常有幫助。
十六進位值本身對我或其他任何人都沒有太大幫助:它會取決於特定的內核設置。
您應該做的是從EIP行獲取十六進位值忽略 ``0010:`` ),然後在內核名字列表
中查找它,以查看哪個內核函數包含有問題的地址。
要找到內核函數名,您需要找到與顯示症狀的內核相關聯的系統二進位文件。就是
文件「linux/vmlinux」。要提取名字列表並將其與內核崩潰中的EIP進行匹配
請執行::
nm vmlinux | sort | less
這將爲您提供一個按升序排序的內核地址列表,從中很容易找到包含有問題的地址
的函數。請注意,內核調試消息提供的地址不一定與函數地址完全匹配(事實上,
這是不可能的因此您不能只「grep」列表不過列表將爲您提供每個內核函數
的起點,因此通過查找起始地址低於你正在搜索的地址,但後一個函數的高於的
函數,你會找到您想要的。實際上,在您的問題報告中加入一些「上下文」可能是
一個好主意,給出相關的上下幾行。
如果您由於某些原因無法完成上述操作(如您使用預編譯的內核映像或類似的映像),
請儘可能多地告訴我您的相關設置信息,這會有所幫助。有關詳細信息請閱讀
『Documentation/admin-guide/reporting-issues.rst』。
- 或者您可以在正在運行的內核上使用gdb只讀的即不能更改值或設置斷點
爲此,請首先使用-g編譯內核適當地編輯arch/x86/Makefile然後執行 ``make
clean`` 。您還需要啓用CONFIG_PROC_FS通過 ``make config`` )。
使用新內核重新啓動後,執行 ``gdb vmlinux /proc/kcore`` 。現在可以使用所有
普通的gdb命令。查找系統崩潰點的命令是 ``l *0xXXXXXXXX`` 將xxx替換爲EIP
值)。
用gdb無法調試一個當前未運行的內核是由於gdb錯誤地忽略了編譯內核的起始
偏移量。

View File

@ -0,0 +1,85 @@
.. SPDX-License-Identifier: GPL-2.0
.. include:: ../disclaimer-zh_TW.rst
:Original: :doc:`../../../admin-guide/bug-bisect`
:譯者:
吳想成 Wu XiangCheng <bobwxc@email.cn>
胡皓文 Hu Haowen <src.res@email.cn>
二分bisect缺陷
+++++++++++++++++++
英文版最後更新2016年10月28日
引言
=====
始終嘗試由來自kernel.org的原始碼構建的最新內核。如果您沒有信心這樣做請將
錯誤報告給您的發行版供應商,而不是內核開發人員。
找到缺陷bug並不總是那麼容易不過仍然得去找。如果你找不到它不要放棄。
儘可能多的向相關維護人員報告您發現的信息。請參閱MAINTAINERS文件以了解您所
關注的子系統的維護人員。
在提交錯誤報告之前請閱讀「Documentation/admin-guide/reporting-issues.rst」。
設備未出現Devices not appearing
====================================
這通常是由udev/systemd引起的。在將其歸咎於內核之前先檢查一下。
查找導致缺陷的補丁
===================
使用 ``git`` 提供的工具可以很容易地找到缺陷,只要缺陷是可復現的。
操作步驟:
- 從git原始碼構建內核
- 以此開始二分 [#f1]_::
$ git bisect start
- 標記損壞的變更集::
$ git bisect bad [commit]
- 標記正常工作的變更集::
$ git bisect good [commit]
- 重新構建內核並測試
- 使用以下任一與git bisect進行交互::
$ git bisect good
或::
$ git bisect bad
這取決於您測試的變更集上是否有缺陷
- 在一些交互之後git bisect將給出可能導致缺陷的變更集。
- 例如如果您知道當前版本有問題而4.8版本是正常的,則可以執行以下操作::
$ git bisect start
$ git bisect bad # Current version is bad
$ git bisect good v4.8
.. [#f1] 您可以可選地在開始git bisect的時候提供good或bad參數
``git bisect start [BAD] [GOOD]``
如需進一步參考,請閱讀:
- ``git-bisect`` 的手冊頁
- `Fighting regressions with git bisect用git bisect解決回歸
<https://www.kernel.org/pub/software/scm/git/docs/git-bisect-lk2009.html>`_
- `Fully automated bisecting with "git bisect run"使用git bisect run
來全自動二分) <https://lwn.net/Articles/317154>`_
- `Using Git bisect to figure out when brokenness was introduced
使用Git二分來找出何時引入了錯誤 <http://webchick.net/node/99>`_

View File

@ -0,0 +1,344 @@
.. SPDX-License-Identifier: GPL-2.0
.. include:: ../disclaimer-zh_TW.rst
:Original: :doc:`../../../admin-guide/bug-hunting`
:譯者:
吳想成 Wu XiangCheng <bobwxc@email.cn>
胡皓文 Hu Haowen <src.res@email.cn>
追蹤缺陷
=========
內核錯誤報告通常附帶如下堆棧轉儲::
------------[ cut here ]------------
WARNING: CPU: 1 PID: 28102 at kernel/module.c:1108 module_put+0x57/0x70
Modules linked in: dvb_usb_gp8psk(-) dvb_usb dvb_core nvidia_drm(PO) nvidia_modeset(PO) snd_hda_codec_hdmi snd_hda_intel snd_hda_codec snd_hwdep snd_hda_core snd_pcm snd_timer snd soundcore nvidia(PO) [last unloaded: rc_core]
CPU: 1 PID: 28102 Comm: rmmod Tainted: P WC O 4.8.4-build.1 #1
Hardware name: MSI MS-7309/MS-7309, BIOS V1.12 02/23/2009
00000000 c12ba080 00000000 00000000 c103ed6a c1616014 00000001 00006dc6
c1615862 00000454 c109e8a7 c109e8a7 00000009 ffffffff 00000000 f13f6a10
f5f5a600 c103ee33 00000009 00000000 00000000 c109e8a7 f80ca4d0 c109f617
Call Trace:
[<c12ba080>] ? dump_stack+0x44/0x64
[<c103ed6a>] ? __warn+0xfa/0x120
[<c109e8a7>] ? module_put+0x57/0x70
[<c109e8a7>] ? module_put+0x57/0x70
[<c103ee33>] ? warn_slowpath_null+0x23/0x30
[<c109e8a7>] ? module_put+0x57/0x70
[<f80ca4d0>] ? gp8psk_fe_set_frontend+0x460/0x460 [dvb_usb_gp8psk]
[<c109f617>] ? symbol_put_addr+0x27/0x50
[<f80bc9ca>] ? dvb_usb_adapter_frontend_exit+0x3a/0x70 [dvb_usb]
[<f80bb3bf>] ? dvb_usb_exit+0x2f/0xd0 [dvb_usb]
[<c13d03bc>] ? usb_disable_endpoint+0x7c/0xb0
[<f80bb48a>] ? dvb_usb_device_exit+0x2a/0x50 [dvb_usb]
[<c13d2882>] ? usb_unbind_interface+0x62/0x250
[<c136b514>] ? __pm_runtime_idle+0x44/0x70
[<c13620d8>] ? __device_release_driver+0x78/0x120
[<c1362907>] ? driver_detach+0x87/0x90
[<c1361c48>] ? bus_remove_driver+0x38/0x90
[<c13d1c18>] ? usb_deregister+0x58/0xb0
[<c109fbb0>] ? SyS_delete_module+0x130/0x1f0
[<c1055654>] ? task_work_run+0x64/0x80
[<c1000fa5>] ? exit_to_usermode_loop+0x85/0x90
[<c10013f0>] ? do_fast_syscall_32+0x80/0x130
[<c1549f43>] ? sysenter_past_esp+0x40/0x6a
---[ end trace 6ebc60ef3981792f ]---
這樣的堆棧跟蹤提供了足夠的信息來識別內核原始碼中發生錯誤的那一行。根據問題的
嚴重性,它還可能包含 **「Oops」** 一詞,比如::
BUG: unable to handle kernel NULL pointer dereference at (null)
IP: [<c06969d4>] iret_exc+0x7d0/0xa59
*pdpt = 000000002258a001 *pde = 0000000000000000
Oops: 0002 [#1] PREEMPT SMP
...
儘管有 **Oops** 或其他類型的堆棧跟蹤,但通常需要找到出問題的行來識別和處理缺
陷。在本章中我們將參考「Oops」來了解需要分析的各種堆棧跟蹤。
如果內核是用 ``CONFIG_DEBUG_INFO`` 編譯的,那麼可以使用文件:
`scripts/decode_stacktrace.sh`
連結的模塊
-----------
受到汙染或正在加載/卸載的模塊用「(…)」標記,汙染標誌在
`Documentation/admin-guide/tainted-kernels.rst` 文件中進行了描述,「正在被加
載」用「+」標註,「正在被卸載」用「-」標註。
Oops消息在哪
---------------
通常Oops文本由klogd從內核緩衝區讀取然後交給 ``syslogd`` ,後者將其寫入
syslog文件通常是 ``/var/log/messages`` (取決於 ``/etc/syslog.conf`` )。
在使用systemd的系統上它也可以由 ``journald`` 守護進程存儲,並通過運行
``journalctl`` 命令進行訪問。
有時 ``klogd`` 會掛掉,這種情況下您可以運行 ``dmesg > file`` 從內核緩衝區
讀取數據並保存它。或者您可以 ``cat /proc/kmsg > file`` ,但是您必須適時
中斷以停止傳輸,因爲 ``kmsg`` 是一個「永無止境的文件」。
如果機器嚴重崩潰,無法輸入命令或磁碟不可用,那還有三個選項:
(1) 手動複製屏幕上的文本,並在機器重新啓動後輸入。很難受,但這是突然崩潰下
唯一的選擇。或者你可以用數位相機拍下屏幕——雖然不那麼好,但總比什麼都沒
有好。如果消息滾動超出控制台頂部,使用更高解析度(例如 ``vga=791``
引導啓動將允許您閱讀更多文本。(警告:這需要 ``vesafb`` ,因此對「早期」
的Oppses沒有幫助
(2) 從串口終端啓動(參見
:ref:`Documentation/admin-guide/serial-console.rst <serial_console>`
在另一台機器上運行數據機然後用你喜歡的通信程序捕獲輸出。
Minicom運行良好。
(3) 使用Kdump參閱 Documentation/admin-guide/kdump/kdump.rst ),使用
Documentation/admin-guide/kdump/gdbmacros.txt 中的dmesg gdbmacro從舊內存
中提取內核環形緩衝區。
找到缺陷位置
-------------
如果你能指出缺陷在內核原始碼中的位置,則報告缺陷的效果會非常好。這有兩種方法。
通常來說使用 ``gdb`` 會比較容易,不過內核需要用調試信息來預編譯。
gdb
^^^^
GNU 調試器GNU debugger ``gdb`` )是從 ``vmlinux`` 文件中找出OOPS的確切
文件和行號的最佳方法。
在使用 ``CONFIG_DEBUG_INFO`` 編譯的內核上使用gdb效果最好。可通過運行以下命令
進行設置::
$ ./scripts/config -d COMPILE_TEST -e DEBUG_KERNEL -e DEBUG_INFO
在用 ``CONFIG_DEBUG_INFO`` 編譯的內核上你可以直接從OOPS複製EIP值::
EIP: 0060:[<c021e50e>] Not tainted VLI
並使用GDB來將其翻譯成可讀形式::
$ gdb vmlinux
(gdb) l *0xc021e50e
如果沒有啓用 ``CONFIG_DEBUG_INFO`` 則使用OOPS的函數偏移::
EIP is at vt_ioctl+0xda8/0x1482
並在啓用 ``CONFIG_DEBUG_INFO`` 的情況下重新編譯內核::
$ ./scripts/config -d COMPILE_TEST -e DEBUG_KERNEL -e DEBUG_INFO
$ make vmlinux
$ gdb vmlinux
(gdb) l *vt_ioctl+0xda8
0x1888 is in vt_ioctl (drivers/tty/vt/vt_ioctl.c:293).
288 {
289 struct vc_data *vc = NULL;
290 int ret = 0;
291
292 console_lock();
293 if (VT_BUSY(vc_num))
294 ret = -EBUSY;
295 else if (vc_num)
296 vc = vc_deallocate(vc_num);
297 console_unlock();
或者若您想要更詳細的顯示::
(gdb) p vt_ioctl
$1 = {int (struct tty_struct *, unsigned int, unsigned long)} 0xae0 <vt_ioctl>
(gdb) l *0xae0+0xda8
您也可以使用對象文件作爲替代::
$ make drivers/tty/
$ gdb drivers/tty/vt/vt_ioctl.o
(gdb) l *vt_ioctl+0xda8
如果你有調用跟蹤,類似::
Call Trace:
[<ffffffff8802c8e9>] :jbd:log_wait_commit+0xa3/0xf5
[<ffffffff810482d9>] autoremove_wake_function+0x0/0x2e
[<ffffffff8802770b>] :jbd:journal_stop+0x1be/0x1ee
...
這表明問題可能在 :jbd: 模塊中。您可以在gdb中加載該模塊並列出相關代碼::
$ gdb fs/jbd/jbd.ko
(gdb) l *log_wait_commit+0xa3
.. note::
您還可以對堆棧跟蹤處的任何函數調用執行相同的操作,例如::
[<f80bc9ca>] ? dvb_usb_adapter_frontend_exit+0x3a/0x70 [dvb_usb]
上述調用發生的位置可以通過以下方式看到::
$ gdb drivers/media/usb/dvb-usb/dvb-usb.o
(gdb) l *dvb_usb_adapter_frontend_exit+0x3a
objdump
^^^^^^^^
要調試內核請使用objdump並從崩潰輸出中查找十六進位偏移以找到有效的代碼/匯
編行。如果沒有調試符號,您將看到所示例程的彙編程序代碼,但是如果內核有調試
符號C代碼也將可見調試符號可以在內核配置菜單的hacking項中啓用。例如::
$ objdump -r -S -l --disassemble net/dccp/ipv4.o
.. note::
您需要處於內核樹的頂層以便此獲得您的C文件。
如果您無法訪問原始碼仍然可以使用以下方法調試一些崩潰轉儲如Dave Miller的
示例崩潰轉儲輸出所示)::
EIP is at +0x14/0x4c0
...
Code: 44 24 04 e8 6f 05 00 00 e9 e8 fe ff ff 8d 76 00 8d bc 27 00 00
00 00 55 57 56 53 81 ec bc 00 00 00 8b ac 24 d0 00 00 00 8b 5d 08
<8b> 83 3c 01 00 00 89 44 24 14 8b 45 28 85 c0 89 44 24 18 0f 85
Put the bytes into a "foo.s" file like this:
.text
.globl foo
foo:
.byte .... /* bytes from Code: part of OOPS dump */
Compile it with "gcc -c -o foo.o foo.s" then look at the output of
"objdump --disassemble foo.o".
Output:
ip_queue_xmit:
push %ebp
push %edi
push %esi
push %ebx
sub $0xbc, %esp
mov 0xd0(%esp), %ebp ! %ebp = arg0 (skb)
mov 0x8(%ebp), %ebx ! %ebx = skb->sk
mov 0x13c(%ebx), %eax ! %eax = inet_sk(sk)->opt
`scripts/decodecode` 文件可以用來自動完成大部分工作這取決於正在調試的CPU
體系結構。
報告缺陷
---------
一旦你通過定位缺陷找到了其發生的地方,你可以嘗試自己修復它或者向上游報告它。
爲了向上游報告,您應該找出用於開發受影響代碼的郵件列表。這可以使用 ``get_maintainer.pl``
例如您在gspca的sonixj.c文件中發現一個缺陷則可以通過以下方法找到它的維護者::
$ ./scripts/get_maintainer.pl -f drivers/media/usb/gspca/sonixj.c
Hans Verkuil <hverkuil@xs4all.nl> (odd fixer:GSPCA USB WEBCAM DRIVER,commit_signer:1/1=100%)
Mauro Carvalho Chehab <mchehab@kernel.org> (maintainer:MEDIA INPUT INFRASTRUCTURE (V4L/DVB),commit_signer:1/1=100%)
Tejun Heo <tj@kernel.org> (commit_signer:1/1=100%)
Bhaktipriya Shridhar <bhaktipriya96@gmail.com> (commit_signer:1/1=100%,authored:1/1=100%,added_lines:4/4=100%,removed_lines:9/9=100%)
linux-media@vger.kernel.org (open list:GSPCA USB WEBCAM DRIVER)
linux-kernel@vger.kernel.org (open list)
請注意它將指出:
- 最後接觸原始碼的開發人員如果這是在git樹中完成的。在上面的例子中是Tejun
和Bhaktipriya在這個特定的案例中沒有人真正參與這個文件的開發
- 驅動維護人員Hans Verkuil
- 子系統維護人員Mauro Carvalho Chehab
- 驅動程序和/或子系統郵件列表linux-media@vger.kernel.org
- Linux內核郵件列表linux-kernel@vger.kernel.org
通常修復缺陷的最快方法是將它報告給用於開發相關代碼的郵件列表linux-media
ML抄送驅動程序維護者Hans
如果你完全不知道該把報告寄給誰,且 ``get_maintainer.pl`` 也沒有提供任何有用
的信息請發送到linux-kernel@vger.kernel.org。
感謝您的幫助這使Linux儘可能穩定:-)
修復缺陷
---------
如果你懂得編程,你不僅可以通過報告錯誤來幫助我們,還可以提供一個解決方案。
畢竟,開源就是分享你的工作,你不想因爲你的天才而被認可嗎?
如果你決定這樣做,請在制定解決方案後將其提交到上游。
請務必閱讀
:ref:`Documentation/process/submitting-patches.rst <submittingpatches>`
以幫助您的代碼被接受。
---------------------------------------------------------------------------
``klogd`` 進行Oops跟蹤的注意事項
------------------------------------
爲了幫助Linus和其他內核開發人員 ``klogd`` 對保護故障的處理提供了大量支持。
爲了完整支持地址解析,至少應該使用 ``sysklogd`` 包的1.3-pl3版本。
當發生保護故障時, ``klogd`` 守護進程會自動將內核日誌消息中的重要地址轉換爲
它們的等效符號。然後通過 ``klogd`` 使用的任何報告機制來轉發這個已翻譯的內核
消息。保護錯誤消息可以直接從消息文件中剪切出來並轉發給內核開發人員。
``klogd`` 執行兩種類型的地址解析靜態翻譯和動態翻譯。靜態翻譯使用System.map
文件。爲了進行靜態轉換, ``klogd`` 守護進程必須能夠在守護進程初始化時找到系
統映射文件。有關 ``klogd`` 如何搜索映射文件的信息請參見klogd手冊頁。
當使用內核可加載模塊時,動態地址轉換非常重要。由於內核模塊的內存是從內核的
動態內存池中分配的,因此無論是模塊的開頭還是模塊中的函數和符號都沒有固定的
位置。
內核支持系統調用允許程序確定加載哪些模塊及其在內存中的位置。klogd守護進程
使用這些系統調用構建了一個符號表,可用於調試可加載內核模塊中發生的保護錯誤。
klogd至少會提供產生保護故障的模塊的名稱。如果可加載模塊的開發人員選擇從模塊
導出符號信息,則可能會有其他可用的符號信息。
由於內核模塊環境可以是動態的,因此當模塊環境發生變化時,必須有一種通知
``klogd`` 守護進程的機制。有一些可用的命令行選項允許klogd向當前正在執行的守
護進程發出信號示意應該刷新符號信息。有關更多信息,請參閱 ``klogd`` 手冊頁。
sysklogd發行版附帶了一個補丁它修改了 ``modules-2.0.0`` 包,以便在加載或
卸載模塊時自動向klogd發送信號。應用此補丁基本上可無縫支持調試內核可加載模塊
發生的保護故障。
以下是 ``klogd`` 處理的可加載模塊中的保護故障示例::
Aug 29 09:51:01 blizard kernel: Unable to handle kernel paging request at virtual address f15e97cc
Aug 29 09:51:01 blizard kernel: current->tss.cr3 = 0062d000, %cr3 = 0062d000
Aug 29 09:51:01 blizard kernel: *pde = 00000000
Aug 29 09:51:01 blizard kernel: Oops: 0002
Aug 29 09:51:01 blizard kernel: CPU: 0
Aug 29 09:51:01 blizard kernel: EIP: 0010:[oops:_oops+16/3868]
Aug 29 09:51:01 blizard kernel: EFLAGS: 00010212
Aug 29 09:51:01 blizard kernel: eax: 315e97cc ebx: 003a6f80 ecx: 001be77b edx: 00237c0c
Aug 29 09:51:01 blizard kernel: esi: 00000000 edi: bffffdb3 ebp: 00589f90 esp: 00589f8c
Aug 29 09:51:01 blizard kernel: ds: 0018 es: 0018 fs: 002b gs: 002b ss: 0018
Aug 29 09:51:01 blizard kernel: Process oops_test (pid: 3374, process nr: 21, stackpage=00589000)
Aug 29 09:51:01 blizard kernel: Stack: 315e97cc 00589f98 0100b0b4 bffffed4 0012e38e 00240c64 003a6f80 00000001
Aug 29 09:51:01 blizard kernel: 00000000 00237810 bfffff00 0010a7fa 00000003 00000001 00000000 bfffff00
Aug 29 09:51:01 blizard kernel: bffffdb3 bffffed4 ffffffda 0000002b 0007002b 0000002b 0000002b 00000036
Aug 29 09:51:01 blizard kernel: Call Trace: [oops:_oops_ioctl+48/80] [_sys_ioctl+254/272] [_system_call+82/128]
Aug 29 09:51:01 blizard kernel: Code: c7 00 05 00 00 00 eb 08 90 90 90 90 90 90 90 90 89 ec 5d c3
---------------------------------------------------------------------------
::
Dr. G.W. Wettstein Oncology Research Div. Computing Facility
Roger Maris Cancer Center INTERNET: greg@wind.rmcc.com
820 4th St. N.
Fargo, ND 58122
Phone: 701-234-7556

View File

@ -0,0 +1,16 @@
.. SPDX-License-Identifier: GPL-2.0
.. include:: ../disclaimer-zh_TW.rst
:Translator: 胡皓文 Hu Haowen <src.res@email.cn>
清除 WARN_ONCE
--------------
WARN_ONCE / WARN_ON_ONCE / printk_once 僅僅列印一次消息.
echo 1 > /sys/kernel/debug/clear_warn_once
可以清除這種狀態並且再次允許列印一次告警信息,這對於運行測試集後重現問題
很有用。

View File

@ -0,0 +1,112 @@
.. SPDX-License-Identifier: GPL-2.0
.. include:: ../disclaimer-zh_TW.rst
:Translator: 胡皓文 Hu Haowen <src.res@email.cn>
========
CPU 負載
========
Linux通過``/proc/stat````/proc/uptime``導出各種信息,用戶空間工具
如top(1)使用這些信息計算系統花費在某個特定狀態的平均時間。
例如:
$ iostat
Linux 2.6.18.3-exp (linmac) 02/20/2007
avg-cpu: %user %nice %system %iowait %steal %idle
10.01 0.00 2.92 5.44 0.00 81.63
...
這裡系統認爲在默認採樣周期內有10.01%的時間工作在用戶空間2.92%的時
間用在系統空間總體上有81.63%的時間是空閒的。
大多數情況下``/proc/stat``的信息幾乎真實反映了系統信息,然而,由於內
核採集這些數據的方式/時間的特點,有時這些信息根本不可靠。
那麼這些信息是如何被搜集的呢?每當時間中斷觸發時,內核查看此刻運行的
進程類型,並增加與此類型/狀態進程對應的計數器的值。這種方法的問題是
在兩次時間中斷之間系統(進程)能夠在多種狀態之間切換多次,而計數器只
增加最後一種狀態下的計數。
舉例
---
假設系統有一個進程以如下方式周期性地占用cpu::
兩個時鐘中斷之間的時間線
|-----------------------|
^ ^
|_ 開始運行 |
|_ 開始睡眠
(很快會被喚醒)
在上面的情況下,根據``/proc/stat``的信息(由於當系統處於空閒狀態時,
時間中斷經常會發生系統的負載將會是0
大家能夠想像內核的這種行爲會發生在許多情況下,這將導致``/proc/stat``
中存在相當古怪的信息::
/* gcc -o hog smallhog.c */
#include <time.h>
#include <limits.h>
#include <signal.h>
#include <sys/time.h>
#define HIST 10
static volatile sig_atomic_t stop;
static void sighandler (int signr)
{
(void) signr;
stop = 1;
}
static unsigned long hog (unsigned long niters)
{
stop = 0;
while (!stop && --niters);
return niters;
}
int main (void)
{
int i;
struct itimerval it = { .it_interval = { .tv_sec = 0, .tv_usec = 1 },
.it_value = { .tv_sec = 0, .tv_usec = 1 } };
sigset_t set;
unsigned long v[HIST];
double tmp = 0.0;
unsigned long n;
signal (SIGALRM, &sighandler);
setitimer (ITIMER_REAL, &it, NULL);
hog (ULONG_MAX);
for (i = 0; i < HIST; ++i) v[i] = ULONG_MAX - hog (ULONG_MAX);
for (i = 0; i < HIST; ++i) tmp += v[i];
tmp /= HIST;
n = tmp - (tmp / 3.0);
sigemptyset (&set);
sigaddset (&set, SIGALRM);
for (;;) {
hog (n);
sigwait (&set, &i);
}
return 0;
}
參考
---
- https://lore.kernel.org/r/loom.20070212T063225-663@post.gmane.org
- Documentation/filesystems/proc.rst (1.8)
謝謝
---
Con Kolivas, Pavel Machek

View File

@ -0,0 +1,135 @@
.. SPDX-License-Identifier: GPL-2.0
.. include:: ../disclaimer-zh_TW.rst
:Original: :doc:`../../../admin-guide/index`
:Translator: 胡皓文 Hu Haowen <src.res@email.cn>
Linux 內核用戶和管理員指南
==========================
下面是一組隨時間添加到內核中的面向用戶的文檔的集合。到目前爲止,還沒有一個
整體的順序或組織 - 這些材料不是一個單一的,連貫的文件!幸運的話,情況會隨著
時間的推移而迅速改善。
這個初始部分包含總體信息包括描述內核的README 關於內核參數的文檔等。
.. toctree::
:maxdepth: 1
README
Todolist:
kernel-parameters
devices
sysctl/index
本節介紹CPU漏洞及其緩解措施。
Todolist:
hw-vuln/index
下面的一組文檔針對的是試圖跟蹤問題和bug的用戶。
.. toctree::
:maxdepth: 1
reporting-issues
security-bugs
bug-hunting
bug-bisect
tainted-kernels
init
Todolist:
reporting-bugs
ramoops
dynamic-debug-howto
kdump/index
perf/index
這是應用程式開發人員感興趣的章節的開始。可以在這裡找到涵蓋內核ABI各個
方面的文檔。
Todolist:
sysfs-rules
本手冊的其餘部分包括各種指南,介紹如何根據您的喜好配置內核的特定行爲。
.. toctree::
:maxdepth: 1
clearing-warn-once
cpu-load
unicode
Todolist:
acpi/index
aoe/index
auxdisplay/index
bcache
binderfs
binfmt-misc
blockdev/index
bootconfig
braille-console
btmrvl
cgroup-v1/index
cgroup-v2
cifs/index
cputopology
dell_rbu
device-mapper/index
edid
efi-stub
ext4
nfs/index
gpio/index
highuid
hw_random
initrd
iostats
java
jfs
kernel-per-CPU-kthreads
laptops/index
lcd-panel-cgram
ldm
lockup-watchdogs
LSM/index
md
media/index
mm/index
module-signing
mono
namespaces/index
numastat
parport
perf-security
pm/index
pnp
rapidio
ras
rtc
serial-console
svga
sysrq
thunderbolt
ufs
vga-softcursor
video-output
xfs
.. only:: subproject and html
Indices
=======
* :ref:`genindex`

View File

@ -0,0 +1,58 @@
.. SPDX-License-Identifier: GPL-2.0
.. include:: ../disclaimer-zh_TW.rst
:Original: :doc:`../../../admin-guide/init`
:譯者:
吳想成 Wu XiangCheng <bobwxc@email.cn>
胡皓文 Hu Haowen <src.res@email.cn>
解釋「No working init found.」啓動掛起消息
==========================================
:作者:
Andreas Mohr <andi at lisas period de>
Cristian Souza <cristianmsbr at gmail period com>
本文檔提供了加載初始化二進位init binary失敗的一些高層級原因大致按執行
順序列出)。
1) **無法掛載根文件系統Unable to mount root FS** 請設置「debug」內核參數
引導加載程序bootloader配置文件或CONFIG_CMDLINE以獲取更詳細的內核消息。
2) **初始化二進位不存在於根文件系統上init binary doesn't exist on rootfs**
確保您的根文件系統類型正確(並且 ``root=`` 內核參數指向正確的分區);擁有
所需的驅動程序例如SCSI或USB等存儲硬體文件系統ext3、jffs2等是內建的
或者作爲模塊由initrd預加載
3) **控制台設備損壞Broken console device** ``console= setup`` 中可能存在
衝突 --> 初始控制台不可用initial console unavailable。例如由於串行
IRQ問題如缺少基於中斷的配置導致的某些串行控制台不可靠。嘗試使用不同的
``console= device`` 或像 ``netconsole=``
4) **二進位存在但依賴項不可用Binary exists but dependencies not available**
例如初始化二進位的必需庫依賴項,像 ``/lib/ld-linux.so.2`` 丟失或損壞。使用
``readelf -d <INIT>|grep NEEDED`` 找出需要哪些庫。
5) **無法加載二進位Binary cannot be loaded** :請確保二進位的體系結構與您的
硬體匹配。例如i386不匹配x86_64或者嘗試在ARM硬體上加載x86。如果您嘗試在
此處加載非二進位文件shell腳本您應該確保腳本在其工作頭shebang
header``#!/...`` 中指定能正常工作的解釋器(包括其庫依賴項)。在處理
腳本之前,最好先測試一個簡單的非腳本二進位文件,比如 ``/bin/sh`` ,並確認
它能成功執行。要了解更多信息,請將代碼添加到 ``init/main.c`` 以顯示
kernel_execve()的返回值。
當您發現新的失敗原因時,請擴展本解釋(畢竟加載初始化二進位是一個 **關鍵**
艱難的過渡步驟需要儘可能無痛地進行然後向LKML提交一個補丁。
待辦事項:
- 通過一個可以存儲 ``kernel_execve()`` 結果值的結構體數組實現各種
``run_init_process()`` 調用,並在失敗時通過疊代 **所有** 結果來記錄一切
(非常重要的可用性修復)。
- 試著使實現本身在一般情況下更有幫助,例如在受影響的地方提供額外的錯誤消息。

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,78 @@
.. SPDX-License-Identifier: GPL-2.0
.. include:: ../disclaimer-zh_TW.rst
:Original: :doc:`../../../admin-guide/security-bugs`
:譯者:
吳想成 Wu XiangCheng <bobwxc@email.cn>
胡皓文 Hu Haowen <src.res@email.cn>
安全缺陷
=========
Linux內核開發人員非常重視安全性。因此我們想知道何時發現了安全漏洞以便儘快
修復和披露。請向Linux內核安全團隊報告安全漏洞。
聯絡
-----
可以通過電子郵件<security@kernel.org>聯繫Linux內核安全團隊。這是一個安全人員
的私有列表,他們將幫助驗證錯誤報告並開發和發布修復程序。如果您已經有了一個
修復,請將其包含在您的報告中,這樣可以大大加快進程。安全團隊可能會從區域維護
人員那裡獲得額外的幫助,以理解和修復安全漏洞。
與任何缺陷一樣,提供的信息越多,診斷和修復就越容易。如果您不清楚哪些信息有用,
請查看「Documentation/translations/zh_TW/admin-guide/reporting-issues.rst」中
概述的步驟。任何利用漏洞的攻擊代碼都非常有用,未經報告者同意不會對外發布,除
非已經公開。
請儘可能發送無附件的純文本電子郵件。如果所有的細節都藏在附件里,那麼就很難對
一個複雜的問題進行上下文引用的討論。把它想像成一個
:doc:`常規的補丁提交 <../process/submitting-patches>` (即使你還沒有補丁):
描述問題和影響,列出復現步驟,然後給出一個建議的解決方案,所有這些都是純文本的。
披露和限制信息
---------------
安全列表不是公開渠道。爲此,請參見下面的協作。
一旦開發出了健壯的補丁,發布過程就開始了。對公開的缺陷的修復會立即發布。
儘管我們傾向於在未公開缺陷的修復可用時即發布補丁,但應報告者或受影響方的請求,
這可能會被推遲到發布過程開始後的7日內如果根據缺陷的嚴重性需要更多的時間
則可額外延長到14天。推遲發布修復的唯一有效原因是爲了適應QA的邏輯和需要發布
協調的大規模部署。
雖然可能與受信任的個人共享受限信息以開發修復,但未經報告者許可,此類信息不會
與修復程序一起發布或發布在任何其他披露渠道上。這包括但不限於原始錯誤報告和
後續討論如有、漏洞、CVE信息或報告者的身份。
換句話說,我們唯一感興趣的是修復缺陷。提交給安全列表的所有其他資料以及對報告
的任何後續討論,即使在解除限制之後,也將永久保密。
協調
------
對敏感缺陷(例如那些可能導致權限提升的缺陷)的修復可能需要與私有郵件列表
<linux-distros@vs.openwall.org>進行協調,以便分發供應商做好準備,在公開披露
上游補丁時發布一個已修復的內核。發行版將需要一些時間來測試建議的補丁,通常
會要求至少幾天的限制,而供應商更新發布更傾向於周二至周四。若合適,安全團隊
可以協助這種協調或者報告者可以從一開始就包括linux發行版。在這種情況下
記住在電子郵件主題行前面加上「[vs]」如linux發行版wiki中所述
<http://oss-security.openwall.org/wiki/mailing-lists/distros#how-to-use-the-lists>
CVE分配
--------
安全團隊通常不分配CVE我們也不需要它們來進行報告或修復因爲這會使過程不必
要的複雜化並可能耽誤缺陷處理。如果報告者希望在公開披露之前分配一個CVE編號
他們需要聯繫上述的私有linux-distros列表。當在提供補丁之前已有這樣的CVE編號時
如報告者願意,最好在提交消息中提及它。
保密協議
---------
Linux內核安全團隊不是一個正式的機構實體因此無法簽訂任何保密協議。

View File

@ -0,0 +1,161 @@
.. SPDX-License-Identifier: GPL-2.0
.. include:: ../disclaimer-zh_TW.rst
:Original: :doc:`../../../admin-guide/tainted-kernels`
:譯者:
吳想成 Wu XiangCheng <bobwxc@email.cn>
胡皓文 Hu Haowen <src.res@email.cn>
受汙染的內核
-------------
當發生一些在稍後調查問題時可能相關的事件時,內核會將自己標記爲「受汙染
tainted」的。不用太過擔心大多數情況下運行受汙染的內核沒有問題這些信息
主要在有人想調查某個問題時才有意義的,因爲問題的真正原因可能是導致內核受汙染
的事件。這就是爲什麼來自受汙染內核的缺陷報告常常被開發人員忽略,因此請嘗試用
未受汙染的內核重現問題。
請注意,即使在您消除導致汙染的原因(亦即卸載專有內核模塊)之後,內核仍將保持
汙染狀態以表示內核仍然不可信。這也是爲什麼內核在注意到內部問題「kernel
bug」、可恢復錯誤「kernel oops」或不可恢復錯誤「kernel panic」時會列印
受汙染狀態,並將有關此的調試信息寫入日誌 ``dmesg`` 輸出。也可以通過
``/proc/`` 中的文件在運行時檢查受汙染的狀態。
BUG、Oops或Panics消息中的汙染標誌
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
在頂部以「CPU:」開頭的一行中可以找到受汙染的狀態;內核是否受到汙染和原因會顯示
在進程ID「PID:」和觸發事件命令的縮寫名稱「Comm:」)之後::
BUG: unable to handle kernel NULL pointer dereference at 0000000000000000
Oops: 0002 [#1] SMP PTI
CPU: 0 PID: 4424 Comm: insmod Tainted: P W O 4.20.0-0.rc6.fc30 #1
Hardware name: Red Hat KVM, BIOS 0.5.1 01/01/2011
RIP: 0010:my_oops_init+0x13/0x1000 [kpanic]
[...]
如果內核在事件發生時沒有被汙染您將在那裡看到「Not-tainted:」;如果被汙染,那
麼它將是「Tainted:」以及字母或空格。在上面的例子中,它看起來是這樣的::
Tainted: P W O
下表解釋了這些字符的含義。在本例中,由於加載了專有模塊( ``P`` ),出現了
警告( ``W`` ),並且加載了外部構建的模塊( ``O`` ),所以內核早些時候受到
了汙染。要解碼其他字符,請使用下表。
解碼運行時的汙染狀態
~~~~~~~~~~~~~~~~~~~~~
在運行時,您可以通過讀取 ``cat /proc/sys/kernel/tainted`` 來查詢受汙染狀態。
如果返回 ``0`` ,則內核沒有受到汙染;任何其他數字都表示受到汙染的原因。解碼
這個數字的最簡單方法是使用腳本 ``tools/debugging/kernel-chktaint`` ,您的
發行版可能會將其作爲名爲 ``linux-tools````kernel-tools`` 的包的一部分提
供;如果沒有,您可以從
`git.kernel.org <https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/plain/tools/debugging/kernel-chktaint>`_
網站下載此腳本並用 ``sh kernel-chktaint`` 執行,它會在上面引用的日誌中有類似
語句的機器上列印這樣的內容::
Kernel is Tainted for following reasons:
* Proprietary module was loaded (#0)
* Kernel issued warning (#9)
* Externally-built ('out-of-tree') module was loaded (#12)
See Documentation/admin-guide/tainted-kernels.rst in the Linux kernel or
https://www.kernel.org/doc/html/latest/admin-guide/tainted-kernels.html for
a more details explanation of the various taint flags.
Raw taint value as int/string: 4609/'P W O '
你也可以試著自己解碼這個數字。如果內核被汙染的原因只有一個,那麼這很簡單,
在本例中您可以通過下表找到數字。如果你需要解碼有多個原因的數字,因爲它是一
個位域bitfield其中每個位表示一個特定類型的汙染的存在或不存在最好讓
前面提到的腳本來處理。但是如果您需要快速看一下可以使用這個shell命令來檢查
設置了哪些位::
$ for i in $(seq 18); do echo $(($i-1)) $(($(cat /proc/sys/kernel/tainted)>>($i-1)&1));done
汙染狀態代碼表
~~~~~~~~~~~~~~~
=== ===== ====== ========================================================
位 日誌 數字 內核被汙染的原因
=== ===== ====== ========================================================
0 G/P 1 已加載專用模塊
1 _/F 2 模塊被強制加載
2 _/S 4 內核運行在不合規範的系統上
3 _/R 8 模塊被強制卸載
4 _/M 16 處理器報告了機器檢測異常MCE
5 _/B 32 引用了錯誤的頁或某些意外的頁標誌
6 _/U 64 用戶空間應用程式請求的汙染
7 _/D 128 內核最近死機了即曾出現OOPS或BUG
8 _/A 256 ACPI表被用戶覆蓋
9 _/W 512 內核發出警告
10 _/C 1024 已加載staging驅動程序
11 _/I 2048 已應用平台固件缺陷的解決方案
12 _/O 4096 已加載外部構建(「樹外」)模塊
13 _/E 8192 已加載未簽名的模塊
14 _/L 16384 發生軟鎖定
15 _/K 32768 內核已實時打補丁
16 _/X 65536 備用汙染,爲發行版定義並使用
17 _/T 131072 內核是用結構隨機化插件構建的
=== ===== ====== ========================================================
註:字符 ``_`` 表示空白,以便於閱讀表。
汙染的更詳細解釋
~~~~~~~~~~~~~~~~~
0) ``G`` 加載的所有模塊都有GPL或兼容許可證 ``P`` 加載了任何專有模塊。
沒有MODULE_LICENSE模塊許可證或MODULE_LICENSE未被insmod認可爲GPL
兼容的模塊被認爲是專有的。
1) ``F`` 任何模塊被 ``insmod -f`` 強制加載, ``' '`` 所有模塊正常加載。
2) ``S`` 內核運行在不合規範的處理器或系統上:硬體已運行在不受支持的配置中,
因此無法保證正確執行。內核將被汙染,例如:
- 在x86上PAE是通過intel CPU如Pentium M上的forcepae強制執行的這些
CPU不報告PAE但可能有功能實現SMP內核在非官方支持的SMP Athlon CPU上
運行MSR被暴露到用戶空間中。
- 在arm上在某些CPU如Keystone 2上運行的內核沒有啓用某些內核特性。
- 在arm64上CPU之間存在不匹配的硬體特性引導加載程序以不同的模式引導CPU。
- 某些驅動程序正在被用在不受支持的體系結構上例如x86_64以外的其他系統
上的scsi/snic非x86/x86_64/itanium上的scsi/ips已經損壞了arm64上
irqchip/irq-gic的固件設置…
3) ``R`` 模塊被 ``rmmod -f`` 強制卸載, ``' '`` 所有模塊都正常卸載。
4) ``M`` 任何處理器報告了機器檢測異常, ``' '`` 未發生機器檢測異常。
5) ``B`` 頁面釋放函數發現錯誤的頁面引用或某些意外的頁面標誌。這表示硬體問題
或內核錯誤;日誌中應該有其他信息指示發生此汙染的原因。
6) ``U`` 用戶或用戶應用程式特意請求設置受汙染標誌,否則應爲 ``' '``
7) ``D`` 內核最近死機了即出現了OOPS或BUG。
8) ``A`` ACPI表被重寫。
9) ``W`` 內核之前已發出過警告(儘管有些警告可能會設置更具體的汙染標誌)。
10) ``C`` 已加載staging驅動程序。
11) ``I`` 內核正在處理平台固件BIOS或類似軟體中的嚴重錯誤。
12) ``O`` 已加載外部構建(「樹外」)模塊。
13) ``E`` 在支持模塊簽名的內核中加載了未簽名的模塊。
14) ``L`` 系統上先前發生過軟鎖定。
15) ``K`` 內核已經實時打了補丁。
16) ``X`` 備用汙染由Linux發行版定義和使用。
17) ``T`` 內核構建時使用了randstruct插件它可以有意生成非常不尋常的內核結構
布局(甚至是性能病態的布局),這在調試時非常有用。於構建時設置。

View File

@ -0,0 +1,174 @@
.. SPDX-License-Identifier: GPL-2.0
.. include:: ../disclaimer-zh_TW.rst
:Original: Documentation/admin-guide/unicode.rst
:譯者:
吳想成 Wu XiangCheng <bobwxc@email.cn>
胡皓文 Hu Haowen <src.res@email.cn>
Unicode統一碼支持
======================
英文版上次更新2005-01-17版本號 1.4
此文檔由H. Peter Anvin <unicode@lanana.org>管理是Linux註冊名稱與編號管理局
Linux Assigned Names And Numbers AuthorityLANANA項目的一部分。
現行版本請見:
http://www.lanana.org/docs/unicode/admin-guide/unicode.rst
簡介
-----
Linux內核代碼已被重寫以使用Unicode來將字符映射到字體。下載一個Unicode到字體
Unicode-to-font八位字符集與UTF-8模式都將改用此字體來顯示。
這微妙地改變了八位字符表的語義。現在的四個字符表是:
=============== =============================== ================
映射代號 映射名稱 Escape代碼 (G0)
=============== =============================== ================
LAT1_MAP Latin-1 (ISO 8859-1) ESC ( B
GRAF_MAP DEC VT100 pseudographics ESC ( 0
IBMPC_MAP IBM code page 437 ESC ( U
USER_MAP User defined ESC ( K
=============== =============================== ================
特別是 ESC ( U 不再是「直通字體」因爲字體可能與IBM字符集完全不同。
例如即使加載了一個Latin-1字體也允許使用塊圖形block graphics
請注意儘管這些代碼與ISO 2022類似但這些代碼及其用途都與ISO 2022不匹配
Linux有兩個八位代碼G0和G1而ISO 2022有四個七位代碼G0-G3
根據Unicode標準/ISO 10646U+F000到U+F8FF被保留用於作業系統範圍內的分配
Unicode標準將其稱爲「團體區域Corporate Zone因爲這對於Linux是不準確
所以我們稱之爲「Linux區域」。選擇U+F000作爲起點因爲它允許直接映射
區域以2的大倍數開始以防需要1024或2048個字符的字體。這就留下U+E000到
U+EFFF作爲最終用戶區。
[v1.2]Unicodes範圍從U+F000到U+F7FF已經被硬編碼爲直接映射到加載的字體
繞過了翻譯表。用戶定義的映射現在默認爲U+F000到U+F0FF模擬前述行爲。實際上
此範圍可能較短例如vgacon只能處理256字符U+F000..U+F0FF或512字符
U+F000..U+F1FF字體。
Linux 區域中定義的實際字符
---------------------------
此外還定義了Unicode 1.1.4中不存在的以下字符這些字符由DEC VT圖形映射使用。
[v1.2]此用法已過時,不應再使用;請參見下文。
====== ======================================
U+F800 DEC VT GRAPHICS HORIZONTAL LINE SCAN 1
U+F801 DEC VT GRAPHICS HORIZONTAL LINE SCAN 3
U+F803 DEC VT GRAPHICS HORIZONTAL LINE SCAN 7
U+F804 DEC VT GRAPHICS HORIZONTAL LINE SCAN 9
====== ======================================
DEC VT220使用6x10字符矩陣這些字符在DEC VT圖形字符集中形成一個平滑的過渡。
我省略了掃描5行因爲它也被用作塊圖形字符因此被編碼爲U+2500 FORMS LIGHT
HORIZONTAL。
[v1.3]這些字符已正式添加到Unicode 3.2.0中它們在U+23BA、U+23BB、U+23BC、
U+23BD處添加。Linux現在使用新值。
[v1.2]添加了以下字符來表示常見的鍵盤符號這些符號不太可能被添加到Unicode
中,因爲它們非常討厭地取決於特定供應商。當然,這是糟糕設計的一個好例子。
====== ======================================
U+F810 KEYBOARD SYMBOL FLYING FLAG
U+F811 KEYBOARD SYMBOL PULLDOWN MENU
U+F812 KEYBOARD SYMBOL OPEN APPLE
U+F813 KEYBOARD SYMBOL SOLID APPLE
====== ======================================
克林貢Klingon語支持
------------------------
1996年Linux是世界上第一個添加對人工語言克林貢支持的作業系統克林貢是由
Marc Okrand爲《星際迷航》電視連續劇創造的。這種編碼後來被徵募Unicode註冊表
ConScript Unicode RegistryCSUR採用並建議但最終被拒絕納入Unicode
平面一。不過它仍然是Linux區域中的Linux/CSUR私有分配。
這種編碼已經得到克林貢語言研究所Klingon Language Institute的認可。
有關更多信息,請聯繫他們:
http://www.kli.org/
由於Linux CZ開頭部分的字符大多是dingbats/symbols/forms類型而且這是一種
語言因此根據標準Unicode慣例我將它放置在16單元的邊界上。
.. note::
這個範圍現在由徵募Unicode註冊表正式管理。規範性引用文件爲
https://www.evertype.com/standards/csur/klingon.html
克林貢語有一個26個字符的字母表一個10位數的位置數字書寫系統從左到右
,從上到下書寫。
克林貢字母的幾種字形已經被提出。但是由於這組符號看起來始終是一致的,只有實際
的形狀不同因此按照標準Unicode慣例這些差異被認爲是字體變體。
====== =======================================================
U+F8D0 KLINGON LETTER A
U+F8D1 KLINGON LETTER B
U+F8D2 KLINGON LETTER CH
U+F8D3 KLINGON LETTER D
U+F8D4 KLINGON LETTER E
U+F8D5 KLINGON LETTER GH
U+F8D6 KLINGON LETTER H
U+F8D7 KLINGON LETTER I
U+F8D8 KLINGON LETTER J
U+F8D9 KLINGON LETTER L
U+F8DA KLINGON LETTER M
U+F8DB KLINGON LETTER N
U+F8DC KLINGON LETTER NG
U+F8DD KLINGON LETTER O
U+F8DE KLINGON LETTER P
U+F8DF KLINGON LETTER Q
- Written <q> in standard Okrand Latin transliteration
U+F8E0 KLINGON LETTER QH
- Written <Q> in standard Okrand Latin transliteration
U+F8E1 KLINGON LETTER R
U+F8E2 KLINGON LETTER S
U+F8E3 KLINGON LETTER T
U+F8E4 KLINGON LETTER TLH
U+F8E5 KLINGON LETTER U
U+F8E6 KLINGON LETTER V
U+F8E7 KLINGON LETTER W
U+F8E8 KLINGON LETTER Y
U+F8E9 KLINGON LETTER GLOTTAL STOP
U+F8F0 KLINGON DIGIT ZERO
U+F8F1 KLINGON DIGIT ONE
U+F8F2 KLINGON DIGIT TWO
U+F8F3 KLINGON DIGIT THREE
U+F8F4 KLINGON DIGIT FOUR
U+F8F5 KLINGON DIGIT FIVE
U+F8F6 KLINGON DIGIT SIX
U+F8F7 KLINGON DIGIT SEVEN
U+F8F8 KLINGON DIGIT EIGHT
U+F8F9 KLINGON DIGIT NINE
U+F8FD KLINGON COMMA
U+F8FE KLINGON FULL STOP
U+F8FF KLINGON SYMBOL FOR EMPIRE
====== =======================================================
其他虛構和人工字母
-------------------
自從分配了克林貢Linux Unicode塊之後John Cowan <jcowan@reutershealth.com>
和 Michael Everson <everson@evertype.com> 建立了一個虛構和人工字母的註冊表。
徵募Unicode註冊表請訪問
https://www.evertype.com/standards/csur/
所使用的範圍位於最終用戶區域的低端,因此無法進行規範化分配,但建議希望對虛構
字母進行編碼的人員使用這些代碼以實現互操作性。對於克林貢語CSUR採用了Linux
編碼。CSUR的人正在推動將Tengwar和Cirth添加到Unicode平面一將克林貢添加到
Unicode平面一被拒絕因此上述編碼仍然是官方的。

View File

@ -0,0 +1,11 @@
:orphan:
.. warning::
此文件的目的是爲讓中文讀者更容易閱讀和理解,而不是作爲一個分支。因此,
如果您對此文件有任何意見或改動,請先嘗試更新原始英文文件。如果要更改或
修正某處翻譯文件,請將意見或補丁發送給維護者(聯繫方式見下)。
.. note::
如果您發現本文檔與原始文件有任何不同或者有翻譯問題,請聯繫該文件的譯者,
或者發送電子郵件給胡皓文以獲取幫助:<src.res@email.cn>。

View File

@ -0,0 +1,651 @@
Chinese translated version of Documentation/admin-guide/gpio
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: Grant Likely <grant.likely@secretlab.ca>
Linus Walleij <linus.walleij@linaro.org>
Traditional Chinese maintainer: Hu Haowen <src.res@email.cn>
---------------------------------------------------------------------
Documentation/admin-guide/gpio 的繁體中文翻譯
如果想評論或更新本文的內容,請直接聯繫原文檔的維護者。如果你使用英文
交流有困難的話,也可以向繁體中文版維護者求助。如果本翻譯更新不及時或
者翻譯存在問題,請聯繫繁體中文版維護者。
英文版維護者: Grant Likely <grant.likely@secretlab.ca>
Linus Walleij <linus.walleij@linaro.org>
繁體中文版維護者: 胡皓文 Hu Haowen <src.res@email.cn>
繁體中文版翻譯者: 胡皓文 Hu Haowen <src.res@email.cn>
繁體中文版校譯者: 胡皓文 Hu Haowen <src.res@email.cn>
以下爲正文
---------------------------------------------------------------------
GPIO 接口
本文檔提供了一個在Linux下訪問GPIO的公約概述。
這些函數以 gpio_* 作爲前綴。其他的函數不允許使用這樣的前綴或相關的
__gpio_* 前綴。
什麼是GPIO?
==========
"通用輸入/輸出口"(GPIO)是一個靈活的由軟體控制的數位訊號。他們可
由多種晶片提供,且對於從事嵌入式和定製硬體的 Linux 開發者來說是
比較熟悉。每個GPIO 都代表一個連接到特定引腳或球柵陣列(BGA)封裝中
「球珠」的一個位。電路板原理圖顯示了 GPIO 與外部硬體的連接關係。
驅動可以編寫成通用代碼,以使板級啓動代碼可傳遞引腳配置數據給驅動。
片上系統 (SOC) 處理器對 GPIO 有很大的依賴。在某些情況下,每個
非專用引腳都可配置爲 GPIO,且大多數晶片都最少有一些 GPIO。
可編程邏輯器件(類似 FPGA) 可以方便地提供 GPIO。像電源管理和
音頻編解碼器這樣的多功能晶片經常留有一些這樣的引腳來幫助那些引腳
匱乏的 SOC。同時還有通過 I2C 或 SPI 串行總線連接的「GPIO擴展器」
晶片。大多數 PC 的南橋有一些擁有 GPIO 能力的引腳 (只有BIOS
固件才知道如何使用他們)。
GPIO 的實際功能因系統而異。通常用法有:
- 輸出值可寫 (高電平=1低電平=0)。一些晶片也有如何驅動這些值的選項,
例如只允許輸出一個值、支持「線與」及其他取值類似的模式(值得注意的是
「開漏」信號)
- 輸入值可讀(1、0)。一些晶片支持引腳在配置爲「輸出」時回讀,這對於類似
「線與」的情況(以支持雙向信號)是非常有用的。GPIO 控制器可能有輸入
去毛刺/消抖邏輯,這有時需要軟體控制。
- 輸入通常可作爲 IRQ 信號,一般是沿觸發,但有時是電平觸發。這樣的 IRQ
可能配置爲系統喚醒事件,以將系統從低功耗狀態下喚醒。
- 通常一個 GPIO 根據不同產品電路板的需求,可以配置爲輸入或輸出,也有僅
支持單向的。
- 大部分 GPIO 可以在持有自旋鎖時訪問,但是通常由串行總線擴展的 GPIO
不允許持有自旋鎖。但某些系統也支持這種類型。
對於給定的電路板,每個 GPIO 都用於某個特定的目的,如監控 MMC/SD 卡的
插入/移除、檢測卡的防寫狀態、驅動 LED、配置收發器、模擬串行總線、
復位硬體看門狗、感知開關狀態等等。
GPIO 公約
=========
注意,這個叫做「公約」,因爲這不是強制性的,不遵循這個公約是無傷大雅的,
因爲此時可移植性並不重要。GPIO 常用於板級特定的電路邏輯,甚至可能
隨著電路板的版本而改變,且不可能在不同走線的電路板上使用。僅有在少數
功能上才具有可移植性,其他功能是平台特定。這也是由於「膠合」的邏輯造成的。
此外,這不需要任何的執行框架,只是一個接口。某個平台可能通過一個簡單地
訪問晶片寄存器的內聯函數來實現它其他平台可能通過委託一系列不同的GPIO
控制器的抽象函數來實現它。(有一些可選的代碼能支持這種策略的實現,本文檔
後面會介紹,但作爲 GPIO 接口的客戶端驅動程序必須與它的實現無關。)
也就是說,如果在他們的平台上支持這個公約,驅動應儘可能的使用它。同時,平台
必須在 Kconfig 中選擇 ARCH_REQUIRE_GPIOLIB 或者 ARCH_WANT_OPTIONAL_GPIOLIB
選項。那些調用標準 GPIO 函數的驅動應該在 Kconfig 入口中聲明依賴GENERIC_GPIO。
當驅動包含文件:
#include <linux/gpio.h>
則 GPIO 函數是可用,無論是「真實代碼」還是經優化過的語句。如果你遵守
這個公約,當你的代碼完成後,對其他的開發者來說會更容易看懂和維護。
注意,這些操作包含所用平台的 I/O 屏障代碼,驅動無須顯式地調用他們。
標識 GPIO
---------
GPIO 是通過無符號整型來標識的,範圍是 0 到 MAX_INT。保留「負」數
用於其他目的,例如標識信號「在這個板子上不可用」或指示錯誤。未接觸底層
硬體的代碼會忽略這些整數。
平台會定義這些整數的用法,且通常使用 #define 來定義 GPIO這樣
板級特定的啓動代碼可以直接關聯相應的原理圖。相對來說,驅動應該僅使用
啓動代碼傳遞過來的 GPIO 編號,使用 platform_data 保存板級特定
引腳配置數據 (同時還有其他須要的板級特定數據),避免可能出現的問題。
例如一個平台使用編號 32-159 來標識 GPIO,而在另一個平台使用編號0-63
標識一組 GPIO 控制器,64-79標識另一類 GPIO 控制器,且在一個含有
FPGA 的特定板子上使用 80-95。編號不一定要連續,那些平台中,也可以
使用編號2000-2063來標識一個 I2C 接口的 GPIO 擴展器中的 GPIO。
如果你要初始化一個帶有無效 GPIO 編號的結構體,可以使用一些負編碼
(如"-EINVAL"),那將使其永遠不會是有效。來測試這樣一個結構體中的編號
是否關聯一個 GPIO你可使用以下斷言:
int gpio_is_valid(int number);
如果編號不存在,則請求和釋放 GPIO 的函數將拒絕執行相關操作(見下文)。
其他編號也可能被拒絕,比如一個編號可能存在,但暫時在給定的電路上不可用。
一個平台是否支持多個 GPIO 控制器爲平台特定的實現問題,就像是否可以
在 GPIO 編號空間中有「空洞」和是否可以在運行時添加新的控制器一樣。
這些問題會影響其他事情,包括相鄰的 GPIO 編號是否存在等。
使用 GPIO
---------
對於一個 GPIO系統應該做的第一件事情就是通過 gpio_request()
函數分配它,見下文。
接下來是設置I/O方向這通常是在板級啓動代碼中爲所使用的 GPIO 設置
platform_device 時完成。
/* 設置爲輸入或輸出, 返回 0 或負的錯誤代碼 */
int gpio_direction_input(unsigned gpio);
int gpio_direction_output(unsigned gpio, int value);
返回值爲零代表成功,否則返回一個負的錯誤代碼。這個返回值需要檢查,因爲
get/set(獲取/設置)函數調用沒法返回錯誤,且有可能是配置錯誤。通常,
你應該在進程上下文中調用這些函數。然而,對於自旋鎖安全的 GPIO在板子
啓動的早期、進程啓動前使用他們也是可以的。
對於作爲輸出的 GPIO爲其提供初始輸出值對於避免在系統啓動期間出現
信號毛刺是很有幫助的。
爲了與傳統的 GPIO 接口兼容, 在設置一個 GPIO 方向時,如果它還未被申請,
則隱含了申請那個 GPIO 的操作(見下文)。這種兼容性正在從可選的 gpiolib
框架中移除。
如果這個 GPIO 編碼不存在,或者特定的 GPIO 不能用於那種模式,則方向
設置可能失敗。依賴啓動固件來正確地設置方向通常是一個壞主意,因爲它可能
除了啓動Linux並沒有做更多的驗證工作。(同理, 板子的啓動代碼可能需要
將這個復用的引腳設置爲 GPIO並正確地配置上拉/下拉電阻。)
訪問自旋鎖安全的 GPIO
-------------------
大多數 GPIO 控制器可以通過內存讀/寫指令來訪問。這些指令不會休眠,可以
安全地在硬(非線程)中斷例程和類似的上下文中完成。
對於那些用 gpio_cansleep()測試總是返回失敗的 GPIO(見下文),使用
以下的函數訪問:
/* GPIO 輸入:返回零或非零 */
int gpio_get_value(unsigned gpio);
/* GPIO 輸出 */
void gpio_set_value(unsigned gpio, int value);
GPIO值是布爾值零表示低電平非零表示高電平。當讀取一個輸出引腳的值時
返回值應該是引腳上的值。這個值不總是和輸出值相符,因爲存在開漏輸出信號和
輸出延遲問題。
以上的 get/set 函數無錯誤返回值,因爲之前 gpio_direction_*()應已檢查過
其是否爲「無效GPIO」。此外還需要注意的是並不是所有平台都可以從輸出引腳
中讀取數據,對於不能讀取的引腳應總返回零。另外,對那些在原子上下文中無法
安全訪問的 GPIO (譯者註:因爲訪問可能導致休眠)使用這些函數是不合適的
(見下文)。
在 GPIO 編號(還有輸出、值)爲常數的情況下,鼓勵通過平台特定的實現來優化
這兩個函數來訪問 GPIO 值。這種情況(讀寫一個硬體寄存器)下只需要幾條指令
是很正常的,且無須自旋鎖。這種優化函數比起那些在子程序上花費許多指令的
函數可以使得模擬接口(譯者注:例如 GPIO 模擬 I2C、1-wire 或 SPI)的
應用(在空間和時間上都)更具效率。
訪問可能休眠的 GPIO
-----------------
某些 GPIO 控制器必須通過基於總線(如 I2C 或 SPI)的消息訪問。讀或寫這些
GPIO 值的命令需要等待其信息排到隊首才發送命令,再獲得其反饋。期間需要
休眠,這不能在 IRQ 例程(中斷上下文)中執行。
支持此類 GPIO 的平台通過以下函數返回非零值來區分出這種 GPIO。(此函數需要
一個之前通過 gpio_request 分配到的有效 GPIO 編號):
int gpio_cansleep(unsigned gpio);
爲了訪問這種 GPIO,內核定義了一套不同的函數:
/* GPIO 輸入:返回零或非零 ,可能會休眠 */
int gpio_get_value_cansleep(unsigned gpio);
/* GPIO 輸出,可能會休眠 */
void gpio_set_value_cansleep(unsigned gpio, int value);
訪問這樣的 GPIO 需要一個允許休眠的上下文,例如線程 IRQ 處理例程,並用以上的
訪問函數替換那些沒有 cansleep()後綴的自旋鎖安全訪問函數。
除了這些訪問函數可能休眠,且它們操作的 GPIO 不能在硬體 IRQ 處理例程中訪問的
事實,這些處理例程實際上和自旋鎖安全的函數是一樣的。
** 除此之外 ** 調用設置和配置此類 GPIO 的函數也必須在允許休眠的上下文中,
因爲它們可能也需要訪問 GPIO 控制器晶片: (這些設置函數通常在板級啓動代碼或者
驅動探測/斷開代碼中,所以這是一個容易滿足的約束條件。)
gpio_direction_input()
gpio_direction_output()
gpio_request()
## gpio_request_one()
## gpio_request_array()
## gpio_free_array()
gpio_free()
gpio_set_debounce()
聲明和釋放 GPIO
----------------------------
爲了有助於捕獲系統配置錯誤,定義了兩個函數。
/* 申請 GPIO, 返回 0 或負的錯誤代碼.
* 非空標籤可能有助於診斷.
*/
int gpio_request(unsigned gpio, const char *label);
/* 釋放之前聲明的 GPIO */
void gpio_free(unsigned gpio);
將無效的 GPIO 編碼傳遞給 gpio_request()會導致失敗,申請一個已使用這個
函數聲明過的 GPIO 也會失敗。gpio_request()的返回值必須檢查。你應該在
進程上下文中調用這些函數。然而,對於自旋鎖安全的 GPIO,在板子啓動的早期、
進入進程之前是可以申請的。
這個函數完成兩個基本的目標。一是標識那些實際上已作爲 GPIO 使用的信號線,
這樣便於更好地診斷;系統可能需要服務幾百個可用的 GPIO但是對於任何一個
給定的電路板通常只有一些被使用。另一個目的是捕獲衝突,查明錯誤:如兩個或
更多驅動錯誤地認爲他們已經獨占了某個信號線,或是錯誤地認爲移除一個管理著
某個已激活信號的驅動是安全的。也就是說,申請 GPIO 的作用類似一種鎖機制。
某些平台可能也使用 GPIO 作爲電源管理激活信號(例如通過關閉未使用晶片區和
簡單地關閉未使用時鐘)。
對於 GPIO 使用 pinctrl 子系統已知的引腳,子系統應該被告知其使用情況;
一個 gpiolib 驅動的 .request()操作應調用 pinctrl_gpio_request()
而 gpiolib 驅動的 .free()操作應調用 pinctrl_gpio_free()。pinctrl
子系統允許 pinctrl_gpio_request()在某個引腳或引腳組以復用形式「屬於」
一個設備時都成功返回。
任何須將 GPIO 信號導向適當引腳的引腳復用硬體的編程應該發生在 GPIO
驅動的 .direction_input()或 .direction_output()函數中,以及
任何輸出 GPIO 值的設置之後。這樣可使從引腳特殊功能到 GPIO 的轉換
不會在引腳產生毛刺波形。有時當用一個 GPIO 實現其信號驅動一個非 GPIO
硬體模塊的解決方案時,就需要這種機制。
某些平台允許部分或所有 GPIO 信號使用不同的引腳。類似的GPIO 或引腳的
其他方面也需要配置,如上拉/下拉。平台軟體應該在對這些 GPIO 調用
gpio_request()前將這類細節配置好,例如使用 pinctrl 子系統的映射表,
使得 GPIO 的用戶無須關注這些細節。
還有一個值得注意的是在釋放 GPIO 前,你必須停止使用它。
注意:申請一個 GPIO 並沒有以任何方式配置它,只不過標識那個 GPIO 處於使用
狀態。必須有另外的代碼來處理引腳配置(如控制 GPIO 使用的引腳、上拉/下拉)。
考慮到大多數情況下聲明 GPIO 之後就會立即配置它們,所以定義了以下三個輔助函數:
/* 申請一個 GPIO 信號, 同時通過特定的'flags'初始化配置,
* 其他和 gpio_request()的參數和返回值相同
*
*/
int gpio_request_one(unsigned gpio, unsigned long flags, const char *label);
/* 在單個函數中申請多個 GPIO
*/
int gpio_request_array(struct gpio *array, size_t num);
/* 在單個函數中釋放多個 GPIO
*/
void gpio_free_array(struct gpio *array, size_t num);
這裡 'flags' 當前定義可指定以下屬性:
* GPIOF_DIR_IN - 配置方向爲輸入
* GPIOF_DIR_OUT - 配置方向爲輸出
* GPIOF_INIT_LOW - 在作爲輸出時,初始值爲低電平
* GPIOF_INIT_HIGH - 在作爲輸出時,初始值爲高電平
* GPIOF_OPEN_DRAIN - gpio引腳爲開漏信號
* GPIOF_OPEN_SOURCE - gpio引腳爲源極開路信號
* GPIOF_EXPORT_DIR_FIXED - 將 gpio 導出到 sysfs並保持方向
* GPIOF_EXPORT_DIR_CHANGEABLE - 同樣是導出, 但允許改變方向
因爲 GPIOF_INIT_* 僅有在配置爲輸出的時候才存在,所以有效的組合爲:
* GPIOF_IN - 配置爲輸入
* GPIOF_OUT_INIT_LOW - 配置爲輸出,並初始化爲低電平
* GPIOF_OUT_INIT_HIGH - 配置爲輸出,並初始化爲高電平
當設置 flag 爲 GPIOF_OPEN_DRAIN 時,則假設引腳是開漏信號。這樣的引腳
將不會在輸出模式下置1。這樣的引腳需要連接上拉電阻。通過使能這個標誌gpio庫
將會在被要求輸出模式下置1時將引腳變爲輸入狀態來使引腳置高。引腳在輸出模式下
通過置0使其輸出低電平。
當設置 flag 爲 GPIOF_OPEN_SOURCE 時,則假設引腳爲源極開路信號。這樣的引腳
將不會在輸出模式下置0。這樣的引腳需要連接下拉電阻。通過使能這個標誌gpio庫
將會在被要求輸出模式下置0時將引腳變爲輸入狀態來使引腳置低。引腳在輸出模式下
通過置1使其輸出高電平。
將來這些標誌可能擴展到支持更多的屬性。
更進一步,爲了更簡單地聲明/釋放多個 GPIO,'struct gpio'被引進來封裝所有
這三個領域:
struct gpio {
unsigned gpio;
unsigned long flags;
const char *label;
};
一個典型的用例:
static struct gpio leds_gpios[] = {
{ 32, GPIOF_OUT_INIT_HIGH, "Power LED" }, /* 默認開啓 */
{ 33, GPIOF_OUT_INIT_LOW, "Green LED" }, /* 默認關閉 */
{ 34, GPIOF_OUT_INIT_LOW, "Red LED" }, /* 默認關閉 */
{ 35, GPIOF_OUT_INIT_LOW, "Blue LED" }, /* 默認關閉 */
{ ... },
};
err = gpio_request_one(31, GPIOF_IN, "Reset Button");
if (err)
...
err = gpio_request_array(leds_gpios, ARRAY_SIZE(leds_gpios));
if (err)
...
gpio_free_array(leds_gpios, ARRAY_SIZE(leds_gpios));
GPIO 映射到 IRQ
--------------------
GPIO 編號是無符號整數;IRQ 編號也是。這些構成了兩個邏輯上不同的命名空間
(GPIO 0 不一定使用 IRQ 0)。你可以通過以下函數在它們之間實現映射:
/* 映射 GPIO 編號到 IRQ 編號 */
int gpio_to_irq(unsigned gpio);
/* 映射 IRQ 編號到 GPIO 編號 (儘量避免使用) */
int irq_to_gpio(unsigned irq);
它們的返回值爲對應命名空間的相關編號,或是負的錯誤代碼(如果無法映射)。
(例如,某些 GPIO 無法做爲 IRQ 使用。)以下的編號錯誤是未經檢測的:使用一個
未通過 gpio_direction_input()配置爲輸入的 GPIO 編號,或者使用一個
並非來源於gpio_to_irq()的 IRQ 編號。
這兩個映射函數可能會在信號編號的加減計算過程上花些時間。它們不可休眠。
gpio_to_irq()返回的非錯誤值可以傳遞給 request_irq()或者 free_irq()。
它們通常通過板級特定的初始化代碼存放到平台設備的 IRQ 資源中。注意:IRQ
觸發選項是 IRQ 接口的一部分,如 IRQF_TRIGGER_FALLING系統喚醒能力
也是如此。
irq_to_gpio()返回的非錯誤值大多數通常可以被 gpio_get_value()所使用,
比如在 IRQ 是沿觸發時初始化或更新驅動狀態。注意某些平台不支持反映射,所以
你應該儘量避免使用它。
模擬開漏信號
----------------------------
有時在只有低電平信號作爲實際驅動結果(譯者注:多個輸出連接於一點,邏輯電平
結果爲所有輸出的邏輯與)的時候,共享的信號線需要使用「開漏」信號。(該術語
適用於 CMOS 管;而 TTL 用「集電極開路」。)一個上拉電阻使信號爲高電平。這
有時被稱爲「線與」。實際上,從負邏輯(低電平爲真)的角度來看,這是一個「線或」。
一個開漏信號的常見例子是共享的低電平使能 IRQ 信號線。此外,有時雙向數據總線
信號也使用漏極開路信號。
某些 GPIO 控制器直接支持開漏輸出,還有許多不支持。當你需要開漏信號,但
硬體又不直接支持的時候,一個常用的方法是用任何即可作輸入也可作輸出的 GPIO
引腳來模擬:
LOW: gpio_direction_output(gpio, 0) ... 這代碼驅動信號並覆蓋
上拉配置。
HIGH: gpio_direction_input(gpio) ... 這代碼關閉輸出,所以上拉電阻
(或其他的一些器件)控制了信號。
如果你將信號線「驅動」爲高電平,但是 gpio_get_value(gpio)報告了一個
低電平(在適當的上升時間後),你就可以知道是其他的一些組件將共享信號線拉低了。
這不一定是錯誤的。一個常見的例子就是 I2C 時鐘的延長:一個需要較慢時鐘的
從設備延遲 SCK 的上升沿,而 I2C 主設備相應地調整其信號傳輸速率。
這些公約忽略了什麼?
================
這些公約忽略的最大一件事就是引腳復用,因爲這屬於高度晶片特定的屬性且
沒有可移植性。某個平台可能不需要明確的復用信息;有的對於任意給定的引腳
可能只有兩個功能選項;有的可能每個引腳有八個功能選項;有的可能可以將
幾個引腳中的任何一個作爲給定的 GPIO。(是的,這些例子都來自於當前運行
Linux 的系統。)
在某些系統中,與引腳復用相關的是配置和使能集成的上、下拉模式。並不是所有
平台都支持這種模式,或者不會以相同的方式來支持這種模式;且任何給定的電路板
可能使用外置的上拉(或下拉)電阻,這時晶片上的就不應該使用。(當一個電路需要
5kOhm 的拉動電阻,晶片上的 100 kOhm 電阻就不能做到。)同樣的,驅動能力
(2 mA vs 20 mA)和電壓(1.8V vs 3.3V)是平台特定問題,就像模型一樣在
可配置引腳和 GPIO 之間(沒)有一一對應的關係。
還有其他一些系統特定的機制沒有在這裡指出,例如上述的輸入去毛刺和線與輸出
選項。硬體可能支持批量讀或寫 GPIO但是那一般是配置相關的對於處於同一
塊區(bank)的GPIO。(GPIO 通常以 16 或 32 個組成一個區塊,一個給定的
片上系統一般有幾個這樣的區塊。)某些系統可以通過輸出 GPIO 觸發 IRQ
或者從並非以 GPIO 管理的引腳取值。這些機制的相關代碼沒有必要具有可移植性。
當前,動態定義 GPIO 並不是標準的,例如作爲配置一個帶有某些 GPIO 擴展器的
附加電路板的副作用。
GPIO 實現者的框架 (可選)
=====================
前面提到了,有一個可選的實現框架,讓平台使用相同的編程接口,更加簡單地支持
不同種類的 GPIO 控制器。這個框架稱爲"gpiolib"。
作爲一個輔助調試功能,如果 debugfs 可用,就會有一個 /sys/kernel/debug/gpio
文件。通過這個框架,它可以列出所有註冊的控制器,以及當前正在使用中的 GPIO
的狀態。
控制器驅動: gpio_chip
-------------------
在框架中每個 GPIO 控制器都包裝爲一個 "struct gpio_chip",他包含了
該類型的每個控制器的常用信息:
- 設置 GPIO 方向的方法
- 用於訪問 GPIO 值的方法
- 告知調用其方法是否可能休眠的標誌
- 可選的 debugfs 信息導出方法 (顯示類似上拉配置一樣的額外狀態)
- 診斷標籤
也包含了來自 device.platform_data 的每個實例的數據:它第一個 GPIO 的
編號和它可用的 GPIO 的數量。
實現 gpio_chip 的代碼應支持多控制器實例,這可能使用驅動模型。那些代碼要
配置每個 gpio_chip並發起gpiochip_add()。卸載一個 GPIO 控制器很少見,
但在必要的時候可以使用 gpiochip_remove()。
大部分 gpio_chip 是一個實例特定結構體的一部分,而並不將 GPIO 接口單獨
暴露出來,比如編址、電源管理等。類似編解碼器這樣的晶片會有複雜的非 GPIO
狀態。
任何一個 debugfs 信息導出方法通常應該忽略還未申請作爲 GPIO 的信號線。
他們可以使用 gpiochip_is_requested()測試,當這個 GPIO 已經申請過了
就返回相關的標籤,否則返回 NULL。
平台支持
-------
爲了支持這個框架,一個平台的 Kconfig 文件將會 "select"(選擇)
ARCH_REQUIRE_GPIOLIB 或 ARCH_WANT_OPTIONAL_GPIOLIB並讓它的
<asm/gpio.h> 包含 <asm-generic/gpio.h>,同時定義三個方法:
gpio_get_value()、gpio_set_value()和 gpio_cansleep()。
它也應提供一個 ARCH_NR_GPIOS 的定義值,這樣可以更好地反映該平台 GPIO
的實際數量,節省靜態表的空間。(這個定義值應該包含片上系統內建 GPIO 和
GPIO 擴展器中的數據。)
ARCH_REQUIRE_GPIOLIB 意味著 gpiolib 核心在這個構架中將總是編譯進內核。
ARCH_WANT_OPTIONAL_GPIOLIB 意味著 gpiolib 核心默認關閉,且用戶可以
使能它,並將其編譯進內核(可選)。
如果這些選項都沒被選擇,該平台就不通過 GPIO-lib 支持 GPIO,且代碼不可以
被用戶使能。
以下這些方法的實現可以直接使用框架代碼,並總是通過 gpio_chip 調度:
#define gpio_get_value __gpio_get_value
#define gpio_set_value __gpio_set_value
#define gpio_cansleep __gpio_cansleep
這些定義可以用更理想的實現方法替代,那就是使用經過邏輯優化的內聯函數來訪問
基於特定片上系統的 GPIO。例如,若引用的 GPIO (寄存器位偏移)是常量「12」
讀取或設置它可能只需少則兩或三個指令,且不會休眠。當這樣的優化無法實現時,
那些函數必須使用框架提供的代碼,那就至少要幾十條指令才可以實現。對於用 GPIO
模擬的 I/O 接口, 如此精簡指令是很有意義的。
對於片上系統,平台特定代碼爲片上 GPIO 每個區(bank)定義並註冊 gpio_chip
實例。那些 GPIO 應該根據晶片廠商的文檔進行編碼/標籤,並直接和電路板原理圖
對應。他們應該開始於零並終止於平台特定的限制。這些 GPIO(代碼)通常從
arch_initcall()或者更早的地方集成進平台初始化代碼,使這些 GPIO 總是可用,
且他們通常可以作爲 IRQ 使用。
板級支持
-------
對於外部 GPIO 控制器(例如 I2C 或 SPI 擴展器、專用晶片、多功能器件、FPGA
或 CPLD),大多數常用板級特定代碼都可以註冊控制器設備,並保證他們的驅動知道
gpiochip_add()所使用的 GPIO 編號。他們的起始編號通常跟在平台特定的 GPIO
編號之後。
例如板級啓動代碼應該創建結構體指明晶片公開的 GPIO 範圍,並使用 platform_data
將其傳遞給每個 GPIO 擴展器晶片。然後晶片驅動中的 probe()例程可以將這個
數據傳遞給 gpiochip_add()。
初始化順序很重要。例如,如果一個設備依賴基於 I2C 的(擴展)GPIO那麼它的
probe()例程就應該在那個 GPIO 有效以後才可以被調用。這意味著設備應該在
GPIO 可以工作之後才可被註冊。解決這類依賴的的一種方法是讓這種 gpio_chip
控制器向板級特定代碼提供 setup()和 teardown()回調函數。一旦所有必須的
資源可用之後,這些板級特定的回調函數將會註冊設備,並可以在這些 GPIO 控制器
設備變成無效時移除它們。
用戶空間的 Sysfs 接口(可選)
========================
使用「gpiolib」實現框架的平台可以選擇配置一個 GPIO 的 sysfs 用戶接口。
這不同於 debugfs 接口,因爲它提供的是對 GPIO方向和值的控制而不只顯示
一個GPIO 的狀態摘要。此外,它可以出現在沒有調試支持的產品級系統中。
例如,通過適當的系統硬體文檔,用戶空間可以知道 GIOP #23 控制 Flash
存儲器的防寫(用於保護其中 Bootloader 分區)。產品的系統升級可能需要
臨時解除這個保護:首先導入一個 GPIO改變其輸出狀態然後在重新使能防寫
前升級代碼。通常情況下,GPIO #23 是不會被觸及的,並且內核也不需要知道他。
根據適當的硬體文檔,某些系統的用戶空間 GPIO 可以用於確定系統配置數據,
這些數據是標準內核不知道的。在某些任務中,簡單的用戶空間 GPIO 驅動可能是
系統真正需要的。
注意標準內核驅動中已經存在通用的「LED 和按鍵」GPIO 任務,分別是:
"leds-gpio" 和 "gpio_keys"。請使用這些來替代直接訪問 GPIO因爲集成在
內核框架中的這類驅動比你在用戶空間的代碼更好。
Sysfs 中的路徑
--------------
在/sys/class/gpio 中有 3 類入口:
- 用於在用戶空間控制 GPIO 的控制接口;
- GPIOs 本身;以及
- GPIO 控制器 ("gpio_chip" 實例)。
除了這些標準的文件,還包含「device」符號連結。
控制接口是只寫的:
/sys/class/gpio/
"export" ... 用戶空間可以通過寫其編號到這個文件,要求內核導出
一個 GPIO 的控制到用戶空間。
例如: 如果內核代碼沒有申請 GPIO #19,"echo 19 > export"
將會爲 GPIO #19 創建一個 "gpio19" 節點。
"unexport" ... 導出到用戶空間的逆操作。
例如: "echo 19 > unexport" 將會移除使用"export"文件導出的
"gpio19" 節點。
GPIO 信號的路徑類似 /sys/class/gpio/gpio42/ (對於 GPIO #42 來說)
並有如下的讀/寫屬性:
/sys/class/gpio/gpioN/
"direction" ... 讀取得到 "in" 或 "out"。這個值通常運行寫入。
寫入"out" 時,其引腳的默認輸出爲低電平。爲了確保無故障運行,
"low" 或 "high" 的電平值應該寫入 GPIO 的配置,作爲初始輸出值。
注意:如果內核不支持改變 GPIO 的方向,或者在導出時內核代碼沒有
明確允許用戶空間可以重新配置 GPIO 方向,那麼這個屬性將不存在。
"value" ... 讀取得到 0 (低電平) 或 1 (高電平)。如果 GPIO 配置爲
輸出,這個值允許寫操作。任何非零值都以高電平看待。
如果引腳可以配置爲中斷信號,且如果已經配置了產生中斷的模式
(見"edge"的描述),你可以對這個文件使用輪詢操作(poll(2))
且輪詢操作會在任何中斷觸發時返回。如果你使用輪詢操作(poll(2))
請在 events 中設置 POLLPRI 和 POLLERR。如果你使用輪詢操作
(select(2)),請在 exceptfds 設置你期望的文件描述符。在
輪詢操作(poll(2))返回之後,既可以通過 lseek(2)操作讀取
sysfs 文件的開始部分,也可以關閉這個文件並重新打開它來讀取數據。
"edge" ... 讀取得到「none」、「rising」、「falling」或者「both」。
將這些字符串寫入這個文件可以選擇沿觸發模式,會使得輪詢操作
(select(2))在"value"文件中返回。
這個文件僅有在這個引腳可以配置爲可產生中斷輸入引腳時,才存在。
"active_low" ... 讀取得到 0 (假) 或 1 (真)。寫入任何非零值可以
翻轉這個屬性的(讀寫)值。已存在或之後通過"edge"屬性設置了"rising"
和 "falling" 沿觸發模式的輪詢操作(poll(2))將會遵循這個設置。
GPIO 控制器的路徑類似 /sys/class/gpio/gpiochip42/ (對於從#42 GPIO
開始實現控制的控制器),並有著以下只讀屬性:
/sys/class/gpio/gpiochipN/
"base" ... 與以上的 N 相同,代表此晶片管理的第一個 GPIO 的編號
"label" ... 用於診斷 (並不總是只有唯一值)
"ngpio" ... 此控制器所管理的 GPIO 數量(而 GPIO 編號從 N 到
N + ngpio - 1)
大多數情況下,電路板的文檔應當標明每個 GPIO 的使用目的。但是那些編號並不總是
固定的,例如在擴展卡上的 GPIO會根據所使用的主板或所在堆疊架構中其他的板子而
有所不同。在這種情況下,你可能需要使用 gpiochip 節點(儘可能地結合電路圖)來
確定給定信號所用的 GPIO 編號。
從內核代碼中導出
-------------
內核代碼可以明確地管理那些已通過 gpio_request()申請的 GPIO 的導出:
/* 導出 GPIO 到用戶空間 */
int gpio_export(unsigned gpio, bool direction_may_change);
/* gpio_export()的逆操作 */
void gpio_unexport();
/* 創建一個 sysfs 連接到已導出的 GPIO 節點 */
int gpio_export_link(struct device *dev, const char *name,
unsigned gpio)
在一個內核驅動申請一個 GPIO 之後,它可以通過 gpio_export()使其在 sysfs
接口中可見。該驅動可以控制信號方向是否可修改。這有助於防止用戶空間代碼無意間
破壞重要的系統狀態。
這個明確的導出有助於(通過使某些實驗更容易來)調試,也可以提供一個始終存在的接口,
與文檔配合作爲板級支持包的一部分。
在 GPIO 被導出之後gpio_export_link()允許在 sysfs 文件系統的任何地方
創建一個到這個 GPIO sysfs 節點的符號連結。這樣驅動就可以通過一個描述性的
名字,在 sysfs 中他們所擁有的設備下提供一個(到這個 GPIO sysfs 節點的)接口。

View File

@ -0,0 +1,162 @@
.. SPDX-License-Identifier: GPL-2.0
.. raw:: latex
\renewcommand\thesection*
\renewcommand\thesubsection*
\kerneldocCJKon
.. _linux_doc_zh_tw:
繁體中文翻譯
============
.. note::
內核文檔繁體中文版的翻譯工作正在進行中。如果您願意並且有時間參與這項工
作,歡迎提交補丁給胡皓文 <src.res@email.cn>。
許可證文檔
----------
下面的文檔介紹了Linux內核原始碼的許可證GPLv2、如何在原始碼樹中正確標記
單個文件的許可證、以及指向完整許可證文本的連結。
TODOList:
* Documentation/translations/zh_TW/process/license-rules.rst
用戶文檔
--------
下面的手冊是爲內核用戶編寫的——即那些試圖讓它在給定系統上以最佳方式工作的
用戶。
.. toctree::
:maxdepth: 2
admin-guide/index
TODOList:
* kbuild/index
固件相關文檔
------------
下列文檔描述了內核需要的平台固件相關信息。
TODOList:
* firmware-guide/index
* devicetree/index
應用程式開發人員文檔
--------------------
用戶空間API手冊涵蓋了描述應用程式開發人員可見內核接口方面的文檔。
TODOlist:
* userspace-api/index
內核開發簡介
------------
這些手冊包含有關如何開發內核的整體信息。內核社區非常龐大,一年下來有數千名
開發人員做出貢獻。與任何大型社區一樣,知道如何完成任務將使得更改合併的過程
變得更加容易。
TODOList:
* process/index
* dev-tools/index
* doc-guide/index
* kernel-hacking/index
* trace/index
* maintainer/index
* fault-injection/index
* livepatch/index
* rust/index
內核API文檔
-----------
以下手冊從內核開發人員的角度詳細介紹了特定的內核子系統是如何工作的。這裡的
大部分信息都是直接從內核原始碼獲取的,並根據需要添加補充材料(或者至少是在
我們設法添加的時候——可能不是所有的都是有需要的)。
TODOList:
* driver-api/index
* core-api/index
* locking/index
* accounting/index
* block/index
* cdrom/index
* cpu-freq/index
* ide/index
* fb/index
* fpga/index
* hid/index
* i2c/index
* iio/index
* isdn/index
* infiniband/index
* leds/index
* netlabel/index
* networking/index
* pcmcia/index
* power/index
* target/index
* timers/index
* spi/index
* w1/index
* watchdog/index
* virt/index
* input/index
* hwmon/index
* gpu/index
* security/index
* sound/index
* crypto/index
* filesystems/index
* vm/index
* bpf/index
* usb/index
* PCI/index
* scsi/index
* misc-devices/index
* scheduler/index
* mhi/index
體系結構無關文檔
----------------
TODOList:
* asm-annotations
特定體系結構文檔
----------------
TODOList:
* arch
其他文檔
--------
有幾份未排序的文檔似乎不適合放在文檔的其他部分,或者可能需要進行一些調整和/或
轉換爲reStructureText格式也有可能太舊。
TODOList:
* staging/index
* watch_queue
目錄和表格
----------
* :ref:`genindex`

View File

@ -0,0 +1,68 @@
Chinese translated version of Documentation/driver-api/io_ordering.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.
Traditional Chinese maintainer: Hu Haowen <src.res@email.cn>
---------------------------------------------------------------------
Documentation/driver-api/io_ordering.rst 的繁體中文翻譯
如果想評論或更新本文的內容,請直接聯繫原文檔的維護者。如果你使用英文
交流有困難的話,也可以向繁體中文版維護者求助。如果本翻譯更新不及時或
者翻譯存在問題,請聯繫繁體中文版維護者。
繁體中文版維護者: 胡皓文 Hu Haowen <src.res@email.cn>
繁體中文版翻譯者: 胡皓文 Hu Haowen <src.res@email.cn>
繁體中文版校譯者: 胡皓文 Hu Haowen <src.res@email.cn>
以下爲正文
---------------------------------------------------------------------
在某些平台上所謂的內存映射I/O是弱順序。在這些平台上驅動開發者有責任
保證I/O內存映射地址的寫操作按程序圖意的順序達到設備。通常讀取一個「安全」
設備寄存器或橋寄存器觸發IO晶片清刷未處理的寫操作到達設備後才處理讀操作
而達到保證目的。驅動程序通常在spinlock保護的臨界區退出之前使用這種技術。
這也可以保證後面的寫操作只在前面的寫操作之後到達設備(這非常類似於內存
屏障操作mb()不過僅適用於I/O
假設一個設備驅動程的具體例子:
...
CPU A: spin_lock_irqsave(&dev_lock, flags)
CPU A: val = readl(my_status);
CPU A: ...
CPU A: writel(newval, ring_ptr);
CPU A: spin_unlock_irqrestore(&dev_lock, flags)
...
CPU B: spin_lock_irqsave(&dev_lock, flags)
CPU B: val = readl(my_status);
CPU B: ...
CPU B: writel(newval2, ring_ptr);
CPU B: spin_unlock_irqrestore(&dev_lock, flags)
...
上述例子中設備可能會先接收到newval2的值然後接收到newval的值問題就
發生了。不過很容易通過下面方法來修復:
...
CPU A: spin_lock_irqsave(&dev_lock, flags)
CPU A: val = readl(my_status);
CPU A: ...
CPU A: writel(newval, ring_ptr);
CPU A: (void)readl(safe_register); /* 配置寄存器?*/
CPU A: spin_unlock_irqrestore(&dev_lock, flags)
...
CPU B: spin_lock_irqsave(&dev_lock, flags)
CPU B: val = readl(my_status);
CPU B: ...
CPU B: writel(newval2, ring_ptr);
CPU B: (void)readl(safe_register); /* 配置寄存器?*/
CPU B: spin_unlock_irqrestore(&dev_lock, flags)
在解決方案中讀取safe_register寄存器觸發IO晶片清刷未處理的寫操作
再處理後面的讀操作,防止引發數據不一致問題。

View File

@ -0,0 +1,212 @@
Chinese translated version of Documentation/admin-guide/bug-hunting.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.
Traditional Chinese maintainer: Hu Haowen <src.res@email.cn>
---------------------------------------------------------------------
Documentation/admin-guide/bug-hunting.rst 的繁體中文版翻譯
如果想評論或更新本文的內容,請直接聯繫原文檔的維護者。如果你使用英文
交流有困難的話,也可以向繁體中文版維護者求助。如果本翻譯更新不及時或
者翻譯存在問題,請聯繫繁體中文版維護者。
繁體中文版維護者: 胡皓文 Hu Haowen <src.res@email.cn>
繁體中文版翻譯者: 胡皓文 Hu Haowen <src.res@email.cn>
繁體中文版校譯者: 胡皓文 Hu Haowen <src.res@email.cn>
以下爲正文
---------------------------------------------------------------------
注意: ksymoops 在2.6中是沒有用的。 請以原有格式使用Oops(來自dmesg等等)。
忽略任何這樣那樣關於「解碼Oops」或者「通過ksymoops運行」的文檔。 如果你貼出運行過
ksymoops的來自2.6的Oops人們只會讓你重貼一次。
快速總結
-------------
發現Oops並發送給看似相關的內核領域的維護者。別太擔心對不上號。如果你不確定就發給
和你所做的事情相關的代碼的負責人。 如果可重現試著描述怎樣重構。 那甚至比oops更有
價值。
如果你對於發送給誰一無所知, 發給linux-kernel@vger.kernel.org。感謝你幫助Linux
儘可能地穩定。
Oops在哪裡?
----------------------
通常Oops文本由klogd從內核緩衝區里讀取並傳給syslogd由syslogd寫到syslog文件中
典型地是/var/log/messages(依賴於/etc/syslog.conf)。有時klogd崩潰了,這種情況下你
能夠運行dmesg > file來從內核緩衝區中讀取數據並保存下來。 否則你可以
cat /proc/kmsg > file 然而你必須介入中止傳輸, kmsg是一個「永不結束的文件」。如
果機器崩潰壞到你不能輸入命令或者磁碟不可用那麼你有三種選擇:-
1 手抄屏幕上的文本待機器重啓後再輸入計算機。 麻煩但如果沒有針對崩潰的準備,
這是僅有的選擇。 另外,你可以用數位相機把屏幕拍下來-不太好,但比沒有強。 如果信
息滾動到了終端的上面你會發現以高分辯率啓動比如vga=791會讓你讀到更多的文
本。注意這需要vesafb所以對『早期』的oops沒有幫助
2用串口終端啓動請參看Documentation/admin-guide/serial-console.rst運行一個null
modem到另一台機器並用你喜歡的通訊工具獲取輸出。Minicom工作地很好。
3使用Kdump請參看Documentation/admin-guide/kdump/kdump.rst
使用在Documentation/admin-guide/kdump/gdbmacros.txt中定義的dmesg gdb宏從舊的內存中提取內核
環形緩衝區。
完整信息
----------------
注意以下來自於Linus的郵件適用於2.4內核。 我因爲歷史原因保留了它,並且因爲其中
一些信息仍然適用。 特別注意的是請忽略任何ksymoops的引用。
From: Linus Torvalds <torvalds@osdl.org>
怎樣跟蹤Oops.. [原發到linux-kernel的一封郵件]
主要的竅門是有五年和這些煩人的oops消息打交道的經驗;-)
實際上,你有辦法使它更簡單。我有兩個不同的方法:
gdb /usr/src/linux/vmlinux
gdb> disassemble <offending_function>
那是發現問題的簡單辦法至少如果bug報告做的好的情況下象這個一樣-運行ksymoops
得到oops發生的函數及函數內的偏移
哦,如果報告發生的內核以相同的編譯器和相似的配置編譯它會有幫助的。
另一件要做的事是反彙編bug報告的「Code」部分ksymoops也會用正確的工具來做這件事
但如果沒有那些工具你可以寫一個傻程序:
char str[] = "\xXX\xXX\xXX...";
main(){}
並用gcc -g編譯它然後執行「disassemble str」XX部分是由Oops報告的值-你可以僅剪切
粘貼並用「\x」替換空格-我就是這麼做的,因爲我懶得寫程序自動做這一切)。
另外你可以用scripts/decodecode這個shell腳本。它的使用方法是
decodecode < oops.txt
「Code」之後的十六進位字節可能在某些架構上有一些當前指令之前的指令字節以及
當前和之後的指令字節
Code: f9 0f 8d f9 00 00 00 8d 42 0c e8 dd 26 11 c7 a1 60 ea 2b f9 8b 50 08 a1
64 ea 2b f9 8d 34 82 8b 1e 85 db 74 6d 8b 15 60 ea 2b f9 <8b> 43 04 39 42 54
7e 04 40 89 42 54 8b 43 04 3b 05 00 f6 52 c0
最後,如果你想知道代碼來自哪裡,你可以:
cd /usr/src/linux
make fs/buffer.s # 或任何產生BUG的文件
然後你會比gdb反彙編更清楚的知道發生了什麼。
現在問題是把你所擁有的所有數據結合起來C源碼關於它應該怎樣的一般知識
彙編代碼及其反彙編得到的代碼另外還有從「oops」消息得到的寄存器狀態-對了解毀壞的
指針有用而且當你有了彙編代碼你也能拿其它的寄存器和任何它們對應的C表達式做匹配
)。
實際上你僅需看看哪裡不匹配這個例子是「Code」反彙編和編譯器生成的代碼不匹配
然後你須要找出爲什麼不匹配。通常很簡單-你看到代碼使用了空指針然後你看代碼想知道
空指針是怎麼出現的,還有檢查它是否合法..
現在,如果明白這是一項耗時的工作而且需要一丁點兒的專心,沒錯。這就是我爲什麼大多
只是忽略那些沒有符號表信息的崩潰報告的原因:簡單的說太難查找了(我有一些
程序用於在內核代碼段中搜索特定的模式,而且有時我也已經能找出那些崩潰的地方,但是
僅僅是找出正確的序列也確實需要相當紮實的內核知識)
_有時_會發生這種情況我僅看到崩潰中的反彙編代碼序列 然後我馬上就明白問題出在
哪裡。這時我才意識到自己幹這個工作已經太長時間了;-)
Linus
---------------------------------------------------------------------------
關於Oops跟蹤的註解
爲了幫助Linus和其它內核開發者klogd納入了大量的支持來處理保護錯誤。爲了擁有對
地址解析的完整支持至少應該使用1.3-pl3的sysklogd包。
當保護錯誤發生時klogd守護進程自動把內核日誌信息中的重要地址翻譯成它們相應的符
號。
klogd執行兩種類型的地址解析。首先是靜態翻譯其次是動態翻譯。靜態翻譯和ksymoops
一樣使用System.map文件。爲了做靜態翻譯klogd守護進程必須在初始化時能找到system
map文件。關於klogd怎樣搜索map文件請參看klogd手冊頁。
動態地址翻譯在使用內核可裝載模塊時很重要。 因爲內核模塊的內存是從內核動態內存池
里分配的,所以不管是模塊開始位置還是模塊中函數和符號的位置都不是固定的。
內核支持允許程序決定裝載哪些模塊和它們在內存中位置的系統調用。使用這些系統調用
klogd守護進程生成一張符號表用於調試發生在可裝載模塊中的保護錯誤。
至少klogd會提供產生保護錯誤的模塊名。還可有額外的符號信息供可裝載模塊開發者選擇
以從模塊中輸出符號信息。
因爲內核模塊環境可能是動態的所以必須有一種機制當模塊環境發生改變時來通知klogd
守護進程。 有一些可用的命令行選項允許klogd向當前執行中的守護進程發送信號告知符
號信息應該被刷新了。 更多信息請參看klogd手冊頁。
sysklogd發布時包含一個補丁修改了modules-2.0.0包,無論何時一個模塊裝載或者卸載都
會自動向klogd發送信號。打上這個補丁提供了必要的對調試發生於內核可裝載模塊的保護
錯誤的無縫支持。
以下是被klogd處理過的發生在可裝載模塊中的一個保護錯誤例子
---------------------------------------------------------------------------
Aug 29 09:51:01 blizard kernel: Unable to handle kernel paging request at virtual address f15e97cc
Aug 29 09:51:01 blizard kernel: current->tss.cr3 = 0062d000, %cr3 = 0062d000
Aug 29 09:51:01 blizard kernel: *pde = 00000000
Aug 29 09:51:01 blizard kernel: Oops: 0002
Aug 29 09:51:01 blizard kernel: CPU: 0
Aug 29 09:51:01 blizard kernel: EIP: 0010:[oops:_oops+16/3868]
Aug 29 09:51:01 blizard kernel: EFLAGS: 00010212
Aug 29 09:51:01 blizard kernel: eax: 315e97cc ebx: 003a6f80 ecx: 001be77b edx: 00237c0c
Aug 29 09:51:01 blizard kernel: esi: 00000000 edi: bffffdb3 ebp: 00589f90 esp: 00589f8c
Aug 29 09:51:01 blizard kernel: ds: 0018 es: 0018 fs: 002b gs: 002b ss: 0018
Aug 29 09:51:01 blizard kernel: Process oops_test (pid: 3374, process nr: 21, stackpage=00589000)
Aug 29 09:51:01 blizard kernel: Stack: 315e97cc 00589f98 0100b0b4 bffffed4 0012e38e 00240c64 003a6f80 00000001
Aug 29 09:51:01 blizard kernel: 00000000 00237810 bfffff00 0010a7fa 00000003 00000001 00000000 bfffff00
Aug 29 09:51:01 blizard kernel: bffffdb3 bffffed4 ffffffda 0000002b 0007002b 0000002b 0000002b 00000036
Aug 29 09:51:01 blizard kernel: Call Trace: [oops:_oops_ioctl+48/80] [_sys_ioctl+254/272] [_system_call+82/128]
Aug 29 09:51:01 blizard kernel: Code: c7 00 05 00 00 00 eb 08 90 90 90 90 90 90 90 90 89 ec 5d c3
---------------------------------------------------------------------------
Dr. G.W. Wettstein Oncology Research Div. Computing Facility
Roger Maris Cancer Center INTERNET: greg@wind.rmcc.com
820 4th St. N.
Fargo, ND 58122
Phone: 701-234-7556
---------------------------------------------------------------------------
受汙染的內核
一些oops報告在程序記數器之後包含字符串'Tainted: '。這表明內核已經被一些東西給汙
染了。 該字符串之後緊跟著一系列的位置敏感的字符,每個代表一個特定的汙染值。
1'G'如果所有裝載的模塊都有GPL或相容的許可證'P'如果裝載了任何的專有模塊。
沒有模塊MODULE_LICENSE或者帶有insmod認爲是與GPL不相容的的MODULE_LICENSE的模塊被
認定是專有的。
2'F'如果有任何通過「insmod -f」被強制裝載的模塊' '如果所有模塊都被正常裝載。
3'S'如果oops發生在SMP內核中運行於沒有證明安全運行多處理器的硬體。 當前這種
情況僅限於幾種不支持SMP的速龍處理器。
4'R'如果模塊通過「insmod -f」被強制裝載' '如果所有模塊都被正常裝載。
5'M'如果任何處理器報告了機器檢查異常,' '如果沒有發生機器檢查異常。
6'B'如果頁釋放函數發現了一個錯誤的頁引用或者一些非預期的頁標誌。
7'U'如果用戶或者用戶應用程式特別請求設置汙染標誌,否則' '。
8'D'如果內核剛剛死掉比如有OOPS或者BUG。
使用'Tainted: '字符串的主要原因是要告訴內核調試者,這是否是一個乾淨的內核亦或發
生了任何的不正常的事。汙染是永久的:即使出錯的模塊已經被卸載了,汙染值仍然存在,
以表明內核不再值得信任。

View File

@ -0,0 +1,91 @@
Chinese translated version of Documentation/dev-tools/sparse.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.
Traditional Chinese maintainer: Hu Haowen <src.res@email.cn>
---------------------------------------------------------------------
Documentation/dev-tools/sparse.rst 的繁體中文翻譯
如果想評論或更新本文的內容,請直接聯繫原文檔的維護者。如果你使用英文
交流有困難的話,也可以向繁體中文版維護者求助。如果本翻譯更新不及時或
者翻譯存在問題,請聯繫繁體中文版維護者。
繁體中文版維護者: 胡皓文 Hu Haowen <src.res@email.cn>
繁體中文版翻譯者: 胡皓文 Hu Haowen <src.res@email.cn>
以下爲正文
---------------------------------------------------------------------
Copyright 2004 Linus Torvalds
Copyright 2004 Pavel Machek <pavel@ucw.cz>
Copyright 2006 Bob Copeland <me@bobcopeland.com>
使用 sparse 工具做類型檢查
~~~~~~~~~~~~~~~~~~~~~~~~~~
"__bitwise" 是一種類型屬性,所以你應該這樣使用它:
typedef int __bitwise pm_request_t;
enum pm_request {
PM_SUSPEND = (__force pm_request_t) 1,
PM_RESUME = (__force pm_request_t) 2
};
這樣會使 PM_SUSPEND 和 PM_RESUME 成爲位方式(bitwise)整數(使用"__force"
是因爲 sparse 會抱怨改變位方式的類型轉換,但是這裡我們確實需要強制進行轉
換)。而且因爲所有枚舉值都使用了相同的類型,這裡的"enum pm_request"也將
會使用那個類型做爲底層實現。
而且使用 gcc 編譯的時候,所有的 __bitwise/__force 都會消失,最後在 gcc
看來它們只不過是普通的整數。
坦白來說,你並不需要使用枚舉類型。上面那些實際都可以濃縮成一個特殊的"int
__bitwise"類型。
所以更簡單的辦法只要這樣做:
typedef int __bitwise pm_request_t;
#define PM_SUSPEND ((__force pm_request_t) 1)
#define PM_RESUME ((__force pm_request_t) 2)
現在你就有了嚴格的類型檢查所需要的所有基礎架構。
一個小提醒:常數整數"0"是特殊的。你可以直接把常數零當作位方式整數使用而
不用擔心 sparse 會抱怨。這是因爲"bitwise"(恰如其名)是用來確保不同位方
式類型不會被弄混小尾模式大尾模式cpu尾模式或者其他對他們來說
常數"0"確實是特殊的。
獲取 sparse 工具
~~~~~~~~~~~~~~~~
你可以從 Sparse 的主頁獲取最新的發布版本:
http://www.kernel.org/pub/linux/kernel/people/josh/sparse/
或者,你也可以使用 git 克隆最新的 sparse 開發版本:
git://git.kernel.org/pub/scm/linux/kernel/git/josh/sparse.git
一旦你下載了源碼,只要以普通用戶身份運行:
make
make install
它將會被自動安裝到你的 ~/bin 目錄下。
使用 sparse 工具
~~~~~~~~~~~~~~~~
用"make C=1"命令來編譯內核,會對所有重新編譯的 C 文件使用 sparse 工具。
或者使用"make C=2"命令,無論文件是否被重新編譯都會對其使用 sparse 工具。
如果你已經編譯了內核,用後一種方式可以很快地檢查整個源碼樹。
make 的可選變量 CHECKFLAGS 可以用來向 sparse 工具傳遞參數。編譯系統會自
動向 sparse 工具傳遞 -Wbitwise 參數。