日本黄色一级经典视频|伊人久久精品视频|亚洲黄色色周成人视频九九九|av免费网址黄色小短片|黄色Av无码亚洲成年人|亚洲1区2区3区无码|真人黄片免费观看|无码一级小说欧美日免费三级|日韩中文字幕91在线看|精品久久久无码中文字幕边打电话

當前位置:首頁 > 嵌入式 > 嵌入式客棧
[導讀][導讀] 前面的文章有提到linux啟動的第一個進程為init,那么該進程究竟是如何從內(nèi)核啟動入口一步一步運行起來的,而該進程又有些什么作用呢?做嵌入式Linux開發(fā),有必要對這些概念了解清楚。本文基于ARM體系的內(nèi)核啟動做出解析。 跳轉(zhuǎn)內(nèi)核前基本準備 參考./Do

[導讀] 前面的文章有提到linux啟動的第一個進程為init,那么該進程究竟是如何從內(nèi)核啟動入口一步一步運行起來的,而該進程又有些什么作用呢?做嵌入式Linux開發(fā),有必要對這些概念了解清楚。本文基于ARM體系的內(nèi)核啟動做出解析。

跳轉(zhuǎn)內(nèi)核前基本準備

參考./Documentation/arm64/booting.txt

Bootloader至少完成以下基本的初始化準備:

  • 設(shè)置并初始化RAM(必須),引導加載程序應(yīng)找到并初始化內(nèi)核將用于系統(tǒng)中易失性數(shù)據(jù)存儲的所有RAM。它以機器相關(guān)的方式執(zhí)行此操作。(它可以使用內(nèi)部算法來自動定位和調(diào)整所有RAM的大小,或者可以使用機器中RAM的知識或引導加載程序設(shè)計者認為合適的任何其他方法。)

  • 設(shè)置設(shè)備樹dtb(必須) , 設(shè)備樹blob(dtb)必須8字節(jié)對齊,并且大小不能超過2兆字節(jié)。由于dtb將使用最大2 MB的塊進行映射以可緩存,因此它不能放置在必須使用任何特定屬性進行映射的任何2M區(qū)域內(nèi)。注意:v4.2之前的版本還要求將DTB放置在512 MB區(qū)域內(nèi),從內(nèi)核映像下方的text_offset字節(jié)開始計算。

  • 解壓縮內(nèi)核映像(可選),AArch64內(nèi)核當前不提供解壓縮器,因此如果使用壓縮的Image目標(例如Image.gz),則需要由引導加載程序執(zhí)行解壓縮(gzip等)。對于未實現(xiàn)此要求的引導加載程序,可以使用未經(jīng)壓縮內(nèi)核編譯。

  • 調(diào)用內(nèi)核映像(必須)。壓縮內(nèi)核頭部如下:

    u32 code0;              /* 可執(zhí)行code   */
    u32 code1;             /* 可執(zhí)行code   */
    u64 text_offset;       /* 加載偏移,小端 */
    u64 image_size;        /* 有效映象尺寸,小端 */
    u64 flags;             /* 內(nèi)核標志, 小端    */
    u64 res2  = 0;         /* 保留 */
    u64 res3  = 0;         /* 保留 */
    u64 res4  = 0;         /* 保留 */
    u32 magic = 0x644d5241/* 幻數(shù),小端, "ARM\x64"  */
    u32 res5;          /* 保留(用于PE COFF偏移量) */

