溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

如何實現Cortex-A9 uboot啟動代碼

發布時間:2021-12-27 13:37:29 來源:億速云 閱讀:289 作者:小新 欄目:系統運維

小編給大家分享一下如何實現Cortex-A9 uboot啟動代碼,希望大家閱讀完這篇文章之后都有所收獲,下面讓我們一起去探討吧!

一、uboot

1. 概念

U-Boot  是一個主要用于嵌入式系統的引導加載程序,可以支持多種不同的計算機系統結構,包括PPC、ARM、AVR32、MIPS、x86、68k、Nios與MicroBlaze。這也是一套在GNU通用公共許可證之下發布的自由軟件。

U-Boot不僅僅支持嵌入式Linux系統的引導,它還支持NetBSD, VxWorks, QNX, RTEMS, ARTOS, LynxOS,  android嵌入式操作系統。其目前要支持的目標操作系統是OpenBSD, NetBSD, FreeBSD,4.4BSD, Linux, SVR4, Esix,  Solaris, Irix, SCO, Dell, NCR, VxWorks, LynxOS, pSOS, QNX, RTEMS, ARTOS,  android。

2. uboot基本功能

U-Boot可支持的主要功能列表:

  • 系統引導支持NFS掛載、RAMDISK(壓縮或非壓縮)形式的根文件系統;支持NFS掛載、從FLASH中引導壓縮或非壓縮系統內核;

  • 基本輔助功能強大的操作系統接口功能;可靈活設置、傳遞多個關鍵參數給操作系統,適合系統在不同開發階段的調試要求與產品發布,尤以Linux支持最為強勁;支持目標板環境參數多種存儲方式,如FLASH、NVRAM、EEPROM;

  • CRC32校驗可校驗FLASH中內核、RAMDISK鏡像文件是否完好;

  • 設備驅動串口、SDRAM、FLASH、以太網、LCD、NVRAM、EEPROM、鍵盤、USB、PCMCIA、PCI、RTC等驅動支持;

  • 上電自檢功能SDRAM、FLASH大小自動檢測;SDRAM故障檢測;CPU型號。

3. 常用命令

uboot命令比較多,下面只列舉網絡啟動要用到的命令:

如何實現Cortex-A9 uboot啟動代碼

4. 配置參數舉例

以下以網絡下載內核、網絡掛載nfs為例。

1)ubuntu環境

ubuntu ip:192.168.6.186

nfs配置:

配置文件如下:

/etc/exports

配置信息如下:

 如何實現Cortex-A9 uboot啟動代碼

nfs

2)開發板設置

開發板ip:192.168.6.187

配置命令:

setenv ipaddr 192.168.6.187      ;板子的ip setenv serverip 192.168.6.186    ;虛擬機的ip setenv gatewayip 192.168.1.1     ;網關 saveenv                          ;保存配置

加載內核和設備樹

setenv bootcmd tftp 41000000 uImage\;tftp 42000000 exynos4412-fs4412.dtb\;bootm 41000000 - 42000000

bootcmd:uboot2啟動之后,首先先執行找到這個參數,執行后面的命令。

從tftp服務器下載內核鏡像uImage到地址41000000,設備樹文件exynos4412-fs4412.dtb到42000000,并通過命令bootm加載啟動內核。

  • 掛載nfs

setenv bootargs root=/dev/nfs nfsroot=192.168.6.186:/rootfs rw console=ttySAC2,115200 init=/linuxrc ip=192.168.6.187

掛載nfs文件系統

  • root=/dev/nfs

  • nfsroot=192.168.6.186:/rootfs nfs服務器地址192.168.6.186,目錄為/rootfs,

  • rw 文件系統操作權限為可續寫

  • console=ttySAC2,115200 串口名稱和波特率

  • init=/linuxrc 內核啟動后運行的進程為linuxrc

  • ip=192.168.6.187 開發板地址

二、exynos-4412 Soc 啟動順序

要想了解exynos-4412的啟動順序,我們首先需要了解該soc的內存布局。

1. exynos-4412內存布局

通常一款soc的內存在廠家設計的時候就已經規定死了,對于使用者來說,我們無法改變。

如何實現Cortex-A9 uboot啟動代碼

我們只關心和啟動相關的一個地址,

  1. 鴻蒙官方戰略合作共建——HarmonyOS技術社區

  2. iROM 在soc內部,出廠時廠家固化了特定的程序,iROM中程序對應用戶來說不可改變

  3. iRAM 在soc內部,速度較快,但空間不大

  4. DMC RAM控制器,位于SOC內部,用于驅動RAM,大容量的RAM都需要連接到該控制器

2. Booting Sequence

不同的廠家的啟動順序是不太一樣的,本篇主要以三星的exynos-4412 soc為基礎,講解該基于該板子的uboot啟動順序。

如何實現Cortex-A9 uboot啟動代碼

