From: Mark Rutland <mark.rutland@arm.com>
To: Geoff Levand <geoff@infradead.org>
Cc: Marc Zyngier <Marc.Zyngier@arm.com>,
Catalin Marinas <Catalin.Marinas@arm.com>,
Will Deacon <Will.Deacon@arm.com>,
"linux-arm-kernel@lists.infradead.org"
<linux-arm-kernel@lists.infradead.org>,
"kexec@lists.infradead.org" <kexec@lists.infradead.org>,
"christoffer.dall@linaro.org" <christoffer.dall@linaro.org>
Subject: Re: [PATCH 03/13] arm64: Convert hcalls to use ISS field
Date: Mon, 15 Sep 2014 18:57:08 +0100 [thread overview]
Message-ID: <20140915175708.GD13789@leverpostej> (raw)
In-Reply-To: <2d8dd1ea41dc51878dd4ce75de00eaec2518a76b.1410302383.git.geoff@infradead.org>
Hi Geoff,
The general approach looks good to me, using the HVC immediate makes
this look far nicer to me. Hopefully Marc and Christoffer agree on that.
That said, I have some comments on the mechanics below.
On Tue, Sep 09, 2014 at 11:49:04PM +0100, Geoff Levand wrote:
> To allow for additional hcalls to be defined and to make the arm64 hcall API
> more consistent across exception vector routines change the hcall implementations
> to use the ISS field of the ESR_EL2 register to specify the hcall type.
>
> The existing arm64 hcall implementations are limited in that they only allow
> for two distinct hcalls; with the x0 register either zero, or not zero. Also,
> the API of the hyp-stub exception vector routines and the KVM exception vector
> routines differ; hyp-stub uses a non-zero value in x0 to implement
> __hyp_set_vectors, whereas KVM uses it to implement kvm_call_hyp.
>
> Define three new preprocessor macros HVC_GET_VECTORS, HVC_SET_VECTORS and
> HVC_KVM_CALL_HYP and to be used as hcall type specifiers and convert the
> existing __hyp_get_vectors(), __hyp_set_vectors() and kvm_call_hyp() routines
> to use these new macros when executing and HVC call. Also change the
> corresponding hyp-stub and KVM el1_sync exception vector routines to use these
> new macros.
>
> Signed-off-by: Geoff Levand <geoff@infradead.org>
> ---
> arch/arm64/include/asm/virt.h | 20 ++++++++++++++++++++
> arch/arm64/kernel/hyp-stub.S | 38 ++++++++++++++++++++++++++------------
> arch/arm64/kvm/hyp.S | 19 ++++++++++++-------
> 3 files changed, 58 insertions(+), 19 deletions(-)
>
> diff --git a/arch/arm64/include/asm/virt.h b/arch/arm64/include/asm/virt.h
> index 7a5df52..894fe53 100644
> --- a/arch/arm64/include/asm/virt.h
> +++ b/arch/arm64/include/asm/virt.h
> @@ -21,6 +21,26 @@
> #define BOOT_CPU_MODE_EL1 (0xe11)
> #define BOOT_CPU_MODE_EL2 (0xe12)
>
> +/*
> + * HVC_GET_VECTORS - Return the value of the vbar_el2 register.
> + */
> +
> +#define HVC_GET_VECTORS 1
> +
> +/*
> + * HVC_SET_VECTORS - Set the value of the vbar_el2 register.
> + *
> + * @x0: Physical address of the new vector table.
> + */
> +
> +#define HVC_SET_VECTORS 2
> +
> +/*
> + * HVC_KVM_CALL_HYP - Execute kvm_call_hyp routine.
> + */
> +
> +#define HVC_KVM_CALL_HYP 3
If this can be used without KVM (e.g. in the hyp stub) I'd just call
this HVC_CALL_HYP, or the name will be a little misleading.
> +
> #ifndef __ASSEMBLY__
>
> /*
> diff --git a/arch/arm64/kernel/hyp-stub.S b/arch/arm64/kernel/hyp-stub.S
> index 2d960a9..9ab5f70 100644
> --- a/arch/arm64/kernel/hyp-stub.S
> +++ b/arch/arm64/kernel/hyp-stub.S
> @@ -54,16 +54,29 @@ ENDPROC(__hyp_stub_vectors)
>
> #define ESR_EL2_EC_SHIFT 26
> #define ESR_EL2_EC_HVC64 0x16
> +#define ESR_EL2_ISS 0xffff
The last patch tried to add an identical macro to a header file. Can we
use that header please?
>
> el1_sync:
> - mrs x1, esr_el2
> - lsr x1, x1, #ESR_EL2_EC_SHIFT
> - cmp x1, #ESR_EL2_EC_HVC64
> - b.ne 2f // Not an HVC trap
> - cbz x0, 1f
> - msr vbar_el2, x0 // Set vbar_el2
> + mrs x10, esr_el2
Any reason for using x10?
If we want to preserve the lowest register numbers, start with the
highest caller-saved register numbers (i.e. x18). At least for me it
makes the code far easier to read; it doesn't make it look like x10 is
special.
> + lsr x9, x10, #ESR_EL2_EC_SHIFT // x9=EC
> + and x10, x10, #ESR_EL2_ISS // x10=ISS
The mnemonics make these comments redundant.
> + cmp x9, #ESR_EL2_EC_HVC64
> + b.ne 2f // Not a host HVC trap
Now that we have the nice mnemonic, we could get rid of the comment
here. I'd drop the 'host' from the comment; it wasn't there orginally
and it's somewhat meaningless for the stub (KVM isn't up yet, and the
only the native OS can make a HVC).
> + mrs x9, vttbr_el2
> + cbnz x9, 2f // Not a host HVC trap
I don't understand this. When is vttbr_el2 non-zero, and why do we want
to silently return from a HVC in that case? That didn't seem to be the
case in the original code.
> +
> + cmp x10, #HVC_GET_VECTORS
> + b.ne 1f
> + mrs x0, vbar_el2
> b 2f
> -1: mrs x0, vbar_el2 // Return vbar_el2
> +
> +1: cmp x10, #HVC_SET_VECTORS
> + b.ne 1f
> + msr vbar_el2, x0
> +
> +1:
It feels like we should explode if we ever reach here from the host --
if we've made an unsupported HVC wereally want to know that we've done
so.
> 2: eret
> ENDPROC(el1_sync)
>
> @@ -103,11 +116,12 @@ ENDPROC(\label)
> * initialisation entry point.
> */
>
> -ENTRY(__hyp_get_vectors)
> - mov x0, xzr
> - // fall through
> ENTRY(__hyp_set_vectors)
> - hvc #0
> + hvc #HVC_SET_VECTORS
> ret
> -ENDPROC(__hyp_get_vectors)
> ENDPROC(__hyp_set_vectors)
> +
> +ENTRY(__hyp_get_vectors)
> + hvc #HVC_GET_VECTORS
> + ret
> +ENDPROC(__hyp_get_vectors)
> diff --git a/arch/arm64/kvm/hyp.S b/arch/arm64/kvm/hyp.S
> index b72aa9f..3972ee9 100644
> --- a/arch/arm64/kvm/hyp.S
> +++ b/arch/arm64/kvm/hyp.S
> @@ -26,6 +26,7 @@
> #include <asm/kvm_asm.h>
> #include <asm/kvm_arm.h>
> #include <asm/kvm_mmu.h>
> +#include <asm/virt.h>
>
> #define CPU_GP_REG_OFFSET(x) (CPU_GP_REGS + x)
> #define CPU_XREG_OFFSET(x) CPU_GP_REG_OFFSET(CPU_USER_PT_REGS + 8*x)
> @@ -1105,12 +1106,9 @@ __hyp_panic_str:
> * in Hyp mode (see init_hyp_mode in arch/arm/kvm/arm.c). Return values are
> * passed in r0 and r1.
> *
> - * A function pointer with a value of 0 has a special meaning, and is
> - * used to implement __hyp_get_vectors in the same way as in
> - * arch/arm64/kernel/hyp_stub.S.
> */
> ENTRY(kvm_call_hyp)
> - hvc #0
> + hvc #HVC_KVM_CALL_HYP
> ret
> ENDPROC(kvm_call_hyp)
>
> @@ -1140,6 +1138,7 @@ el1_sync: // Guest trapped into EL2
> push x2, x3
>
> mrs x1, esr_el2
> + and x0, x1, #ESR_EL2_ISS
> lsr x2, x1, #ESR_EL2_EC_SHIFT
>
> cmp x2, #ESR_EL2_EC_HVC64
> @@ -1149,15 +1148,19 @@ el1_sync: // Guest trapped into EL2
> cbnz x3, el1_trap // called HVC
>
> /* Here, we're pretty sure the host called HVC. */
> + mov x10, x0
As above, please use the highest numbered caller-saved register so as to
not make the register numbering look special.
> pop x2, x3
> pop x0, x1
>
> - /* Check for __hyp_get_vectors */
> - cbnz x0, 1f
> + cmp x10, #HVC_GET_VECTORS
> + b.ne 1f
> mrs x0, vbar_el2
> b 2f
>
> -1: push lr, xzr
> +1: cmp x10, #HVC_KVM_CALL_HYP
> + b.ne 1f
> +
> + push lr, xzr
>
> /*
> * Compute the function address in EL2, and shuffle the parameters.
> @@ -1170,6 +1173,8 @@ el1_sync: // Guest trapped into EL2
> blr lr
>
> pop lr, xzr
> +
> +1:
> 2: eret
Any reason we need two labels here?
If we've got here with an invalid HVC immediate, I think we should
explode loudly.
Mark.
_______________________________________________
kexec mailing list
kexec@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kexec
WARNING: multiple messages have this Message-ID (diff)
From: mark.rutland@arm.com (Mark Rutland)
To: linux-arm-kernel@lists.infradead.org
Subject: [PATCH 03/13] arm64: Convert hcalls to use ISS field
Date: Mon, 15 Sep 2014 18:57:08 +0100 [thread overview]
Message-ID: <20140915175708.GD13789@leverpostej> (raw)
In-Reply-To: <2d8dd1ea41dc51878dd4ce75de00eaec2518a76b.1410302383.git.geoff@infradead.org>
Hi Geoff,
The general approach looks good to me, using the HVC immediate makes
this look far nicer to me. Hopefully Marc and Christoffer agree on that.
That said, I have some comments on the mechanics below.
On Tue, Sep 09, 2014 at 11:49:04PM +0100, Geoff Levand wrote:
> To allow for additional hcalls to be defined and to make the arm64 hcall API
> more consistent across exception vector routines change the hcall implementations
> to use the ISS field of the ESR_EL2 register to specify the hcall type.
>
> The existing arm64 hcall implementations are limited in that they only allow
> for two distinct hcalls; with the x0 register either zero, or not zero. Also,
> the API of the hyp-stub exception vector routines and the KVM exception vector
> routines differ; hyp-stub uses a non-zero value in x0 to implement
> __hyp_set_vectors, whereas KVM uses it to implement kvm_call_hyp.
>
> Define three new preprocessor macros HVC_GET_VECTORS, HVC_SET_VECTORS and
> HVC_KVM_CALL_HYP and to be used as hcall type specifiers and convert the
> existing __hyp_get_vectors(), __hyp_set_vectors() and kvm_call_hyp() routines
> to use these new macros when executing and HVC call. Also change the
> corresponding hyp-stub and KVM el1_sync exception vector routines to use these
> new macros.
>
> Signed-off-by: Geoff Levand <geoff@infradead.org>
> ---
> arch/arm64/include/asm/virt.h | 20 ++++++++++++++++++++
> arch/arm64/kernel/hyp-stub.S | 38 ++++++++++++++++++++++++++------------
> arch/arm64/kvm/hyp.S | 19 ++++++++++++-------
> 3 files changed, 58 insertions(+), 19 deletions(-)
>
> diff --git a/arch/arm64/include/asm/virt.h b/arch/arm64/include/asm/virt.h
> index 7a5df52..894fe53 100644
> --- a/arch/arm64/include/asm/virt.h
> +++ b/arch/arm64/include/asm/virt.h
> @@ -21,6 +21,26 @@
> #define BOOT_CPU_MODE_EL1 (0xe11)
> #define BOOT_CPU_MODE_EL2 (0xe12)
>
> +/*
> + * HVC_GET_VECTORS - Return the value of the vbar_el2 register.
> + */
> +
> +#define HVC_GET_VECTORS 1
> +
> +/*
> + * HVC_SET_VECTORS - Set the value of the vbar_el2 register.
> + *
> + * @x0: Physical address of the new vector table.
> + */
> +
> +#define HVC_SET_VECTORS 2
> +
> +/*
> + * HVC_KVM_CALL_HYP - Execute kvm_call_hyp routine.
> + */
> +
> +#define HVC_KVM_CALL_HYP 3
If this can be used without KVM (e.g. in the hyp stub) I'd just call
this HVC_CALL_HYP, or the name will be a little misleading.
> +
> #ifndef __ASSEMBLY__
>
> /*
> diff --git a/arch/arm64/kernel/hyp-stub.S b/arch/arm64/kernel/hyp-stub.S
> index 2d960a9..9ab5f70 100644
> --- a/arch/arm64/kernel/hyp-stub.S
> +++ b/arch/arm64/kernel/hyp-stub.S
> @@ -54,16 +54,29 @@ ENDPROC(__hyp_stub_vectors)
>
> #define ESR_EL2_EC_SHIFT 26
> #define ESR_EL2_EC_HVC64 0x16
> +#define ESR_EL2_ISS 0xffff
The last patch tried to add an identical macro to a header file. Can we
use that header please?
>
> el1_sync:
> - mrs x1, esr_el2
> - lsr x1, x1, #ESR_EL2_EC_SHIFT
> - cmp x1, #ESR_EL2_EC_HVC64
> - b.ne 2f // Not an HVC trap
> - cbz x0, 1f
> - msr vbar_el2, x0 // Set vbar_el2
> + mrs x10, esr_el2
Any reason for using x10?
If we want to preserve the lowest register numbers, start with the
highest caller-saved register numbers (i.e. x18). At least for me it
makes the code far easier to read; it doesn't make it look like x10 is
special.
> + lsr x9, x10, #ESR_EL2_EC_SHIFT // x9=EC
> + and x10, x10, #ESR_EL2_ISS // x10=ISS
The mnemonics make these comments redundant.
> + cmp x9, #ESR_EL2_EC_HVC64
> + b.ne 2f // Not a host HVC trap
Now that we have the nice mnemonic, we could get rid of the comment
here. I'd drop the 'host' from the comment; it wasn't there orginally
and it's somewhat meaningless for the stub (KVM isn't up yet, and the
only the native OS can make a HVC).
> + mrs x9, vttbr_el2
> + cbnz x9, 2f // Not a host HVC trap
I don't understand this. When is vttbr_el2 non-zero, and why do we want
to silently return from a HVC in that case? That didn't seem to be the
case in the original code.
> +
> + cmp x10, #HVC_GET_VECTORS
> + b.ne 1f
> + mrs x0, vbar_el2
> b 2f
> -1: mrs x0, vbar_el2 // Return vbar_el2
> +
> +1: cmp x10, #HVC_SET_VECTORS
> + b.ne 1f
> + msr vbar_el2, x0
> +
> +1:
It feels like we should explode if we ever reach here from the host --
if we've made an unsupported HVC wereally want to know that we've done
so.
> 2: eret
> ENDPROC(el1_sync)
>
> @@ -103,11 +116,12 @@ ENDPROC(\label)
> * initialisation entry point.
> */
>
> -ENTRY(__hyp_get_vectors)
> - mov x0, xzr
> - // fall through
> ENTRY(__hyp_set_vectors)
> - hvc #0
> + hvc #HVC_SET_VECTORS
> ret
> -ENDPROC(__hyp_get_vectors)
> ENDPROC(__hyp_set_vectors)
> +
> +ENTRY(__hyp_get_vectors)
> + hvc #HVC_GET_VECTORS
> + ret
> +ENDPROC(__hyp_get_vectors)
> diff --git a/arch/arm64/kvm/hyp.S b/arch/arm64/kvm/hyp.S
> index b72aa9f..3972ee9 100644
> --- a/arch/arm64/kvm/hyp.S
> +++ b/arch/arm64/kvm/hyp.S
> @@ -26,6 +26,7 @@
> #include <asm/kvm_asm.h>
> #include <asm/kvm_arm.h>
> #include <asm/kvm_mmu.h>
> +#include <asm/virt.h>
>
> #define CPU_GP_REG_OFFSET(x) (CPU_GP_REGS + x)
> #define CPU_XREG_OFFSET(x) CPU_GP_REG_OFFSET(CPU_USER_PT_REGS + 8*x)
> @@ -1105,12 +1106,9 @@ __hyp_panic_str:
> * in Hyp mode (see init_hyp_mode in arch/arm/kvm/arm.c). Return values are
> * passed in r0 and r1.
> *
> - * A function pointer with a value of 0 has a special meaning, and is
> - * used to implement __hyp_get_vectors in the same way as in
> - * arch/arm64/kernel/hyp_stub.S.
> */
> ENTRY(kvm_call_hyp)
> - hvc #0
> + hvc #HVC_KVM_CALL_HYP
> ret
> ENDPROC(kvm_call_hyp)
>
> @@ -1140,6 +1138,7 @@ el1_sync: // Guest trapped into EL2
> push x2, x3
>
> mrs x1, esr_el2
> + and x0, x1, #ESR_EL2_ISS
> lsr x2, x1, #ESR_EL2_EC_SHIFT
>
> cmp x2, #ESR_EL2_EC_HVC64
> @@ -1149,15 +1148,19 @@ el1_sync: // Guest trapped into EL2
> cbnz x3, el1_trap // called HVC
>
> /* Here, we're pretty sure the host called HVC. */
> + mov x10, x0
As above, please use the highest numbered caller-saved register so as to
not make the register numbering look special.
> pop x2, x3
> pop x0, x1
>
> - /* Check for __hyp_get_vectors */
> - cbnz x0, 1f
> + cmp x10, #HVC_GET_VECTORS
> + b.ne 1f
> mrs x0, vbar_el2
> b 2f
>
> -1: push lr, xzr
> +1: cmp x10, #HVC_KVM_CALL_HYP
> + b.ne 1f
> +
> + push lr, xzr
>
> /*
> * Compute the function address in EL2, and shuffle the parameters.
> @@ -1170,6 +1173,8 @@ el1_sync: // Guest trapped into EL2
> blr lr
>
> pop lr, xzr
> +
> +1:
> 2: eret
Any reason we need two labels here?
If we've got here with an invalid HVC immediate, I think we should
explode loudly.
Mark.
next prev parent reply other threads:[~2014-09-15 17:57 UTC|newest]
Thread overview: 80+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-09-09 22:51 [PATCH 00/13] arm64 kexec kernel patches V2 Geoff Levand
2014-09-09 22:51 ` Geoff Levand
2014-09-09 22:49 ` [PATCH 06/13] arm64: Add new routine read_cpu_properties Geoff Levand
2014-09-09 22:49 ` Geoff Levand
2014-09-15 18:42 ` Mark Rutland
2014-09-15 18:42 ` Mark Rutland
2014-09-25 0:23 ` Geoff Levand
2014-09-25 0:23 ` Geoff Levand
2014-09-09 22:49 ` [PATCH 01/13] arm64: Add ESR_EL2_EC macros to hyp-stub Geoff Levand
2014-09-09 22:49 ` Geoff Levand
2014-09-15 16:10 ` Mark Rutland
2014-09-15 16:10 ` Mark Rutland
2014-09-22 21:45 ` Geoff Levand
2014-09-22 21:45 ` Geoff Levand
2014-09-09 22:49 ` [PATCH 03/13] arm64: Convert hcalls to use ISS field Geoff Levand
2014-09-09 22:49 ` Geoff Levand
2014-09-11 16:14 ` Arun Chandran
2014-09-11 16:14 ` Arun Chandran
2014-09-15 17:57 ` Mark Rutland [this message]
2014-09-15 17:57 ` Mark Rutland
2014-09-22 21:46 ` Geoff Levand
2014-09-22 21:46 ` Geoff Levand
2014-09-09 22:49 ` [PATCH 07/13] arm64: Add new routine local_disable Geoff Levand
2014-09-09 22:49 ` Geoff Levand
2014-09-15 18:56 ` Mark Rutland
2014-09-15 18:56 ` Mark Rutland
2014-09-25 0:24 ` Geoff Levand
2014-09-25 0:24 ` Geoff Levand
2014-09-09 22:49 ` [PATCH 05/13] arm64: Add EL2 switch to soft_restart Geoff Levand
2014-09-09 22:49 ` Geoff Levand
2014-09-09 22:49 ` [PATCH 02/13] arm64/kvm: Fix assembler compatibility of macros Geoff Levand
2014-09-09 22:49 ` Geoff Levand
2014-09-10 8:40 ` Ard Biesheuvel
2014-09-10 8:40 ` Ard Biesheuvel
2014-09-10 16:35 ` Geoff Levand
2014-09-10 16:35 ` Geoff Levand
2014-09-10 17:09 ` Ard Biesheuvel
2014-09-10 17:09 ` Ard Biesheuvel
2014-09-15 16:14 ` Mark Rutland
2014-09-15 16:14 ` Mark Rutland
2014-09-10 18:04 ` [PATCH V2 " Geoff Levand
2014-09-10 18:04 ` Geoff Levand
2014-09-09 22:49 ` [PATCH 04/13] arm64: Add new hcall HVC_CALL_FUNC Geoff Levand
2014-09-09 22:49 ` Geoff Levand
2014-09-10 17:07 ` Will Deacon
2014-09-10 17:07 ` Will Deacon
2014-09-10 17:23 ` Geoff Levand
2014-09-10 17:23 ` Geoff Levand
2014-09-10 17:35 ` Will Deacon
2014-09-10 17:35 ` Will Deacon
2014-09-10 18:11 ` [PATCH V2 " Geoff Levand
2014-09-10 18:11 ` Geoff Levand
2014-09-15 18:11 ` [PATCH " Mark Rutland
2014-09-15 18:11 ` Mark Rutland
2014-09-25 0:24 ` Geoff Levand
2014-09-25 0:24 ` Geoff Levand
2014-09-09 22:49 ` [PATCH 11/13] arm64/kexec: Add core kexec support Geoff Levand
2014-09-09 22:49 ` Geoff Levand
2014-09-18 1:13 ` Mark Rutland
2014-09-18 1:13 ` Mark Rutland
2014-09-25 0:25 ` Geoff Levand
2014-09-25 0:25 ` Geoff Levand
2014-09-09 22:49 ` [PATCH 10/13] arm64/kexec: Revert change to machine_shutdown() Geoff Levand
2014-09-09 22:49 ` Geoff Levand
2014-09-15 19:20 ` Mark Rutland
2014-09-15 19:20 ` Mark Rutland
2014-09-09 22:49 ` [PATCH 12/13] arm64/kexec: Enable kexec in the arm64 defconfig Geoff Levand
2014-09-09 22:49 ` Geoff Levand
2014-09-09 22:49 ` [PATCH 09/13] arm64/kexec: Kexec expects cpu_die Geoff Levand
2014-09-09 22:49 ` Geoff Levand
2014-09-15 19:10 ` Mark Rutland
2014-09-15 19:10 ` Mark Rutland
2014-09-09 22:49 ` [PATCH 13/13] arm64/kexec: Add kexec_ignore_compat_check param Geoff Levand
2014-09-09 22:49 ` Geoff Levand
2014-09-09 22:49 ` [PATCH 08/13] arm64: Use cpu_ops for smp_stop Geoff Levand
2014-09-09 22:49 ` Geoff Levand
2014-09-15 19:06 ` Mark Rutland
2014-09-15 19:06 ` Mark Rutland
2014-09-25 0:24 ` Geoff Levand
2014-09-25 0:24 ` Geoff Levand
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=20140915175708.GD13789@leverpostej \
--to=mark.rutland@arm.com \
--cc=Catalin.Marinas@arm.com \
--cc=Marc.Zyngier@arm.com \
--cc=Will.Deacon@arm.com \
--cc=christoffer.dall@linaro.org \
--cc=geoff@infradead.org \
--cc=kexec@lists.infradead.org \
--cc=linux-arm-kernel@lists.infradead.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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.