From: Will Deacon <will.deacon@arm.com>
To: Marc Zyngier <marc.zyngier@arm.com>
Cc: "kvm@vger.kernel.org" <kvm@vger.kernel.org>,
Catalin Marinas <Catalin.Marinas@arm.com>,
"linux-kernel@vger.kernel.org" <linux-kernel@vger.kernel.org>,
"kvmarm@lists.cs.columbia.edu" <kvmarm@lists.cs.columbia.edu>,
"linux-arm-kernel@lists.infradead.org"
<linux-arm-kernel@lists.infradead.org>
Subject: Re: [PATCH 11/13] arm64: Panic when VHE and non VHE CPUs coexist
Date: Thu, 16 Jul 2015 19:03:08 +0100 [thread overview]
Message-ID: <20150716180308.GQ26390@arm.com> (raw)
In-Reply-To: <1436372356-30410-12-git-send-email-marc.zyngier@arm.com>
On Wed, Jul 08, 2015 at 05:19:14PM +0100, Marc Zyngier wrote:
> Having both VHE and non-VHE capable CPUs in the same system
> is likely to be a recipe for disaster.
>
> If the boot CPU has VHE, but a secondary is not, we won't be
> able to downgrade and run the kernel at EL1. Add CPU hotplug
> to the mix, and this produces a terrifying mess.
>
> Let's solve the problem once and for all. If you mix VHE and
> non-VHE CPUs in the same system, you deserve to loose, and this
> patch makes sure you don't get a chance.
>
> This is implemented by storing the kernel execution level in
> a global variable. Secondaries will park themselves in a
> WFI loop if they observe a mismatch. Also, the primary CPU
> will detect that the secondary CPU has died on a mismatched
> execution level. Panic will follow.
>
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> ---
> arch/arm64/include/asm/virt.h | 15 +++++++++++++++
> arch/arm64/kernel/head.S | 15 +++++++++++++++
> arch/arm64/kernel/smp.c | 4 ++++
> 3 files changed, 34 insertions(+)
>
> diff --git a/arch/arm64/include/asm/virt.h b/arch/arm64/include/asm/virt.h
> index 9f22dd6..8e246f7 100644
> --- a/arch/arm64/include/asm/virt.h
> +++ b/arch/arm64/include/asm/virt.h
> @@ -36,6 +36,11 @@
> */
> extern u32 __boot_cpu_mode[2];
>
> +/*
> + * __run_cpu_mode records the mode the boot CPU uses for the kernel.
> + */
> +extern u32 __run_cpu_mode;
> +
> void __hyp_set_vectors(phys_addr_t phys_vector_base);
> phys_addr_t __hyp_get_vectors(void);
>
> @@ -60,6 +65,16 @@ static inline bool is_kernel_in_hyp_mode(void)
> return el == CurrentEL_EL2;
> }
>
> +static inline bool is_kernel_mode_mismatched(void)
> +{
> + u64 el;
> + u32 mode;
> +
> + asm("mrs %0, CurrentEL" : "=r" (el));
> + mode = ACCESS_ONCE(__run_cpu_mode);
> + return el != mode;
Why the temporary 'mode' variable?
> +}
> +
> /* The section containing the hypervisor text */
> extern char __hyp_text_start[];
> extern char __hyp_text_end[];
> diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S
> index a179747..318e69f 100644
> --- a/arch/arm64/kernel/head.S
> +++ b/arch/arm64/kernel/head.S
> @@ -578,7 +578,20 @@ ENTRY(set_cpu_boot_mode_flag)
> 1: str w20, [x1] // This CPU has booted in EL1
> dmb sy
> dc ivac, x1 // Invalidate potentially stale cache line
> + adr_l x1, __run_cpu_mode
> + ldr w0, [x1]
> + mrs x20, CurrentEL
Why x20?
> + str w20, [x1]
> + dmb sy
> + dc ivac, x1 // Invalidate potentially stale cache line
Can we stick __run_cpu_mode and __boot_cpu_mode into a struct in the same
cacheline and avoid the extra maintenance?
> + cbz x0, skip_el_check
w0?
> + cmp x0, x20
w0, w20?
> + bne mismatched_el
> +skip_el_check:
> ret
> +mismatched_el:
> + wfi
> + b mismatched_el
> ENDPROC(set_cpu_boot_mode_flag)
>
> /*
> @@ -593,6 +606,8 @@ ENDPROC(set_cpu_boot_mode_flag)
> ENTRY(__boot_cpu_mode)
> .long BOOT_CPU_MODE_EL2
> .long BOOT_CPU_MODE_EL1
> +ENTRY(__run_cpu_mode)
> + .long 0
> .popsection
>
> #ifdef CONFIG_SMP
> diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c
> index 695801a..b467f51 100644
> --- a/arch/arm64/kernel/smp.c
> +++ b/arch/arm64/kernel/smp.c
> @@ -52,6 +52,7 @@
> #include <asm/sections.h>
> #include <asm/tlbflush.h>
> #include <asm/ptrace.h>
> +#include <asm/virt.h>
>
> #define CREATE_TRACE_POINTS
> #include <trace/events/ipi.h>
> @@ -112,6 +113,9 @@ int __cpu_up(unsigned int cpu, struct task_struct *idle)
> pr_crit("CPU%u: failed to come online\n", cpu);
> ret = -EIO;
> }
> +
> + if (is_kernel_mode_mismatched())
> + panic("CPU%u: incompatible execution level", cpu);
Might be useful to print the incompatible values, if possible.
Will
WARNING: multiple messages have this Message-ID (diff)
From: will.deacon@arm.com (Will Deacon)
To: linux-arm-kernel@lists.infradead.org
Subject: [PATCH 11/13] arm64: Panic when VHE and non VHE CPUs coexist
Date: Thu, 16 Jul 2015 19:03:08 +0100 [thread overview]
Message-ID: <20150716180308.GQ26390@arm.com> (raw)
In-Reply-To: <1436372356-30410-12-git-send-email-marc.zyngier@arm.com>
On Wed, Jul 08, 2015 at 05:19:14PM +0100, Marc Zyngier wrote:
> Having both VHE and non-VHE capable CPUs in the same system
> is likely to be a recipe for disaster.
>
> If the boot CPU has VHE, but a secondary is not, we won't be
> able to downgrade and run the kernel at EL1. Add CPU hotplug
> to the mix, and this produces a terrifying mess.
>
> Let's solve the problem once and for all. If you mix VHE and
> non-VHE CPUs in the same system, you deserve to loose, and this
> patch makes sure you don't get a chance.
>
> This is implemented by storing the kernel execution level in
> a global variable. Secondaries will park themselves in a
> WFI loop if they observe a mismatch. Also, the primary CPU
> will detect that the secondary CPU has died on a mismatched
> execution level. Panic will follow.
>
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> ---
> arch/arm64/include/asm/virt.h | 15 +++++++++++++++
> arch/arm64/kernel/head.S | 15 +++++++++++++++
> arch/arm64/kernel/smp.c | 4 ++++
> 3 files changed, 34 insertions(+)
>
> diff --git a/arch/arm64/include/asm/virt.h b/arch/arm64/include/asm/virt.h
> index 9f22dd6..8e246f7 100644
> --- a/arch/arm64/include/asm/virt.h
> +++ b/arch/arm64/include/asm/virt.h
> @@ -36,6 +36,11 @@
> */
> extern u32 __boot_cpu_mode[2];
>
> +/*
> + * __run_cpu_mode records the mode the boot CPU uses for the kernel.
> + */
> +extern u32 __run_cpu_mode;
> +
> void __hyp_set_vectors(phys_addr_t phys_vector_base);
> phys_addr_t __hyp_get_vectors(void);
>
> @@ -60,6 +65,16 @@ static inline bool is_kernel_in_hyp_mode(void)
> return el == CurrentEL_EL2;
> }
>
> +static inline bool is_kernel_mode_mismatched(void)
> +{
> + u64 el;
> + u32 mode;
> +
> + asm("mrs %0, CurrentEL" : "=r" (el));
> + mode = ACCESS_ONCE(__run_cpu_mode);
> + return el != mode;
Why the temporary 'mode' variable?
> +}
> +
> /* The section containing the hypervisor text */
> extern char __hyp_text_start[];
> extern char __hyp_text_end[];
> diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S
> index a179747..318e69f 100644
> --- a/arch/arm64/kernel/head.S
> +++ b/arch/arm64/kernel/head.S
> @@ -578,7 +578,20 @@ ENTRY(set_cpu_boot_mode_flag)
> 1: str w20, [x1] // This CPU has booted in EL1
> dmb sy
> dc ivac, x1 // Invalidate potentially stale cache line
> + adr_l x1, __run_cpu_mode
> + ldr w0, [x1]
> + mrs x20, CurrentEL
Why x20?
> + str w20, [x1]
> + dmb sy
> + dc ivac, x1 // Invalidate potentially stale cache line
Can we stick __run_cpu_mode and __boot_cpu_mode into a struct in the same
cacheline and avoid the extra maintenance?
> + cbz x0, skip_el_check
w0?
> + cmp x0, x20
w0, w20?
> + bne mismatched_el
> +skip_el_check:
> ret
> +mismatched_el:
> + wfi
> + b mismatched_el
> ENDPROC(set_cpu_boot_mode_flag)
>
> /*
> @@ -593,6 +606,8 @@ ENDPROC(set_cpu_boot_mode_flag)
> ENTRY(__boot_cpu_mode)
> .long BOOT_CPU_MODE_EL2
> .long BOOT_CPU_MODE_EL1
> +ENTRY(__run_cpu_mode)
> + .long 0
> .popsection
>
> #ifdef CONFIG_SMP
> diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c
> index 695801a..b467f51 100644
> --- a/arch/arm64/kernel/smp.c
> +++ b/arch/arm64/kernel/smp.c
> @@ -52,6 +52,7 @@
> #include <asm/sections.h>
> #include <asm/tlbflush.h>
> #include <asm/ptrace.h>
> +#include <asm/virt.h>
>
> #define CREATE_TRACE_POINTS
> #include <trace/events/ipi.h>
> @@ -112,6 +113,9 @@ int __cpu_up(unsigned int cpu, struct task_struct *idle)
> pr_crit("CPU%u: failed to come online\n", cpu);
> ret = -EIO;
> }
> +
> + if (is_kernel_mode_mismatched())
> + panic("CPU%u: incompatible execution level", cpu);
Might be useful to print the incompatible values, if possible.
Will
WARNING: multiple messages have this Message-ID (diff)
From: Will Deacon <will.deacon@arm.com>
To: Marc Zyngier <marc.zyngier@arm.com>
Cc: Catalin Marinas <Catalin.Marinas@arm.com>,
Christoffer Dall <christoffer.dall@linaro.org>,
"linux-arm-kernel@lists.infradead.org"
<linux-arm-kernel@lists.infradead.org>,
"linux-kernel@vger.kernel.org" <linux-kernel@vger.kernel.org>,
"kvm@vger.kernel.org" <kvm@vger.kernel.org>,
"kvmarm@lists.cs.columbia.edu" <kvmarm@lists.cs.columbia.edu>
Subject: Re: [PATCH 11/13] arm64: Panic when VHE and non VHE CPUs coexist
Date: Thu, 16 Jul 2015 19:03:08 +0100 [thread overview]
Message-ID: <20150716180308.GQ26390@arm.com> (raw)
In-Reply-To: <1436372356-30410-12-git-send-email-marc.zyngier@arm.com>
On Wed, Jul 08, 2015 at 05:19:14PM +0100, Marc Zyngier wrote:
> Having both VHE and non-VHE capable CPUs in the same system
> is likely to be a recipe for disaster.
>
> If the boot CPU has VHE, but a secondary is not, we won't be
> able to downgrade and run the kernel at EL1. Add CPU hotplug
> to the mix, and this produces a terrifying mess.
>
> Let's solve the problem once and for all. If you mix VHE and
> non-VHE CPUs in the same system, you deserve to loose, and this
> patch makes sure you don't get a chance.
>
> This is implemented by storing the kernel execution level in
> a global variable. Secondaries will park themselves in a
> WFI loop if they observe a mismatch. Also, the primary CPU
> will detect that the secondary CPU has died on a mismatched
> execution level. Panic will follow.
>
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> ---
> arch/arm64/include/asm/virt.h | 15 +++++++++++++++
> arch/arm64/kernel/head.S | 15 +++++++++++++++
> arch/arm64/kernel/smp.c | 4 ++++
> 3 files changed, 34 insertions(+)
>
> diff --git a/arch/arm64/include/asm/virt.h b/arch/arm64/include/asm/virt.h
> index 9f22dd6..8e246f7 100644
> --- a/arch/arm64/include/asm/virt.h
> +++ b/arch/arm64/include/asm/virt.h
> @@ -36,6 +36,11 @@
> */
> extern u32 __boot_cpu_mode[2];
>
> +/*
> + * __run_cpu_mode records the mode the boot CPU uses for the kernel.
> + */
> +extern u32 __run_cpu_mode;
> +
> void __hyp_set_vectors(phys_addr_t phys_vector_base);
> phys_addr_t __hyp_get_vectors(void);
>
> @@ -60,6 +65,16 @@ static inline bool is_kernel_in_hyp_mode(void)
> return el == CurrentEL_EL2;
> }
>
> +static inline bool is_kernel_mode_mismatched(void)
> +{
> + u64 el;
> + u32 mode;
> +
> + asm("mrs %0, CurrentEL" : "=r" (el));
> + mode = ACCESS_ONCE(__run_cpu_mode);
> + return el != mode;
Why the temporary 'mode' variable?
> +}
> +
> /* The section containing the hypervisor text */
> extern char __hyp_text_start[];
> extern char __hyp_text_end[];
> diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S
> index a179747..318e69f 100644
> --- a/arch/arm64/kernel/head.S
> +++ b/arch/arm64/kernel/head.S
> @@ -578,7 +578,20 @@ ENTRY(set_cpu_boot_mode_flag)
> 1: str w20, [x1] // This CPU has booted in EL1
> dmb sy
> dc ivac, x1 // Invalidate potentially stale cache line
> + adr_l x1, __run_cpu_mode
> + ldr w0, [x1]
> + mrs x20, CurrentEL
Why x20?
> + str w20, [x1]
> + dmb sy
> + dc ivac, x1 // Invalidate potentially stale cache line
Can we stick __run_cpu_mode and __boot_cpu_mode into a struct in the same
cacheline and avoid the extra maintenance?
> + cbz x0, skip_el_check
w0?
> + cmp x0, x20
w0, w20?
> + bne mismatched_el
> +skip_el_check:
> ret
> +mismatched_el:
> + wfi
> + b mismatched_el
> ENDPROC(set_cpu_boot_mode_flag)
>
> /*
> @@ -593,6 +606,8 @@ ENDPROC(set_cpu_boot_mode_flag)
> ENTRY(__boot_cpu_mode)
> .long BOOT_CPU_MODE_EL2
> .long BOOT_CPU_MODE_EL1
> +ENTRY(__run_cpu_mode)
> + .long 0
> .popsection
>
> #ifdef CONFIG_SMP
> diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c
> index 695801a..b467f51 100644
> --- a/arch/arm64/kernel/smp.c
> +++ b/arch/arm64/kernel/smp.c
> @@ -52,6 +52,7 @@
> #include <asm/sections.h>
> #include <asm/tlbflush.h>
> #include <asm/ptrace.h>
> +#include <asm/virt.h>
>
> #define CREATE_TRACE_POINTS
> #include <trace/events/ipi.h>
> @@ -112,6 +113,9 @@ int __cpu_up(unsigned int cpu, struct task_struct *idle)
> pr_crit("CPU%u: failed to come online\n", cpu);
> ret = -EIO;
> }
> +
> + if (is_kernel_mode_mismatched())
> + panic("CPU%u: incompatible execution level", cpu);
Might be useful to print the incompatible values, if possible.
Will
next prev parent reply other threads:[~2015-07-16 17:51 UTC|newest]
Thread overview: 114+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-07-08 16:19 [PATCH 00/13] arm64: Virtualization Host Extension support Marc Zyngier
2015-07-08 16:19 ` Marc Zyngier
2015-07-08 16:19 ` Marc Zyngier
2015-07-08 16:19 ` [PATCH 01/13] arm/arm64: Add new is_kernel_in_hyp_mode predicate Marc Zyngier
2015-07-08 16:19 ` Marc Zyngier
2015-07-09 9:42 ` Mark Rutland
2015-07-09 9:42 ` Mark Rutland
2015-07-09 9:42 ` Mark Rutland
2015-07-09 10:05 ` Marc Zyngier
2015-07-09 10:05 ` Marc Zyngier
2015-07-09 10:12 ` Mark Rutland
2015-07-09 10:12 ` Mark Rutland
2015-07-16 18:08 ` Will Deacon
2015-07-16 18:08 ` Will Deacon
2015-07-16 18:08 ` Will Deacon
2015-07-08 16:19 ` [PATCH 02/13] arm64: Allow the arch timer to use the HYP timer Marc Zyngier
2015-07-08 16:19 ` Marc Zyngier
2015-07-08 16:19 ` Marc Zyngier
2015-07-08 16:19 ` [PATCH 03/13] arm64: Add ARM64_HAS_VIRT_HOST_EXTN feature Marc Zyngier
2015-07-08 16:19 ` Marc Zyngier
2015-07-08 16:19 ` Marc Zyngier
2015-07-09 9:48 ` Mark Rutland
2015-07-09 9:48 ` Mark Rutland
2015-07-09 9:48 ` Mark Rutland
2015-07-09 9:59 ` Marc Zyngier
2015-07-09 9:59 ` Marc Zyngier
2015-07-09 9:59 ` Marc Zyngier
2015-07-16 18:04 ` Will Deacon
2015-07-16 18:04 ` Will Deacon
2015-07-16 18:04 ` Will Deacon
2015-07-08 16:19 ` [PATCH 04/13] arm64: KVM: skip HYP setup when already running in HYP Marc Zyngier
2015-07-08 16:19 ` Marc Zyngier
2015-07-08 16:19 ` Marc Zyngier
2015-07-08 16:19 ` [PATCH 05/13] arm64: KVM: VHE: macroize VTCR_EL2 setup Marc Zyngier
2015-07-08 16:19 ` Marc Zyngier
2015-07-08 16:19 ` Marc Zyngier
2015-07-08 16:19 ` [PATCH 06/13] arm64: KVM: VHE: Patch out kern_hyp_va Marc Zyngier
2015-07-08 16:19 ` Marc Zyngier
2015-07-08 16:19 ` Marc Zyngier
2015-07-08 16:19 ` [PATCH 07/13] arm64: KVM: VHE: Patch out use of HVC Marc Zyngier
2015-07-08 16:19 ` Marc Zyngier
2015-07-08 16:19 ` Marc Zyngier
2015-07-08 17:14 ` Paolo Bonzini
2015-07-08 17:14 ` Paolo Bonzini
2015-07-08 17:14 ` Paolo Bonzini
2015-07-08 17:54 ` Marc Zyngier
2015-07-08 17:54 ` Marc Zyngier
2015-07-10 11:02 ` Paolo Bonzini
2015-07-10 11:02 ` Paolo Bonzini
2015-07-10 11:02 ` Paolo Bonzini
2015-08-05 17:57 ` Catalin Marinas
2015-08-05 17:57 ` Catalin Marinas
2015-07-08 16:19 ` [PATCH 08/13] arm64: KVM: VHE: Preserve VHE config in world switch Marc Zyngier
2015-07-08 16:19 ` Marc Zyngier
2015-07-08 16:19 ` Marc Zyngier
2015-07-08 16:19 ` [PATCH 09/13] arm64: KVM: VHE: Add alternatives for VHE-enabled world-switch Marc Zyngier
2015-07-08 16:19 ` Marc Zyngier
2015-07-08 16:19 ` Marc Zyngier
2015-07-09 1:29 ` Mario Smarduch
2015-07-09 1:29 ` Mario Smarduch
2015-07-09 8:06 ` Marc Zyngier
2015-07-09 8:06 ` Marc Zyngier
2015-07-09 20:58 ` Mario Smarduch
2015-07-09 20:58 ` Mario Smarduch
2015-07-09 20:58 ` Mario Smarduch
2015-08-31 18:46 ` Christoffer Dall
2015-08-31 18:46 ` Christoffer Dall
2015-07-08 16:19 ` [PATCH 10/13] arm64: Add support for running Linux in EL2 mode Marc Zyngier
2015-07-08 16:19 ` Marc Zyngier
2015-07-08 16:19 ` Marc Zyngier
2015-07-16 17:48 ` Will Deacon
2015-07-16 17:48 ` Will Deacon
2015-07-16 17:48 ` Will Deacon
2015-07-08 16:19 ` [PATCH 11/13] arm64: Panic when VHE and non VHE CPUs coexist Marc Zyngier
2015-07-08 16:19 ` Marc Zyngier
2015-07-08 16:19 ` Marc Zyngier
2015-07-16 18:03 ` Will Deacon [this message]
2015-07-16 18:03 ` Will Deacon
2015-07-16 18:03 ` Will Deacon
2015-08-06 14:08 ` Catalin Marinas
2015-08-06 14:08 ` Catalin Marinas
2015-08-06 14:08 ` Catalin Marinas
2015-07-08 16:19 ` [PATCH 12/13] arm64: KVM: Split sysreg save/restore Marc Zyngier
2015-07-08 16:19 ` Marc Zyngier
2015-07-08 16:19 ` Marc Zyngier
2015-08-31 18:49 ` Christoffer Dall
2015-08-31 18:49 ` Christoffer Dall
2015-07-08 16:19 ` [PATCH 13/13] arm64: KVM: VHE: Early interrupt handling Marc Zyngier
2015-07-08 16:19 ` Marc Zyngier
2015-07-08 16:19 ` Marc Zyngier
2015-08-31 18:52 ` Christoffer Dall
2015-08-31 18:52 ` Christoffer Dall
2015-08-06 17:43 ` [PATCH 00/13] arm64: Virtualization Host Extension support Catalin Marinas
2015-08-06 17:43 ` Catalin Marinas
2015-08-26 9:12 ` Antonios Motakis
2015-08-26 9:12 ` Antonios Motakis
2015-08-26 9:12 ` Antonios Motakis
2015-08-26 9:21 ` Jan Kiszka
2015-08-26 9:21 ` Jan Kiszka
2015-08-26 9:28 ` Antonios Motakis
2015-08-26 9:28 ` Antonios Motakis
2015-08-26 9:28 ` Antonios Motakis
2015-08-26 9:54 ` Jan Kiszka
2015-08-26 9:54 ` Jan Kiszka
2015-08-26 9:54 ` Jan Kiszka
2015-08-26 9:59 ` Marc Zyngier
2015-08-26 9:59 ` Marc Zyngier
2015-08-26 9:59 ` Marc Zyngier
2015-08-26 11:16 ` Antonios Motakis
2015-08-26 11:16 ` Antonios Motakis
2015-08-26 11:16 ` Antonios Motakis
2015-08-28 7:04 ` Marc Zyngier
2015-08-28 7:04 ` Marc Zyngier
2015-08-28 7:04 ` Marc Zyngier
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=20150716180308.GQ26390@arm.com \
--to=will.deacon@arm.com \
--cc=Catalin.Marinas@arm.com \
--cc=kvm@vger.kernel.org \
--cc=kvmarm@lists.cs.columbia.edu \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-kernel@vger.kernel.org \
--cc=marc.zyngier@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 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.