你知道kernel version的实现原理和细节吗
引言
kernel 啟動(dòng)時(shí)通常會(huì)看到下面第二行信息的內(nèi)容,它們代表了當(dāng)前 kernel 的版本、編譯工具版本、編譯環(huán)境等信息。
Booting?Linux?on?physical?CPU?0x0 Linux?version?5.4.124+?(funny@funny)?(gcc?version?6.5.0?(Linaro?GCC?6.5-2018.12))?#30?SMP?Sat?Sep?11?11:10:28?CST?2021 ......要知道,系統(tǒng)啟動(dòng)過(guò)程中的任何一條打印信息,都是經(jīng)過(guò)了無(wú)數(shù)次討論和驗(yàn)證才呈現(xiàn)在大家的面前??此茻o(wú)關(guān)緊要的一條信息,但背后卻隱藏著非常有趣的故事。
為什么要打印version信息
當(dāng)系統(tǒng)啟動(dòng)之后有很多種方式能夠確定內(nèi)核版本號(hào)信息,在嵌入式或安卓 kernel 系統(tǒng)下,查看版本信息:
uname
proc/version
在發(fā)行版 linux 系統(tǒng)環(huán)境下,還可以用下面的命令查看版本信息:
hostnamectl
lsb_release
以上方法都是系統(tǒng)啟動(dòng)正常、加載完文件系統(tǒng)之后使用的。
那么,系統(tǒng)啟動(dòng)過(guò)程中是否有必要打印內(nèi)核版本信息呢?答案是完全有必要。
例如下面列出的幾種應(yīng)用場(chǎng)景:
SoC 芯片的 kernel 適配
可裝載驅(qū)動(dòng)程序調(diào)試
多分支內(nèi)核版本加載
內(nèi)核偽裝
kernel version實(shí)現(xiàn)原理
kernel version這條打印信息來(lái)源于start_kernl()中的linux_banner字符串。
asmlinkage?__visible?void?__init?start_kernel(void) { ...boot_cpu_init();page_address_init();pr_notice("%s",?linux_banner); ...這里的banner好比是ubuntu系統(tǒng)里的ssh登錄橫幅一樣,呈現(xiàn)了系統(tǒng)的一些基本信息。
Welcome?to?Ubuntu?16.04.7?LTS?(GNU/Linux?4.15.0-142-generic?x86_64)*?Documentation:??https://help.ubuntu.com*?Management:?????https://landscape.canonical.com*?Support:????????https://ubuntu.com/advantage*?Super-optimized?for?small?spaces?-?read?how?we?shrank?the?memoryfootprint?of?MicroK8s?to?make?it?the?smallest?full?K8s?around.https://ubuntu.com/blog/microk8s-memory-optimisation ...banner字符串的定義位于init/version.c中,注意,它是一個(gè)只讀字符串,不要去修改它。
const?char?linux_banner[]?="Linux?version?"?UTS_RELEASE?"?("?LINUX_COMPILE_BY?"@"LINUX_COMPILE_HOST?")?("?LINUX_COMPILER?")?"?UTS_VERSION?"\n";由以下幾部分組成:
UTS_RELEASE
對(duì)應(yīng)"5.4.124+"LINUX_COMPILE_BY
對(duì)應(yīng)"funny",我的編譯機(jī)funnyLINUX_COMPILE_HOST
對(duì)應(yīng)"funny",我的編譯機(jī)Host是funnyLINUX_COMPILER
對(duì)應(yīng)"gcc version 6.5.0 (Linaro GCC 6.5-2018.12"UTS_VERSION
對(duì)應(yīng)"#30 SMP Sat Sep 11 11:10:28 CST 2021"
UTS:Unix Time Stamp,從這個(gè)名字可以看出linux中的UNIX印記。
接下來(lái)對(duì)這些字符串逐條進(jìn)行解析
上面這些宏的第一級(jí)定義位于./scripts/mkcompile_h文件中。
{?echo?/\*?This?file?is?auto?generated,?version?$VERSION?\*/if?[?-n?"$CONFIG_FLAGS"?]?;?then?echo?"/*?$CONFIG_FLAGS?*/";?fiecho?\#define?UTS_MACHINE?\"$ARCH\"echo?\#define?UTS_VERSION?\"`echo?$UTS_VERSION?|?$UTS_TRUNCATE`\"echo?\#define?LINUX_COMPILE_BY?\"`echo?$LINUX_COMPILE_BY?|?$UTS_TRUNCATE`\"echo?\#define?LINUX_COMPILE_HOST?\"`echo?$LINUX_COMPILE_HOST?|?$UTS_TRUNCATE`\"echo?\#define?LINUX_COMPILER?\"`$CC?-v?2>&1?|?grep?'?version?'?|?sed?'s/[[:space:]]*$//'`\" }?>?.tmpcompileUTS_VERSION
UTS_VERSION="#$VERSION" CONFIG_FLAGS="" if?[?-n?"$SMP"?]?;?then?CONFIG_FLAGS="SMP";?fi if?[?-n?"$PREEMPT"?]?;?then?CONFIG_FLAGS="$CONFIG_FLAGS?PREEMPT";?fi if?[?-n?"$PREEMPT_RT"?]?;?then?CONFIG_FLAGS="$CONFIG_FLAGS?PREEMPT_RT";?fi UTS_VERSION="$UTS_VERSION?$CONFIG_FLAGS?$TIMESTAMP"LINUX_COMPILE_BY
LINUX_COMPILE_HOST
LINUX_COMPILER
UTS_RELEASE --- 重點(diǎn)分析這個(gè)宏的來(lái)源
這是一個(gè)在kernel頂層Makefile中定義的一個(gè)宏,如下:
提高make的打印等級(jí)可以看到,上面的腳本內(nèi)容經(jīng)過(guò)翻譯之后如下:
if?[?`echo?-n?"5.4.124+"?|?wc?-c?`?-gt?64?];?then?echo?'"5.4.124+"?exceeds?64?characters'?>&2;?exit?1;?fi;?echo?\#define?UTS_RELEASE?\"5.4.124+\";?}現(xiàn)在可以確定KERNELRELEASE就是從kernel.release文件中獲取到的。打開kernel.release確認(rèn)一下:
其中KERNELRELEASE對(duì)應(yīng)5.4.124+。
KERNELRELEASE又是怎么來(lái)的呢?
KERNELRELEASE同樣也是在Makefile中定義的、自動(dòng)生成的字符串,它可以在多個(gè)地方被修改。在Makefile中查找KERNELRELEASE字符串,看見(jiàn)它是由下面這條命令生成的。
這條命令里的2>/dev/null的含義是:若cat失敗即沒(méi)有取到文件內(nèi)容,那么將錯(cuò)誤信息輸出到黑洞文件。
通過(guò)下面命令驗(yàn)證:
一切準(zhǔn)備就緒之后,通過(guò)下面的代碼將UTS_RELEASE更新到utsrelease.h中。
1195?include/generated/utsrelease.h:?include/config/kernel.release?FORCE 1196?????????$(call?filechk,utsrelease.h)其中filechk的定義位于scripts/Kbuild.include
define?filechk$(Q)set?-e;?????????????????????????????????????????????\mkdir?-p?$(dir?$@);?????????????????????????????????????\trap?"rm?-f?$(dot-target).tmp"?EXIT;????????????????????\{?$(filechk_$(1));?}?>?$(dot-target).tmp;???????????????\if?[?!?-r?$@?]?||?!?cmp?-s?$@?$(dot-target).tmp;?then???\$(kecho)?'??UPD?????$@';????????????????????????\mv?-f?$(dot-target).tmp?$@;?????????????????????\fi endef而utsrelease.h中內(nèi)容如下:
linux$?cat?./obj/include/generated/utsrelease.h #define?UTS_RELEASE?"5.4.124+" linux$這就是我們內(nèi)核啟動(dòng)過(guò)程中打印出來(lái)的kernel version信息。
推薦閱讀:
專輯|Linux文章匯總
專輯|程序人生
專輯|C語(yǔ)言
我的知識(shí)小密圈
關(guān)注公眾號(hào),后臺(tái)回復(fù)「1024」獲取學(xué)習(xí)資料網(wǎng)盤鏈接。
歡迎點(diǎn)贊,關(guān)注,轉(zhuǎn)發(fā),在看,您的每一次鼓勵(lì),我都將銘記于心~
嵌入式Linux
微信掃描二維碼,關(guān)注我的公眾號(hào)
總結(jié)
以上是生活随笔為你收集整理的你知道kernel version的实现原理和细节吗的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: python 导入数据集并画图_pyth
- 下一篇: 二叉树的非递归遍历算法