qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Thiemo Seufer <ths@networkno.de>
To: qemu-devel@nongnu.org
Subject: [Qemu-devel] [PATCH 4/6] A cumulative MIPS patchset
Date: Tue, 21 Nov 2006 14:43:31 +0000	[thread overview]
Message-ID: <20061121144331.GE12745@networkno.de> (raw)

[-- Attachment #1: Type: text/plain, Size: 11339 bytes --]

Hello All,

this patch inlines mfc0 instructions for the MIPS system emulation.


Thiemo


Index: qemu-work/target-mips/exec.h
===================================================================
--- qemu-work.orig/target-mips/exec.h	2006-11-15 22:41:21.000000000 +0000
+++ qemu-work/target-mips/exec.h	2006-11-15 22:41:24.000000000 +0000
@@ -66,7 +66,8 @@
 void do_msub (void);
 void do_msubu (void);
 #endif
-void do_mfc0(int reg, int sel);
+void do_mfc0_random(void);
+void do_mfc0_count(void);
 void do_mtc0(int reg, int sel);
 void do_tlbwi (void);
 void do_tlbwr (void);
Index: qemu-work/target-mips/op.c
===================================================================
--- qemu-work.orig/target-mips/op.c	2006-11-15 22:41:18.000000000 +0000
+++ qemu-work/target-mips/op.c	2006-11-15 22:41:24.000000000 +0000
@@ -688,9 +688,167 @@
 }
 
 /* CP0 functions */
-void op_mfc0 (void)
+void op_mfc0_index (void)
 {
-    CALL_FROM_TB2(do_mfc0, PARAM1, PARAM2);
+    T0 = env->CP0_index;
+    RETURN();
+}
+
+void op_mfc0_random (void)
+{
+    CALL_FROM_TB0(do_mfc0_random);
+    RETURN();
+}
+
+void op_mfc0_entrylo0 (void)
+{
+    T0 = env->CP0_EntryLo0;
+    RETURN();
+}
+
+void op_mfc0_entrylo1 (void)
+{
+    T0 = env->CP0_EntryLo1;
+    RETURN();
+}
+
+void op_mfc0_context (void)
+{
+    T0 = env->CP0_Context;
+    RETURN();
+}
+
+void op_mfc0_pagemask (void)
+{
+    T0 = env->CP0_PageMask;
+    RETURN();
+}
+
+void op_mfc0_wired (void)
+{
+    T0 = env->CP0_Wired;
+    RETURN();
+}
+
+void op_mfc0_badvaddr (void)
+{
+    T0 = env->CP0_BadVAddr;
+    RETURN();
+}
+
+void op_mfc0_count (void)
+{
+    CALL_FROM_TB0(do_mfc0_count);
+    RETURN();
+}
+
+void op_mfc0_entryhi (void)
+{
+    T0 = env->CP0_EntryHi;
+    RETURN();
+}
+
+void op_mfc0_compare (void)
+{
+    T0 = env->CP0_Compare;
+    RETURN();
+}
+
+void op_mfc0_status (void)
+{
+    T0 = env->CP0_Status;
+    if (env->hflags & MIPS_HFLAG_UM)
+        T0 |= (1 << CP0St_UM);
+    if (env->hflags & MIPS_HFLAG_ERL)
+        T0 |= (1 << CP0St_ERL);
+    if (env->hflags & MIPS_HFLAG_EXL)
+        T0 |= (1 << CP0St_EXL);
+    RETURN();
+}
+
+void op_mfc0_cause (void)
+{
+    T0 = env->CP0_Cause;
+    RETURN();
+}
+
+void op_mfc0_epc (void)
+{
+    T0 = env->CP0_EPC;
+    RETURN();
+}
+
+void op_mfc0_prid (void)
+{
+    T0 = env->CP0_PRid;
+    RETURN();
+}
+
+void op_mfc0_config0 (void)
+{
+    T0 = env->CP0_Config0;
+    RETURN();
+}
+
+void op_mfc0_config1 (void)
+{
+    T0 = env->CP0_Config1;
+    RETURN();
+}
+
+void op_mfc0_lladdr (void)
+{
+    T0 = env->CP0_LLAddr >> 4;
+    RETURN();
+}
+
+void op_mfc0_watchlo (void)
+{
+    T0 = env->CP0_WatchLo;
+    RETURN();
+}
+
+void op_mfc0_watchhi (void)
+{
+    T0 = env->CP0_WatchHi;
+    RETURN();
+}
+
+void op_mfc0_debug (void)
+{
+    T0 = env->CP0_Debug;
+    if (env->hflags & MIPS_HFLAG_DM)
+        T0 |= 1 << CP0DB_DM;
+    RETURN();
+}
+
+void op_mfc0_depc (void)
+{
+    T0 = env->CP0_DEPC;
+    RETURN();
+}
+
+void op_mfc0_taglo (void)
+{
+    T0 = env->CP0_TagLo;
+    RETURN();
+}
+
+void op_mfc0_datalo (void)
+{
+    T0 = env->CP0_DataLo;
+    RETURN();
+}
+
+void op_mfc0_errorepc (void)
+{
+    T0 = env->CP0_ErrorEPC;
+    RETURN();
+}
+
+void op_mfc0_desave (void)
+{
+    T0 = env->CP0_DESAVE;
     RETURN();
 }
 
