1-系統(tǒng)移植_u-boot移植

c語(yǔ)言、匯編、腳本、Makefile、Kconfig、設(shè)備樹(shù)


裝windows:BIOS界面、運(yùn)行系統(tǒng)內(nèi)核、安裝驅(qū)動(dòng)、裝軟件
移植就是給一個(gè)開(kāi)發(fā)板裝一個(gè)系統(tǒng):學(xué)完這門(mén)課之后我們都是嵌入式的網(wǎng)管
嵌入式平臺(tái):引導(dǎo)程序(u-boot)、uImage、寫(xiě)驅(qū)動(dòng)(改驅(qū)動(dòng))、第三方源碼(相當(dāng)于一個(gè)應(yīng)用軟件)

* 什么是移植?軟件系統(tǒng)移植、硬件系統(tǒng)移植

一個(gè)平臺(tái)的代碼應(yīng)用到另一個(gè)不同體系的平臺(tái)上,需要做的工作就是移植

在移植過(guò)程中:
  • 虛擬內(nèi)存空間分配:用戶(hù)空間、內(nèi)核空間(文件系統(tǒng),驅(qū)動(dòng),內(nèi)存管理,網(wǎng)絡(luò)協(xié)議棧,設(shè)備管理,中斷,進(jìn)程管理)
  • 上層的open和內(nèi)核的open有什么關(guān)系?
struct file_operations
{
    int (*open)(struct *file,);
}
交叉編譯器
  • x86 arm 交叉編譯器:在x86平臺(tái)編寫(xiě)代碼,然后通過(guò)交叉編譯器編譯后生成了適用于arm平臺(tái)的二進(jìn)制代碼
  • arm-none-linux-gnueabi-gcc
編譯過(guò)程:
  • 預(yù)處理 gcc -E 1.c -o 1.i 或 cpp(預(yù)處理器) 1.c -o 1.i
  • 編譯 gcc -S 1.i -o 1.s 或 cc1(編譯器) 1.i -o 1.s
  • 匯編 gcc -c 1.s -o 1.o 或 as(匯編器) 1.s -o 1.o
  • 鏈接 gcc 1.o 或 ld -m elf_i386 -dynamic-linker /lib/ld-linux.so.2 -o 1 1.o /usr/lib/i386-linux-gnu/crt1.o
  • /usr/lib/i386-linux-gnu/crti.o /usr/lib/gcc/i686-linux-gnu/4.6/crtbegin.o -lc
  • /usr/lib/gcc/i686-linux-gnu/4.6/crtend.o /usr/lib/i386-linux-gnu/crtn.o
  • 鏈接器調(diào)用.o文件,.o文件中包含分段信息。
  • .data .text .bss .rodata
nm 二進(jìn)制文件 顯示二進(jìn)制文件中符號(hào)表的信息
  • 顯示的內(nèi)容包含3列:

  • 內(nèi)存地址 屬于哪個(gè)分段 符號(hào)名稱(chēng)

  • 大寫(xiě)字母代表全局

  • 小寫(xiě)字母代表局部

  • T D B R W

void fun() __atteibute__((weak));
//將fun函數(shù)變成弱標(biāo)號(hào),如果沒(méi)有調(diào)用的話(huà)不會(huì)報(bào)錯(cuò),編譯器會(huì)直接忽略掉fun相關(guān)鏈接操作

strip 二進(jìn)制文件 清除二進(jìn)制文件中的符號(hào) 清除符號(hào)表的目的是為了節(jié)省資源
什么是符號(hào)?函數(shù)名或者變量名
符號(hào)什么作用? 符號(hào)是給鏈接器使用的或者說(shuō)鏈接器通過(guò)符號(hào)的名字來(lái)找到了代碼分段的位置
鏈接器在生成可執(zhí)行文件時(shí)要使用符號(hào),如果符號(hào)被清除,那么鏈接器失效。所以strip不要對(duì)中間文件進(jìn)行瘦身。

在操作開(kāi)發(fā)板前要先對(duì)u-boot進(jìn)行配置。

u-boot有兩種模式:交互模式,自啟動(dòng)模式.
  • 在配置時(shí)要進(jìn)入到交互模式中,一旦配置好之后使用自啟動(dòng)模式.
  • 在交互模式中的命令操作:注意這里的命令不是shell命令。
設(shè)置環(huán)境變量?jī)?nèi)容:
  • setenv 環(huán)境變量名 內(nèi)容
  • 例如:setenv serverip 172.21.1.250
刪除環(huán)境變量:
  • setenv 環(huán)境變量名
