kvmarm.lists.cs.columbia.edu archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/3] KVM: arm64: Ask the compiler to __always_inline functions used by KVM at HYP
@ 2020-02-20 16:58 James Morse
  2020-02-20 16:58 ` [PATCH 1/3] KVM: arm64: Ask the compiler to __always_inline functions used " James Morse
                   ` (4 more replies)
  0 siblings, 5 replies; 13+ messages in thread
From: James Morse @ 2020-02-20 16:58 UTC (permalink / raw)
  To: linux-arm-kernel, kvmarm
  Cc: Ard Biesheuvel, Marc Zyngier, Sami Tolvanen, Catalin Marinas,
	Will Deacon

Hello!

It turns out KVM relies on the inline hint being honoured by the compiler
in quite a few more places than expected. Something about the Shadow Call
Stack support[0] causes the compiler to avoid inline-ing and to place
these functions outside the __hyp_text. This ruins KVM's day.

Add the simon-says __always_inline annotation to all the static
inlines that KVM calls from HYP code.

This series based on v5.6-rc2.


[0] https://lore.kernel.org/linux-arm-kernel/20200219000817.195049-1-samitolvanen@google.com/

Thanks,

James Morse (3):
  KVM: arm64: Ask the compiler to __always_inline functions used at HYP
  KVM: arm64: define our own swab32() to avoid a uapi static inline
  arm64: Ask the compiler to __always_inline functions used by KVM at
    HYP

 arch/arm64/include/asm/arch_gicv3.h      |  2 +-
 arch/arm64/include/asm/cache.h           |  2 +-
 arch/arm64/include/asm/cacheflush.h      |  2 +-
 arch/arm64/include/asm/cpufeature.h      | 10 ++---
 arch/arm64/include/asm/io.h              |  4 +-
 arch/arm64/include/asm/kvm_emulate.h     | 48 ++++++++++++------------
 arch/arm64/include/asm/kvm_hyp.h         |  7 ++++
 arch/arm64/include/asm/kvm_mmu.h         |  3 +-
 arch/arm64/include/asm/virt.h            |  2 +-
 arch/arm64/kvm/hyp/vgic-v2-cpuif-proxy.c |  4 +-
 10 files changed, 46 insertions(+), 38 deletions(-)

-- 
2.24.1

_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH 1/3] KVM: arm64: Ask the compiler to __always_inline functions used at HYP
  2020-02-20 16:58 [PATCH 0/3] KVM: arm64: Ask the compiler to __always_inline functions used by KVM at HYP James Morse
@ 2020-02-20 16:58 ` James Morse
  2020-02-20 16:58 ` [PATCH 2/3] KVM: arm64: define our own swab32() to avoid a uapi static inline James Morse
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 13+ messages in thread
From: James Morse @ 2020-02-20 16:58 UTC (permalink / raw)
  To: linux-arm-kernel, kvmarm
  Cc: Ard Biesheuvel, Marc Zyngier, Sami Tolvanen, Catalin Marinas,
	Will Deacon

On non VHE CPUs, KVM's __hyp_text contains code run at EL2 while the rest
of the kernel runs at EL1. This code lives in its own section with start
and end markers so we can map it to EL2.

The compiler may decide not to inline static-inline functions from the
header file. It may also decide not to put these out-of-line functions
in the same section, meaning they aren't mapped when called at EL2.

Clang-9 does exactly this with __kern_hyp_va() and a few others when
x18 is reserved for the shadow call stack. Add the additional __always_
hint to all the static-inlines that are called from a hyp file.

Signed-off-by: James Morse <james.morse@arm.com>

----
kvm_get_hyp_vector() pulls in all the regular per-cpu accessors
and this_cpu_has_cap(), fortunately its only called for VHE.
---
 arch/arm64/include/asm/arch_gicv3.h  |  2 +-
 arch/arm64/include/asm/cpufeature.h  |  2 +-
 arch/arm64/include/asm/kvm_emulate.h | 48 ++++++++++++++--------------
 arch/arm64/include/asm/kvm_mmu.h     |  3 +-
 arch/arm64/include/asm/virt.h        |  2 +-
 5 files changed, 29 insertions(+), 28 deletions(-)

diff --git a/arch/arm64/include/asm/arch_gicv3.h b/arch/arm64/include/asm/arch_gicv3.h
index 25fec4bde43a..a358e97572c1 100644
--- a/arch/arm64/include/asm/arch_gicv3.h
+++ b/arch/arm64/include/asm/arch_gicv3.h
@@ -32,7 +32,7 @@ static inline void gic_write_eoir(u32 irq)
 	isb();
 }
 
-static inline void gic_write_dir(u32 irq)
+static __always_inline void gic_write_dir(u32 irq)
 {
 	write_sysreg_s(irq, SYS_ICC_DIR_EL1);
 	isb();
diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h
index 92ef9539874a..42ce41eef274 100644
--- a/arch/arm64/include/asm/cpufeature.h
+++ b/arch/arm64/include/asm/cpufeature.h
@@ -581,7 +581,7 @@ static inline bool system_supports_sve(void)
 		cpus_have_const_cap(ARM64_SVE);
 }
 
-static inline bool system_supports_cnp(void)
+static __always_inline bool system_supports_cnp(void)
 {
 	return IS_ENABLED(CONFIG_ARM64_CNP) &&
 		cpus_have_const_cap(ARM64_HAS_CNP);
diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h
index 688c63412cc2..f658dda12364 100644
--- a/arch/arm64/include/asm/kvm_emulate.h
+++ b/arch/arm64/include/asm/kvm_emulate.h
@@ -36,7 +36,7 @@ void kvm_inject_undef32(struct kvm_vcpu *vcpu);
 void kvm_inject_dabt32(struct kvm_vcpu *vcpu, unsigned long addr);
 void kvm_inject_pabt32(struct kvm_vcpu *vcpu, unsigned long addr);
 
-static inline bool vcpu_el1_is_32bit(struct kvm_vcpu *vcpu)
+static __always_inline bool vcpu_el1_is_32bit(struct kvm_vcpu *vcpu)
 {
 	return !(vcpu->arch.hcr_el2 & HCR_RW);
 }
@@ -127,7 +127,7 @@ static inline void vcpu_set_vsesr(struct kvm_vcpu *vcpu, u64 vsesr)
 	vcpu->arch.vsesr_el2 = vsesr;
 }
 
