-Makefile編- xv6 (mips) コードリーディング

QEMUで実行できる形に最適化されているので、実機(FPGA)で動作させる場合はコードの手直しが必要かもしれない。

xv6.img, fs.img

QEMUで実行する際に

qemu-nox: fs.img xv6.img
    $(QEMU) -nographic $(QEMUOPTS)

となるが、これは下記のようなコマンドとして実行される

qemu-system-mipsel -nographic -hdb fs.img -kernel kernel -smp 1 -m 256 -M mips

hdb   : block device file
kernel: Use bzImage as kernel image
smp   : the number of simulation processor
m     : RAM size (MB)
M     : Set the emulated machine type

original vs. mips

MIPS版では、bootblock(Master Boot Record)を使わない。実機で動かす場合はこの辺の手直しが必要?

original

xv6.img: bootblock kernel fs.img
    dd if=/dev/zero of=xv6.img count=10000
    dd if=bootblock of=xv6.img conv=notrunc
    dd if=kernel of=xv6.img seek=1 conv=notrunc

bootblock: bootasm.S bootmain.c
    $(CC) $(CFLAGS) -fno-pic -O -nostdinc -I. -c bootmain.c
    $(CC) $(CFLAGS) -fno-pic -nostdinc -I. -c bootasm.S
    $(LD) $(LDFLAGS) -N -e start -Ttext 0x7C00 -o bootblock.o bootasm.o bootmain.o
    $(OBJDUMP) -S bootblock.o > bootblock.asm
    $(OBJCOPY) -S -O binary -j .text bootblock.o bootblock
    ./sign.pl bootblock

mips

xv6.img: kernel fs.img
    dd if=/dev/zero of=xv6.img count=10000
    dd if=kernel of=xv6.img seek=1 conv=notrunc

じゃあどうやってxv6-mipsは動作しているのか?

結論から書くと、xv6-mipsQEMU上での動作しかサポートしていない。QEMUはあくまでエミュレータなので、BIOSにあたるもの(MBRセクタ)がなくても問題ないらしい。実機ではおそらく何かしら

There currently is no MIPS BIOS file for QEMU (see firmware). However if passed a -kernel argument qemu will not call the firmware at all, so this does no harm at all. Since QEMU 0.8.1 this workaround is obsolete, a missing BIOS file triggers only a warning message.

Firmware

The QEMU distribution does not contain any firmware for MIPS. This is only a minor problem as unlike on a real system QEMU's virtual hardware is mostly initialized after a reset. At least some existing firmware for MIPS Malta also works with QEMU, e.g. RedBoot. There is also a mmon port to QEMU.

https://www.linux-mips.org/wiki/QEMU#MIPS_BIOS_not_found_on_startup https://www.linux-mips.org/wiki/QEMU#Firmware

そもそもファームウェアとは?

x86でいうBIOSのように、ハードウェアとソフトウェアの間にあるもの。電源投入と同時に実行される。主な働きはハードウェアを初期化して記憶装置からブートローダーを呼び出すこと。 ハード的に見たら、ProgramCounterが0に初期化された後、すぐ実行される位置に格納されているProgram、という感じなのかな?実装がよくわからない。

Firmware is the system software residing in a non-volatile memory, typically a ROM, EPROM or today often a flash memory. What is called firmware for the MIPS systems is relatively close to what is called the BIOS for the PC sector. There is a small number of firmware implementations in use on MIPS only however in a large number of variants.

ARC
Common Firmware Environment (CFE)
Cobalt Firmware
CoLo
IDT/sim, IDT/boot
mmon tiny monitor program for MIPS VR4300
PMON
PMON 2000
RedBoot
U-Boot
YAMON

実機でのfirmware実装のヒント

UTのCPU実験、GAIA上で動作させたxv6がヒントになるかも。カーネルビルドの最後にヘッダ部分に4bytesのサイズを書き込んでる。この辺はプロセッサ回路がどう設計されてるかで、firmware実装も変わってきそうな気がする。

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

xv6/Makefile at 94d02ecb2b9492365574f2166cf29ce5a170abf5 · nyuichi/xv6 · GitHub

TODO

  • JTAG-UARTってDE10-Lite+MIPS+xv6で使えるのか。使えなかったらシリアルポート付きFPGAを購入する必要あり?

http://blog.goo.ne.jp/sim00/e/236d685cc29873571051270075449cac

Nios II/eでHello, world! (Quartus IIとQsys) - FPGAがさっぱり分からない人がDE0でFPGAを勉強する

x86のVGA操作について - FPGA開発日記

  • UARTってそもそもなに?(実装)

UART in VHDL and Verilog for an FPGA

  • harvard architectureだとData MemoryとProgram Memoryが別れているけど、kernelからどうやってProgram領域にデータロードするのか