setenv bootargs root=/dev/nfs nfsroot=172.21.1.250:/rootfs rw console=ttySAC2,115200 init=/linuxrc  ip=開(kāi)發(fā)板的ip地址
//使用nfs服務(wù),通過(guò)nfs服務(wù)掛載/rootfs,創(chuàng)建了init進(jìn)程

setenv bootcmd tftp 41000000 uImage\;tftp 42000000 exynos4412-fs4412.dtb\;bootm 41000000 - 42000000
//tftp 41000000 uImage 在u-boot中通過(guò)tftp命令從Ubuntu的/tftpboot目錄下下載uImage文件到開(kāi)發(fā)板的偏外內(nèi)存41000000地址處

//三星手冊(cè)給的偏外內(nèi)存最大地址范圍40000000 - A0000000 1.5G 我們實(shí)際用的是40000000 - 8000000 1G

//bootm 內(nèi)核鏡像地址 文件系統(tǒng)鏡像地址 設(shè)備樹(shù)二進(jìn)制文件地址   這三個(gè)地址順序不能改變.
//本質(zhì):1、類(lèi)似于go命令有跳轉(zhuǎn)到指定地址的作用
      2、可以給內(nèi)核傳遞參數(shù)
//2.4 2.6 3.0不支持設(shè)備樹(shù)  ————————   3.1x可以選擇是否支持設(shè)備樹(shù)

u-boot移植:

配置過(guò)程:
  • 1、自己去百度
  • 2、每個(gè)源碼頂層目錄下都會(huì)有一個(gè)README文件,查看README文件知道配置方法為:make 板子名稱(chēng)_config
    • 我們?nèi)A清的板子叫做FS4412,這個(gè)板子包含了——SOC,外設(shè).
    • 其中SOC還有分類(lèi),exynos就是SOC中的某一類(lèi),我們FS4412使用的SOC是exynos系列的芯片,這個(gè)芯片系列三星公司規(guī)定必須以origen為模板。
    • 所以配置時(shí)可以執(zhí)行 make origen_config
  • 為什么要配置?
    • 因?yàn)槭褂昧薽ake命令所以會(huì)用到Makefile文件。
    • 在使用一個(gè)大型Makefile時(shí),一定要先確定入口,千萬(wàn)別從第一行開(kāi)始讀。
    • 通過(guò)make origen_config 可以知道當(dāng)前的Makefile入口是origen_config(也就是說(shuō)我們要去尋找目標(biāo)或者偽目標(biāo)叫做origen_config)
Makefile的基本機(jī)制:
  • Makefile的基本機(jī)制:顯示規(guī)則、隱式規(guī)則、變量、條件語(yǔ)句、函數(shù)
  • 顯示規(guī)則語(yǔ)法:
  • 目標(biāo)文件:依賴(lài)文件
    • 生成目標(biāo)文件的命令
    • 779 %_config:: unconfig
    • 780 @$(MKCONFIG) -A $(@:_config=)
查找變量的方法:
  • 1、/變量名
  • 2、命令模式下 按#
  • 3、通過(guò)ctags -R生成tags文件,然后ctrl ]
  • 4、make -p Makefile > 隨便一個(gè)文件名
  • $(@:_config=) 以$@為基礎(chǔ)添加一個(gè)規(guī)則,而這個(gè)規(guī)則的作用就是將_config替換為空,所以最終%_config會(huì)變成origen
  • @$(MKCONFIG) -A $(@:_config=) ==> @頂層目錄/mkconfig -A origen
* 文件系統(tǒng)移植:根文件系統(tǒng)的制作以及文件系統(tǒng)鏡像的制作
line=`egrep -i "^[[:space:]]*${2}[[:space:]]" boards.cfg`

line=origen               arm     armv7       origen      samsung    exynos
        $1                                                                $6
//-i忽略大小寫(xiě)
//[[:space:]]空格或者TAB

set $line 根據(jù)變量的內(nèi)容重置$#的值,當(dāng)前$#=6

57 CONFIG_NAME="${1%_config}" ==> CONFIG_NAME=origen

59 [ "${BOARD_NAME}" ] || BOARD_NAME="${1%_config}"  ==> BOARD_NAME=origen

61 arch="$2" ==> arm
62 cpu=`echo $3 | awk 'BEGIN {FS = ":"} ; {print $1}'`  ==> armv7
63 spl_cpu=`echo $3 | awk 'BEGIN {FS = ":"} ; {print $2}'`  spl_cpu=
64 if [ "$4" = "-" ] ; then
65     board=${BOARD_NAME}
66 else
67     board="$4" ==> board = origen
68 fi
69 [ $# -gt 4 ] && [ "$5" != "-" ] && vendor="$5" ==> samsung
70 [ $# -gt 5 ] && [ "$6" != "-" ] && soc="$6" ==> exynos

97     echo "Configuring for ${BOARD_NAME} board..."

113     cd ./include
114     rm -f asm
115     ln -s ../arch/${arch}/include/asm asm

123     ln -s ${LNPREFIX}arch-${soc} asm/arch  <==>     ln -s arch-exynos asm/arch
//當(dāng)我們創(chuàng)建軟鏈接時(shí)有一種用法是:如果當(dāng)前目錄下不存在源文件,會(huì)到目標(biāo)路徑下去尋找是否有源文件

128     ln -s ${LNPREFIX}proc-armv asm/proc
//到此為止我們發(fā)現(xiàn)產(chǎn)生了3個(gè)軟連接文件。無(wú)論換成什么平臺(tái)什么架構(gòu)我們只需要關(guān)心這些軟鏈接文件就可以,至于軟鏈接文件存放的路徑是隨平臺(tái)的改變而改變的。

134 ( echo "ARCH   = ${arch}"
135     if [ ! -z "$spl_cpu" ] ; then
136     echo 'ifeq ($(CONFIG_SPL_BUILD),y)'
137     echo "CPU    = ${spl_cpu}"
138     echo "else"
139     echo "CPU    = ${cpu}"
140     echo "endif"
141     else
142     echo "CPU    = ${cpu}"
143     fi
144     echo "BOARD  = ${board}"
145
146     [ "${vendor}" ] && echo "VENDOR = ${vendor}"
147     [ "${soc}"    ] && echo "SOC    = ${soc}"
148     exit 0 ) > config.mk
在config.mk中存放5個(gè)變量的賦值:
ARCH = arm
CPU = armv7
BOARD = origen
VENDOR = samsung
SOC = exynos
config.mk文件會(huì)被頂層目錄的Makefile引用,然后將里面的變量變成全局
154     BOARDDIR=${vendor}/${board} ==> samsung/origen
164     > config.h 創(chuàng)建一個(gè)空的config.h頭文件

echo "#define CONFIG_SYS_ARCH  \"${arch}\""  >> config.h
174 echo "#define CONFIG_SYS_CPU   \"${cpu}\""   >> config.h
175 echo "#define CONFIG_SYS_BOARD \"${board}\"" >> config.h
176
177 [ "${vendor}" ] && echo "#define CONFIG_SYS_VENDOR \"${vendor}\"" >> config.h
178
179 [ "${soc}"    ] && echo "#define CONFIG_SYS_SOC    \"${soc}\""    >> config.h
180
181 cat << EOF >> config.h
182 #define CONFIG_BOARDDIR board/$BOARDDIR
183 #include <config_cmd_defaults.h>
184 #include <config_defaults.h>
185 #include <configs/${CONFIG_NAME}.h>
186 #include <asm/config.h>
187 #include <config_fallbacks.h>
188 #include <config_uncmd_spl.h>
189 EOF
將一些宏定義和系統(tǒng)頭文件存放到include/config.h頭文件中
配置u-boot的功能:產(chǎn)生了3個(gè)軟鏈接,include/config.mk include/config.h
常用的Makefile命名:GNUmakefile makefile Makefile
.mk .Linux .AIX

編譯過(guò)程:

  • make all
428 all:        $(ALL-y) $(SUBDIR_EXAMPLES)
//ALL-y = u-boot.bin 所以后續(xù)要去以u(píng)-boot.bin為目標(biāo)

411 ALL-y += $(obj)u-boot.srec $(obj)u-boot.bin $(obj)System.map
443 $(obj)u-boot.bin:   $(obj)u-boot
444         $(OBJCOPY) ${OBJCFLAGS} -O binary $< $@
445         $(BOARD_SIZE_CHECK)

//要生成u-boot.bin必須事先生成u-boot,所以要搜索u-boot目標(biāo)
570 $(obj)u-boot:   depend \
571         $(SUBDIR_TOOLS) $(OBJS) $(LIBBOARD) $(LIBS) $(LDSCRIPT) $(obj)u-boot.lds
572         $(GEN_UBOOT)

248 OBJS := $(addprefix $(obj),$(OBJS) $(RESET_OBJS-))

236 OBJS  = $(CPUDIR)/start.o

B=
A=$(B)
//ifdef A 判斷的是變量A是否有內(nèi)容,如果有內(nèi)容成立,沒(méi)有內(nèi)容不成立

LDSCRIPT=arch/arm/cpu/u-boot.lds

561 GEN_UBOOT = \
562         UNDEF_LST=`$(OBJDUMP) -x $(LIBBOARD) $(LIBS) | \
563         sed  -n -e 's/      .*(_u_boot_list_.*)/-u\1       /p'|sort|uniq`;\

564         cd $(LNDIR) && $(LD) $(LDFLAGS) $(LDFLAGS_$(@F)) \
565             $$UNDEF_LST $(__OBJS) \
566             --start-group $(__LIBS) --end-group $(PLATFORM_LIBS) \
567             -Map u-boot.map -o u-boot

// sed基本功能用來(lái)字符串替換的
// \1的作用是用來(lái)標(biāo)記的,標(biāo)記的是前面的括號(hào)內(nèi)部的內(nèi)容
// -u\1作用就是用-u替換標(biāo)記前面的內(nèi)容
/ /所以替換完成后是 -u_u_boot_list_.*


// -u\1的用法:sed -n  -e 's/.*(_u_boot)_list_.*/-u\1' 替換后變成-u_u_boot_list_.*
// \1-u用法:sed -n -e 's/.*_u_boot-u'
// $(@F) <==> $(notdir $@)
驗(yàn)證:
  • abc=/home/linux/Makefilex
  • info=$(notdir $(abc))
start:
    echo $(info)
最終結(jié)果為Makefilex,無(wú)論有沒(méi)有這個(gè)文件,我們關(guān)心的是能否去掉文件前的路徑

$(LDFLAGS_$(@F)) 轉(zhuǎn)化完成后為 LDFLAGS_u-boot
LDFLAGS_u-boot = -pie -T $(obj)u-boot.lds $(LDFLAGS_FINAL) -Ttext $(CONFIG_SYS_TEXT_BASE)

-pie -T u-boot.lds為了告訴鏈接器,根據(jù)u-boot.lds的內(nèi)容哪些分段是需要鏈接的哪些分段是需要拋棄的。

312 LDFLAGS_FINAL = -Bstatic 所有內(nèi)容進(jìn)行靜態(tài)鏈接
-Ttext 0x43e00000  一旦進(jìn)行鏈接后,u-boot.lds中的00000000地址會(huì)被替換成0x43e00000
--start-group $(__LIBS) --end-group 指定一組庫(kù)的二進(jìn)制文件
上面一堆操作我們重點(diǎn)關(guān)心鏈接器鏈接時(shí)用到哪些內(nèi)容?
  • 1、分段,符號(hào),分段和符號(hào)是一堆.o文件提供的
  • 2、用到哪些分段u-boot.lds指定的
    分段相對(duì)于符號(hào)來(lái)講是一個(gè)整體,分段是包含符號(hào)的。
    u-boot.map會(huì)告訴鏈接器,在鏈接時(shí)使用到的符號(hào)對(duì)應(yīng)的地址是什么
鏈接最終的結(jié)果生成的u-boot可執(zhí)行文件,再通過(guò)objcopy將u-boot轉(zhuǎn)化為u-boot.bin
理論來(lái)講這個(gè)u-boot.bin可以燒寫(xiě)到開(kāi)發(fā)板上了。但是三星板子不允許。
* 我們最終用的u-boot-fs4412.bin包含u-boot.bin、bl1、bl2、填充代碼、trustzone
開(kāi)發(fā)板——SOC、外設(shè)
  • SOC內(nèi)部——CPU(cortex-a9)、外設(shè)控制器、IROM、IRAM
  • 我們的SOC三星公司給取名為exynos4412
  • 在SOC內(nèi)部的IROM中固化了一部分代碼叫做bl0,bl0的作用是將bl1加載到IRAM中運(yùn)行,bl1是三星提供的二進(jìn)制文件,作用是初始化硬件
    同時(shí)將bl2加載到IRAM中運(yùn)行,bl2是u-boot.bin的前14k,這14K的主要作用是計(jì)算出片外內(nèi)存可用的高位地址,然后將u-boot.bin整體
    搬移到計(jì)算出的高位地址中去運(yùn)行。
linux內(nèi)核:主版本號(hào).次版本號(hào).修訂版本號(hào)
通常情況下次版本號(hào)為偶數(shù)的是穩(wěn)定版本。www.kernel.org
2.4devfs 2.6sysfs 3.0 3.1x sysfs
選擇內(nèi)核版本時(shí),不要選擇比較老的版本,最好不要選擇最新版本。
linux重要的目錄:
  • arch存放的是和體系架構(gòu)相關(guān)的代碼
  • Documentation存放說(shuō)明文檔
  • drivers存放驅(qū)動(dòng)代碼
  • init/main.c 存放了內(nèi)核啟動(dòng)代碼的c語(yǔ)言程序
  • include 存放的是頭文件

linux內(nèi)核:

配置
  • 方法:
    • 1、make exynos(芯片名稱(chēng))_defconfig
    • 2、cp arch/arm/configs/exynos_defconfig .config
  • 目的: 通過(guò)配置方法讓內(nèi)核的功能只支持當(dāng)前平臺(tái)。
如何對(duì)內(nèi)核進(jìn)行軟件裁剪:make menuconfig
  • 注意:
    • 1、在頂層目錄
    • 2、屏幕不能太小
    • 3、第一次在執(zhí)行make menuconfig時(shí)會(huì)不成功,可能是因?yàn)闆](méi)安裝一個(gè)軟件包
進(jìn)入menuconfig后選項(xiàng)的種類(lèi)主要使用3種:
  • [] 有兩種狀態(tài)——選中和未選中
  • <> 有三種狀態(tài)——選中和未選中、模塊
  • () 可以存放十進(jìn)制整數(shù),十六進(jìn)制整數(shù)、字符串
  • 內(nèi)核選項(xiàng)是如何添加到menuconfig中的?必須要先學(xué)習(xí)Kconfig語(yǔ)法
Kconfig中的屬性:
  • source "路徑/Kconfig" 引用某個(gè)路徑下的Kconfig文件
  • config 字符串
  • 例如config ABC 我們會(huì)在頂層目錄下的.config文件中尋找到CONFIG_ABC這個(gè)變量。同時(shí)CONFIG_ABC還有可能出現(xiàn)在Makefile文件中
  • bool "字符串" 這個(gè)字符串就是menuconfig中的一個(gè)選項(xiàng)名稱(chēng),bool代表了選項(xiàng)[]
  • tristate "字符串" 代表了<>
  • string "字符串" 代表了(),這個(gè)小括號(hào)中只能存放字符串
  • int "字符串" 代表了(),這里存放十進(jìn)制整數(shù)
  • hex "字符串" 代表了(),智力存放十六進(jìn)制整數(shù)
  • menu,endmenu 這兩個(gè)配對(duì)使用,當(dāng)一個(gè)選項(xiàng)有子選項(xiàng)時(shí)使用
  • default y | n | m | 字符串 | 整數(shù)
  • depends on 字符串 當(dāng)前選項(xiàng)的出現(xiàn)要依賴(lài)另一個(gè)選項(xiàng)是否選中,而另一個(gè)選項(xiàng)是誰(shuí)?通過(guò)字符串來(lái)尋找的
