GAIAとxv6におけるbootloader

SRAM

GAIAで使ってる基盤は4MB(222)のSRAMを積んでる。 rom.vhd は実際には sram.vhd をラップしてるに過ぎず、いわゆるDRAMは一切使用していない。(BlockRamというのもSRAMの一種らしい?)

sram.vhdの中では、入ってきたアドレスの上位10bitは見ておらず、下位22bitだけを見ている。(これが単純な仮想アドレス変換として機能している?ページテーブルやTLBの実装等は見当たらないため)

xv6

nyuichi/xv6

Makefile

kernelmemfs: $(MEMFSASMS) initcode _min-rt fs.img
    ./tools/gen_binary_blobs 0x80002000 initcode _min-rt fs.img
    $(AS) $(ASFLAGS) -c -o _kernelmemfs -e 0x80002000 -start _start $(MEMFSASMS) _binary_blobs.s $(UCCLIBS) -f __UCC_HEAP_START
    ./tools/gen_binary_blobs `ruby -e "print open('_kernelmemfs').size + 0x80002000"` initcode _min-rt fs.img
    $(AS) $(ASFLAGS) -c -o _kernelmemfs -e 0x80002000 -start _start $(MEMFSASMS) _binary_blobs.s $(UCCLIBS) -f __UCC_HEAP_START
    cat _kernelmemfs initcode _min-rt fs.img > kernelmemfs
    rm _kernelmemfs
    ./tools/attach_boot_header kernelmemfs
  • 公式のようなリンカスクリプトは使っていない。よくみるとハードコーディングで 0x80002000 を使っており、これがkernelが配置されている先頭仮想アドレスである。 0x8010_0000 を使ってないのは、無駄に0 - 1MB空間を空けないようにするため?
  • そして、GAIAではプロセスごとのアドレス空間切り替えをどうやって実装しているのか。MIPSでいうASID的なものが見当たらないが...

memlayout.h

// Memory layout

#define EXTMEM   0x2000             // Start of extended memory
#define PHYSTOP  (4*1024*1024)      // Top physical memory
#define DEVSPACE 0xFE000000         // Other devices are at high addresses

// Key addresses for address space layout (see kmap in vm.c for layout)
#define KERNBASE 0x80000000         // First kernel virtual address
#define KERNLINK (KERNBASE+EXTMEM)  // Address where kernel is linked

// [0x80000000, 0x80001FFF] is special memory mapped area.
// Kernel MUST guarantee that this memory area is directly mapped to the physical same area.
#define VAENABLE   0x80001200
#define PDADDR     0x80001204
#define INTHANDLER 0x80001100
#define INTENABLE  0x80001104
#define EPC        0x80001108
#define CAUSE      0x8000110C
#define SERIAL     0x80001000
#define SERIALWE   0x80001004

ここで、だいたい分かる。このへんのアドレス設定はGAIAのアーキテクチャと密結合な感じで、GAIAのソースコード内にもがっつりハードコーディングで書かれている。

* EXTMEM  : 物理アドレスのどこにkernel先頭が配置されてるのか示す。
* PHYSTOP : 詰んでるSRAMの容量に合わせる(実質的な物理メモリ容量)
* その他  : I/Oで使うメモリマップドのアドレス。例えば、シリアル通信は0x80001000, 0x80001004。uart.cで使用している

mips移植を考える場合

xv6-mips では上記のような考慮はされていないため、適宜パラメタを書き換える必要がある。特にEXTMEMはkernellをSRAMに載せるにしろDRAMに載せるにしろ書き換えないとまともに動かない。オリジナルのxv6, xv6-mipsでは memlayout.hはシンプルで、定数は各クラスファイル内に書かれているケースが多い。(uart.c, mips.hなど)

// Memory layout

#define EXTMEM  0x100000            // Start of extended memory
#define PHYSTOP 0xE000000           // Top physical memory
#define DEVSPACE 0xFE000000         // Other devices are at high addresses

// Key addresses for address space layout (see kmap in vm.c for layout)
#define KERNBASE 0x80000000         // First kernel virtual address
#define KERNLINK (KERNBASE+EXTMEM)  // Address where kernel is linked

#define V2P(a) (((uint) (a)) - KERNBASE)
#define P2V(a) (((void *) (a)) + KERNBASE)

#define V2P_WO(x) ((x) - KERNBASE)    // same as V2P, but without casts
#define P2V_WO(x) ((x) + KERNBASE)    // same as P2V, but without casts