(UNIXv6を読むと)textセグメント、dataセグメントに分けて考えているが、恐らくこれがそのままProgramMemory、DataMemoryに対応づくのだと思う。両Memoryは必ずしも物理的に別個のデバイスでなくとも問題ない。(ただし、回路設計上、アドレスバス、データバスは別々に接続されてなければならない。でないとRISC的な5段パイプラインが実現できないため)

  • User Programとは?

Makefileをみると、ユーザプログラム(cat, mkdir, echo...)は最初の段階でroot inode dirに書き込んでいるようにみえる。fork & execの過程でどうやって主記憶(ディスク)からProgramMemoryへ読み込まれるのだろうか。そもそもMIPS命令セットには「ProgramMemoryへ書き込み」などという命令はないのだから、やはり物理メモリは1本で、ProgramMemoryと呼ばれるものはあくまでキャッシュにすぎない。というイメージだろうか?

UNIXではコンテキストスイッチによってマルチプロセスを実現させる。レジスタは本数も少なく、容量も僅かなのでコンテキストスイッチの際、そのまま退避させたり復帰させたりするのが容易。しかし、物理メモリ上のデータはでかいのでいちいち退避させず、物理アドレスと仮想アドレスの対応関係を実行時に変換する。

各プロセスの仮想アドレス空間のアドレス範囲は同じでありオーバーラップしているのが一般的である。これを多重仮想記憶と呼ぶ。MMUは現に実行中のプロセスの仮想空間のみを認識する。コンテキストスイッチでプロセスを切り替える際、MMUに対して仮想アドレス空間の切り替えも指示する必要があるが、その方式はアーキテクチャによって様々である。

なお、アーキテクチャによっては、多重仮想記憶がオーバーラップしていると捉えず、全仮想空間がフラットに並んだ巨大な仮想空間を想定することもある。この場合、仮想空間識別番号が巨大な仮想空間のアドレスの一部と考えられる。もっとも、これは単にモデル化の手法が違うだけで実装に大きな違いがあるわけではない。実際、各ユーザープロセスが自分の仮想空間識別番号以外の仮想空間にアクセスすることはできない。

R3000の場合、TLBでPIDを識別する6bit情報を持っているので、仮想アドレス+PIDで物理アドレスマッピングする感じ

f:id:varmil:20171105145606p:plain http://www.cqpub.co.jp/dwm/contents/0074/dwm007401330.pdf

  • xv6-mipsにおける、bootloaderではbootasm.Sを使ってない?

YES.使ってない。そもそもbootasmはx86の命令セットを使用しているのでMIPSでは動作しない。

  • "unix v6 bootloader" v6はbootloaderも併せ持つようだが、どういう実装になっているのか
  • xv6-MIPSリンカスクリプトは?
  • メモリマップドのベースアドレスはどうやって決めている?MIPSの仕様?
  • MIPS R4000, 3000, 2000の違い(xv6-mipsはR4000基準のため)

XV6の入出力

inb, outb

◆入出力の方法

  1. CPU が持つ入出力命令を使うもの。 どのデバイスをアクセスするかは、ポート番号で指定する。
  2. 通常のメモリアクセスの命令を使うもの(memory mapped I/O)。 どのデバイスをアクセスするかは、番地で指定する。

x86ではポートマップドのIN, OUT命令セットが存在する。

Linux における入出力命令を使った入出力は、inb() と outb() で行われる。

outb(unsigned char value, int port)
  ポート番号 port に 1 バイトの value を出力する

unsigned char inb(int port)
  ポート番号 port から 1 バイトの value を入力してその値を返す

x86では、IDEやUARTはinbやoutb命令で操作できるが(つまりポートマップドI/O)、MIPSRISC-Vではそうはいかない。メモリマップに、これらのモジュールを定義しておかなければならない。 http://msyksphinz.hatenablog.com/?page=1461085200

xv6

オリジナル (port-mapped I/O)

/uart.c

void
uartputc(int c)
{
  int i;

  if(!uart)
    return;
  for(i = 0; i < 128 && !(inb(COM1+5) & 0x20); i++)
    microdelay(10);
  outb(COM1+0, c);
}

/mips.h

static inline void
outb(ushort port, uchar data)
{
  asm volatile("out %0,%1" : : "a" (data), "d" (port));
}

xv6/uart.c at ff2783442ea2801a4bf6c76f198f36a6e985e7dd · guilleiguaran/xv6 · GitHub

nyuichi/xv6 (memory-mapped I/O)

/uart.c

uartputc(int c)
{
  int i;
  if(!uart)
    return;
  while(*(int*)SERIALWE == 0) microdelay();
  *(int*)SERIAL = c;
}

/memorylayout.c

#define SERIAL     0x80001000

