FPGA開発日記

カテゴリ別記事インデックス https://msyksphinz.github.io/github_pages , English Version https://fpgadevdiary.hatenadiary.com/

QEMUに入門してみる(2. 独自コンフィグレーションを用意して必要なファイルを確認)

QEMUの続き。独自ターゲットでビルドしてみる。myriscvx64コンフィグレーションを用意した。

../configure --disable-werror --target-list=myriscvx64-softmmu
make -j$(nproc)
  • default_configs/myriscvx64-softmmu.mak
# Default configuration for myriscvx64-softmmu

# Uncomment the following lines to disable these optional devices:
#
#CONFIG_PCI_DEVICES=n

# Boards:
#
CONFIG_SPIKE=y
CONFIG_SIFIVE_E=y
CONFIG_SIFIVE_U=y
CONFIG_RISCV_VIRT=y
$ ../configure --disable-werror --target-list=myriscvx64-softmmu
$ make -j$(nproc)

以下のようなエラーメッセージが表示された。cpu.hはすべてのターゲットで必須なのか?

/home/msyksphinz/work/riscv/qemu/tcg/tcg-op.c:26:10: fatal error: cpu.h: No such file or directory
 #include "cpu.h"
          ^~~~~~~
compilation terminated.
/home/msyksphinz/work/riscv/qemu/tcg/tcg-op-vec.c:21:10: fatal error: cpu.h: No such file or directory
 #include "cpu.h"
          ^~~~~~~
compilation terminated.
In file included from /home/msyksphinz/work/riscv/qemu/exec-vary.c:25:
$ git find cpu.h
${BASE}/qemu/include/hw/acpi/cpu.h
${BASE}/qemu/include/hw/core/cpu.h
${BASE}/qemu/include/migration/cpu.h
${BASE}/qemu/target/alpha/cpu.h
${BASE}/qemu/target/arm/cpu.h
${BASE}/qemu/target/cris/cpu.h
${BASE}/qemu/target/hppa/cpu.h
${BASE}/qemu/target/i386/cpu.h
${BASE}/qemu/target/lm32/cpu.h
${BASE}/qemu/target/m68k/cpu.h
${BASE}/qemu/target/microblaze/cpu.h
${BASE}/qemu/target/mips/cpu.h
${BASE}/qemu/target/moxie/cpu.h
${BASE}/qemu/target/nios2/cpu.h
${BASE}/qemu/target/openrisc/cpu.h
${BASE}/qemu/target/ppc/cpu.h
${BASE}/qemu/target/riscv/cpu.h
${BASE}/qemu/target/rx/cpu.h
${BASE}/qemu/target/s390x/cpu.h
${BASE}/qemu/target/sh4/cpu.h
${BASE}/qemu/target/sparc/cpu.h
${BASE}/qemu/target/tilegx/cpu.h
${BASE}/qemu/target/tricore/cpu.h
${BASE}/qemu/target/unicore32/cpu.h
${BASE}/qemu/target/xtensa/cpu.h

${BASE}/qemu/target/myriscvx/cpu.hを作ってみる。

#ifndef MYRISCVX_CPU_H
#define MYRISCVX_CPU_H

#endif /* MYRISCVX_CPU_H */

するとバンバンエラーが出てきた。

  CC      myriscvx64-softmmu/fpu/softfloat.o
  CC      myriscvx64-softmmu/disas.o
  GEN     myriscvx64-softmmu/gdbstub-xml.c
In file included from /home/msyksphinz/work/riscv/qemu/include/exec/exec-all.h:26,
                 from /home/msyksphinz/work/riscv/qemu/tcg/tcg.c:45:
/home/msyksphinz/work/riscv/qemu/include/exec/cpu_ldst.h:93:9: error: unknown type name 'target_ulong'
 typedef target_ulong abi_ptr;
         ^~~~~~~~~~~~
/home/msyksphinz/work/riscv/qemu/include/exec/cpu_ldst.h:97:24: error: unknown type name 'CPUArchState'; did you mean 'CPUState'?
 uint32_t cpu_ldub_data(CPUArchState *env, abi_ptr ptr);
                        ^~~~~~~~~~~~
                        CPUState