Index: qemu-work/target-mips/op_helper.c
===================================================================
--- qemu-work.orig/target-mips/op_helper.c	2006-11-15 22:41:04.000000000 +0000
+++ qemu-work/target-mips/op_helper.c	2006-11-15 22:41:24.000000000 +0000
@@ -132,10 +132,16 @@
 #endif
 
 #if defined(CONFIG_USER_ONLY) 
-void do_mfc0 (int reg, int sel)
+void do_mfc0_random (void)
 {
-    cpu_abort(env, "mfc0 reg=%d sel=%d\n", reg, sel);
+    cpu_abort(env, "mfc0 random\n");
 }
+
+void do_mfc0_count (void)
+{
+    cpu_abort(env, "mfc0 count\n");
+}
+
 void do_mtc0 (int reg, int sel)
 {
     cpu_abort(env, "mtc0 reg=%d sel=%d\n", reg, sel);
@@ -160,152 +166,18 @@
 {
     cpu_abort(env, "tlbr\n");
 }
+
 #else
 
 /* CP0 helpers */
-void do_mfc0 (int reg, int sel)
+void do_mfc0_random (void)
 {
-    const unsigned char *rn;
+    T0 = cpu_mips_get_random(env);
+}
 
-    if (sel != 0 && reg != 16 && reg != 28) {
-        rn = "invalid";
-        goto print;
-    }
-    switch (reg) {
-    case 0:
-        T0 = env->CP0_index;
-        rn = "Index";
-        break;
-    case 1:
-        T0 = cpu_mips_get_random(env);
-        rn = "Random";
-        break;
-    case 2:
-        T0 = env->CP0_EntryLo0;
-        rn = "EntryLo0";
-        break;
-    case 3:
-        T0 = env->CP0_EntryLo1;
-        rn = "EntryLo1";
-        break;
-    case 4:
-        T0 = env->CP0_Context;
-        rn = "Context";
-        break;
-    case 5:
-        T0 = env->CP0_PageMask;
-        rn = "PageMask";
-        break;
-    case 6:
-        T0 = env->CP0_Wired;
-        rn = "Wired";
-        break;
-    case 8:
-        T0 = env->CP0_BadVAddr;
-        rn = "BadVaddr";
-        break;
-    case 9:
-        T0 = cpu_mips_get_count(env);
-        rn = "Count";
-        break;
-    case 10:
-        T0 = env->CP0_EntryHi;
-        rn = "EntryHi";
-        break;
-    case 11:
-        T0 = env->CP0_Compare;
-        rn = "Compare";
-        break;
-    case 12:
-        T0 = env->CP0_Status;
-        if (env->hflags & MIPS_HFLAG_UM)
-            T0 |= (1 << CP0St_UM);
-        rn = "Status";
-        break;
-    case 13:
-        T0 = env->CP0_Cause;
-        rn = "Cause";
-        break;
-    case 14:
-        T0 = env->CP0_EPC;
-        rn = "EPC";
-        break;
-    case 15:
-        T0 = env->CP0_PRid;
-        rn = "PRid";
-        break;
-    case 16:
-        switch (sel) {
-        case 0:
-            T0 = env->CP0_Config0;
-            rn = "Config";
-            break;
-        case 1:
-            T0 = env->CP0_Config1;
-            rn = "Config1";
-            break;
-        default:
-            rn = "Unknown config register";
-            break;
-        }
-        break;
-    case 17:
-        T0 = env->CP0_LLAddr >> 4;
-        rn = "LLAddr";
-        break;
-    case 18:
-        T0 = env->CP0_WatchLo;
-        rn = "WatchLo";
-        break;
-    case 19:
-        T0 = env->CP0_WatchHi;
-        rn = "WatchHi";
-        break;
-    case 23:
-        T0 = env->CP0_Debug;
-        if (env->hflags & MIPS_HFLAG_DM)
-            T0 |= 1 << CP0DB_DM;
-        rn = "Debug";
-        break;
-    case 24:
-        T0 = env->CP0_DEPC;
-        rn = "DEPC";
-        break;
-    case 28:
-        switch (sel) {
-        case 0:
-            T0 = env->CP0_TagLo;
-            rn = "TagLo";
-            break;
-        case 1:
-            T0 = env->CP0_DataLo;
-            rn = "DataLo";
-            break;
-        default:
-            rn = "unknown sel";
-            break;
-        }
-        break;
-    case 30:
-        T0 = env->CP0_ErrorEPC;
-        rn = "ErrorEPC";
-        break;
-    case 31:
-        T0 = env->CP0_DESAVE;
-        rn = "DESAVE";
-        break;
-    default:
-        rn = "unknown";
-        break;
-    }
- print:
-#if defined MIPS_DEBUG_DISAS
-    if (loglevel & CPU_LOG_TB_IN_ASM) {
-        fprintf(logfile, "%08x mfc0 %s => %08x (%d %d)\n",
-                env->PC, rn, T0, reg, sel);
-    }
-#endif
-    return;
+void do_mfc0_count (void)
+{
+    T0 = cpu_mips_get_count(env);
 }
 
 void do_mtc0 (int reg, int sel)
Index: qemu-work/target-mips/translate.c
===================================================================
--- qemu-work.orig/target-mips/translate.c	2006-11-15 22:41:18.000000000 +0000
+++ qemu-work/target-mips/translate.c	2006-11-15 22:41:24.000000000 +0000
@@ -1349,6 +1349,155 @@
 }
 
 /* CP0 (MMU and control) */