https://github.com/nyuichi/xv6/blob/94d02ecb2b9492365574f2166cf29ce5a170abf5/uart.c#L34

nullpo-head/xv6-mips (memory-mapped I/O)

/uart.c

#define COM1    0x3f8
.....
.....
void
uartputc(int c)
{
  int i;

  if(!uart)
    return;
  for(i = 0; i < 128 && !(inb(COM1+5) & 0x20); i++)
    microdelay(10);
  outb(COM1+0, c);
}

/mips.h

static int io_port_base = 0xb4000000;
.....
.....
static inline void
outb(ushort port, uchar data)
{
  *((uchar *) (io_port_base + port)) = data;
}

GitHub - nullpo-head/xv6-mips: A MIPS port of xv6

呼び出し

console.printf() --> console.consputc(c) --> uart.uartputc(c)
                                         --> uart.cgaputc(c)

uart.cgaputc(c) は、オリジナル以外ではコメントアウトMIPS) or 削除(GAIA)されている

WIP ハードウェア資源は足りる?

MIPS/LinuxがDE-10 Liteで動くかという問題

  • 出力:
    • VGA, 2*20GPIO(SerialPortがないけど大丈夫?...MIPS/Linuxって標準でどこへ出力すんの?)
  • メモリ:

特にディスプレイ出力どうするの

ttyとpts

ttyとかptsとかについて確認してみる - Qiita

わかりやすい。

tty - Linuxカーネルメモ

より実装よりの図解とか。

kernelのconsole設定

http://archive.linux.or.jp/JF/JFdocs/Remote-Serial-Console-HOWTO/configure-kernel.html

JF: Linux Kernel 3.x/2.6 Documentation: serial-console.txt

initとgetty

http://www.gcd.org/sengoku/docs/NikkeiLinux01-03.pdf

Linux/MIPS のFDC

Fast Debug Channel - LinuxMIPS

[PATCH 7/9] tty: Add MIPS EJTAG Fast Debug Channel TTY driver

MIPSアーキテクチャ上にLinuxを初期インストールするには「ブートローダ」が重要

とりあえず、既存のMIPS CPUリポジトリを使ってFPGA実機でLinux動作させようと思ったが...

Q. そもそも、LinuxカーネルイメージをFPGA(上のMIPS CPU)に転送しても、どうやって起動(or インストール)するのだろう?

A1. ブートローダが鍵になるっぽい。

  • x86は起動時にBIOSによってディスクからブートローダをロードし、起動する。
  • MIPSはROMモニタをフラッシュ領域からロードし、状態を設定する。 (U-boot, YAMON)

xv6のテキストAppendix-B "The Boot Loader" を翻訳しました - FPGA開発日記

パタヘネ本には特にブートシーケンスの説明はなかったから、あくまでプロセッサ側は愚直にProgramCounterに従って命令を実行するのみで、ブートローダ自体はソフトウェア層で実装するもの、という理解。

U-Boot

  • serial console support
  • integrated shell alike setup interface
  • optional password protectection and timeout for acces to setup interface on boot
  • editable configuration space
  • downloads software trough tftp servers
  • flash routines for EEPROMS of misc technology including NANDs
  • runs test applications directly
  • boots Linux

U-Boot - LinuxMIPS

http://blog.techlab-xe.net/archives/4208

Linux Boot sequence on MIPS??

Re: Linux Boot sequence on MIPS??

ブートローダもCPUアーキテクチャに依存する

f:id:varmil:20171102213308p:plain

http://www.cqpub.co.jp/interface/sample/200511/if0511_chap1.pdf

YANONやU-BootというのはMIPSアーキテクチャに対応したOSSブートローダ、といった位置づけだろうか。

initramfsとは

initrd - Wikipedia

第384回 Initramfsのしくみ:Ubuntu Weekly Recipe|gihyo.jp … 技術評論社

カーネルブートローダーによって起動されたあと,ルートファイルシステムをマウントするために,サポートしているすべてのディスクデバイスのドライバを持っている必要があります。

しかしながらこのドライバをすべてカーネルに組み込んでしまうと,カーネルが肥大化してしまいます。しかもそのほとんどは,今使っているディスクデバイスでは不要なドライバです。必要なドライバを必要に応じてロードする仕組みとして「カーネルモジュール」がありますが,今度はその「カーネルモジュール」をどこに保存するのかという問題が発生します。当然のことながら,この時点でルートファイルシステムにはアクセスできません。

そこで出てくるのが「Initramfs」という仕組みです。

Ubuntuに限らずほとんどのLinuxディストリビューションでは,「⁠ミニルート」とも呼ばれるメモリ上に展開可能な,小さなサイズのルートファイルシステムを持っています。「Initramfs」は,現在はデスクトップLinuxでもっとも使われているミニルートのファイルフォーマットの1つです