2008年12月24日水曜日

Memory Map の作り方

CPUReadMemoryFun *foo_readfn[3]  と CPUWriteMemoryFunc *foo_writefn[3]  をそれぞれ定義する。配列の中身は、それぞれ、メモリを byte/word/double word で読んだときに呼び出されるコールバック。
iomemtype = cpu_register_io_memory(io_index, foo_readfn,foo_writefn, s);
cpu_register_physical_memory(開始アドレス, サイズ, iomemtype);
io_index が 0 の時は新しい io 領域が作られる。
s は、CPU の io の状態を表現する任意の構造体。
サイズはターゲットのページサイズの倍数。
iomemtype (phys_offset) は、phys_offset & ~TARGET_PAGE_MASK) != 0 となる ( io memory page)。

qemu-0.9.1/exec.c

/* mem_read and mem_write are arrays of functions containing the
   function to access byte (index 0), word (index 1) and dword (index
   2). Functions can be omitted with a NULL function pointer. The
   registered functions may be modified dynamically later.
   If io_index is non zero, the corresponding io zone is
   modified. If it is zero, a new io zone is allocated. The return
   value can be used with cpu_register_physical_memory(). (-1) is
   returned if error. */
int cpu_register_io_memory(int io_index,
                           CPUReadMemoryFunc **mem_read,
                           CPUWriteMemoryFunc **mem_write,
                           void *opaque)
{
    int i, subwidth = 0;

    if (io_index <= 0) {
        if (io_mem_nb >= IO_MEM_NB_ENTRIES)
            return -1;
        io_index = io_mem_nb++;
    } else {
        if (io_index >= IO_MEM_NB_ENTRIES)
            return -1;
    }

    for(i = 0;i < 3; i++) {
        if (!mem_read[i] || !mem_write[i])
            subwidth = IO_MEM_SUBWIDTH;
        io_mem_read[io_index][i] = mem_read[i];
        io_mem_write[io_index][i] = mem_write[i];
    }
    io_mem_opaque[io_index] = opaque;
    return (io_index << IO_MEM_SHIFT) | subwidth;
}

qemu-0.9.1/cpu-all.h
typedef void CPUWriteMemoryFunc(void *opaque,
                                target_phys_addr_t addr,
                                uint32_t value);

typedef uint32_t CPUReadMemoryFunc(void *opaque,
                                   target_phys_addr_t addr);

int cpu_register_io_memory(int io_index,
                           CPUReadMemoryFunc **mem_read,
                           CPUWriteMemoryFunc **mem_write,
                           void *opaque);

2008年12月23日火曜日

QEMU で新しい target board を作るためには

詳しい追加場所や、QEMU の API などは、qemu-0.9.1/hw/integratorcp.[co] などを参考に。
  1. qemu-0.9.1/hw/board.h に extern QEMUMachine  sample_machine;  を追加する。
  2. qemu-0.9.1/hw/sample_board.c の中で、board.h に追加した exterm 宣言の実体を定義する。具体的には、ターゲットボードの初期化関数 sample_board_init() などを定義し、QEMUMachine sample_machine = {"sampleboard", "説明", sample_board_init}; 
  3. qemu-0.9.1/Makefile.target に sample_board.o を追加する。これで sample_board.c がビルドされてリンクされる。
  4. qemu-0.9.1/vl.c に qemu_register_machine(&sample_machine); を追加する。これで、QEMU の引数に -M sampleboard を渡したときに、ターゲットボードの初期化と実行が行われるようになる。
あとは sample_board.c の中でひたすらボードの定義 (メモリマップなど) と初期化を書けば良い。

2008年12月22日月曜日

CPUState

けっこう探すのに難儀した。実体は qemu-0.9.1/target-arm など。CPU は、一応ちゃんとターゲットごとに分かれている。ボードもちゃんと分けて欲しい。


/* We currently assume float and double are IEEE single and double
   precision respectively.
   Doing runtime conversions is tricky because VFP registers may contain
   integer values (eg. as the result of a FTOSI instruction).
   s<2n> maps to the least significant half of d<n>
   s<2n+1> maps to the most significant half of d<n>
 */