+static void gen_mfc0 (DisasContext *ctx, int reg, int sel)
+{
+    const unsigned char *rn;
+
+    if (sel != 0 && reg != 16 && reg != 28) {
+        rn = "invalid";
+        goto die;
+    }
+    switch (reg) {
+    case 0:
+        gen_op_mfc0_index();
+        rn = "Index";
+        break;
+    case 1:
+        gen_op_mfc0_random();
+        rn = "Random";
+        break;
+    case 2:
+        gen_op_mfc0_entrylo0();
+        rn = "EntryLo0";
+        break;
+    case 3:
+        gen_op_mfc0_entrylo1();
+        rn = "EntryLo1";
+        break;
+    case 4:
+        gen_op_mfc0_context();
+        rn = "Context";
+        break;
+    case 5:
+        gen_op_mfc0_pagemask();
+        rn = "PageMask";
+        break;
+    case 6:
+        gen_op_mfc0_wired();
+        rn = "Wired";
+        break;
+    case 8:
+        gen_op_mfc0_badvaddr();
+        rn = "BadVaddr";
+        break;
+    case 9:
+        gen_op_mfc0_count();
+        rn = "Count";
+        break;
+    case 10:
+        gen_op_mfc0_entryhi();
+        rn = "EntryHi";
+        break;
+    case 11:
+        gen_op_mfc0_compare();
+        rn = "Compare";
+        break;
+    case 12:
+        gen_op_mfc0_status();
+        rn = "Status";
+        break;
+    case 13:
+        gen_op_mfc0_cause();
+        rn = "Cause";
+        break;
+    case 14:
+        gen_op_mfc0_epc();
+        rn = "EPC";
+        break;
+    case 15:
+        gen_op_mfc0_prid();
+        rn = "PRid";
+        break;
+    case 16:
+        switch (sel) {
+        case 0:
+           gen_op_mfc0_config0();
+            rn = "Config";
+            break;
+        case 1:
+           gen_op_mfc0_config1();
+            rn = "Config1";
+            break;
+        default:
+            rn = "Unknown config register";
+            goto die;
+        }
+        break;
+    case 17:
+        gen_op_mfc0_lladdr();
+        rn = "LLAddr";
+        break;
+    case 18:
+        gen_op_mfc0_watchlo();
+        rn = "WatchLo";
+        break;
+    case 19:
+        gen_op_mfc0_watchhi();
+        rn = "WatchHi";
+        break;
+    case 23:
+        gen_op_mfc0_debug();
+        rn = "Debug";
+        break;
+    case 24:
+        gen_op_mfc0_depc();
+        rn = "DEPC";
+        break;
+    case 28:
+        switch (sel) {
+        case 0:
+            gen_op_mfc0_taglo();
+            rn = "TagLo";
+            break;
+        case 1:
+            gen_op_mfc0_datalo();
+            rn = "DataLo";
+            break;
+        default:
+            rn = "unknown sel";
+            goto die;
+        }
+        break;
+    case 30:
+        gen_op_mfc0_errorepc();
+        rn = "ErrorEPC";
+        break;
+    case 31:
+        gen_op_mfc0_desave();
+        rn = "DESAVE";
+        break;
+    default:
+        rn = "unknown";
+       goto die;
+    }
+#if defined MIPS_DEBUG_DISAS
+    if (loglevel & CPU_LOG_TB_IN_ASM) {
+        fprintf(logfile, "%08x mfc0 %s => %08x (%d %d)\n",
+                env->PC, rn, T0, reg, sel);
+    }
+#endif
+    return;
+
+die:
+#if defined MIPS_DEBUG_DISAS
+    if (loglevel & CPU_LOG_TB_IN_ASM) {
+        fprintf(logfile, "%08x mfc0 %s => %08x (%d %d)\n",
+                env->PC, rn, T0, reg, sel);
+    }
+#endif
+    generate_exception(ctx, EXCP_RI);
+}
+
 static void gen_cp0 (DisasContext *ctx, uint16_t opc, int rt, int rd)
 {
     const unsigned char *opn = "unk";
@@ -1370,7 +1519,7 @@
             /* Treat as NOP */
             return;
         }
