2012-02-09 45 views
2

在尋找基本的裸機Cortex-M3編程信息時(我在稍後嘗試找到一個很好的答案中提到),我遇到了與以下內容類似的內容。ARM鏈接器如何知道異常錶停止的位置?

/* vectors.s */ 
.cpu cortex-m3 
.thumb 

.word 0x20002000 /* stack top address */ 
.word _start  /* 1 Reset */ 
.word hang  /* 2 NMI */ 
.word hang  /* 3 HardFault */ 
.word hang  /* 4 MemManage */ 
.word hang  /* 5 BusFault */ 
.word hang  /* 6 UsageFault */ 
.word hang  /* 7 RESERVED */ 
.word hang  /* 8 RESERVED */ 
.word hang  /* 9 RESERVED*/ 
.word hang  /* 10 RESERVED */ 
.word hang  /* 11 SVCall */ 
.word hang  /* 12 Debug Monitor */ 
.word hang  /* 13 RESERVED */ 
.word hang  /* 14 PendSV */ 
.word hang  /* 15 SysTick */ 
.word hang  /* 16 External Interrupt(0) */ 
.word hang  /* 17 External Interrupt(1) */ 
.word hang  /* 18 External Interrupt(2) */ 
.word hang  /* 19 ... */ 

.thumb_func 
.global _start 
_start: 
    bl notmain 
    b hang 

.thumb_func 
hang: b . 

這對我來說很有意義,我明白它做什麼,但什麼沒有意義,我是鏈接器(或CPU,我不知道這...)知道哪裏有異常表結束並開始實際代碼。在我看來,從Cortex-M3文檔中可以得到任意數量的表中的外部中斷。

這是如何工作,我應該讀什麼來學習?

回答

2

這是我的代碼,它是程序員而不是鏈接器,需要知道發生了什麼。皮層-m具有不同的向量表,它們可以相當長,許多單獨的中斷向量。以上僅僅是一種風味的一天。如果你永遠不會使用比復位向量更多的東西,你是否需要燒更多的內存位置來創建整個表格?可能不會。你可能想要創建一個足夠覆蓋未定義的異常和異常終止等,這樣你就可以用一個受控的掛起來捕獲它們。如果你只需要重置和一箇中斷,但是這個中斷在表格中很深,你可以製作一個巨大的表格來覆蓋兩者,或者足夠勇敢的在它們之間放置一些代碼來恢復丟失的空間。

要了解/閱讀更多信息,您需要閱讀針對特定cortex-m核心cortex-m0,cortex-m3和cortex-m4以及armv7-arm4 ARM ARM的技術參考手冊。 m(皮層-m都是家庭armv7-m)。 ARM ARM意味着ARM體系結構參考手冊,該手冊一般涉及整個系列,但並未涵蓋任何詳細的核心特定細節,通常在爲ARM編程時需要ARM ARM和正確的TRM(如果您需要進入任何低端級別如asm或特定的寄存器)。所有可以在左側的架構網站infocenter.arm.com中找到,或者查找Cortex-M系列處理器。

這些內核足夠新,它們可能沒有超過原始版本號。對於一些較舊的內核,最好爲特定內核獲取TRM。以ARM11 Mpcore爲例,如果供應商使用內核的rev 1.0(r1p0),儘管手冊上的過時標記至少要試圖在Rev 2.0手冊中使用rev 1.0手冊(如果存在差異)。供應商並不總是告訴你他們購買/使用的是哪一種版本,所以在整理如何編程這個東西或者什麼是勘誤適用於你時,這可能是一個問題。 (由於不瞭解這一點,Linux是完整的與ARM相關的錯誤,通常應用錯誤或應用於錯誤核心的錯誤,在錯誤核心或錯誤時間使用的指令等)。

我可能寫了一個cortex-m3處理程序,當我第一次得到一個,然後剪切和粘貼在這裏和那裏沒有打擾修復/改變它。

核心(CPU,邏輯)明確知道支持多少中斷,並知道向量表的完整構成。核心邊緣可能存在控制信號,可能會改變這些類型的東西,供應商可能會將這些方式聯繫起來或使其可編程等。無論該核心的邏輯如何,都明確知道向量表的外觀就像程序員根據需要使代碼與硬件匹配一樣。這將在TRM中針對該核心進行描述。

EDIT

在邏輯硬編碼將是對於每個這些事件或中斷偏移一個地址或。所以當中斷或事件發生時,它會執行從該地址讀取的內存。

這只是一個閃存的銀行,你給它一個地址,輕擊一個讀選通脈衝並輸出一些數據。除非你把它們放在上下文中,否則這些位並不意味着什麼。如果您創建了一些代碼在該地址執行加載指令,或者您可以跳轉到該地址,並且讀取週期讀取希望查找指令的位置,並且如果事件具有該硬編碼,則可以在地址0x10處導致內存循環地址和讀取發生在該地址,它希望找到一個處理程序的地址。但它只是一個記憶。就像文件系統上的文件一樣,它只是磁盤上的字節。如果它是一個jpeg,那麼一個特定的字節可能是一個像素,如果磁盤上的文件是一個程序,那麼偏移量處的一個字節可能是一條指令。它只是一個字節。