-static inline unsigned long *vcpu_pc(const struct kvm_vcpu *vcpu)
+static __always_inline unsigned long *vcpu_pc(const struct kvm_vcpu *vcpu)
 {
 	return (unsigned long *)&vcpu_gp_regs(vcpu)->regs.pc;
 }
@@ -153,17 +153,17 @@ static inline void vcpu_write_elr_el1(const struct kvm_vcpu *vcpu, unsigned long
 		*__vcpu_elr_el1(vcpu) = v;
 }
 
-static inline unsigned long *vcpu_cpsr(const struct kvm_vcpu *vcpu)
+static __always_inline unsigned long *vcpu_cpsr(const struct kvm_vcpu *vcpu)
 {
 	return (unsigned long *)&vcpu_gp_regs(vcpu)->regs.pstate;
 }
 
-static inline bool vcpu_mode_is_32bit(const struct kvm_vcpu *vcpu)
+static __always_inline bool vcpu_mode_is_32bit(const struct kvm_vcpu *vcpu)
 {
 	return !!(*vcpu_cpsr(vcpu) & PSR_MODE32_BIT);
 }
 
-static inline bool kvm_condition_valid(const struct kvm_vcpu *vcpu)
+static __always_inline bool kvm_condition_valid(const struct kvm_vcpu *vcpu)
 {
 	if (vcpu_mode_is_32bit(vcpu))
 		return kvm_condition_valid32(vcpu);
@@ -181,13 +181,13 @@ static inline void vcpu_set_thumb(struct kvm_vcpu *vcpu)
  * coming from a read of ESR_EL2. Otherwise, it may give the wrong result on
  * AArch32 with banked registers.
  */
-static inline unsigned long vcpu_get_reg(const struct kvm_vcpu *vcpu,
+static __always_inline unsigned long vcpu_get_reg(const struct kvm_vcpu *vcpu,
 					 u8 reg_num)
 {
 	return (reg_num == 31) ? 0 : vcpu_gp_regs(vcpu)->regs.regs[reg_num];
 }
 
-static inline void vcpu_set_reg(struct kvm_vcpu *vcpu, u8 reg_num,
+static __always_inline void vcpu_set_reg(struct kvm_vcpu *vcpu, u8 reg_num,
 				unsigned long val)
 {
 	if (reg_num != 31)
@@ -264,12 +264,12 @@ static inline bool vcpu_mode_priv(const struct kvm_vcpu *vcpu)
 	return mode != PSR_MODE_EL0t;
 }
 
-static inline u32 kvm_vcpu_get_hsr(const struct kvm_vcpu *vcpu)
+static __always_inline u32 kvm_vcpu_get_hsr(const struct kvm_vcpu *vcpu)
 {
 	return vcpu->arch.fault.esr_el2;
 }
 
-static inline int kvm_vcpu_get_condition(const struct kvm_vcpu *vcpu)
+static __always_inline int kvm_vcpu_get_condition(const struct kvm_vcpu *vcpu)
 {
 	u32 esr = kvm_vcpu_get_hsr(vcpu);
 
@@ -279,12 +279,12 @@ static inline int kvm_vcpu_get_condition(const struct kvm_vcpu *vcpu)
 	return -1;
 }
 
-static inline unsigned long kvm_vcpu_get_hfar(const struct kvm_vcpu *vcpu)
+static __always_inline unsigned long kvm_vcpu_get_hfar(const struct kvm_vcpu *vcpu)
 {
 	return vcpu->arch.fault.far_el2;
 }
 
-static inline phys_addr_t kvm_vcpu_get_fault_ipa(const struct kvm_vcpu *vcpu)
+static __always_inline phys_addr_t kvm_vcpu_get_fault_ipa(const struct kvm_vcpu *vcpu)
 {
 	return ((phys_addr_t)vcpu->arch.fault.hpfar_el2 & HPFAR_MASK) << 8;
 }
@@ -299,7 +299,7 @@ static inline u32 kvm_vcpu_hvc_get_imm(const struct kvm_vcpu *vcpu)
 	return kvm_vcpu_get_hsr(vcpu) & ESR_ELx_xVC_IMM_MASK;
 }
 
-static inline bool kvm_vcpu_dabt_isvalid(const struct kvm_vcpu *vcpu)
+static __always_inline bool kvm_vcpu_dabt_isvalid(const struct kvm_vcpu *vcpu)
 {
 	return !!(kvm_vcpu_get_hsr(vcpu) & ESR_ELx_ISV);
 }
@@ -319,17 +319,17 @@ static inline bool kvm_vcpu_dabt_issf(const struct kvm_vcpu *vcpu)
 	return !!(kvm_vcpu_get_hsr(vcpu) & ESR_ELx_SF);
 }
 
-static inline int kvm_vcpu_dabt_get_rd(const struct kvm_vcpu *vcpu)
+static __always_inline int kvm_vcpu_dabt_get_rd(const struct kvm_vcpu *vcpu)
 {
 	return (kvm_vcpu_get_hsr(vcpu) & ESR_ELx_SRT_MASK) >> ESR_ELx_SRT_SHIFT;
 }
 
-static inline bool kvm_vcpu_dabt_iss1tw(const struct kvm_vcpu *vcpu)
+static __always_inline bool kvm_vcpu_dabt_iss1tw(const struct kvm_vcpu *vcpu)
 {
 	return !!(kvm_vcpu_get_hsr(vcpu) & ESR_ELx_S1PTW);
 }
 
-static inline bool kvm_vcpu_dabt_iswrite(const struct kvm_vcpu *vcpu)
+static __always_inline bool kvm_vcpu_dabt_iswrite(const struct kvm_vcpu *vcpu)
 {
 	return !!(kvm_vcpu_get_hsr(vcpu) & ESR_ELx_WNR) ||
 		kvm_vcpu_dabt_iss1tw(vcpu); /* AF/DBM update */
@@ -340,18 +340,18 @@ static inline bool kvm_vcpu_dabt_is_cm(const struct kvm_vcpu *vcpu)
 	return !!(kvm_vcpu_get_hsr(vcpu) & ESR_ELx_CM);
 }
 
-static inline unsigned int kvm_vcpu_dabt_get_as(const struct kvm_vcpu *vcpu)
+static __always_inline unsigned int kvm_vcpu_dabt_get_as(const struct kvm_vcpu *vcpu)
 {
 	return 1 << ((kvm_vcpu_get_hsr(vcpu) & ESR_ELx_SAS) >> ESR_ELx_SAS_SHIFT);
 }
 
 /* This one is not specific to Data Abort */
-static inline bool kvm_vcpu_trap_il_is32bit(const struct kvm_vcpu *vcpu)
+static __always_inline bool kvm_vcpu_trap_il_is32bit(const struct kvm_vcpu *vcpu)
 {
 	return !!(kvm_vcpu_get_hsr(vcpu) & ESR_ELx_IL);
 }
 
-static inline u8 kvm_vcpu_trap_get_class(const struct kvm_vcpu *vcpu)
+static __always_inline u8 kvm_vcpu_trap_get_class(const struct kvm_vcpu *vcpu)
 {
 	return ESR_ELx_EC(kvm_vcpu_get_hsr(vcpu));
 }
@@ -361,17 +361,17 @@ static inline bool kvm_vcpu_trap_is_iabt(const struct kvm_vcpu *vcpu)
 	return kvm_vcpu_trap_get_class(vcpu) == ESR_ELx_EC_IABT_LOW;
 }
 
