1、Linux系統(tǒng)啟動(dòng)與U-Boot
所謂移植就是把程序代碼從一種運(yùn)行環(huán)境轉(zhuǎn)移到另一種運(yùn)行環(huán)境。對(duì)于內(nèi)核移植來(lái)說(shuō),主要是從一種硬件平臺(tái)轉(zhuǎn)移到另一種硬件平臺(tái)上運(yùn)行。
體系結(jié)構(gòu)級(jí)別的移植是指在不同體系結(jié)構(gòu)平臺(tái)上Linux內(nèi)核的移植,例如,在ARM、MIPS、PPC等不同體系結(jié)構(gòu)上分別都要對(duì)每個(gè)體系結(jié)構(gòu)進(jìn)行特定的移植工作。一個(gè)新的體系結(jié)構(gòu)出現(xiàn)就需要進(jìn)行這個(gè)層次上的移植。
SoC級(jí)別的移植是指在具體的SoC處理器平臺(tái)上Linux內(nèi)核的移植,例如,ARM i.MX6Dual處理器要進(jìn)行SoC特定的移植工作,主要包括處理器相關(guān)的內(nèi)核修改、集成外設(shè)驅(qū)動(dòng)。
主板級(jí)別的移植是指在具體的目標(biāo)主板上Linux內(nèi)核的移植,例如,在i.MX6DualFS2410目標(biāo)板上,需要進(jìn)行主板特定的移植工作,主要包括特定目標(biāo)板系統(tǒng)啟動(dòng)與主板擴(kuò)展外設(shè)相關(guān)的外設(shè)驅(qū)動(dòng)等。
基于同一款處理器的不同嵌入式設(shè)備并不是所有的外部設(shè)備都相同,不同的開(kāi)發(fā)板可以使用不同的SDRAM、Flash、以太網(wǎng)接口芯片等。這就需要根據(jù)硬件修改或者開(kāi)發(fā)驅(qū)動(dòng)程序。
一個(gè)最基本的Linux操作系統(tǒng)應(yīng)該包括:引導(dǎo)程序、內(nèi)核與根文件系統(tǒng)三部分。因此,需要移植一個(gè)Linux系統(tǒng)的話,那么需要以下4個(gè)步驟:
搭建交叉開(kāi)發(fā)環(huán)境;
BootLoader的選擇和移植;
kernel的配置、編譯、和移植;
根文件系統(tǒng)的制作。
(1)BootLoader簡(jiǎn)介
引導(dǎo)加載程序(Boot Loader)就是在操作系統(tǒng)內(nèi)核運(yùn)行之前運(yùn)行的一段小程序。通過(guò)這段小程序,我們可以初始化硬件設(shè)備、建立內(nèi)存空間的映射圖,從而將系統(tǒng)的軟硬件環(huán)境帶到一個(gè)合適的狀態(tài),以便為最終調(diào)用操作系統(tǒng)內(nèi)核準(zhǔn)備好正確的環(huán)境。
如下圖所示:
為什么系統(tǒng)移植之前要先移植BootLoader?
BootLoader的任務(wù)是引導(dǎo)操作系統(tǒng),所謂初始化CPU運(yùn)行環(huán)境,引導(dǎo)操作系統(tǒng)。就是啟動(dòng)內(nèi)核,讓內(nèi)核運(yùn)行就是把內(nèi)核加載到內(nèi)存RAM中去運(yùn)行。
是誰(shuí)把CPU運(yùn)行環(huán)境初始化的?
是誰(shuí)把內(nèi)核搬到內(nèi)存中去運(yùn)行?
SRAM只要系統(tǒng)上電就可以運(yùn)行,而SDRAM需要軟件進(jìn)行初始化才能運(yùn)行,那么內(nèi)存是由誰(shuí)來(lái)初始化的呢?
(2)Bootloader的執(zhí)行過(guò)程
uboot 啟動(dòng)流程詳細(xì)分析
初始化SDRAM;
初始化串口;
檢測(cè)處理器類型;
設(shè)置Linux啟動(dòng)參數(shù);
調(diào)用Linux內(nèi)核映像。
(3)BootLoader的分類
很多人說(shuō)BootLoader就是U-Boot,這種說(shuō)法是錯(cuò)誤的,確切來(lái)說(shuō)是U-Boot是BootLoader的一種。u-boot和bootloader到底有什么區(qū)別。
如下圖所示。
可以知道如果使用開(kāi)發(fā)板board/
u-boot.bin:二進(jìn)制可執(zhí)行文件,它就是可以直接燒入eMMC中的文件。
u-boot: ELF格式的可執(zhí)行文件。
u-boot.srec: 原摩托羅拉格式的可執(zhí)行文件。
對(duì)于imx6dlsabresd開(kāi)發(fā)板,可以根據(jù)開(kāi)發(fā)板的型號(hào)選擇執(zhí)行“make imx6dlsabresd_defconfig”、“make"進(jìn)行編譯。
編譯后生成的u-boot.imx鏡像可以燒入SD卡中執(zhí)行,具體命令如下:
sudo dd if=u-boot.imx of=/dev/sdb bs=512 seek=2其中sdb代表SD卡在系統(tǒng)中對(duì)應(yīng)的設(shè)備。
(4)u-boot配置過(guò)程
在配置之前,為了使編譯后的u-boot在開(kāi)發(fā)板上運(yùn)行,首先需要安裝交叉編譯鏈。并使用如下命令配置環(huán)境變量:
source /opt/fsl-imx-fb/4.14-sumo/environment-setup-cortexa9hf-neon-poky- linux-gnueabi
u-boot啟動(dòng)流程分析如下
第一階段:(注明下每個(gè)步驟的作用)
a -- 設(shè)置cpu工作模式為SVC模式。需要SVC權(quán)限對(duì)CPU的狀態(tài)寄存器進(jìn)行操作 b -- 關(guān)閉中斷,mmu,,cache。需要直接物理地址訪問(wèn) v -- 關(guān)看門狗 d -- 初始化內(nèi)存,串口。用于初始化基本的存儲(chǔ)空間與通信接口,用于啟動(dòng)信息交互 e -- 設(shè)置棧。用于系統(tǒng)啟動(dòng)臨時(shí)數(shù)據(jù)交換和初始化棧指針 f -- 代碼自搬移。用于拷貝系統(tǒng)啟動(dòng)代碼 g -- 清bss
h -- 跳c
第二階段:
a -- 初始化外設(shè),進(jìn)入超循環(huán)
b -- 超循環(huán)處理用戶命令
函數(shù)前期執(zhí)行流程如下:
1)_start(arch/arm/lib/vector.S)
b reset 2)reset(arch/arm/cpu/$CPU/start.S)
bl cpu_init_cp15
bl cpu_init_crit
bl _main
3)_main(archarmlibcrt0.S)
board_init_f(commonBoard_f.c)
b relocate_code
ldr lr, =board_init_r(common/Board_r.c)
4)main_loop()
5)啟動(dòng)內(nèi)核:
main_loop->autoboot_command->run_command_list->cli_simple_run_ command_list->cli_simple_run_command->cmd_process->find_cmd/cmd_call(result=(cmdtp->cmd)(cmdtp, flag, argc, argv))
uboot的最終目的是引導(dǎo)內(nèi)核,在此之前uboot需要完成一系列初始化操作,包括設(shè)置時(shí)鐘、初始化DDR、Flash、串口、網(wǎng)卡等等。
這時(shí)uboot有兩條路走
(1)通過(guò)按鍵,觸發(fā)uboot進(jìn)入命令行模式,等待處理命令。
(2)引導(dǎo)內(nèi)核
2、Linux系統(tǒng)裁剪與移植
內(nèi)核編譯相關(guān)文件主要包括頂層Makefile與子目錄下的Makefile、各級(jí)目錄Kconfig文件。
a--在內(nèi)核配置之前先使用make mrproper命令清除以前的內(nèi)核。
b--詳細(xì)配置make menuconfig
c--編譯
make zImage ---生成內(nèi)核鏡像/arch/arm/boot/zImage
make dtbs ---生成設(shè)備樹(shù)文件/arch/arm/boot/dts/imx6dl-sabresd.dtb
make modules ---把配置值選成M的代碼編譯生成模塊文件。(.ko)放在對(duì)應(yīng)的源碼目錄下。
可以看出,內(nèi)核編譯主要包括兩部分:一部分是內(nèi)核配置;另一部分是內(nèi)核編譯。如下圖所示。
內(nèi)核的Kconfig分析:
a -- 我們解壓內(nèi)核后需要先修改內(nèi)核頂層目錄下的Makefile,配置好交叉編譯工具
b -- 然后導(dǎo)入默認(rèn)配置(使用make imx_v7_defconfig 或者
cparch/arm/configs/imx_v7_deconfig.config)
c -- 配置內(nèi)核
如下圖所示。
內(nèi)核中的哪些文件將被編譯?它們是怎樣被編譯的?它們連接時(shí)的順序如何確定?哪個(gè)文件在最前面?哪些文件或函數(shù)先執(zhí)行?這些都是通過(guò)Makefile來(lái)管理的。
從最簡(jiǎn)單的角度來(lái)總結(jié)Makefile的作用,有以下3點(diǎn):
1)-- 決定編譯哪些文件?
2)-- 怎樣編譯這些文件?
3)-- 怎樣連接這些文件,最重要的是它們的順序如何?
1)頂層Makefile 決定內(nèi)核根目錄下哪些子目錄將被編進(jìn)內(nèi)核;
2)arch/$(ARCH)/Makefile 決定arch/$(ARCH)目錄下哪些文件、哪些目錄將被編進(jìn)內(nèi)核;
3)各級(jí)子目錄下的Makefile決定所在目錄下哪些文件將被編進(jìn)內(nèi)核,哪些文件將被編程模塊(即驅(qū)動(dòng)程序),進(jìn)入哪些子目錄繼續(xù)調(diào)用它們的Makefile。
與移植U-Boot的過(guò)程相似,在移植Linux之前,先了解它的啟動(dòng)過(guò)程。
Linux 的過(guò)程可以分為兩部分:架構(gòu)/開(kāi)發(fā)板相關(guān)的引導(dǎo)過(guò)程、后續(xù)的通用啟動(dòng)過(guò)程。對(duì)于uImage、zImage ,它們首先進(jìn)行自解壓得到vmlinux ,然后執(zhí)行 vmlinux 開(kāi)始“正常的”啟動(dòng)流程。
引導(dǎo)階段通常使用匯編語(yǔ)言編寫,它首先檢查內(nèi)核是否支持當(dāng)前架構(gòu)的處理器,然后檢查是否支持當(dāng)前開(kāi)發(fā)板。
通過(guò)檢查后,就為調(diào)用下一階段的start_kernel函數(shù)作準(zhǔn)備了。
這主要分如下兩個(gè)步驟:
1) 連接內(nèi)核時(shí)使用的虛擬地址,所以要設(shè)置頁(yè)表、使能MMU;
2)調(diào)用C 函數(shù) start_kernel 之前的常規(guī)工作,包括復(fù)制數(shù)據(jù)段、清除BSS段、調(diào)用start_kernel 函數(shù)。
第二階段的關(guān)鍵代碼主要使用C語(yǔ)言編寫。
它進(jìn)行內(nèi)核初始化的全部工作,最后調(diào)用 rest_init 函數(shù)啟動(dòng)init 過(guò)程,創(chuàng)建系統(tǒng)第一個(gè)進(jìn)程:init 進(jìn)程。在第二階段,仍有部分架構(gòu)/開(kāi)發(fā)板相關(guān)的代碼,比如重新設(shè)置頁(yè)表、設(shè)置系統(tǒng)時(shí)鐘、初始化串口等。
內(nèi)核自解壓階段:
Linux內(nèi)核有兩種映像:一種是非壓縮內(nèi)核,叫Image,另一種是它的壓縮版本,叫zImage。根據(jù)內(nèi)核映像的不同,Linux內(nèi)核的啟動(dòng)在開(kāi)始階段也有所不同。
zImage是Image經(jīng)過(guò)壓縮形成的,所以它的大小比Image小。但為了能使用zImage,必須在它的開(kāi)頭加上解壓縮的代碼,將zImage解壓縮之后才能執(zhí)行,因此它的執(zhí)行速度比Image要慢。
但考慮到嵌入式系統(tǒng)的存儲(chǔ)空容量一般比較小,采用zImage可以占用較少的存儲(chǔ)空間,因此犧牲一點(diǎn)性能上的代價(jià)也是值得的。所以一般的嵌入式系統(tǒng)均采用壓縮內(nèi)核的方式。
內(nèi)核自解壓階段依次完成以下工作:開(kāi)啟MMU和Cache,調(diào)用decompress_kernel()解壓內(nèi)核,最后通過(guò)調(diào)用call_kernel()進(jìn)入非壓縮內(nèi)核Image的啟動(dòng)。
內(nèi)核引導(dǎo)階段:
內(nèi)核引導(dǎo)階段是內(nèi)核啟動(dòng)第一階段,該部分代碼實(shí)現(xiàn)在arch/arm/kernel的 head.S中,該文件中的匯編代碼通過(guò)查找處理器內(nèi)核類型和機(jī)器碼類型調(diào)用相應(yīng)的初始化函數(shù),再建 立頁(yè)表,最后跳轉(zhuǎn)到start_kernel()函數(shù)開(kāi)始內(nèi)核的初始化工作。如下圖所示:
內(nèi)核初始化階段:
Linux內(nèi)核啟動(dòng)的第二階段從start_kernel()函數(shù)開(kāi)始。start_kernel()是所有Linux平臺(tái)進(jìn)入系統(tǒng)內(nèi)核初始化后的入口函數(shù),它主要完成剩余的與硬件平臺(tái)相關(guān)的初始化工作,在進(jìn)行一系列與內(nèi)核相關(guān)的初始化后,調(diào)用第一個(gè)用戶進(jìn)程-init進(jìn)程并等待用戶進(jìn)程的執(zhí)行,這樣整個(gè)Linux內(nèi)核便啟動(dòng)完畢。
BusyBox初始化階段:
除了基本的命令之外,BusyBox還支持init功能,如同其它的init一樣,busybox的init也是完成系統(tǒng)的初始化工作,關(guān)機(jī)前的工作等等。
BusyBox的init進(jìn)程會(huì)依次進(jìn)行以下工作:
為init設(shè)置信號(hào)處理過(guò)程;
初始化控制臺(tái);
分析 inittab文件,/etc/inittab;
執(zhí)行系統(tǒng)初始化腳本,缺省情況下會(huì)使用/etc/init.d/rcS;
執(zhí)行所有導(dǎo)致init暫停的inittab命令(動(dòng)作類型:wait);
執(zhí)行所有僅執(zhí)行一次的inittab(動(dòng)作類型:once)。
3、Linux根文件系統(tǒng)移植
(1)文件系統(tǒng)與根文件系統(tǒng)
根,可以理解為基礎(chǔ)的意思。根文件系統(tǒng)是一種最基礎(chǔ)的文件系統(tǒng)。
Linux系統(tǒng)也可以將磁盤或Flash等存儲(chǔ)設(shè)備劃分為若干個(gè)分區(qū),在不同的分區(qū)存放不同類型的文件,在某個(gè)分區(qū)存放u-boot的可執(zhí)行文件;在某個(gè)分區(qū)存放內(nèi)核映像文件,在另一分區(qū)存放根文件系統(tǒng)映像文件等。
Linux也需要在一個(gè)分區(qū)上存放系統(tǒng)啟動(dòng)的必要文件,比如內(nèi)核啟動(dòng)運(yùn)行后的第一個(gè)程序(init進(jìn)程)、用于掛接文件系統(tǒng)的腳本、給用戶提供操作界面的shell程序,應(yīng)用程序所要依賴的庫(kù)等,這些必要的基本文件的集合稱為根文件系統(tǒng)(一般也叫做rootfs)。
Linux系統(tǒng)啟動(dòng)后首先會(huì)掛載這個(gè)分區(qū),這稱為掛載(mount)根文件系統(tǒng)。其他分區(qū)上的所有目錄、文件的集合,稱為文件系統(tǒng)。
為什么需要根文件系統(tǒng)?
1)init進(jìn)程的應(yīng)用程序在根文件系統(tǒng)上;
2)根文件系統(tǒng)提供了根目錄/;
3)內(nèi)核啟動(dòng)后的應(yīng)用層配置(etc目錄)在根文件系統(tǒng)上。可以認(rèn)為:發(fā)行版=內(nèi)核+rootfs。
4)shell命令程序在根文件系統(tǒng)上。譬如ls、cd等命令。
因此,一套Linux體系,只有內(nèi)核本身是不能工作的,必須要rootfs(上的etc目錄下的配置文件、/bin與/sbin等目錄下的shell命令,還有/lib目錄下的庫(kù)文件等)相配合才能工作。
(2)根文件系統(tǒng)概述
Linux中的根文件系統(tǒng)更像是一個(gè)文件夾或者叫做目錄(特殊的文件夾),在這個(gè)目錄里面會(huì)有很多的子目錄。
根目錄下和子目錄中會(huì)有很多的文件,這些文件是Linux運(yùn)行所必須的,比如庫(kù)、常用的軟件和命令、設(shè)備文件、配置文件等等。
根文件系統(tǒng)和Linux內(nèi)核是分開(kāi)的,單獨(dú)的Linux內(nèi)核是沒(méi)法正常工作的,必須要搭配根文件系統(tǒng)。
(3)根文件系統(tǒng)的結(jié)構(gòu)
Linux的根文件系統(tǒng)是采用級(jí)層式的樹(shù)狀目錄結(jié)構(gòu),在此結(jié)構(gòu)中的最上層是根目錄“/”,然后在此目錄下再創(chuàng)建其他的目錄。樹(shù)的根結(jié)點(diǎn)為根目錄root。
其中:
1)/root 系統(tǒng)管理員的主目錄
2)/bin 存放二進(jìn)制可執(zhí)行命令的目錄
3)/boot 存放的是啟動(dòng)Linux時(shí)使用的一些核心文件,包括一些連接文件以及鏡像文件。
4)/dev 存放設(shè)備文件的目錄
5)/etc 存放系統(tǒng)管理和配置文件的目錄
6)/home 用戶主目錄
7)/lib 存放動(dòng)態(tài)鏈接共享庫(kù)的目錄
8)/sbin存放系統(tǒng)管理員使用的管理程序的目錄
9)/mnt 系統(tǒng)提供這個(gè)目錄是讓用戶臨時(shí)掛載其他的文件系統(tǒng)
10)/proc 虛擬文件系統(tǒng)
11)/usr 最龐大的目錄
12)/var某些大文件的溢出區(qū)
13)/tmp 公用的臨時(shí)文件存儲(chǔ)點(diǎn)
一般我們?cè)贚inux驅(qū)動(dòng)開(kāi)發(fā)的時(shí)候都是通過(guò)nfs掛載根文件系統(tǒng)的,當(dāng)產(chǎn)品最終上市開(kāi)賣的時(shí)候才會(huì)將根文件系統(tǒng)燒寫到EMMC或者NAND中。
1)修改Makefile,添加編譯器;
2)配置busybox ;
3)編譯busybox ;
4)向根文件系統(tǒng)添加lib庫(kù)(完成基本根文件系統(tǒng));
5)創(chuàng)建其他文件夾;
6)完善根文件系統(tǒng)。
Linux系統(tǒng)掛載完根文件系統(tǒng)之后,就會(huì)執(zhí)行init程序,創(chuàng)建init進(jìn)程。執(zhí)行過(guò)程大概如下圖所示。
審核編輯:劉清
-
處理器
+關(guān)注
關(guān)注
68文章
19407瀏覽量
231186 -
嵌入式
+關(guān)注
關(guān)注
5092文章
19177瀏覽量
307679 -
SDRAM
+關(guān)注
關(guān)注
7文章
430瀏覽量
55368 -
Linux系統(tǒng)
+關(guān)注
關(guān)注
4文章
595瀏覽量
27510 -
SoC芯片
+關(guān)注
關(guān)注
1文章
617瀏覽量
35041
原文標(biāo)題:嵌入式 Linux 移植與系統(tǒng)啟動(dòng)
文章出處:【微信號(hào):嵌入式開(kāi)發(fā)愛(ài)好者,微信公眾號(hào):嵌入式開(kāi)發(fā)愛(ài)好者】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論