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);
色々アレゲな設定を、なのかどうか。一旦止めてマニュアル確認します。
ちなみに
使ってるマニュアルは以下です。