新聞中心

EEPW首頁(yè) > 嵌入式系統(tǒng) > 設(shè)計(jì)應(yīng)用 > ARM的啟動(dòng)代碼(3):異常向量

ARM的啟動(dòng)代碼(3):異常向量

作者: 時(shí)間:2016-11-10 來(lái)源:網(wǎng)絡(luò) 收藏
ARM啟動(dòng)代碼是非常重要的代碼,直接關(guān)系到系統(tǒng)的穩(wěn)定性和可靠性(這里主要討論arm7,arm9;cortex系列的會(huì)在后續(xù)的文章中討論)。上次我們通過(guò)兩則文章討論了ARM啟動(dòng)代碼的過(guò)程,

ARM的啟動(dòng)代碼(1):介紹

本文引用地址:http://butianyuan.cn/article/201611/317543.htm

ARM的啟動(dòng)代碼(2):AT91SAM9260啟動(dòng)詳解

這次我們聊聊ARM的代碼的具體編寫。那么什么樣的代碼會(huì)涉及到這些問(wèn)題呢?

1.Bootloader或者位于啟動(dòng)序列上進(jìn)行加載其他應(yīng)用程序的程序;

2.單獨(dú)的二進(jìn)制鏡像,直接可以在ARM處理器上直接執(zhí)行。

這兩種代碼都需要對(duì)ARM的啟動(dòng)過(guò)程有深入理解。說(shuō)深入理解,其實(shí)只有一條,鬧鬧記住,ARM7,ARM9的異常向量表從地址0開(kāi)始。這是鐵打不能改變的事實(shí)。這樣一來(lái),所有的程序都要用0地址存儲(chǔ)自己的向量表,這豈不是成了稀缺資源。所以不同家的ARM芯片都提供了一些辦法解決這種問(wèn)題。

對(duì)于arm7,很多芯片使用片內(nèi)的flash。如at91sam7x256。為了方便,經(jīng)常需要bootloader+應(yīng)用程序的方式。At91sam7x256提供了一個(gè)叫bootMemory的地址,1Mbytes,從0x0~0x000FFFFF??梢杂成涑蔀閮?nèi)部的Flash和內(nèi)部的SRAM。這個(gè)映射是:

BootMemory:0x0~0x000FFFFF,1Mbytes

InternalFlash:0x00100000~0x001FFFFF,1Mbytes

InternalSRAM:0x00200000~0x002FFFFF,1Mbytes

當(dāng)BootMemory映射成InternalFlash,flash的地址仍然從0x00100000開(kāi)始,但是從0x0訪問(wèn),等同于訪問(wèn)0x00100000;當(dāng)映射成為InternalSRAM,SRAM地址不變,訪問(wèn)0x0地址,等同于訪問(wèn)0x00200000。其實(shí)硬件做起來(lái)很簡(jiǎn)單,就是將地址線用邏輯電路稍微處理一下。

由于代碼都要存放在FLASH里,否則,沒(méi)電以后,啥都沒(méi)有了,也無(wú)法再次啟動(dòng)。所以,異常向量要從0x0開(kāi)始,那么自然也要把向量放在這個(gè)位置,7x256上電以后默認(rèn)bootmemory映射從flash開(kāi)始。也就是說(shuō),把向量放在0x00100000即可解決這樣的問(wèn)題。

當(dāng)0x00100000被占用以后,bootloader的向量問(wèn)題解決了,那用戶代碼的中斷向量怎么辦呢?不可能把bootloader的向量擦了,把用戶自己的向量寫入,那豈不是bootloader也完了?這里有個(gè)小技巧,如果用戶程序從0x00101000開(kāi)始,向量依然從這個(gè)位置開(kāi)始。只不過(guò),在打開(kāi)中斷,向量真正起作用前,將0x00101000這個(gè)地方向量到SRAM的首地址上,然后切換BootMemory映射SRAM。那么向量依然從0x0開(kāi)始。這樣的話,無(wú)論多少級(jí)boot代碼,都可以完美的解決該問(wèn)題。

ARM9除了以上的方法,還有個(gè)終極的利器,那就是MMU,你高興放哪就放哪,在向量起作用之前,用MMU將其地址變換為0即可。一點(diǎn)技術(shù)含量都沒(méi)有。

道理總是簡(jiǎn)單的,實(shí)現(xiàn)起來(lái)總是有點(diǎn)點(diǎn)彎彎繞。我們看看實(shí)際的實(shí)現(xiàn)吧。這是7x256的向量代碼:

