メッセージ欄

分類 【NetBSD】 で検索

一覧で表示する

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

前回の終わりに169行目にジャンプしたところから再開します。

今回読むのは以下の部分です。
    169 2:	str	pa, [l1table, va]
    170 	add	va, va, #4
    171 	add	pa, pa, #(L1_S_SIZE)
    172 	adds	n_sec, n_sec, #-1
    173 	bhi	2b
まずは169行目から。
    169 2:	str	pa, [l1table, va]
strはストア命令です。無印なので32ビットストアですね。レジスタpaをアドレス[l1table, va]にストアします。角かっこがいやらしいですね。

[Rn, Rm]はMem[Rn + Rm]ですから、
  *(l1table + va) = pa;
ということになります。Ll1_tableは.word 0x4000の空間でしたね。
    170 	add	va, va, #4
    171 	add	pa, pa, #(L1_S_SIZE)
addは加算ですね。L1_S_SIZEはセクションのサイズ、つまり1MBですから
  va += 4;
  pa += 0x00100000; /* L1_S_SIZEは1M */
となります。

次に進みます。
    172 	adds	n_sec, n_sec, #-1
    173 	bhi	2b
addsのaddは加算命令で、のこりのsはステータスレジスタの更新あり、でしたね。
セクションから1減算し、ゼロでなければラベル2にジャンプする、という処理になりますね。つまり、今回読んでいるソースはn_secでループしているわけですね。

ループを抜けると、再びラベル3の処理に入ります。そして、新しいMMU_INITマクロで設定したva, pa, n_sec, attrを読み込んで、vaとpaを適切に変換して、また、今回読んだループに入るというわけです。二重ループをこうやって実現しているんですね。

しかし、よくわからないのが173行目にあるbhiのhiです。
これは、キャリーフラグが1かつゼロフラグが0である、という意味になります。

キャリーフラグが1とは桁あふれが発生した場合で、ゼロフラグが0とは命令の結果が0でない(0ならフラグは1)である、という意味です。

なるほど、n_secから1を引いたときにゼロになればゼロフラグが1になりそうです。
一方で、キャリーフラグはn_secつまり0x06や0x10からマイナス1されるだけなので、ちっとも桁あふれなど起きなさそうです。

良く考えると、マイナス1を2の補数で表すと全部の桁が1になります。全部の桁が1に対して正の数を足せば、桁あふれが起きそうな気がします。もしかすると、それでキャリーフラグが立つのかもしれません。

だったら、ゼロフラグだけ見ていればよい気もします。すっきりしないなぁ。

すっきりしませんが、今回読んだ部分をCっぽく書いて終わりにしましょう。
do {
  *(l1table + va) = pa;
  va += 4;
  pa += 0x00100000; /* L1_S_SIZEは1M */
} while (--n_sec > 0)

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行目

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

第3回で154行目まできていましたが、第4回と第5回のMMU_INITマクロでずいぶんと寄り道してしまいました。

今回は、第3回の154行目から空行をはさんで、156行目から始めましょう。
    156 	/* Now create our entries per the mmu_init_table. */
    157 	l1table	.req r0
    158 	va	.req r1
    159 	pa	.req r2
    160 	n_sec	.req r3
    161 	attr	.req r4
    162 	itable	.req r5
    163 	l1sfrm	.req r6
    164 
    165 	adr	itable, mmu_init_table
    166 	ldr	l1sfrm, Ll1_s_frame
    167 	b	3f
まずは、mmu_init_tableのエントリーを作ります。というコメントからスタートです。
    156 	/* Now create our entries per the mmu_init_table. */
    157 	l1table	.req r0
    158 	va	.req r1
    159 	pa	.req r2
    160 	n_sec	.req r3
    161 	attr	.req r4
    162 	itable	.req r5
    163 	l1sfrm	.req r6
157行目から163行目に.recというのが出てきています。これはGNU ASのディレクティブと呼ばれるものだそうです。

レジスタに名前を付ける、と思っていればよさそうです。r0はl1tableと呼びますよ、ということでしょうね。ここから先が読みやすくなっていいですねぇ。

それでは次です。
    165 	adr	itable, mmu_init_table