-        gen_op_mfc0(rd, ctx->opcode & 0x7);
+        gen_mfc0(ctx, rd, ctx->opcode & 0x7);
         gen_op_store_T0_gpr(rt);
         opn = "mfc0";
         break;

[-- Attachment #2: qemu.drow-halt-reboot --]
[-- Type: text/plain, Size: 8060 bytes --]

Date: Sat, 11 Nov 2006 20:02:40 -0500
From: Daniel Jacobowitz <drow@false.org>
To: qemu-devel@nongnu.org
Subject: [Qemu-devel] MIPS halt / reboot

The MIPS kernel already has a reset/halt device for qemu
(arch/mips/qemu/q-reset.c).  I have no idea at all where this came
from, but hey, it seems sensible enough to me so I implemented it
in qemu.

This requires a bit of additional mucking around, since MIPS doesn't
currently have any BIOS support, so I made the reset vector reload any
specified kernel and initrd.  Works in my Debian rootfs; very handy for
automated benchmarking.

-- 
Daniel Jacobowitz
CodeSourcery

---
 hw/mips_r4k.c           |  144 +++++++++++++++++++++++++++++++++---------------
 target-mips/cpu.h       |    8 ++
 target-mips/translate.c |   10 +++
 3 files changed, 116 insertions(+), 46 deletions(-)

Index: qemu-work/hw/mips_r4k.c
===================================================================
--- qemu-work.orig/hw/mips_r4k.c	2006-11-15 22:40:28.000000000 +0000
+++ qemu-work/hw/mips_r4k.c	2006-11-15 22:41:14.000000000 +0000
@@ -110,6 +110,93 @@
     cpu_mips_update_count(env, 1, 0);
 }
 
