1. u-boot是一款功能十分強大的bootloader,分析其代碼,獲悉bootloader的基本寫法。
2. 以sbc2410這塊開發板為例分析,u-boot版本為2010.03。
3. cpu相關部分
3.1 cpu在硬體上就是一個門陣列,是一個完全的邏輯器件,它提供了指令集,對cpu的控制就是靠對cpu發送相關指令實現的。這些指令是一連串的二進位碼,將這些二進位碼發送到cpu指令匯流排上就能控制cpu。bootloader就是這個二進位碼序列,編譯u-boot就是為了產生bootloader。產生後的bootloader檔案會被寫入flash,eeprom等儲存空間中,cpu會在啟動後自動載入運行bootloader中的二進位指令,從而啟動。
3.2 指令序列存放在何處?又該如何存放?順序如何?這些就要看lds檔案,一段的格式分開存放這些資料和指令。
3.2.1 sbc2410開發板的cpu是s3c2410,屬於arm 920t系列。對這個些列cpu的支援檔案在cpu/arm920t下,裡面有個u-boot.lds的檔案。內容如下:
<cpu/arm920t/u-boot.lds>
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
OUTPUT_ARCH(arm)
ENTRY(_start)
SECTIONS
{
. = 0x00000000;
. = ALIGN(4);
.text :
{
cpu/arm920t/start.o
(.text)
*(.text)
}
. = ALIGN(4);
.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
. = ALIGN(4);
.data : { *(.data) }
. = ALIGN(4);
.got : { *(.got) }
. = .;
__u_boot_cmd_start = .;
.u_boot_cmd : { *(.u_boot_cmd) }
__u_boot_cmd_end = .;
. = ALIGN(4);
__bss_start = .;
.bss (NOLOAD) : { *(.bss) . = ALIGN(4); }
_end = .;
}
網上有專門介紹這個lds檔案格式的文檔,這些知識是一定要掌握的,具體的就不多說了,看了文檔自己就能全看明白了。大體上能看出,起始地址是0x00000000,依次向下有如下幾個段.text .rodata .data .got .u_boot_cmd .bss (NOLOAD)。
3.3 最前面的是text段,裡面的代碼是 {
cpu/arm920t/start.o
(.text)
*(.text)
}
最先放的是cpu/arm920t/start.o (.text),即cpu/arm920t/start.o檔案的text段內容。這個檔案是cpu/arm920t/start.S編譯而得來的。
最先的一段
.globl _start
_start: b start_code
ldr pc, _undefined_instruction
ldr pc, _software_interrupt
ldr pc, _prefetch_abort
ldr pc, _data_abort
ldr pc, _not_used
ldr pc, _irq
ldr pc, _fiq
_undefined_instruction: .word undefined_instruction
_software_interrupt: .word software_interrupt
_prefetch_abort: .word prefetch_abort
_data_abort: .word data_abort
_not_used: .word not_used
_irq: .word irq
_fiq: .word fiq
存放的第一個指令是一個跳轉指令,後面是異常處理表,分別有相應的處理函數。
start_code:
mrs r0, cpsr
bic r0, r0, #0x1f
orr r0, r0, #0xd3
msr cpsr, r0
讓cpu工作在svc模式下
bl coloured_LED_init
bl red_LED_on
對LED燈的控制,以方便程式調試,但是是空函數。
#if defined(CONFIG_AT91RM9200DK) || defined(CONFIG_AT91RM9200EK)
ldr r0, =_start
ldr r1, =0x0
mov r2, #16
copyex:
subs r2, r2, #1
ldr r3, [r0], #4
str r3, [r1], #4
bne copyex
#endif
將異常處理表複製到0x0000000處,前面看到這個表就是放在此處的,所以不需操作。
#ifdef CONFIG_S3C24X0
# if defined(CONFIG_S3C2400)
# define pWTCON 0x15300000
# define INTMSK 0x14400008
# define CLKDIVN 0x14800014
#else
# define pWTCON 0x53000000
# define INTMSK 0x4A000008
# define INTSUBMSK 0x4A00001C
# define CLKDIVN 0x4C000014
# endif
通過宏定義了一些地址常量,具體這些寄存器的內容,需要看s3c2410手冊才行。
ldr r0, =pWTCON
mov r1, #0x0
str r1, [r0]
關閉watchdog功能,不然一到時間就cpu就複位了。
mov r1, #0xffffffff
ldr r0, =INTMSK
str r1, [r0]
# if defined(CONFIG_S3C2410)
ldr r1, =0x3ff
ldr r0, =INTSUBMSK
str r1, [r0]
# endif
將所有的中斷都mask掉,不響應
ldr r0, =CLKDIVN
mov r1, #3
str r1, [r0]
#endif
設定時鐘分頻,應該是cpu上某些部分使用不同的時鐘頻率。
stack_setup:
ldr r0, _TEXT_BASE
sub r0, r0, #CONFIG_SYS_MALLOC_LEN
sub r0, r0, #CONFIG_SYS_GBL_DATA_SIZE
#ifdef CONFIG_USE_IRQ
sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)
#endif
sub sp, r0, #12
留出空間,設定sp棧指標,此時可以運行C程式了
clear_bss:
ldr r0, _bss_start
ldr r1, _bss_end
mov r2, #0x00000000
清空bss段
clbss_l:str r2, [r0]
add r0, r0, #4
cmp r0, r1
ble clbss_l
ldr pc, _start_armboot
pc指向_start_armboot,即跳轉執行start_armboot
_start_armboot: .word start_armboot