adrは先ほども出てきた疑似命令です。mmu_init_tableのアドレスをitableにロードします。mmu_init_tableは、第3回と第4回でさんざんやったMMU_INITマクロですね。

先に進みます。
    166 	ldr	l1sfrm, Ll1_s_frame
ldrはロード命令です。l1sfrmにラベルLl1_s_frameの値をロードします。
Ll1_s_frameは後ろのほうに定義されています。
    255 Ll1_s_frame:
    256 	.word	L1_S_FRAME
つまりL1_S_FRAMEの値をl1sfrmにロードするわけです。L1_S_FRAMEは先のpte.hに書かれています。
  #define    L1_S_SIZE    0x00100000    /* 1M */
  #define    L1_S_OFFSET    (L1_S_SIZE - 1)
  #define    L1_S_FRAME    (~L1_S_OFFSET)
  #define    L1_S_SHIFT    20
つまり、L1_S_FRAME = ~(0x00100000 - 1)=0xFFF00000です。

ということで、l1sfrm = 0xFFF00000;になります。
    167 	b	3f
bだけなので無条件ジャンプ。ラベルは3fなので3、つまり175行目にジャンプします。3fのfはなんでしょうか... forwardのfかな?

ということで、今回は実質3行だけでした。Cっぽく書いてみます。
  itable = &mmu_init_table;
  l1sfrm = 0xFFF00000; /* L1_S_FRAME (12bit) */
  goto 175行目

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

MMU_INITマクロの続編です。前回だいぶ解明したおかげで残りは順調に進みそうです。

二つ目のMMU_INITマクロを読み解きましょう。
    314 	MMU_INIT(KERNEL_BASE, 0x0,
    315 	    (_end - KERNEL_BASE + 2 * L1_S_SIZE - 1),
    316 	    L1_S_PROTO | L1_S_AP_KRW  | L1_S_B | L1_S_C)
三つめまでの引数は先ほどのほぼ同様ですね。KERNEL_BASEもわかっているので問題ありません。
最後の引数も新しいのはL1_S_B, L1_S_Cの二つです。
おなじみ、pte.hで定義されています。先ほどのL1_S_IMPの上にいました。
  /* L1 Section Descriptor */
  #define L1_S_B          0x00000004      /* bufferable Section */
  #define L1_S_C          0x00000008      /* cacheable Section */
  #define L1_S_IMP        0x00000010      /* implementation defined */
ですから、L1_S_PROTO | L1_S_AP_KRW | L1_S_B | L1_S_C = 0x0012 | 0x0400 | 0x0004 | 0x0008 = 0x041Eです。

ということで、
    314 	MMU_INIT(KERNEL_BASE, 0x0,
    315 	    (_end - KERNEL_BASE + 2 * L1_S_SIZE - 1),
    316 	    L1_S_PROTO | L1_S_AP_KRW  | L1_S_B | L1_S_C)
というMMU_INITは
  va = 0xC0000000;
  pa = 0x0;
  n_sec = 0x643033;
  attr = 0x041E;
と表現できることがわかります。

さて、最後のMMU_INITマクロです。
コメントによると16MBのペリフェラルのマップとのこと。メモリマップI/Oされた周辺機器に関するエントリのようですね。
    318 	/* Map the 16MB of peripherals */
    319 	MMU_INIT(RPI_KERNEL_IO_VBASE, RPI_KERNEL_IO_PBASE,
    320 	    (RPI_KERNEL_IO_VSIZE + L1_S_SIZE - 1),
    321 	    L1_S_PROTO | L1_S_AP_KRW)
これは、四つ目の引数が一つ目のMMU_INITマクロと同じですから最初の三つの引数が読み解ければよいですね。

まずは、RPI_KERNEL_IO_VBASE, RPI_KERNEL_IO_PBASEです。

これは、arch/evbarm/rpi/rpi.hにある
  #define    RPI_KERNEL_IO_VBASE        BCM2835_PERIPHERALS_VBASE
  #define    RPI_KERNEL_IO_PBASE        BCM2835_PERIPHERALS_BASE
  
  #define    RPI_KERNEL_IO_VSIZE        BCM2835_PERIPHERALS_SIZE