+static void mips_qemu_writel (void *opaque, target_phys_addr_t addr,
+			      uint32_t val)
+{
+    if ((addr & 0xffff) == 0 && val == 42)
+        qemu_system_reset_request ();
+    else if ((addr & 0xffff) == 4 && val == 42)
+        qemu_system_shutdown_request ();
+}
+
+static uint32_t mips_qemu_readl (void *opaque, target_phys_addr_t addr)
+{
+    return 0;
+}
+
+static CPUWriteMemoryFunc *mips_qemu_write[] = {
+    &mips_qemu_writel,
+    &mips_qemu_writel,
+    &mips_qemu_writel,
+};
+
+static CPUReadMemoryFunc *mips_qemu_read[] = {
+    &mips_qemu_readl,
+    &mips_qemu_readl,
+    &mips_qemu_readl,
+};
+
+static int mips_qemu_iomemtype = 0;
+
+void load_kernel (CPUState *env, int ram_size, const char *kernel_filename,
+		  const char *kernel_cmdline,
+		  const char *initrd_filename)
+{
+    int64_t entry = 0;
+    long kernel_size, initrd_size;
+
+    kernel_size = load_elf(kernel_filename, VIRT_TO_PHYS_ADDEND, &entry);
+    if (kernel_size >= 0)
+        env->PC = entry;
+    else {
+        kernel_size = load_image(kernel_filename,
+                                 phys_ram_base + KERNEL_LOAD_ADDR + VIRT_TO_PHYS_ADDEND);
+        if (kernel_size < 0) {
+            fprintf(stderr, "qemu: could not load kernel '%s'\n",
+                    kernel_filename);
+            exit(1);
+        }
+        env->PC = KERNEL_LOAD_ADDR;
+    }
+
+    /* load initrd */
+    initrd_size = 0;
+    if (initrd_filename) {
+        initrd_size = load_image(initrd_filename,
+                                 phys_ram_base + INITRD_LOAD_ADDR + VIRT_TO_PHYS_ADDEND);
+        if (initrd_size == (target_ulong) -1) {
+            fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
+                    initrd_filename);
+            exit(1);
+        }
+    }
+
+    /* Store command line.  */
+    if (initrd_size > 0) {
+        int ret;
+        ret = sprintf(phys_ram_base + (16 << 20) - 256,
+                      "rd_start=0x%08x rd_size=%li ",
+                      INITRD_LOAD_ADDR,
+                      initrd_size);
+        strcpy (phys_ram_base + (16 << 20) - 256 + ret, kernel_cmdline);
+    }
+    else {
+        strcpy (phys_ram_base + (16 << 20) - 256, kernel_cmdline);
+    }
+
+    *(int *)(phys_ram_base + (16 << 20) - 260) = tswap32 (0x12345678);
+    *(int *)(phys_ram_base + (16 << 20) - 264) = tswap32 (ram_size);
+}
+
+static void main_cpu_reset(void *opaque)
+{
+    CPUState *env = opaque;
+    cpu_reset(env);
+
+    if (env->kernel_filename)
+        load_kernel (env, env->ram_size, env->kernel_filename,
+                     env->kernel_cmdline, env->initrd_filename);
+}
 
 void mips_r4k_init (int ram_size, int vga_ram_size, int boot_device,
                     DisplayState *ds, const char **fd_filename, int snapshot,
@@ -117,19 +204,24 @@
                     const char *initrd_filename)
 {
     char buf[1024];
-    int64_t entry = 0;
     unsigned long bios_offset;
     int ret;
     CPUState *env;
-    long kernel_size;
     int i;
 
     env = cpu_init();
     register_savevm("cpu", 0, 3, cpu_save, cpu_load, env);
+    qemu_register_reset(main_cpu_reset, env);
 
     /* allocate RAM */
     cpu_register_physical_memory(0, ram_size, IO_MEM_RAM);
 
+    if (!mips_qemu_iomemtype) {
+        mips_qemu_iomemtype = cpu_register_io_memory(0, mips_qemu_read,
+						     mips_qemu_write, NULL);
+    }
+    cpu_register_physical_memory(0x1fbf0000, 0x10000, mips_qemu_iomemtype);
+
     /* Try to load a BIOS image. If this fails, we continue regardless,
        but initialize the hardware ourselves. When a kernel gets
        preloaded we also initialize the hardware, since the BIOS wasn't
@@ -146,38 +238,13 @@
 		buf);
     }
 
-    kernel_size = 0;
     if (kernel_filename) {
-	kernel_size = load_elf(kernel_filename, VIRT_TO_PHYS_ADDEND, &entry);
-	if (kernel_size >= 0)
-	    env->PC = entry;
-	else {
-	    kernel_size = load_image(kernel_filename,
-                                     phys_ram_base + KERNEL_LOAD_ADDR + VIRT_TO_PHYS_ADDEND);
-            if (kernel_size < 0) {
-                fprintf(stderr, "qemu: could not load kernel '%s'\n",
-                        kernel_filename);
-                exit(1);
-            }
-            env->PC = KERNEL_LOAD_ADDR;
-	}
-
-        /* load initrd */
-        if (initrd_filename) {
-            if (load_image(initrd_filename,
-			   phys_ram_base + INITRD_LOAD_ADDR + VIRT_TO_PHYS_ADDEND)
-		== (target_ulong) -1) {
-                fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", 
-                        initrd_filename);
-                exit(1);
-            }
-        }
-
-	/* Store command line.  */
-        strcpy (phys_ram_base + (16 << 20) - 256, kernel_cmdline);
-        /* FIXME: little endian support */
-        *(int *)(phys_ram_base + (16 << 20) - 260) = tswap32 (0x12345678);
-        *(int *)(phys_ram_base + (16 << 20) - 264) = tswap32 (ram_size);
+        load_kernel (env, ram_size, kernel_filename, kernel_cmdline,
+		     initrd_filename);
+	env->ram_size = ram_size;
+	env->kernel_filename = kernel_filename;
+	env->kernel_cmdline = kernel_cmdline;
+	env->initrd_filename = initrd_filename;
     }
 
     /* Init internal devices */
