tomoyuki-nakabayashi / Rustemu86

Apache License 2.0
5 stars 0 forks source link

正しいエミュレータで正しい動作をテストできるようにする #5

Closed tomoyuki-nakabayashi closed 5 years ago

tomoyuki-nakabayashi commented 6 years ago

qemuとかなんでもいいんだけど、命令実行後のレジスタやメモリの状態を確認できるようにする必要がある。

tomoyuki-nakabayashi commented 6 years ago

まず形式をどうしようかな。JSONで良いかね?

tomoyuki-nakabayashi commented 6 years ago

RustのSerdeの簡単な紹介 https://docs.serde.rs/serde/#data-formats

素晴らしいな。

tomoyuki-nakabayashi commented 6 years ago
{"ram":[0,0,0,0,248,0,0,0]}

こんな感じで出力してくれる。

tomoyuki-nakabayashi commented 6 years ago

Bochsのコードを眺める。まぁ簡単に出力機能は追加できそうだけど、全体的にコードがひどいな。

tomoyuki-nakabayashi commented 6 years ago

http://rkx1209.hatenablog.com/entry/2015/11/20/203511

るくすさんが居なければつらかったな。

cpu-exec.cのcpu_tb_exec()が実質命令実行している(ぽい)。

tomoyuki-nakabayashi commented 6 years ago

qom/cpu.c

void cpu_dump_state(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf,
                    int flags)
{
    CPUClass *cc = CPU_GET_CLASS(cpu);

    if (cc->dump_state) {
        cpu_synchronize_state(cpu);
        cc->dump_state(cpu, f, cpu_fprintf, flags);
    }
}
#define X86_CPU_CLASS(klass) \
    OBJECT_CLASS_CHECK(X86CPUClass, (klass), TYPE_X86_CPU)
#define X86_CPU(obj) \
    OBJECT_CHECK(X86CPU, (obj), TYPE_X86_CPU)
#define X86_CPU_GET_CLASS(obj) \
    OBJECT_GET_CLASS(X86CPUClass, (obj), TYPE_X86_CPU)

CPUClassでdumpを実装している箇所があるはず。

tomoyuki-nakabayashi commented 6 years ago

CPUClassの中にdump_stateが関数ポインタとして定義されている。 後はこれがどこで登録されているか、かな。

tomoyuki-nakabayashi commented 6 years ago

target/i386/helper.c

void x86_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf,
                        int flags)
{
    X86CPU *cpu = X86_CPU(cs);
    CPUX86State *env = &cpu->env;
    int eflags, i, nb;
    char cc_op_name[32];
    static const char *seg_name[6] = { "ES", "CS", "SS", "DS", "FS", "GS" };

    eflags = cpu_compute_eflags(env);
#ifdef TARGET_X86_64
...

おったおった。

tomoyuki-nakabayashi commented 6 years ago
#if defined(DEBUG_DISAS)
    if (qemu_loglevel_mask(CPU_LOG_TB_CPU)
        && qemu_log_in_addr_range(itb->pc)) {
        qemu_log_lock();
        int flags = 0;
        if (qemu_loglevel_mask(CPU_LOG_TB_FPU)) {
            flags |= CPU_DUMP_FPU;
        }
#if defined(TARGET_I386)
        flags |= CPU_DUMP_CCOP;
#endif
        log_cpu_state(cpu, flags);
        qemu_log_unlock();
    }
#endif /* DEBUG_DISAS */

ここに戻ると、何がどこまで定義されているんだろう?

tomoyuki-nakabayashi commented 6 years ago

DEBUG_DISASは定義されている。

exec-all.h

/* allow to see translation results - the slowdown should be negligible, so we leave it */
#define DEBUG_DISAS
tomoyuki-nakabayashi commented 6 years ago

https://unix.stackexchange.com/questions/237409/logging-and-debugging-for-qemu-virtual-machines

普通に-dで動かせと?

tomoyuki-nakabayashi commented 6 years ago

-dオプションで色々吐ける。

$ qemu-system-x86_64 -d ./qemu.log -drive format=raw,file=target/x86_64-blog_os/debug/bootimage-blog_os.bin
Log items (comma separated):
out_asm    show generated host assembly code for each compiled TB
in_asm     show target assembly code for each compiled TB
op         show micro ops for each compiled TB
op_opt     show micro ops (x86 only: before eflags optimization) and
after liveness analysis
int        show interrupts/exceptions in short format
exec       show trace before each executed TB (lots of logs)
cpu        show CPU state before block translation
mmu        log MMU-related activities
pcall      x86 only: show protected mode far calls/returns/exceptions
cpu_reset  show CPU state before CPU resets
unimp      log unimplemented functionality
guest_errors log when the guest OS does something invalid (eg accessing a
non-existent register)
nochain    do not chain compiled TBs so that "exec" and "cpu" show
complete traces

-d cpu

EAX=0000fe7e EBX=00000000 ECX=00009135 EDX=0000e000
ESI=00000000 EDI=00000000 EBP=00000000 ESP=0000fe6c
EIP=00007824 EFL=00000002 [-------] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =0040 00000400 ffffffff 008f9300
CS =f000 000f0000 ffffffff 008f9b00
SS =e000 000e0000 ffffffff 008f9300
DS =e000 000e0000 ffffffff 008f9300
FS =0000 00000000 ffffffff 008f9300
GS =0000 00000000 ffffffff 008f9300
LDT=0000 00000000 0000ffff 00008200
TR =0000 00000000 0000ffff 00008b00
GDT=     000f6c00 00000037
IDT=     00000000 000003ff
CR0=00000010 CR2=00000000 CR3=00000000 CR4=00000000
DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000 DR3=0000000000000000 
DR6=00000000ffff0ff0 DR7=0000000000000400
CCS=0000f6e0 CCD=00000001 CCO=LOGICL  
EFER=0000000000000000

-Dでログファイルが指定できる。

tomoyuki-nakabayashi commented 6 years ago

一瞬で870MBか…。厳しいなぁ。

tomoyuki-nakabayashi commented 6 years ago

まぁいいか。

tomoyuki-nakabayashi commented 6 years ago

あーBIOSから動くから…。

tomoyuki-nakabayashi commented 6 years ago

BIOS(相当のものを)を作るか。 で、0x7c00に飛ぶところからエミュレータを開始しよう。

tomoyuki-nakabayashi commented 6 years ago

なるほど。qemuのdumpって毎サイクル吐き出されているわけじゃないみたいだな。 うまく使う必要がありそう。

tomoyuki-nakabayashi commented 6 years ago

checkpointとして使うか。

tomoyuki-nakabayashi commented 6 years ago

qemu-fromが仕上がってきた。 ↓で公開していないcrateも取ってこれる。

[dependencies]
qemu-from = { git = "https://github.com/tomoyuki-nakabayashi/qemu-from.git" }
tomoyuki-nakabayashi commented 5 years ago

自動化はできていないけど、一旦close。