進入內(nèi)核之前,必須滿足以下條件:

  • 禁止所有具有DMA功能的設(shè)備,以免內(nèi)存被虛假錯誤的網(wǎng)絡(luò)數(shù)據(jù)包或磁盤數(shù)據(jù)損壞。

  • 主CPU通用寄存器設(shè)置:

    • x0 =系統(tǒng)RAM中設(shè)備樹Blob(dtb)的物理地址。

    • x1/x2/x3 = 0(保留供將來使用)

  • CPU模式

    • 所有形式的中斷都必須在PSTATE.DAIF中屏蔽(調(diào)試,SError,IRQ和FIQ)。

    • CPU必須位于EL2(推薦使用,以便可以訪問虛擬化擴展)或非安全EL1中。

  • Caches, MMUs

    • MMU必須關(guān)閉。

    • 指令緩存可以打開或關(guān)閉。

    • 與加載的內(nèi)核映像相對應(yīng)的地址范圍必須清除到PoC。如果存在系統(tǒng)緩存或啟用了緩存的其他相關(guān)主服務(wù)器,則通常需要通過VA而不是通過設(shè)置/方式操作來維護緩存。

    • 遵循VA對架構(gòu)化緩存維護的系統(tǒng)緩存。必須配置并啟用操作。

    • 不遵循VA對架構(gòu)化混存維護的系統(tǒng)緩存,必須配置和禁用操作(不推薦)。

  • 架構(gòu)定時器

    • 必須在所有CPU上以定時器頻率設(shè)置CNTFRQ,并且必須以一致的值設(shè)置CNTVOFF。如果在EL1處進入內(nèi)核,則CNTHCTL_EL2必須在可用時設(shè)置EL1PCTEN(位0)。

  • 連貫性

    • 內(nèi)核啟動時,所有要由內(nèi)核引導的CPU都必須屬于同一一致性域。需要初始化定義的實現(xiàn),才能在每個CPU上接收維護操作。

  • 系統(tǒng)寄存器

    • 所有將在其中輸入內(nèi)核映像的異常級別的可寫體系結(jié)構(gòu)系統(tǒng)寄存器都必須由更高級別的異常級別的軟件初始化,以防止在UNKNOWN狀態(tài)下執(zhí)行。

    • 對CPU模式,高速緩存,MMU,架構(gòu)計時器,一致性和系統(tǒng)寄存器的要求適用于所有CPU。所有CPU必須以相同的異常級別進入內(nèi)核。

  • 主CPU必須直接跳轉(zhuǎn)到內(nèi)核映像的第一條指令。此CPU傳遞的設(shè)備樹Blob必須為每個cpu節(jié)點包含一個“啟用方法”屬性。支持的啟用方法如下所述。引導加載程序?qū)⑸蛇@些設(shè)備樹屬性,并將其插入內(nèi)核入口之前的blob中。

  • 具有“旋轉(zhuǎn)表”啟用方法的CPU在其cpu節(jié)點中必須具有“ cpu-release-addr”屬性。此屬性標識自然對齊的64位零初始化內(nèi)存位置。

  • 具有“ psci”啟用方法的CPU應(yīng)該保留在內(nèi)核之外(即,在內(nèi)存節(jié)點中描述給內(nèi)核的內(nèi)存區(qū)域之外,或者在內(nèi)核中通過/ memreserve /描述給內(nèi)核描述的內(nèi)存保留區(qū)域之外)。設(shè)備樹)。內(nèi)核將按照ARM文檔編號ARM DEN 0022A(“ ARM處理器上的電源狀態(tài)協(xié)調(diào)接口系統(tǒng)軟件”)中的說明發(fā)出CPU_ON調(diào)用,以將CPU帶入內(nèi)核。設(shè)備樹應(yīng)包含一個“ psci”節(jié)點,參考/bindings/arm/psci.txt.

  • 第二CPU通用寄存器設(shè)置的x0/x1/x2/x3都為0,保留。

內(nèi)核啟動init總過程

內(nèi)核啟動有兩種方式,壓縮格式或不壓縮格式,壓縮模式所不同的就是其入口位于arch/ /boot/compressed/head.S,為與該路徑下的代碼主要負責執(zhí)行執(zhí)行前期的初始化為解壓內(nèi)核做準備。當完成解壓內(nèi)核后,就跳轉(zhuǎn)到./arm/kernel/head.S開始啟動內(nèi)核。

本文僅分析不壓縮方式啟動內(nèi)核,通過分析內(nèi)核代碼,整理出內(nèi)核啟動過程的部分順序如下:


內(nèi)核的啟動與U-Boot一樣,前面一段是匯編代碼,然后跳轉(zhuǎn)到C代碼。匯編的入口在

./arm/kernel/head.S中,符號名為__HEAD,該文件包含了head-common.S。

