rpi_start.Sを読む (第10回)
2013/11/10(日) 12:28 NetBSD はてブ情報 はてブに登録 はてブ数

いよいよ10回目に入りました。

今回読むのは次の部分です。
    194 	/*
    195 	 * In theory, because the MMU is off, we shouldn't need all of this,
    196 	 * but let's not take any chances and do a typical sequence to set
    197 	 * the Translation Table Base.
    198 	 */
    199 	mov	r0, #0			/* SBZ */
    200 	Invalidate_I_cache(r0)
    201 
    202 	mcr	p15, 0, r0, c7, c14, 0	/* Clean and Invalidate Entire Data Cache */
    203 
    204         ldr     r2, Lctl_ID_dis		/* Disable I+D caches */
    205 	mrc	p15, 0, r1, c1, c0, 0	/*  "       "   "     */
    206 	and	r1, r1, r2		/*  "       "   "     */
    207 	mcr	p15, 0, r1, c1, c0, 0	/*  "       "   "     */
    208 
    209 	mcr	p15, 0, r0, c7, c10, 4	/* Drain the write buffers. */
まずはコメントです。
    194 	/*
    195 	 * In theory, because the MMU is off, we shouldn't need all of this,
    196 	 * but let's not take any chances and do a typical sequence to set
    197 	 * the Translation Table Base.
    198 	 */
うーん。どう訳すんでしょう。

理論上、MMUはオフなので、これから行う操作がすべて必要ではないけれど、この辺でやるしかないので、TTB(Translation Table Base)をセットする典型的な手順を実行します、って感じですかねぇ。

まぁ、先に進みましょうか。
    199 	mov	r0, #0			/* SBZ */
    200 	Invalidate_I_cache(r0)
SBZって何かとしらべたところ、SBZ = Should Be Zeroの略なんですね。ちなみに、SBO = Should Be Oneの略のようです。

movでレジスタr0をゼロにしてInvalidate_I_cache(reg)を実行します。

Invalidate_I_cache(reg)はずいぶん最初のほうに記述がありました。
     92 /*
     93  * Workaround Erratum 411920
     94  *
     95  *	- value of arg 'reg' Should Be Zero
     96  */
     97 #define Invalidate_I_cache(reg) \
     98 	.p2align 5;								\
     99 	mcr	p15, 0, reg, c7, c5, 0;	/* Invalidate Entire I cache */		\
    100 	mcr	p15, 0, reg, c7, c5, 0;	/* Invalidate Entire I cache */		\
    101 	mcr	p15, 0, reg, c7, c5, 0;	/* Invalidate Entire I cache */		\
    102 	mcr	p15, 0, reg, c7, c5, 0;	/* Invalidate Entire I cache */		\
    103 	nop;									\
    104 	nop;									\
    105 	nop;									\
    106 	nop;									\
    107 	nop;									\
    108 	nop;									\
    109 	nop;									\
    110 	nop;									\
    111 	nop;									\
    112 	nop;									\
    113 	nop;
Errata 411920に対応するためのI cacheを0にクリアします。
ちなみに、I cacheはInstruction cacheでD cacheはData cacheです。

c7はキャッシュ操作のレジスタです。ARM1176JZ-S™ Technical Reference Manualに、「MCR p15, 0, , c7, c5, 0 Invalidate entire Instruction Cache」とあります。
なんでかわかりませんが、4回ほど連発してますね。

このあたりから、マニュアルと首っ引きで調べる感じです。

それでは、202行目に戻りましょう。
    202 	mcr	p15, 0, r0, c7, c14, 0	/* Clean and Invalidate Entire Data Cache */
これも「MCR p15, 0, , c7, c14, 0 SBZ Clean and Invalidate Entire Data Cache.」とあります。
さっきがインストラクションキャッシュだったので、今度はデータキャッシュですね。