__vector:

LDR PC,[PC,#24];Absolutejumpcanreach4GByte

LDRPC,[PC,#24];Branchtoundef_handler

LDRPC,[PC,#24];Branchtoswi_handler

LDRPC,[PC,#24];Branchtoprefetch_handler

LDRPC,[PC,#24];Branchtodata_handler

DC320;Reserved

LDR PC,[PC,#24] ;Branchtoirq_handler

LDR PC,[PC,#24] ;Branchtofiq_handler

DC32_program_start

DC32ARM_ExceptUndefInstrHndlr

DC32ARM_ExceptSwiHndlr

DC32ARM_ExceptPrefetchAbortHndlr

DC32ARM_ExceptDataAbortHndlr

DC320

DC32ARM_ExceptIrqHndlr

DC32ARM_ExceptFiqHndlr

這里相對(duì)比較簡(jiǎn)單,對(duì)這個(gè)指令做一下解釋。LDR PC,[PC,#24]是將當(dāng)前PC+24的地址的值載入到PC寄存器中。由于ARM流水線的問(wèn)題,當(dāng)前執(zhí)行的指令,地址已經(jīng)是后面兩條了。所以,是+24并不是+32。也就是把_program_start加載入PC指針里。這段代碼已經(jīng)消除了指令當(dāng)前位置對(duì)跳轉(zhuǎn)位置的影響,可以隨意的拷貝到任意的地方去執(zhí)行。這段代碼放在0x200000地方,可以正常執(zhí)行;放在0x100000地方也可以正常執(zhí)行。

RTEMS的ARM9(CSB337)啟動(dòng)向量:

vector_block:

ldrpc,Reset_Handler

ldrpc,Undefined_Handler

ldrpc,SWI_Handler

ldrpc,Prefetch_Handler

ldrpc,Abort_Handler

nop

ldrpc,IRQ_Handler

ldrpc,FIQ_Handler

Reset_Handler:bbsp_reset

Undefined_Handler:bUndefined_Handler

SWI_Handler:bSWI_Handler

Prefetch_Handler:bPrefetch_Handler

Abort_Handler:bAbort_Handler

nop

IRQ_Handler:bIRQ_Handler

FIQ_Handler:bFIQ_Handler

Rtems是個(gè)復(fù)雜的操作系統(tǒng),在匯編代碼里安裝的只是一個(gè)簡(jiǎn)單的復(fù)位向量。其它向量都只是簡(jiǎn)單的死循環(huán)。操作系統(tǒng)運(yùn)行起來(lái)以后,還要再次安裝向量的。向量指向操作系統(tǒng)的復(fù)雜的處理函數(shù)。但不管這些,向量存儲(chǔ)的地址是沒(méi)有改變的。Link腳本上可以看到向量被放在內(nèi)部的SRAM的首地址上。(CSB337)

SECTIONS

{

.base:

{

_sram_base=.;

/*reserveroomforthevectorsandfunctionpointers*/

arm_exception_table=.;

.+=64;

連接器雖然把位置空出來(lái)了,但連接器依然不知道將vector_block放到什么位置。怎么辦?這里的代碼解釋了一切。

/*

*InitializetheMMU.Afterwereturn,theMMUisenabled,

*andmemorymayberemapped.Ihopewedontremapthis

*memoryaway.

*/

ldrr0,=mem_map

blmmu_init

/*

*Initializetheexceptionvectors.Thisincludesthe

*exceptionsvectors(0x00000000-0x0000001c),andthe

*pointerstotheexceptionhandlers(0x00000020-0x0000003c).

*/

movr0,#0

adrr1,vector_block

ldmiar1!,{r2-r9}

stmiar0!,{r2-r9}

ldmiar1!,{r2-r9}

stmiar0!,{r2-r9}

Gnu的工具鏈并不針對(duì)某一個(gè)具體的平臺(tái)。所以解決方案從某種意義上說(shuō),更具有普遍意義。先調(diào)用mmu_init,這是干什么,實(shí)際上是將MMU初始化,將我們定義的.base地址放到0x0位置去。然后緊接著下面的幾行代碼,是將上面的中斷向量到0x0位置去。一共64個(gè)字節(jié),實(shí)現(xiàn)4GB內(nèi)的地址絕對(duì)跳轉(zhuǎn)。



關(guān)鍵詞: ARM啟動(dòng)代碼異常向

評(píng)論


技術(shù)專區(qū)

關(guān)閉