所以從啟動用戶首進程init而言,我將其分成大致分為四大步:

  • head.S ,初始化通用部分環(huán)境,與芯片無關(guān)

  • start_kernel, head.S完成后,調(diào)準到start_kernel,進入C函數(shù)執(zhí)行,該函數(shù)為于./init/main.c中

  • rest_init,創(chuàng)建init進程,以及kthredd進程,其中Init進程號為1,kthredd為內(nèi)核進程。

  • 啟動調(diào)度器,執(zhí)行kernel_init,該函數(shù)將調(diào)用根文件系統(tǒng)中的init執(zhí)行文件,至此用戶空間的init進程就啟動起來了。

head.S/head-common.S作用

剖析匯編代碼比較枯燥,這里就不進行描述了。僅就其作用進行總結(jié):

  • 檢查架構(gòu),處理器和機器類型。

  • 配置MMU,創(chuàng)建頁表條目并啟用虛擬內(nèi)存。

  • 在init / main.c中調(diào)用start_kernel函數(shù)。

  • 所有架構(gòu)的代碼相同。這也是為什么采用匯編代碼的原因,規(guī)避針對不同芯片管理大量重復代碼。

start_kernel階段

該函數(shù)主要完成以下以下工作:

  • lockdep 死鎖檢測模塊初始化,

  • RCU機制初始化:RCU(Read-Copy Update),顧名思義就是讀-拷貝修改,它是基于其原理命名的。對于被RCU保護的共享數(shù)據(jù)結(jié)構(gòu),讀者不需要獲得任何鎖就可以訪問它,但寫者在訪問它時首先拷貝一個副本,然后對副本進行修改,最后使用一個回調(diào)(callback)機制在適當?shù)臅r機把指向原來數(shù)據(jù)的指針重新指向新的被修改的數(shù)據(jù)。這個時機就是所有引用該數(shù)據(jù)的CPU都退出對共享數(shù)據(jù)的操作。

  • SMP初始化,對稱多處理"(Symmetrical Multi-Processing)簡稱SMP,完成CPU ID的創(chuàng)建。

  • debug_objects_early_init,負責調(diào)試對象初始化,以便于內(nèi)核調(diào)試

  • lockdep死鎖檢測模塊初始化,lockdep的工作方式是在內(nèi)核中的鎖定調(diào)用包起來。每次采用或釋放特定類型的鎖時,都會記錄該事實以及輔助詳細信息,例如處理器當時是否正在處理中斷。Lockdep還記錄了使用新鎖時還持有哪些其他鎖;這是lockdep能夠執(zhí)行的許多檢查的關(guān)鍵。

  • 調(diào)用setup_arch(&command_line),該函數(shù)位于arch/

    /kernel/setup.c,用于解析從bootloader傳入的引導命令行。
  • 初始化控制臺,以打印啟動日志。

  • 初始化其他各子系統(tǒng),如VFS,trace,內(nèi)存管理子系統(tǒng),F(xiàn)ORK子系統(tǒng),cgroup,acpi,proc文件系統(tǒng),內(nèi)核服務(wù),緩存等等。

  • ……

  • 調(diào)用rest_init,以創(chuàng)建init進程以及內(nèi)核進程,并啟動內(nèi)核調(diào)度器。

rest_init階段

代碼如下,其注釋如下,主要作用就是先創(chuàng)建init進程使其進程號為1,這是第一個用戶空間進程,該進程執(zhí)行后在衍生出一系列的應(yīng)用進程。具體取決于啟動腳本或者Init的具體實現(xiàn)。然后創(chuàng)建內(nèi)核進程kthreadd,該進程用于管理內(nèi)核進程。該進程進程號為2。所有內(nèi)核進程都是kthreadd的后代, kthreadd枚舉其他內(nèi)核線程;它提供了接口例程,內(nèi)核服務(wù)可以在運行時動態(tài)生成其他內(nèi)核進程。通過kthread_create_list維護其他內(nèi)核進程??梢允褂胮s -ef命令從命令行查看內(nèi)核線程-它們顯示在[方括號]中:

static noinline void __init_refok rest_init(void)
{
    int pid;

    rcu_scheduler_starting();
    smpboot_thread_init();

    /*創(chuàng)建init進程,第一個用戶空間進程我們
    *需要首先生成init,以便它獲得pid 1,但是
    *init任務(wù)最終將要創(chuàng)建kthread,如果在創(chuàng)建
    *kthreadd之前對其進行調(diào)度,則OOPS。*/

    kernel_thread(kernel_init, NULL, CLONE_FS);
    numa_default_policy();

    /*創(chuàng)建kthreadd用于管理內(nèi)核線程*/
    pid = kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES);

    /*RCU 鎖*/
    rcu_read_lock();
    kthreadd_task = find_task_by_pid_ns(pid, &init_pid_ns);
    rcu_read_unlock();
    /*讓內(nèi)核進程kthreadd處于就緒態(tài)TASK_NORMAL*/
    complete(&kthreadd_done);

    /* 啟動調(diào)度器      */
    init_idle_bootup_task(current);
    schedule_preempt_disabled();
    /* 禁用搶占的情況下調(diào)用cpu_idle */
    cpu_startup_entry(CPUHP_ONLINE);
}

kernel_init階段

當內(nèi)核調(diào)度器運行后,就會執(zhí)行kernel_init函數(shù):

static int __ref kernel_init(void *unused)
{
    int ret;

    kernel_init_freeable();
    /* 同步完成所有初始化操作 */
    async_synchronize_full();
#ifndef CONFIG_INITCALLS_THREAD
    free_initmem();
#endif
    mark_readonly();
    system_state = SYSTEM_RUNNING;
    numa_default_policy();

    flush_delayed_fput();

    /*如果使能了ramdisk執(zhí)行命令啟動init*/
    if (ramdisk_execute_command) {
        ret = run_init_process(ramdisk_execute_command);
        if (!ret)
            return 0;
        pr_err("Failed to execute %s (error %d)\n",
               ramdisk_execute_command, ret);
    }

    /* 如果execute_command使能,則按命令啟動init*/
    if (execute_command) {
        ret = run_init_process(execute_command);
        if (!ret)
            return 0;
        panic("Requested init %s failed (error %d).",
              execute_command, ret);
    }

    /*如果前面兩項都沒有使能,則依次在根文件系統(tǒng)下尋找并啟動Init*/
    if (!try_to_run_init_process("/sbin/init") ||
        !try_to_run_init_process("/etc/init") ||
        !try_to_run_init_process("/bin/init") ||
        !try_to_run_init_process("/bin/sh"))
        return 0;

    panic("No working init found.  Try passing init= option to kernel. "
          "See Linux Documentation/init.txt for guidance.");
}

從而init用戶進程就啟動起來了,至于最終執(zhí)行的是哪一個Init可執(zhí)行文件,取決于系統(tǒng)移植的配置,如前文描述,常見的有busybox init,systemV init,systemD init等等。

niprogram-servicetype="">點擊留言/查看留言

END

果喜歡右下點個在看,也會讓我倍感鼓舞

往期精彩推薦




▲深度解析U-Boot網(wǎng)絡(luò)實現(xiàn)(長篇好文)
讀U-Boot源碼-C語言編程大法總結(jié)篇一
讀U-Boot源碼-C語言編程技巧總結(jié)篇二
基于Buildroot的Linux系統(tǒng)構(gòu)建之根文件系統(tǒng)
手把手教系列之移動平均濾波器C實現(xiàn)
手把手教系列之IIR數(shù)字濾波器設(shè)計實現(xiàn)

關(guān)注置頂:掃描左下二維碼關(guān)注公眾號加星

討論加群:掃描右下二維碼添加,發(fā)送“加群”

關(guān)注

加群

免責聲明:本文內(nèi)容由21ic獲得授權(quán)后發(fā)布,版權(quán)歸原作者所有,本平臺僅提供信息存儲服務(wù)。文章僅代表作者個人觀點,不代表本平臺立場,如有問題,請聯(lián)系我們,謝謝!

本站聲明: 本文章由作者或相關(guān)機構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點,本站亦不保證或承諾內(nèi)容真實性等。需要轉(zhuǎn)載請聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請及時聯(lián)系本站刪除。
換一批
延伸閱讀

