Linuxプログラミング入門--正点原子Linux駆動開発ガイドライン学習2021 W 26


十一、U-Boot起動プロセスの詳細
(1)リンクスクリプトu-boot.lds詳細
コンパイルが完了するとubootルートディレクトリの下でu-bootが生成される.ldsファイル、このファイルからU-boot起動プロセスを分析します.
/*
1.   3          : _start, _start     arch/arm/lib/vectors.S     
2. __image_copy_start        u-boot-spl.lds       ,         .text  
     
*/
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
OUTPUT_ARCH(arm)

ENTRY(_start)
SECTIONS
{
 . = 0x00000000;
 . = ALIGN(4);
 .text :
 {
  *(.__image_copy_start)
  *(.vectors)
  arch/arm/cpu/armv7/start.o (.text*)
  *(.text*)
 }
 . = ALIGN(4);
 .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
 . = ALIGN(4);
 .data : {
  *(.data*)
 }
 . = ALIGN(4);
 . = .;
 . = ALIGN(4);
 .u_boot_list : {
  KEEP(*(SORT(.u_boot_list*)));
 }
 . = ALIGN(4);
 .image_copy_end :
 {
  *(.__image_copy_end)
 }
 .rel_dyn_start :
 {
  *(.__rel_dyn_start)
 }
 .rel.dyn : {
  *(.rel*)
 }
 .rel_dyn_end :
 {
  *(.__rel_dyn_end)
 }
 .end :
 {
  *(.__end)
 }
 _image_binary_end = .;
 . = ALIGN(4096);
 .mmutable : {
  *(.mmutable)
 }
 .bss_start __rel_dyn_start (OVERLAY) : {
  KEEP(*(.__bss_start));
  __bss_base = .;
 }
 .bss __bss_base (OVERLAY) : {
  *(.bss*)
   . = ALIGN(4);
   __bss_limit = .;
 }
 .bss_end __bss_limit (OVERLAY) : {
  KEEP(*(.__bss_end));
 }
 .dynsym _image_binary_end : { *(.dynsym) }
 .dynbss : { *(.dynbss) }
 .dynstr : { *(.dynstr*) }
 .dynamic : { *(.dynamic*) }
 .plt : { *(.plt*) }
 .interp : { *(.interp*) }
 .gnu.hash : { *(.gnu.hash) }
 .gnu : { *(.gnu*) }
 .ARM.exidx : { *(.ARM.exidx*) }
 .gnu.linkonce.armexidx : { *(.gnu.linkonce.armexidx.*) }
}

ファイルでarch/arm/lib/vectors.Sでは、個別のセグメント.section ".vectors", "ax"が定義されていることがわかる.startの後ろには割り込みベクトルテーブルがあります.
#include 

/*
 *************************************************************************
 *
 * Symbol _start is referenced elsewhere, so make it global
 *
 *************************************************************************
 */

.globl _start

/*
 *************************************************************************
 *
 * Vectors have their own section so linker script can map them easily
 *
 *************************************************************************
 */

    .section ".vectors", "ax"

/*
 *************************************************************************
 *
 * Exception vectors as described in ARM reference manuals
 *
 * Uses indirect branch to allow reaching handlers anywhere in memory.
 *
 *************************************************************************
 */

_start:

#ifdef CONFIG_SYS_DV_NOR_BOOT_CFG
    .word    CONFIG_SYS_DV_NOR_BOOT_CFG
#endif

    b    reset
    ldr    pc, _undefined_instruction
    ldr    pc, _software_interrupt
    ldr    pc, _prefetch_abort
    ldr    pc, _data_abort
    ldr    pc, _not_used
    ldr    pc, _irq
    ldr    pc, _fiq

