From: Marc Zyngier <marc.zyngier@arm.com>
To: "Paolo Bonzini" <pbonzini@redhat.com>,
"Radim Krčmář" <rkrcmar@redhat.com>,
kvmarm@lists.cs.columbia.edu,
linux-arm-kernel@lists.infradead.org, kvm@vger.kernel.org
Cc: Christoffer Dall <cdall@cs.columbia.edu>,
Shunyong Yang <shunyong.yang@hxt-semitech.com>,
Julien Thierry <julien.thierry@arm.com>,
Andre Przywara <andre.przywara@arm.com>,
Will Deacon <will.deacon@arm.com>,
Shih-Wei Li <shihwei@cs.columbia.edu>,
Catalin Marinas <catalin.marinas@arm.com>,
Dave Martin <Dave.Martin@arm.com>
Subject: [PATCH 84/85] Revert "arm64: KVM: Use SMCCC_ARCH_WORKAROUND_1 for Falkor BP hardening"
Date: Wed, 28 Mar 2018 13:52:53 +0100 [thread overview]
Message-ID: <20180328125254.31380-85-marc.zyngier@arm.com> (raw)
In-Reply-To: <20180328125254.31380-1-marc.zyngier@arm.com>
Creates far too many conflicts with arm64/for-next/core, to be
resent post -rc1.
This reverts commit f9f5dc19509bbef6f5e675346f1a7d7b846bdb12.
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
arch/arm64/include/asm/cpucaps.h | 2 +-
arch/arm64/include/asm/kvm_asm.h | 2 ++
arch/arm64/kernel/bpi.S | 8 ++++++
arch/arm64/kernel/cpu_errata.c | 55 ++++++++++++++++++++++++++--------------
arch/arm64/kvm/hyp/entry.S | 12 +++++++++
arch/arm64/kvm/hyp/switch.c | 10 ++++++++
6 files changed, 69 insertions(+), 20 deletions(-)
diff --git a/arch/arm64/include/asm/cpucaps.h b/arch/arm64/include/asm/cpucaps.h
index c7dfe68fbcc7..d4cc54ed0656 100644
--- a/arch/arm64/include/asm/cpucaps.h
+++ b/arch/arm64/include/asm/cpucaps.h
@@ -43,7 +43,7 @@
#define ARM64_SVE 22
#define ARM64_UNMAP_KERNEL_AT_EL0 23
#define ARM64_HARDEN_BRANCH_PREDICTOR 24
-/* #define ARM64_UNUSED_CAP_TO_BE_REMOVED 25 */
+#define ARM64_HARDEN_BP_POST_GUEST_EXIT 25
#define ARM64_HAS_RAS_EXTN 26
#define ARM64_NCAPS 27
diff --git a/arch/arm64/include/asm/kvm_asm.h b/arch/arm64/include/asm/kvm_asm.h
index f6648a3e4152..d53d40704416 100644
--- a/arch/arm64/include/asm/kvm_asm.h
+++ b/arch/arm64/include/asm/kvm_asm.h
@@ -71,6 +71,8 @@ extern u32 __kvm_get_mdcr_el2(void);
extern u32 __init_stage2_translation(void);
+extern void __qcom_hyp_sanitize_btac_predictors(void);
+
#else /* __ASSEMBLY__ */
.macro get_host_ctxt reg, tmp
diff --git a/arch/arm64/kernel/bpi.S b/arch/arm64/kernel/bpi.S
index 9404f6aecda7..bb0b67722e86 100644
--- a/arch/arm64/kernel/bpi.S
+++ b/arch/arm64/kernel/bpi.S
@@ -74,6 +74,14 @@ ENTRY(__bp_harden_hyp_vecs_end)
.popsection
+ENTRY(__qcom_hyp_sanitize_link_stack_start)
+ stp x29, x30, [sp, #-16]!
+ .rept 16
+ bl . + 4
+ .endr
+ ldp x29, x30, [sp], #16
+ENTRY(__qcom_hyp_sanitize_link_stack_end)
+
.macro smccc_workaround_1 inst
sub sp, sp, #(8 * 4)
stp x2, x3, [sp, #(8 * 0)]
diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c
index caa73af7d26e..aacdc118c4c9 100644
--- a/arch/arm64/kernel/cpu_errata.c
+++ b/arch/arm64/kernel/cpu_errata.c
@@ -69,6 +69,8 @@ atomic_t arm64_el2_vector_last_slot = ATOMIC_INIT(-1);
DEFINE_PER_CPU_READ_MOSTLY(struct bp_hardening_data, bp_hardening_data);
#ifdef CONFIG_KVM
+extern char __qcom_hyp_sanitize_link_stack_start[];
+extern char __qcom_hyp_sanitize_link_stack_end[];
extern char __smccc_workaround_1_smc_start[];
extern char __smccc_workaround_1_smc_end[];
extern char __smccc_workaround_1_hvc_start[];
@@ -112,6 +114,8 @@ static void __install_bp_hardening_cb(bp_hardening_cb_t fn,
spin_unlock(&bp_lock);
}
#else
+#define __qcom_hyp_sanitize_link_stack_start NULL
+#define __qcom_hyp_sanitize_link_stack_end NULL
#define __smccc_workaround_1_smc_start NULL
#define __smccc_workaround_1_smc_end NULL
#define __smccc_workaround_1_hvc_start NULL
@@ -156,25 +160,12 @@ static void call_hvc_arch_workaround_1(void)
arm_smccc_1_1_hvc(ARM_SMCCC_ARCH_WORKAROUND_1, NULL);
}
-static void qcom_link_stack_sanitization(void)
-{
- u64 tmp;
-
- asm volatile("mov %0, x30 \n"
- ".rept 16 \n"
- "bl . + 4 \n"
- ".endr \n"
- "mov x30, %0 \n"
- : "=&r" (tmp));
-}
-
static int enable_smccc_arch_workaround_1(void *data)
{
const struct arm64_cpu_capabilities *entry = data;
bp_hardening_cb_t cb;
void *smccc_start, *smccc_end;
struct arm_smccc_res res;
- u32 midr = read_cpuid_id();
if (!entry->matches(entry, SCOPE_LOCAL_CPU))
return 0;
@@ -207,15 +198,33 @@ static int enable_smccc_arch_workaround_1(void *data)
return 0;
}
- if (((midr & MIDR_CPU_MODEL_MASK) == MIDR_QCOM_FALKOR) ||
- ((midr & MIDR_CPU_MODEL_MASK) == MIDR_QCOM_FALKOR_V1))
- cb = qcom_link_stack_sanitization;
-
install_bp_hardening_cb(entry, cb, smccc_start, smccc_end);
return 0;
}
+static void qcom_link_stack_sanitization(void)
+{
+ u64 tmp;
+
+ asm volatile("mov %0, x30 \n"
+ ".rept 16 \n"
+ "bl . + 4 \n"
+ ".endr \n"
+ "mov x30, %0 \n"
+ : "=&r" (tmp));
+}
+
+static int qcom_enable_link_stack_sanitization(void *data)
+{
+ const struct arm64_cpu_capabilities *entry = data;
+
+ install_bp_hardening_cb(entry, qcom_link_stack_sanitization,
+ __qcom_hyp_sanitize_link_stack_start,
+ __qcom_hyp_sanitize_link_stack_end);
+
+ return 0;
+}
#endif /* CONFIG_HARDEN_BRANCH_PREDICTOR */
#define MIDR_RANGE(model, min, max) \
@@ -390,12 +399,20 @@ const struct arm64_cpu_capabilities arm64_errata[] = {
{
.capability = ARM64_HARDEN_BRANCH_PREDICTOR,
MIDR_ALL_VERSIONS(MIDR_QCOM_FALKOR_V1),
- .enable = enable_smccc_arch_workaround_1,
+ .enable = qcom_enable_link_stack_sanitization,
+ },
+ {
+ .capability = ARM64_HARDEN_BP_POST_GUEST_EXIT,
+ MIDR_ALL_VERSIONS(MIDR_QCOM_FALKOR_V1),
},
{
.capability = ARM64_HARDEN_BRANCH_PREDICTOR,
MIDR_ALL_VERSIONS(MIDR_QCOM_FALKOR),
- .enable = enable_smccc_arch_workaround_1,
+ .enable = qcom_enable_link_stack_sanitization,
+ },
+ {
+ .capability = ARM64_HARDEN_BP_POST_GUEST_EXIT,
+ MIDR_ALL_VERSIONS(MIDR_QCOM_FALKOR),
},
{
.capability = ARM64_HARDEN_BRANCH_PREDICTOR,
diff --git a/arch/arm64/kvm/hyp/entry.S b/arch/arm64/kvm/hyp/entry.S
index e41a161d313a..1f458f7c3b44 100644
--- a/arch/arm64/kvm/hyp/entry.S
+++ b/arch/arm64/kvm/hyp/entry.S
@@ -209,3 +209,15 @@ alternative_endif
eret
ENDPROC(__fpsimd_guest_restore)
+
+ENTRY(__qcom_hyp_sanitize_btac_predictors)
+ /**
+ * Call SMC64 with Silicon provider serviceID 23<<8 (0xc2001700)
+ * 0xC2000000-0xC200FFFF: assigned to SiP Service Calls
+ * b15-b0: contains SiP functionID
+ */
+ movz x0, #0x1700
+ movk x0, #0xc200, lsl #16
+ smc #0
+ ret
+ENDPROC(__qcom_hyp_sanitize_btac_predictors)
diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
index d9645236e474..07b572173265 100644
--- a/arch/arm64/kvm/hyp/switch.c
+++ b/arch/arm64/kvm/hyp/switch.c
@@ -472,6 +472,16 @@ int __hyp_text __kvm_vcpu_run_nvhe(struct kvm_vcpu *vcpu)
/* And we're baaack! */
} while (fixup_guest_exit(vcpu, &exit_code));
+ if (cpus_have_const_cap(ARM64_HARDEN_BP_POST_GUEST_EXIT)) {
+ u32 midr = read_cpuid_id();
+
+ /* Apply BTAC predictors mitigation to all Falkor chips */
+ if (((midr & MIDR_CPU_MODEL_MASK) == MIDR_QCOM_FALKOR) ||
+ ((midr & MIDR_CPU_MODEL_MASK) == MIDR_QCOM_FALKOR_V1)) {
+ __qcom_hyp_sanitize_btac_predictors();
+ }
+ }
+
fp_enabled = __fpsimd_enabled_nvhe();
__sysreg_save_state_nvhe(guest_ctxt);
--
2.14.2
next prev parent reply other threads:[~2018-03-28 12:52 UTC|newest]
Thread overview: 87+ messages / expand[flat|nested] mbox.gz Atom feed top
2018-03-28 12:51 [GIT PULL] KVM/ARM updates for v4.17 Marc Zyngier
2018-03-28 12:51 ` [PATCH 01/85] KVM: arm/arm64: Fix arch timers with userspace irqchips Marc Zyngier
2018-03-28 12:51 ` [PATCH 02/85] ARM: kvm: fix building with gcc-8 Marc Zyngier
2018-03-28 12:51 ` [PATCH 03/85] arm64/kvm: Prohibit guest LOR accesses Marc Zyngier
2018-03-28 12:51 ` [PATCH 04/85] arm64: KVM: Move CPU ID reg trap setup off the world switch path Marc Zyngier
2018-03-28 12:51 ` [PATCH 05/85] KVM: arm64: Enable the EL1 physical timer for AArch32 guests Marc Zyngier
2018-03-28 12:51 ` [PATCH 06/85] KVM: arm: Enable emulation of the physical timer Marc Zyngier
2018-03-28 12:51 ` [PATCH 07/85] KVM: arm/arm64: No need to zero CNTVOFF in kvm_timer_vcpu_put() for VHE Marc Zyngier
2018-03-28 12:51 ` [PATCH 08/85] KVM: arm/arm64: vgic: Add missing irq_lock to vgic_mmio_read_pending Marc Zyngier
2018-03-28 12:51 ` [PATCH 09/85] KVM: arm/arm64: Avoid vcpu_load for other vcpu ioctls than KVM_RUN Marc Zyngier
2018-03-28 12:51 ` [PATCH 10/85] KVM: arm/arm64: Reset mapped IRQs on VM reset Marc Zyngier
2018-03-28 12:51 ` [PATCH 11/85] KVM: arm/arm64: Reduce verbosity of KVM init log Marc Zyngier
2018-03-28 12:51 ` [PATCH 12/85] KVM: arm/arm64: vgic: Don't populate multiple LRs with the same vintid Marc Zyngier
2018-03-28 12:51 ` [PATCH 13/85] kvm: arm/arm64: vgic-v3: Tighten synchronization for guests using v2 on v3 Marc Zyngier
2018-03-28 12:51 ` [PATCH 14/85] KVM: arm/arm64: Avoid vcpu_load for other vcpu ioctls than KVM_RUN Marc Zyngier
2018-03-28 12:51 ` [PATCH 15/85] KVM: arm/arm64: Move vcpu_load call after kvm_vcpu_first_run_init Marc Zyngier
2018-03-28 12:51 ` [PATCH 16/85] KVM: arm64: Avoid storing the vcpu pointer on the stack Marc Zyngier
2018-03-28 12:51 ` [PATCH 17/85] KVM: arm64: Rework hyp_panic for VHE and non-VHE Marc Zyngier
2018-03-28 12:51 ` [PATCH 18/85] KVM: arm64: Move HCR_INT_OVERRIDE to default HCR_EL2 guest flag Marc Zyngier
2018-03-28 12:51 ` [PATCH 19/85] KVM: arm/arm64: Get rid of vcpu->arch.irq_lines Marc Zyngier
2018-03-28 12:51 ` [PATCH 20/85] KVM: arm/arm64: Add kvm_vcpu_load_sysregs and kvm_vcpu_put_sysregs Marc Zyngier
2018-03-28 12:51 ` [PATCH 21/85] KVM: arm/arm64: Introduce vcpu_el1_is_32bit Marc Zyngier
2018-03-28 12:51 ` [PATCH 22/85] KVM: arm64: Move debug dirty flag calculation out of world switch Marc Zyngier
2018-03-28 12:51 ` [PATCH 23/85] KVM: arm64: Slightly improve debug save/restore functions Marc Zyngier
2018-03-28 12:51 ` [PATCH 24/85] KVM: arm64: Improve debug register save/restore flow Marc Zyngier
2018-03-28 12:51 ` [PATCH 25/85] KVM: arm64: Factor out fault info population and gic workarounds Marc Zyngier
2018-03-28 12:51 ` [PATCH 26/85] KVM: arm64: Introduce VHE-specific kvm_vcpu_run Marc Zyngier
2018-03-28 12:51 ` [PATCH 27/85] KVM: arm64: Remove kern_hyp_va() use in VHE switch function Marc Zyngier
2018-03-28 12:51 ` [PATCH 28/85] KVM: arm64: Don't deactivate VM on VHE systems Marc Zyngier
2018-03-28 12:51 ` [PATCH 29/85] KVM: arm64: Remove noop calls to timer save/restore from VHE switch Marc Zyngier
2018-03-28 12:51 ` [PATCH 30/85] KVM: arm64: Move userspace system registers into separate function Marc Zyngier
2018-03-28 12:52 ` [PATCH 31/85] KVM: arm64: Rewrite sysreg alternatives to static keys Marc Zyngier
2018-03-28 12:52 ` [PATCH 32/85] KVM: arm64: Introduce separate VHE/non-VHE sysreg save/restore functions Marc Zyngier
2018-03-28 12:52 ` [PATCH 33/85] KVM: arm/arm64: Remove leftover comment from kvm_vcpu_run_vhe Marc Zyngier
2018-03-28 12:52 ` [PATCH 34/85] KVM: arm64: Unify non-VHE host/guest sysreg save and restore functions Marc Zyngier
2018-03-28 12:52 ` [PATCH 35/85] KVM: arm64: Don't save the host ELR_EL2 and SPSR_EL2 on VHE systems Marc Zyngier
2018-03-28 12:52 ` [PATCH 36/85] KVM: arm64: Change 32-bit handling of VM system registers Marc Zyngier
2018-03-28 12:52 ` [PATCH 37/85] KVM: arm64: Rewrite system register accessors to read/write functions Marc Zyngier
2018-03-28 12:52 ` [PATCH 38/85] KVM: arm64: Introduce framework for accessing deferred sysregs Marc Zyngier
2018-03-28 12:52 ` [PATCH 39/85] KVM: arm/arm64: Prepare to handle deferred save/restore of SPSR_EL1 Marc Zyngier
2018-03-28 12:52 ` [PATCH 40/85] KVM: arm64: Prepare to handle deferred save/restore of ELR_EL1 Marc Zyngier
2018-03-28 12:52 ` [PATCH 41/85] KVM: arm64: Defer saving/restoring 64-bit sysregs to vcpu load/put on VHE Marc Zyngier
2018-03-28 12:52 ` [PATCH 42/85] KVM: arm64: Prepare to handle deferred save/restore of 32-bit registers Marc Zyngier
2018-03-28 12:52 ` [PATCH 43/85] KVM: arm64: Defer saving/restoring 32-bit sysregs to vcpu load/put Marc Zyngier
2018-03-28 12:52 ` [PATCH 44/85] KVM: arm64: Move common VHE/non-VHE trap config in separate functions Marc Zyngier
2018-03-28 12:52 ` [PATCH 45/85] KVM: arm64: Directly call VHE and non-VHE FPSIMD enabled functions Marc Zyngier
2018-03-28 12:52 ` [PATCH 46/85] KVM: arm64: Configure c15, PMU, and debug register traps on cpu load/put for VHE Marc Zyngier
2018-03-28 12:52 ` [PATCH 47/85] KVM: arm64: Cleanup __activate_traps and __deactive_traps for VHE and non-VHE Marc Zyngier
2018-03-28 12:52 ` [PATCH 48/85] KVM: arm/arm64: Get rid of vgic_elrsr Marc Zyngier
2018-03-28 12:52 ` [PATCH 49/85] KVM: arm/arm64: Handle VGICv2 save/restore from the main VGIC code Marc Zyngier
2018-03-28 12:52 ` [PATCH 50/85] KVM: arm/arm64: Move arm64-only vgic-v2-sr.c file to arm64 Marc Zyngier
2018-03-28 12:52 ` [PATCH 51/85] KVM: arm/arm64: Handle VGICv3 save/restore from the main VGIC code on VHE Marc Zyngier
2018-03-28 12:52 ` [PATCH 52/85] KVM: arm/arm64: Move VGIC APR save/restore to vgic put/load Marc Zyngier
2018-03-28 12:52 ` [PATCH 53/85] KVM: arm/arm64: Avoid VGICv3 save/restore on VHE with no IRQs Marc Zyngier
2018-03-28 12:52 ` [PATCH 54/85] arm64: alternatives: Add dynamic patching feature Marc Zyngier
2018-03-28 12:52 ` [PATCH 55/85] arm64: insn: Add N immediate encoding Marc Zyngier
2018-03-28 12:52 ` [PATCH 56/85] arm64: insn: Add encoder for bitwise operations using literals Marc Zyngier
2018-03-28 12:52 ` [PATCH 57/85] arm64: KVM: Dynamically patch the kernel/hyp VA mask Marc Zyngier
2018-03-28 12:52 ` [PATCH 58/85] arm64: cpufeatures: Drop the ARM64_HYP_OFFSET_LOW feature flag Marc Zyngier
2018-03-28 12:52 ` [PATCH 59/85] KVM: arm/arm64: Do not use kern_hyp_va() with kvm_vgic_global_state Marc Zyngier
2018-03-28 12:52 ` [PATCH 60/85] KVM: arm/arm64: Demote HYP VA range display to being a debug feature Marc Zyngier
2018-03-28 12:52 ` [PATCH 61/85] KVM: arm/arm64: Move ioremap calls to create_hyp_io_mappings Marc Zyngier
2018-03-28 12:52 ` [PATCH 62/85] KVM: arm/arm64: Keep GICv2 HYP VAs in kvm_vgic_global_state Marc Zyngier
2018-03-28 12:52 ` [PATCH 63/85] KVM: arm/arm64: Fix idmap size and alignment Marc Zyngier
2018-03-28 12:52 ` [PATCH 64/85] KVM: arm64: Fix HYP idmap unmap when using 52bit PA Marc Zyngier
2018-03-28 12:52 ` [PATCH 65/85] KVM: arm/arm64: Move HYP IO VAs to the "idmap" range Marc Zyngier
2018-03-28 12:52 ` [PATCH 66/85] arm64; insn: Add encoder for the EXTR instruction Marc Zyngier
2018-03-28 12:52 ` [PATCH 67/85] arm64: insn: Allow ADD/SUB (immediate) with LSL #12 Marc Zyngier
2018-03-28 12:52 ` [PATCH 68/85] arm64: KVM: Dynamically compute the HYP VA mask Marc Zyngier
2018-03-28 12:52 ` [PATCH 69/85] arm64: KVM: Introduce EL2 VA randomisation Marc Zyngier
2018-03-28 12:52 ` [PATCH 70/85] arm64: Update the KVM memory map documentation Marc Zyngier
2018-03-28 12:52 ` [PATCH 71/85] arm64: KVM: Move vector offsetting from hyp-init.S to kvm_get_hyp_vector Marc Zyngier
2018-03-28 12:52 ` [PATCH 72/85] arm64: KVM: Move stashing of x0/x1 into the vector code itself Marc Zyngier
2018-03-28 12:52 ` [PATCH 73/85] arm64: KVM: Move BP hardening vectors into .hyp.text section Marc Zyngier
2018-03-28 12:52 ` [PATCH 74/85] arm64: KVM: Reserve 4 additional instructions in the BPI template Marc Zyngier
2018-03-28 12:52 ` [PATCH 75/85] arm64: KVM: Allow far branches from vector slots to the main vectors Marc Zyngier
2018-03-28 12:52 ` [PATCH 76/85] arm/arm64: KVM: Introduce EL2-specific executable mappings Marc Zyngier
2018-03-28 12:52 ` [PATCH 77/85] arm64: Make BP hardening slot counter available Marc Zyngier
2018-03-28 12:52 ` [PATCH 78/85] arm64: KVM: Allow mapping of vectors outside of the RAM region Marc Zyngier
2018-03-28 12:52 ` [PATCH 79/85] arm64: Enable ARM64_HARDEN_EL2_VECTORS on Cortex-A57 and A72 Marc Zyngier
2018-03-28 12:52 ` [PATCH 80/85] KVM: arm: Reserve bit in KVM_REG_ARM encoding for secure/nonsecure Marc Zyngier
2018-03-28 12:52 ` [PATCH 81/85] arm64: KVM: Use SMCCC_ARCH_WORKAROUND_1 for Falkor BP hardening Marc Zyngier
2018-03-28 12:52 ` [PATCH 82/85] KVM: arm/arm64: vgic: Disallow Active+Pending for level interrupts Marc Zyngier
2018-03-28 12:52 ` [PATCH 83/85] KVM: arm/arm64: vgic-its: Fix potential overrun in vgic_copy_lpi_list Marc Zyngier
2018-03-28 12:52 ` Marc Zyngier [this message]
2018-03-28 12:52 ` [PATCH 85/85] arm64: Add temporary ERRATA_MIDR_ALL_VERSIONS compatibility macro Marc Zyngier
2018-03-28 20:00 ` [GIT PULL] KVM/ARM updates for v4.17 Radim Krčmář
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=20180328125254.31380-85-marc.zyngier@arm.com \
--to=marc.zyngier@arm.com \
--cc=Dave.Martin@arm.com \
--cc=andre.przywara@arm.com \
--cc=catalin.marinas@arm.com \
--cc=cdall@cs.columbia.edu \
--cc=julien.thierry@arm.com \
--cc=kvm@vger.kernel.org \
--cc=kvmarm@lists.cs.columbia.edu \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=pbonzini@redhat.com \
--cc=rkrcmar@redhat.com \
--cc=shihwei@cs.columbia.edu \
--cc=shunyong.yang@hxt-semitech.com \
--cc=will.deacon@arm.com \
/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