SylixOS ARM BSP第2編【startup.S】


このブログはSylixOS ARM BSPの連載第2編で、主にstartupを紹介している.Sファイルは具体的に実装される.
startup.SはBSP起動コードのエントリであり、通常bootloaderによりSylixOSミラーをマウント後に呼び出されるが、以下、S 3 C 2440 Aプロセッサを例に、ブロック毎にstartupを紹介する.Sコード.
#ifndef ASSEMBLY
#define ASSEMBLY 1
#endif

このコードは、アセンブリプログラムである後に参照されるヘッダファイルを通知します.
#include <arch/assembler.h>

オペレーティングシステムのアセンブリヘッダファイルを参照します.このヘッダファイルは、コンパイラとプラットフォームのタイプに基づいて、多くのコンパイラとプラットフォームに関連する処理マクロを定義し、異なるプラットフォーム、異なるコンパイラ間のアセンブリ言語のキーワードの違いを統一することができます.例えばFILE_BEGIN()マクロは、アセンブリ言語ファイルの開始を表すこのファイルに定義されます.
#define UND_STACK_SIZE  0x00001000
#define ABT_STACK_SIZE  0x00001000
#define FIQ_STACK_SIZE  0x00001000
#define IRQ_STACK_SIZE  0x00001000
#define SVC_STACK_SIZE  0x00001000
#define SYS_STACK_SIZE  0x00001000

このコードは、ARMの各モードにおけるプリセットスタックのサイズを定義し、一般的には調整する必要はありません.
IMPORT_LABEL(archIntEntry)
IMPORT_LABEL(archAbtEntry)
IMPORT_LABEL(archPreEntry)
IMPORT_LABEL(archUndEntry)
IMPORT_LABEL(archSwiEntry)
IMPORT_LABEL(sdramInit)
IMPORT_LABEL(targetInit)
IMPORT_LABEL(bspInit)

IMPORT_LABEL()は、このファイルが参照する必要がある外部記号を表し、Cプログラムのexternキーワードに相当します.
SECTION(.vector)

以下に示すすべてのコードまたは文字プールは、コンパイル後に名前で格納.vertorのセクションでは、リンクスクリプトに基づいて、リンクをシステムエントリに設定します.
FUNC_DEF(vector)
    LDR     PC, resetEntry
    LDR     PC, undefineEntry
    LDR     PC, swiEntry
    LDR     PC, prefetchEntry
    LDR     PC, abortEntry
    LDR     PC, reserveEntry
    LDR     PC, irqEntry
    LDR     PC, fiqEntry
    FUNC_END()
    
FUNC_LABEL(resetEntry)
    .word   reset
FUNC_LABEL(undefineEntry)
    .word   archUndEntry
FUNC_LABEL(swiEntry)
    .word   archSwiEntry
FUNC_LABEL(prefetchEntry)
    .word   archPreEntry
FUNC_LABEL(abortEntry)
    .word   archAbtEntry
FUNC_LABEL(reserveEntry)
    .word   0
FUNC_LABEL(irqEntry)
    .word   archIntEntry
FUNC_LABEL(fiqEntry)
    .word   0

FUNC_DEF()は定義関数を表し、ここでvectorという関数を定義し、順序によってこの関数は.vectorセクションのエントリ関数.
FUNC_END()は関数の終わりを表します.
このコードはARMベクトル仕様に従って作成されたジャンプテーブルであり、異なる異常に入って異なるアドレスにジャンプし、ここではARM FIQの高速割り込みは処理されていない.SylixOSのデフォルトではFIQ異常を引き継ぐことはなく、ユーザーが必要であれば自分で関連処理関数を作成することができることを示している.
以上のコードから,システムリセットベクトルは最終的にreset関数(またはラベル)にジャンプし,次にreset関数実装を見ることができる.
SECTION(.text)

SECTION(.vector)の意味と同様に、以下のコードまたは文字プールが存在することを示す.textセクションにあります.ここで説明する必要があるのは、一般的に1つのプログラムが少なくとも3つのセグメント(セグメント)に分けられ、それぞれコードセグメント(.text)、データセグメント(.data)、クリアセグメント(.bss)である.ここで、コードセグメントに格納されるのは、一般的にプログラムコードと実行時に変更されないテーブル構造である.データ・セグメントには、主に初期値のグローバル変数が格納されます.クリアセグメントには、プライマリ・プログラムを実行する前にクリア操作が必要なグローバル変数が格納されます.リンクは、リンクスクリプトに基づいて、リンクtargetの各セクション(セグメント)のメモリレイアウトを決定します.具体的なリンクスクリプトの作成は、後述する章で説明します.
FUNC_DEF(reset)
    LDR     R0 , =WTCON
    LDR     R1 , =0x0
    STR     R1 , [R0]

