lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [day] [month] [year] [list]
Message-Id: <20250619071449.1714869-1-maobibo@loongson.cn>
Date: Thu, 19 Jun 2025 15:14:49 +0800
From: Bibo Mao <maobibo@...ngson.cn>
To: Tianrui Zhao <zhaotianrui@...ngson.cn>,
	Huacai Chen <chenhuacai@...nel.org>,
	Xianglai Li <lixianglai@...ngson.cn>
Cc: kvm@...r.kernel.org,
	loongarch@...ts.linux.dev,
	linux-kernel@...r.kernel.org
Subject: [PATCH v2] LoongArch: KVM: INTC: Add IOCSR MISC register emulation

IOCSR MISC register 0x420 controlls some features of eiointc, such as
BIT 48 enables eiointc and BIT 49 set interrupt encoding mode.

When kernel irqchip is set, IOCSR MISC register should be emulated in
kernel also. Here add IOCSR MISC register emulation in kernel side.

Signed-off-by: Bibo Mao <maobibo@...ngson.cn>
---
v1 ... v2:
  1. Add separate file arch/loongarch/kvm/intc/misc.c for IOCSR MISC
     register 0x420 emulation, since it controls feature about AVEC
     irqchip also.

  2. Define macro MISC_BASE as LOONGARCH_IOCSR_MISC_FUNC rather than
     hard coded 0x420
---
 arch/loongarch/include/asm/kvm_eiointc.h |   2 +
 arch/loongarch/include/asm/kvm_host.h    |   2 +
 arch/loongarch/include/asm/kvm_misc.h    |  17 +++
 arch/loongarch/include/asm/loongarch.h   |   1 +
 arch/loongarch/kvm/Makefile              |   1 +
 arch/loongarch/kvm/intc/eiointc.c        |  61 +++++++++++
 arch/loongarch/kvm/intc/misc.c           | 125 +++++++++++++++++++++++
 7 files changed, 209 insertions(+)
 create mode 100644 arch/loongarch/include/asm/kvm_misc.h
 create mode 100644 arch/loongarch/kvm/intc/misc.c