typedef struct CPUARMState {
    /* Regs for current mode.  */
    uint32_t regs[16];
    /* Frequently accessed CPSR bits are stored separately for efficiently.
       This contains all the other bits.  Use cpsr_{read,write} to access
       the whole CPSR.  */
    uint32_t uncached_cpsr;
    uint32_t spsr;

    /* Banked registers.  */
    uint32_t banked_spsr[6];
    uint32_t banked_r13[6];
    uint32_t banked_r14[6];

    /* These hold r8-r12.  */
    uint32_t usr_regs[5];
    uint32_t fiq_regs[5];

    /* cpsr flag cache for faster execution */
    uint32_t CF; /* 0 or 1 */
    uint32_t VF; /* V is the bit 31. All other bits are undefined */
    uint32_t NZF; /* N is bit 31. Z is computed from NZF */
    uint32_t QF; /* 0 or 1 */
    uint32_t GE; /* cpsr[19:16] */
    int thumb; /* cprs[5]. 0 = arm mode, 1 = thumb mode. */
    uint32_t condexec_bits; /* IT bits.  cpsr[15:10,26:25].  */

    /* System control coprocessor (cp15) */
    struct {
        uint32_t c0_cpuid;
        uint32_t c0_cachetype;
        uint32_t c0_c1[8]; /* Feature registers.  */
        uint32_t c0_c2[8]; /* Instruction set registers.  */
        uint32_t c1_sys; /* System control register.  */
        uint32_t c1_coproc; /* Coprocessor access register.  */
        uint32_t c1_xscaleauxcr; /* XScale auxiliary control register.  */
        uint32_t c2_base0; /* MMU translation table base 0.  */
        uint32_t c2_base1; /* MMU translation table base 1.  */
        uint32_t c2_mask; /* MMU translation table base mask.  */
        uint32_t c2_data; /* MPU data cachable bits.  */
        uint32_t c2_insn; /* MPU instruction cachable bits.  */
        uint32_t c3; /* MMU domain access control register
                        MPU write buffer control.  */
        uint32_t c5_insn; /* Fault status registers.  */
        uint32_t c5_data;
        uint32_t c6_region[8]; /* MPU base/size registers.  */
        uint32_t c6_insn; /* Fault address registers.  */
        uint32_t c6_data;
        uint32_t c9_insn; /* Cache lockdown registers.  */
        uint32_t c9_data;
        uint32_t c13_fcse; /* FCSE PID.  */
        uint32_t c13_context; /* Context ID.  */
        uint32_t c13_tls1; /* User RW Thread register.  */
        uint32_t c13_tls2; /* User RO Thread register.  */
        uint32_t c13_tls3; /* Privileged Thread register.  */
        uint32_t c15_cpar; /* XScale Coprocessor Access Register */
        uint32_t c15_ticonfig; /* TI925T configuration byte.  */
        uint32_t c15_i_max; /* Maximum D-cache dirty line index.  */
        uint32_t c15_i_min; /* Minimum D-cache dirty line index.  */
        uint32_t c15_threadid; /* TI debugger thread-ID.  */
    } cp15;

    struct {
        uint32_t other_sp;
        uint32_t vecbase;
        uint32_t basepri;
        uint32_t control;
        int current_sp;
        int exception;
        int pending_exception;
        void *nvic;
    } v7m;

    /* Coprocessor IO used by peripherals */
    struct {
        ARMReadCPFunc *cp_read;
        ARMWriteCPFunc *cp_write;
        void *opaque;
    } cp[15];

    /* Internal CPU feature flags.  */
    uint32_t features;

    /* Callback for vectored interrupt controller.  */
    int (*get_irq_vector)(struct CPUARMState *);
    void *irq_opaque;

    /* exception/interrupt handling */
    jmp_buf jmp_env;
    int exception_index;
    int interrupt_request;
    int user_mode_only;
    int halted;

    /* VFP coprocessor state.  */
    struct {
        float64 regs[32];

        uint32_t xregs[16];
        /* We store these fpcsr fields separately for convenience.  */
        int vec_len;
        int vec_stride;

        /* Temporary variables if we don't have spare fp regs.  */
        float32 tmp0s, tmp1s;
        float64 tmp0d, tmp1d;
        /* scratch space when Tn are not sufficient.  */
        uint32_t scratch[8];

        float_status fp_status;
    } vfp;
#if defined(CONFIG_USER_ONLY)
    struct mmon_state *mmon_entry;
#else
    uint32_t mmon_addr;
#endif

    /* iwMMXt coprocessor state.  */
    struct {
        uint64_t regs[16];
        uint64_t val;

        uint32_t cregs[16];
    } iwmmxt;

#if defined(CONFIG_USER_ONLY)
    /* For usermode syscall translation.  */
    int eabi;
#endif

    CPU_COMMON

    /* These fields after the common ones so they are preserved on reset.  */
    int ram_size;
    const char *kernel_filename;
    const char *kernel_cmdline;
    const char *initrd_filename;
    int board_id;
    target_phys_addr_t loader_start;
} CPUARMState;