/home/msyksphinz/work/riscv/qemu/include/exec/cpu_ldst.h:98:24: error: unknown type name 'CPUArchState'; did you mean 'CPUState'?
 uint32_t cpu_lduw_data(CPUArchState *env, abi_ptr ptr);
                        ^~~~~~~~~~~~
                        CPUState
/home/msyksphinz/work/riscv/qemu/include/exec/cpu_ldst.h:99:23: error: unknown type name 'CPUArchState'; did you mean 'CPUState'?
 uint32_t cpu_ldl_data(CPUArchState *env, abi_ptr ptr);
                       ^~~~~~~~~~~~
                       CPUState

target_ulongcpu-defs.hに定義がある。また、アーキテクチャの定義するビット長はcpu-param.hで決定するようだ。

  • qemu/include/exec/cpu-defs.h
/* target_ulong is the type of a virtual address */
#if TARGET_LONG_SIZE == 4
typedef int32_t target_long;
typedef uint32_t target_ulong;
#define TARGET_FMT_lx "%08x"
#define TARGET_FMT_ld "%d"
#define TARGET_FMT_lu "%u"
#elif TARGET_LONG_SIZE == 8
typedef int64_t target_long;
typedef uint64_t target_ulong;
#define TARGET_FMT_lx "%016" PRIx64
#define TARGET_FMT_ld "%" PRId64
#define TARGET_FMT_lu "%" PRIu64
#else
#error TARGET_LONG_SIZE undefined
#endif
  • qemu/target/riscv/cpu-param.h
#if defined(TARGET_RISCV64)
# define TARGET_LONG_BITS 64
# define TARGET_PHYS_ADDR_SPACE_BITS 56 /* 44-bit PPN */
# define TARGET_VIRT_ADDR_SPACE_BITS 48 /* sv48 */
#elif defined(TARGET_RISCV32)
# define TARGET_LONG_BITS 32
# define TARGET_PHYS_ADDR_SPACE_BITS 34 /* 22-bit PPN */
# define TARGET_VIRT_ADDR_SPACE_BITS 32 /* sv32 */
#endif

MYRISCVXでは64ビットのみとした。

  • qemu/target/myriscvx/cpu-param.h
#ifndef MYRISCVX_CPU_PARAM_H
#define MYRISCVX_CPU_PARAM_H 1

#define TARGET_LONG_BITS 64

#endif

RISC-VではTARGET_RISCV64TARGET_RISCV32で条件分けがされているが...

  • build/riscv64-softmmu/config-target.mak
# Automatically generated by configure - do not modify
TARGET_RISCV64=y
TARGET_NAME=riscv64
TARGET_BASE_ARCH=riscv
TARGET_ABI_DIR=riscv
CONFIG_SOFTMMU=y
TARGET_SUPPORTS_MTTCG=y
TARGET_XML_FILES= /home/msyksphinz/work/riscv/qemu/gdb-xml/riscv-64bit-cpu.xml /home/msyksphinz/work/riscv/qemu/gdb-xml/riscv-32bit-fpu.xml /home/msyksphinz/work/riscv/qemu/gdb-xml/riscv-64bit-fpu.xml /home/msyksphinz/work/riscv/qemu/gdb-xml/riscv-64bit-csr.xml /home/msyksphinz/work/riscv/qemu/gdb-xml/riscv-64bit-virtual.xml
CONFIG_I386_DIS=y
CONFIG_RISCV_DIS=y
QEMU_LDFLAGS+=
QEMU_CFLAGS+=

なるほど、ここでTARGET_RISCV64が定義される。では、TARGET_MYRISCVX64は、

  • build-myriscvx/myriscvx64-softmmu/config-target.mak
