ARM のoverlayについて

ARM のoverlayについて調べてみました。

## 動機

Cortex-Mを使ったシステムでARMのOverlayを使う必要が出てきた。というか提供されたサンプルコードがOverlayをバリバリ利用していたという理由です。

## Overlayとは

ARMのOverlay機能とは、Cortex-M等のMMUの無いプロセッサにおいて、動的にメモリのある領域を切り替えて、その切り替えたエリアを使ってコードを実行する機能です。

簡単に言うと「バンク切り替えでコード実行」する機能です。

よく使われる例として、RAMの限られた環境にて、FLASH等から動的にコードをRAMにコピーして実行する場合などに利用します。

ARM純正の開発環境のMDK-ARMとDS-5ではOverlay機能が使えます。

## Overlayのサンプルコード

ARMがOverlayのサンプルコードを用意しているので、読んでみました。

overlay の領域を管理する構造体　roとrwとziを切り替える。

```c:overlay_manager.c
/* struct to hold addresses and lengths */
typedef struct overlay_region_t_struct
{
        void* load_ro_base;
        void* load_rw_base;
        void* exec_zi_base;
        unsigned int ro_length;
        unsigned int zi_length;
} overlay_region_t;

```

overlayの領域にコードとデータをロードする関数。roとrwをコピーして、ziに０を設定する。

```c
void load_overlay(int n)
{
        const overlay_region_t * selected_region;
...       
        /* set selected region */
        selected_region = &overlay_regions[n-1];
        
        /* load code overlay */
        memcpy(code_base, selected_region->load_ro_base, selected_region->ro_length);
        
        /* load data overlay */
        memcpy(data_base, selected_region->load_rw_base, (unsigned int)selected_region->exec_zi_base - (unsigned int)data_base);
        
        /* Comment out the next line if your overlays have any static ZI variables
         * and should not be reinitialized each time, and move them out of the
         * overlay region in your scatter file */
        memset(selected_region->exec_zi_base, 0, selected_region->zi_length);
...        
}
```

Overlay領域のアドレスと長さはリンカから取得する。

Scatterファイル　(リンカスクリプト)でro,　rwとziの領域を設定する。

```
    CODE_ONE 0x08400000 OVERLAY 0x4000
    {
        overlay_one.o (+RO)
    }

    CODE_TWO 0x08400000 OVERLAY 0x4000
    {
        overlay_two.o (+RO)
    }
    
    DATA_ONE 0x08700000 OVERLAY 0x4000
    {
        overlay_one.o (+RW,+ZI)
    }
    
    DATA_TWO 0x08700000 OVERLAY 0x4000
    {
        overlay_two.o (+RW,+ZI)
    }
```

リンカのセクション情報を読み出し構造体に値を設定するアセンブリソースコード

```
        AREA    overlay_list, DATA, READONLY

        ; Linker-defined symbols to use
        
        IMPORT ||Load$$CODE_ONE$$Base||
        IMPORT ||Load$$CODE_TWO$$Base||
        IMPORT ||Load$$DATA_ONE$$Base||
        IMPORT ||Load$$DATA_TWO$$Base||

        IMPORT ||Image$$CODE_ONE$$Base||
        IMPORT ||Image$$DATA_ONE$$Base||
        IMPORT ||Image$$DATA_ONE$$ZI$$Base||
        IMPORT ||Image$$DATA_TWO$$ZI$$Base||

        IMPORT ||Image$$CODE_ONE$$Length||
        IMPORT ||Image$$CODE_TWO$$Length||

        IMPORT ||Image$$DATA_ONE$$ZI$$Length||
        IMPORT ||Image$$DATA_TWO$$ZI$$Length||

        ; Symbols to export
        
        EXPORT code_base
        EXPORT data_base
        EXPORT overlay_regions

; Common base execution addresses of the two OVERLAY regions

code_base DCD ||Image$$CODE_ONE$$Base||
data_base DCD ||Image$$DATA_ONE$$Base||

; Array of details for each region -
; see overlay_manager.c for structure layout

overlay_regions
; overlay 1
        DCD ||Load$$CODE_ONE$$Base||
        DCD ||Load$$DATA_ONE$$Base||
        DCD ||Image$$DATA_ONE$$ZI$$Base||
        DCD ||Image$$CODE_ONE$$Length||
        DCD ||Image$$DATA_ONE$$ZI$$Length||
        
; overlay 2     
        DCD ||Load$$CODE_TWO$$Base||
        DCD ||Load$$DATA_TWO$$Base||
        DCD ||Image$$DATA_TWO$$ZI$$Base||
        DCD ||Image$$CODE_TWO$$Length||
        DCD ||Image$$DATA_TWO$$ZI$$Length||


        END
```

実際に使う場合は関数を呼ぶ前にロードしてから実行する。

```
void main(void)
{
        load_overlay(1);
        func1();

        load_overlay(2);
        func2();
}
```


## 注意するべきこと

* armlinkに--datacompressor=offを指定する。
* overlay領域にあるコードはロードしてからでないと実行できないです。ロードしていない状態で実行するとぶっ飛びます。
* ARMのDS-5はoverlayを使ったコードをデバッガで実行できますが、それ以外の環境ではデバッガが使えません。


## 参考ページ
* http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.faqs/ka4234.html
* http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0206ij/Cchihacc.html