如何在晶心平台實作 ROM patch

Facebook
Twitter
LinkedIn

賴歆雅,技術經理,晶心科技股份有限公司

筆者曾協助多家公司工程師,在 AndesCore™上發展 firmware。我們發現,當客戶開發 Non-OS 的程式碼,最常遇到的問題在於開發者不知如何撰寫 linker script。網路上有 GNU ld 的使用文件,但是 linker script 的範例太少,尤其開發者需要撰寫進階的 linker script,常常不知如何下手。

本篇文章我們分享如何實作 ROM patch。使用晶心 CPU 建構的 embedded system,一般具有 CPU、週邊 IP 及 RAM、ROM。部份客戶使用 ROM code 開機,程式碼放在 ROM 內,data section 放在 SRAM 裡。ROM code 的特性是成本低,跟著 IC 光罩一起生產,當 IC 製作完成即不可修改,若有製作上的錯誤或是程式碼邏輯上的錯誤,只能用 ROM patch 的方式修補。也就是將需要修補的程式碼放到小容量的 flash 裡。這就是我們今天要分享的技術。

1. 主程式架構
  首先介紹主程式的架構。IC 的 Memory layout 如下圖

紅色框線的部份,為主程式編譯的範圍。主程式 main 會呼叫到 func1、func2
和 func3 這 3 個 function。

在上圖中,黃色區域是 IC 的 ROM,這部份的程式是 IC 製作出來即不可以改變。綠色部份是 flash。在圖中,flash 分成 2 區,一個是 jump_table,存放 func1~func3 的位址。剩餘的空間 FUNC_PATCH,預留給 patch 使用。

為了要修補 ROM 內的 function,所以規劃出 jump_table 區域,原本都是指向ROM 的 function。如果 ROM 裡的部份 function 損壞或是需要改寫,就把jump_table 改為指向 FUNC_PATCH 裡新建的 function。

   1.1 原始程式碼
   主程式的程式碼如下:(main.c)

   1.2 主程式 linker script (僅列需要修改的部份)

Flash 的位址由 0x510000 起,將 FUNC_TABLE 固定在 flash 的最開頭,語法如上。

   1.3 主程式執行結果

2. 經過Patch之後的架構圖
  假設 ROM 裡的 func2 損壞,要改用 flash 裡的 func2。需要更改指向 func2 的指標,及 func2 的內容。如下圖:

用紅色框線標起來的地方,表示為 patch 編譯的範圍。其中 jump table 在這裡重新編譯,指向新的位址。

   2.1 實作方法
  (1) 匯出主程式的 symbol table。
在主程式的 Linker flags 加上-Wl,–mgen-symbol-ld-script=export.txt ,ld 會產生 export.txt 這個檔案, 這個檔案包含了一個 SECTION block 以及許多變數的位址。如下圖所示

Linker script 在 import Main program 的 symbols 時,除了需要修改的 func2 不要 import 之外,其他的 symbols 全部要 import 進來。(將 export.txt 刪去這一行: func2 = 0x005001c4; /* ./main.o */)
   (2) patch 在編譯之前,先匯入主程式的 symbol table。(將 export.txt 檔案放在一起編譯)。Patch 的 linker script 要匯入主程式的 symbol,寫法如下面紅色字體。

   (3) patch 的程式碼裡如下,沒有 main function,也不要加入 startup files。改寫 func2。func2 放在 flash 的 FUNC_PATCH section。並且將 jump_table 裡的 func2,改成指向新的 func2。

   (4) patch 的 linker script,加入 FUNC_PATH 在 jump_table 之後。

3. 如何除錯
首先,將程式碼存放在 IC 的 ROM 及 flash 裡。(本文為了示範,我們的做法是在 AndeShape™ ADP-XC5 的 FPGA 板上,用 RAM 模擬 ROM 及 flash,分別將主程式和 patch 的 bin 檔 restore 到板子上。)

當 gdb debug 時,載入 patch 的 symbol。以下節錄 gdb 指令。

上面過程中,先載入 main 的 symbol,再載入 patch 的 symbol 及 debug information。”add-symbol-file patch.adx       0x500000 -s FUNC_TABLE 0x510000 -s FUNC_PATCH 0x510020″是將 patch section 的 symbol 及 debug information 也載入 gdb 以 debug。讀者可以在 gdb 裡,打”help add-symbol-file” 查閱 add-symbol-file 的用法。

   3.1 主程式 patch 後的執行結果

4.結語
目前晶心科技使用GNU的toolchain,其功能非常強大。讀者可多動手試試不同的linker script寫法,使得開發firmware更有彈性及效率。