TARGET_MYRISCVX64=y
TARGET_NAME=myriscvx64
TARGET_BASE_ARCH=myriscvx
TARGET_ABI_DIR=myriscvx
CONFIG_SOFTMMU=y
TARGET_SUPPORTS_MTTCG=y
TARGET_XML_FILES= /home/msyksphinz/work/riscv/qemu/gdb-xml/riscv-64bit-cpu.xml /home/msyksphinz/work/riscv/qemu/gdb-xml/riscv-32bit-fpu.xml /home/msyksphinz/work/riscv/qemu/gdb-xml/riscv-64bit-fpu.xml /home/msyksphinz/work/riscv/qemu/gdb-xml/riscv-64bit-csr.xml /home/msyksphinz/work/riscv/qemu/gdb-xml/riscv-64bit-virtual.xml
CONFIG_I386_DIS=y
QEMU_LDFLAGS+=
QEMU_CFLAGS+=

ここで定義されているのか。

次はCPUArchStateの定義だ。これはCPUそのものを定義するのか?RISC-Vでは以下のような定義になっていた。

  • qemu/target/riscv/cpu.h
typedef struct CPURISCVState CPURISCVState;

struct CPURISCVState {
    target_ulong gpr[32];
    uint64_t fpr[32]; /* assume both F and D extensions */
    target_ulong pc;
    target_ulong load_res;
    target_ulong load_val;

...

    float_status fp_status;

    /* Fields from here on are preserved across CPU reset. */
    QEMUTimer *timer; /* Internal timer */
};
...
typedef CPURISCVState CPUArchState;
typedef RISCVCPU ArchCPU;

なるほど、ここでCPU機能全体を定義するのか。まずは簡単なものだけ定義しておこう。PCも必要なようだ。

  • qemu/target/riscv/cpu.h
typedef struct CPUMYRISCVXState {
  target_ulong gpr[32];
  target_ulong pc;
} CPURISCVState;

typedef CPURISCVState CPUArchState;
typedef RISCVCPU ArchCPU;

#include "exec/cpu-all.h"

最後のcpu-all.hはなんとなくRISC-V版の実装でも入っていたし、便利なユーティリティが入っているようだったので入れてみた。

まだエラーがある。いろんなパラメータをcpu-param.hで設定しなければならないらしい。

/home/msyksphinz/work/riscv/qemu/include/exec/cpu-defs.h:43:3: error: #error NB_MMU_MODES must be defined in cpu-param.h
 # error NB_MMU_MODES must be defined in cpu-param.h
   ^~~~~
In file included from /home/msyksphinz/work/riscv/qemu/target/myriscvx/cpu.h:24,
                 from /home/msyksphinz/work/riscv/qemu/tcg/tcg-op-vec.c:21:
/home/msyksphinz/work/riscv/qemu/include/exec/cpu-defs.h:43:3: error: #error NB_MMU_MODES must be defined in cpu-param.h
 # error NB_MMU_MODES must be defined in cpu-param.h
   ^~~~~
/home/msyksphinz/work/riscv/qemu/include/exec/cpu-defs.h:46:3: error: #error TARGET_PHYS_ADDR_SPACE_BITS must be defined in cpu-param.h
 # error TARGET_PHYS_ADDR_SPACE_BITS must be defined in cpu-param.h
   ^~~~~
In file included from /home/msyksphinz/work/riscv/qemu/target/myriscvx/cpu.h:24,
                 from /home/msyksphinz/work/riscv/qemu/include/tcg/tcg.h:28,
                 from /home/msyksphinz/work/riscv/qemu/tcg/tcg-op-gvec.c:21:
/home/msyksphinz/work/riscv/qemu/include/exec/cpu-defs.h:43:3: error: #error NB_MMU_MODES must be defined in cpu-param.

NB_MMU_MODESNBって何だ?

  • qemu/target/myriscvx/cpu-param.h
#if defined(TARGET_MYRISCVX64)
#define TARGET_LONG_BITS 64
#define TARGET_PHYS_ADDR_SPACE_BITS 56 /* 44-bit PPN */
#define TARGET_VIRT_ADDR_SPACE_BITS 39 /* sv39 */
#endif // defined(TARGET_RISCV64)
#define TARGET_PAGE_BITS 12 /* 4 KiB Pages */
#define NB_MMU_MODES 4