日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

uboot源码——内核启动分析

發(fā)布時(shí)間:2023/12/20 编程问答 40 豆豆
生活随笔 收集整理的這篇文章主要介紹了 uboot源码——内核启动分析 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

以下內(nèi)容源于朱有鵬嵌入式課程的學(xué)習(xí),如有侵權(quán),請告知?jiǎng)h除。

參考資料:http://www.cnblogs.com/biaohc/p/6403863.html


總結(jié):uboot啟動(dòng)linux內(nèi)核的整個(gè)流程

開機(jī)時(shí)會(huì)出現(xiàn)倒計(jì)時(shí),當(dāng)沒有按鍵按下的時(shí)候,uboot會(huì)讀取出bootcmd這個(gè)環(huán)境變量,并使用rum_command函數(shù)來執(zhí)行這個(gè)命令;

  • 實(shí)質(zhì)是執(zhí)行了movi read kernel 30008000;bootm 30008000。
  • movi read kernel,把sd卡中的kernel分區(qū)賦值到30008000內(nèi)存處;
  • bootm 30008000,真正的傳參以及跳轉(zhuǎn)到linux內(nèi)核中執(zhí)行(實(shí)際執(zhí)行do_bootm()函數(shù))。
  • bootm(do_bootm()函數(shù))首先要做的事情是判斷這個(gè)內(nèi)核鏡像類型(zImage、uImage、設(shè)備樹);
  • 通過對鏡像文件的頭文件的驗(yàn)證,以確定是哪種內(nèi)核鏡像,然后再把必須的信息儲存起來(linux操作系統(tǒng)、ep的值等)。
  • 確定好以后調(diào)用do_bootm_linux函數(shù)來對內(nèi)核傳參并且啟動(dòng)內(nèi)核。

?


一、uboot作用簡介

uboot的主要作用是用來啟動(dòng)linux內(nèi)核。

  • 因?yàn)镃PU不能直接從塊設(shè)備中執(zhí)行代碼,需要把塊設(shè)備中的程序復(fù)制到內(nèi)存中,而復(fù)制之前還需要進(jìn)行很多初始化工作,如時(shí)鐘、串口、dram等;
  • 如要想讓CPU啟動(dòng)linux內(nèi)核,只能通過另外的程序,進(jìn)行必要的初始化工作,在把linux內(nèi)核中代碼復(fù)制到內(nèi)存中,并執(zhí)行這塊內(nèi)存中的代碼,即可啟動(dòng)linux內(nèi)核;
  • 一般情況下,linux鏡像儲存在塊設(shè)備中(SD卡、iNand、Nandflash等)。首先執(zhí)行uboot代碼,把塊設(shè)備中的內(nèi)核代碼復(fù)制到內(nèi)存地址0x30008000地址處,然后再執(zhí)行bootm 0x30008000命令以啟動(dòng)內(nèi)核代碼。


?

二、基礎(chǔ)知識?

vmlinuz、Image、zImage、uImage的區(qū)別與聯(lián)系

(1)linux內(nèi)核代碼經(jīng)過編譯鏈接,生成一個(gè)elf格式的可執(zhí)行文件,即vmlinuz或者vmlinux;

  • 此文件不能直接燒錄。

(2)vmlinuz文件經(jīng)過arm-linux-objcopy以后,生成一個(gè)Image鏡像文件。

  • vmlinuz.elf文件大小為70M以上,而Image鏡像文件為7M左右。

(3)Image文件在進(jìn)一步經(jīng)過壓縮,并添加解壓縮代碼,形成zImage文件。

  • 當(dāng)zImage文件作為啟動(dòng)鏡像來啟動(dòng)時(shí),首先要解壓這個(gè)文件,這個(gè)解壓過程可以由uboot解壓或者zImage文件本身自解壓。
  • zImage中除了linux內(nèi)核的鏡像以外,還有一些頭文件以及這部分解壓代碼,所以內(nèi)核實(shí)際上在addr地址中再加一個(gè)偏移量的位置。

