rpi_start.Sを読む (第3回)
続きです。
まずは、コメントです。
MMUに最低限の準備をします、ぐらいにとらえておけばよいのでしょうかねぇ。
さて、今回のメインはこちらです。
先に進みます。
まぁ、とにかくL1変換テーブルの先頭をr0に代入したという感じです。
次に進みます。
あとでr0を使うので温存しておいて、r1のほうを作業用に使うという感じですかね。
次に進みます。
先に進みましょう。
ここから、ループに入ります。
ということで、r1つまりL1_temp_tableの先頭からゼロを代入した8つのレジスタをどんどんメモリに転送していきます。
次に進みます。
L1_TABLE_SIZE(つまり0x4000)が格納されたr2から4*4*8を引きます。レジスタは32ビットなので4, stmiaが4回なので4, レジスタは8個転送されているので4*4*8ですね。
次に進みます。
bneのneはNot Equalつまりbneはr2がゼロでなければ1bに飛べと言っています。1bとは149行目の1:というラベルです。1bのbはbackのbでしょうか?
今回の処理をCっぽく書いてみると次のような感じでしょうか。
さてこれで、Ltemp_l1_tableが全部ゼロクリアされた状態になりました。
まずは、コメントです。
132 /* 133 * Set up a preliminary mapping in the MMU to allow us to run 134 * at KERNEL_BASE with caches on. 135 */キャッシュをONにしてKERNEL_BASEで動かすため、MMUに準備的なマッピングをセットアップします、とでも訳すのでしょうか? なんのこっちゃ。
MMUに最低限の準備をします、ぐらいにとらえておけばよいのでしょうかねぇ。
さて、今回のメインはこちらです。
136 /* Build page table from scratch */ 137 ldr r0, Ltemp_l1_table /* The page table address - entered into TTB later */ 138 mov r1, r0 /* Start address to clear memory. */ 139 /* Zero the entire table so all virtual addresses are invalid. */ 140 mov r2, #L1_TABLE_SIZE /* in bytes */ 141 mov r3, #0 142 mov r4, r3 143 mov r5, r3 144 mov r6, r3 145 mov r7, r3 146 mov r8, r3 147 mov r10, r3 148 mov r11, r3 149 1: stmia r1!, {r3-r8,r10-r11} 150 stmia r1!, {r3-r8,r10-r11} 151 stmia r1!, {r3-r8,r10-r11} 152 stmia r1!, {r3-r8,r10-r11} 153 subs r2, r2, #(4 * 4 * 8) /* bytes per loop */ 154 bne 1bちょっと長いですが、似た命令が多いので、大丈夫でしょう。
136 /* Build page table from scratch */ページテーブルをスクラッチからつくりますというコメントです。なるほど、以降の処理はページテーブルに関する処理というわけですね。
先に進みます。
137 ldr r0, Ltemp_l1_table /* The page table address - entered into TTB later */Ltemp_l1_tableのアドレスをr0にロードします。TTBとはTransration Table Baseの略ですね。Ltemp_l1_tableのところは、
258 Ltemp_l1_table: 259 /* Put the temporary L1 translation table just below the kernel. */ 260 .word 0x4000と書かれています。kernelのすぐ後ろにテンポラリのL1変換テーブルを置く、と読めます。0x4000の大きさのテーブルが確保されているってことですかね。
まぁ、とにかくL1変換テーブルの先頭をr0に代入したという感じです。
次に進みます。
138 mov r1, r0 /* Start address to clear memory. */これは、先ほどのr0つまりL1変換テーブルの先頭をr1にも代入しています。
あとでr0を使うので温存しておいて、r1のほうを作業用に使うという感じですかね。
次に進みます。
139 /* Zero the entire table so all virtual addresses are invalid. */テーブル全体をゼロにして、すべての仮想アドレスをinvalidにします。というコメントです。なんだかよくわかりませんが、ゼロにするようです。
140 mov r2, #L1_TABLE_SIZE /* in bytes */L1_TABLE_SIZEはarch/arm/include/arm32/pte.hで
#define L1_TABLE_SIZE 0x4000 /* 16K */と定義されていますので、
r2 = 0x4000; /* L1_TABLE_SIZE */ということになりますね。そういえば、さっきのL1_temp_tableは
260 .word 0x4000でしたね。なるほど、関係ありそうです。
先に進みましょう。
141 mov r3, #0 142 mov r4, r3 143 mov r5, r3 144 mov r6, r3 145 mov r7, r3 146 mov r8, r3 147 mov r10, r3 148 mov r11, r3レジスタr3に0を代入し、それをレジスタr4, r5, r6, r7, r8, r10, r11に代入しています。つまり、8つのレジスタをぜんぶゼロにしているようです。
ここから、ループに入ります。
149 1: stmia r1!, {r3-r8,r10-r11} 150 stmia r1!, {r3-r8,r10-r11} 151 stmia r1!, {r3-r8,r10-r11} 152 stmia r1!, {r3-r8,r10-r11}stmiaです。stmはレジスタ-メモリ転送命令の複数版で、iaはIncrement Afterということで、メモリアクセス後にポインタを増やす、でしたね。
ということで、r1つまりL1_temp_tableの先頭からゼロを代入した8つのレジスタをどんどんメモリに転送していきます。
次に進みます。
153 subs r2, r2, #(4 * 4 * 8) /* bytes per loop */subsのsubは減算命令です。subsの後ろのsはステータスレジスタを更新するためののsです。
L1_TABLE_SIZE(つまり0x4000)が格納されたr2から4*4*8を引きます。レジスタは32ビットなので4, stmiaが4回なので4, レジスタは8個転送されているので4*4*8ですね。
次に進みます。
154 bne 1bbneのbは分岐命令です。先のsubsの末尾のsで更新されたステータスフラグをみて、分岐します。見るステータスフラグはZ、つまりゼロかどうかです。
bneのneはNot Equalつまりbneはr2がゼロでなければ1bに飛べと言っています。1bとは149行目の1:というラベルです。1bのbはbackのbでしょうか?
今回の処理をCっぽく書いてみると次のような感じでしょうか。
r0 = &(Ltemp_l1_table); r1 = r0; r2 = 0x4000; /* L1_TABLE_SIZE */ r3 = 0; r4 = r3; r5 = r3; r6 = r3; r7 = r3; r8 = r3; r10 = r3; r11 = r3; do { for (int i = 0; i < 4; i++) { *(r1++) = r3; *(r1++) = r4; *(r1++) = r5; *(r1++) = r6; *(r1++) = r7; *(r1++) = r8; *(r1++) = r10; *(r1++) = r11; } r2 -= (4 * 4 * 8); } while (r2 != 0)素朴に、r3に0をセットして0x1000回のループにすればよいと思ったのですが、stmiaで8レジスタ一気に転送して、0x4000/(4*4*8)回のループのほうが効率的なんでしょうね。
さてこれで、Ltemp_l1_tableが全部ゼロクリアされた状態になりました。
コメント(0件)
- TB-URL http://www.tokuda.net/diary/0805/tb/