假設(shè)需要操作一個(gè)設(shè)備。而且內(nèi)核中已經(jīng)有驅(qū)動(dòng)來(lái)支持這個(gè)設(shè)備,但這個(gè)驅(qū)動(dòng)相關(guān)選項(xiàng)沒(méi)有選中,如何找到這個(gè)選項(xiàng)?
  • 1、確定用到哪個(gè)具體的驅(qū)動(dòng)程序。假設(shè)這個(gè)驅(qū)動(dòng)程序叫做test.c
  • 2、一旦找到驅(qū)動(dòng)程序所在路徑,進(jìn)入這個(gè)路徑下的Makefile中,尋找obj-$(CONFIG_ABC) += test.o
  • 3、還在當(dāng)前目錄下進(jìn)入Kconfig文件,尋找ABC,找到ABC之后可以知道這個(gè)驅(qū)動(dòng)用哪個(gè)選項(xiàng)了

編譯

啟動(dòng)


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,545評(píng)論 19 139
  • linux資料總章2.1 1.0寫(xiě)的不好抱歉 但是2.0已經(jīng)改了很多 但是錯(cuò)誤還是無(wú)法避免 以后資料會(huì)慢慢更新 大...
    數(shù)據(jù)革命閱讀 13,216評(píng)論 2 33
  • Ubuntu的發(fā)音 Ubuntu,源于非洲祖魯人和科薩人的語(yǔ)言,發(fā)作 oo-boon-too 的音。了解發(fā)音是有意...
    螢火蟲(chóng)de夢(mèng)閱讀 100,621評(píng)論 9 468
  • 2014-05-26 21:21:38構(gòu)建Linux 編譯Linux BeagleBone Black 14年即將...
    外星間諜閱讀 3,619評(píng)論 0 9
  • 開(kāi)春,氣溫回升。閑暇時(shí)候,人總想出去走走,畢竟在家都宅了一個(gè)冬天。而養(yǎng)寵物的朋友,尤其是養(yǎng)狗狗的朋友,也都愿意帶著...
    有寵閱讀 403評(píng)論 0 0

友情鏈接更多精彩內(nèi)容