(5)uImage是uboot自己專用的啟動(dòng)內(nèi)核鏡像,相對于zImage他們之間頭文件有一定區(qū)別。

  • uImage現(xiàn)在基本上要屬于過時(shí)的技術(shù)了,新一點(diǎn)的技術(shù)為設(shè)備樹的啟動(dòng)方式;

?


三、UBOOT啟動(dòng)內(nèi)核的代碼分析


在啟動(dòng)UBOOT時(shí),出現(xiàn)倒計(jì)時(shí),如果沒有按鍵按下,則會(huì)自動(dòng)啟動(dòng)內(nèi)核。

1、start_armboot()函數(shù)末尾的main_loop

?



下面這段代碼在此main_loop函數(shù)中,作用是執(zhí)行完倒計(jì)時(shí)函數(shù)之后,啟動(dòng)linux內(nèi)核。

  • 啟動(dòng)方式是s = getenv ("bootcmd");;
  • 假定不使用HUAH_PARSER,則run_command (s, 0);實(shí)際上就是讀取環(huán)境變量bootcmd,然后執(zhí)行這個(gè)命令。

?

?

2、bootcmd命令

  • bootcmd=movi read kernel 30008000; movi read rootfs 30B00000 300000; bootm 30008000 30B00000
  • 這兩個(gè)命令完成linux內(nèi)核啟動(dòng)。
  • movi read kernel 30008000,把sd卡中kernel分區(qū)復(fù)制到30008000內(nèi)存地址處;
  • bootm 30008000,到內(nèi)存地址處執(zhí)行代碼;
  • 執(zhí)行bootm命令,實(shí)際執(zhí)行do_bootm函數(shù)。

??

3、do_bootm()函數(shù)

?

?

(1)因?yàn)閎ootm 0x30008000,參數(shù)為2,因此有addr = simple_strtoul(argv[1], NULL, 16)

  • 此時(shí)addr中的值為0x30008000。

(2)接著判斷0x30008000偏移36字節(jié)以后的地址中的值

  • 如果為0x016f2818,說明啟動(dòng)鏡像為zImage,則輸出boot with zImage。

(3)內(nèi)核的操作系統(tǒng)類型,和內(nèi)核真正的入口

  • hdr->ih_os = IH_OS_LINUX;zImage header中ih_os賦值為 IH_OS_LINUX;
  • hdr->ih_ep = ntohl(addr);ih_ep中存放的是point address,這個(gè)值是真正內(nèi)核代碼的地址(起始執(zhí)行入口地址);

(4)image變量

  • static bootm_headers_t?images;?
  • images為uboot內(nèi)定義的一個(gè)bootm_header_t格式的全局變量,用來完成啟動(dòng)過程的。
  • bootm_header_t類型為一個(gè)結(jié)構(gòu)體,如下圖:
  • 包含一個(gè)image_header_t類型的指針,這個(gè)指針最后指向了0x30008000處的zImage header。
  • 包含一個(gè)image_header_t類型的結(jié)構(gòu)體,后面會(huì)把0x30008000處的zImage header復(fù)制一份到此結(jié)構(gòu)體;
  • 包含一個(gè)標(biāo)志位 legacy_hdr_valid。如果上面兩個(gè)賦值以后,把legacy_hdr_valid賦值為1;

?

(5)memmove (&images.legacy_hdr_os_copy, hdr, sizeof(image_header_t));

  • 把hdr中的值復(fù)制一份到 image.legacy_hdr_os_copy中,即把內(nèi)存地址0x30008000處設(shè)置好的zImage頭復(fù)制一份到uboot的data段。

(6)直接跳轉(zhuǎn)到after_header_check處,os為IH_OS_LINUX。



4、after_header_check

  • 判斷操作系統(tǒng),然后調(diào)用do_bootm_linux函數(shù)

?