reset関数は、まず2440プロセッサの内部ウォッチドッグを閉じて、起動中にウォッチドッグにリセットされないようにします.ここでは、ターゲットマシンがSMP(対称マルチプロセッサ)プロセッサ、例えばARM Cortex-A 9マルチコアであれば、すべてのコアプログラムエントリがresetであるため、reset関数が最初からこのコアをプライマリコア(primary)またはセカンダリコア(secondary)と判断する必要があり、システム起動時に異なるコア初期化順序が異なるが、マルチタスク状態に入った後、各コア間に明確な違いはない.
    LDR     R0 , =0x31800000                   /*                    */
    MSR     CPSR_c, #(UND32_MODE | DIS_INT)
    MOV     SP , R0
    SUB     R0 , R0, #UND_STACK_SIZE
    MSR     CPSR_c, #(ABT32_MODE | DIS_INT)
    MOV     SP , R0
    SUB     R0 , R0, #ABT_STACK_SIZE
    MSR     CPSR_c, #(IRQ32_MODE | DIS_INT)
    MOV     SP , R0
    SUB     R0 , R0, #IRQ_STACK_SIZE
    MSR     CPSR_c, #(FIQ32_MODE | DIS_INT)
    MOV     SP , R0
    SUB     R0 , R0, #FIQ_STACK_SIZE
    MSR     CPSR_c, #(SVC32_MODE | DIS_INT)
    MOV     SP , R0
    SUB     R0 , R0, #SVC_STACK_SIZE
    MSR     CPSR_c, #(SYS32_MODE | DIS_INT)
    MOV     SP , R0
    SUB     R0 , R0, #SYS_STACK_SIZE
    MSR     CPSR_c, #(SVC32_MODE | DIS_INT)

このセグメントコードは、ARMプロセッサの様々なモードでのスタックを初期化し、ARMプロセッサは、スタックが高アドレスから低アドレスに増加することをサポートするとともに、スタックが低アドレスから高アドレスに増加することをサポートするが、一般的には、高アドレスから低アドレスに増加するモードを使用する.したがって、スタックの実点は、bspMapによるカーネルの高アドレス位置に定義される.h設定メモリレイアウトは、後でbspMap.hで詳しく紹介します.
    BL      sdramInit
    BL      targetInit

ARMスタックの初期化が完了すると、2440のSDRAMインタフェースとPPLロックリングを初期化するために2つのサブ関数を呼び出します.もちろん、異なるプロセッサに対しても、ここのコードは異なります.bootloaderによって起動されると、実際にはこの部分のコードは必要ありません.bootloaderは関連するパラメータを初期化しました.
    LDR     R1 , =_etext                    /*  -> ROM data end             */
    LDR     R2 , =_data                     /*  -> data start               */
    LDR     R3 , =_edata                    /*  -> end of data              */
1:
    CMP     R2 , R3                         /*  check if data to move       */
    LDRLO   R0 , [R1] , #4                  /*  copy it                     */
    STRLO   R0 , [R2] , #4
    BLO     1b                              /*  loop until done             */

このコードは領域コピー関数です.このコードがデータ・セグメント(.data)に初期値を付与していることを知るだけでいいです.ここでは、ロード・セグメントと実行セグメントが異なる場合の処理サポートについて、リンク・スクリプトの内容に基づいて読者自身が関連知識を調べる必要があります.もちろんRealCoderは、ユーザーBSPウィザードでユーザーが設定した関連パラメータに基づいて、リンクスクリプトの生成を自動的に完了します.
    MOV     R0 , #0                          /*  get a zero                  */
    LDR     R1 , =__bss_start                /*  -> bss start                */
    LDR     R2 , =__bss_end                  /*  -> bss end                  */
2:
    CMP     R1 , R2                          /*  check if data to clear      */
    STRLO   R0 , [R1],   #4                  /*  clear 4 bytes               */
    BLO     2b                               /*  loop until done             */

以上のコードは、データ・セグメント(.data)の初期値と類似しており、このコードは、ゼロ・セグメント(.bss)のゼロ・オペレーション・ループである.
以上のコードは、コードセグメント(.text)がbootloaderによって初期化され、データセグメント(.data)とクリアセグメント(.bss)がBSPエントリ関数によって初期化され、この3つのセグメントが初期化されると、bspInit()関数に入ってオペレーティングシステムを正式に初期化し、bspInit()関数コードを呼び出すことができると結論した.
    LDR     R10, =bspInit
    MOV     LR , PC
    BX      R10

startup.Sファイルの最後にFILEがあります.END()は、FILEとBEGIN()文は対称的に使用され、アセンブリが終了したことを示します.
(この編完)