-static inline u8 kvm_vcpu_trap_get_fault(const struct kvm_vcpu *vcpu)
+static __always_inline u8 kvm_vcpu_trap_get_fault(const struct kvm_vcpu *vcpu)
 {
 	return kvm_vcpu_get_hsr(vcpu) & ESR_ELx_FSC;
 }
 
-static inline u8 kvm_vcpu_trap_get_fault_type(const struct kvm_vcpu *vcpu)
+static __always_inline u8 kvm_vcpu_trap_get_fault_type(const struct kvm_vcpu *vcpu)
 {
 	return kvm_vcpu_get_hsr(vcpu) & ESR_ELx_FSC_TYPE;
 }
 
-static inline bool kvm_vcpu_dabt_isextabt(const struct kvm_vcpu *vcpu)
+static __always_inline bool kvm_vcpu_dabt_isextabt(const struct kvm_vcpu *vcpu)
 {
 	switch (kvm_vcpu_trap_get_fault(vcpu)) {
 	case FSC_SEA:
@@ -390,7 +390,7 @@ static inline bool kvm_vcpu_dabt_isextabt(const struct kvm_vcpu *vcpu)
 	}
 }
 
-static inline int kvm_vcpu_sys_get_rt(struct kvm_vcpu *vcpu)
+static __always_inline int kvm_vcpu_sys_get_rt(struct kvm_vcpu *vcpu)
 {
 	u32 esr = kvm_vcpu_get_hsr(vcpu);
 	return ESR_ELx_SYS64_ISS_RT(esr);
@@ -504,7 +504,7 @@ static inline unsigned long vcpu_data_host_to_guest(struct kvm_vcpu *vcpu,
 	return data;		/* Leave LE untouched */
 }
 
-static inline void kvm_skip_instr(struct kvm_vcpu *vcpu, bool is_wide_instr)
+static __always_inline void kvm_skip_instr(struct kvm_vcpu *vcpu, bool is_wide_instr)
 {
 	if (vcpu_mode_is_32bit(vcpu))
 		kvm_skip_instr32(vcpu, is_wide_instr);
@@ -519,7 +519,7 @@ static inline void kvm_skip_instr(struct kvm_vcpu *vcpu, bool is_wide_instr)
  * Skip an instruction which has been emulated at hyp while most guest sysregs
  * are live.
  */
-static inline void __hyp_text __kvm_skip_instr(struct kvm_vcpu *vcpu)
+static __always_inline void __hyp_text __kvm_skip_instr(struct kvm_vcpu *vcpu)
 {
 	*vcpu_pc(vcpu) = read_sysreg_el2(SYS_ELR);
 	vcpu->arch.ctxt.gp_regs.regs.pstate = read_sysreg_el2(SYS_SPSR);
diff --git a/arch/arm64/include/asm/kvm_mmu.h b/arch/arm64/include/asm/kvm_mmu.h
index 53d846f1bfe7..785762860c63 100644
--- a/arch/arm64/include/asm/kvm_mmu.h
+++ b/arch/arm64/include/asm/kvm_mmu.h
@@ -93,7 +93,7 @@ void kvm_update_va_mask(struct alt_instr *alt,
 			__le32 *origptr, __le32 *updptr, int nr_inst);
 void kvm_compute_layout(void);
 
-static inline unsigned long __kern_hyp_va(unsigned long v)
+static __always_inline unsigned long __kern_hyp_va(unsigned long v)
 {
 	asm volatile(ALTERNATIVE_CB("and %0, %0, #1\n"
 				    "ror %0, %0, #1\n"
@@ -473,6 +473,7 @@ static inline int kvm_write_guest_lock(struct kvm *kvm, gpa_t gpa,
 extern void *__kvm_bp_vect_base;
 extern int __kvm_harden_el2_vector_slot;
 
+/*  This is only called on a VHE system */
 static inline void *kvm_get_hyp_vector(void)
 {
 	struct bp_hardening_data *data = arm64_get_bp_hardening_data();
diff --git a/arch/arm64/include/asm/virt.h b/arch/arm64/include/asm/virt.h
index 0958ed6191aa..61fd26752adc 100644
--- a/arch/arm64/include/asm/virt.h
+++ b/arch/arm64/include/asm/virt.h
@@ -83,7 +83,7 @@ static inline bool is_kernel_in_hyp_mode(void)
 	return read_sysreg(CurrentEL) == CurrentEL_EL2;
 }
 
-static inline bool has_vhe(void)
+static __always_inline bool has_vhe(void)
 {
 	if (cpus_have_const_cap(ARM64_HAS_VIRT_HOST_EXTN))
 		return true;
-- 
2.24.1

_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 2/3] KVM: arm64: define our own swab32() to avoid a uapi static inline
  2020-02-20 16:58 [PATCH 0/3] KVM: arm64: Ask the compiler to __always_inline functions used by KVM at HYP James Morse
  2020-02-20 16:58 ` [PATCH 1/3] KVM: arm64: Ask the compiler to __always_inline functions used " James Morse
@ 2020-02-20 16:58 ` James Morse
  2020-02-20 16:58 ` [PATCH 3/3] arm64: Ask the compiler to __always_inline functions used by KVM at HYP James Morse
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 13+ messages in thread
From: James Morse @ 2020-02-20 16:58 UTC (permalink / raw)
  To: linux-arm-kernel, kvmarm
  Cc: Ard Biesheuvel, Marc Zyngier, Sami Tolvanen, Catalin Marinas,
	Will Deacon

KVM uses swab32() when mediating GIC MMIO accesses if the GICV is badly
aligned, and the host and guest differ in endianness.

arm64 doesn't provide a __arch_swab32(), so __fswab32() is always backed
by the macro implementation that the compiler reduces to a single
instruction. But the static-inline causes problems for KVM if the compiler
chooses not to inline this function, it may not be located in the
__hyp_text where __vgic_v2_perform_cpuif_access() needs it.

Create our own __kvm_swab32() macro that calls ___constant_swab32()
directly. This way we know it will always be inlined.

Signed-off-by: James Morse <james.morse@arm.com>
---
 arch/arm64/include/asm/kvm_hyp.h         | 7 +++++++
 arch/arm64/kvm/hyp/vgic-v2-cpuif-proxy.c | 4 ++--
 2 files changed, 9 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_hyp.h b/arch/arm64/include/asm/kvm_hyp.h
index a3a6a2ba9a63..fe57f60f06a8 100644
--- a/arch/arm64/include/asm/kvm_hyp.h
+++ b/arch/arm64/include/asm/kvm_hyp.h
@@ -47,6 +47,13 @@
 #define read_sysreg_el2(r)	read_sysreg_elx(r, _EL2, _EL1)
 #define write_sysreg_el2(v,r)	write_sysreg_elx(v, r, _EL2, _EL1)
 
+/*
+ * Without an __arch_swab32(), we fall back to ___constant_swab32(), but the
+ * static inline can allow the compiler to out-of-line this. KVM always wants
+ * the macro version as its always inlined.
+ */
+#define __kvm_swab32(x)	___constant_swab32(x)
+
 int __vgic_v2_perform_cpuif_access(struct kvm_vcpu *vcpu);
 
 void __vgic_v3_save_state(struct kvm_vcpu *vcpu);
diff --git a/arch/arm64/kvm/hyp/vgic-v2-cpuif-proxy.c b/arch/arm64/kvm/hyp/vgic-v2-cpuif-proxy.c
index 29ee1feba4eb..4f3a087e36d5 100644
--- a/arch/arm64/kvm/hyp/vgic-v2-cpuif-proxy.c
+++ b/arch/arm64/kvm/hyp/vgic-v2-cpuif-proxy.c
@@ -69,14 +69,14 @@ int __hyp_text __vgic_v2_perform_cpuif_access(struct kvm_vcpu *vcpu)
 		u32 data = vcpu_get_reg(vcpu, rd);
 		if (__is_be(vcpu)) {
 			/* guest pre-swabbed data, undo this for writel() */
-			data = swab32(data);
+			data = __kvm_swab32(data);
 		}
 		writel_relaxed(data, addr);
 	} else {
 		u32 data = readl_relaxed(addr);
 		if (__is_be(vcpu)) {
 			/* guest expects swabbed data */
-			data = swab32(data);
+			data = __kvm_swab32(data);
 		}
 		vcpu_set_reg(vcpu, rd, data);
 	}
-- 
2.24.1

_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 3/3] arm64: Ask the compiler to __always_inline functions used by KVM at HYP
  2020-02-20 16:58 [PATCH 0/3] KVM: arm64: Ask the compiler to __always_inline functions used by KVM at HYP James Morse
  2020-02-20 16:58 ` [PATCH 1/3] KVM: arm64: Ask the compiler to __always_inline functions used " James Morse
  2020-02-20 16:58 ` [PATCH 2/3] KVM: arm64: define our own swab32() to avoid a uapi static inline James Morse
@ 2020-02-20 16:58 ` James Morse
  2020-02-21 13:13   ` Will Deacon
  2020-02-20 17:04 ` [PATCH 0/3] KVM: " Ard Biesheuvel
  2020-02-21 12:55 ` Marc Zyngier
  4 siblings, 1 reply; 13+ messages in thread
From: James Morse @ 2020-02-20 16:58 UTC (permalink / raw)
  To: linux-arm-kernel, kvmarm
  Cc: Ard Biesheuvel, Marc Zyngier, Sami Tolvanen, Catalin Marinas,
	Will Deacon

KVM uses some of the static-inline helpers like icache_is_vipt() from
its HYP code. This assumes the function is inlined so that the code is
mapped to EL2. The compiler may decide not to inline these, and the
out-of-line version may not be in the __hyp_text section.

Add the additional __always_ hint to these static-inlines that are used
by KVM.

Signed-off-by: James Morse <james.morse@arm.com>
---
 arch/arm64/include/asm/cache.h      | 2 +-
 arch/arm64/include/asm/cacheflush.h | 2 +-
 arch/arm64/include/asm/cpufeature.h | 8 ++++----
 arch/arm64/include/asm/io.h         | 4 ++--
 4 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/arch/arm64/include/asm/cache.h b/arch/arm64/include/asm/cache.h
index 806e9dc2a852..a4d1b5f771f6 100644
--- a/arch/arm64/include/asm/cache.h
+++ b/arch/arm64/include/asm/cache.h
@@ -69,7 +69,7 @@ static inline int icache_is_aliasing(void)
 	return test_bit(ICACHEF_ALIASING, &__icache_flags);
 }
 
-static inline int icache_is_vpipt(void)
+static __always_inline int icache_is_vpipt(void)
 {
 	return test_bit(ICACHEF_VPIPT, &__icache_flags);
 }
diff --git a/arch/arm64/include/asm/cacheflush.h b/arch/arm64/include/asm/cacheflush.h
index 665c78e0665a..e6cca3d4acf7 100644
--- a/arch/arm64/include/asm/cacheflush.h
+++ b/arch/arm64/include/asm/cacheflush.h
@@ -145,7 +145,7 @@ extern void copy_to_user_page(struct vm_area_struct *, struct page *,
 #define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1
 extern void flush_dcache_page(struct page *);
 
-static inline void __flush_icache_all(void)
+static __always_inline void __flush_icache_all(void)
 {
 	if (cpus_have_const_cap(ARM64_HAS_CACHE_DIC))
 		return;
diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h
index 42ce41eef274..2a746b99e937 100644
--- a/arch/arm64/include/asm/cpufeature.h
+++ b/arch/arm64/include/asm/cpufeature.h
@@ -435,13 +435,13 @@ cpuid_feature_extract_signed_field(u64 features, int field)
 	return cpuid_feature_extract_signed_field_width(features, field, 4);
 }
 
-static inline unsigned int __attribute_const__
+static __always_inline unsigned int __attribute_const__
 cpuid_feature_extract_unsigned_field_width(u64 features, int field, int width)
 {
 	return (u64)(features << (64 - width - field)) >> (64 - width);
 }
 
-static inline unsigned int __attribute_const__
+static __always_inline unsigned int __attribute_const__
 cpuid_feature_extract_unsigned_field(u64 features, int field)
 {
 	return cpuid_feature_extract_unsigned_field_width(features, field, 4);
@@ -564,7 +564,7 @@ static inline bool system_supports_mixed_endian(void)
 	return val == 0x1;
 }
 
-static inline bool system_supports_fpsimd(void)
+static __always_inline bool system_supports_fpsimd(void)
 {
 	return !cpus_have_const_cap(ARM64_HAS_NO_FPSIMD);
 }
@@ -575,7 +575,7 @@ static inline bool system_uses_ttbr0_pan(void)
 		!cpus_have_const_cap(ARM64_HAS_PAN);
 }
 
-static inline bool system_supports_sve(void)
+static __always_inline bool system_supports_sve(void)
 {
 	return IS_ENABLED(CONFIG_ARM64_SVE) &&
 		cpus_have_const_cap(ARM64_SVE);
diff --git a/arch/arm64/include/asm/io.h b/arch/arm64/include/asm/io.h
index 4e531f57147d..6facd1308e7c 100644
--- a/arch/arm64/include/asm/io.h
+++ b/arch/arm64/include/asm/io.h
@@ -34,7 +34,7 @@ static inline void __raw_writew(u16 val, volatile void __iomem *addr)
 }
 
 #define __raw_writel __raw_writel
-static inline void __raw_writel(u32 val, volatile void __iomem *addr)
+static __always_inline void __raw_writel(u32 val, volatile void __iomem *addr)
 {
 	asm volatile("str %w0, [%1]" : : "rZ" (val), "r" (addr));
 }
@@ -69,7 +69,7 @@ static inline u16 __raw_readw(const volatile void __iomem *addr)
 }
 
 #define __raw_readl __raw_readl
-static inline u32 __raw_readl(const volatile void __iomem *addr)
+static __always_inline u32 __raw_readl(const volatile void __iomem *addr)
 {
 	u32 val;
 	asm volatile(ALTERNATIVE("ldr %w0, [%1]",
-- 
2.24.1

_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* Re: [PATCH 0/3] KVM: arm64: Ask the compiler to __always_inline functions used by KVM at HYP
  2020-02-20 16:58 [PATCH 0/3] KVM: arm64: Ask the compiler to __always_inline functions used by KVM at HYP James Morse
                   ` (2 preceding siblings ...)
  2020-02-20 16:58 ` [PATCH 3/3] arm64: Ask the compiler to __always_inline functions used by KVM at HYP James Morse
@ 2020-02-20 17:04 ` Ard Biesheuvel
  2020-02-20 17:33   ` James Morse
  2020-02-21 12:55 ` Marc Zyngier
  4 siblings, 1 reply; 13+ messages in thread
From: Ard Biesheuvel @ 2020-02-20 17:04 UTC (permalink / raw)
  To: James Morse
  Cc: Marc Zyngier, linux-arm-kernel, Sami Tolvanen, Catalin Marinas,
	Will Deacon, kvmarm

On Thu, 20 Feb 2020 at 17:58, James Morse <james.morse@arm.com> wrote:
>
> Hello!
>
> It turns out KVM relies on the inline hint being honoured by the compiler
> in quite a few more places than expected. Something about the Shadow Call
> Stack support[0] causes the compiler to avoid inline-ing and to place
> these functions outside the __hyp_text. This ruins KVM's day.
>
> Add the simon-says __always_inline annotation to all the static
> inlines that KVM calls from HYP code.
>
> This series based on v5.6-rc2.
>

This isn't quite as yuck as I expected, fortunately, but it does beg
the question whether we shouldn't simply map the entire kernel at EL2
instead?
_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH 0/3] KVM: arm64: Ask the compiler to __always_inline functions used by KVM at HYP
  2020-02-20 17:04 ` [PATCH 0/3] KVM: " Ard Biesheuvel
@ 2020-02-20 17:33   ` James Morse
  2020-02-20 17:35     ` Ard Biesheuvel
  0 siblings, 1 reply; 13+ messages in thread
From: James Morse @ 2020-02-20 17:33 UTC (permalink / raw)
  To: Ard Biesheuvel
  Cc: Marc Zyngier, linux-arm-kernel, Sami Tolvanen, Catalin Marinas,
	Will Deacon, kvmarm

Hi Ard,

On 20/02/2020 17:04, Ard Biesheuvel wrote:
> On Thu, 20 Feb 2020 at 17:58, James Morse <james.morse@arm.com> wrote:
>> It turns out KVM relies on the inline hint being honoured by the compiler
>> in quite a few more places than expected. Something about the Shadow Call
>> Stack support[0] causes the compiler to avoid inline-ing and to place
>> these functions outside the __hyp_text. This ruins KVM's day.
>>
>> Add the simon-says __always_inline annotation to all the static
>> inlines that KVM calls from HYP code.

> This isn't quite as yuck as I expected, fortunately, but it does beg
> the question whether we shouldn't simply map the entire kernel at EL2
> instead?

If the kernel is big enough to need internal veneers (the 128M range?), these would
certainly go horribly wrong because its running somewhere other than the relocation-time
address. We would need a way of telling the linker to keep the bits of KVM close together...


Thanks,

James
_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH 0/3] KVM: arm64: Ask the compiler to __always_inline functions used by KVM at HYP
  2020-02-20 17:33   ` James Morse
@ 2020-02-20 17:35     ` Ard Biesheuvel
  0 siblings, 0 replies; 13+ messages in thread
From: Ard Biesheuvel @ 2020-02-20 17:35 UTC (permalink / raw)
  To: James Morse
  Cc: Marc Zyngier, linux-arm-kernel, Sami Tolvanen, Catalin Marinas,
	Will Deacon, kvmarm

On Thu, 20 Feb 2020 at 18:33, James Morse <james.morse@arm.com> wrote:
>
> Hi Ard,
>
> On 20/02/2020 17:04, Ard Biesheuvel wrote:
> > On Thu, 20 Feb 2020 at 17:58, James Morse <james.morse@arm.com> wrote:
> >> It turns out KVM relies on the inline hint being honoured by the compiler
> >> in quite a few more places than expected. Something about the Shadow Call
> >> Stack support[0] causes the compiler to avoid inline-ing and to place
> >> these functions outside the __hyp_text. This ruins KVM's day.
> >>
> >> Add the simon-says __always_inline annotation to all the static
> >> inlines that KVM calls from HYP code.
>
> > This isn't quite as yuck as I expected, fortunately, but it does beg
> > the question whether we shouldn't simply map the entire kernel at EL2
> > instead?
>
> If the kernel is big enough to need internal veneers (the 128M range?), these would
> certainly go horribly wrong because its running somewhere other than the relocation-time
> address. We would need a way of telling the linker to keep the bits of KVM close together...
>

Ah, of course, there is that as well ...
_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH 0/3] KVM: arm64: Ask the compiler to __always_inline functions used by KVM at HYP
  2020-02-20 16:58 [PATCH 0/3] KVM: arm64: Ask the compiler to __always_inline functions used by KVM at HYP James Morse
                   ` (3 preceding siblings ...)
  2020-02-20 17:04 ` [PATCH 0/3] KVM: " Ard Biesheuvel
@ 2020-02-21 12:55 ` Marc Zyngier
  2020-02-21 14:57   ` James Morse
  2020-02-24 13:22   ` Andrew Jones
  4 siblings, 2 replies; 13+ messages in thread
From: Marc Zyngier @ 2020-02-21 12:55 UTC (permalink / raw)
  To: James Morse
  Cc: Catalin Marinas, Ard Biesheuvel, linux-arm-kernel, Sami Tolvanen,
	Will Deacon, kvmarm

Hi James,

On 2020-02-20 16:58, James Morse wrote:
> Hello!
> 
> It turns out KVM relies on the inline hint being honoured by the 
> compiler
> in quite a few more places than expected. Something about the Shadow 
> Call
> Stack support[0] causes the compiler to avoid inline-ing and to place
> these functions outside the __hyp_text. This ruins KVM's day.
> 
> Add the simon-says __always_inline annotation to all the static
> inlines that KVM calls from HYP code.
> 
> This series based on v5.6-rc2.

Many thanks for going through all this.

I'm happy to take it if Catalin or Will ack the arm64 patches.
It case we decide to go the other way around:

Acked-by: Marc Zyngier <maz@kernel.org>

One thing I'd like to look into though is a compile-time check that
nothing in the hyp_text section has a reference to a non-hyp_text
symbol.

We already have checks around non-init symbols pointing to init symbols,
and I was wondering if we could reuse this for fun and profit...

Thanks,

         M.
-- 
Jazz is not dead. It just smells funny...
_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH 3/3] arm64: Ask the compiler to __always_inline functions used by KVM at HYP
  2020-02-20 16:58 ` [PATCH 3/3] arm64: Ask the compiler to __always_inline functions used by KVM at HYP James Morse
@ 2020-02-21 13:13   ` Will Deacon
  2020-02-21 13:22     ` Ard Biesheuvel
  0 siblings, 1 reply; 13+ messages in thread
From: Will Deacon @ 2020-02-21 13:13 UTC (permalink / raw)
  To: James Morse
  Cc: Marc Zyngier, Ard Biesheuvel, linux-arm-kernel, Sami Tolvanen,
	Catalin Marinas, kvmarm

On Thu, Feb 20, 2020 at 04:58:39PM +0000, James Morse wrote:
> KVM uses some of the static-inline helpers like icache_is_vipt() from
> its HYP code. This assumes the function is inlined so that the code is
> mapped to EL2. The compiler may decide not to inline these, and the
> out-of-line version may not be in the __hyp_text section.
> 
> Add the additional __always_ hint to these static-inlines that are used
> by KVM.
> 
> Signed-off-by: James Morse <james.morse@arm.com>
> ---
>  arch/arm64/include/asm/cache.h      | 2 +-
>  arch/arm64/include/asm/cacheflush.h | 2 +-
>  arch/arm64/include/asm/cpufeature.h | 8 ++++----
>  arch/arm64/include/asm/io.h         | 4 ++--
>  4 files changed, 8 insertions(+), 8 deletions(-)

Acked-by: Will Deacon <will@kernel.org>

It's the right thing to do, but if this stuff keeps trickling in then
we should make CONFIG_OPTIMIZE_INLINING depend on !ARM64 because seeing
"__always_inline" tells you nothing about /why/ it needs to be there and
it's hard to know if/when you can remove those annotations in future.

Will
_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH 3/3] arm64: Ask the compiler to __always_inline functions used by KVM at HYP
  2020-02-21 13:13   ` Will Deacon
@ 2020-02-21 13:22     ` Ard Biesheuvel
  0 siblings, 0 replies; 13+ messages in thread
From: Ard Biesheuvel @ 2020-02-21 13:22 UTC (permalink / raw)
  To: Will Deacon
  Cc: Marc Zyngier, linux-arm-kernel, Sami Tolvanen, Catalin Marinas, kvmarm

On Fri, 21 Feb 2020 at 14:13, Will Deacon <will@kernel.org> wrote:
>
> On Thu, Feb 20, 2020 at 04:58:39PM +0000, James Morse wrote:
> > KVM uses some of the static-inline helpers like icache_is_vipt() from
> > its HYP code. This assumes the function is inlined so that the code is
> > mapped to EL2. The compiler may decide not to inline these, and the
> > out-of-line version may not be in the __hyp_text section.
> >
> > Add the additional __always_ hint to these static-inlines that are used
> > by KVM.
> >
> > Signed-off-by: James Morse <james.morse@arm.com>
> > ---
> >  arch/arm64/include/asm/cache.h      | 2 +-
> >  arch/arm64/include/asm/cacheflush.h | 2 +-
> >  arch/arm64/include/asm/cpufeature.h | 8 ++++----
> >  arch/arm64/include/asm/io.h         | 4 ++--
> >  4 files changed, 8 insertions(+), 8 deletions(-)
>
> Acked-by: Will Deacon <will@kernel.org>
>
> It's the right thing to do, but if this stuff keeps trickling in then
> we should make CONFIG_OPTIMIZE_INLINING depend on !ARM64 because seeing
> "__always_inline" tells you nothing about /why/ it needs to be there and
> it's hard to know if/when you can remove those annotations in future.
>

We might need to follow the same approach as we took for the EFI stub,
and create a special __kvm_hyp symbol namespace so that we can
carefully control which routines from the kernel proper it has access
to.
_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH 0/3] KVM: arm64: Ask the compiler to __always_inline functions used by KVM at HYP
  2020-02-21 12:55 ` Marc Zyngier
@ 2020-02-21 14:57   ` James Morse
  2020-02-21 16:38     ` Marc Zyngier
  2020-02-24 13:22   ` Andrew Jones
  1 sibling, 1 reply; 13+ messages in thread
From: James Morse @ 2020-02-21 14:57 UTC (permalink / raw)
  To: Marc Zyngier, Ard Biesheuvel
  Cc: Catalin Marinas, linux-arm-kernel, Sami Tolvanen, Will Deacon, kvmarm

Hi Marc,

On 21/02/2020 12:55, Marc Zyngier wrote:
> On 2020-02-20 16:58, James Morse wrote:
>> It turns out KVM relies on the inline hint being honoured by the compiler
>> in quite a few more places than expected. Something about the Shadow Call
>> Stack support[0] causes the compiler to avoid inline-ing and to place
>> these functions outside the __hyp_text. This ruins KVM's day.
>>
>> Add the simon-says __always_inline annotation to all the static
>> inlines that KVM calls from HYP code.
>>
>> This series based on v5.6-rc2.
> 
> Many thanks for going through all this.
> 
> I'm happy to take it if Catalin or Will ack the arm64 patches.
> It case we decide to go the other way around:
> 
> Acked-by: Marc Zyngier <maz@kernel.org>
> 
> One thing I'd like to look into though is a compile-time check that
> nothing in the hyp_text section has a reference to a non-hyp_text
> symbol.

Heh, that hypothetical tool would choke on things like arch/arm64/kvm/hyp/tlb.c:
| static void __hyp_text __tlb_switch_to_guest_vhe(...)
| {

[...]

|	local_irq_save(cxt->flags);

which calls trace_hardirqs_off() ... which is absolutely fine because this only happens on
VHE.

To do it purely with the section information, you'd need to separate all the VHE code...
(maybe as a debug option that only runs when VHE is turned off?)


> We already have checks around non-init symbols pointing to init symbols,
> and I was wondering if we could reuse this for fun and profit...

I think objtool is the tool-of-the-future that can do this. You need something that
believes everything behind has_vhe() is unreachable...


Thanks,

James
_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH 0/3] KVM: arm64: Ask the compiler to __always_inline functions used by KVM at HYP
  2020-02-21 14:57   ` James Morse
@ 2020-02-21 16:38     ` Marc Zyngier
  0 siblings, 0 replies; 13+ messages in thread
From: Marc Zyngier @ 2020-02-21 16:38 UTC (permalink / raw)
  To: James Morse
  Cc: Catalin Marinas, Ard Biesheuvel, linux-arm-kernel, Sami Tolvanen,
	Will Deacon, kvmarm

Hi James,

On 2020-02-21 14:57, James Morse wrote:
> Hi Marc,
> 
> On 21/02/2020 12:55, Marc Zyngier wrote:
>> On 2020-02-20 16:58, James Morse wrote:
>>> It turns out KVM relies on the inline hint being honoured by the 
>>> compiler
>>> in quite a few more places than expected. Something about the Shadow 
>>> Call
>>> Stack support[0] causes the compiler to avoid inline-ing and to place
>>> these functions outside the __hyp_text. This ruins KVM's day.
>>> 
>>> Add the simon-says __always_inline annotation to all the static
>>> inlines that KVM calls from HYP code.
>>> 
>>> This series based on v5.6-rc2.
>> 
>> Many thanks for going through all this.
>> 
>> I'm happy to take it if Catalin or Will ack the arm64 patches.
>> It case we decide to go the other way around:
>> 
>> Acked-by: Marc Zyngier <maz@kernel.org>
>> 
>> One thing I'd like to look into though is a compile-time check that
>> nothing in the hyp_text section has a reference to a non-hyp_text
>> symbol.
> 
> Heh, that hypothetical tool would choke on things like 
> arch/arm64/kvm/hyp/tlb.c:
> | static void __hyp_text __tlb_switch_to_guest_vhe(...)
> | {
> 
> [...]
> 
> |	local_irq_save(cxt->flags);
> 
> which calls trace_hardirqs_off() ... which is absolutely fine because
> this only happens on VHE.

Duh, indeed.

> To do it purely with the section information, you'd need to separate
> all the VHE code... (maybe as a debug option that only runs when VHE
> is turned off?)

We may have to to that anyway at some point. If the "KVM compartment"
thing becomes real, we may have to end-up compiling both separately
(and jettison the one we don't need at runtime).

>> We already have checks around non-init symbols pointing to init 
>> symbols,
>> and I was wondering if we could reuse this for fun and profit...
> 
> I think objtool is the tool-of-the-future that can do this. You need
> something that believes everything behind has_vhe() is unreachable...

I need to educate myself about objtool. Seems to be the miracle cure
for a lot of ailments! ;-)

Anyway, I've now queued the series for 5.6.

          M.
-- 
Jazz is not dead. It just smells funny...
_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH 0/3] KVM: arm64: Ask the compiler to __always_inline functions used by KVM at HYP
  2020-02-21 12:55 ` Marc Zyngier
  2020-02-21 14:57   ` James Morse
@ 2020-02-24 13:22   ` Andrew Jones
  1 sibling, 0 replies; 13+ messages in thread
From: Andrew Jones @ 2020-02-24 13:22 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: Ard Biesheuvel, Catalin Marinas, Sami Tolvanen, Will Deacon,
	kvmarm, linux-arm-kernel

On Fri, Feb 21, 2020 at 12:55:16PM +0000, Marc Zyngier wrote:
> Hi James,
> 
> On 2020-02-20 16:58, James Morse wrote:
> > Hello!
> > 
> > It turns out KVM relies on the inline hint being honoured by the
> > compiler
> > in quite a few more places than expected. Something about the Shadow
> > Call
> > Stack support[0] causes the compiler to avoid inline-ing and to place
> > these functions outside the __hyp_text. This ruins KVM's day.
> > 
> > Add the simon-says __always_inline annotation to all the static
> > inlines that KVM calls from HYP code.
> > 
> > This series based on v5.6-rc2.
> 
> Many thanks for going through all this.
> 
> I'm happy to take it if Catalin or Will ack the arm64 patches.
> It case we decide to go the other way around:
> 
> Acked-by: Marc Zyngier <maz@kernel.org>
> 
> One thing I'd like to look into though is a compile-time check that
> nothing in the hyp_text section has a reference to a non-hyp_text
> symbol.
> 
> We already have checks around non-init symbols pointing to init symbols,
> and I was wondering if we could reuse this for fun and profit...

Hi Marc,

I recall that you've suggested that before, and I even tried it around
that time [*]. I wasn't happy enough with it to post a proper patch
though.

[*] https://lists.cs.columbia.edu/pipermail/kvmarm/2018-May/031629.html

Thanks,
drew

> 
> Thanks,
> 
>         M.
> -- 
> Jazz is not dead. It just smells funny...
> _______________________________________________
> kvmarm mailing list
> kvmarm@lists.cs.columbia.edu
> https://lists.cs.columbia.edu/mailman/listinfo/kvmarm
> 

_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2020-02-24 13:22 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-02-20 16:58 [PATCH 0/3] KVM: arm64: Ask the compiler to __always_inline functions used by KVM at HYP James Morse
2020-02-20 16:58 ` [PATCH 1/3] KVM: arm64: Ask the compiler to __always_inline functions used " James Morse
2020-02-20 16:58 ` [PATCH 2/3] KVM: arm64: define our own swab32() to avoid a uapi static inline James Morse
2020-02-20 16:58 ` [PATCH 3/3] arm64: Ask the compiler to __always_inline functions used by KVM at HYP James Morse
2020-02-21 13:13   ` Will Deacon
2020-02-21 13:22     ` Ard Biesheuvel
2020-02-20 17:04 ` [PATCH 0/3] KVM: " Ard Biesheuvel
2020-02-20 17:33   ` James Morse
2020-02-20 17:35     ` Ard Biesheuvel
2020-02-21 12:55 ` Marc Zyngier
2020-02-21 14:57   ` James Morse
2020-02-21 16:38     ` Marc Zyngier
2020-02-24 13:22   ` Andrew Jones

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).