diff --git a/arch/loongarch/include/asm/kvm_eiointc.h b/arch/loongarch/include/asm/kvm_eiointc.h
index a3a40aba8acf..2d1c183f2b1b 100644
--- a/arch/loongarch/include/asm/kvm_eiointc.h
+++ b/arch/loongarch/include/asm/kvm_eiointc.h
@@ -119,5 +119,7 @@ struct loongarch_eiointc {
 
 int kvm_loongarch_register_eiointc_device(void);
 void eiointc_set_irq(struct loongarch_eiointc *s, int irq, int level);
+int kvm_eiointc_get_status(struct kvm_vcpu *vcpu, unsigned long *value);
+int kvm_eiointc_update_status(struct kvm_vcpu *vcpu, unsigned long value, unsigned long mask);
 
 #endif /* __ASM_KVM_EIOINTC_H */
diff --git a/arch/loongarch/include/asm/kvm_host.h b/arch/loongarch/include/asm/kvm_host.h
index a3c4cc46c892..f463ec52d86c 100644
--- a/arch/loongarch/include/asm/kvm_host.h
+++ b/arch/loongarch/include/asm/kvm_host.h
@@ -132,6 +132,8 @@ struct kvm_arch {
 	struct loongarch_ipi *ipi;
 	struct loongarch_eiointc *eiointc;
 	struct loongarch_pch_pic *pch_pic;
+	struct kvm_io_device misc;
+	bool   misc_created;
 };
 
 #define CSR_MAX_NUMS		0x800
diff --git a/arch/loongarch/include/asm/kvm_misc.h b/arch/loongarch/include/asm/kvm_misc.h
new file mode 100644
index 000000000000..621e4228dea2
--- /dev/null
+++ b/arch/loongarch/include/asm/kvm_misc.h
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2025 Loongson Technology Corporation Limited
+ */
+
+#ifndef __ASM_KVM_MISC_H
+#define __ASM_KVM_MISC_H
+
+#include <asm/loongarch.h>
+
+#define MISC_BASE		LOONGARCH_IOCSR_MISC_FUNC
+#define MISC_SIZE		0x8
+
+int kvm_loongarch_create_misc(struct kvm *kvm);
+void kvm_loongarch_destroy_misc(struct kvm *kvm);
+
+#endif /* __ASM_KVM_MISC_H */
diff --git a/arch/loongarch/include/asm/loongarch.h b/arch/loongarch/include/asm/loongarch.h
index d84dac88a584..e30d330d497e 100644
--- a/arch/loongarch/include/asm/loongarch.h
+++ b/arch/loongarch/include/asm/loongarch.h
@@ -1141,6 +1141,7 @@
 #define  IOCSR_MISC_FUNC_SOFT_INT	BIT_ULL(10)
 #define  IOCSR_MISC_FUNC_TIMER_RESET	BIT_ULL(21)
 #define  IOCSR_MISC_FUNC_EXT_IOI_EN	BIT_ULL(48)
+#define  IOCSR_MISC_FUNC_INT_ENCODE	BIT_ULL(49)
 #define  IOCSR_MISC_FUNC_AVEC_EN	BIT_ULL(51)
 
 #define LOONGARCH_IOCSR_CPUTEMP		0x428
diff --git a/arch/loongarch/kvm/Makefile b/arch/loongarch/kvm/Makefile
index cb41d9265662..25fa3866613d 100644
--- a/arch/loongarch/kvm/Makefile
+++ b/arch/loongarch/kvm/Makefile
@@ -18,6 +18,7 @@ kvm-y += vcpu.o
 kvm-y += vm.o
 kvm-y += intc/ipi.o
 kvm-y += intc/eiointc.o
+kvm-y += intc/misc.o
 kvm-y += intc/pch_pic.o
 kvm-y += irqfd.o
 
diff --git a/arch/loongarch/kvm/intc/eiointc.c b/arch/loongarch/kvm/intc/eiointc.c
index f39929d7bf8a..87d01521e92f 100644
--- a/arch/loongarch/kvm/intc/eiointc.c
+++ b/arch/loongarch/kvm/intc/eiointc.c
@@ -4,6 +4,7 @@
  */
 
 #include <asm/kvm_eiointc.h>
+#include <asm/kvm_misc.h>
 #include <asm/kvm_vcpu.h>
 #include <linux/count_zeros.h>
 
@@ -708,6 +709,56 @@ static const struct kvm_io_device_ops kvm_eiointc_ops = {
 	.write	= kvm_eiointc_write,
 };
 
+int kvm_eiointc_get_status(struct kvm_vcpu *vcpu, unsigned long *value)
+{
+	unsigned long data, flags;
+	struct loongarch_eiointc *eiointc = vcpu->kvm->arch.eiointc;
+
+	if (!eiointc) {
+		kvm_err("%s: eiointc irqchip not valid!\n", __func__);
+		return -EINVAL;
+	}
+
+	data = 0;
+	spin_lock_irqsave(&eiointc->lock, flags);
+	if (eiointc->status & BIT(EIOINTC_ENABLE))
+		data |= IOCSR_MISC_FUNC_EXT_IOI_EN;
+
+	if (eiointc->status & BIT(EIOINTC_ENABLE_INT_ENCODE))
+		data |= IOCSR_MISC_FUNC_INT_ENCODE;
+	spin_unlock_irqrestore(&eiointc->lock, flags);
+
+	*value = data;
+	return 0;
+}
+
+int kvm_eiointc_update_status(struct kvm_vcpu *vcpu, unsigned long value, unsigned long mask)
+{
+	struct loongarch_eiointc *eiointc = vcpu->kvm->arch.eiointc;
+	unsigned long old, flags;
+
+	if (!eiointc) {
+		kvm_err("%s: eiointc irqchip not valid!\n", __func__);
+		return -EINVAL;
+	}
+
+	old = 0;
+	spin_lock_irqsave(&eiointc->lock, flags);
+	if (eiointc->status & BIT(EIOINTC_ENABLE))
+		old |= IOCSR_MISC_FUNC_EXT_IOI_EN;
+	if (eiointc->status & BIT(EIOINTC_ENABLE_INT_ENCODE))
+		old |= IOCSR_MISC_FUNC_INT_ENCODE;
+
+	value |= (old & ~mask);
+	eiointc->status &= ~(BIT(EIOINTC_ENABLE_INT_ENCODE) | BIT(EIOINTC_ENABLE));
+	if (value & IOCSR_MISC_FUNC_INT_ENCODE)
+		eiointc->status |= BIT(EIOINTC_ENABLE_INT_ENCODE);
+	if (value & IOCSR_MISC_FUNC_EXT_IOI_EN)
+		eiointc->status |= BIT(EIOINTC_ENABLE);
+	spin_unlock_irqrestore(&eiointc->lock, flags);
+	return 0;
+}
+
 static int kvm_eiointc_virt_read(struct kvm_vcpu *vcpu,
 				struct kvm_io_device *dev,
 				gpa_t addr, int len, void *val)
@@ -993,6 +1044,15 @@ static int kvm_eiointc_create(struct kvm_device *dev, u32 type)
 		kfree(s);
 		return ret;
 	}