這些地址直接從邏輯生成。現在,邏輯是使用編程語言編寫的(通常是verilog或vhdl或某些生成verilog或vhdl作爲輸出的更高級語言)。沒有什麼不同,如果你在你最喜歡的語言編寫一個程序,你可以選擇從字面上硬編碼一些地址

x = (unsigned int *)0x1234; 

,或者你可以選擇使用一個結構或數組或某種其他的編程風格,但是一旦編譯它最終還是生產一些固定地址或偏移:

unsigned int vector_table[256]; 
... 
handler_address = vector_table[interrupt_base+interrupt_number]; 
... 

所以,作爲一個程序員,在這個低水平,你必須知道,如果當硬件要讀這些地址之一,以及爲什麼。如果您從不使用中斷,因爲您從不啓用任何中斷,那麼那些通常可以保存中斷處理程序地址的內存位置現在是您可以用於任何需要的內存位置。如果你看到很多,幾乎所有的例子,我只有需要復位向量,其餘我不使用。如果我不小心執行了未對齊的訪問,我可能會意外地碰到一個未定義的指令處理程序或數據中止,但我不擔心它通常會在那裏放置處理程序。無論如何,我會崩潰/掛起,所以當我到達那裏時,我會解決這個問題,當我到達它時,穿過那座橋。所以我通常以最低限度的Cortex-M的堆棧地址的內容和復位地址:

.cpu cortex-m3 
.thumb 

.word 0x20002000 /* stack top address */ 
.word _start  /* 1 Reset */ 

.thumb_func 
.global _start 
_start: 
    bl notmain 
    b hang 

.thumb_func 
hang: b . 

是的,絕對是我放在兩個字指令BL notmain在一個NMI的存儲位置。如果NMI發生,那麼cpu會讀取該位置,假設它是一個處理程序的地址,嘗試在該地址獲取該指令,這將有誰知道什麼。它甚至可能在獲取之前知道它是一個無效地址並導致數據中止,在上述情況下,它會成爲另一個地址,並可能變成無限循環的數據中止。或者,如果碰巧這些指令中的一條碰巧看起來像我們程序中的地址,那麼基本上它會跳到程序的中間,這往往會以某種方式崩潰。什麼是崩潰?真?如果這些指令指示它執行未對齊的訪問,或者那些字節不是有效的指令或導致您讀取無效的內存地址,則您將返回到向量表中,CPU將執行其作業從內存中讀取字節並將其解釋爲指令。或者你可能非常幸運,通過在代碼空間的中間跳轉來寫入或讀取混亂的地址會導致閃存組被擦除,或者一個字節吐出一個uart,或者一個gpio輸入端口被改變成一個輸出端口(如果真的很幸運,你可以嘗試在地面或其他地方開車,然後將芯片熔化)。

如果我開始看到奇怪的東西(希望沒有聽到或聞到或看到芯片熔化),我可能會折騰向量表中的幾十個指向掛起的條目,或者指向一個處理程序吐出某個端口或打開gpio/led。如果我的怪異現在變成了這種情況,或者處理器中的uart輸出,那麼我必須弄清楚發生了什麼事件,或者如果我想到應用程序的最後幾個變化,我可能會意識到我有一個未對齊的訪問或分支入雜草等

這又回到了那句話,「電腦沒有做你想要做什麼,就做什麼,你告訴它做」。你把字節放在那裏,它解釋了它們是什麼,如果你沒有把正確的字節放在正確的位置(向量地址到正確的地方,說明做正確的事,正確的數據在正確的地方)它可以/會崩潰。

+0

我知道它是中斷向量表,我明白它可以像一個人可能需要它那樣稀疏/完整,但我不明白的是CPU或其他什麼知道那個特定的行塊是中斷向量表,而它後面的行不是。什麼劃分部分?向量表是否必須是文件中的第一個?它是否定義爲「第一個.thumb_func指令之前的所有內容」? – Mark 2012-02-09 22:30:36

+0

或者,我們是簡單地結束向量表,並將其餘部分用作代碼空間? I.E.例如,如果我們在NMI中斷後結束了表,並且發生了BusFault中斷,我們是否會跳到一些奇怪的地方,因爲某些指令或數據佔用了向量表中的那個槽? – Mark 2012-02-09 22:43:14

1

答案是不。程序員有責任放置足夠數量的向量來捕獲CPU產生的所有數據。如果你搞砸了,CPU可能會試着在向量表之後加載一些東西(比如你的_start代碼中的指令),把它當作一個向量來處理,然後嘗試跳入它(這可能會導致數據中止)。