0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

你知道kernel version的實(shí)現(xiàn)原理和細(xì)節(jié)嗎?

冬至子 ? 來源:Linux與SoC ? 作者:Linux與SoC ? 2023-06-05 14:59 ? 次閱讀

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)過程中的任何一條打印信息,都是經(jīng)過了無數(shù)次討論和驗(yàn)證才呈現(xiàn)在大家的面前??此茻o關(guān)緊要的一條信息,但背后卻隱藏著非常有趣的故事。

為什么要打印version信息

當(dāng)系統(tǒng)啟動(dòng)之后有很多種方式能夠確定內(nèi)核版本號(hào)信息,在嵌入式或安卓 kernel 系統(tǒng)下,查看版本信息:

  • uname
[root@cpu ]# uname -a
Linux cpu 5.4.124+ #30 SMP Sat Sep 11 11:10:28 CST 2021 armv7l GNU/Linux
[root@cpu ]#
  • proc/version
[root@cpu ]# cat /proc/version
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
[root@cpu ]#

在發(fā)行版 linux 系統(tǒng)環(huán)境下,還可以用下面的命令查看版本信息:

  • hostnamectl
funny@funny:~$ hostnamectl
   Static hostname: funny
         Icon name: computer-vm
           Chassis: vm
  ...
    Virtualization: vmware
  Operating System: Ubuntu 16.04.7 LTS
            Kernel: Linux 4.15.0-142-generic
      Architecture: x86-64
funny@funny:~$
  • lsb_release
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 16.04.7 LTS
Release:        16.04
Codename:       xenial

以上方法都是系統(tǒng)啟動(dòng)正常、加載完文件系統(tǒng)之后使用的。

那么,系統(tǒng)啟動(dòng)過程中是否有必要打印內(nèi)核版本信息呢?答案是完全有必要。

例如下面列出的幾種應(yīng)用場(chǎng)景:

  1. SoC 芯片的 kernel 適配
  2. 可裝載驅(qū)動(dòng)程序調(diào)試
  3. 多分支內(nèi)核版本加載
  4. 內(nèi)核偽裝

kernel version實(shí)現(xiàn)原理

kernel version這條打印信息來源于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 memory
   footprint 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ī)funny

  • LINUX_COMPILE_HOST

    對(duì)應(yīng)"funny",我的編譯機(jī)Host是funny

  • LINUX_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印記。

接下來對(duì)這些字符串逐條進(jìn)行解析

上面這些宏的第一級(jí)定義位于./scripts/mkcompile_h文件中。

{ echo /\\* This file is auto generated, version $VERSION \\*/
  if [ -n "$CONFIG_FLAGS" ] ; then echo "/* $CONFIG_FLAGS */"; fi

  echo \\#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:]]*$//'`\"
} > .tmpcompile

UTS_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

if test -z "$KBUILD_BUILD_USER"; then
         LINUX_COMPILE_BY=$(whoami | sed 's/\\\\/\\\\\\\\/')
 else
         LINUX_COMPILE_BY=$KBUILD_BUILD_USER
 fi
 if test -z "$KBUILD_BUILD_HOST"; then
         LINUX_COMPILE_HOST=`hostname`
 else
         LINUX_COMPILE_HOST=$KBUILD_BUILD_HOST
 fi

UTS_RELEASE --- 重點(diǎn)分析這個(gè)宏的來源

這是一個(gè)在kernel頂層Makefile中定義的一個(gè)宏,如下:

uts_len := 64
define filechk_utsrelease.h
        if [ `echo -n "$(KERNELRELEASE)" | wc -c ` -gt $(uts_len) ]; then \\
          echo '"$(KERNELRELEASE)" exceeds $(uts_len) characters' >&2;    \\
          exit 1;                                                         \\
        fi;                                                               \\
        echo \\#define UTS_RELEASE \"$(KERNELRELEASE)\"
endef

提高make的打印等級(jí)可以看到,上面的腳本內(nèi)容經(jīng)過翻譯之后如下:

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又是怎么來的呢?

KERNELRELEASE同樣也是在Makefile中定義的、自動(dòng)生成的字符串,它可以在多個(gè)地方被修改。在Makefile中查找KERNELRELEASE字符串,看見它是由下面這條命令生成的。