根據上圖,系統啟動的大概順序:

  • iROM在SOC內部,是一個64KB的ROM,他樹池化一些系統啟動必須的功能。比如:時鐘、棧。

  • iROM負責從特殊的啟動外設加載BL1的image到soc內部的256KB的SRAM中。啟動的外設由操作按鈕來決定的。根據不同按鍵的值,iROM將會對bl1  的image做不同的校驗。

  • BL1初始化系統時鐘和DRAM控制器,然后從啟動外設加載OS image到DRAM中。根據啟動按鈕的值的不同,BL1會對OS做不同的校驗。

  • 啟動完成之后,BL1跳轉到操作系統(kernel)。

iROM會根據OM 引腳的不同選擇不同的啟動設備,對應的OM寄存器需要提供對應的啟動信息。

三、內核啟動流程概述

1. 內核啟動流程 概述

 如何實現Cortex-A9 uboot啟動代碼

uboot啟動流程

如上圖所示:

  1. 鴻蒙官方戰略合作共建——HarmonyOS技術社區

  2. 設備上電之后,先執行iROM中的出廠代碼,先進行必要硬件的初始化 去執行uboot,

  3. 通常把kernel、設備樹文件放到flash中

  4. 程序啟動之后,往往先從flash啟動,運行uboot

  5. 第一步:先進行硬件的初始化(svc模式棧、clock、內存、串口)  第二步:自搬移:把uboot從flash中拷貝到RAM中,跳轉到RAM中執行剩下的uboot代碼

  6. 第三步:把內核拷貝到RAM中,執行內核,把控制權交給內核。

2. 內核啟動詳細流程

如何實現Cortex-A9 uboot啟動代碼

開發板從上電到啟動內核的過程

四、uboot啟動流程代碼詳解

1. lds文件

要想了解uboot整個項目的代碼流程,必須首先了解鏈接腳本【鏈接腳本參考《7. 從0開始學ARM-GNU偽指令,lds使用》】。

該文件決定了uboot最終生成的鏡像文件,各個段的布局。

uboot鏈接腳本如下:

u-boot-2013.01/arch/arm/cpu/u-boot.lds

文件內容:

26 OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")  27 OUTPUT_ARCH(arm)  28 ENTRY(_start)  29 SECTIONS  30 {  31     . = 0x00000000;  32   33     . = ALIGN(4);  34     .text :  35     {  36         __image_copy_start = .;  37         CPUDIR/start.o (.text*)  38         *(.text*)  39     }  40   41     . = ALIGN(4);  42     .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }  43   44     . = ALIGN(4);  45     .data : {  46         *(.data*)  47     }  48   49     . = ALIGN(4);  50   51     . = .;  52   53     . = ALIGN(4);  54     .u_boot_list : {  55     #include <u-boot.lst>  56     }  57   58     . = ALIGN(4);  59   60     __image_copy_end = .;  61   62     .rel.dyn : {  63         __rel_dyn_start = .;  64         *(.rel*)  65         __rel_dyn_end = .;  66     }  67   68     .dynsym : {  69         __dynsym_start = .;  70         *(.dynsym)  71     }  72   73     _end = .;  74   75     /*  76      * Deprecated: this MMU section is used by pxa at present but  77      * should not be used by new boards/CPUs.  78      */  79     . = ALIGN(4096);  80     .mmutable : {  81         *(.mmutable)  82     }  83   84     .bss __rel_dyn_start (OVERLAY) : {  85         __bss_start = .;  86         *(.bss*)  87          . = ALIGN(4);  88         __bss_end__ = .;  89     }  90   91     /DISCARD/ : { *(.dynstr*) }  92     /DISCARD/ : { *(.dynamic*) }  93     /DISCARD/ : { *(.plt*) }  94     /DISCARD/ : { *(.interp*) }  95     /DISCARD/ : { *(.gnu*) }  96 }  97

核心內容解釋:

