rpi_start.Sを読む (第7回)
2013/11/09(土) 5:28 NetBSD はてブ情報 はてブに登録 はてブ数

さて、前回175行目にジャンプしたところで終わったので、175行目から始めましょう。

今回は、どどんと10行読みます。ちょっと長いかな。
    175 3:	ldmia	itable!, {va,pa,n_sec,attr}
    176 	mov	n_sec, n_sec, lsr #L1_S_SHIFT
    177 	/* Convert va to l1 offset:	va = 4 * (va >> L1_S_SHIFT)	*/
    178 	mov	va, va, LSR #L1_S_SHIFT
    179 	mov	va, va, LSL #2
    180 	/* Convert pa to l1 entry:	pa = (pa & L1_S_FRAME) | attr	*/
    181 	and	pa, pa, l1sfrm
    182 	orr	pa, pa, attr
    183 	cmp	n_sec, #0
    184 	bne	2b
さて始めましょう。
    175 3:	ldmia	itable!, {va,pa,n_sec,attr}
ldmは複数アドレスからのロード、iaは転送ごとにitableをインクリメントするのでした。
itableにはmmu_init_tableのアドレスが入っており、
vapansecattr
0x00x00x6430330x412
0xC00000000x00x6430330x041E
0xF20000000x200000000x010FFFFF0x0412
といった感じにメモリに展開されていたわけですから、ldmia命令によって
  va = 0x0
  pa = 0x0;
  n_sec = 0x643033;
  attr = 0x0412;
てな感じに、各レジスタに値が読み込まれます。

先に進みましょう。
    176 	mov	n_sec, n_sec, lsr #L1_S_SHIFT
movでシフト演算ができるそうで、176行目もそのパターンですね。
lsrは(Logical Shift Right)で右シフト。L1_S_SHIFTが20だったので、
  n_sec = n_sec >> 20;
ということで0x643033 >> 20ですから0x6になります。n_sec = 0x6。
MMU_INITマクロの3つ目はn_secが0x010FFFFFだったので、0x010FFFFF >> 20はn_sec = 0x10ですね。

カーネルのサイズが4MBのところを0x6MBぶん、ペリフェラルの所は16MBなので0x10MBぶん。カーネルは1MB多めにするって書いてありましたけど2MB増えているような気がしますが、よくわかりません。

n_secはセクション数ということで、カーネルは4セクション、ペリフェラルは16セクションということになります。

次に進みます。
    177 	/* Convert va to l1 offset:	va = 4 * (va >> L1_S_SHIFT)	*/
    178 	mov	va, va, LSR #L1_S_SHIFT
    179 	mov	va, va, LSL #2
これもmovを使ったシフト演算です。やっていることはコメントのとおりですね。vaをL1_S_SHIFT分だけ右シフトさせ、4倍(つまり左シフト2)します。

ではなぜ、4倍するんでしょうか?

コメントにva からL1オフセットに変換する、とありますね。32ビットのpa+attrを入れるとアドレスは4つ進むから、L1オフセットは4刻みで増える、だから4倍するのですね。

実際の数字がどうなるかというと、カーネルとペリフェラルのそれぞれで次のようになります。
  va = 4 * (0xC0000000 >> 20) = 0x00002000
  va = 4 * (0xF2000000 >> 20) = 0x00003C80
L1オフセットが計算できました。

つぎは、PAをL1エントリに変換です。
    180 	/* Convert pa to l1 entry:	pa = (pa & L1_S_FRAME) | attr	*/
    181 	and	pa, pa, l1sfrm
    182 	orr	pa, pa, attr
これもコメントのとおりですね。pa & L1_S_FRAMEしてからattrでORをとると。

L1_S_FRAMEが0xFFF00000ですから、ページテーブルのフォーマットに合わせて、上位12ビットにセクションを入れて下位20ビットにアトリビュートを入れているわけですね。

第4回で触れたページテーブルのフォーマットを再掲しておきます。
31-20191817161514-1211-1098-543210
セクションのベースアドレス(12bit)SBZ0nGSAPXTEXAPIMPドメインXNCB10
先に進みましょう。
    183 	cmp	n_sec, #0
    184 	bne	2b
ここはループの条件ですね。n_secと0を比較して、番兵の0つまりMMU_INIT(0, 0, 0, 0)じゃなければラベル2、つまり169行目にジャンプせよ、ということになります。

ということで、今回ぶんをCっぽくしてみると次のような感じでしょうか。
  va = *(itable++);
  pa = *(itable++);
  n_sec = *(itable++);
  attr = *(itable++);

  n_sec = n_sec >> L1_S_SHIFT; /* L1_S_SHIFT = 20 */
  va = 4 * (va >> L1_S_SHIFT);
  pa = (pa & L1_S_FRAME) | attr; /* L1_S_FRAME = 0xFFF00000 */
  if (n_sec != 0)
    goto 162行目

名前:  非公開コメント   

  • TB-URL  http://www.tokuda.net/diary/0809/tb/