From: Steffen Eiden <seiden@linux.ibm.com>
To: Marc Zyngier <maz@kernel.org>, Oliver Upton <oupton@kernel.org>,
Fuad Tabba <fuad.tabba@linux.dev>,
Joey Gouly <joey.gouly@arm.com>,
Suzuki K Poulose <suzuki.poulose@arm.com>,
Zenghui Yu <yuzenghui@huawei.com>,
Catalin Marinas <catalin.marinas@arm.com>,
Will Deacon <will@kernel.org>,
Mark Rutland <mark.rutland@arm.com>,
Andreas Grapentin <gra@linux.ibm.com>,
Christian Borntraeger <borntraeger@linux.ibm.com>,
Janosch Frank <frankja@linux.ibm.com>,
Claudio Imbrenda <imbrenda@linux.ibm.com>,
David Hildenbrand <david@kernel.org>,
Heiko Carstens <hca@linux.ibm.com>,
Vasily Gorbik <gor@linux.ibm.com>,
Alexander Gordeev <agordeev@linux.ibm.com>,
Sven Schnelle <svens@linux.ibm.com>,
Friedrich Welter <fritz@linux.ibm.com>,
Gautam Gala <ggala@linux.ibm.com>,
Hariharan Mari <hari55@linux.ibm.com>,
Hendrik Brueckner <brueckner@linux.ibm.com>,
Nico Boehr <nrb@linux.ibm.com>,
Ulrich Weigand <Ulrich.Weigand@de.ibm.com>,
Arnd Bergmann <arnd@arndb.de>,
Paolo Bonzini <pbonzini@redhat.com>
Cc: linux-arm-kernel@lists.infradead.org, kvmarm@lists.linux.dev,
linux-kernel@vger.kernel.org, kvm@vger.kernel.org,
linux-s390@vger.kernel.org, Steffen Eiden <seiden@linux.ibm.com>
Subject: [PATCH v3 15/23] KVM: s390: arm64: Implement feature sanitisation
Date: Fri, 06 Nov 2026 17:07:48 +0100 [thread overview]
Message-ID: <20261106-sysreg-v3-15-75e95980fb10@linux.ibm.com> (raw)
In-Reply-To: <20261106-sysreg-v3-0-75e95980fb10@linux.ibm.com>
Implement feature detection and sanitization for arm64 KVM guests on
s390.
Query hardware capabilities using QAAF instruction and sanitize arm64 ID
registers. Provide accessor functions for queried capabilities and
integrate feature detection into module initialization sequence.
Co-developed-by: Andreas Grapentin <gra@linux.ibm.com>
Signed-off-by: Andreas Grapentin <gra@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
---
arch/s390/include/asm/kvm_host_arm64.h | 13 +++
arch/s390/kvm/arm64/Makefile | 1 +
arch/s390/kvm/arm64/arm.c | 2 +-
arch/s390/kvm/arm64/feature.c | 163 +++++++++++++++++++++++++++++++++
arch/s390/kvm/arm64/feature.h | 86 +++++++++++++++++
arch/s390/kvm/arm64/qaaf.c | 2 +
6 files changed, 266 insertions(+), 1 deletion(-)
diff --git a/arch/s390/include/asm/kvm_host_arm64.h b/arch/s390/include/asm/kvm_host_arm64.h
index 3e69724f17c9..9afe37f6696c 100644
--- a/arch/s390/include/asm/kvm_host_arm64.h
+++ b/arch/s390/include/asm/kvm_host_arm64.h
@@ -15,6 +15,19 @@ enum vcpu_sysreg;
#include <asm/sae.h>
+enum {
+ ARM64_HAS_WFXT,
+ ARM64_HAS_RASV1P1_EXTN,
+ ARM64_HAS_STAGE2_FWB,
+ ARM64_HAS_RAS_EXTN,
+ ARM64_HAS_EVT,
+ ARM64_HAS_HCR_NV1,
+ ARM64_MISMATCHED_CACHE_TYPE,
+ ARM64_HAS_ECV_CNTPOFF,
+};
+
+bool cpus_have_final_cap(unsigned int num);
+
#define KVM_HAVE_MMU_RWLOCK
#define KVM_MAX_VCPUS 1
#define __KVM_HAVE_VCPU_RUN_PID_CHANGE
diff --git a/arch/s390/kvm/arm64/Makefile b/arch/s390/kvm/arm64/Makefile
index e9587c6d6de9..e75b38071f8a 100644
--- a/arch/s390/kvm/arm64/Makefile
+++ b/arch/s390/kvm/arm64/Makefile
@@ -11,6 +11,7 @@ ccflags-y += -I $(src) -I $(objtree)/$(obj) -I$(srctree)/arch/$(SRCARCH)/kvm/gma
kvm-arm64-local := \
arm.o \
+ feature.o \
guest.o \
handle_exit.o \
inject_fault.o \
diff --git a/arch/s390/kvm/arm64/arm.c b/arch/s390/kvm/arm64/arm.c
index 3af0b47b8377..ba6235629c7d 100644
--- a/arch/s390/kvm/arm64/arm.c
+++ b/arch/s390/kvm/arm64/arm.c
@@ -20,6 +20,7 @@
#include <kvm_mmu.h>
#include "arm.h"
+#include "feature.h"
#include "handle_exit.h"
#include "qaaf.h"
@@ -27,7 +28,6 @@
#include "trace.h"
static unsigned long system_supported_vcpu_features(struct kvm_vcpu *vcpu);
-#define read_sanitised_ftr_reg(_id) 0
#define __INCL_GEN_ARM_FILE
#include "generated/arm.inc"
diff --git a/arch/s390/kvm/arm64/feature.c b/arch/s390/kvm/arm64/feature.c
new file mode 100644
index 000000000000..f8b23ba85f9e
--- /dev/null
+++ b/arch/s390/kvm/arm64/feature.c
@@ -0,0 +1,163 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <linux/kvm_host.h>
+#include <linux/printk.h>
+#include <linux/bitfield.h>
+#include <asm/sae.h>
+#include <asm/kvm_host_types.h>
+
+#include <arm64/sysreg.h>
+
+#include "feature.h"
+
+#define MASK_RESERVED(_qaafp, _id) \
+ ({ \
+ u64 *_reg = &((_qaafp)->regs[QAAF_REG_##_id]); \
+ *_reg = (*_reg & ~_id##_RES0) | _id##_RES1; \
+ })
+
+#define QAAF_FIELD_MODIFY(_idp, _id_field, _val) \
+ FIELD_MODIFY(_id_field##_MASK, _idp, _id_field##_##_val)
+
+#define MODIFY(_qaafp, _id, _field, _val) \
+ QAAF_FIELD_MODIFY(&((_qaafp)->regs[QAAF_REG_##_id]), _id##_##_field, _val)
+
+void __init kvm_arm_host_sanitize_features(struct qaaf_qmc_block *qaaf_qmc)
+{
+ MASK_RESERVED(qaaf_qmc, ID_AA64ISAR0_EL1);
+
+ MODIFY(qaaf_qmc, ID_AA64ISAR1_EL1, LS64, NI);
+ MASK_RESERVED(qaaf_qmc, ID_AA64ISAR1_EL1);
+
+ MODIFY(qaaf_qmc, ID_AA64ISAR2_EL1, SYSINSTR_128, NI);
+ MODIFY(qaaf_qmc, ID_AA64ISAR2_EL1, SYSREG_128, NI);
+ MODIFY(qaaf_qmc, ID_AA64ISAR2_EL1, PAC_frac, NI);
+ MASK_RESERVED(qaaf_qmc, ID_AA64ISAR2_EL1);
+
+ MASK_RESERVED(qaaf_qmc, ID_AA64ISAR3_EL1);
+
+ MASK_RESERVED(qaaf_qmc, ID_AA64MMFR0_EL1);
+ MASK_RESERVED(qaaf_qmc, ID_AA64MMFR1_EL1);
+ MASK_RESERVED(qaaf_qmc, ID_AA64MMFR2_EL1);
+
+ MODIFY(qaaf_qmc, ID_AA64MMFR3_EL1, Spec_FPACC, NI);
+ MODIFY(qaaf_qmc, ID_AA64MMFR3_EL1, ADERR, NI);
+ MODIFY(qaaf_qmc, ID_AA64MMFR3_EL1, SDERR, NI);
+ MODIFY(qaaf_qmc, ID_AA64MMFR3_EL1, ANERR, NI);
+ MODIFY(qaaf_qmc, ID_AA64MMFR3_EL1, SNERR, NI);
+ MODIFY(qaaf_qmc, ID_AA64MMFR3_EL1, MEC, NI);
+ MASK_RESERVED(qaaf_qmc, ID_AA64MMFR3_EL1);
+
+ MODIFY(qaaf_qmc, ID_AA64MMFR4_EL1, SRMASK, NI);
+ MODIFY(qaaf_qmc, ID_AA64MMFR4_EL1, E3DSE, NI);
+ MODIFY(qaaf_qmc, ID_AA64MMFR4_EL1, RMEGDI, NI);
+ MODIFY(qaaf_qmc, ID_AA64MMFR4_EL1, FGWTE3, NI);
+ MODIFY(qaaf_qmc, ID_AA64MMFR4_EL1, ASID2, NI);
+ MASK_RESERVED(qaaf_qmc, ID_AA64MMFR4_EL1);
+
+ MODIFY(qaaf_qmc, ID_AA64PFR0_EL1, SEL2, NI);
+ MODIFY(qaaf_qmc, ID_AA64PFR0_EL1, SVE, NI);
+ MASK_RESERVED(qaaf_qmc, ID_AA64PFR0_EL1);
+ MASK_RESERVED(qaaf_qmc, ID_AA64PFR1_EL1);
+ MASK_RESERVED(qaaf_qmc, ID_AA64PFR2_EL1);
+
+ MODIFY(qaaf_qmc, ID_AA64DFR0_EL1, PMUVer, NI);
+ MASK_RESERVED(qaaf_qmc, ID_AA64DFR0_EL1);
+ MASK_RESERVED(qaaf_qmc, ID_AA64DFR1_EL1);
+ MASK_RESERVED(qaaf_qmc, ID_AA64DFR2_EL1);
+
+ MASK_RESERVED(qaaf_qmc, ID_AA64AFR0_EL1);
+ MASK_RESERVED(qaaf_qmc, ID_AA64AFR1_EL1);
+
+ MASK_RESERVED(qaaf_qmc, ID_AA64ZFR0_EL1);
+
+ MASK_RESERVED(qaaf_qmc, ID_AA64SMFR0_EL1);
+
+ MASK_RESERVED(qaaf_qmc, ID_AA64FPFR0_EL1);
+
+ MASK_RESERVED(qaaf_qmc, ID_PFR0_EL1);
+ MASK_RESERVED(qaaf_qmc, ID_PFR1_EL1);
+ MASK_RESERVED(qaaf_qmc, ID_PFR2_EL1);
+
+ MASK_RESERVED(qaaf_qmc, ID_DFR0_EL1);
+ MASK_RESERVED(qaaf_qmc, ID_DFR1_EL1);
+
+ MASK_RESERVED(qaaf_qmc, ID_MMFR0_EL1);
+ MASK_RESERVED(qaaf_qmc, ID_MMFR1_EL1);
+ MASK_RESERVED(qaaf_qmc, ID_MMFR2_EL1);
+ MASK_RESERVED(qaaf_qmc, ID_MMFR3_EL1);
+ MASK_RESERVED(qaaf_qmc, ID_MMFR4_EL1);
+ MASK_RESERVED(qaaf_qmc, ID_MMFR5_EL1);
+
+ MASK_RESERVED(qaaf_qmc, ID_ISAR0_EL1);
+ MASK_RESERVED(qaaf_qmc, ID_ISAR1_EL1);
+ MASK_RESERVED(qaaf_qmc, ID_ISAR2_EL1);
+ MASK_RESERVED(qaaf_qmc, ID_ISAR3_EL1);
+ MASK_RESERVED(qaaf_qmc, ID_ISAR4_EL1);
+ MASK_RESERVED(qaaf_qmc, ID_ISAR5_EL1);
+ MASK_RESERVED(qaaf_qmc, ID_ISAR6_EL1);
+
+ MASK_RESERVED(qaaf_qmc, MVFR0_EL1);
+ MASK_RESERVED(qaaf_qmc, MVFR1_EL1);
+ MASK_RESERVED(qaaf_qmc, MVFR2_EL1);
+
+ MASK_RESERVED(qaaf_qmc, CTR_EL0);
+
+ MASK_RESERVED(qaaf_qmc, ICH_VTR_EL2);
+}
+
+/**
+ * cpus_have_final_cap - Check if an ARM64 CPU capability is supported
+ * @num: Capability number to check
+ *
+ * Maps ARM64 CPU capabilities to their corresponding ID register fields
+ * and checks if the feature is supported by the s390 hardware via QAAF.
+ *
+ * Return: true if capability is supported, false otherwise
+ */
+bool cpus_have_final_cap(unsigned int num)
+{
+ u64 reg_val;
+
+ switch (num) {
+ case ARM64_HAS_STAGE2_FWB:
+ reg_val = read_sanitised_ftr_reg(SYS_ID_AA64MMFR2_EL1);
+ return SYS_FIELD_GET(ID_AA64MMFR2_EL1, FWB, reg_val) >=
+ ID_AA64MMFR2_EL1_FWB_IMP;
+
+ case ARM64_HAS_WFXT:
+ reg_val = read_sanitised_ftr_reg(SYS_ID_AA64ISAR2_EL1);
+ return SYS_FIELD_GET(ID_AA64ISAR2_EL1, WFxT, reg_val) >=
+ ID_AA64ISAR2_EL1_WFxT_IMP;
+
+ case ARM64_HAS_RASV1P1_EXTN:
+ reg_val = read_sanitised_ftr_reg(SYS_ID_AA64PFR1_EL1);
+ return SYS_FIELD_GET(ID_AA64PFR1_EL1, RAS_frac, reg_val) ==
+ ID_AA64PFR1_EL1_RAS_frac_RASv1p1;
+
+ case ARM64_HAS_HCR_NV1:
+ reg_val = read_sanitised_ftr_reg(SYS_ID_AA64MMFR4_EL1);
+ return SYS_FIELD_GET(ID_AA64MMFR4_EL1, E2H0, reg_val) ==
+ ID_AA64MMFR4_EL1_E2H0_IMP;
+
+ case ARM64_HAS_RAS_EXTN:
+ reg_val = read_sanitised_ftr_reg(SYS_ID_AA64PFR0_EL1);
+ return SYS_FIELD_GET(ID_AA64PFR0_EL1, RAS, reg_val) >=
+ ID_AA64PFR0_EL1_RAS_IMP;
+
+ case ARM64_HAS_EVT:
+ reg_val = read_sanitised_ftr_reg(SYS_ID_AA64MMFR2_EL1);
+ return SYS_FIELD_GET(ID_AA64MMFR2_EL1, EVT, reg_val) >=
+ ID_AA64MMFR2_EL1_EVT_IMP;
+
+ case ARM64_HAS_ECV_CNTPOFF:
+ reg_val = read_sanitised_ftr_reg(SYS_ID_AA64MMFR0_EL1);
+ return SYS_FIELD_GET(ID_AA64MMFR0_EL1, ECV, reg_val) >=
+ ID_AA64MMFR0_EL1_ECV_CNTPOFF;
+
+ case ARM64_MISMATCHED_CACHE_TYPE:
+ return false;
+ default:
+ return false;
+ }
+}
diff --git a/arch/s390/kvm/arm64/feature.h b/arch/s390/kvm/arm64/feature.h
new file mode 100644
index 000000000000..0a59047fda6e
--- /dev/null
+++ b/arch/s390/kvm/arm64/feature.h
@@ -0,0 +1,86 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef ARCH_S390_KVM_FEATURE_H
+#define ARCH_S390_KVM_FEATURE_H
+
+#include <linux/types.h>
+#include <linux/bitfield.h>
+
+#include <asm/sae.h>
+
+#include "qaaf.h"
+
+void __init kvm_arm_host_sanitize_features(struct qaaf_qmc_block *qaaf_qmc);
+
+/**
+ * read_sanitised_ftr_reg() - Get the value of a sys register
+ *
+ * @id - ARM sysreg id
+ *
+ * Get the value of a sys register describing the host configuration.
+ * The returned value indicates support by the machine (HW/FW)
+ * after some sanitisation.
+ *
+ * Example:
+ * read_sanitised_ftr_reg(SYS_ID_AA64PFR0_EL1)
+ *
+ * Return: Sanitised HW value of the specified register
+ */
+static inline u64 read_sanitised_ftr_reg(u32 id)
+{
+ return kvm_qaaf_read_ftr_reg(id);
+}
+
+/**
+ * kvm_sae_supported_sd_formats() - Retrieve supported SAE SD formats
+ *
+ * Return: Bitmap of supported SAE state description formats.
+ */
+static inline u32 kvm_sae_supported_sd_formats(void)
+{
+ struct qaaf_qmc_block *qmc = kvm_qaaf_qmc();
+
+ return qmc->ssdf;
+}
+
+/**
+ * kvm_sae_supported_sa_formats() - Retrieve supported SAE SA formats
+ *
+ * Return: Bitmap of supported SAE save area formats.
+ */
+static inline u32 kvm_sae_supported_sa_formats(void)
+{
+ struct qaaf_qmc_block *qmc = kvm_qaaf_qmc();
+
+ return qmc->ssaf;
+}
+
+/**
+ * kvm_sae_max_vcpus() - Retrieve maximum supported vcpus
+ *
+ * Return: Max number of vCPUs supported by the SAE instruction/the machine
+ * as indicated by QAAF, not necessarily that supported by the host software.
+ */
+static inline u32 kvm_sae_max_vcpus(void)
+{
+ struct qaaf_qmc_block *qmc = kvm_qaaf_qmc();
+
+ /* QAAF QMC reports the max id not the max num */
+ return qmc->maxncpu + 1;
+}
+
+/**
+ * kvm_sae_irptc() - Retrieve supported SAE IRPTCs
+ *
+ * Return: Bitmap of supported SAE IRPTCs.
+ */
+static inline u64 kvm_sae_irptc(void)
+{
+ struct qaaf_qmc_block *qmc = kvm_qaaf_qmc();
+
+ return qmc->regs[QAAF_IRPTC];
+}
+
+#define kvm_vcpu_has_pmu(_v) false
+
+#endif /* ARCH_S390_KVM_FEATURE_H */
diff --git a/arch/s390/kvm/arm64/qaaf.c b/arch/s390/kvm/arm64/qaaf.c
index f6b1750aed68..36487025013c 100644
--- a/arch/s390/kvm/arm64/qaaf.c
+++ b/arch/s390/kvm/arm64/qaaf.c
@@ -3,6 +3,7 @@
#include <linux/kvm_host.h>
#include <asm/aef.h>
#include "qaaf.h"
+#include "feature.h"
static struct qaaf_qmc_block qmc_sanitized;
@@ -17,6 +18,7 @@ struct qaaf_qmc_block *kvm_qaaf_qmc(void)
void __init kvm_init_qaaf(void)
{
qmc_sanitized = *aef_qmc();
+ kvm_arm_host_sanitize_features(&qmc_sanitized);
}
#define _qaaf_reg_case(id) case SYS_##id: return qmc_sanitized.regs[QAAF_REG_##id]
--
2.56.0
next prev parent reply other threads:[~2026-11-06 16:08 UTC|newest]
Thread overview: 24+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-06 16:07 [PATCH v3 00/23] KVM: arm64 on s390 System Register Handling Steffen Eiden
2026-11-06 16:07 ` [PATCH v3 01/23] KVM: arm64: Refactor idreg caching into dedicated structure Steffen Eiden
2026-11-06 16:07 ` [PATCH v3 02/23] KVM: arm64: Extract number of sys_reg_desc into a constant Steffen Eiden
2026-11-06 16:07 ` [PATCH v3 03/23] arm64: sysreg: Convert OSLSR to automatic register generation Steffen Eiden
2026-11-06 16:07 ` [PATCH v3 04/23] arm64: Prepare headers for sysreg sharing with s390 Steffen Eiden
2026-11-06 16:07 ` [PATCH v3 05/23] arm64: Share system register related headers and functions " Steffen Eiden
2026-11-06 16:07 ` [PATCH v3 06/23] KVM: s390: arm64: Prepare for sharing arm64 SVE and ftr-reg code Steffen Eiden
2026-11-06 16:07 ` [PATCH v3 07/23] KVM: arm64: Prepare sys_regs.c for sharing with s390 Steffen Eiden
2026-11-06 16:07 ` [PATCH v3 08/23] KVM: arm64: Share system register code " Steffen Eiden
2026-11-06 16:07 ` [PATCH v3 09/23] s390: tools: Share arm64/kvm headers Steffen Eiden
2026-11-06 16:07 ` [PATCH v3 10/23] s390: Add range check asm macro Steffen Eiden
2026-11-06 16:07 ` [PATCH v3 11/23] s390: Read/write ARM system registers Steffen Eiden
2026-11-06 16:07 ` [PATCH v3 12/23] s390: Query arm guest time Steffen Eiden
2026-11-06 16:07 ` [PATCH v3 13/23] KVM: s390: arm64: Query Available Arm features Steffen Eiden
2026-11-06 16:07 ` [PATCH v3 14/23] KVM: s390: arm64: Verify machine feature set before loading Steffen Eiden
2026-11-06 16:07 ` Steffen Eiden [this message]
2026-11-06 16:07 ` [PATCH v3 16/23] KVM: s390: arm64: Implement arm sysreg managing infrastructure Steffen Eiden
2026-11-06 16:07 ` [PATCH v3 17/23] KVM: s390: arm64: Integrate sysreg into the host Steffen Eiden
2026-11-06 16:07 ` [PATCH v3 18/23] KVM: s390: arm64: Use QAAF init save area Steffen Eiden
2026-11-06 16:07 ` [PATCH v3 19/23] KVM: s390: arm64: Implement exception injection Steffen Eiden
2026-11-06 16:07 ` [PATCH v3 20/23] KVM: s390: arm64: Finalize page fault handling Steffen Eiden
2026-11-06 16:07 ` [PATCH v3 21/23] KVM: s390: arm64: Implement SVE for arm guests Steffen Eiden
2026-11-06 16:07 ` [PATCH v3 22/23] KVM: s390: arm64: Promote PTRAUTH capability Steffen Eiden
2026-11-06 16:07 ` [PATCH v3 23/23] s390: Report AEF features to sysfs Steffen Eiden
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=20261106-sysreg-v3-15-75e95980fb10@linux.ibm.com \
--to=seiden@linux.ibm.com \
--cc=Ulrich.Weigand@de.ibm.com \
--cc=agordeev@linux.ibm.com \
--cc=arnd@arndb.de \
--cc=borntraeger@linux.ibm.com \
--cc=brueckner@linux.ibm.com \
--cc=catalin.marinas@arm.com \
--cc=david@kernel.org \
--cc=frankja@linux.ibm.com \
--cc=fritz@linux.ibm.com \
--cc=fuad.tabba@linux.dev \
--cc=ggala@linux.ibm.com \
--cc=gor@linux.ibm.com \
--cc=gra@linux.ibm.com \
--cc=hari55@linux.ibm.com \
--cc=hca@linux.ibm.com \
--cc=imbrenda@linux.ibm.com \
--cc=joey.gouly@arm.com \
--cc=kvm@vger.kernel.org \
--cc=kvmarm@lists.linux.dev \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-s390@vger.kernel.org \
--cc=mark.rutland@arm.com \
--cc=maz@kernel.org \
--cc=nrb@linux.ibm.com \
--cc=oupton@kernel.org \
--cc=pbonzini@redhat.com \
--cc=suzuki.poulose@arm.com \
--cc=svens@linux.ibm.com \
--cc=will@kernel.org \
--cc=yuzenghui@huawei.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
all inboxes | Powered by JetHome®