からのarch/arm/broadcom/bcm2835reg.hにおいて定義されています。
  #define    BCM2835_PERIPHERALS_BASE    0x20000000
  #define    BCM2835_PERIPHERALS_SIZE    0x01000000    /* 16MBytes */
  
  #define BCM2835_IOPHYSTOVIRT(a) \
      ((0xf0000000 | (((a) & 0xf0000000) >> 4)) + ((a) & ~0xf0000000))
  
  #define    BCM2835_PERIPHERALS_VBASE \
      BCM2835_IOPHYSTOVIRT(BCM2835_PERIPHERALS_BASE)
RPI_KERNEL_IO_PBASEはそのままBCM2835_PERIPHERALS_BASEですから0x20000000になります。

RPI_KERNEL_IO_VBASEはBCM2835_IOPHYSTOVIRTというマクロを経由しますが、計算するとRPI_KERNEL_IO_VBASE = 0xF2000000になります。

三つ目のMMU_INITマクロである
    318 	/* Map the 16MB of peripherals */
    319 	MMU_INIT(RPI_KERNEL_IO_VBASE, RPI_KERNEL_IO_PBASE,
    320 	    (RPI_KERNEL_IO_VSIZE + L1_S_SIZE - 1),
    321 	    L1_S_PROTO | L1_S_AP_KRW)
については次のように表現できます。
  va = 0xF2000000
  pa = 0x20000000
  n_sec = 0x01000000 + 0x00100000 - 1 = 0x010FFFFF
  attr = 0x0412
最後のMMU_INITマクロは、
    323 	/* end of table */
    324 	MMU_INIT(0, 0, 0, 0)
ということで、テーブルの最後にすべてを0にしたものです。テーブルの最後を示す、番兵の役目ということでしょうか。

番兵を除く、MMU_INITマクロを表にしてみましょう。
vapansecattr
0x00x00x6430330x412
0xC00000000x00x6430330x041E
0xF20000000x200000000x010FFFFF0x0412

rpi_start.Sを読む (第4回)
2013/11/05(火) 27:06 NetBSD はてブ情報 はてブに登録 はてブ数

続きです、と行きたいところですが、今回は先に以下の部分を読み解きます。
    308 mmu_init_table:
    309 	/* Add 1MB of VA==PA at 0x00000000 so we can keep the kernel going */
    310 	MMU_INIT(0x0, 0x0,
    311 	    (_end - KERNEL_BASE + 2 * L1_S_SIZE - 1),
    312 	    L1_S_PROTO | L1_S_AP_KRW)
    313 
    314 	MMU_INIT(KERNEL_BASE, 0x0,
    315 	    (_end - KERNEL_BASE + 2 * L1_S_SIZE - 1),
    316 	    L1_S_PROTO | L1_S_AP_KRW  | L1_S_B | L1_S_C)
    317 
    318 	/* Map the 16MB of peripherals */
    319 	MMU_INIT(RPI_KERNEL_IO_VBASE, RPI_KERNEL_IO_PBASE,
    320 	    (RPI_KERNEL_IO_VSIZE + L1_S_SIZE - 1),
    321 	    L1_S_PROTO | L1_S_AP_KRW)
    322 
    323 	/* end of table */
    324 	MMU_INIT(0, 0, 0, 0)
MMU_INITとはすぐ上にあるマクロのようです。
    301 /* We'll modify va and pa at run time so we can use relocatable addresses. */
    302 #define MMU_INIT(va,pa,n_sec,attr) \
    303 	.word	va					    ; \
    304 	.word	pa					    ; \
    305 	.word	n_sec					    ; \
    306 	.word	attr					    ;
単純に引数を.wordで並べればいいということですね。301行目のコメントが気になりますよねぇ。訳すと、再配置可能なアドレスを使えるように、実行時にva(仮想アドレス)とpa(物理アドレス)を変換する、といったところでしょうか。引数はそれぞれ、仮想アドレスと物理アドレスの先頭、n_sec はセクション数ですかね。attrはそのアドレス領域の属性でしょう。

では、一行目のMMU_INITからいってみましょう。
    309 	/* Add 1MB of VA==PA at 0x00000000 so we can keep the kernel going */
    310 	MMU_INIT(0x0, 0x0,
    311 	    (_end - KERNEL_BASE + 2 * L1_S_SIZE - 1),
    312 	    L1_S_PROTO | L1_S_AP_KRW)
MMU_INITの引数を読み解いていきます。最初の二つ0x0, 0x0はいいですね。va=0x0, pa=0x0です。

三つめは(_end - KERNEL_BASE + 2 * L1_S_SIZE - 1)です。これは面倒ですね。_end, KERNEL_BASE, L1_S_SIZEはどう定義されているのでしょう。

まず、KERNEL_BASEはarch/evbarm/include/vmparam.hに定義されています。
  #ifdef KERNEL_BASE_EXT
  #define    KERNEL_BASE        KERNEL_BASE_EXT
  #else
  #define    KERNEL_BASE        0x80000000
  #endif
おっと、KERNEL_BASE_EXTが必要になりました。
KERNEL_BASE_EXTはconf/std.rpiに定義されています。
  options         KERNEL_BASE_EXT=0xc0000000
次に、_endですが、うーん、arch/evbarm/conf/ldscript.evbarmになるのかな。
    }
    . = ALIGN(32 / 8);
    _end = .;
    _bss_end__ = . ; __bss_end__ = . ; __end__ = . ;
    PROVIDE (end = .);
  }
_endの具体的な定義はどうなるのでしょうか? カーネルをreadelfしてendというシンボルを探すと(ABSとendで探す) ちゃんとあるようです。

NetBSD 6.1_RC1のnetbsd-RPI.gzをreadelfしてみると、次のようになります。
  n61rc1# readelf -a netbsd-RPI|grep end|grep ABS
  
   6634: c0443034     0 NOTYPE  GLOBAL DEFAULT  ABS end
  10028: c0443034     0 NOTYPE  GLOBAL DEFAULT  ABS __end__
  10100: c0443034     0 NOTYPE  GLOBAL DEFAULT  ABS __bss_end__
  11198: c0443034     0 NOTYPE  GLOBAL DEFAULT  ABS _bss_end__
  12138: c0443034     0 NOTYPE  GLOBAL DEFAULT  ABS _end
ですから_end = 0xc0443034ということになりそうです。

残りのL1_S_SIZEは先ほども出てきたpte.hに書かれています。
  #define    L1_S_SIZE    0x00100000    /* 1M */
  #define    L1_S_OFFSET    (L1_S_SIZE - 1)
  #define    L1_S_FRAME    (~L1_S_OFFSET)
  #define    L1_S_SHIFT    20
これで謎だった_end, KERNEL_BASE, L1_S_SIZEがわかりました。

n_sec = (_end - KERNEL_BASE + 2 * L1_S_SIZE - 1)は、_end - KERNEL_BASEはkernelの末尾 - kernelの頭、つまりkernelのサイズと読めます。それにL1_S_SIZEつまり1MBの二倍、2MBを足して1を引くだから、0x1FFFFFを足すと以下のように計算されます。
  n_sec = 0xc0443034 - 0xC0000000 + 2 * 0x00100000 - 1 
        = 0x643033;
だいぶ長くなりました。どこを読んでいたんでしたっけ? ということで再掲します。
    309 	/* Add 1MB of VA==PA at 0x00000000 so we can keep the kernel going */
    310 	MMU_INIT(0x0, 0x0,
    311 	    (_end - KERNEL_BASE + 2 * L1_S_SIZE - 1),
    312 	    L1_S_PROTO | L1_S_AP_KRW)
MMU_INITの最後の引数、attr = L1_S_PROTO | L1_S_AP_KRWを読みましょう。

ここで、attrつまりアトリビュートがどのようなものなのかイメージするために、ページテーブルの形式について触れておきます。

MMUはメモリアクセスの方式を複数選択でき、ページ(タイニー、スモール、ラージの三種)かセクション(セクション、スーパーセクション?)を選びます。NetBSD/rpiではセクションタイプのページテーブルを使っています。