Index: qemu-work/target-mips/cpu.h
===================================================================
--- qemu-work.orig/target-mips/cpu.h	2006-11-15 22:41:04.000000000 +0000
+++ qemu-work/target-mips/cpu.h	2006-11-15 22:41:14.000000000 +0000
@@ -182,7 +182,6 @@
     uint32_t CP0_ErrorEPC;
     uint32_t CP0_DESAVE;
     /* Qemu */
-    struct QEMUTimer *timer; /* Internal timer */
     int interrupt_request;
     jmp_buf jmp_env;
     int exception_index;
@@ -213,6 +212,13 @@
     int halted; /* TRUE if the CPU is in suspend state */
 
     CPU_COMMON
+
+    int ram_size;
+    const char *kernel_filename;
+    const char *kernel_cmdline;
+    const char *initrd_filename;
+
+    struct QEMUTimer *timer; /* Internal timer */
 };
 
 #include "cpu-all.h"
Index: qemu-work/target-mips/translate.c
===================================================================
--- qemu-work.orig/target-mips/translate.c	2006-11-15 22:41:04.000000000 +0000
+++ qemu-work/target-mips/translate.c	2006-11-15 22:41:14.000000000 +0000
@@ -2425,7 +2425,16 @@
     if (!env)
         return NULL;
     cpu_exec_init(env);
+    cpu_reset(env);
+    return env;
+}
+
+void cpu_reset (CPUMIPSState *env)
+{
+    memset(env, 0, offsetof(CPUMIPSState, breakpoints));
+
     tlb_flush(env, 1);
+
     /* Minimal init */
     env->PC = 0xBFC00000;
 #if defined (MIPS_USES_R4K_TLB)
@@ -2456,5 +2465,4 @@
 #ifdef MIPS_USES_FPU
     env->fcr0 = MIPS_FCR0;	
 #endif
-    return env;
 }

             reply	other threads:[~2006-11-21 14:44 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2006-11-21 14:43 Thiemo Seufer [this message]
  -- strict thread matches above, loose matches on Subject: below --
2006-11-21 14:44 [Qemu-devel] [PATCH 4/6] A cumulative MIPS patchset Thiemo Seufer

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20061121144331.GE12745@networkno.de \
    --to=ths@networkno.de \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).