進めましょう。
    204         ldr     r2, Lctl_ID_dis		/* Disable I+D caches */
    205 	mrc	p15, 0, r1, c1, c0, 0	/*  "       "   "     */
    206 	and	r1, r1, r2		/*  "       "   "     */
    207 	mcr	p15, 0, r1, c1, c0, 0	/*  "       "   "     *
mrc, mcr命令にあるc1は Control Registerです。

Lctl_ID_disをr2にロードして。mcrでコントロールレジスタを読んで、Lctl_ID_disとのANDを取って、mrcで書き戻しています。。
I cache, D cacheをinvalidにしていますって、コメントのままですね。

ここからコントロールレジスタがたくさん出てくるので、フォーマットと定義を整理しておきましょう。

まずはレジスタのフォーマットです。
31-30292827-26252423222120-191817161514131211109876-43210
SBZFATRSBZEEVEXPUFISBZITSBZDTL4RRVIZFRSBSBOWCAM
それぞれのフィールドの定義は/sys/arch/arm/include/armreg.hにあります。
  /* CPU control register (CP15 register 1) */
  #define CPU_CONTROL_MMU_ENABLE	0x00000001 /* M: MMU/Protection unit enable */
  #define CPU_CONTROL_AFLT_ENABLE	0x00000002 /* A: Alignment fault enable */
  #define CPU_CONTROL_DC_ENABLE		0x00000004 /* C: IDC/DC enable */
  #define CPU_CONTROL_WBUF_ENABLE 	0x00000008 /* W: Write buffer enable */
  #define CPU_CONTROL_32BP_ENABLE 	0x00000010 /* P: 32-bit exception handlers */
  #define CPU_CONTROL_32BD_ENABLE 	0x00000020 /* D: 32-bit addressing */
  #define CPU_CONTROL_LABT_ENABLE 	0x00000040 /* L: Late abort enable */
  #define CPU_CONTROL_BEND_ENABLE 	0x00000080 /* B: Big-endian mode */
  #define CPU_CONTROL_SYST_ENABLE 	0x00000100 /* S: System protection bit */
  #define CPU_CONTROL_ROM_ENABLE	0x00000200 /* R: ROM protection bit */
  #define CPU_CONTROL_CPCLK		0x00000400 /* F: Implementation defined */
  #define CPU_CONTROL_SWP_ENABLE	0x00000400 /* SW: SWP{B} perform normally. */
  #define CPU_CONTROL_BPRD_ENABLE 	0x00000800 /* Z: Branch prediction enable */
  #define CPU_CONTROL_IC_ENABLE   	0x00001000 /* I: IC enable */
  #define CPU_CONTROL_VECRELOC		0x00002000 /* V: Vector relocation */
  #define CPU_CONTROL_ROUNDROBIN	0x00004000 /* RR: Predictable replacement */
  #define CPU_CONTROL_V4COMPAT		0x00008000 /* L4: ARMv4 compat LDR R15 etc */
  #define CPU_CONTROL_FI_ENABLE		0x00200000 /* FI: Low interrupt latency */
  #define CPU_CONTROL_UNAL_ENABLE	0x00400000 /* U: unaligned data access */
  #define CPU_CONTROL_XP_ENABLE		0x00800000 /* XP: extended page table */
  #define CPU_CONTROL_V_ENABLE		0x01000000 /* VE: Interrupt vectors enable */
  #define CPU_CONTROL_EX_BEND		0x02000000 /* EE: exception endianness */
  #define CPU_CONTROL_NMFI		0x08000000 /* NMFI: Non maskable FIQ */
  #define CPU_CONTROL_TR_ENABLE		0x10000000 /* TRE: */
  #define CPU_CONTROL_AF_ENABLE		0x20000000 /* AFE: Access flag enable */
  #define CPU_CONTROL_TE_ENABLE		0x40000000 /* TE: Thumb Exception enable */
ファイル後半で定義されているコントロールレジスタに関連するのは次の四つ (Lcontrol_set, Lcontrol_clr, Lcontrol_wax, Lctl_ID_dis) になります。waxって何でしょうねぇ。
    268 	/* bits to set in the Control Register */
    269 Lcontrol_set:
    270 	.word CPU_CONTROL_MMU_ENABLE  | \
    271 	      CPU_CONTROL_AFLT_ENABLE | \
    272 	      CPU_CONTROL_DC_ENABLE   | \
    273 	      CPU_CONTROL_WBUF_ENABLE |    /* not defined in 1176 */   \
    274 	      CPU_CONTROL_32BP_ENABLE | \
    275 	      CPU_CONTROL_32BD_ENABLE | \
    276 	      CPU_CONTROL_LABT_ENABLE | \
    277 	      CPU_CONTROL_SYST_ENABLE | \
    278 		(1 << 16) | 	/* SBO - Global enable for data tcm */ \
    279 		(1 << 18) |	/* SBO - Global enable for insn tcm */ \
    280 	      CPU_CONTROL_IC_ENABLE
    281 
    282 
    283 	/* bits to clear in the Control Register */
    284 Lcontrol_clr:
    285 	.word	0
    286 
    287 	/* bits to "write as existing" in the Control Register */
    288 Lcontrol_wax:
    289 	.word	(3 << 30) | \
    290 		(1 << 29) | \
    291 		(1 << 28) | \
    292 		(3 << 26) | \
    293 		(3 << 19) | \
    294 		(1 << 17) | \
    295 	        (1 << 10)
    296 
    297 	/* bits to disable the caches */
    298 Lctl_ID_dis:
    299 	.word	~(CPU_CONTROL_IC_ENABLE|CPU_CONTROL_DC_ENABLE)
それぞれを一覧にしてみます。Lcontrol_clrは全部0なので省略です。
定義31-30292827-26252423222120-191817161514131211109876-43210
SBZFATRSBZEEVEXPUFISBZITSBZDTL4RRVIZFRSBSBOWCAM
Lctl_ID_dis1 1111 1111111 11111110111111111011
Lcontrol_wax1 1111 1000001 10100000010000000000
Lcontrol_set0 0000 0000000 01010001000101111111
209行目に戻り、ふたたび、c7のキャッシュまわりです。
    209 	mcr	p15, 0, r0, c7, c10, 4	/* Drain the write buffers. */
うーん、マニュアルでは「MCR p15,0,,c7,c10,4 ; Data Synchronization Barrier operation.」と書いてあります。どういうことでしょう?

どうやら、昔はDrain the write buffersと呼ばれていたそうです。マニュアルを読んでもまるで自信はないですが、どうやらバリアというだけあって、この命令より前のメモリの操作やらキャッシュやらの操作が完了するまで待ちますよ、ってな感じの動きをするようです。

たしかに、ここまでいろいろキャッシュの操作をしてきたので、それらの操作がちゃんと終わるまで待ちましょう、という命令のようです。

mcr, mrc命令はマニュアルを拾い読みするだけでは理解に至らないことが多くて苦戦します。

名前:  非公開コメント   

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