KERNELRELEASE = $(shell cat include/config/kernel.release 2 > /dev/null)

這條命令里的2>/dev/null的含義是:若cat失敗即沒有取到文件內(nèi)容,那么將錯(cuò)誤信息輸出到黑洞文件。

通過下面命令驗(yàn)證:

funny@funny:~$ cat funny.txt
funny? yeah
funny@funny:~$ B=$(cat funny.txt 2 > /dev/null)
funny@funny:~$ echo $B
funny? yeah
funny@funny:~$

一切準(zhǔn)備就緒之后,通過下面的代碼將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)過程中打印出來的kernel version信息。

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 嵌入式系統(tǒng)
    +關(guān)注

    關(guān)注

    41

    文章

    3532

    瀏覽量

    128989
  • Linux系統(tǒng)
    +關(guān)注

    關(guān)注

    4

    文章

    588

    瀏覽量

    27267
  • SoC芯片
    +關(guān)注

    關(guān)注

    1

    文章

    592

    瀏覽量

    34804
  • 驅(qū)動(dòng)程序
    +關(guān)注

    關(guān)注

    19

    文章

    814

    瀏覽量

    47867
  • LSB算法
    +關(guān)注

    關(guān)注

    0

    文章

    7

    瀏覽量

    5797
收藏 人收藏

    評(píng)論

    相關(guān)推薦

    【電磁兼容標(biāo)準(zhǔn)解析分享】汽車電子零部件EMC標(biāo)準(zhǔn)解析---應(yīng)該了解和知道細(xì)節(jié)(二)

    【電磁兼容標(biāo)準(zhǔn)解析分享】汽車電子零部件EMC標(biāo)準(zhǔn)解析---應(yīng)該了解和知道細(xì)節(jié)(二)
    的頭像 發(fā)表于 08-08 08:17 ?3423次閱讀
    【電磁兼容標(biāo)準(zhǔn)解析分享】汽車電子零部件EMC標(biāo)準(zhǔn)解析---<b class='flag-5'>你</b>應(yīng)該了解和<b class='flag-5'>知道</b>的<b class='flag-5'>細(xì)節(jié)</b>(二)

    編譯自己的Linux內(nèi)核(Kernel

    摘要:馬上就會(huì)發(fā)現(xiàn),也可以獲得(get),配置(configure),編譯(compile)和安裝(install)屬于自己的Linux內(nèi)核(Kernel)。目錄:引言安裝內(nèi)核源
    發(fā)表于 11-10 12:16

    flashlayout的kernel實(shí)現(xiàn)

    一般嵌入式系統(tǒng)都會(huì)通過uboot或者lk將flashlayout的信息傳遞給kernel,kernel拿到這些flashlayout的信息后,將對(duì)應(yīng)的每個(gè)partition mount成block device.我們看看kernel
    發(fā)表于 05-23 08:59

    為什么要打印version信息?kernel version實(shí)現(xiàn)原理是什么

    加載內(nèi)核偽裝kernel version實(shí)現(xiàn)原理kernel version這條打印信息來源于start_kernl()中的linux_ba
    發(fā)表于 06-21 16:18

    知道LINUX系統(tǒng)內(nèi)核的實(shí)現(xiàn)原理是什么嗎

    適配可負(fù)載驅(qū)動(dòng)程序調(diào)試多分支版本加載內(nèi)核偽裝內(nèi)核版本實(shí)現(xiàn)原理內(nèi)核版本的標(biāo)簽打印信息 start_kernl(中的linux_kernl)字符串。這里的橫幅比是 ubuntu 系統(tǒng)里的 ssh 基本橫幅
    發(fā)表于 06-30 15:43

    看電機(jī)選幕布-告訴知道的產(chǎn)品細(xì)節(jié)

    看電機(jī)選幕布-告訴知道的產(chǎn)品細(xì)節(jié) 家用投影幕布以固定畫框幕和電動(dòng)式投影幕為主,其中電動(dòng)幕由于安裝容易,對(duì)裝修影響較小
    發(fā)表于 02-10 10:28 ?7343次閱讀

    linux內(nèi)核kernel-api

    linux內(nèi)核kernel-api,不知道從哪兒找的了,但是如果想要做內(nèi)核編程,這是一部api函數(shù)詳盡的工具書!?。∥逍峭扑]
    發(fā)表于 10-30 17:16 ?19次下載

    SYS_BIOS (TI-RTOS Kernel) v6.46 User's Guide

    "TI-RTOS Kernel" in some documents. This document describes SYS/BIOS 6.46, which is the version
    發(fā)表于 10-31 11:22 ?0次下載
    SYS_BIOS (TI-RTOS <b class='flag-5'>Kernel</b>) v6.46 User's Guide

    如何在OpenCL 2.0中實(shí)現(xiàn)Sierpinski Carpet Kernel

    在這個(gè)簡(jiǎn)短的視頻中,您將學(xué)習(xí)如何在OpenCL 2.0中實(shí)現(xiàn)Sierpinski Carpet Kernel。
    的頭像 發(fā)表于 11-07 06:20 ?3135次閱讀

    這些小細(xì)節(jié)知道申卡為什么被拒

      申請(qǐng)信用卡被拒絕了?微辰金服介紹這些小細(xì)節(jié)知道申卡為什么被拒。  申卡被拒的原因:  第一種:信用記錄不良。這條猶如鐵一般的紀(jì)律,對(duì)于“老賴”銀行通常是無法容忍的?! 〉诙N:銀行記仇,申卡
    發(fā)表于 11-14 14:27 ?254次閱讀

    知道linux kernel內(nèi)存碎片防治技術(shù)?

    Linux kernel組織管理物理內(nèi)存的方式是buddy system(伙伴系統(tǒng)),而物理內(nèi)存碎片正式buddy system的弱點(diǎn)之一,為了預(yù)防以及解決碎片問題,kernel采取了一些實(shí)用技術(shù),這里將對(duì)這些技術(shù)進(jìn)行總結(jié)歸納。
    發(fā)表于 05-10 10:59 ?920次閱讀

    知道linux kernel內(nèi)存回收機(jī)制是怎樣的?

    無論計(jì)算機(jī)上有多少內(nèi)存都是不夠的,因而linux kernel需要回收一些很少使用的內(nèi)存頁面來保證系統(tǒng)持續(xù)有內(nèi)存使用。頁面回收的方式有頁回寫、頁交換和頁丟棄三種方式:如果一個(gè)很少使用的頁的后備存儲(chǔ)器是一個(gè)塊設(shè)備(例如文件映射),則可以將內(nèi)存直接同步到塊設(shè)備,騰出的頁面可以被重用;
    發(fā)表于 05-10 11:37 ?890次閱讀
    <b class='flag-5'>你</b><b class='flag-5'>知道</b>linux <b class='flag-5'>kernel</b>內(nèi)存回收機(jī)制是怎樣的?

    知道怎么在IP的kernel module里設(shè)置并使用IP interrupt嗎

    有時(shí)我們需要為官方 IP 或者自己創(chuàng)建的 IP 生成 kernel module,然后在 linux kernel space 里使用 kernel module 來控制這個(gè) IP。如果要使用 IP
    的頭像 發(fā)表于 05-18 11:48 ?1435次閱讀

    關(guān)于繼電器應(yīng)用那些知道細(xì)節(jié)

    繼電器的應(yīng)用,相信大家都知道,在電路中只要給它供電、斷電也就可以工作了。本文討論它的應(yīng)用細(xì)節(jié)。 現(xiàn)在流行的接法 圖中,繼電器的線圈經(jīng)過Q1作為開關(guān),使其導(dǎo)通與斷開。D1作為續(xù)流,消耗線圈中的能量
    的頭像 發(fā)表于 11-01 09:55 ?2668次閱讀
    關(guān)于繼電器應(yīng)用那些<b class='flag-5'>你</b>不<b class='flag-5'>知道</b>的<b class='flag-5'>細(xì)節(jié)</b>

    UBoot如何跳轉(zhuǎn)Kernel

    首先我們知道kernel的鏡像最開始是壓縮的zImage格式的存在,然后Uboot有工具mkimage把其轉(zhuǎn)換為uImage。 什么?不知道?好,那我先給你整兩幅圖瞅瞅,
    的頭像 發(fā)表于 12-04 17:02 ?435次閱讀
    UBoot如何跳轉(zhuǎn)<b class='flag-5'>Kernel</b>