LED驅(qū)動電源的輸入包括高壓工頻交流(即市電)、低壓直流、高壓直流、低壓高頻交流(如電子變壓器的輸出)等。

關(guān)鍵字: 驅(qū)動電源

在工業(yè)自動化蓬勃發(fā)展的當下,工業(yè)電機作為核心動力設(shè)備,其驅(qū)動電源的性能直接關(guān)系到整個系統(tǒng)的穩(wěn)定性和可靠性。其中,反電動勢抑制與過流保護是驅(qū)動電源設(shè)計中至關(guān)重要的兩個環(huán)節(jié),集成化方案的設(shè)計成為提升電機驅(qū)動性能的關(guān)鍵。

關(guān)鍵字: 工業(yè)電機 驅(qū)動電源

LED 驅(qū)動電源作為 LED 照明系統(tǒng)的 “心臟”,其穩(wěn)定性直接決定了整個照明設(shè)備的使用壽命。然而,在實際應(yīng)用中,LED 驅(qū)動電源易損壞的問題卻十分常見,不僅增加了維護成本,還影響了用戶體驗。要解決這一問題,需從設(shè)計、生...

關(guān)鍵字: 驅(qū)動電源 照明系統(tǒng) 散熱

根據(jù)LED驅(qū)動電源的公式,電感內(nèi)電流波動大小和電感值成反比,輸出紋波和輸出電容值成反比。所以加大電感值和輸出電容值可以減小紋波。

關(guān)鍵字: LED 設(shè)計 驅(qū)動電源

電動汽車(EV)作為新能源汽車的重要代表,正逐漸成為全球汽車產(chǎn)業(yè)的重要發(fā)展方向。電動汽車的核心技術(shù)之一是電機驅(qū)動控制系統(tǒng),而絕緣柵雙極型晶體管(IGBT)作為電機驅(qū)動系統(tǒng)中的關(guān)鍵元件,其性能直接影響到電動汽車的動力性能和...

關(guān)鍵字: 電動汽車 新能源 驅(qū)動電源

在現(xiàn)代城市建設(shè)中,街道及停車場照明作為基礎(chǔ)設(shè)施的重要組成部分,其質(zhì)量和效率直接關(guān)系到城市的公共安全、居民生活質(zhì)量和能源利用效率。隨著科技的進步,高亮度白光發(fā)光二極管(LED)因其獨特的優(yōu)勢逐漸取代傳統(tǒng)光源,成為大功率區(qū)域...

關(guān)鍵字: 發(fā)光二極管 驅(qū)動電源 LED

LED通用照明設(shè)計工程師會遇到許多挑戰(zhàn),如功率密度、功率因數(shù)校正(PFC)、空間受限和可靠性等。

關(guān)鍵字: LED 驅(qū)動電源 功率因數(shù)校正

在LED照明技術(shù)日益普及的今天,LED驅(qū)動電源的電磁干擾(EMI)問題成為了一個不可忽視的挑戰(zhàn)。電磁干擾不僅會影響LED燈具的正常工作,還可能對周圍電子設(shè)備造成不利影響,甚至引發(fā)系統(tǒng)故障。因此,采取有效的硬件措施來解決L...

關(guān)鍵字: LED照明技術(shù) 電磁干擾 驅(qū)動電源

開關(guān)電源具有效率高的特性,而且開關(guān)電源的變壓器體積比串聯(lián)穩(wěn)壓型電源的要小得多,電源電路比較整潔,整機重量也有所下降,所以,現(xiàn)在的LED驅(qū)動電源

關(guān)鍵字: LED 驅(qū)動電源 開關(guān)電源

LED驅(qū)動電源是把電源供應(yīng)轉(zhuǎn)換為特定的電壓電流以驅(qū)動LED發(fā)光的電壓轉(zhuǎn)換器,通常情況下:LED驅(qū)動電源的輸入包括高壓工頻交流(即市電)、低壓直流、高壓直流、低壓高頻交流(如電子變壓器的輸出)等。

關(guān)鍵字: LED 隧道燈 驅(qū)動電源
關(guān)閉