#define CPUState CPUARMState

QEMU 0.9.1 のビルド

MinGW + MSYS 環境は、ここらへんを参考にしつつ 作る。

MinGW 5.1.4 のインストーラを使ってデフォルトインストール (/c/mingw 以下)
MSYS 1.0.10 のインストーラを使ってデフォルトインストール) (/c/msys/1.0 以下)

MSYS Core 1.0.11 と MSYS DTK 1.0 を /c/msys 以下に適宜ディレクトリ構成を合わせて展開する。

これだけだと unistd.h が古くて、QEMU をビルドする時に getopts で引っかかるので、mingwrt-3.15.1-mingw32-dev.tar.gz と mingwrt-3.15.1-mingw32-dll.tar.gz を /mingw 以下に適宜ディレクトリ構成を合わせて展開しておく。

http://sourceforge.jp/projects/mingw/releases/35393

SDL を ./configure --prefi=/usr/local で install (これはどこでも良いと思う)。

SDL-1.2.13.tar.gz

Zlib を ./configure --prefix=/mingw で install(mingw 以下じゃないと見つけてくれない)。

zlib-1.2.3.tar.gz

QEMU を ./configure --prefix=/usr/local/QEMU などに make ; make install

qemu-0.9.1.tar.gz

ただし qemu-0.9.1/hw/omap.c の localtime_r と gmtime_r を使っているところ (4671, 4733, 4750 行目)
を comment out しておかないとコケる。

これで、とりあえずビルドは通るはず (各ターゲットの動作検証はしてない)

CPU のシミュレーションだけを行いたい場合は、--disable-sdl で、SDL をインストールしなくてもビルドできると思う。
あと、使いたいターゲットだけをビルドした方が良いと思う。

configure option

$ ./configure --help

Usage: configure [options]
Options: [defaults in brackets after descriptions]

Standard options:
--help print this message
--prefix=PREFIX install in PREFIX []
--interp-prefix=PREFIX where to find shared libraries, etc.
use %M for cpu name [/usr/gnemul/qemu-%M]
--target-list=LIST set target list []

kqemu kernel acceleration support:
--disable-kqemu disable kqemu support

Advanced options (experts only):
--source-path=PATH path of source code [/home/aloha/work/QEMU/qemu-0.9.1]
--cross-prefix=PREFIX use PREFIX for compile tools []
--cc=CC use C compiler CC [gcc]
--host-cc=CC use C compiler CC [gcc] for dyngen etc.
--make=MAKE use specified make [make]
--install=INSTALL use specified install [install]
--static enable static build [no]
--disable-werror disable compilation abort on warning
--disable-sdl disable SDL
--enable-cocoa enable COCOA (Mac OS X only)
--enable-mingw32 enable Win32 cross compilation with mingw32
--enable-adlib enable Adlib emulation
--enable-coreaudio enable Coreaudio audio driver
--enable-alsa enable ALSA audio driver
--enable-fmod enable FMOD audio driver
--enable-dsound enable DirectSound audio driver
--disable-vnc-tls disable TLS encryption for VNC server
--enable-system enable all system emulation targets
--disable-system disable all system emulation targets
--enable-linux-user enable all linux usermode emulation targets
--disable-linux-user disable all linux usermode emulation targets
--enable-darwin-user enable all darwin usermode emulation targets
--disable-darwin-user disable all darwin usermode emulation targets
--fmod-lib path to FMOD library
--fmod-inc path to FMOD includes
--enable-uname-release=R Return R for uname -r in usermode emulation
--sparc_cpu=V Build qemu for Sparc architecture v7, v8, v8plus, v8plusa, v9

NOTE: The object files are built at the place where configure is launched



なぜか --target-list=arm-softmmu でやったら undefined reference to `ffs' というエラーが出たので、qemu-0.9.1/hw/max7310.c や sd.c などの該当行を comment out した。

--disable-sdl --disable-gfx-check などとすると、グラフィカルアウトプットを切れるみたい。
(ただし、QEMU のサイトのサンプルイメージは、-nographic では起動しなかった)

Makefile だけ編集してもダメ。confighost.mak なども変更しないと反映されない。