(2)Cortex-A 7割り込みシステムの詳細
  • GICコントローラ一覧
  • ここでCortex-A 7が中断した知識を補足します.そうしないと、後の分析は少し難しいです.Cortex-A 7にも割り込みベクトルテーブルがあり、割り込みベクトルテーブルもコードの先頭にあります.CortexA 7カーネルには8つの異常割り込みがあり、この8つの異常割り込みの割り込みベクトル表は以下の表の通りである.
    ベクトルアドレス
    ターミナルタイプ
    割り込みモード
    紹介する
    0x00
    複数回中断(RSET)
    特権モード(SVC)
    CPUリセット後はリセット割り込みに入ります.リセット割り込みサービス関数では、SPポインタの初期化、DDRの初期化など、初期化作業を行うことができます.
    0x04
    未定義命令割り込み(Undefined Instruction)
    命令中止モードが定義されていません(Undef)
    命令が認識されないと、この割り込みが発生します.
    0x08
    ソフトブレーク(Software Interrupt,SWI)
    特権モード(SVC)
    SWI命令による割り込み,Linuxのシステム呼び出しはSWI命令によりソフト割り込みを起こし,ソフト割り込みによりカーネル空間に陥る.
    0x0C
    命令プリフェッチ中断(Prefetch Abort)
    中止モード
    プリフェッチ命令のエラー時にこの割り込みが発生します.
    0x10
    データアクセス中断(Data Abort)
    中止モード
    この割り込みは、データへのアクセスエラー時に発生します.
    0x14
    未使用(Not Used)
    未使用
    ユニット4
    0x18
    IRQ割込み(IRQ Interrupt)
    外部割り込みモード(IRQ)
    チップ内部の周辺機器の割り込みは、この割り込みを引き起こす.
    0x1C
    FIQ割込み(FIQ Interrupt)
    クイックブレークモード(FIQ)
    割り込みをすばやく処理すれば、この割り込みを使用できます.
    GICはARM社がCortex-A/Rカーネルに提供する割り込みコントローラであり、Cortex-MカーネルのNVICに似ている.現在GICには4つのバージョンがある:V 1~V 4、V 1は最も古いバージョンで、すでに廃棄されている.V 2~V 4は現在大量に使用されている.GIC V 2はARMv 7-Aアーキテクチャに使用され、I.MX 6 Uが使用する.ARMはGIC V 2に対してGIC 400という割り込みコントローラIPコアを開発した.GICが外部割り込み信号を受信するとARMカーネルに報告されるが、ARMカーネルは、VFIQ(仮想高速割り込み)、VIRQ(仮想外部割り込み)、FIQ、およびIRQの4つの信号のみをGICに提供する.
  • 割り込みID
  • GICは多くの割り込みソースを3つに分類します.
    ① SPI(Shared Peripheral Interrupt),    ,    ,   Core      ,       ,          SPI   (  !   SPI       ) 。      、      ,        Core      ,      Core。
    ② PPI(Private Peripheral Interrupt),    , GIC       ,             。                  ,             。
    ③ SGI(Software-generated Interrupt),    ,          ,      GICD_SGIR        ,      SGI             。

    割り込みソースはたくさんありますが、これらの異なる割り込みソースを区別するためには、割り込みIDである一意のIDを割り当てる必要があります.各CPUは最大1020個の割り込みIDをサポートし、割り込みID番号はID 0~ID 1019である.ID 0~ID 15:この16個のIDはSGIに割り当てられる.ID 16~ID 31:この16個のIDはPPIに割り当てられる.ID 32~ID 1019:この988個のIDはSPIに割り当てられており、GPIO割込み、シリアルポート割込みなどの外部割込みのように、あるIDがどの割込みに対応するかを具体的には半導体メーカーが実際の状況に応じて定義している.
  • GIC論理ブロック
  • GICアーキテクチャは2つの論理ブロックに分けられる:DistributorとCPU Interface、すなわち配布器側とCPUインタフェース側.Distributor(ディストリビュータ側):この論理ブロックは、各割り込みイベントの配布問題、すなわち、割り込みイベントがどのCPU Interfaceに送信されるべきかを処理する.配布器はすべての割り込みソースを収集し、各割り込みの優先度を制御することができ、常に優先度が最も高い割り込みイベントをCPUインタフェース側に送信する.配布器側が行う主な仕事は以下の通りである:1、グローバル中断使能制御.②、各割り込みのイネーブル又はクローズを制御する.③、割り込みごとの優先度を設定する.④、割り込みごとのターゲットプロセッサリストを設定します.⑤、各外部割り込みのトリガモードを設定する:レベルトリガまたはエッジトリガ.⑥各割り込みがグループ0に属するかグループ1に属するかを設定します.CPU Interface(CPUインタフェース端子):CPUインタフェース端子は名前を聞くとCPU Coreに接続されていることがわかり、各CPU CoreはGICで対応するCPU Interfaceを見つけることができる.CPUインタフェース端子は配布器とCPU Coreとの架け橋であり、CPUインタフェース端子は主に以下のように動作する:1、CPU Coreに送信された割り込み要求信号をオフまたはオフにする.②、応答が途切れる.③、割り込み処理完了を通知する.④、優先マスクを設定し、マスクによってCPU Coreに報告する必要のない割り込みを設定する.⑤、プリエンプトポリシーを定義する.⑥複数の割り込みが来た場合、優先度が最も高い割り込み通知をCPU Coreに選択する.
    (3)U-Boot起動フロー詳細
  • reset関数ソースコード詳細
  • 前述arch/arm/lib/vectors.S割り込みベクトルテーブルのreset,reset関数はarch/arm/cpu/armv 7/start.Sの中.35行でresetの定義を見て、ここでまたsave_にジャンプします.boot_params.
        .globl    reset
        .globl    save_boot_params_ret
    
    reset:
        /* Allow the board to save important registers */
        b    save_boot_params

    100行でsave_が定義されていますboot_params、ここでまたsaveにジャンプboot_params_ret .
    /*************************************************************************
     *
     * void save_boot_params(u32 r0, u32 r1, u32 r2, u32 r3)
     *    __attribute__((weak));
     *
     * Stack pointer is not yet initialized at this moment
     * Don't save anything to stack even if compiled with -O0
     *
     *************************************************************************/
    ENTRY(save_boot_params)
        b    save_boot_params_ret        @ back to my caller

    38行でsave_が定義されていますboot_params_ret
    save_boot_params_ret:
        /*
         * disable interrupts (FIQ and IRQ), also set the cpu to SVC32 mode,
         * except if in HYP mode already
         */
        mrs    r0, cpsr                @   cpsr     r0
        and    r1, r0, #0x1f        @ mask mode bits
        teq    r1, #0x1a        @ test for HYP mode
        bicne    r0, r0, #0x1f        @ clear all mode bits     r1   0X1A    ,  r0
        orrne    r0, r0, #0x13        @ set SVC(Supervisor) mode    r1   0X1A    ,  r0 #0x13
        orr    r0, r0, #0xc0        @ disable FIQ and IRQ
        msr    cpsr,r0

    下に進み続け、
    /*
     * Setup vector:
     * (OMAP4 spl TEXT_BASE is not 32 byte aligned.
     * Continue to use ROM code vector only in OMAP4 spl)
     */
    #if !(defined(CONFIG_OMAP44XX) && defined(CONFIG_SPL_BUILD))
        /* Set V=0 in CP15 SCTLR register - for VBAR to point to vector */
        mrc    p15, 0, r0, c1, c0, 0    @ Read CP15 SCTLR Register    CP15   c1        r0     
        bic    r0, #CR_V        @ V = 0  CR_V = (1 << 13),   SCTLR     bit13
        mcr    p15, 0, r0, c1, c0, 0    @ Write CP15 SCTLR Register   r0               SCTLR  
    
        /* Set vector address in CP15 VBAR register */
        ldr    r0, =_start       @ _start     uboot     ,    0X87800000
        mcr    p15, 0, r0, c12, c0, 0    @Set VBAR          r0      (    )    CP15   c12     ,    VBAR    。
    #endif

    さらに下に進むと、
        /* the mask ROM code should have PLL and others stable */
    #ifndef CONFIG_SKIP_LOWLEVEL_INIT
        bl    cpu_init_cp15        //     105 ,     CP15      ,     MMU    
        bl    cpu_init_crit       
    #endif
    
        bl    _main
    

    ここではcpu_を重点的に見ますinit_crit関数は259行で、
    #ifndef CONFIG_SKIP_LOWLEVEL_INIT
    /*************************************************************************
     *
     * CPU_init_critical registers
     *
     * setup important registers
     * setup memory timing
     *
     *************************************************************************/
    ENTRY(cpu_init_crit)
        /*
         * Jump to board specific initialization...
         * The Mask ROM will have already initialized
         * basic memory. Go here to bump up clock rate and handle
         * wake up conditions.
         */
        b    lowlevel_init        @ go setup pll,mux,memory
    ENDPROC(cpu_init_crit)
    #endif

    reset関数が最終的にlowlevelにジャンプすることがわかります.initと_mainという2つの関数です.後で分析します.