5、do_bootm_linux()函數(shù)

?

?

(1)獲取環(huán)境變量bootargs;

(2)判斷全局變量images中的legacy_hdr_valid是否為1,如果為1獲取ep值,如果不為1則error。

(3)把ep強(qiáng)制類型換換為函數(shù)指針類型賦值給thekernel;

(4)從環(huán)境變量中讀取machid的值,賦值給s,如果s不空則machid = 環(huán)境變量中machid的值,并打印machid;



----------------------------------uboot給內(nèi)核傳參-----------------------------------------------

6、uboot給內(nèi)核傳參

  • 傳參主要是uboot把與硬件有關(guān)的信息傳給linux內(nèi)核,如memory信息(多少bank、size、起始地址)、命令行信息、lcd 串口、initrd、MTD等信息。
  • 如要定義了任意一個(gè)CONFIG_XXXXX,則執(zhí)行setup_start_tag(bd)

一、setup_start_tag函數(shù)

  • 初始化第一塊參數(shù)tag

??



(1)params = (struct tag *) bd->bi_boot_params;?

  • gd->bd->bi_boot_params = (PHYS_SDRAM_1+0x100);
  • 這句代碼,把uboot中的全局變量(即gd)的bi_boot_params內(nèi)存地址,強(qiáng)制轉(zhuǎn)換為stuct tag* 類型,然后賦值給params;
  • 把PHYS_SDRAM_1+0x100這個(gè)地址設(shè)置為傳參的起始地址;??

(2)struct tag結(jié)構(gòu)體


  • 此結(jié)構(gòu)體由一個(gè)stuct tag_header類型的結(jié)構(gòu)體,加上一個(gè)由一系列結(jié)構(gòu)體組成的union聯(lián)合體組成;
  • 這一系列結(jié)構(gòu)體中存放的就是與board有關(guān)的參數(shù);

(3)hdr.tag 與hdr.size賦值

  • params->hdr.tag = ATAG_CORE;?params->hdr.size = tag_size (tag_core);
(4)對聯(lián)合體中的結(jié)構(gòu)體參數(shù)賦值
  • params->u.core.flags = 0;
  • params->u.core.pagesize = 0;
  • params->u.core.rootdev = 0;
(5)對下一個(gè)params進(jìn)行初始化
  • params = tag_next (params);?
  • //#define tag_next(t) ((struct tag *)((u32 *)(t) + (t)->hdr.size)),把params移動(dòng)sizeof(tag_core)大小繼續(xù)賦值



二、傳遞內(nèi)存參數(shù),setup_memory_tags函數(shù)

  • 把內(nèi)存每個(gè)bank的信息放到這里:第一個(gè)扇區(qū)的起始地址和大小,第二個(gè)扇區(qū)的起始地址和大小……

?


三、傳遞命令行參數(shù),setup_commandline_tag函數(shù)

  • commandline是一個(gè)char *類型,指向環(huán)境變量中的bootargs的值,即:
  • #define CONFIG_BOOTARGS ?"root=/dev/mtdblock4 rootfstype=yaffs2 init=/init console=ttySAC0,115200"

?



四、setup_end_tag (bd):結(jié)束傳參


-----------------------------------------uboot給內(nèi)核傳參結(jié)束-----------------------------------------------



?7、uboot中最后一句代碼

  • 通過執(zhí)行thekernel函數(shù)直接啟動(dòng)linux內(nèi)核,傳遞三個(gè)參數(shù):0、machid、傳參的首地址;
  • 這三個(gè)參數(shù)是通過r0、r1、r2三個(gè)寄存器來傳遞,r0傳遞0、r1傳遞machid、r2傳遞傳參的首地址。
  • 這樣就把內(nèi)核啟動(dòng)起來了。

?






創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎(jiǎng)勵(lì)來咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎(jiǎng)

總結(jié)

以上是生活随笔為你收集整理的uboot源码——内核启动分析的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。