單片機有最小系統,所謂最小系統,就是單片機能正常工作所需要的最少外設。對于Uboot來說,同樣有個最小系統,因為Uboot最主要的功能就是引導內核。下面我們通過一個簡單的Mini-Uboot來分析Uboot的啟動加載過程。(只是分析過程,此Uboot具有引導內核功能)
注:這個uboot 只是具有基本的內核引導功能,只是作為前期簡單的學習使用,入門而已,并不是正常的uboot 啟動流程
下面是mini-uboot 的根目錄樹狀圖:
我們拿到一個工程,想了解它的功能,最方便的就是讀它的makefile。
![]()
一、Makefile
![]()
[cpp] view plain copy
1. sinclude include/config.mk
2.
3. #ARCH=arm
4. #CPU=arm920t
5. #VENDOR=samsung
6. #SOC=s3c2410
7. #BOARD=smdk2410
8.
9. SRC_TREE:=$(shell pwd)
10. MKCONFIG=$(SRC_TREE)/mkconfig
11.
12. INCLUDE_PATH=include
13. DRIVER_PATH=driver
14. LIB_DIR=lib
15.
16.
17. CFLAG=-mabi=apcs-gnu -fno-builtin -fno-builtin-function -g -O0 -c -I$(INCLUDE_PATH) -I$(DRIVER_PATH) -o
18. LDFLAG=-Tcpu/arm/arm_cortexa8/map.lds -o
19. OBJS= cpu/$(ARCH)/$(CPU)/start.o
20. OBJS+=lib_arm/board.o
21. OBJS+=board/$(VENDOR)/$(BOARD)/lowlevel_init.o
22. OBJS+=board/$(VENDOR)/$(BOARD)/mem_setup.o
23. OBJS+=board/$(VENDOR)/$(BOARD)/nand.o
24. OBJS+=driver/uart.o
25. OBJS+=lib/string.o
26. OBJS+=common/do_go.o
27. OBJS+=common/main.o
28.
29. ifeq ($(ARCH), arm)
30. CROSS_COMPILE=arm-cortex_a8-linux-gnueabi-
31. endif
32.
33. PROJ_NAME=mini_uboot
34.
35. all: $(OBJS)
36. $(CROSS_COMPILE)ld $(OBJS) $(LDFLAG) $(PROJ_NAME).elf
37. $(CROSS_COMPILE)objcopy -O binary $(PROJ_NAME).elf $(PROJ_NAME).bin
38. $(CROSS_COMPILE)objdump -D $(PROJ_NAME).elf > $(PROJ_NAME).dis
39. cp *.bin /tftpboot
40.
41. %.o: %.S
42. $(CROSS_COMPILE)gcc $(CFLAG) $@ $<
43. %.o: %.s
44. $(CROSS_COMPILE)gcc $(CFLAG) $@ $<
45.
46. %.o: %.c
47. $(CROSS_COMPILE)gcc $(CFLAG) $@ $<
48.
49. fsc100_config: # ARCH CPU VENDOR BOARD SOC
50. $(MKCONFIG) $(@:_config=) arm arm_cortexa8 samsung fsc100 s5pc100
51. #mkconfig fsc100 arm arm_cortexa8 samsung fsc100 s5pc100
52.
53. smdk2410_config: # ARCH CPU VENDOR BOARD SOC
54. $(MKCONFIG) $(@:_config=) arm arm920t samsung smdk2410 s3c2410
55.
56. clean:
57. @rm -rf $(OBJS) *.bin *.elf config.mk
這里以2440為例,咱們來分析:
[cpp] view plain copy
1. #ARCH=arm
2. #CPU=arm920t
3. #VENDOR=samsung
4. #SOC=s3c2410
5. #BOARD=smdk2410
架構為arm,CPU為arm920t,生產商 samsung,片上系統sc2410,板子為smdk2410。
[cpp] view plain copy
1. OBJS= cpu/$(ARCH)/$(CPU)/start.o
2. OBJS+=lib_arm/board.o
3. OBJS+=board/$(VENDOR)/$(BOARD)/lowlevel_init.o
4. OBJS+=board/$(VENDOR)/$(BOARD)/mem_setup.o
5. OBJS+=board/$(VENDOR)/$(BOARD)/nand.o
6. OBJS+=driver/uart.o
7. OBJS+=lib/string.o
8. OBJS+=common/do_go.o
9. OBJS+=common/main.o
OBJS為依賴文件,生成的.o文件。
[cpp] view plain copy
1. ifeq ($(ARCH), arm)
2. CROSS_COMPILE=arm-cortex_a8-linux-gnueabi-
3. endif
根據相應的架構,制作相應的交叉編譯工具。
[cpp] view plain copy
1. all: $(OBJS)
2. $(CROSS_COMPILE)ld $(OBJS) $(LDFLAG) $(PROJ_NAME).elf
3. $(CROSS_COMPILE)objcopy -O binary $(PROJ_NAME).elf $(PROJ_NAME).bin
4. $(CROSS_COMPILE)objdump -D $(PROJ_NAME).elf > $(PROJ_NAME).dis
第一步:連接 ;第二步:格式轉換;第三步:反匯編 " >" 為重定向的意思;
[cpp] view plain copy
1. %.o: %.S
2. $(CROSS_COMPILE)gcc $(CFLAG) $@ $<
3. %.o: %.s
4. $(CROSS_COMPILE)gcc $(CFLAG) $@ $<
5.
6. %.o: %.c
7. $(CROSS_COMPILE)gcc $(CFLAG) $@ $<
將所有的.S 文件、.s文件、.c文件編譯成.o文件。
注意:.S文件可以在編譯過程接受參數,.s文件不可以。
![]()
二、鏈接文件
![]()
[cpp] view plain copy
1. OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
2. /*OUTPUT_FORMAT("elf32-arm", "elf32-arm", "elf32-arm")*/
3. OUTPUT_ARCH(arm)
4. ENTRY(_start) //指定入口地址
5. SECTIONS //段信息
6. {
7. /* . */
8. . = 0x22000000; //elf文件的入口地址
9. . = ALIGN(4); //指定四字節對齊
10. .text : //代碼段
11. {
12. cpu/arm/arm_cortexa8/start.o(.text) //確保執行的第一段代碼是start.o
13. *(.text) //所有代碼段融合在一起
14. }
15. . = ALIGN(4);
16. .rodata : //只讀數據段
17. { *(.rodata) } //所有數據段
18. . = ALIGN(4);
19. .data : //數據段
20. { *(.data) }
21. . = ALIGN(4);
22.
23. _start_bss = .; //bss段開始地址
24. .bss :
25. { *(.bss) }
26. _end_bss = .; //bss段結束地址,兩者可確定bss段大小
27. }
![]()
三、start.s文件(Uboot執行的第一個文件)
![]()
[cpp] view plain copy
1. @ 匯編中的宏
2. .equ USER_MODE, 0x10 @define USER_MODE 0x10
3. .equ IRQ_MODE, 0x12
4. .equ SVC_MODE, 0x13
5. .equ MODE_MASK, 0x1f
6.
7. .section .text
8. .global _start
9.
10. @ 不支持異常處理的,這里只寫了復位異常處理
11. _start:
12. vector:
13. b reset_handler
14. nop @undef ......
15. nop
16. nop
17. nop
18. nop
19. nop
20. nop
21.
22. reset_handler:
23. @step 1: svc close irq fiq //第一步:將運行模式改成SVC模式
24. mrs r0, cpsr //修改cpsr模式位
25. bic r0, r0, #0x1f
26. orr r0, r0, #0xc0 @IRQ FIQ //關閉IRQ FIQ
27. msr cpsr_c, r0
28.
29. @step 2: cache 關閉I CACHE D CACHE //第二步:關閉cache,直接運行,不需緩存
30. mrc p15, 0, r0, c12, c0, 0
31. bic r0, #0x1000
32. bic r0, #0x2
33. mcr p15, 0, r0, c12, c0, 0
34.
35. @step 3: //第三步:調用
電路板級初始化程序, system clock , dram, watchdog
36. @bl low_level_init //初始化時鐘、dram、關閉
看門狗 37.
38. @step 4: sp-> 0x30000000 //第四步:設置棧指針,使其指向一個地址即可
39. ldr sp, =0x2e000000
40.
41. @step 5: mini_uboot.bin > 16KB bin < 16KB
42. @step 5 代碼自搬移
43. @copy_miniuboot_rto_sdram 如果你的代碼大于了16KB代碼需要實現自我搬移
44.
45. @step 6: //第六步:清除BSS段,BSS段大小由鏈接文件里確定
46. @STEP 6.1 , 清除 BSS段
47. @
48. clear_bss:
49. ldr r0, =_start_bss @| BSS 起始地址
50. ldr r1, =_end_bss @| BSS 終止地址
51. mov r2, #0
52. bss_loop:
53. cmp r0, r1
54. strne r2, [r0], #4
55. bne bss_loop
56.
57. @step 7, 進入C //跳轉到C程序入口
58. b start_armboot
59. stop:
60. b stop
61.
62. .end