+
+	ret = kvm_loongarch_create_misc(kvm);
+	if (ret < 0) {
+		kvm_io_bus_unregister_dev(kvm, KVM_IOCSR_BUS, &s->device);
+		kvm_io_bus_unregister_dev(kvm, KVM_IOCSR_BUS, &s->device_vext);
+		kfree(s);
+		return ret;
+	}
+
 	kvm->arch.eiointc = s;
 
 	return 0;
@@ -1010,6 +1070,7 @@ static void kvm_eiointc_destroy(struct kvm_device *dev)
 	eiointc = kvm->arch.eiointc;
 	kvm_io_bus_unregister_dev(kvm, KVM_IOCSR_BUS, &eiointc->device);
 	kvm_io_bus_unregister_dev(kvm, KVM_IOCSR_BUS, &eiointc->device_vext);
+	kvm_loongarch_destroy_misc(kvm);
 	kfree(eiointc);
 }
 
diff --git a/arch/loongarch/kvm/intc/misc.c b/arch/loongarch/kvm/intc/misc.c
new file mode 100644
index 000000000000..edee66afa36e
--- /dev/null
+++ b/arch/loongarch/kvm/intc/misc.c
@@ -0,0 +1,125 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2025 Loongson Technology Corporation Limited
+ */
+#include <asm/kvm_vcpu.h>
+#include <asm/kvm_eiointc.h>
+#include <asm/kvm_misc.h>
+
+static int kvm_misc_read(struct kvm_vcpu *vcpu, struct kvm_io_device *dev,
+			gpa_t addr, int len, void *val)
+{
+	unsigned long data;
+	unsigned int ret;
+
+	addr -= MISC_BASE;
+	if (addr & (len - 1)) {
+		kvm_err("%s: eiointc not aligned addr %llx len %d\n", __func__, addr, len);
+		return -EINVAL;
+	}
+
+	ret = kvm_eiointc_get_status(vcpu, &data);
+	if (ret)
+		return ret;
+
+	data = data >> ((addr & 7) * 8);
+	switch (len) {
+	case 1:
+		*(unsigned char *)val = (unsigned char)data;
+		break;
+
+	case 2:
+		*(unsigned short *)val = (unsigned short)data;
+		break;
+
+	case 4:
+		*(unsigned int *)val = (unsigned int)data;
+		break;
+
+	default:
+		*(unsigned long *)val = data;
+		break;
+	}
+
+	return 0;
+}
+
+static int kvm_misc_write(struct kvm_vcpu *vcpu, struct kvm_io_device *dev,
+		gpa_t addr, int len, const void *val)
+{
+	unsigned long data, mask;
+	unsigned int shift;
+
+	addr -= MISC_BASE;
+	if (addr & (len - 1)) {
+		kvm_err("%s: eiointc not aligned addr %llx len %d\n", __func__, addr, len);
+		return -EINVAL;
+	}
+
+	shift = (addr & 7) * 8;
+	switch (len) {
+	case 1:
+		data = *(unsigned char *)val;
+		mask = 0xFF;
+		mask = mask << shift;
+		data = data << shift;
+		break;
+
+	case 2:
+		data = *(unsigned short *)val;
+		mask = 0xFFFF;
+		mask = mask << shift;
+		data = data << shift;
+		break;
+
+	case 4:
+		data = *(unsigned int *)val;
+		mask = UINT_MAX;
+		mask = mask << shift;
+		data = data << shift;
+		break;
+
+	default:
+		data = *(unsigned long *)val;
+		mask = ULONG_MAX;
+		mask = mask << shift;
+		data = data << shift;
+		break;
+	}
+
+	return kvm_eiointc_update_status(vcpu, data, mask);
+}
+
+static const struct kvm_io_device_ops kvm_misc_ops = {
+	.read   = kvm_misc_read,
+	.write  = kvm_misc_write,
+};
+
+int kvm_loongarch_create_misc(struct kvm *kvm)
+{
+	struct kvm_io_device *device;
+	int ret;
+
+	if (kvm->arch.misc_created)
+		return 0;
+
+	device = &kvm->arch.misc;
+	kvm_iodevice_init(device, &kvm_misc_ops);
+	ret = kvm_io_bus_register_dev(kvm, KVM_IOCSR_BUS, MISC_BASE, MISC_SIZE, device);
+	if (ret < 0)
+		return ret;
+
+	kvm->arch.misc_created = true;
+	return 0;
+}
+
+void kvm_loongarch_destroy_misc(struct kvm *kvm)
+{
+	struct kvm_io_device *device;
+
+	if (kvm->arch.misc_created) {
+		device = &kvm->arch.misc;
+		kvm_io_bus_unregister_dev(kvm, KVM_IOCSR_BUS, device);
+		kvm->arch.misc_created = false;
+	}
+}

base-commit: 52da431bf03b5506203bca27fe14a97895c80faf
-- 
2.39.3


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