27 OUTPUT_ARCH(arm)       :    該鏡像運行在arm架構的硬件上 28 ENTRY(_start)          :    程序的入口是 _start 29 SECTIONS 30 { 31  . = 0x00000000;      :   程序的鏈接地址,不是運行地址【uboot一定是位置無關碼】 34     .text : 35     { 36         __image_copy_start = .;    : 宏對應整個程序編譯好后首地址,自搬移代碼的初始位置 37         CPUDIR/start.o (.text*)    : 第一個目標文件CPUDIR/start.o中的代碼段 38         *(.text*)                  : 剩下的目標文件的代碼段 39     } 60     __image_copy_end = .;          : 自搬移代碼的結束為止

BSS全局未初始化變量、全局初始化為0的變量所在的段:

84     .bss __rel_dyn_start (OVERLAY) : {  85         __bss_start = .;  88         __bss_end__ = .;  89     }

2. uboot啟動代碼流程概要

代碼只分析到uboot命令行,函數main_loop()位置。

如何實現Cortex-A9 uboot啟動代碼

3. 啟動代碼詳細分析

_start入口位于以下文件:

u-boot-2013.01/arch/arm/cpu/armv7/start.S

第一階段:

 如何實現Cortex-A9 uboot啟動代碼

第二階段

第二階段代碼從_main開始:

如何實現Cortex-A9 uboot啟動代碼

以上代碼詳細解釋,請結合B站視頻同步學習。

五、uboot啟動的幾個關鍵知識點

1.如何判斷第一條機器指令的位置?

鏈接腳本決定了內存的布局。

uboot鏈接腳本如下:

u-boot-2013.01/arch/arm/cpu/u-boot.lds

文件內容:

28 ENTRY(_start) 29 SECTIONS 30 { 31     . = 0x00000000; 32

uboot的入口是_start

鏈接地址是0x00000000

2.uboot如何搬運代碼?

代碼位于:

u-boot-2013.01/arch/arm/cpu/armv7/start.S

搬移代碼如下:

ENTRY(relocate_code)  mov r4, r0 /* save addr_sp */  mov r5, r1 /* save addr of gd */  mov r6, r2 /* save addr of destination */   adr r0, _start  cmp r0, r6  moveq r9, #0  /* no relocation. relocation offset(r9) = 0 */  beq relocate_done  /* skip relocation */  mov r1, r6   /* r1 <- scratch for copy_loop */  ldr r3, _image_copy_end_ofs  add r2, r0, r3  /* r2 <- source end address     */  copy_loop:  ldmia r0!, {r9-r10}  /* copy from source address [r0]    */  stmia r1!, {r9-r10}  /* copy to   target address [r1]    */  cmp r0, r2   /* until source end address [r2]    */  blo copy_loop

詳情參考第四章,第3節。

3.uboot中,如何判斷此次開機是從斷電狀態開機還是從休眠狀態啟動的?

board/samsung/fs4412/lowlevel_init.S

代碼如下:

41   lowlevel_init: 54     /* AFTR wakeup reset */ 55     ldr r2, =S5P_CHECK_DIDLE 56     cmp r1, r2 57     beq exit_wakeup 58  59     /* LPA wakeup reset */ 60     ldr r2, =S5P_CHECK_LPA 61     cmp r1, r2 62     beq exit_wakeup 63  64     /* Sleep wakeup reset */ 65     ldr r2, =S5P_CHECK_SLEEP 66     cmp r1, r2 67     beq wakeup_reset  112 wakeup_reset: 113     bl system_clock_init 114     bl mem_ctrl_asm_init 115     bl tzpc_init 116  117 exit_wakeup: 118     /* Load return address and jump to kernel */ 119     ldr r0, =(EXYNOS4_POWER_BASE + INFORM0_OFFSET) 120  121     /* r1 = physical address of exynos4210_cpu_resume function */ 122     ldr r1, [r0] 123  124     /* Jump to kernel*/ 125     mov pc, r1

由上可知,當手機因為各種原因進入休眠時,會將當前程序執行的上下文保護起來,并向一些pmic的寄存器中寫入指定的數據,以表明此次是因為何種原因進入休眠。

而手機并沒有完全斷電,而是處于一個低功耗模式下,此時啟動RAM仍然有數據,所以在此啟動后,只需要從特殊的寄存器中讀取相應的值,就可以知道之前是因為什么原因休眠,進而回復休眠之前的上下文即可。

3.uboot代碼搬到ram之后,代碼的運行地址發生了變化,如何保證程序跳轉不會出錯?

除了要保證uboot代碼是基于地址無關的,此外.rel.dyn幫我們解決了,其實主要還是編譯器幫我們做了很多工作。

位置無關碼參考《15. 從0學ARM-什么是位置無關碼?》

4.設備啟動的時候,有可能直接從ram啟動, 如何知道當前是從flah啟動還是ram啟動的?

文件:

board/samsung/fs4412/lowlevel_init.S

代碼:

lowlevel_init:

85     /*  86      * If U-boot is already running in ram, no need to relocate U-Boot.  87      * Memory controller must be configured before relocating U-Boot  88      * in ram.  89      */  90     ldr r0, =0x0ffffff      /* r0 <- Mask Bits*/  91     bic r1, pc, r0      /* pc <- current addr of code */  92                     /* r1 <- unmasked bits of pc */  93     ldr r2, _TEXT_BASE      /* r2 <- original base addr in ram */  94     bic r2, r2, r0      /* r2 <- unmasked bits of r2*/  95     cmp r1, r2          /* compare r1, r2 */  96     beq 1f          /* r0 == r1 then skip sdram init */

原理:RAM地址空間是:0x40000000-0xA0000000 0xA0000000-0x00000000  而iROM/iRAM地址的bit:28-31均是0,所以只需要讀取出執行到lowlevel_init時pc的值,判斷其bit:28-31是否是0即可知道現在代碼是否運行在RAM中。

看完了這篇文章,相信你對“如何實現Cortex-A9 uboot啟動代碼”有了一定的了解,如果想了解更多相關知識,歡迎關注億速云行業資訊頻道,感謝各位的閱讀!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

亚洲午夜精品一区二区_中文无码日韩欧免_久久香蕉精品视频_欧美主播一区二区三区美女