1. 程式人生 > >uboot移植(一)

uboot移植(一)

這次移植是將三星移植過的 uboot 移植到九鼎的開發板上,難度不大,算是對之前 uboot 學習的一個階段性的總結和回顧。 一、 搭建 tftp 伺服器,為測試啟動核心做準備( 開發板用 tftp 方式下載核心到DDR ) 測試 tftp 伺服器 在/tftpboot 中新建一個檔案 file,然後在其中隨便輸入內容;然後進入一個不是/tftpboot 的目錄下在終端中輸入 sudo tftp localhost,進入 tftp 命令符下(可以在其中輸入 help 檢視命令和命令的作用),輸入 get file,如果沒有任何提示,就說明傳輸成功了,然後輸入 q退出 tftp 命令符,在當前目錄下就可以看到一個 file 檔案,內容是與開始新建的那個 file 的內容是一致的。同樣也可以在 tftp 命令符中輸入 put xx,把 xx 檔案上傳到伺服器資料夾中。如果一切 ok,那就麼一個可用的 tftp 伺服器就順利搭建成功了。 開發板下載 kernel 則是在 uboot 命令列下 tftp 30008000 zImage-qt (30008000是核心啟動的地址,zImage-qt 是映象名稱,需要在 /tftpboot 資料夾中。) 二、 虛擬機器上網、ping通主機和開發板 同樣參考網上文章,這裡只記錄我遇到的一些問題和解決方法。 1. 虛擬機器上網選擇橋接模式無法上網。 問題可能是:1) 檢視->虛擬網路編輯器,橋接到了有線網絡卡 2) /etc/network/interfaces 是否設定為靜態ip( static ),改為動態ip( dhcp )即可。 3) 以上兩種都不是,可能是虛擬機器相關驅動或服務有問題,解決方法:1) 重灌 vm tools 2) 啟動 計算機->系統服務-> Vmware 相關服務 3) 修復 Vmware 控制面板->程式和功能->Vmware 右鍵 更改,選擇修復。 2. 虛擬機器ping不通主機、開發板。 虛擬機器能上網後,將橋接改回有線網絡卡,設定為靜態ip,之後測試與主機ping,能通,但是需要主機連線網線到能上網的機器( 否則 Windows 網絡卡驅動不工作,ping 不通)。之後將開發板和主機之間用網線連線,這時候虛擬機器 ping 不通主機,猜測還是和 Windows 的驅動相關,但是開發板能 ping 通主機和虛擬機器,因此沒有深究。 三、 開始移植 移植前看兩個部分,一個是 Makefile,找到相對應的配置,之後移植的時候以這個配置為藍本進行修改,這裡選的是 smdkv210single_config,對應的配置都在 smdkv210single.h 中。其次要看燒寫指令碼,uboot/sd_fusing/sd_fusing.sh。vi 進去看 BL1 燒寫 的扇區號,bl1_position=1( BL1 的位置) uboot_position=49( uboot的位置,要和BL1隔32個扇區以上(16KB加上一些間隔空間)),使用之前先 make clean 再 make。 移植難度並不大,因為三星已經移植過了。 整體的思路就是燒錄 uboot 到 SD卡然後啟動觀察串列埠列印資訊,之後定位問題到具體程式碼,問題可能是程式碼上的也可能是配置上的,程式碼上的問題需要閱讀程式碼進行修改,一般先網上搜索,如果沒有再結合具體程式碼實現的過程對照資料手冊修改,配置上的問題則需要閱讀開發板原理圖和資料手冊進行修改。 這次移植只遇到了幾個問題: 首先檢查完 Makefile 和 sd_fusing.sh 指令碼,燒錄 uboot 到 SD卡中去啟動,串列埠列印 SD checksum error ,之後無輸出,開發板供電自鎖。 SD checksum error 這一句是板子內部的 iROM 中的程式碼輸出的,因為要 SD卡啟動就要破壞板載 iNand 內部的 uboot 程式碼,因此校驗失敗轉到 SD channel 2 啟動,之後串列埠沒有資訊輸出,說明在start.S 的串列埠列印 'O' 之前程式碼就死了,但是注意細節:開發板供電鎖存開啟,說明程式碼出現問題是在 供電自鎖 到 串列埠列印'O'之間。因此定位具體問題程式碼到 lowlevel_init 函式中。通過之前對整個 uboot 啟動程式碼的分析,可以發現中間有一句 bl PMIC_InitIp 是多餘的,開發板沒有 PMIC 電源管理模組。註釋掉之後 uboot 就能正常啟動了,但是打印出來的很多配置資訊是錯的,還需要修改。 其次是 DDR 的配置出錯,使用 md 和 mw 命令測試記憶體,發現20000000和40000000開頭的記憶體都是可以用的,說明程式碼中 DDR 初始化部分是正確的,只是 size 錯了。在 smdkv210single.h 中修改相應的配置即可,從資料手冊中可以看到 DDR 是2個bank,從原理圖看到每個 bank 是256MB( 實際是4塊記憶體,每塊128MB,兩塊16位的並聯在一起形成32位的記憶體)。 之後還進行了更改,將 bank0 的基地址配在了 0x3000_0000,實際有效範圍是 0x3000_00000~0x3FFF_FFFF。需要修改 DDR 的基地址巨集 MEMORY_BASE_ADDRESS 和配置巨集DMC0_MEMCONFIG_0 ,具體暫存器位的意義在資料手冊的 Memory Chip0 Configuration Register 裡,主要修改了 chip_base 和 chip_mask。DDR 相關的記憶體地址變了,因此還要更改有關虛擬地址對映相關的地方,在 uboot/board/samsung/smdkc110/lowlevel_init.S 中找到轉換表 mmu_table ,之後將地址對映 0x2000_0000 對映到 0xc000_0000 的一段程式碼將 0x200 改為 0x300。但是 uboot 還是啟動不成功,只出現"SD/MMC:"而沒有後面打印出的 size 。由於在更改 DDR 地址配置之前整個 uboot 已經啟動起來了,所以問題程式碼一定是與 DDR 配置相關的程式碼。教程中講的太含糊,用經驗去找到了問題所在,這裡我重新用除錯的辦法定位,由於初始化了串列埠,所以通過 printf 來列印除錯資訊。 由於問題出現在 "SD/MMC:"之後,又和DDR有關,因此首先將問題定位在 mmc_initialize 函式中。繼續除錯,將問題定位在 mmc_init 函式中。繼續,在 mmc_read_ext_csd 函式。 mmc_send_ext_csd 函式。mmc_send_cmd 函式,裡面返回 mmc->send_cmd(mmc, cmd, data) ,之後用 SI 的搜尋,只在 uboot/drivers/mmc/s3c_hsmmc.c 中有 send_cmd 被賦值為 s3c_hsmmc_send_command,這裡面主要是對 host->ioaddr 操作,使用的 readl 和 writel 是強制型別轉換的巨集,與 DDR 無關,還有嫌疑的就是兩個函式:sdhci_prepare_data 和 sdhci_set_transfer_mode。追到 sdhci_prepare_data 函式中檢視,基本與 s3c_hsmmc_send_command 函式使用的操作差不多,但多了一個函式:virt_to_phys,看名字是用於虛擬地址轉換到實體地址,結合 uboot 更改 DDR 配置後出現問題的情況,這個函式多半就是問題所在。這個函式是一個巨集定義,在 smdkv210single.h 檔案裡,巨集定義為 virt_to_phy_smdkc110 函式,發現這個函式在虛擬地址到實體地址的對映時,是將 0xC000_0000 對映到 0x2000_0000,而我們之前配置的是要對映到 0x3000_0000,所以這裡將2該為3。 DDR 的問題解決了,uboot 可以正常啟動了,但是 iNand 的 size 還是讀不出來,不過好在打印出了錯誤資訊 unrecognised EXT_CSD structure version 7,因此在 SI 中直接搜尋關鍵詞定位在 uboot/drivers/mmc/mmc.c 中的 818 行,由於打印出了錯誤資訊,因此先上網搜尋解決方案,經過網上的一些解決方案的閱讀,知道這個錯誤是由於 SD卡的 EXT_CSD 版本過高引起的,只要將判斷的條件改高即可,高版本並無太多差異,不影響讀寫。 iNand 配置完成後就是網絡卡驅動的移植,因為之後要用 tftp 下載核心映象來啟動,用 ping 命令時 ping 不通,查原理圖知道開發板用的是 dm9000 網絡卡,之前在 uboot解析(三)時看過,當時對這些配置還不懂,現在補上。因為原理圖中 CS# 接的 CSn1,即bank1。因此所做的修改就是將 bank5 改為 bank1即可。 網絡卡驅動配置好厚測試 ping 命令和 tftp 下載映象都成功了,但是還是不能啟動核心,列印環境變數發現 bootcmd 中的 bootm 引數不對,在配置中修改過來即可。 之後測試啟動核心,成功。這個 uboot 算是基本移植成功了,主要功能(啟動核心)完成了,還有一些其他的細節沒有修改。 四、 一些問題和注意事項 燒錄 uboot 時,sd_fusing.sh 指令碼報錯 1) Unsupported SD reader 檢視指令碼發現只支援燒錄 /dev/sdb ,改為 sdc 即可。 2) /dev/sdb is NOT identified. 先格式化SD卡即可。 移植的時候務必細心, 2017/11/08 11:27 修改 uboot/drivers/mmc/mmc.c 中程式碼,解決串列埠列印 unrecognised EXT_CSD structure version 7 問題時,修改了程式碼,但是實際燒寫時發現問題未解決,網上搜索解決方法都相同,懷疑未儲存。經過排查到 Linux 下進入 uboot/drivers/mmc 檔案下下發現多了一個 mmc. 檔案,後在 cp.sh 指令碼中發現自己最後少打了一個 c 造成檔案未替換到 ubbot 原始碼中。 cpu、板子型號是 s5pc11x,smdkv210 uboot 燒錄後感覺 SD卡沒用,要先破壞板載 iNand 內的 uboot。

