Help us understand the problem. What is going on with this article?

rt-threadのラズパイ2MMU設定

More than 1 year has passed since last update.

cortex-AのMMU勉強中ということでrt-threadのMMU設定を見てみる。

rt_hw_mmu_init()

rt-threadにおけるMMU設定の全体。

bsp/raspi2/cpu/mmu.c
void rt_hw_mmu_init(void)
{
    rt_hw_cpu_dcache_disable();
    rt_hw_cpu_icache_disable();
    rt_cpu_mmu_disable();

    /* set page table */
    /* 4G 1:1 memory */
    rt_hw_mmu_setmtt(0, 0xffffffff-1, 0, RW_CB);
    /* IO memory region */
    rt_hw_mmu_setmtt(0x44000000, 0x80000000-1, 0x44000000, RW_NCNBXN);

    /*rt_hw_cpu_dump_page_table(MMUTable);*/
    rt_hw_set_domain_register(0x55555555);

    rt_cpu_tlb_set(MMUTable);

    rt_cpu_mmu_enable();

    rt_hw_cpu_icache_enable();
    rt_hw_cpu_dcache_enable();
}

以降で各関数について説明していく。

rt_hw_mmu_setmtt()

bsp/raspi2/cpu/mmu.c
/* level1 page table, each entry for 1MB memory. */
volatile static unsigned long MMUTable[4*1024] __attribute__((aligned(16*1024)));
void rt_hw_mmu_setmtt(rt_uint32_t vaddrStart,
                      rt_uint32_t vaddrEnd,
                      rt_uint32_t paddrStart,
                      rt_uint32_t attr)
{
    volatile rt_uint32_t *pTT;
    volatile int i, nSec;
    pTT  = (rt_uint32_t *)MMUTable + (vaddrStart >> 20);
    nSec = (vaddrEnd >> 20) - (vaddrStart >> 20);
    for(i = 0; i <= nSec; i++)
    {
        *pTT = attr | (((paddrStart >> 20) + i) << 20);
        pTT++;
    }
}

メモリ変換テーブルの設定を行っている。

short-descriptionでの1段めのテーブルは立てたビットにより名称と使用方法が変わるが、rt-threadではSectionと呼ばれる1段目テーブルのみを使用する1MB単位でのメモリ変換を定義している。

1st-table-section.png

なお1段めテーブルのBit[1]が1かつBit[18]が0でSectionとなる。

このコードでは仮想アドレスvaddrStartからvaddrEndまでのアドレスを物理アドレスpaddrStartとリニアに対応付けている。

属性について

引数に指定している属性は以下の通り。

bsp/raspi2/cpu.mmu.c
#define DESC_SEC       (0x2)
#define CB             (3<<2)  //cache_on, write_back
#define CNB            (2<<2)  //cache_on, write_through
#define NCB            (1<<2)  //cache_off,WR_BUF on
#define NCNB           (0<<2)  //cache_off,WR_BUF off
#define AP_RW          (3<<10) //supervisor=RW, user=RW
#define AP_RO          (2<<10) //supervisor=RW, user=RO
#define XN             (1<<4)  // eXecute Never

#define DOMAIN0        (0x0<<5)
#define DOMAIN1        (0x1<<5)

/* Read/Write, cache, write back */
#define RW_CB          (AP_RW|DOMAIN0|CB|DESC_SEC)
/* Read/Write, cache, write through */
#define RW_CNB         (AP_RW|DOMAIN0|CNB|DESC_SEC)
/* Read/Write without cache and write buffer */
#define RW_NCNB        (AP_RW|DOMAIN0|NCNB|DESC_SEC)
/* Read/Write without cache and write buffer, no execute */
#define RW_NCNBXN      (AP_RW|DOMAIN0|NCNB|DESC_SEC|XN)
/* Read/Write without cache and write buffer */
#define RW_FAULT       (AP_RW|DOMAIN1|NCNB|DESC_SEC)

rt-threadではIOメモリである0x4400_0000から0x8000_0000-1までをRW_NCNBXNつまり、「実行不可、RW可、ドメイン0,キャッシュ/バッファOFF」とし(AP_ROじゃなくて良いのか?とも思うがrt-threadってそもそもユーザーモード使ってないし…)、それ以外をRW_CBつまり「実行可、RW可、ドメイン0、キャッシュON」としている。

ドメインについて

B3.7.3参照

short-descriptionでは16種類のドメインが設定でき、それぞれについて「No access」、「Clients」、「Managers」の設定が可能。
rt-threadでは全てのドメインが「Clients」に設定されている。
「Clients」ではメモリアクセスの権限がチェックされ、権限がない場合はパーミッションフォルトが発生する。

rt_cpu_tlb_set()

bsp/raspi2/cpu/cp15_gcc.S
.globl rt_cpu_tlb_set
rt_cpu_tlb_set:
    mcr     p15, #0, r0, c2, c0, #0
    dmb
    bx      lr

TTBR0に対してメモリ変換テーブルの先頭アドレスの設定。

TTBR0のフォーマットは以下の通り

32-bit-TTBR0.png

xは14-TTBCR.N(後述)。ここではTTBCR.N=0なのでx=14。
[31:x]はメモリ変換テーブルのアドレスをxビットシフトしたものになっている。
その他のビットは主にメモリ共有関連の設定になっているがあまり良くわかってないので要追記。

x=14なのでメモリ変換テーブルは1MB境界になっている必要がある。rt_cpu_tlb_set(MMUTable)という形で呼び出されるが,MMUTablealigned(16*1024 /*0x4000*/)なので1MB境界となっている。

TTBCRについて

rt-threadではTTBCRの設定は行っていないため、デフォルト値の0になっていると思われる。

最上位ビットEAEが0の場合はTTBCRは以下のshort-descriptor形式をとる。

short-descriptor_TTBCR.png

Nが0にになっているので、rt-threadではTTBR0しか使わないことになる。

rt_hw_set_domain_regiter()

bsp/raspi2/cpu/mmu.c
unsigned long rt_hw_set_domain_register(unsigned long domain_val)
{
    unsigned long old_domain;

    asm volatile ("mrc p15, 0, %0, c3, c0\n" : "=r" (old_domain));
    asm volatile ("mcr p15, 0, %0, c3, c0\n" : :"r" (domain_val) : "memory");

    return old_domain;
}

rt-threadでは16全てのドメインにClients(=0x01)を設定するため、
0x5555_5555を設定している(0x5=0b0101)

rt_cpu_mmu_enable()

bsp/raspi2/cpu/cp15_gcc.S
.globl rt_cpu_mmu_enable
rt_cpu_mmu_enable:
    mrc     p15, #0, r0, c1, c0, #0
    orr     r0, r0, #0x001
    mcr     p15, #0, r0, c1, c0, #0    @ set mmu enable bit
    dsb
    bx      lr

SCTLR.M[0]を有効にするだけ。

参考・引用URL

itage
ITAGEは「IT」のAGENCYになることを夢、目標として進化、変化していきます。「It’s It Agency」
http://www.itage.co.jp
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした