/var/log/messages

debugging with sixth sense

Xv6-rpi 掘削

okidevops で QEMU 向けだから駄目、って事にしかけたんですが pi-baremetal ほど真面目にヤらなくても良いのではないか、と思いはじめた次第です。

メモは以下に投入してます。

とりあえずヤリかけの set_bootpgtbl 手続きから確認開始。

つうか、手続き先頭でアドレスなパラメータの類が全部シフトされてて笑いました。

// convert all the parameters to indexes
virt >>= PDE_SHIFT;
phy  >>= PDE_SHIFT;
len  >>= PDE_SHIFT;

ちなみに PDE_SHIRT は 20 で #define されてます。最初、set_bootpgtbl 手続きの len な引数に INIT_KERNMAP が指定されてて

set_bootpgtbl(0, 0, INIT_KERNMAP, 0);

びっくりしてたのですが、shift されてたのか。ちなみに値は src/memlayout.h で #define されてて以下です。

// we first map 1MB low memory containing kernel code.
#define INIT_KERNMAP    0x100000

コメントにもある通り、1MB な値ですね。つうかこれも 20bit なのか。ざっくりで申し訳ないのですが繰り返しの中で以下を、なのかな。

        pde |= (AP_KO << 10) | PE_CACHE | PE_BUF | KPDE_TYPE;

で、pde が kernel_pgtbl に、なのか。

        kernel_pgtbl[virt] = pde;

しかもこれ、20bit shift してるので繰り返しは一回のみ、なのかどうか。

ぐぬ

何だこれ。とりあえず 0 番地と KERNBASE (0x80000000) 番地の kernel_pgtbl を設定する、は分かったのですが次の部分。

// vector table is in the middle of first 1MB (0xF000)
vectbl = P2V_WO (VEC_TBL & PDE_MASK);

if (vectbl <= (uint)&end) {
    cprintf ("error: vector table overlaps kernel\n");
}

VEC_TBL が 0xFFFF0000 で PDE_MASK がおそらく 0xFFFFF なような。あ、& なのか。つうことは vectbl は 0x800f0000 になるんですが良いのかな。

あるいは次の VEC_TBL の扱いも謎。

set_bootpgtbl(VEC_TBL, 0, 1 << PDE_SHIFT, 0);

0xffff0000 な番地も 0 に map してるのかなぁ。次のソレはメモリマップな番地を云々、という事になるのかどうか。

set_bootpgtbl(KERNBASE+DEVBASE, DEVBASE, DEV_MEM_SZ, 1);

このあたり、なんとなく眺めてる限りではマニュアルてきに色々と違いますね。

kmain 手続き呼び出しまで

続いて以下な手続きを順に呼び出してます。

load_pgtlb (kernel_pgtbl, user_pgtbl);
jump_stack ();

// We can now call normal kernel functions at high memory
clear_bss ();

kmain ();

load_pgtlb 手続きあたりが pi-baremetal の initsys にあたるかどうか。突き合わせつつ確認してみます。

とりあえず以下から。

// read the main id register to make sure we are running on ARMv6
asm("MRC p15, 0, %[r], c0, c0, 0": [r]"=r" (ret)::);

マニュアルの 3.2.2 c0, Main ID Register という項がありますね。3-20 です。

  • [31:24] は 0x41 であること、とありチェックしてますね
  • [19:16] は 0xF であること、とありこれもチェックしてます

以降は pi-baremetal の initsys となんとなく同じカンジ。次のソレは

// set domain access control: all domain will be checked for permission
val = 0x55555555;
asm("MCR p15, 0, %[v], c3, c0, 0": :[v]"r" (val):);

で、マニュアルの 3.2.16 c3, Domain Access Control Register の項です。3-63 で良いのかな。これ、D0 から D15 までの全ての domain に b01 が設定されるのか。

次は c2 なソレの設定なんですが pi-baremetal と微妙に違いますね。xv6-pi だと以下の部分になります。

// set the page table base registers. We use two page tables: TTBR0
// for user space and TTBR1 for kernel space
val = 32 - UADDR_BITS;
asm("MCR p15, 0, %[v], c2, c0, 2": :[v]"r" (val):);

// set the kernel page table
val = (uint)kernel_pgtbl | 0x00;
asm("MCR p15, 0, %[v], c2, c0, 1": :[v]"r" (val):);

// set the user page table
val = (uint)user_pgtbl | 0x00;
asm("MCR p15, 0, %[v], c2, c0, 0": :[v]"r" (val):);

上から順に

  • 3.2.15 c2, Translation Table Base Control Register
  • 3.2.14 c2, Translation Table Base Register 1
  • 3.2.13 c2, Translation Table Base Register 0

になってます。最初の Control Register の設定から見るに [2:0] な bit が b100 になってます。これ、Translation Table Base Register 0 の boundary size を 1KB にします、という事なのかどうか。

ちなみに pi-baremetal だと

/* Use translation table 0 for everything, for now */
asm volatile("mcr p15, 0, %[n], c2, c0, 2" : : [n] "r" (0));

となっててこれだと boundary size が 16KB になるようです。そして以降の部分ですが xv6-pi だと 1 に kernel_pgtbl、0 に user_pgtbl が設定されてます。

pi-baremetal だと両方同じものが設定されてますね。

/* Translation table 0 - ARM1176JZF-S manual, 3-57 */
asm volatile("mcr p15, 0, %[addr], c2, c0, 0" : : [addr] "r" (pt_addr));
/* Translation table 1 */
asm volatile("mcr p15, 0, %[addr], c2, c0, 1" : : [addr] "r" (pt_addr));

で、MMU を on にしてます。

// ok, enable paging using read/modify/write
asm("MRC p15, 0, %[r], c1, c0, 0": [r]"=r" (val)::);

val |= 0x80300D; // enable MMU, cache, write buffer, high vector tbl,
                 // disable subpage
asm("MCR p15, 0, %[r], c1, c0, 0": :[r]"r" (val):);

pi-baremetal だとセットされるのは以下なので

/* Turn on MMU */
control |= 1;
/* Enable ARMv6 MMU features (disable sub-page AP) */
control |= (1<<23);

色々アレゲな設定を、なのかどうか。一旦止めてマニュアル確認します。

ちなみに

使ってるマニュアルは以下です。

Comments