1. 程式人生 > >核心執行之前的載入程式uboot --- 地址問題

核心執行之前的載入程式uboot --- 地址問題

Android系統的核心要載入並執行,其實是經歷了千辛萬苦的,因為萬事開頭難。在一個系統剛開始時,並沒有什麼資源可以使用,CPU只認得0x00000000地址,並從那裡執行第一條指令,並且這段程式碼有大小限制,不可以很大。因此需要開發一個載入程式放在那裡執行,在這裡的培訓課程裡,主要使用是S3C6410開發板,並且使用UBoot作為載入程式(Bootloader)。UBoot是一個很通用的載入程式,並且在嵌入式系統的應用裡非常廣泛,功能也相當強大,設計的架構相當靈活,很方便移植到不同的嵌入式裝置裡。

從前面知道ARMCPU是固定從0x00000000開始執行的,那麼UBoot的編譯出來的大小,是放不到0x00000000的記憶體空間的,那麼UBoot

又是怎麼樣獲得控制權呢?其實在S3C6410裡可以通過CPU的管腳設定不同的電平,可以選擇執行CPU內部的程式,然後讓這段小程式載入UBoot到合適地址執行。那麼接著下來的問題就是UBoot放到那裡才是合適的地址?要理解這個合適地址,就需要看S3C6410的手冊了,通過閱讀這個手冊,就會發現CPU的記憶體是固定在兩個地址空間,如下:

0x50000000--0x5FFFFFFF大小為256M

0x60000000--0x6FFFFFFF大小為256M

由此可知,所有記憶體RAM都必須放到這段地址空間,也就是實體地址空間,因此UBoot就必須載入到這段記憶體空間裡才可以執行,那麼UBoot在編譯時是否需要知道在那裡執行呢?答案是需要的。

UBoot執行時,有很多資料是需要找到對記憶體地址定址。在UBoot編譯時,就作出如下指定:

TEXT_BASE= 0xc7e00000

譁,這裡的地址為什麼是0xc7e00000的呢?難道是寫錯了嗎?其實這裡是大有文章的,與其相關的內容就是MMU了,所謂的MMU就是一個記憶體對映的硬體,主要作用就是把無限的虛擬記憶體地址空間對映到有限的實體記憶體地址空間,作用就是複用實體記憶體,方便編譯所有軟體。由此可知,UBoot是編譯到虛擬地址0xc7e00000執行,在未有開啟MMU之前,它的實體地址是0x57e00000,其實在實體地址上來看來是同一個地方。

從前面的可以知道UBoot真實執行的實體地址是0x57e00000,相對應的虛擬地址是0xc7e00000,這段地址相對於

256記憶體來說是一個高階地址,為什麼要放到這個地址執行,而不放到0x50000000的實體地址(虛擬機器地址0xC0000000)執行呢?其實這是為了後面的核心linux執行做好準備,否則就會相互打架,整個系統執行就出錯。從UBoot編譯後的記憶體映像檔案可以看到相關資訊:

c7e00000T _start

c7e00020t _undefined_instruction

c7e00024t _software_interrupt

c7e00028t _prefetch_abort

c7e0002ct _data_abort

c7e00030t _not_used

c7e00034t _irq

c7e00038t _fiq

c7e0003ct _pad

c7e00040T _end_vect

c7e00040t _TEXT_BASE

c7e00044t _TEXT_PHY_BASE

c7e00048T _armboot_start

c7e0004cT _bss_start

c7e00050T _bss_end

c7e00054t reset

這段映像檔案就說明所有開始程式碼都是相對0xc7e00000開始的,包括所有資料訪問。在UBootMMU配置裡,用下面的程式碼來把實體地址0x50000000對映到虛擬地址0xc0000000,如下:

//128MB for SDRAM 0xC0000000 -> 0x50000000

.set__base, 0x500

.rept0xD00 - 0xC00

FL_SECTION_ENTRY__base,3,0,1,1

.set__base,__base+1

.endr

載入程式載入執行,做好充分準備之後就可以載入核心運行了。它載入核心地址也是有講究的,一般linux核心需要載入在0x50008000的實體地址開始,因此虛擬地址就是0xc0008000了,這樣就可以把核心載入在低端執行,高階地址就可以給所有應用程式運行了。

總結一下,CPU0x00000000開始執行Flash的程式,然後把UBoot重定位到實體地址0x57e00000(虛擬地址0xc7e00000)執行,然後開啟MMU,就對應在虛擬地址0xc7e00000執行,然後載入核心到虛擬地址0xc0008000(實體地址0x50008000),然後再跳到這個地址裡執行,因此UBoot要指定虛擬地址0xc7e00000作來連線程式的基地址。

Config.mk有下面一段話:

# SMDK6410 has a 128 MB SDR SDRAM
#
# 5000'0000 to 5800'0000
#
#
# Linux-Kernel is expected to be at 5000'8000, entry 5000'8000
# optionally with a ramdisk at 5080'0000
#
# we load ourself to 57e0'0000 without MMU
# with MMU, load address is changed to 0xc7e0_0000
#
# download area is 5000'0000
#


ifndef TEXT_BASE
TEXT_BASE = 0xc7e00000
endif

S3C6410datasheet地址如下:

DRAM Controller of the Memory Port1  :
         Address                Size(MB)         
0x5000_0000    0x5FFF_FFFF       256MB 
0x6000_0000    0x6FFF_FFFF       256MB