From: Richard Henderson <richard.henderson@linaro.org>
To: qemu-devel@nongnu.org
Cc: Anton Johansson <anjo@rev.ng>
Subject: [PULL 06/52] tcg: Widen CPUTLBEntry comparators to 64-bits
Date: Mon, 5 Jun 2023 13:15:02 -0700 [thread overview]
Message-ID: <20230605201548.1596865-7-richard.henderson@linaro.org> (raw)
In-Reply-To: <20230605201548.1596865-1-richard.henderson@linaro.org>
This makes CPUTLBEntry agnostic to the address size of the guest.
When 32-bit addresses are in effect, we can simply read the low
32 bits of the 64-bit field. Similarly when we need to update
the field for setting TLB_NOTDIRTY.
For TCG backends that could in theory be big-endian, but in
practice are not (arm, loongarch, riscv), use QEMU_BUILD_BUG_ON
to document and ensure this is not accidentally missed.
For s390x, which is always big-endian, use HOST_BIG_ENDIAN anyway,
to document the reason for the adjustment.
For sparc64 and ppc64, always perform a 64-bit load, and rely on
the following 32-bit comparison to ignore the high bits.
Rearrange mips and ppc if ladders for clarity.
Reviewed-by: Anton Johansson <anjo@rev.ng>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
include/exec/cpu-defs.h | 37 +++++++++++---------------------
include/exec/cpu_ldst.h | 19 ++++++++++------
accel/tcg/cputlb.c | 8 +++++--
tcg/aarch64/tcg-target.c.inc | 1 +
tcg/arm/tcg-target.c.inc | 1 +
tcg/loongarch64/tcg-target.c.inc | 1 +
tcg/mips/tcg-target.c.inc | 13 ++++++-----
tcg/ppc/tcg-target.c.inc | 28 +++++++++++++-----------
tcg/riscv/tcg-target.c.inc | 1 +
tcg/s390x/tcg-target.c.inc | 1 +
tcg/sparc64/tcg-target.c.inc | 8 +++++--
11 files changed, 67 insertions(+), 51 deletions(-)
diff --git a/include/exec/cpu-defs.h b/include/exec/cpu-defs.h
index a6e0cf1812..b757d37966 100644
--- a/include/exec/cpu-defs.h
+++ b/include/exec/cpu-defs.h
@@ -65,11 +65,7 @@
/* use a fully associative victim tlb of 8 entries */
#define CPU_VTLB_SIZE 8
-#if HOST_LONG_BITS == 32 && TARGET_LONG_BITS == 32
-#define CPU_TLB_ENTRY_BITS 4
-#else
#define CPU_TLB_ENTRY_BITS 5
-#endif
#define CPU_TLB_DYN_MIN_BITS 6
#define CPU_TLB_DYN_DEFAULT_BITS 8
@@ -95,33 +91,26 @@
# endif
/* Minimalized TLB entry for use by TCG fast path. */
-typedef struct CPUTLBEntry {
- /* bit TARGET_LONG_BITS to TARGET_PAGE_BITS : virtual address
- bit TARGET_PAGE_BITS-1..4 : Nonzero for accesses that should not
- go directly to ram.
- bit 3 : indicates that the entry is invalid
- bit 2..0 : zero
- */
- union {
- struct {
- target_ulong addr_read;
- target_ulong addr_write;
- target_ulong addr_code;
- /* Addend to virtual address to get host address. IO accesses
- use the corresponding iotlb value. */
- uintptr_t addend;
- };
+typedef union CPUTLBEntry {
+ struct {
+ uint64_t addr_read;
+ uint64_t addr_write;
+ uint64_t addr_code;
/*
- * Padding to get a power of two size, as well as index
- * access to addr_{read,write,code}.
+ * Addend to virtual address to get host address. IO accesses
+ * use the corresponding iotlb value.
*/
- target_ulong addr_idx[(1 << CPU_TLB_ENTRY_BITS) / TARGET_LONG_SIZE];
+ uintptr_t addend;
};
+ /*
+ * Padding to get a power of two size, as well as index
+ * access to addr_{read,write,code}.
+ */
+ uint64_t addr_idx[(1 << CPU_TLB_ENTRY_BITS) / sizeof(uint64_t)];
} CPUTLBEntry;
QEMU_BUILD_BUG_ON(sizeof(CPUTLBEntry) != (1 << CPU_TLB_ENTRY_BITS));
-
#endif /* !CONFIG_USER_ONLY && CONFIG_TCG */
#if !defined(CONFIG_USER_ONLY)
diff --git a/include/exec/cpu_ldst.h b/include/exec/cpu_ldst.h
index 5939688f69..a43b34e46b 100644
--- a/include/exec/cpu_ldst.h
+++ b/include/exec/cpu_ldst.h
@@ -334,18 +334,25 @@ static inline target_ulong tlb_read_idx(const CPUTLBEntry *entry,
{
/* Do not rearrange the CPUTLBEntry structure members. */
QEMU_BUILD_BUG_ON(offsetof(CPUTLBEntry, addr_read) !=
- MMU_DATA_LOAD * TARGET_LONG_SIZE);
+ MMU_DATA_LOAD * sizeof(uint64_t));
QEMU_BUILD_BUG_ON(offsetof(CPUTLBEntry, addr_write) !=
- MMU_DATA_STORE * TARGET_LONG_SIZE);
+ MMU_DATA_STORE * sizeof(uint64_t));
QEMU_BUILD_BUG_ON(offsetof(CPUTLBEntry, addr_code) !=
- MMU_INST_FETCH * TARGET_LONG_SIZE);
+ MMU_INST_FETCH * sizeof(uint64_t));
- const target_ulong *ptr = &entry->addr_idx[access_type];
-#if TCG_OVERSIZED_GUEST
- return *ptr;
+#if TARGET_LONG_BITS == 32
+ /* Use qatomic_read, in case of addr_write; only care about low bits. */
+ const uint32_t *ptr = (uint32_t *)&entry->addr_idx[access_type];
+ ptr += HOST_BIG_ENDIAN;
+ return qatomic_read(ptr);
#else
+ const uint64_t *ptr = &entry->addr_idx[access_type];
+# if TCG_OVERSIZED_GUEST
+ return *ptr;
+# else
/* ofs might correspond to .addr_write, so use qatomic_read */
return qatomic_read(ptr);
+# endif
#endif
}
diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c
index 90c72c9940..6beaeb0a81 100644
--- a/accel/tcg/cputlb.c
+++ b/accel/tcg/cputlb.c
@@ -1000,11 +1000,15 @@ static void tlb_reset_dirty_range_locked(CPUTLBEntry *tlb_entry,
addr &= TARGET_PAGE_MASK;
addr += tlb_entry->addend;
if ((addr - start) < length) {
-#if TCG_OVERSIZED_GUEST
+#if TARGET_LONG_BITS == 32
+ uint32_t *ptr_write = (uint32_t *)&tlb_entry->addr_write;
+ ptr_write += HOST_BIG_ENDIAN;
+ qatomic_set(ptr_write, *ptr_write | TLB_NOTDIRTY);
+#elif TCG_OVERSIZED_GUEST
tlb_entry->addr_write |= TLB_NOTDIRTY;
#else
qatomic_set(&tlb_entry->addr_write,
- tlb_entry->addr_write | TLB_NOTDIRTY);
+ tlb_entry->addr_write | TLB_NOTDIRTY);
#endif
}
}
diff --git a/tcg/aarch64/tcg-target.c.inc b/tcg/aarch64/tcg-target.c.inc
index 261ad25210..e23c57e2cd 100644
--- a/tcg/aarch64/tcg-target.c.inc
+++ b/tcg/aarch64/tcg-target.c.inc
@@ -1690,6 +1690,7 @@ static TCGLabelQemuLdst *prepare_host_addr(TCGContext *s, HostAddress *h,
tcg_out_insn(s, 3502, ADD, 1, TCG_REG_TMP1, TCG_REG_TMP1, TCG_REG_TMP0);
/* Load the tlb comparator into TMP0, and the fast path addend into TMP1. */
+ QEMU_BUILD_BUG_ON(HOST_BIG_ENDIAN);
tcg_out_ld(s, addr_type, TCG_REG_TMP0, TCG_REG_TMP1,
is_ld ? offsetof(CPUTLBEntry, addr_read)
: offsetof(CPUTLBEntry, addr_write));
diff --git a/tcg/arm/tcg-target.c.inc b/tcg/arm/tcg-target.c.inc
index 20cc1cc477..64eb0cb5dc 100644
--- a/tcg/arm/tcg-target.c.inc
+++ b/tcg/arm/tcg-target.c.inc
@@ -1430,6 +1430,7 @@ static TCGLabelQemuLdst *prepare_host_addr(TCGContext *s, HostAddress *h,
* Add the tlb_table pointer, creating the CPUTLBEntry address in R1.
* Load the tlb comparator into R2/R3 and the fast path addend into R1.
*/
+ QEMU_BUILD_BUG_ON(HOST_BIG_ENDIAN);
if (cmp_off == 0) {
if (s->addr_type == TCG_TYPE_I32) {
tcg_out_ld32_rwb(s, COND_AL, TCG_REG_R2, TCG_REG_R1, TCG_REG_R0);
diff --git a/tcg/loongarch64/tcg-target.c.inc b/tcg/loongarch64/tcg-target.c.inc
index 0bae922982..e89f3b848b 100644
--- a/tcg/loongarch64/tcg-target.c.inc
+++ b/tcg/loongarch64/tcg-target.c.inc
@@ -875,6 +875,7 @@ static TCGLabelQemuLdst *prepare_host_addr(TCGContext *s, HostAddress *h,
tcg_out_opc_add_d(s, TCG_REG_TMP2, TCG_REG_TMP2, TCG_REG_TMP1);
/* Load the tlb comparator and the addend. */
+ QEMU_BUILD_BUG_ON(HOST_BIG_ENDIAN);
tcg_out_ld(s, addr_type, TCG_REG_TMP0, TCG_REG_TMP2,
is_ld ? offsetof(CPUTLBEntry, addr_read)
: offsetof(CPUTLBEntry, addr_write));
diff --git a/tcg/mips/tcg-target.c.inc b/tcg/mips/tcg-target.c.inc
index 3274d9aace..4c0de0a380 100644
--- a/tcg/mips/tcg-target.c.inc
+++ b/tcg/mips/tcg-target.c.inc
@@ -1311,14 +1311,17 @@ static TCGLabelQemuLdst *prepare_host_addr(TCGContext *s, HostAddress *h,
/* Add the tlb_table pointer, creating the CPUTLBEntry address in TMP3. */
tcg_out_opc_reg(s, ALIAS_PADD, TCG_TMP3, TCG_TMP3, TCG_TMP1);
+ if (TCG_TARGET_REG_BITS == 32 || addr_type == TCG_TYPE_I32) {
+ /* Load the (low half) tlb comparator. */
+ tcg_out_ld(s, TCG_TYPE_I32, TCG_TMP0, TCG_TMP3,
+ cmp_off + HOST_BIG_ENDIAN * 4);
+ } else {
+ tcg_out_ld(s, TCG_TYPE_I64, TCG_TMP0, TCG_TMP3, cmp_off);
+ }
+
if (TCG_TARGET_REG_BITS == 64 || addr_type == TCG_TYPE_I32) {
- /* Load the tlb comparator. */
- tcg_out_ld(s, addr_type, TCG_TMP0, TCG_TMP3, cmp_off);
/* Load the tlb addend for the fast path. */
tcg_out_ld(s, TCG_TYPE_PTR, TCG_TMP3, TCG_TMP3, add_off);
- } else {
- /* Load the low half of the tlb comparator. */
- tcg_out_ldst(s, OPC_LW, TCG_TMP0, TCG_TMP3, cmp_off + LO_OFF);
}
/*
diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc
index 11955a6cc2..73f6ea0393 100644
--- a/tcg/ppc/tcg-target.c.inc
+++ b/tcg/ppc/tcg-target.c.inc
@@ -2098,20 +2098,24 @@ static TCGLabelQemuLdst *prepare_host_addr(TCGContext *s, HostAddress *h,
}
tcg_out32(s, AND | SAB(TCG_REG_TMP1, TCG_REG_TMP1, TCG_REG_R0));
- /* Load the (low part) TLB comparator into TMP2. */
- if (cmp_off == 0
- && (TCG_TARGET_REG_BITS == 64 || addr_type == TCG_TYPE_I32)) {
- uint32_t lxu = (TCG_TARGET_REG_BITS == 32 || addr_type == TCG_TYPE_I32
- ? LWZUX : LDUX);
- tcg_out32(s, lxu | TAB(TCG_REG_TMP2, TCG_REG_TMP1, TCG_REG_TMP2));
+ /*
+ * Load the (low part) TLB comparator into TMP2.
+ * For 64-bit host, always load the entire 64-bit slot for simplicity.
+ * We will ignore the high bits with tcg_out_cmp(..., addr_type).
+ */
+ if (TCG_TARGET_REG_BITS == 64) {
+ if (cmp_off == 0) {
+ tcg_out32(s, LDUX | TAB(TCG_REG_TMP2, TCG_REG_TMP1, TCG_REG_TMP2));
+ } else {
+ tcg_out32(s, ADD | TAB(TCG_REG_TMP1, TCG_REG_TMP1, TCG_REG_TMP2));
+ tcg_out_ld(s, TCG_TYPE_I64, TCG_REG_TMP2, TCG_REG_TMP1, cmp_off);
+ }
+ } else if (cmp_off == 0 && !HOST_BIG_ENDIAN) {
+ tcg_out32(s, LWZUX | TAB(TCG_REG_TMP2, TCG_REG_TMP1, TCG_REG_TMP2));
} else {
tcg_out32(s, ADD | TAB(TCG_REG_TMP1, TCG_REG_TMP1, TCG_REG_TMP2));
- if (TCG_TARGET_REG_BITS == 32 && addr_type != TCG_TYPE_I32) {
- tcg_out_ld(s, TCG_TYPE_I32, TCG_REG_TMP2,
- TCG_REG_TMP1, cmp_off + 4 * HOST_BIG_ENDIAN);
- } else {
- tcg_out_ld(s, addr_type, TCG_REG_TMP2, TCG_REG_TMP1, cmp_off);
- }
+ tcg_out_ld(s, TCG_TYPE_I32, TCG_REG_TMP2, TCG_REG_TMP1,
+ cmp_off + 4 * HOST_BIG_ENDIAN);
}
/*
diff --git a/tcg/riscv/tcg-target.c.inc b/tcg/riscv/tcg-target.c.inc
index a8f99f7e77..a6d56e2d0e 100644
--- a/tcg/riscv/tcg-target.c.inc
+++ b/tcg/riscv/tcg-target.c.inc
@@ -1249,6 +1249,7 @@ static TCGLabelQemuLdst *prepare_host_addr(TCGContext *s, TCGReg *pbase,
}
/* Load the tlb comparator and the addend. */
+ QEMU_BUILD_BUG_ON(HOST_BIG_ENDIAN);
tcg_out_ld(s, addr_type, TCG_REG_TMP0, TCG_REG_TMP2,
is_ld ? offsetof(CPUTLBEntry, addr_read)
: offsetof(CPUTLBEntry, addr_write));
diff --git a/tcg/s390x/tcg-target.c.inc b/tcg/s390x/tcg-target.c.inc
index 2795242b60..03be800c3b 100644
--- a/tcg/s390x/tcg-target.c.inc
+++ b/tcg/s390x/tcg-target.c.inc
@@ -1796,6 +1796,7 @@ static TCGLabelQemuLdst *prepare_host_addr(TCGContext *s, HostAddress *h,
ofs = offsetof(CPUTLBEntry, addr_write);
}
if (addr_type == TCG_TYPE_I32) {
+ ofs += HOST_BIG_ENDIAN * 4;
tcg_out_insn(s, RX, C, TCG_REG_R0, TCG_TMP0, TCG_REG_NONE, ofs);
} else {
tcg_out_insn(s, RXY, CG, TCG_REG_R0, TCG_TMP0, TCG_REG_NONE, ofs);
diff --git a/tcg/sparc64/tcg-target.c.inc b/tcg/sparc64/tcg-target.c.inc
index 48efd83817..6c60657c36 100644
--- a/tcg/sparc64/tcg-target.c.inc
+++ b/tcg/sparc64/tcg-target.c.inc
@@ -1063,8 +1063,12 @@ static TCGLabelQemuLdst *prepare_host_addr(TCGContext *s, HostAddress *h,
/* Add the tlb_table pointer, creating the CPUTLBEntry address into R2. */
tcg_out_arith(s, TCG_REG_T1, TCG_REG_T1, TCG_REG_T3, ARITH_ADD);
- /* Load the tlb comparator and the addend. */
- tcg_out_ld(s, addr_type, TCG_REG_T2, TCG_REG_T1, cmp_off);
+ /*
+ * Load the tlb comparator and the addend.
+ * Always load the entire 64-bit comparator for simplicity.
+ * We will ignore the high bits via BPCC_ICC below.
+ */
+ tcg_out_ld(s, TCG_TYPE_I64, TCG_REG_T2, TCG_REG_T1, cmp_off);
tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_T1, TCG_REG_T1, add_off);
h->base = TCG_REG_T1;
--
2.34.1
next prev parent reply other threads:[~2023-06-05 20:25 UTC|newest]
Thread overview: 57+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-06-05 20:14 [PULL 00/52] tcg patch queue Richard Henderson
2023-06-05 20:14 ` [PULL 01/52] tcg/ppc: Remove TARGET_LONG_BITS, TCG_TYPE_TL Richard Henderson
2023-06-05 20:14 ` [PULL 02/52] tcg/riscv: " Richard Henderson
2023-06-05 20:14 ` [PULL 03/52] tcg/s390x: " Richard Henderson
2023-06-05 20:15 ` [PULL 04/52] tcg/sparc64: " Richard Henderson
2023-06-05 20:15 ` [PULL 05/52] tcg: Move TCG_TYPE_TL from tcg.h to tcg-op.h Richard Henderson
2023-06-05 20:15 ` Richard Henderson [this message]
2023-06-05 20:15 ` [PULL 07/52] tcg: Add tlb_fast_offset to TCGContext Richard Henderson
2023-06-05 20:15 ` [PULL 08/52] target/avr: Add missing includes of qemu/error-report.h Richard Henderson
2023-06-05 20:15 ` [PULL 09/52] target/*: Add missing includes of tcg/debug-assert.h Richard Henderson
2023-06-05 20:15 ` [PULL 10/52] *: Add missing includes of tcg/tcg.h Richard Henderson
2023-06-05 20:15 ` [PULL 11/52] tcg: Split out tcg-target-reg-bits.h Richard Henderson
2023-06-05 20:15 ` [PULL 12/52] target/arm: Fix test of TCG_OVERSIZED_GUEST Richard Henderson
2023-06-05 20:15 ` [PULL 13/52] tcg: Split out tcg/oversized-guest.h Richard Henderson
2023-06-05 20:15 ` [PULL 14/52] tcg: Move TCGv, dup_const_tl definitions to tcg-op.h Richard Henderson
2023-06-05 20:15 ` [PULL 15/52] tcg: Split tcg/tcg-op-common.h from tcg/tcg-op.h Richard Henderson
2023-06-05 20:15 ` [PULL 16/52] target/arm: Include helper-gen.h in translator.h Richard Henderson
2023-06-05 20:15 ` [PULL 17/52] target/hexagon: Include helper-gen.h where needed Richard Henderson
2023-06-05 20:15 ` [PULL 18/52] tcg: Remove outdated comments in helper-head.h Richard Henderson
2023-06-05 20:15 ` [PULL 19/52] tcg: Move TCGHelperInfo and dependencies to tcg/helper-info.h Richard Henderson
2023-06-05 20:15 ` [PULL 20/52] tcg: Pass TCGHelperInfo to tcg_gen_callN Richard Henderson
2023-06-05 20:15 ` [PULL 21/52] tcg: Move temp_idx and tcgv_i32_temp debug out of line Richard Henderson
2023-06-05 20:15 ` [PULL 22/52] tcg: Split tcg_gen_callN Richard Henderson
2023-06-05 20:15 ` [PULL 23/52] tcg: Split helper-gen.h Richard Henderson
2023-06-05 20:15 ` [PULL 24/52] tcg: Split helper-proto.h Richard Henderson
2023-06-05 20:15 ` [PULL 25/52] target/sh4: Emit insn_start for each insn in gUSA region Richard Henderson
2023-06-05 20:15 ` [PULL 26/52] tcg: Add insn_start_words to TCGContext Richard Henderson
2023-06-05 20:15 ` [PULL 27/52] tcg: Add guest_mo " Richard Henderson
2023-06-05 20:15 ` [PULL 28/52] tcg: Move TLB_FLAGS_MASK check out of get_alignment_bits Richard Henderson
2023-06-05 20:15 ` [PULL 29/52] tcg: Split tcg/tcg-op-gvec.h Richard Henderson
2023-06-05 20:15 ` [PULL 30/52] tcg: Remove NO_CPU_IO_DEFS Richard Henderson
2023-06-05 20:15 ` [PULL 31/52] exec-all: Widen tb_page_addr_t for user-only Richard Henderson
2023-06-05 20:15 ` [PULL 32/52] exec-all: Widen TranslationBlock pc and cs_base to 64-bits Richard Henderson
2023-07-11 16:42 ` Peter Maydell
2023-06-05 20:15 ` [PULL 33/52] tcg: Spit out exec/translation-block.h Richard Henderson
2023-06-05 20:15 ` [PULL 34/52] include/exec: Remove CODE_GEN_AVG_BLOCK_SIZE Richard Henderson
2023-06-05 20:15 ` [PULL 35/52] accel/tcg: Move most of gen-icount.h into translator.c Richard Henderson
2023-06-05 20:15 ` [PULL 36/52] accel/tcg: Introduce translator_io_start Richard Henderson
2023-06-05 20:15 ` [PULL 37/52] target/ppc: Inline gen_icount_io_start() Richard Henderson
2023-06-05 20:15 ` [PULL 38/52] accel/tcg: Move translator_fake_ldb out of line Richard Henderson
2023-06-05 20:15 ` [PULL 39/52] target/arm: Tidy helpers for translation Richard Henderson
2023-06-05 20:15 ` [PULL 40/52] target/mips: " Richard Henderson
2023-06-05 20:15 ` [PULL 41/52] target/*: Add missing includes of exec/translation-block.h Richard Henderson
2023-06-05 20:15 ` [PULL 42/52] target/arm: Add missing include of exec/exec-all.h Richard Henderson
2023-06-05 20:15 ` [PULL 43/52] accel/tcg: Tidy includes for translator.[ch] Richard Henderson
2023-06-05 20:15 ` [PULL 44/52] tcg: Fix PAGE/PROT confusion Richard Henderson
2023-06-05 20:15 ` [PULL 45/52] tcg: Move env defines out of NEED_CPU_H in helper-head.h Richard Henderson
2023-06-05 20:15 ` [PULL 46/52] tcg: Remove target-specific headers from tcg.[ch] Richard Henderson
2023-06-05 20:15 ` [PULL 47/52] plugins: Move plugin_insn_append to translator.c Richard Henderson
2023-06-05 20:15 ` [PULL 48/52] plugins: Drop unused headers from exec/plugin-gen.h Richard Henderson
2023-06-05 20:15 ` [PULL 49/52] exec/poison: Do not poison CONFIG_SOFTMMU Richard Henderson
2023-06-20 18:01 ` Peter Maydell
2023-06-21 5:12 ` Richard Henderson
2023-06-05 20:15 ` [PULL 50/52] tcg: Build once for system and once for user-only Richard Henderson
2023-06-05 20:15 ` [PULL 51/52] accel/tcg: Unmap perf_marker Richard Henderson
2023-06-05 20:15 ` [PULL 52/52] tcg/tcg-op-vec: Remove left over _link_error() definitions Richard Henderson
2023-06-05 21:37 ` [PULL 00/52] tcg patch queue Richard Henderson
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=20230605201548.1596865-7-richard.henderson@linaro.org \
--to=richard.henderson@linaro.org \
--cc=anjo@rev.ng \
--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).