清除 uboot 中環境變數的命令 mmc write 0 30000000 11# 32 (表示將DDR的0x30000000開頭的一段記憶體中的內容寫入iNand中的第17個扇區開始的32個扇區內,寫入長度是32個扇區長(16KB))

五、總結 整體 uboot 的移植感覺不難,因為之前分析過程式碼,瞭解整個 uboot 的啟動過程,移植時主要是修改配置以適應具體的板子。其次對 uboot 移植的認識就是:牽一髮而動全身。比如在修改 virt_to_phys 函式時,由於配置中其實對應了兩個具體的實現,而第二個實現( else 分支)是剛好可以滿足情況的,我就把條件編譯的巨集去掉了,結果導致 uboot 在編譯階段就失敗了,報錯,連編譯都完成不了,最後還是改回去將第一個實現做了對應的修改才得以成功的。第三個是對 uboot 移植的認識,結果不難,難的是中間的過程。也就是說修改配置本身是不難的,但問題是修改哪個配置和為什麼要修改這個配置,同樣是 virt_to_phys 這個巨集,在教程中老師是直接根據經驗在 smdkv210single.h 檔案中一一查詢找到的,沒有普適性,所以我寫這個筆記時重新從問題的出發點一步步的除錯跟蹤程式碼來尋找問題的,事實上在追到 s3c_hsmmc_send_command 函式的時候已經追不動了,程式在這裡迴圈幾遍後死了,沒有辦法定位,只有去一點一點的分析程式碼。解決這樣的問題時,應該要隨時記住問題的根本( DDR 配置),然後從這個根源出發去尋找可能出錯的程式碼,同時對這一問題的相關延伸要有了解( DDR 地址配置,涉及到虛擬地址對映),所以教程中老師是直接用經驗解決的,經驗帶來的其實就是對這個問題的認識非常熟悉,知道這樣的錯誤涉及到哪些方面,隨後一一排查,從本質來說其實有沒有經驗沒有差別,區別只是對 uboot,對整個 SoC 架構的理解和熟悉程度和對問題程式碼的敏感程度。以前我沒有經驗,但是經過這次實踐就有了,所以多實踐,不怕麻煩,慢慢地就會提高我解決問題的能力。