內(nèi)核的編譯:
- make uImage
- 1、在頂層目錄下搜索uImage發(fā)現(xiàn)找不到,有可能uImage存在于其他的Makefile文件中
- 2、include arch/arm/Makefile
- 3、進(jìn)入到arch/arm/Makefile中,尋找uImage目標(biāo)
299 BOOT_TARGETS = zImage Image xipImage bootpImage uImage 304 $(BOOT_TARGETS): vmlinux(頂層目錄下的) 305 $(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $(boot)/$@ boot := arch/arm/boot- 4、進(jìn)入到arch/arm/boot目錄下尋找uImage目標(biāo)
78 $(obj)/uImage: $(obj)/zImage FORCE 79 @$(check_for_multiple_loadaddr) 80 $(call if_changed,uimage) 81 @$(kecho) ' Image $@ is ready'- 如果需要生成uImage,必須依賴zImage
- 5、搜索目標(biāo)zImage
54 $(obj)/zImage: $(obj)/compressed/vmlinux FORCE 55 $(call if_changed,objcopy)- 6、在arch/arm/boot/compressed/Makefile中尋找vmlinux目標(biāo)
185 $(obj)/vmlinux: $(obj)/vmlinux.lds $(obj)/$(HEAD) $(obj)/piggy.$(suffix_y).o \ 186 $(addprefix $(obj)/, $(OBJS)) $(lib1funcs) $(ashldi3) \ 187 $(bswapsdi2) FORCE 188 @$(check_for_multiple_zreladdr) 189 $(call if_changed,ld) 190 @$(check_for_bad_syms) // 如果要生成piggy.$(suffix_y).o,需要依賴 $(obj)/piggy.$(suffix_y) // 如果要生成$(obj)/piggy.$(suffix_y),要依賴$(obj)/../Image- 進(jìn)入到arch/arm/boot/Makefile,尋找Image目標(biāo)
47 $(obj)/Image: vmlinux(頂層目錄下的) 48 $(call if_changed,objcopy)- 以Image為源文件,調(diào)用了gzip命令生成了piggy.gzip
- ld鏈接器以5個.o文件為源文件生成了arch/arm/boot/compressed/vmlinux
- 7、返回到arch/arm/boot/Makefile,以arch/arm/boot/compressed/vmlinux調(diào)用objcopy命令生成了zImage
- 8、以zImage為源文件調(diào)用uimage命令生成uImage文件
- 總結(jié):uImage的生成,頂層目錄下生成vmlinux文件,通過vmlinux文件生成Image,Image調(diào)用gzip進(jìn)行壓縮最終生成了piggy.gzip,
- 調(diào)用ld鏈接器,以piggy.gzip.o和其它.o文件來進(jìn)行鏈接生成了zImage,zImage調(diào)用uimage命令生成uImage文件
啟動過程:
- 啟動過程:涉及到匯編和c,代碼都不需要記。我們需要做到的是用什么功能,了解某個部分的代碼。
- arch/arm/kernel/head.S內(nèi)核的最初啟動文件
1、設(shè)置特權(quán)模式并且屏蔽所有中斷
- 因?yàn)槲覀冃枰跏蓟恍┯布⑶艺{(diào)用協(xié)處理器指令,所以必須設(shè)置特權(quán)模式
中斷代碼還沒有設(shè)置完成
2、判斷u-boot給內(nèi)核傳遞的參數(shù)是設(shè)備樹還是tag結(jié)構(gòu)體
- 我們3.14內(nèi)核在和u-boot2013版本配合使用時默認(rèn)使用了設(shè)備樹
3、創(chuàng)建頁表
- 虛擬地址和物理地址的關(guān)系.如果要理解這個關(guān)系必須先了解什么是頁目錄,頁表,還有頁。
- 虛擬地址32位,在32位中分成3個部分:10 + 10 + 12
- 頁目錄 頁表 頁
- 1024項(xiàng) 1024項(xiàng) 1024項(xiàng)
也就是說我們可以把上面的頁目錄,頁表,頁都看成是數(shù)組,而虛擬地址分成的三個部分就是這三個數(shù)組的下標(biāo)
- 0x12345678
- 0001001000 1101000101 011001111000
4、使能并且開啟MMU
5、進(jìn)入到init/main.c中執(zhí)行start_kernel函數(shù)
- 執(zhí)行setup_arch();
- ==>setup_machine_fdt();接收了u-boot傳遞給內(nèi)核的設(shè)備樹地址然后去解析設(shè)備樹內(nèi)容
- console_init()控制臺初始化函數(shù),如果在它之前調(diào)用printk則輸入信息會被臨時存放到緩存區(qū)中
- vfs_caches_init()
- ==>mnt_init();
- ==>sysfs_init()初始化sysfs文件系統(tǒng),它的作用在驅(qū)動中講
- rest_init()
- ==>kernel_thread(kernel_init,,);
- kernel_init_freeable();
- ==>sys_open();//在應(yīng)用層中的open調(diào)用了sys_open,sys_open()函數(shù)最終幫助我們找到了驅(qū)動接口
- ==>prepare_namespace();
- ==>mount_root();
- ==> mount_nfs_root()通過nfs服務(wù)來掛載rootfs文件夾的
設(shè)備樹:
- 設(shè)備樹是干嘛的?設(shè)備樹是描述硬件信息的。
- 在操作系統(tǒng)內(nèi)核中驅(qū)動、設(shè)備、總線
- 總線上可以理解為既掛載了設(shè)備文件又掛載了驅(qū)動程序??偩€幫助我們?nèi)テヅ潋?qū)動和設(shè)備。
- 所以在使用總線的前提下我們要寫一個驅(qū)動程序和一個設(shè)備程序。這兩種程序都會被最終編譯到uImage文件中。
- 設(shè)備樹命名:.dts(設(shè)備樹的源文件) .dtb(設(shè)備樹的二進(jìn)制文件) .dtsi(設(shè)備樹的頭文件)
vi arch/arm/boot/dts/exynos4412-fs4412.dts
設(shè)備樹的基本語法:
節(jié)點(diǎn)和屬性:
- 每個設(shè)備樹文件都是從根節(jié)點(diǎn)開始的。其它的所有節(jié)點(diǎn)都必須包含于根節(jié)點(diǎn)。
/{
model = "字符串";對平臺或芯片的描述語句,這個屬性不重要。
compatible = "fs4412,key";在驅(qū)動中的某個結(jié)構(gòu)體成員內(nèi)容也必須是"fs4412,key"
reg = <寄存器首地址1 偏移量1 寄存器首地址2 偏移量2>;
節(jié)點(diǎn)@地址{ 為什么某些節(jié)點(diǎn)的后面會出現(xiàn)地址?這個地址為了區(qū)分同種設(shè)備中的不同子設(shè)備
};
標(biāo)號:節(jié)點(diǎn){為什么會有標(biāo)號?如果后面的設(shè)備需要調(diào)用當(dāng)前設(shè)備的所有信息的話,只需要調(diào)用標(biāo)號就可以了
};
interrupt-parent = <&gpx0>; 中斷父節(jié)點(diǎn),其中g(shù)px0是某個頭文件中一個標(biāo)號,引用標(biāo)號的方法要加&
interrupts = <中斷類型 中斷號 中斷觸發(fā)方式>
中斷類型:0代表SPI 1代表PPI
中斷號:6代表了EINT[6]來索引中斷號
觸發(fā)方式:1上升沿觸發(fā) 2下降沿觸發(fā) 4高電平 8低電平
};
根文件系統(tǒng):
- etc/:
- inittab:每行都有4個域,用:分隔
- 域1:域2:域3:域4
- 在嵌入式中前兩個幾乎不用.第三個域是一種動作,第四個域是完成具體動作使用到的命令或者腳本
- tmpfs、proc、sysfs都是文件系統(tǒng)類型,其中tmpfs可以被掛載多次,但是proc必須掛載到proc目錄下,sysfs必須掛載到/sys目錄下
- mount命令只能臨時掛載
- fstab文件可以永久掛載