セクションタイプのページテーブルは、ベースアドレス12ビットとアトリビュート20ビットから構成されています。
31-20191817161514-1211-1098-543210
セクションのベースアドレス(12bit)SBZ0nGSAPXTEXAPIMPドメインXNCB10
セクションの単位は1MBです。32bitメモリアドレスのCPUで表現できるアドレス空間は4GBですから、それを1MB単位で管理するには4096個のページテーブルエントリが必要になります。
4096は0も含めると0-4095で表現できますから4095=0xFFFつまり12ビットあればよいわけです。

あらためてattr = L1_S_PROTO | L1_S_AP_KRWを読みましょう。

L1_S_PROTO のSはどうやらセクションのことのようです。その頭文字をとってSなのでしょう。

L1_S_PROTOを追うと、pmap.hの L1_TYPE_Sに行き着きました。
  #define L1_S_PROTO_generic      (L1_TYPE_S | L1_S_IMP)
L1_TYPE_S, L1_S_IMPはpte.hで定義されています。
  /*
   * ARM L1 Descriptors
   */
  #define L1_TYPE_INV     0x00            /* Invalid (fault) */
  #define L1_TYPE_C       0x01            /* Coarse L2 */
  #define L1_TYPE_S       0x02            /* Section */
  #define L1_TYPE_F       0x03            /* Fine L2 */
  #define L1_TYPE_MASK    0x03            /* mask of type bits */
  
  /* L1 Section Descriptor */
  #define L1_S_B          0x00000004      /* bufferable Section */
  #define L1_S_C          0x00000008      /* cacheable Section */
  #define L1_S_IMP        0x00000010      /* implementation defined */
  #define L1_S_DOM(x)     ((x) << 5)      /* domain */
  #define L1_S_DOM_MASK   L1_S_DOM(0xf)
  #define L1_S_AP(x)      ((x) << 10)     /* access permissions */
  #define L1_S_ADDR_MASK  0xfff00000      /* phys address of section */
L1_TYPE_Sは0x02で定義されており、テーブルの下位2bitを表現しています。
さきのページテーブルの表でも下位2bitは10でしたよね。
L1_S_IMPは0X00000010で定義されています。IMPがimplementationの略だというのはわかりますが、なにをimplementatiionしているんでしょうかねぇ。

ということで、L1_S_PROTO = L1_S_PROTO_generic = L1_TYPE_S | L1_S_IMP = 0x02 | 0x00000010 = 0x0012になります。

つぎは、L1_S_AP_KRWです。

L1_S_AP_KRWはgenassym.cfでマクロになっていて、
  define  L1_S_AP_KRW             L1_S_AP(AP_KRW)
からの
  #define       L1_S_AP(x)      ((x) << 10)     /* access permissions */
なのですね。APはAccess Permissionsの略称だったのですね。

L1_S_AP(AP_KRW)のAP_KRWもおなじみpte.hで定義されています。
  /*
   * Short-hand for common AP_* constants.
   *
   * Note: These values assume the S (System) bit is set and
   * the R (ROM) bit is clear in CP15 register 1.
   */
  #define AP_KR           0x00            /* kernel read */
  #define AP_KRW          0x01            /* kernel read/write */
  #define AP_KRWUR        0x02            /* kernel read/write usr read */
  #define AP_KRWURW       0x03            /* kernel read/write usr read/write */
名前の謎がだいぶ解けてきました。SがSystem bit、KRWがkernel read/writeということのようです。

まとめると、L1_S_AP_KRW = 0x01 << 10 = 0x0400になります。

L1_S_PROTO | L1_S_AP_KRW = 0x0012 | 0x0400 = 0x0412ということがわかりました。

MMU_INITの引数がすべてわかりました。
    309 	/* Add 1MB of VA==PA at 0x00000000 so we can keep the kernel going */
    310 	MMU_INIT(0x0, 0x0,
    311 	    (_end - KERNEL_BASE + 2 * L1_S_SIZE - 1),
    312 	    L1_S_PROTO | L1_S_AP_KRW)
というのは次のように表現できます。
  va = 0x0
  pa = 0x0;
  n_sec = 0xc0443034 - 0xC0000000 + 2 * 0x00100000 - 1 
        = 0x643033;
  attr =  0x0412